Compare commits
25 Commits
14.0.0
..
1b81b0a3ac
| Author | SHA1 | Date | |
|---|---|---|---|
| 1b81b0a3ac | |||
| 3ff2b8e9bb | |||
| 38525c3257 | |||
| f035bcfae2 | |||
| a8bf356d20 | |||
| cd70b70088 | |||
| 14763cc5b3 | |||
| 0258c2e8b7 | |||
| 9b3d34c5d7 | |||
| 335238df3d | |||
| a1519e7a60 | |||
| e55b5cbe15 | |||
| f28719fc6f | |||
| d0423b2017 | |||
| 156672d853 | |||
| 5ab03920d6 | |||
| 9dd6fbd2e7 | |||
| 76ed974352 | |||
| c65a55225d | |||
| adc104b757 | |||
| 2e14c70a02 | |||
| 2d5b844796 | |||
| c62131ac97 | |||
| cc92f5a418 | |||
| b877262283 |
+458
@@ -0,0 +1,458 @@
|
|||||||
|
# Corrections apportées au module Mournblade CYD 2.0
|
||||||
|
|
||||||
|
## Date : 2026-06-07
|
||||||
|
|
||||||
|
## Dernière mise à jour : 2026-06-07
|
||||||
|
|
||||||
|
## Problèmes identifiés et corrigés
|
||||||
|
|
||||||
|
### 1. ❌ Erreur de chargement des partials Handlebars
|
||||||
|
|
||||||
|
**Problème :**
|
||||||
|
Les feuilles de personnage et de créature généraient une erreur lors du rendu :
|
||||||
|
```
|
||||||
|
Failed to render template part "sheet":
|
||||||
|
The partial systems/fvtt-mournblade-cyd-2-0/templates/partial-active-effects.hbs could not be found
|
||||||
|
```
|
||||||
|
|
||||||
|
**Cause :**
|
||||||
|
La fonction `preloadHandlebarsTemplates()` dans `modules/mournblade-cyd2-utility.js` ne préchargeait pas tous les partials nécessaires. Seuls 7 templates étaient préchargés sur 9 utilisés.
|
||||||
|
|
||||||
|
**Partials manquants :**
|
||||||
|
- `partial-active-effects.hbs` - Utilisé dans les feuilles actor-sheet.hbs et creature-sheet.hbs
|
||||||
|
- `partial-item-effects.hbs` - Utilisé dans de nombreux templates d'items
|
||||||
|
|
||||||
|
**Solution :**
|
||||||
|
Ajout des deux partials manquants à la liste des templates préchargés dans la fonction `preloadHandlebarsTemplates()`.
|
||||||
|
|
||||||
|
**Fichier modifié :**
|
||||||
|
- `modules/mournblade-cyd2-utility.js` (lignes 189-201)
|
||||||
|
|
||||||
|
**Code avant :**
|
||||||
|
```javascript
|
||||||
|
const templatePaths = [
|
||||||
|
'systems/fvtt-mournblade-cyd-2-0/templates/editor-notes-gm.hbs',
|
||||||
|
'systems/fvtt-mournblade-cyd-2-0/templates/partial-item-header.hbs',
|
||||||
|
'systems/fvtt-mournblade-cyd-2-0/templates/partial-item-description.hbs',
|
||||||
|
'systems/fvtt-mournblade-cyd-2-0/templates/partial-item-nav.hbs',
|
||||||
|
'systems/fvtt-mournblade-cyd-2-0/templates/partial-item-prix.hbs',
|
||||||
|
'systems/fvtt-mournblade-cyd-2-0/templates/partial-automation.hbs',
|
||||||
|
'systems/fvtt-mournblade-cyd-2-0/templates/hud-adversites.hbs',
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Code après :**
|
||||||
|
```javascript
|
||||||
|
const templatePaths = [
|
||||||
|
'systems/fvtt-mournblade-cyd-2-0/templates/editor-notes-gm.hbs',
|
||||||
|
'systems/fvtt-mournblade-cyd-2-0/templates/partial-item-header.hbs',
|
||||||
|
'systems/fvtt-mournblade-cyd-2-0/templates/partial-item-description.hbs',
|
||||||
|
'systems/fvtt-mournblade-cyd-2-0/templates/partial-item-nav.hbs',
|
||||||
|
'systems/fvtt-mournblade-cyd-2-0/templates/partial-item-prix.hbs',
|
||||||
|
'systems/fvtt-mournblade-cyd-2-0/templates/partial-automation.hbs',
|
||||||
|
'systems/fvtt-mournblade-cyd-2-0/templates/partial-active-effects.hbs', // ✅ Ajouté
|
||||||
|
'systems/fvtt-mournblade-cyd-2-0/templates/partial-item-effects.hbs', // ✅ Ajouté
|
||||||
|
'systems/fvtt-mournblade-cyd-2-0/templates/hud-adversites.hbs',
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. ❌ Erreur de création d'effet actif
|
||||||
|
|
||||||
|
**Problème :**
|
||||||
|
```
|
||||||
|
base-actor-sheet.mjs:357 MournbladeCYD2 | Failed to create effect: TypeError:
|
||||||
|
Cannot read properties of undefined (reading 'create')
|
||||||
|
```
|
||||||
|
|
||||||
|
**Cause :**
|
||||||
|
La fonction `ActiveEffectDialog.create()` n'existe pas dans Foundry VTT v14. L'API a changé et cette méthode a été supprimée.
|
||||||
|
|
||||||
|
**Solution :**
|
||||||
|
Remplacement de l'appel à `foundry.applications.api.ActiveEffectDialog.create()` par une création directe via `document.createEmbeddedDocuments("ActiveEffect", [data])`, suivie de l'ouverture de la feuille d'édition.
|
||||||
|
|
||||||
|
**Fichiers modifiés :**
|
||||||
|
- `modules/applications/sheets/base-actor-sheet.mjs` (lignes 328-363)
|
||||||
|
- `modules/applications/sheets/base-item-sheet.mjs` (lignes 189-224)
|
||||||
|
|
||||||
|
**Code avant :**
|
||||||
|
```javascript
|
||||||
|
const effect = await foundry.applications.api.ActiveEffectDialog.create({
|
||||||
|
document: this.document,
|
||||||
|
effect: defaultEffectData
|
||||||
|
});
|
||||||
|
|
||||||
|
if (effect) {
|
||||||
|
await this.document.createEmbeddedDocuments("ActiveEffect", [effect.toObject()]);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Code après :**
|
||||||
|
```javascript
|
||||||
|
const [effect] = await this.document.createEmbeddedDocuments("ActiveEffect", [defaultEffectData]);
|
||||||
|
|
||||||
|
if (effect) {
|
||||||
|
effect.sheet.render(true);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. ❌ Boucle infinie de chargement d'icône (effect.webp introuvable) ✅
|
||||||
|
|
||||||
|
**Problème :**
|
||||||
|
```
|
||||||
|
404 (Not Found) - GET https://localhost:31000/systems/fvtt-mournblade-cyd-2-0/assets/icons/effect.webp
|
||||||
|
Boucle infinie de tentatives de chargement
|
||||||
|
```
|
||||||
|
|
||||||
|
**Cause :**
|
||||||
|
L'icône `effect.webp` était référencée dans plusieurs fichiers mais n'existait pas dans le dossier `assets/icons/`. Chaque fois que la dialog de création d'effet s'ouvrait, le navigateur essayait de charger cette image manquante en boucle.
|
||||||
|
|
||||||
|
**Fichiers concernés :**
|
||||||
|
- `modules/applications/sheets/base-actor-sheet.mjs` (ligne 336)
|
||||||
|
- `modules/applications/sheets/base-item-sheet.mjs` (ligne 197)
|
||||||
|
- `modules/mournblade-cyd2-effects.js` (lignes 120, 180)
|
||||||
|
- `templates/partial-active-effects.hbs` (ligne 30)
|
||||||
|
- `templates/partial-item-effects.hbs` (ligne 30)
|
||||||
|
|
||||||
|
**Solution :**
|
||||||
|
Remplacement de toutes les références à `effect.webp` par `capacite.webp`, une icône existante dans le dossier `assets/icons/`.
|
||||||
|
|
||||||
|
**Code avant :**
|
||||||
|
```javascript
|
||||||
|
icon: "systems/fvtt-mournblade-cyd-2-0/assets/icons/effect.webp"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Code après :**
|
||||||
|
```javascript
|
||||||
|
icon: "systems/fvtt-mournblade-cyd-2-0/assets/icons/capacite.webp"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. ❌ Propriété dépréciée ActiveEffectDuration.type ✅
|
||||||
|
|
||||||
|
**Problème :**
|
||||||
|
```
|
||||||
|
foundry.mjs:1555 Error: You are accessing ActiveEffectDuration#type,
|
||||||
|
which is now at ActiveEffectDuration#units.
|
||||||
|
Deprecated since Version 14
|
||||||
|
Backwards-compatible support will be removed in Version 16
|
||||||
|
```
|
||||||
|
|
||||||
|
**Cause :**
|
||||||
|
En Foundry VTT v14, la propriété `duration.type` a été renommée en `duration.units`. L'ancien nom était encore supporté pour la compatibilité, mais générait des avertissements et sera supprimé en v16.
|
||||||
|
|
||||||
|
**Fichiers concernés :**
|
||||||
|
- `templates/partial-active-effects.hbs` (lignes 55-61)
|
||||||
|
- `templates/partial-item-effects.hbs` (lignes 51-56)
|
||||||
|
|
||||||
|
**Solution :**
|
||||||
|
Remplacement de toutes les occurrences de `effect.duration.type` par `effect.duration.units` dans les templates.
|
||||||
|
|
||||||
|
**Code avant :**
|
||||||
|
```handlebars
|
||||||
|
{{#if effect.duration.type}}
|
||||||
|
{{#if (eq effect.duration.type "rounds")}}🔄{{/if}}
|
||||||
|
{{#if (eq effect.duration.type "turns")}}🎭{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Code après :**
|
||||||
|
```handlebars
|
||||||
|
{{#if effect.duration.units}}
|
||||||
|
{{#if (eq effect.duration.units "rounds")}}🔄{{/if}}
|
||||||
|
{{#if (eq effect.duration.units "turns")}}🎭{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5. ❌ Helper Handlebars "subtract" manquant ✅
|
||||||
|
|
||||||
|
**Problème :**
|
||||||
|
```
|
||||||
|
Failed to render Application "MournbladeCYD2PersonnageSheet":
|
||||||
|
Missing helper: "subtract"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Cause :**
|
||||||
|
Le template utilisait le helper `subtract` dans `{{#unless (eq index (subtract effect.changes.length 1))}}` mais ce helper n'était pas enregistré dans Handlebars.
|
||||||
|
|
||||||
|
**Fichiers concernés :**
|
||||||
|
- `templates/partial-active-effects.hbs` (ligne 44)
|
||||||
|
- `templates/partial-item-effects.hbs` (ligne 44)
|
||||||
|
- `modules/mournblade-cyd2-utility.js` (helper non enregistré)
|
||||||
|
|
||||||
|
**Solution :**
|
||||||
|
Ajout du helper `subtract` dans la méthode `init()` de `MournbladeCYD2Utility` :
|
||||||
|
|
||||||
|
**Code ajouté :**
|
||||||
|
```javascript
|
||||||
|
Handlebars.registerHelper('subtract', function (a, b) {
|
||||||
|
return parseInt(a) - parseInt(b);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fonctionnalité :**
|
||||||
|
Le helper permet de soustraire deux nombres dans les templates Handlebars, utilisé pour détecter le dernier élément d'une liste.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 6. ❌ Clés i18n manquantes pour les effets ✅
|
||||||
|
|
||||||
|
**Problème :**
|
||||||
|
Les clés de localisation pour les messages d'erreur des effets actifs étaient manquantes dans `lang/fr.json`, ce qui pouvait entraîner l'affichage de messages en anglais ou vides.
|
||||||
|
|
||||||
|
**Clés manquantes identifiées :**
|
||||||
|
- `MOURNBLADECYD2.EFFECT.createError`
|
||||||
|
- `MOURNBLADECYD2.EFFECT.deleteError`
|
||||||
|
- `MOURNBLADECYD2.EFFECT.applyError`
|
||||||
|
- `MOURNBLADECYD2.EFFECT.applyItemError`
|
||||||
|
- `MOURNBLADECYD2.EFFECT.selectActor`
|
||||||
|
- `MOURNBLADECYD2.EFFECT.toggleError`
|
||||||
|
|
||||||
|
**Solution :**
|
||||||
|
Ajout de toutes les clés manquantes dans la section `EFFECT` du fichier `lang/fr.json`.
|
||||||
|
|
||||||
|
**Traductions ajoutées :**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"createError": "Erreur lors de la création de l'effet",
|
||||||
|
"deleteError": "Erreur lors de la suppression de l'effet",
|
||||||
|
"applyError": "Erreur lors de l'application de l'effet",
|
||||||
|
"applyItemError": "Erreur lors de l'application de l'effet sur l'item",
|
||||||
|
"selectActor": "Sélectionnez un acteur pour appliquer l'effet",
|
||||||
|
"toggleError": "Erreur lors de l'activation/désactivation de l'effet"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fichier modifié :** `lang/fr.json`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 7. ❌ Clés i18n MNBL manquantes ✅
|
||||||
|
|
||||||
|
**Problème :**
|
||||||
|
Les clés de localisation `MNBL.details` et `MNBL.description` étaient manquantes dans `lang/fr.json`, ce qui entraînait l'affichage de la clé elle-même au lieu d'une traduction.
|
||||||
|
|
||||||
|
**Clés manquantes identifiées :**
|
||||||
|
- `MNBL.details` - Utilisée dans l'onglet "Détails" des fiches d'items
|
||||||
|
- `MNBL.description` - Utilisée dans l'onglet "Description" des fiches d'items
|
||||||
|
|
||||||
|
**Solution :**
|
||||||
|
Ajout des deux clés manquantes dans la section `MNBL` du fichier `lang/fr.json`.
|
||||||
|
|
||||||
|
**Traductions ajoutées :**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"details": "Détails",
|
||||||
|
"description": "Description"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fichier modifié :** `lang/fr.json`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 8. ❌ Onglet "Effets" manquant dans les fiches d'items ✅
|
||||||
|
|
||||||
|
**Problème :**
|
||||||
|
L'onglet "Effets" n'apparaissait pas dans les fiches d'items, empêchant l'accès à la gestion des effets actifs sur les items.
|
||||||
|
|
||||||
|
**Cause :**
|
||||||
|
Dans `templates/partial-item-nav.hbs`, l'onglet "Effets" n'était affiché que si l'item avait déjà des effets (`{{#if item.effects.length}}`).
|
||||||
|
|
||||||
|
**Solution :**
|
||||||
|
Suppression de la condition pour toujours afficher l'onglet "Effets", même lorsque l'item n'a pas encore d'effets actifs.
|
||||||
|
|
||||||
|
**Fichier modifié :** `templates/partial-item-nav.hbs`
|
||||||
|
|
||||||
|
**Code avant :**
|
||||||
|
```handlebars
|
||||||
|
{{#if item.effects.length}}
|
||||||
|
<a class="item" data-tab="effects" ...>{{localize "MOURNBLADECYD2.EFFECT.activeEffects"}}</a>
|
||||||
|
{{/if}}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Code après :**
|
||||||
|
```handlebars
|
||||||
|
<a class="item" data-tab="effects" ...>{{localize "MOURNBLADECYD2.EFFECT.activeEffects"}}</a>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 9. ❌ Erreur de parsing JSON (historique)
|
||||||
|
|
||||||
|
**Problème mentionné :**
|
||||||
|
```
|
||||||
|
SyntaxError: Expected ',' or '}' after property value in JSON at position 3753 (line 118 column 4)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Statut :**
|
||||||
|
Cette erreur concernait probablement une ancienne version du fichier `lang/fr.json`. Le fichier actuel est valide et ne contient pas d'erreur de syntaxe.
|
||||||
|
|
||||||
|
**Vérification :**
|
||||||
|
```bash
|
||||||
|
# Le fichier passe la validation JSON
|
||||||
|
node -e "require('./lang/fr.json')" # ✅ Pas d'erreur
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Liste complète des partials Handlebars
|
||||||
|
|
||||||
|
### Partials utilisés dans le système :
|
||||||
|
|
||||||
|
| Partial | Utilisation | Pré-chargé ? |
|
||||||
|
|---------|-------------|--------------|
|
||||||
|
| `partial-item-header.hbs` | En-têtes des items | ✅ Oui |
|
||||||
|
| `partial-item-description.hbs` | Descriptions des items | ✅ Oui |
|
||||||
|
| `partial-item-nav.hbs` | Navigation des items | ✅ Oui |
|
||||||
|
| `partial-item-prix.hbs` | Prix des items | ✅ Oui |
|
||||||
|
| `partial-item-effects.hbs` | Effets des items | ✅ Oui (ajouté) |
|
||||||
|
| `partial-active-effects.hbs` | Effets actifs (actors) | ✅ Oui (ajouté) |
|
||||||
|
| `partial-automation.hbs` | Automatisation | ✅ Oui |
|
||||||
|
| `editor-notes-gm.hbs` | Notes GM | ✅ Oui |
|
||||||
|
| `hud-adversites.hbs` | HUD Adversités | ✅ Oui |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Templates principaux
|
||||||
|
|
||||||
|
### Fiches d'acteurs :
|
||||||
|
- `actor-sheet.hbs` - Feuille de personnage
|
||||||
|
- `creature-sheet.hbs` - Feuille de créature
|
||||||
|
|
||||||
|
### Fiches d'items :
|
||||||
|
- `item-arme-sheet.hbs`
|
||||||
|
- `item-capaciteautomata-sheet.hbs`
|
||||||
|
- `item-competence-sheet.hbs`
|
||||||
|
- `item-don-sheet.hbs`
|
||||||
|
- `item-equipement-sheet.hbs`
|
||||||
|
- `item-historique-sheet.hbs`
|
||||||
|
- `item-monnaie-sheet.hbs`
|
||||||
|
- `item-pacte-sheet.hbs`
|
||||||
|
- `item-pouvoirselementaire-sheet.hbs`
|
||||||
|
- `item-profil-sheet.hbs`
|
||||||
|
- `item-protection-sheet.hbs`
|
||||||
|
- `item-ressource-sheet.hbs`
|
||||||
|
- `item-rune-sheet.hbs`
|
||||||
|
- `item-runeeffect-sheet.hbs`
|
||||||
|
- `item-talent-sheet.hbs`
|
||||||
|
- `item-tendance-sheet.hbs`
|
||||||
|
- `item-traitchaotique-sheet.hbs`
|
||||||
|
- `item-traitdemoniaque-sheet.hbs`
|
||||||
|
- `item-traitespece-sheet.hbs`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Outils de test
|
||||||
|
|
||||||
|
Un script de test a été créé pour valider les corrections :
|
||||||
|
- **Fichier :** `test-templates.js`
|
||||||
|
- **Exécution :** `node test-templates.js`
|
||||||
|
|
||||||
|
**Fonctionnalités du test :**
|
||||||
|
1. ✅ Vérifie que tous les templates préchargés existent
|
||||||
|
2. ✅ Scanne tous les templates pour trouver les partials utilisés
|
||||||
|
3. ✅ Vérifie que tous les partials utilisés sont préchargés
|
||||||
|
4. ✅ Valide le fichier de localisation JSON
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Bonnes pratiques rappelées
|
||||||
|
|
||||||
|
### Pré-chargement des templates Handlebars
|
||||||
|
|
||||||
|
En Foundry VTT v12+, il est **obligatoire** de pré-charger tous les partials Handlebars utilisés via la fonction `foundry.applications.handlebars.loadTemplates()` dans le hook `init`.
|
||||||
|
|
||||||
|
**Pourquoi ?**
|
||||||
|
- Les partials ne sont pas chargés automatiquement
|
||||||
|
- Sans pré-chargement, le rendu échouera avec une erreur "partial could not be found"
|
||||||
|
- Le pré-chargement améliore les performances en cacheant les templates
|
||||||
|
|
||||||
|
**Où ?**
|
||||||
|
Dans le hook `init`, avant l'enregistrement des feuilles (sheets) :
|
||||||
|
```javascript
|
||||||
|
Hooks.once("init", async function () {
|
||||||
|
// Pré-charger les templates AVANT d'enregistrer les feuilles
|
||||||
|
await MournbladeCYD2Utility.preloadHandlebarsTemplates();
|
||||||
|
|
||||||
|
// Ensuite enregistrer les feuilles
|
||||||
|
Actors.registerSheet(...);
|
||||||
|
Items.registerSheet(...);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Gestion des chemins des templates
|
||||||
|
|
||||||
|
Les chemins doivent être **relatifs au répertoire `systems/`** :
|
||||||
|
- ✅ Bon : `'systems/fvtt-mournblade-cyd-2-0/templates/partial-active-effects.hbs'`
|
||||||
|
- ❌ Mauvais : `'./templates/partial-active-effects.hbs'`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Impact des corrections
|
||||||
|
|
||||||
|
### Avant les corrections :
|
||||||
|
- ❌ Ouverture des feuilles de personnage → Erreur
|
||||||
|
- ❌ Ouverture des feuilles de créature → Erreur
|
||||||
|
- ❌ Affichage des effets actifs → Impossible
|
||||||
|
- ❌ Utilisation des effets d'items → Problèmes potentiels
|
||||||
|
- ❌ Création d'effets actifs → Erreur TypeError
|
||||||
|
- ❌ Boucle infinie de 404 sur effect.webp
|
||||||
|
- ❌ Avertissements duration.type déprécié
|
||||||
|
- ❌ Helper subtract manquant → Erreur de rendu
|
||||||
|
- ❌ Clés i18n manquantes → Messages en anglais
|
||||||
|
- ❌ Clés MNBL.details et MNBL.description manquantes
|
||||||
|
- ❌ Onglet "Effets" manquant dans les fiches d'items
|
||||||
|
|
||||||
|
### Après les corrections :
|
||||||
|
- ✅ Toutes les feuilles s'ouvrent correctement
|
||||||
|
- ✅ Les effets actifs s'affichent correctement
|
||||||
|
- ✅ Tous les items affichent leurs effets
|
||||||
|
- ✅ Plus d'erreurs de templates manquants
|
||||||
|
- ✅ Création d'effets actifs fonctionne correctement
|
||||||
|
- ✅ Plus de boucles infinies de chargement d'icônes
|
||||||
|
- ✅ Plus d'avertissements de compatibilité
|
||||||
|
- ✅ Helper subtract disponible et fonctionnel
|
||||||
|
- ✅ Toutes les clés i18n présentes → Localisation complète
|
||||||
|
- ✅ Toutes les clés MNBL présentes
|
||||||
|
- ✅ Onglet "Effets" toujours visible dans les fiches d'items
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Recommandations pour le développement futur
|
||||||
|
|
||||||
|
1. **Toujours pré-charger les nouveaux partials** lorsqu'ils sont ajoutés
|
||||||
|
2. **Utiliser un script de test** pour valider les templates après modification
|
||||||
|
3. **Maintenir une liste à jour** des partials utilisés dans le projet
|
||||||
|
4. **Vérifier les erreurs de console** lors du développement
|
||||||
|
5. **Tester toutes les feuilles** après ajout de nouveaux partials
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Fichiers modifiés
|
||||||
|
|
||||||
|
| Fichier | Modification | Statut |
|
||||||
|
|---------|--------------|--------|
|
||||||
|
| `modules/mournblade-cyd2-utility.js` | Ajout partials + helper subtract | ✅ Corrigé |
|
||||||
|
| `modules/applications/sheets/base-actor-sheet.mjs` | Correction création effets + icône | ✅ Corrigé |
|
||||||
|
| `modules/applications/sheets/base-item-sheet.mjs` | Correction création effets + icône | ✅ Corrigé |
|
||||||
|
| `modules/mournblade-cyd2-effects.js` | Remplacement effect.webp par capacite.webp | ✅ Corrigé |
|
||||||
|
| `templates/partial-active-effects.hbs` | Remplacement effect.webp + duration.type → duration.units | ✅ Corrigé |
|
||||||
|
| `templates/partial-item-effects.hbs` | Remplacement effect.webp + duration.type → duration.units | ✅ Corrigé |
|
||||||
|
| `templates/partial-item-nav.hbs` | Affichage permanent onglet Effets + clés MNBL | ✅ Corrigé |
|
||||||
|
| `test-templates.js` | Nouveau fichier de test | ✅ Ajouté |
|
||||||
|
| `CORRECTIONS.md` | Documentation des corrections | ✅ Ajouté |
|
||||||
|
| `lang/fr.json` | Ajout des clés i18n EFFECT + MNBL manquantes | ✅ Corrigé |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Auteurs
|
||||||
|
|
||||||
|
Corrections réalisées par : Mistral Vibe (via Vibe CLI)
|
||||||
|
Date : 2026-06-07
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 7.4 KiB |
+88
-1
@@ -20,7 +20,17 @@
|
|||||||
"runeeffect": "Effet de Rune",
|
"runeeffect": "Effet de Rune",
|
||||||
"tendance": "Tendance",
|
"tendance": "Tendance",
|
||||||
"traitchaotique": "Trait Chaotique",
|
"traitchaotique": "Trait Chaotique",
|
||||||
"traitespece": "Trait d'Espèce"
|
"traitespece": "Trait d'Espèce",
|
||||||
|
"traitdemoniaque": "Trait Démoniaque",
|
||||||
|
"pouvoirselementaire": "Pouvoir Élémentaire",
|
||||||
|
"capaciteautomata": "Capacité d'Automata"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"SHEETS": {
|
||||||
|
"Item": {
|
||||||
|
"traitdemoniaque": "Trait Démoniaque",
|
||||||
|
"pouvoirselementaire": "Pouvoir Élémentaire",
|
||||||
|
"capaciteautomata": "Capacité d'Automata"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"MOURNBLADE": {
|
"MOURNBLADE": {
|
||||||
@@ -28,5 +38,82 @@
|
|||||||
"editTrait": "Modifier le trait",
|
"editTrait": "Modifier le trait",
|
||||||
"deleteTrait": "Supprimer le trait"
|
"deleteTrait": "Supprimer le trait"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"MNBL": {
|
||||||
|
"all": "Tous",
|
||||||
|
"allegiance": "Allégeance",
|
||||||
|
"balance": "Balance",
|
||||||
|
"beastslords": "Seigneurs des Bêtes",
|
||||||
|
"chaos": "Chaos",
|
||||||
|
"difficulty": "Difficulté",
|
||||||
|
"duration": "Durée",
|
||||||
|
"details": "Détails",
|
||||||
|
"description": "Description",
|
||||||
|
"elementslords": "Seigneurs des Éléments",
|
||||||
|
"equipment": "Equipement",
|
||||||
|
"examples": "Exemples",
|
||||||
|
"exercisedskills": "Compétences exercées",
|
||||||
|
"highlanguage": "Haut-Parler",
|
||||||
|
"initiateTalents": "Talents Initié",
|
||||||
|
"law": "Loi",
|
||||||
|
"mode": "Mode",
|
||||||
|
"mainattribute": "Attribut principal",
|
||||||
|
"none": "Aucun",
|
||||||
|
"aguerriTalents": "Talents Aguerri",
|
||||||
|
"prerequisitesAguerri": "Prérequis Aguerri",
|
||||||
|
"prerequisitesMaitre": "Prérequis Maître",
|
||||||
|
"prerequisites": "Prérequis",
|
||||||
|
"maitreTalents": "Talents Maître",
|
||||||
|
"pronounced": "Prononcée",
|
||||||
|
"pronouncedrune": "Rune prononcée",
|
||||||
|
"pronouncerune": "Prononcer",
|
||||||
|
"rune": "Rune",
|
||||||
|
"soulcost": "Coût en points de pouvoir",
|
||||||
|
"soulpoints": "Points de Pouvoir",
|
||||||
|
"traced": "Tracée",
|
||||||
|
"tracedrune": "Rune tracée",
|
||||||
|
"tracerune": "Tracer"
|
||||||
|
},
|
||||||
|
"EFFECT": {
|
||||||
|
"new": "Nouvel Effet",
|
||||||
|
"edit": "Éditer l'effet",
|
||||||
|
"delete": "Supprimer l'effet",
|
||||||
|
"deleteConfirm": "Supprimer l'effet",
|
||||||
|
"deleteConfirmText": "Êtes-vous sûr de vouloir supprimer cet effet ?",
|
||||||
|
"deleteError": "Erreur lors de la suppression de l'effet",
|
||||||
|
"create": "Créer un effet",
|
||||||
|
"createError": "Erreur lors de la création de l'effet",
|
||||||
|
"applyError": "Erreur lors de l'application de l'effet",
|
||||||
|
"applyItemError": "Erreur lors de l'application de l'effet sur l'item",
|
||||||
|
"selectActor": "Sélectionnez un acteur pour appliquer l'effet",
|
||||||
|
"toggleError": "Erreur lors de l'activation/désactivation de l'effet",
|
||||||
|
"name": "Nom de l'effet",
|
||||||
|
"icon": "Icône",
|
||||||
|
"description": "Description",
|
||||||
|
"changes": "Modifications",
|
||||||
|
"addChange": "Ajouter une modification",
|
||||||
|
"duration": "Durée",
|
||||||
|
"durationType": "Type de durée",
|
||||||
|
"durationValue": "Valeur",
|
||||||
|
"disabled": "Désactivé",
|
||||||
|
"transfer": "Transférer au token",
|
||||||
|
"noDuration": "Aucune (permanent)",
|
||||||
|
"rounds": "Rounds",
|
||||||
|
"turns": "Tours",
|
||||||
|
"seconds": "Secondes",
|
||||||
|
"combat": "Jusqu'à la fin du combat",
|
||||||
|
"scene": "Jusqu'à la fin de la scène",
|
||||||
|
"attribute": "Attribut",
|
||||||
|
"value": "Valeur",
|
||||||
|
"mode": "Mode",
|
||||||
|
"modeAdd": "Ajouter",
|
||||||
|
"modeMultiply": "Multiplier",
|
||||||
|
"modeOverride": "Remplacer",
|
||||||
|
"modeUpgrade": "Améliorer",
|
||||||
|
"modeDowngrade": "Dégrader",
|
||||||
|
"activeEffects": "Effets Actifs",
|
||||||
|
"noActiveEffects": "Aucun effet actif",
|
||||||
|
"effectSummary": "Résumé des modifications",
|
||||||
|
"toggleEffect": "Activer/Désactiver"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -398,7 +398,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.items-title-bg {
|
&.items-title-bg {
|
||||||
background: rgba(0, 0, 0, 0.3);
|
background: rgba(0, 0, 0, 0.55);
|
||||||
border-color: rgba(139, 69, 19, 0.5);
|
border-color: rgba(139, 69, 19, 0.5);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-bottom: 0.3rem;
|
margin-bottom: 0.3rem;
|
||||||
@@ -866,14 +866,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.items-title-bg {
|
&.items-title-bg {
|
||||||
background: rgba(20, 10, 0, 0.45);
|
background: rgba(20, 10, 0, 0.65);
|
||||||
border: 1px solid rgba(139, 69, 19, 0.55);
|
border: 1px solid rgba(139, 69, 19, 0.55);
|
||||||
border-radius: 3px 3px 0 0;
|
border-radius: 3px 3px 0 0;
|
||||||
padding: 0.2rem 0.4rem;
|
padding: 0.2rem 0.4rem;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: rgba(20, 10, 0, 0.5);
|
background: rgba(20, 10, 0, 0.7);
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
@@ -990,7 +990,7 @@
|
|||||||
.predilection-text {
|
.predilection-text {
|
||||||
font-size: 0.67rem;
|
font-size: 0.67rem;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
color: #9a7a50 !important;
|
color: #6a4a20 !important;
|
||||||
text-shadow: none;
|
text-shadow: none;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -1001,7 +1001,7 @@
|
|||||||
|
|
||||||
// Defence value label
|
// Defence value label
|
||||||
label.arme-defensif.defense-sheet {
|
label.arme-defensif.defense-sheet {
|
||||||
color: #6090c0 !important;
|
color: #305080 !important;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
|
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
|
||||||
}
|
}
|
||||||
@@ -1011,7 +1011,7 @@
|
|||||||
font-family: "CentaurMT", "Palatino Linotype", serif;
|
font-family: "CentaurMT", "Palatino Linotype", serif;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #c0a060 !important;
|
color: #8a6a30 !important;
|
||||||
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.6);
|
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.6);
|
||||||
letter-spacing: 0.3px;
|
letter-spacing: 0.3px;
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-1
@@ -240,7 +240,7 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #464331c4;
|
color: #2a2515;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
font-family: "CentaurMT", serif;
|
font-family: "CentaurMT", serif;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -296,4 +296,20 @@
|
|||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Section headings in item sheet tabs */
|
||||||
|
.tab .item-list h3 {
|
||||||
|
font-family: "CentaurMT", "Palatino Linotype", serif;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
color: #f0dfc0 !important;
|
||||||
|
background: rgba(20, 10, 0, 0.65);
|
||||||
|
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.9);
|
||||||
|
margin: 0.25rem 0;
|
||||||
|
padding: 0.2rem 0.4rem;
|
||||||
|
border-radius: 3px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+58
-25
@@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
--actor-label-font-size: 0.9rem;
|
--actor-label-font-size: 0.9rem;
|
||||||
--actor-label-font-weight: 700;
|
--actor-label-font-weight: 700;
|
||||||
--actor-label-color: #464331c4;
|
--actor-label-color: #2a2515;
|
||||||
|
|
||||||
/* =================== 2. DEBUGGING HIGHLIGHTERS ============ */
|
/* =================== 2. DEBUGGING HIGHLIGHTERS ============ */
|
||||||
--debug-background-color-red: #ff000054;
|
--debug-background-color-red: #ff000054;
|
||||||
@@ -917,6 +917,29 @@
|
|||||||
text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.75);
|
text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.75);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#chat-controls {
|
||||||
|
height: auto;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#chat-controls textarea,
|
||||||
|
#chat-controls [contenteditable="true"] {
|
||||||
|
min-height: 2rem;
|
||||||
|
max-height: 7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#chat-message {
|
||||||
|
height: auto;
|
||||||
|
min-height: 3rem;
|
||||||
|
max-height: 5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#chat-message .editor-content {
|
||||||
|
height: auto;
|
||||||
|
min-height: 3rem;
|
||||||
|
max-height: 5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.sidebar-tab .directory-list .entity {
|
.sidebar-tab .directory-list .entity {
|
||||||
border-top: 1px dashed rgba(0, 0, 0, 0.25);
|
border-top: 1px dashed rgba(0, 0, 0, 0.25);
|
||||||
border-bottom: 0 none;
|
border-bottom: 0 none;
|
||||||
@@ -949,13 +972,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.message-content .roll-success {
|
.message-content .roll-success {
|
||||||
color: rgb(52, 238, 52);
|
color: rgb(20, 120, 20);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-family: Charlemagne;
|
font-family: Charlemagne;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-content .roll-failure {
|
.message-content .roll-failure {
|
||||||
color: rgb(224, 133, 13);
|
color: rgb(180, 90, 0);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-family: Charlemagne;
|
font-family: Charlemagne;
|
||||||
}
|
}
|
||||||
@@ -1110,9 +1133,7 @@
|
|||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
background: rgba(30, 25, 20, 1);
|
background: rgba(30, 25, 20, 1);
|
||||||
background-origin: padding-box;
|
background-origin: padding-box;
|
||||||
border-image: url(img/ui/footer-button.png) 10 repeat;
|
border: 1px solid rgba(72, 46, 28, 1);
|
||||||
border-image-width: 4px;
|
|
||||||
border-image-outset: 0px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#controls .scene-control.active,
|
#controls .scene-control.active,
|
||||||
@@ -1121,9 +1142,7 @@
|
|||||||
#controls .control-tool:hover {
|
#controls .control-tool:hover {
|
||||||
background: rgba(72, 46, 28, 1);
|
background: rgba(72, 46, 28, 1);
|
||||||
background-origin: padding-box;
|
background-origin: padding-box;
|
||||||
border-image: url(img/ui/footer-button.png) 10 repeat;
|
border: 1px solid rgba(108, 69, 40, 1);
|
||||||
border-image-width: 4px;
|
|
||||||
border-image-outset: 0px;
|
|
||||||
box-shadow: 0 0 3px #ff6400;
|
box-shadow: 0 0 3px #ff6400;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1146,9 +1165,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#players {
|
#players {
|
||||||
border-image: url(img/ui/footer-button.png) 10 repeat;
|
border: 1px solid rgba(72, 46, 28, 1);
|
||||||
border-image-width: 4px;
|
|
||||||
border-image-outset: 0px;
|
|
||||||
background: rgba(30, 25, 20, 1);
|
background: rgba(30, 25, 20, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1159,27 +1176,21 @@
|
|||||||
#navigation #scene-list .scene.nav-item {
|
#navigation #scene-list .scene.nav-item {
|
||||||
background: rgba(30, 25, 20, 1);
|
background: rgba(30, 25, 20, 1);
|
||||||
background-origin: padding-box;
|
background-origin: padding-box;
|
||||||
border-image: url(img/ui/footer-button.png) 10 repeat;
|
border: 1px solid rgba(108, 69, 40, 1);
|
||||||
border-image-width: 4px;
|
|
||||||
border-image-outset: 0px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#navigation #scene-list .scene.view,
|
#navigation #scene-list .scene.view,
|
||||||
#navigation #scene-list .scene.context {
|
#navigation #scene-list .scene.context {
|
||||||
background: rgba(72, 46, 28, 1);
|
background: rgba(72, 46, 28, 1);
|
||||||
background-origin: padding-box;
|
background-origin: padding-box;
|
||||||
border-image: url(img/ui/footer-button.png) 10 repeat;
|
border: 1px solid rgba(108, 69, 40, 1);
|
||||||
border-image-width: 4px;
|
|
||||||
border-image-outset: 0px;
|
|
||||||
box-shadow: 0 0 3px #ff6400;
|
box-shadow: 0 0 3px #ff6400;
|
||||||
}
|
}
|
||||||
|
|
||||||
#navigation #nav-toggle {
|
#navigation #nav-toggle {
|
||||||
background: rgba(30, 25, 20, 1);
|
background: rgba(30, 25, 20, 1);
|
||||||
background-origin: padding-box;
|
background-origin: padding-box;
|
||||||
border-image: url(img/ui/footer-button.png) 10 repeat;
|
border: 1px solid rgba(108, 69, 40, 1);
|
||||||
border-image-width: 4px;
|
|
||||||
border-image-outset: 0px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tooltip container */
|
/* Tooltip container */
|
||||||
@@ -1886,11 +1897,35 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mournblade-cyd2-roll-dialog .checkbox-label input[type="checkbox"] {
|
.mournblade-cyd2-roll-dialog .checkbox-label input[type="checkbox"] {
|
||||||
width: auto;
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
min-width: 14px;
|
||||||
|
min-height: 14px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
flex-shrink: 0;
|
padding: 0;
|
||||||
|
flex: 0 0 auto;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
accent-color: #8b4513;
|
accent-color: #8b4513;
|
||||||
|
appearance: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
background: rgba(230, 215, 195, 0.5);
|
||||||
|
border: 1px solid #8a7a6a;
|
||||||
|
filter: none;
|
||||||
|
box-shadow: none;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.mournblade-cyd2-roll-dialog .checkbox-label input[type="checkbox"]:checked {
|
||||||
|
background: rgba(180, 140, 80, 0.4);
|
||||||
|
border-color: #6a4a20;
|
||||||
|
}
|
||||||
|
.mournblade-cyd2-roll-dialog .checkbox-label input[type="checkbox"]::before {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 12px;
|
||||||
|
color: #2a1a0a;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mournblade-cyd2-roll-dialog .checkbox-label span {
|
.mournblade-cyd2-roll-dialog .checkbox-label span {
|
||||||
@@ -2639,5 +2674,3 @@
|
|||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,3 +23,6 @@ export { default as MournbladeCYD2TalentSheet } from './mournblade-cyd2-talent-s
|
|||||||
export { default as MournbladeCYD2TendanceSheet } from './mournblade-cyd2-tendance-sheet.mjs';
|
export { default as MournbladeCYD2TendanceSheet } from './mournblade-cyd2-tendance-sheet.mjs';
|
||||||
export { default as MournbladeCYD2TraitChaotiqueSheet } from './mournblade-cyd2-traitchaotique-sheet.mjs';
|
export { default as MournbladeCYD2TraitChaotiqueSheet } from './mournblade-cyd2-traitchaotique-sheet.mjs';
|
||||||
export { default as MournbladeCYD2TraitEspeceSheet } from './mournblade-cyd2-traitespece-sheet.mjs';
|
export { default as MournbladeCYD2TraitEspeceSheet } from './mournblade-cyd2-traitespece-sheet.mjs';
|
||||||
|
export { default as MournbladeCYD2TraitDemoniaqueSheet } from './mournblade-cyd2-traitdemoniaque-sheet.mjs';
|
||||||
|
export { default as MournbladeCYD2PouvoirElementaireSheet } from './mournblade-cyd2-pouvoirselementaire-sheet.mjs';
|
||||||
|
export { default as MournbladeCYD2CapaciteAutomataSheet } from './mournblade-cyd2-capaciteautomata-sheet.mjs';
|
||||||
|
|||||||
@@ -60,6 +60,12 @@ export default class MournbladeCYD2ActorSheetV2 extends HandlebarsApplicationMix
|
|||||||
rollDesengager: MournbladeCYD2ActorSheetV2.#onRollDesengager,
|
rollDesengager: MournbladeCYD2ActorSheetV2.#onRollDesengager,
|
||||||
rollInitiative: MournbladeCYD2ActorSheetV2.#onRollInitiative,
|
rollInitiative: MournbladeCYD2ActorSheetV2.#onRollInitiative,
|
||||||
rollFuir: MournbladeCYD2ActorSheetV2.#onRollFuir,
|
rollFuir: MournbladeCYD2ActorSheetV2.#onRollFuir,
|
||||||
|
// Actions pour les ActiveEffects
|
||||||
|
createEffect: MournbladeCYD2ActorSheetV2.#onCreateEffect,
|
||||||
|
editEffect: MournbladeCYD2ActorSheetV2.#onEditEffect,
|
||||||
|
deleteEffect: MournbladeCYD2ActorSheetV2.#onDeleteEffect,
|
||||||
|
toggleEffect: MournbladeCYD2ActorSheetV2.#onToggleEffect,
|
||||||
|
applyEffect: MournbladeCYD2ActorSheetV2.#onApplyEffect,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -176,7 +182,8 @@ export default class MournbladeCYD2ActorSheetV2 extends HandlebarsApplicationMix
|
|||||||
const item = await Item.fromDropData(data);
|
const item = await Item.fromDropData(data);
|
||||||
if (!item) return;
|
if (!item) return;
|
||||||
if (this.document.uuid === item.parent?.uuid) return;
|
if (this.document.uuid === item.parent?.uuid) return;
|
||||||
return this.document.createEmbeddedDocuments("Item", [item.toObject()]);
|
await this.document.createEmbeddedDocuments("Item", [item.toObject()]);
|
||||||
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
async _onDropActor(event, data) {}
|
async _onDropActor(event, data) {}
|
||||||
@@ -283,7 +290,7 @@ export default class MournbladeCYD2ActorSheetV2 extends HandlebarsApplicationMix
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async #onRollAssommer(event, target) {
|
static async #onRollAssommer(event, target) {
|
||||||
await this.document.rollAssomer();
|
await this.document.rollAssommer();
|
||||||
}
|
}
|
||||||
|
|
||||||
static async #onRollCoupBas(event, target) {
|
static async #onRollCoupBas(event, target) {
|
||||||
@@ -309,4 +316,149 @@ export default class MournbladeCYD2ActorSheetV2 extends HandlebarsApplicationMix
|
|||||||
static async #onRollFuir(event, target) {
|
static async #onRollFuir(event, target) {
|
||||||
await this.document.rollFuir();
|
await this.document.rollFuir();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #region ActiveEffects Management
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un nouvel effet actif
|
||||||
|
* @param {Event} event - Événement
|
||||||
|
* @param {HTMLElement} target - Éléments cible
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static async #onCreateEffect(event, target) {
|
||||||
|
event.preventDefault();
|
||||||
|
if (!this.isEditable || !this.document) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Créer les données par défaut pour un nouvel effet
|
||||||
|
const defaultEffectData = {
|
||||||
|
name: game.i18n.localize("MOURNBLADECYD2.EFFECT.new") || "Nouvel Effet",
|
||||||
|
icon: "systems/fvtt-mournblade-cyd-2-0/assets/icons/capacite.webp",
|
||||||
|
description: "",
|
||||||
|
changes: [],
|
||||||
|
disabled: false,
|
||||||
|
duration: {},
|
||||||
|
origin: this.document.uuid,
|
||||||
|
tint: "",
|
||||||
|
transfer: true,
|
||||||
|
flags: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Créer directement l'effet actif sur l'acteur
|
||||||
|
const [effect] = await this.document.createEmbeddedDocuments("ActiveEffect", [defaultEffectData]);
|
||||||
|
|
||||||
|
if (effect) {
|
||||||
|
// Ouvrir la feuille d'édition de l'effet
|
||||||
|
effect.sheet.render(true);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("MournbladeCYD2 | Failed to create effect:", error);
|
||||||
|
ui.notifications.error(
|
||||||
|
game.i18n.localize("MOURNBLADECYD2.EFFECT.createError") ||
|
||||||
|
"Erreur lors de la création de l'effet"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Édite un effet actif existant
|
||||||
|
* @param {Event} event - Événement
|
||||||
|
* @param {HTMLElement} target - Éléments cible
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static async #onEditEffect(event, target) {
|
||||||
|
event.preventDefault();
|
||||||
|
if (!this.isEditable || !this.document) return;
|
||||||
|
|
||||||
|
const effectId = target?.dataset?.effectId;
|
||||||
|
if (!effectId) return;
|
||||||
|
|
||||||
|
const effect = this.document.effects.get(effectId);
|
||||||
|
if (effect) {
|
||||||
|
// Ouvrir la sheet de l'effet pour édition
|
||||||
|
effect.sheet.render(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supprime un effet actif
|
||||||
|
* @param {Event} event - Événement
|
||||||
|
* @param {HTMLElement} target - Éléments cible
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static async #onDeleteEffect(event, target) {
|
||||||
|
event.preventDefault();
|
||||||
|
if (!this.isEditable || !this.document) return;
|
||||||
|
|
||||||
|
const effectId = target?.dataset?.effectId;
|
||||||
|
if (!effectId) return;
|
||||||
|
|
||||||
|
const effect = this.document.effects.get(effectId);
|
||||||
|
if (effect) {
|
||||||
|
const effectName = effect.name;
|
||||||
|
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||||
|
title: game.i18n.localize("MOURNBLADECYD2.EFFECT.deleteConfirm") || "Supprimer l'effet",
|
||||||
|
content: game.i18n.localize("MOURNBLADECYD2.EFFECT.deleteConfirmText", {name: effectName}) ||
|
||||||
|
`Êtes-vous sûr de vouloir supprimer l'effet "${effectName}" ?`
|
||||||
|
});
|
||||||
|
|
||||||
|
if (confirmed) {
|
||||||
|
try {
|
||||||
|
await this.document.deleteEmbeddedDocuments("ActiveEffect", [effectId]);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("MournbladeCYD2 | Failed to delete effect:", error);
|
||||||
|
ui.notifications.error(
|
||||||
|
game.i18n.localize("MOURNBLADECYD2.EFFECT.deleteError") ||
|
||||||
|
"Erreur lors de la suppression de l'effet"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle l'état actif/désactivé d'un effet
|
||||||
|
* @param {Event} event - Événement
|
||||||
|
* @param {HTMLElement} target - Éléments cible
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static async #onToggleEffect(event, target) {
|
||||||
|
event.preventDefault();
|
||||||
|
if (!this.isEditable || !this.document) return;
|
||||||
|
|
||||||
|
const effectId = target?.dataset?.effectId;
|
||||||
|
if (!effectId) return;
|
||||||
|
|
||||||
|
const effect = this.document.effects.get(effectId);
|
||||||
|
if (effect) {
|
||||||
|
try {
|
||||||
|
await effect.update({ disabled: !effect.disabled });
|
||||||
|
} catch (error) {
|
||||||
|
console.error("MournbladeCYD2 | Failed to toggle effect:", error);
|
||||||
|
ui.notifications.error(
|
||||||
|
game.i18n.localize("MOURNBLADECYD2.EFFECT.toggleError") ||
|
||||||
|
"Erreur lors du basculement de l'effet"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applique un effet à partir d'un item
|
||||||
|
* @param {Event} event - Événement
|
||||||
|
* @param {HTMLElement} target - Éléments cible
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static async #onApplyEffect(event, target) {
|
||||||
|
event.preventDefault();
|
||||||
|
const effectId = target?.dataset?.effectId;
|
||||||
|
if (!effectId) return;
|
||||||
|
|
||||||
|
const effect = this.document.effects.get(effectId);
|
||||||
|
if (effect) {
|
||||||
|
await effect.apply();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,14 @@ export default class MournbladeCYD2ItemSheetV2 extends HandlebarsApplicationMixi
|
|||||||
postItem: MournbladeCYD2ItemSheetV2.#onPostItem,
|
postItem: MournbladeCYD2ItemSheetV2.#onPostItem,
|
||||||
addPredilection: MournbladeCYD2ItemSheetV2.#onAddPredilection,
|
addPredilection: MournbladeCYD2ItemSheetV2.#onAddPredilection,
|
||||||
deletePredilection: MournbladeCYD2ItemSheetV2.#onDeletePredilection,
|
deletePredilection: MournbladeCYD2ItemSheetV2.#onDeletePredilection,
|
||||||
|
addAutomation: MournbladeCYD2ItemSheetV2.#onAddAutomation,
|
||||||
|
deleteAutomation: MournbladeCYD2ItemSheetV2.#onDeleteAutomation,
|
||||||
|
// Actions pour les ActiveEffects
|
||||||
|
createEffect: MournbladeCYD2ItemSheetV2.#onCreateEffect,
|
||||||
|
editEffect: MournbladeCYD2ItemSheetV2.#onEditEffect,
|
||||||
|
deleteEffect: MournbladeCYD2ItemSheetV2.#onDeleteEffect,
|
||||||
|
toggleEffect: MournbladeCYD2ItemSheetV2.#onToggleEffect,
|
||||||
|
applyEffect: MournbladeCYD2ItemSheetV2.#onApplyEffect,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -50,13 +58,13 @@ export default class MournbladeCYD2ItemSheetV2 extends HandlebarsApplicationMixi
|
|||||||
item: this.document,
|
item: this.document,
|
||||||
system: this.document.system,
|
system: this.document.system,
|
||||||
source: this.document.toObject(),
|
source: this.document.toObject(),
|
||||||
|
config: game.system.mournbladecyd2.config,
|
||||||
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||||
this.document.system.description || "", { async: true }
|
this.document.system.description || "", { async: true }
|
||||||
),
|
),
|
||||||
isEditMode: true,
|
isEditMode: this.isEditMode,
|
||||||
isEditable: this.isEditable,
|
isEditable: this.isEditable,
|
||||||
isGM: game.user.isGM,
|
isGM: game.user.isGM,
|
||||||
config: game.system.mournbladecyd2.config,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,4 +147,189 @@ export default class MournbladeCYD2ItemSheetV2 extends HandlebarsApplicationMixi
|
|||||||
preds.splice(idx, 1);
|
preds.splice(idx, 1);
|
||||||
await this.document.update({ "system.predilections": preds });
|
await this.document.update({ "system.predilections": preds });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static async #onAddAutomation(event) {
|
||||||
|
const automations = foundry.utils.duplicate(this.document.system.automations || []);
|
||||||
|
automations.push({
|
||||||
|
id: foundry.utils.randomID(),
|
||||||
|
eventtype: "on-drop",
|
||||||
|
name: "",
|
||||||
|
bonusname: "vigueur",
|
||||||
|
bonus: 0,
|
||||||
|
competence: "",
|
||||||
|
minLevel: 0,
|
||||||
|
baCost: 0
|
||||||
|
});
|
||||||
|
await this.document.update({
|
||||||
|
"system.automations": automations,
|
||||||
|
"system.isautomated": true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static async #onDeleteAutomation(event, target) {
|
||||||
|
const idx = Number(target.dataset.automationIndex);
|
||||||
|
const automations = foundry.utils.duplicate(this.document.system.automations || []);
|
||||||
|
automations.splice(idx, 1);
|
||||||
|
await this.document.update({ "system.automations": automations });
|
||||||
|
if (automations.length === 0) {
|
||||||
|
await this.document.update({ "system.isautomated": false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #region ActiveEffects Management
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un nouvel effet actif sur l'item
|
||||||
|
* @param {Event} event - Événement
|
||||||
|
* @param {HTMLElement} target - Éléments cible
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static async #onCreateEffect(event, target) {
|
||||||
|
event.preventDefault();
|
||||||
|
if (!this.isEditable || !this.document) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Créer les données par défaut pour un nouvel effet
|
||||||
|
const defaultEffectData = {
|
||||||
|
name: game.i18n.localize("MOURNBLADECYD2.EFFECT.new") || "Nouvel Effet",
|
||||||
|
icon: "systems/fvtt-mournblade-cyd-2-0/assets/icons/capacite.webp",
|
||||||
|
description: "",
|
||||||
|
changes: [],
|
||||||
|
disabled: false,
|
||||||
|
duration: {},
|
||||||
|
origin: this.document.uuid,
|
||||||
|
tint: "",
|
||||||
|
transfer: false,
|
||||||
|
flags: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Créer directement l'effet actif sur l'item
|
||||||
|
const [effect] = await this.document.createEmbeddedDocuments("ActiveEffect", [defaultEffectData]);
|
||||||
|
|
||||||
|
if (effect) {
|
||||||
|
// Ouvrir la feuille d'édition de l'effet
|
||||||
|
effect.sheet.render(true);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("MournbladeCYD2 | Failed to create effect:", error);
|
||||||
|
ui.notifications.error(
|
||||||
|
game.i18n.localize("MOURNBLADECYD2.EFFECT.createError") ||
|
||||||
|
"Erreur lors de la création de l'effet"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Édite un effet actif existant sur l'item
|
||||||
|
* @param {Event} event - Événement
|
||||||
|
* @param {HTMLElement} target - Éléments cible
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static async #onEditEffect(event, target) {
|
||||||
|
event.preventDefault();
|
||||||
|
if (!this.isEditable || !this.document) return;
|
||||||
|
|
||||||
|
const effectId = target?.dataset?.effectId;
|
||||||
|
if (!effectId) return;
|
||||||
|
|
||||||
|
const effect = this.document.effects.get(effectId);
|
||||||
|
if (effect) {
|
||||||
|
// Ouvrir la sheet de l'effet pour édition
|
||||||
|
effect.sheet.render(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supprime un effet actif de l'item
|
||||||
|
* @param {Event} event - Événement
|
||||||
|
* @param {HTMLElement} target - Éléments cible
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static async #onDeleteEffect(event, target) {
|
||||||
|
event.preventDefault();
|
||||||
|
if (!this.isEditable || !this.document) return;
|
||||||
|
|
||||||
|
const effectId = target?.dataset?.effectId;
|
||||||
|
if (!effectId) return;
|
||||||
|
|
||||||
|
const effect = this.document.effects.get(effectId);
|
||||||
|
if (effect) {
|
||||||
|
const effectName = effect.name;
|
||||||
|
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||||
|
title: game.i18n.localize("MOURNBLADECYD2.EFFECT.deleteConfirm") || "Supprimer l'effet",
|
||||||
|
content: game.i18n.localize("MOURNBLADECYD2.EFFECT.deleteConfirmText", {name: effectName}) ||
|
||||||
|
`Êtes-vous sûr de vouloir supprimer l'effet "${effectName}" ?`
|
||||||
|
});
|
||||||
|
|
||||||
|
if (confirmed) {
|
||||||
|
try {
|
||||||
|
await this.document.deleteEmbeddedDocuments("ActiveEffect", [effectId]);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("MournbladeCYD2 | Failed to delete effect:", error);
|
||||||
|
ui.notifications.error(
|
||||||
|
game.i18n.localize("MOURNBLADECYD2.EFFECT.deleteError") ||
|
||||||
|
"Erreur lors de la suppression de l'effet"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle l'état actif/désactivé d'un effet sur l'item
|
||||||
|
* @param {Event} event - Événement
|
||||||
|
* @param {HTMLElement} target - Éléments cible
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static async #onToggleEffect(event, target) {
|
||||||
|
event.preventDefault();
|
||||||
|
if (!this.isEditable || !this.document) return;
|
||||||
|
|
||||||
|
const effectId = target?.dataset?.effectId;
|
||||||
|
if (!effectId) return;
|
||||||
|
|
||||||
|
const effect = this.document.effects.get(effectId);
|
||||||
|
if (effect) {
|
||||||
|
try {
|
||||||
|
await effect.update({ disabled: !effect.disabled });
|
||||||
|
} catch (error) {
|
||||||
|
console.error("MournbladeCYD2 | Failed to toggle effect:", error);
|
||||||
|
ui.notifications.error(
|
||||||
|
game.i18n.localize("MOURNBLADECYD2.EFFECT.toggleError") ||
|
||||||
|
"Erreur lors du basculement de l'effet"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applique un effet à partir de l'item à un acteur sélectionné
|
||||||
|
* Cette méthode n'est pas directement utilisable sans acteur cible
|
||||||
|
* Elle est gardée pour compatibilité mais devrait être appelée avec un acteur
|
||||||
|
* @param {Event} event - Événement
|
||||||
|
* @param {HTMLElement} target - Éléments cible
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static async #onApplyEffect(event, target) {
|
||||||
|
event.preventDefault();
|
||||||
|
if (!this.isEditable) return;
|
||||||
|
|
||||||
|
const effectId = target?.dataset?.effectId;
|
||||||
|
if (!effectId || !this.document) return;
|
||||||
|
|
||||||
|
const effect = this.document.effects.get(effectId);
|
||||||
|
if (!effect) return;
|
||||||
|
|
||||||
|
// Pour appliquer un effet d'item, il faut sélectionner un acteur
|
||||||
|
// Cette méthode est placeholders - l'application devrait être gérée par drag-drop
|
||||||
|
// ou par une action spécifique qui demande à l'utilisateur de sélectionner un acteur
|
||||||
|
ui.notifications.warn(
|
||||||
|
game.i18n.localize("MOURNBLADECYD2.EFFECT.selectActor") ||
|
||||||
|
"Veuillez d'abord sélectionner un acteur pour appliquer cet effet."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// #endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import MournbladeCYD2ItemSheetV2 from "./base-item-sheet.mjs";
|
||||||
|
|
||||||
|
export default class MournbladeCYD2CapaciteAutomataSheet extends MournbladeCYD2ItemSheetV2 {
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
...super.DEFAULT_OPTIONS,
|
||||||
|
classes: [...super.DEFAULT_OPTIONS.classes, "capaciteautomata"],
|
||||||
|
window: {
|
||||||
|
...super.DEFAULT_OPTIONS.window,
|
||||||
|
title: "SHEETS.Item.capaciteautomata",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static PARTS = {
|
||||||
|
main: {
|
||||||
|
template: "systems/fvtt-mournblade-cyd-2-0/templates/item-capaciteautomata-sheet.hbs",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _prepareContext() {
|
||||||
|
const context = await super._prepareContext();
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,6 +30,8 @@ export default class MournbladeCYD2CreatureSheet extends MournbladeCYD2ActorShee
|
|||||||
|
|
||||||
context.skills = actor.getSkills?.() ?? [];
|
context.skills = actor.getSkills?.() ?? [];
|
||||||
context.combativiteList = MournbladeCYD2Utility.getCombativiteList(actor.system.sante?.nbcombativite || 0);
|
context.combativiteList = MournbladeCYD2Utility.getCombativiteList(actor.system.sante?.nbcombativite || 0);
|
||||||
|
context.ameList = MournbladeCYD2Utility.getAmeList(actor.system.ame.nbame, actor.getAmeMax?.() ?? 0);
|
||||||
|
context.ameMaxList = MournbladeCYD2Utility.getAmeMaxList(actor.system.ame.nbame);
|
||||||
context.armes = foundry.utils.duplicate(actor.getWeapons?.() ?? []);
|
context.armes = foundry.utils.duplicate(actor.getWeapons?.() ?? []);
|
||||||
context.protections = foundry.utils.duplicate(actor.getArmors?.() ?? []);
|
context.protections = foundry.utils.duplicate(actor.getArmors?.() ?? []);
|
||||||
context.runes = foundry.utils.duplicate(actor.getRunes?.() ?? []);
|
context.runes = foundry.utils.duplicate(actor.getRunes?.() ?? []);
|
||||||
@@ -37,9 +39,16 @@ export default class MournbladeCYD2CreatureSheet extends MournbladeCYD2ActorShee
|
|||||||
context.equipements = foundry.utils.duplicate(actor.getEquipments?.() ?? []);
|
context.equipements = foundry.utils.duplicate(actor.getEquipments?.() ?? []);
|
||||||
context.monnaies = foundry.utils.duplicate(actor.getMonnaies?.() ?? []);
|
context.monnaies = foundry.utils.duplicate(actor.getMonnaies?.() ?? []);
|
||||||
context.talents = foundry.utils.duplicate(actor.getTalents?.() ?? []);
|
context.talents = foundry.utils.duplicate(actor.getTalents?.() ?? []);
|
||||||
|
context.traitsChaotiques = foundry.utils.duplicate(actor.getTraitsChaotiques?.() ?? []);
|
||||||
|
context.traitsEspeces = foundry.utils.duplicate(actor.getTraitsEspeces?.() ?? []);
|
||||||
context.protectionTotal = actor.getProtectionTotal?.() ?? 0;
|
context.protectionTotal = actor.getProtectionTotal?.() ?? 0;
|
||||||
context.adversiteTotal = (actor.system.adversite?.bleue || 0) + (actor.system.adversite?.rouge || 0) + (actor.system.adversite?.noire || 0);
|
context.adversiteTotal = (actor.system.adversite?.bleue || 0) + (actor.system.adversite?.rouge || 0) + (actor.system.adversite?.noire || 0);
|
||||||
context.initiative = context.combat?.initTotal ?? 0;
|
|
||||||
|
// Utiliser les valeurs manuelles si elles existent, sinon les valeurs calculées
|
||||||
|
context.initiative = actor.system.combat?.inittotal !== undefined ? actor.system.combat.inittotal : (context.combat?.initTotal ?? 0);
|
||||||
|
context.combat.defenseTotal = actor.system.combat?.defensetotal !== undefined ? actor.system.combat.defensetotal : context.combat.defenseTotal;
|
||||||
|
context.protectionTotal = actor.system.combat?.protectiontotal !== undefined ? actor.system.combat.protectiontotal : context.protectionTotal;
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ export default class MournbladeCYD2DonSheet extends MournbladeCYD2ItemSheetV2 {
|
|||||||
/** @override */
|
/** @override */
|
||||||
async _prepareContext() {
|
async _prepareContext() {
|
||||||
const context = await super._prepareContext();
|
const context = await super._prepareContext();
|
||||||
|
context.owner = this.document.isOwner;
|
||||||
|
context.editable = this.isEditable;
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import MournbladeCYD2ItemSheetV2 from "./base-item-sheet.mjs";
|
||||||
|
|
||||||
|
export default class MournbladeCYD2PouvoirElementaireSheet extends MournbladeCYD2ItemSheetV2 {
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
...super.DEFAULT_OPTIONS,
|
||||||
|
classes: [...super.DEFAULT_OPTIONS.classes, "pouvoirselementaire"],
|
||||||
|
window: {
|
||||||
|
...super.DEFAULT_OPTIONS.window,
|
||||||
|
title: "SHEETS.Item.pouvoirselementaire",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static PARTS = {
|
||||||
|
main: {
|
||||||
|
template: "systems/fvtt-mournblade-cyd-2-0/templates/item-pouvoirselementaire-sheet.hbs",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _prepareContext() {
|
||||||
|
const context = await super._prepareContext();
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import MournbladeCYD2ItemSheetV2 from "./base-item-sheet.mjs";
|
||||||
|
|
||||||
|
export default class MournbladeCYD2TraitDemoniaqueSheet extends MournbladeCYD2ItemSheetV2 {
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
...super.DEFAULT_OPTIONS,
|
||||||
|
classes: [...super.DEFAULT_OPTIONS.classes, "traitdemoniaque"],
|
||||||
|
window: {
|
||||||
|
...super.DEFAULT_OPTIONS.window,
|
||||||
|
title: "SHEETS.Item.traitdemoniaque",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static PARTS = {
|
||||||
|
main: {
|
||||||
|
template: "systems/fvtt-mournblade-cyd-2-0/templates/item-traitdemoniaque-sheet.hbs",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _prepareContext() {
|
||||||
|
const context = await super._prepareContext();
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* Data model pour les capacités d'Automata MournbladeCYD2
|
||||||
|
*/
|
||||||
|
export default class CapaciteAutomataDataModel extends foundry.abstract.TypeDataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields;
|
||||||
|
return {
|
||||||
|
description: new fields.HTMLField({ initial: "" }),
|
||||||
|
bonusmalus: new fields.StringField({ initial: "" })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -88,12 +88,15 @@ export default class CreatureDataModel extends foundry.abstract.TypeDataModel {
|
|||||||
}),
|
}),
|
||||||
combat: new fields.SchemaField({
|
combat: new fields.SchemaField({
|
||||||
initbonus: new fields.NumberField({ initial: 0, integer: true }),
|
initbonus: new fields.NumberField({ initial: 0, integer: true }),
|
||||||
|
inittotal: new fields.NumberField({ initial: 0, integer: true }),
|
||||||
vitessebonus: new fields.NumberField({ initial: 0, integer: true }),
|
vitessebonus: new fields.NumberField({ initial: 0, integer: true }),
|
||||||
bonusdegats: new fields.NumberField({ initial: 0, integer: true }),
|
bonusdegats: new fields.NumberField({ initial: 0, integer: true }),
|
||||||
attaquebonus: new fields.NumberField({ initial: 0, integer: true }),
|
attaquebonus: new fields.NumberField({ initial: 0, integer: true }),
|
||||||
defensebonus: new fields.NumberField({ initial: 0, integer: true }),
|
defensebonus: new fields.NumberField({ initial: 0, integer: true }),
|
||||||
|
defensetotal: new fields.NumberField({ initial: 0, integer: true }),
|
||||||
defensetotale: new fields.BooleanField({ initial: false }),
|
defensetotale: new fields.BooleanField({ initial: false }),
|
||||||
monte: new fields.BooleanField({ initial: false })
|
monte: new fields.BooleanField({ initial: false }),
|
||||||
|
protectiontotal: new fields.NumberField({ initial: 0, integer: true })
|
||||||
}),
|
}),
|
||||||
balance: new fields.SchemaField({
|
balance: new fields.SchemaField({
|
||||||
loi: new fields.NumberField({ initial: 0, integer: true }),
|
loi: new fields.NumberField({ initial: 0, integer: true }),
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ export { default as RuneEffectDataModel } from './runeeffect.mjs';
|
|||||||
export { default as TendanceDataModel } from './tendance.mjs';
|
export { default as TendanceDataModel } from './tendance.mjs';
|
||||||
export { default as TraitChaotiqueDataModel } from './traitchaotique.mjs';
|
export { default as TraitChaotiqueDataModel } from './traitchaotique.mjs';
|
||||||
export { default as TraitEspeceDataModel } from './traitespece.mjs';
|
export { default as TraitEspeceDataModel } from './traitespece.mjs';
|
||||||
|
export { default as TraitDemoniaqueDataModel } from './traitdemoniaque.mjs';
|
||||||
|
export { default as PouvoirElementaireDataModel } from './pouvoirselementaire.mjs';
|
||||||
|
export { default as CapaciteAutomataDataModel } from './capaciteautomata.mjs';
|
||||||
|
|
||||||
// Modèles d'acteurs
|
// Modèles d'acteurs
|
||||||
export { default as PersonnageDataModel } from './personnage.mjs';
|
export { default as PersonnageDataModel } from './personnage.mjs';
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* Data model pour les pouvoirs élémentaires MournbladeCYD2
|
||||||
|
*/
|
||||||
|
export default class PouvoirElementaireDataModel extends foundry.abstract.TypeDataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields;
|
||||||
|
return {
|
||||||
|
description: new fields.HTMLField({ initial: "" }),
|
||||||
|
bonusmalus: new fields.StringField({ initial: "" })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,7 +9,8 @@ export default class RuneDataModel extends foundry.abstract.TypeDataModel {
|
|||||||
formule: new fields.StringField({ initial: "" }),
|
formule: new fields.StringField({ initial: "" }),
|
||||||
seuil: new fields.NumberField({ initial: 0, integer: true }),
|
seuil: new fields.NumberField({ initial: 0, integer: true }),
|
||||||
prononcee: new fields.StringField({ initial: "" }),
|
prononcee: new fields.StringField({ initial: "" }),
|
||||||
tracee: new fields.StringField({ initial: "" })
|
tracee: new fields.StringField({ initial: "" }),
|
||||||
|
coutAme: new fields.StringField({ initial: "" })
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ export default class TendanceDataModel extends foundry.abstract.TypeDataModel {
|
|||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
return {
|
return {
|
||||||
description: new fields.HTMLField({ initial: "" }),
|
description: new fields.HTMLField({ initial: "" }),
|
||||||
allegeance: new fields.StringField({ initial: "" })
|
allegeance: new fields.StringField({ initial: "" }),
|
||||||
|
donlie: new fields.StringField({ initial: "" })
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ export default class TraitChaotiqueDataModel extends foundry.abstract.TypeDataMo
|
|||||||
static defineSchema() {
|
static defineSchema() {
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
return {
|
return {
|
||||||
description: new fields.HTMLField({ initial: "" })
|
description: new fields.HTMLField({ initial: "" }),
|
||||||
|
bonusmalus: new fields.StringField({ initial: "" })
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* Data model pour les traits démoniaques MournbladeCYD2
|
||||||
|
*/
|
||||||
|
export default class TraitDemoniaqueDataModel extends foundry.abstract.TypeDataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields;
|
||||||
|
return {
|
||||||
|
description: new fields.HTMLField({ initial: "" }),
|
||||||
|
bonusmalus: new fields.StringField({ initial: "" })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,8 @@ export default class TraitEspeceDataModel extends foundry.abstract.TypeDataModel
|
|||||||
static defineSchema() {
|
static defineSchema() {
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
return {
|
return {
|
||||||
description: new fields.HTMLField({ initial: "" })
|
description: new fields.HTMLField({ initial: "" }),
|
||||||
|
bonusmalus: new fields.StringField({ initial: "" })
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
const localizeOrFallback = (key, fallback) => globalThis.game?.i18n?.localize?.(key) ?? fallback
|
||||||
|
|
||||||
export const MOURNBLADECYD2_CONFIG = {
|
export const MOURNBLADECYD2_CONFIG = {
|
||||||
attributs: {
|
attributs: {
|
||||||
adr: "Adresse",
|
adr: "Adresse",
|
||||||
@@ -7,19 +9,20 @@ export const MOURNBLADECYD2_CONFIG = {
|
|||||||
tre: "Trempe"
|
tre: "Trempe"
|
||||||
},
|
},
|
||||||
allegeanceOptions: {
|
allegeanceOptions: {
|
||||||
tous: 'Tous',
|
tous: localizeOrFallback("MNBL.all", "Tous"),
|
||||||
chaos: 'Chaos',
|
chaos: localizeOrFallback("MNBL.chaos", "Chaos"),
|
||||||
loi: 'Loi',
|
loi: localizeOrFallback("MNBL.law", "Loi"),
|
||||||
betes: 'Seigneurs des Bêtes',
|
balance: localizeOrFallback("MNBL.balance", "Balance"),
|
||||||
elementaires: 'Seigneurs des Eléments'
|
betes: localizeOrFallback("MNBL.beastslords", "Seigneurs des Bêtes"),
|
||||||
|
elementaires: localizeOrFallback("MNBL.elementslords", "Seigneurs des Éléments")
|
||||||
},
|
},
|
||||||
lancementRuneOptions: {
|
lancementRuneOptions: {
|
||||||
prononcer: 'Prononcer',
|
prononcer: localizeOrFallback("MNBL.pronouncerune", "Prononcer"),
|
||||||
inscrire: 'Tracer'
|
inscrire: localizeOrFallback("MNBL.tracerune", "Tracer")
|
||||||
},
|
},
|
||||||
effetRuneOptions: {
|
effetRuneOptions: {
|
||||||
prononcee: 'Prononcée',
|
prononcee: localizeOrFallback("MNBL.pronounced", "Prononcée"),
|
||||||
inscrite: 'Inscrite'
|
inscrite: localizeOrFallback("MNBL.traced", "Tracée")
|
||||||
},
|
},
|
||||||
|
|
||||||
optionsDifficulte: [
|
optionsDifficulte: [
|
||||||
@@ -116,6 +119,96 @@ export const MOURNBLADECYD2_CONFIG = {
|
|||||||
{ key: "personnage", label: "Personnage" },
|
{ key: "personnage", label: "Personnage" },
|
||||||
{ key: "traitespece", label: "Trait d'espèce" }
|
{ key: "traitespece", label: "Trait d'espèce" }
|
||||||
],
|
],
|
||||||
|
|
||||||
|
// Configuration des ActiveEffects
|
||||||
|
effectTypes: {
|
||||||
|
bonus: "Bonus",
|
||||||
|
malus: "Malus",
|
||||||
|
rune: "Effet de Rune",
|
||||||
|
don: "Effet de Don",
|
||||||
|
talent: "Effet de Talent",
|
||||||
|
trait: "Effet de Trait",
|
||||||
|
temporaire: "Effet Temporaire",
|
||||||
|
permanent: "Effet Permanent"
|
||||||
|
},
|
||||||
|
|
||||||
|
// Clés des attributs pour les modifications d'effets
|
||||||
|
effectAttributeKeys: {
|
||||||
|
// Attributs
|
||||||
|
adr: "system.attributs.adr.value",
|
||||||
|
pui: "system.attributs.pui.value",
|
||||||
|
cla: "system.attributs.cla.value",
|
||||||
|
pre: "system.attributs.pre.value",
|
||||||
|
tre: "system.attributs.tre.value",
|
||||||
|
|
||||||
|
// Santé
|
||||||
|
vigueur: "system.sante.vigueur",
|
||||||
|
etat: "system.sante.etat",
|
||||||
|
nbcombativite: "system.sante.nbcombativite",
|
||||||
|
|
||||||
|
// Âme
|
||||||
|
nbame: "system.ame.nbame",
|
||||||
|
seuilpouvoir: "system.ame.seuilpouvoir",
|
||||||
|
etatAme: "system.ame.etat",
|
||||||
|
|
||||||
|
// Bonne Aventure
|
||||||
|
bonneaventure: "system.bonneaventure.base",
|
||||||
|
bonneaventureActuelle: "system.bonneaventure.actuelle",
|
||||||
|
eclat: "system.eclat.value",
|
||||||
|
|
||||||
|
// Combat
|
||||||
|
initiative: "system.combat.inittotal",
|
||||||
|
defense: "system.combat.defensetotal",
|
||||||
|
protection: "system.combat.protectiontotal",
|
||||||
|
|
||||||
|
// Adversités
|
||||||
|
adversiteBleue: "system.adversite.bleue",
|
||||||
|
adversiteRouge: "system.adversite.rouge",
|
||||||
|
adversiteNoire: "system.adversite.noire",
|
||||||
|
|
||||||
|
// Balance
|
||||||
|
loi: "system.balance.loi",
|
||||||
|
chaos: "system.balance.chaos",
|
||||||
|
aspect: "system.balance.aspect",
|
||||||
|
|
||||||
|
// Ressources
|
||||||
|
ressources: "system.ressources.value",
|
||||||
|
|
||||||
|
// Vitesse
|
||||||
|
vitesse: "system.vitesse.value"
|
||||||
|
},
|
||||||
|
|
||||||
|
// Types de bonus/malus supportés (groupés par catégorie)
|
||||||
|
effectTypesConfig: {
|
||||||
|
attribut: {
|
||||||
|
label: "Attribut",
|
||||||
|
keys: ["adr", "pui", "cla", "pre", "tre"]
|
||||||
|
},
|
||||||
|
sante: {
|
||||||
|
label: "Santé",
|
||||||
|
keys: ["vigueur", "etat", "nbcombativite"]
|
||||||
|
},
|
||||||
|
ame: {
|
||||||
|
label: "Âme",
|
||||||
|
keys: ["nbame", "seuilpouvoir", "etatAme"]
|
||||||
|
},
|
||||||
|
combat: {
|
||||||
|
label: "Combat",
|
||||||
|
keys: ["initiative", "defense", "protection"]
|
||||||
|
},
|
||||||
|
bonneAventure: {
|
||||||
|
label: "Bonne Aventure",
|
||||||
|
keys: ["bonneaventure", "bonneaventureActuelle", "eclat"]
|
||||||
|
},
|
||||||
|
adversite: {
|
||||||
|
label: "Adversité",
|
||||||
|
keys: ["adversiteBleue", "adversiteRouge", "adversiteNoire"]
|
||||||
|
},
|
||||||
|
balance: {
|
||||||
|
label: "Balance",
|
||||||
|
keys: ["loi", "chaos", "aspect"]
|
||||||
|
}
|
||||||
|
},
|
||||||
optionsUseTalent: [
|
optionsUseTalent: [
|
||||||
{ key: "permanent", label: "Permanent" },
|
{ key: "permanent", label: "Permanent" },
|
||||||
{ key: "sceance", label: "Une fois par scéance" },
|
{ key: "sceance", label: "Une fois par scéance" },
|
||||||
|
|||||||
@@ -0,0 +1,807 @@
|
|||||||
|
/**
|
||||||
|
* Gestion des ActiveEffects pour Mournblade CYD 2.0
|
||||||
|
* Ce module fournit des utilitaires pour créer, appliquer et gérer les effets actifs
|
||||||
|
* sur les Acteurs et les Items.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class MournbladeCYD2Effects {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise le système de gestion des effets
|
||||||
|
*/
|
||||||
|
static init() {
|
||||||
|
console.log("MournbladeCYD2 | Initializing ActiveEffects management");
|
||||||
|
|
||||||
|
// Hook pour appliquer les modifications des effets
|
||||||
|
Hooks.on("applyActiveEffect", (effect, change, current, delta, changes) => {
|
||||||
|
return this._onApplyActiveEffect(effect, change, current, delta, changes);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Hook pour supprimer les modifications des effets
|
||||||
|
Hooks.on("removeActiveEffect", (effect, change, current, delta, changes) => {
|
||||||
|
return this._onRemoveActiveEffect(effect, change, current, delta, changes);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse une valeur d'effet en nombre
|
||||||
|
* Gère les strings comme "+2", "-3", "5"
|
||||||
|
* @param {string|number} value - Valeur à parser
|
||||||
|
* @returns {number} - Valeur numérique
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static _parseEffectValue(value) {
|
||||||
|
if (typeof value === 'number') return value;
|
||||||
|
if (typeof value !== 'string') return 0;
|
||||||
|
|
||||||
|
const trimmed = value.trim();
|
||||||
|
if (!trimmed) return 0;
|
||||||
|
|
||||||
|
if (trimmed.startsWith('+')) {
|
||||||
|
return parseFloat(trimmed.substring(1)) || 0;
|
||||||
|
} else if (trimmed.startsWith('-')) {
|
||||||
|
return -(parseFloat(trimmed.substring(1)) || 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parseFloat(trimmed) || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook appelé lorsqu'un effet est appliqué
|
||||||
|
* Permet de personnaliser le calcul des modifications
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static _onApplyActiveEffect(effect, change, current, delta, changes) {
|
||||||
|
// Pour Mournblade, nous voulons gérer les valeurs string (ex: "+1", "-2")
|
||||||
|
// Convertir delta en nombre si nécessaire
|
||||||
|
const numericDelta = this._parseEffectValue(delta);
|
||||||
|
const numericCurrent = current != null ? Number(current) : 0;
|
||||||
|
|
||||||
|
if (!isNaN(numericDelta) && !isNaN(numericCurrent)) {
|
||||||
|
return numericCurrent + numericDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si on ne peut pas calculer, retourner delta tel quel
|
||||||
|
return delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook appelé lorsqu'un effet est supprimé
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static _onRemoveActiveEffect(effect, change, current, delta, changes) {
|
||||||
|
// Logique inverse de l'application
|
||||||
|
// Foundry gère déjà la suppression, ce hook est pour des calculs personnalisés
|
||||||
|
const numericDelta = this._parseEffectValue(delta);
|
||||||
|
const numericCurrent = current != null ? Number(current) : 0;
|
||||||
|
|
||||||
|
if (!isNaN(numericDelta) && !isNaN(numericCurrent)) {
|
||||||
|
return numericCurrent - numericDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/* Méthodes de création d'effets */
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un effet simple de bonus/malus à un attribut
|
||||||
|
* @param {string} name - Nom de l'effet
|
||||||
|
* @param {string} attribute - Attribut cible (adr, pui, cla, pre, tre, vigueur, etc.)
|
||||||
|
* @param {number|string} value - Valeur du bonus/malus
|
||||||
|
* @param {object} options - Options supplémentaires
|
||||||
|
* @returns {Object|null} - Données de l'effet ou null
|
||||||
|
*/
|
||||||
|
static createSimpleEffect(name, attribute, value, options = {}) {
|
||||||
|
// Validation des paramètres
|
||||||
|
if (!name || typeof name !== "string") {
|
||||||
|
console.warn("MournbladeCYD2 | Effect name must be a non-empty string");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value == null) {
|
||||||
|
console.warn("MournbladeCYD2 | Effect value cannot be null or undefined");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const attributeKey = this.getAttributeKey(attribute);
|
||||||
|
if (!attributeKey) {
|
||||||
|
console.warn(`MournbladeCYD2 | Unknown attribute: ${attribute}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normaliser la valeur en string
|
||||||
|
const valueString = String(value).trim();
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: name.trim(),
|
||||||
|
icon: options.icon || "systems/fvtt-mournblade-cyd-2-0/assets/icons/capacite.webp",
|
||||||
|
description: (options.description || "").trim(),
|
||||||
|
changes: [
|
||||||
|
{
|
||||||
|
key: attributeKey,
|
||||||
|
mode: CONST.ActiveEffect.MODES.ADD,
|
||||||
|
value: valueString,
|
||||||
|
priority: options.priority ?? 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
disabled: Boolean(options.disabled),
|
||||||
|
duration: options.duration || {},
|
||||||
|
origin: options.origin || null,
|
||||||
|
tint: options.tint || "",
|
||||||
|
transfer: options.transfer !== false,
|
||||||
|
statuses: options.statuses || [],
|
||||||
|
flags: options.flags || {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un effet de bonus permanent
|
||||||
|
* @param {string} name - Nom de l'effet
|
||||||
|
* @param {string} attribute - Attribut cible
|
||||||
|
* @param {number|string} value - Valeur du bonus
|
||||||
|
* @returns {Object} - Données de l'effet
|
||||||
|
*/
|
||||||
|
static createPermanentEffect(name, attribute, value) {
|
||||||
|
return this.createSimpleEffect(name, attribute, value, {
|
||||||
|
duration: {},
|
||||||
|
type: "base"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un effet temporaire (rounds, turns, etc.)
|
||||||
|
* @param {string} name - Nom de l'effet
|
||||||
|
* @param {string} attribute - Attribut cible
|
||||||
|
* @param {number|string} value - Valeur du bonus/malus
|
||||||
|
* @param {string} durationType - Type de durée (rounds, turns, seconds, combat)
|
||||||
|
* @param {number} durationValue - Valeur de la durée
|
||||||
|
* @returns {Object} - Données de l'effet
|
||||||
|
*/
|
||||||
|
static createTemporaryEffect(name, attribute, value, durationType, durationValue) {
|
||||||
|
return this.createSimpleEffect(name, attribute, value, {
|
||||||
|
duration: { type: durationType, value: durationValue },
|
||||||
|
type: "temp"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un effet avec plusieurs modifications
|
||||||
|
* @param {string} name - Nom de l'effet
|
||||||
|
* @param {Array} changes - Array de modifications {key, mode, value}
|
||||||
|
* @param {object} options - Options supplémentaires
|
||||||
|
* @returns {Object} - Données de l'effet
|
||||||
|
*/
|
||||||
|
static createMultiEffect(name, changes, options = {}) {
|
||||||
|
return {
|
||||||
|
name: name,
|
||||||
|
icon: options.icon || "systems/fvtt-mournblade-cyd-2-0/assets/icons/capacite.webp",
|
||||||
|
description: options.description || "",
|
||||||
|
changes: changes.map(c => ({
|
||||||
|
key: c.key,
|
||||||
|
mode: c.mode || CONST.ActiveEffect.MODES.ADD,
|
||||||
|
value: c.value.toString(),
|
||||||
|
priority: c.priority || 0
|
||||||
|
})),
|
||||||
|
disabled: options.disabled || false,
|
||||||
|
duration: options.duration || {},
|
||||||
|
origin: options.origin || null,
|
||||||
|
tint: options.tint || "",
|
||||||
|
transfer: options.transfer !== false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/* Méthodes d'application d'effets */
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applique un effet à un acteur
|
||||||
|
* @param {Actor} actor - L'acteur cible
|
||||||
|
* @param {Object|ActiveEffect} effectData - Données de l'effet ou instance ActiveEffect
|
||||||
|
* @returns {Promise<ActiveEffect|null>} - L'effet créé ou null
|
||||||
|
*/
|
||||||
|
static async applyEffectToActor(actor, effectData) {
|
||||||
|
if (!actor || !actor.canUserModify(game.user, "update")) return null;
|
||||||
|
|
||||||
|
let effect;
|
||||||
|
if (effectData instanceof foundry.documents.ActiveEffect) {
|
||||||
|
effect = effectData;
|
||||||
|
} else if (effectData?.toObject) {
|
||||||
|
effect = effectData;
|
||||||
|
} else {
|
||||||
|
effect = new CONFIG.ActiveEffect.documentClass(effectData);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const createdEffects = await actor.createEmbeddedDocuments("ActiveEffect", [effect.toObject()]);
|
||||||
|
return createdEffects[0];
|
||||||
|
} catch (error) {
|
||||||
|
console.error("MournbladeCYD2 | Failed to apply effect:", error);
|
||||||
|
ui.notifications?.error(
|
||||||
|
game.i18n?.localize("MOURNBLADECYD2.EFFECT.applyError") ||
|
||||||
|
`Erreur: Impossible d'appliquer l'effet (${error.message})`
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applique les effets d'un item à un acteur
|
||||||
|
* @param {Item} item - L'item source
|
||||||
|
* @param {Actor} actor - L'acteur cible
|
||||||
|
* @returns {Promise<Array<ActiveEffect>>} - Liste des effets appliqués
|
||||||
|
*/
|
||||||
|
static async applyItemEffectsToActor(item, actor) {
|
||||||
|
if (!item?.effects?.length || !actor) return [];
|
||||||
|
if (!actor.canUserModify(game.user, "update")) return [];
|
||||||
|
|
||||||
|
const effectsToApply = [];
|
||||||
|
for (const effectData of item.effects) {
|
||||||
|
// Par défaut, appliquer automatiquement SAUF si explicitement désactivé
|
||||||
|
const autoApply = effectData.getFlag("mournblade-cyd2", "autoApply");
|
||||||
|
if (autoApply !== false) {
|
||||||
|
effectsToApply.push({
|
||||||
|
...effectData.toObject(),
|
||||||
|
origin: item.uuid,
|
||||||
|
name: `${item.name}: ${effectData.name}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (effectsToApply.length === 0) return [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
const createdEffects = await actor.createEmbeddedDocuments("ActiveEffect", effectsToApply);
|
||||||
|
return createdEffects;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("MournbladeCYD2 | Failed to apply item effects:", error);
|
||||||
|
ui.notifications?.error(
|
||||||
|
game.i18n?.localize("MOURNBLADECYD2.EFFECT.applyItemError") ||
|
||||||
|
`Erreur: Impossible d'appliquer les effets de l'item`
|
||||||
|
);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/* Méthodes de gestion d'effets */
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Désactive un effet
|
||||||
|
* @param {Actor|Item} owner - Le propriétaire de l'effet
|
||||||
|
* @param {string} effectId - ID de l'effet
|
||||||
|
* @returns {Promise<ActiveEffect|null>} - L'effet désactivé
|
||||||
|
*/
|
||||||
|
static async disableEffect(owner, effectId) {
|
||||||
|
if (!owner?.canUserModify(game.user, "update")) return null;
|
||||||
|
|
||||||
|
const effect = owner.effects.get(effectId);
|
||||||
|
if (!effect) return null;
|
||||||
|
|
||||||
|
await effect.update({ disabled: true });
|
||||||
|
return effect;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Active un effet
|
||||||
|
* @param {Actor|Item} owner - Le propriétaire de l'effet
|
||||||
|
* @param {string} effectId - ID de l'effet
|
||||||
|
* @returns {Promise<ActiveEffect|null>} - L'effet activé
|
||||||
|
*/
|
||||||
|
static async enableEffect(owner, effectId) {
|
||||||
|
if (!owner?.canUserModify(game.user, "update")) return null;
|
||||||
|
|
||||||
|
const effect = owner.effects.get(effectId);
|
||||||
|
if (!effect) return null;
|
||||||
|
|
||||||
|
await effect.update({ disabled: false });
|
||||||
|
return effect;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle l'état d'un effet (actif/désactivé)
|
||||||
|
* @param {Actor|Item} owner - Le propriétaire de l'effet
|
||||||
|
* @param {string} effectId - ID de l'effet
|
||||||
|
* @returns {Promise<ActiveEffect|null>} - L'effet togglé
|
||||||
|
*/
|
||||||
|
static async toggleEffect(owner, effectId) {
|
||||||
|
if (!owner?.canUserModify(game.user, "update")) return null;
|
||||||
|
|
||||||
|
const effect = owner.effects.get(effectId);
|
||||||
|
if (!effect) return null;
|
||||||
|
|
||||||
|
await effect.update({ disabled: !effect.disabled });
|
||||||
|
return effect;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supprime un effet
|
||||||
|
* @param {Actor|Item} owner - Le propriétaire de l'effet
|
||||||
|
* @param {string} effectId - ID de l'effet
|
||||||
|
* @returns {Promise<ActiveEffect|null>} - L'effet supprimé
|
||||||
|
*/
|
||||||
|
static async deleteEffect(owner, effectId) {
|
||||||
|
if (!owner?.canUserModify(game.user, "delete")) return null;
|
||||||
|
|
||||||
|
const effect = owner.effects.get(effectId);
|
||||||
|
if (!effect) return null;
|
||||||
|
|
||||||
|
await owner.deleteEmbeddedDocuments("ActiveEffect", [effectId]);
|
||||||
|
return effect;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/* Méthodes utilitaires */
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtient la clé complète pour un attribut
|
||||||
|
* @param {string} attribute - Attribut court (adr, pui, cla, pre, tre, vigueur, etc.)
|
||||||
|
* @returns {string|null} - Clé complète ou null
|
||||||
|
*/
|
||||||
|
static getAttributeKey(attribute) {
|
||||||
|
if (!attribute) return null;
|
||||||
|
|
||||||
|
const config = game.system.mournbladecyd2?.config;
|
||||||
|
if (!config?.effectAttributeKeys) return null;
|
||||||
|
|
||||||
|
// Normaliser en minuscules pour correspondre à la config
|
||||||
|
const normalizedAttribute = attribute.toLowerCase().trim();
|
||||||
|
return config.effectAttributeKeys[normalizedAttribute] || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtient tous les attributs modifiables
|
||||||
|
* @returns {Object} - Map des attributs courts vers les clés complètes
|
||||||
|
*/
|
||||||
|
static getAllAttributeKeys() {
|
||||||
|
const config = game.system.mournbladecyd2?.config;
|
||||||
|
return config?.effectAttributeKeys || {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtient les effets actifs d'un acteur
|
||||||
|
* @param {Actor} actor - L'acteur
|
||||||
|
* @returns {Array<ActiveEffect>} - Liste des effets actifs (non désactivés)
|
||||||
|
*/
|
||||||
|
static getActiveEffects(actor) {
|
||||||
|
if (!actor?.effects) return [];
|
||||||
|
return actor.effects.filter(e => !e.disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtient les effets désactivés d'un acteur
|
||||||
|
* @param {Actor} actor - L'acteur
|
||||||
|
* @returns {Array<ActiveEffect>} - Liste des effets désactivés
|
||||||
|
*/
|
||||||
|
static getDisabledEffects(actor) {
|
||||||
|
if (!actor?.effects) return [];
|
||||||
|
return actor.effects.filter(e => e.disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtient les effets par origine
|
||||||
|
* @param {Actor} actor - L'acteur
|
||||||
|
* @param {string} originUuid - UUID de l'origine
|
||||||
|
* @returns {Array<ActiveEffect>} - Liste des effets de cette origine
|
||||||
|
*/
|
||||||
|
static getEffectsByOrigin(actor, originUuid) {
|
||||||
|
if (!actor?.effects) return [];
|
||||||
|
return actor.effects.filter(e => e.origin === originUuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtient les effets temporaires en cours
|
||||||
|
* @param {Actor} actor - L'acteur
|
||||||
|
* @returns {Array<ActiveEffect>} - Liste des effets temporaires actifs
|
||||||
|
*/
|
||||||
|
static getActiveTemporaryEffects(actor) {
|
||||||
|
if (!actor?.effects) return [];
|
||||||
|
return actor.effects.filter(e => !e.disabled && e.duration?.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule la valeur totale des modifications pour une clé donnée
|
||||||
|
* @param {Actor} actor - L'acteur
|
||||||
|
* @param {string} key - Clé à vérifier
|
||||||
|
* @returns {number} - Somme des modifications
|
||||||
|
*/
|
||||||
|
static getTotalModificationForKey(actor, key) {
|
||||||
|
if (!actor?.effects) return 0;
|
||||||
|
|
||||||
|
let total = 0;
|
||||||
|
for (const effect of actor.effects) {
|
||||||
|
if (effect.disabled) continue;
|
||||||
|
|
||||||
|
for (const change of effect.changes || []) {
|
||||||
|
if (change.key === key && change.mode === CONST.ActiveEffect.MODES.ADD) {
|
||||||
|
total += Number(change.value) || 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtient toutes les modifications actives groupées par clé
|
||||||
|
* @param {Actor} actor - L'acteur
|
||||||
|
* @returns {Object} - Objet avec les clés et les valeurs totales
|
||||||
|
*/
|
||||||
|
static getAllActiveModifications(actor) {
|
||||||
|
if (!actor?.effects) return {};
|
||||||
|
|
||||||
|
const modifications = {};
|
||||||
|
|
||||||
|
for (const effect of actor.effects) {
|
||||||
|
if (effect.disabled) continue;
|
||||||
|
|
||||||
|
for (const change of effect.changes || []) {
|
||||||
|
if (!modifications[change.key]) {
|
||||||
|
modifications[change.key] = {
|
||||||
|
value: 0,
|
||||||
|
effects: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Appliquer selon le mode
|
||||||
|
const numericValue = Number(change.value) || 0;
|
||||||
|
switch (change.mode) {
|
||||||
|
case CONST.ActiveEffect.MODES.ADD:
|
||||||
|
modifications[change.key].value += numericValue;
|
||||||
|
break;
|
||||||
|
case CONST.ActiveEffect.MODES.OVERRIDE:
|
||||||
|
modifications[change.key].value = numericValue;
|
||||||
|
modifications[change.key].overridden = true;
|
||||||
|
break;
|
||||||
|
case CONST.ActiveEffect.MODES.MULTIPLY:
|
||||||
|
// Ne peut pas être additionné, stocké séparément
|
||||||
|
if (!modifications[change.key].multipliers) {
|
||||||
|
modifications[change.key].multipliers = [];
|
||||||
|
}
|
||||||
|
modifications[change.key].multipliers.push(numericValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
modifications[change.key].effects.push(effect.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return modifications;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/* Méthodes de création d'effets prédéfinis */
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un effet de bonus d'attribut
|
||||||
|
* @param {string} attribute - Attribut (adr, pui, cla, pre, tre)
|
||||||
|
* @param {number} value - Valeur du bonus
|
||||||
|
* @param {string} source - Source de l'effet
|
||||||
|
* @returns {Object} - Données de l'effet
|
||||||
|
*/
|
||||||
|
static createAttributeBonusEffect(attribute, value, source = "Effet") {
|
||||||
|
const attrNames = {
|
||||||
|
adr: "Adresse",
|
||||||
|
pui: "Puissance",
|
||||||
|
cla: "Clairvoyance",
|
||||||
|
pre: "Présence",
|
||||||
|
tre: "Trempe"
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.createSimpleEffect(
|
||||||
|
`${source}: Bonus de ${attrNames[attribute] || attribute}`,
|
||||||
|
attribute,
|
||||||
|
`+${value}`,
|
||||||
|
{
|
||||||
|
icon: "systems/fvtt-mournblade-cyd-2-0/assets/icons/attributs.webp",
|
||||||
|
type: "base"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un effet de malus d'attribut
|
||||||
|
* @param {string} attribute - Attribut
|
||||||
|
* @param {number} value - Valeur du malus (positif)
|
||||||
|
* @param {string} source - Source de l'effet
|
||||||
|
* @returns {Object} - Données de l'effet
|
||||||
|
*/
|
||||||
|
static createAttributeMalusEffect(attribute, value, source = "Effet") {
|
||||||
|
const attrNames = {
|
||||||
|
adr: "Adresse",
|
||||||
|
pui: "Puissance",
|
||||||
|
cla: "Clairvoyance",
|
||||||
|
pre: "Présence",
|
||||||
|
tre: "Trempe"
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.createSimpleEffect(
|
||||||
|
`${source}: Malus de ${attrNames[attribute] || attribute}`,
|
||||||
|
attribute,
|
||||||
|
`-${value}`,
|
||||||
|
{
|
||||||
|
icon: "systems/fvtt-mournblade-cyd-2-0/assets/icons/malus.webp",
|
||||||
|
type: "base"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un effet de bonus à la Vigueur
|
||||||
|
* @param {number} value - Valeur du bonus
|
||||||
|
* @param {string} source - Source de l'effet
|
||||||
|
* @returns {Object} - Données de l'effet
|
||||||
|
*/
|
||||||
|
static createVigueurBonusEffect(value, source = "Effet") {
|
||||||
|
return this.createSimpleEffect(
|
||||||
|
`${source}: Bonus de Vigueur`,
|
||||||
|
"vigueur",
|
||||||
|
`+${value}`,
|
||||||
|
{
|
||||||
|
icon: "systems/fvtt-mournblade-cyd-2-0/assets/icons/vigueur.webp",
|
||||||
|
type: "base"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un effet de bonus au Seuil de Pouvoir
|
||||||
|
* @param {number} value - Valeur du bonus
|
||||||
|
* @param {string} source - Source de l'effet
|
||||||
|
* @returns {Object} - Données de l'effet
|
||||||
|
*/
|
||||||
|
static createSeuilPouvoirBonusEffect(value, source = "Effet") {
|
||||||
|
return this.createSimpleEffect(
|
||||||
|
`${source}: Bonus au Seuil de Pouvoir`,
|
||||||
|
"seuilPouvoir",
|
||||||
|
`+${value}`,
|
||||||
|
{
|
||||||
|
icon: "systems/fvtt-mournblade-cyd-2-0/assets/icons/ame.webp",
|
||||||
|
type: "base"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un effet de bonus à la Bonne Aventure
|
||||||
|
* @param {number} value - Valeur du bonus
|
||||||
|
* @param {string} source - Source de l'effet
|
||||||
|
* @returns {Object} - Données de l'effet
|
||||||
|
*/
|
||||||
|
static createBonneAventureBonusEffect(value, source = "Effet") {
|
||||||
|
return this.createSimpleEffect(
|
||||||
|
`${source}: Bonus de Bonne Aventure`,
|
||||||
|
"bonneAventure",
|
||||||
|
`+${value}`,
|
||||||
|
{
|
||||||
|
icon: "systems/fvtt-mournblade-cyd-2-0/assets/icons/bonneaventure.webp",
|
||||||
|
type: "base"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un effet de bonus à l'Initiative
|
||||||
|
* @param {number} value - Valeur du bonus
|
||||||
|
* @param {string} source - Source de l'effet
|
||||||
|
* @returns {Object} - Données de l'effet
|
||||||
|
*/
|
||||||
|
static createInitiativeBonusEffect(value, source = "Effet") {
|
||||||
|
return this.createSimpleEffect(
|
||||||
|
`${source}: Bonus d'Initiative`,
|
||||||
|
"initiative",
|
||||||
|
`+${value}`,
|
||||||
|
{
|
||||||
|
icon: "systems/fvtt-mournblade-cyd-2-0/assets/icons/initiative.webp",
|
||||||
|
type: "temp",
|
||||||
|
duration: { type: "rounds", value: 1 }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un effet de bonus à la Défense
|
||||||
|
* @param {number} value - Valeur du bonus
|
||||||
|
* @param {string} source - Source de l'effet
|
||||||
|
* @returns {Object} - Données de l'effet
|
||||||
|
*/
|
||||||
|
static createDefenseBonusEffect(value, source = "Effet") {
|
||||||
|
return this.createSimpleEffect(
|
||||||
|
`${source}: Bonus de Défense`,
|
||||||
|
"defense",
|
||||||
|
`+${value}`,
|
||||||
|
{
|
||||||
|
icon: "systems/fvtt-mournblade-cyd-2-0/assets/icons/defense.webp",
|
||||||
|
type: "temp",
|
||||||
|
duration: { type: "rounds", value: 1 }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un effet de bonus à la Protection
|
||||||
|
* @param {number} value - Valeur du bonus
|
||||||
|
* @param {string} source - Source de l'effet
|
||||||
|
* @returns {Object} - Données de l'effet
|
||||||
|
*/
|
||||||
|
static createProtectionBonusEffect(value, source = "Effet") {
|
||||||
|
return this.createSimpleEffect(
|
||||||
|
`${source}: Bonus de Protection`,
|
||||||
|
"protection",
|
||||||
|
`+${value}`,
|
||||||
|
{
|
||||||
|
icon: "systems/fvtt-mournblade-cyd-2-0/assets/icons/protection.webp",
|
||||||
|
type: "base"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/* Méthodes de gestion des statuts */
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un effet qui applique un statut
|
||||||
|
* @param {string} status - Nom du statut
|
||||||
|
* @param {string} source - Source de l'effet
|
||||||
|
* @returns {Object} - Données de l'effet
|
||||||
|
*/
|
||||||
|
static createStatusEffect(status, source = "Effet") {
|
||||||
|
return {
|
||||||
|
name: `${source}: ${status}`,
|
||||||
|
icon: `systems/fvtt-mournblade-cyd-2-0/assets/icons/status_${status.toLowerCase()}.webp`,
|
||||||
|
description: `Applique le statut ${status}`,
|
||||||
|
changes: [],
|
||||||
|
statuses: [status],
|
||||||
|
disabled: false,
|
||||||
|
duration: {},
|
||||||
|
origin: null,
|
||||||
|
tint: "",
|
||||||
|
transfer: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un effet d'adversité bleue
|
||||||
|
* @param {number} value - Nombre d'adversités
|
||||||
|
* @returns {Object|null} - Données de l'effet ou null
|
||||||
|
*/
|
||||||
|
static createAdversiteBleueEffect(value) {
|
||||||
|
if (value == null) return null;
|
||||||
|
|
||||||
|
return this.createSimpleEffect(
|
||||||
|
`Adversité Bleue: +${value}`,
|
||||||
|
"adversite.bleue",
|
||||||
|
value,
|
||||||
|
{
|
||||||
|
icon: "systems/fvtt-mournblade-cyd-2-0/assets/icons/gemme_bleue.webp",
|
||||||
|
duration: { type: "rounds", value: 1 },
|
||||||
|
statuses: ["adversite-bleue"]
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un effet d'adversité rouge
|
||||||
|
* @param {number} value - Nombre d'adversités
|
||||||
|
* @returns {Object|null} - Données de l'effet ou null
|
||||||
|
*/
|
||||||
|
static createAdversiteRougeEffect(value) {
|
||||||
|
if (value == null) return null;
|
||||||
|
|
||||||
|
return this.createSimpleEffect(
|
||||||
|
`Adversité Rouge: +${value}`,
|
||||||
|
"adversite.rouge",
|
||||||
|
value,
|
||||||
|
{
|
||||||
|
icon: "systems/fvtt-mournblade-cyd-2-0/assets/icons/gemme_rouge.webp",
|
||||||
|
duration: { type: "rounds", value: 1 },
|
||||||
|
statuses: ["adversite-rouge"]
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un effet d'adversité noire
|
||||||
|
* @param {number} value - Nombre d'adversités
|
||||||
|
* @returns {Object|null} - Données de l'effet ou null
|
||||||
|
*/
|
||||||
|
static createAdversiteNoireEffect(value) {
|
||||||
|
if (value == null) return null;
|
||||||
|
|
||||||
|
return this.createSimpleEffect(
|
||||||
|
`Adversité Noire: +${value}`,
|
||||||
|
"adversite.noire",
|
||||||
|
value,
|
||||||
|
{
|
||||||
|
icon: "systems/fvtt-mournblade-cyd-2-0/assets/icons/gemme_noire.webp",
|
||||||
|
duration: { type: "rounds", value: 1 },
|
||||||
|
statuses: ["adversite-noire"]
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/* Méthodes pour les Runes */
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un effet de Rune prononcée
|
||||||
|
* @param {Object} rune - Données de la rune
|
||||||
|
* @param {number} pointsAme - Points de pouvoir dépensés
|
||||||
|
* @returns {Object|null} - Données de l'effet ou null
|
||||||
|
*/
|
||||||
|
static createRunePrononceeEffect(rune, pointsAme) {
|
||||||
|
if (!rune || !rune.name || pointsAme == null) return null;
|
||||||
|
|
||||||
|
// Utiliser une icône par défaut si l'image de la rune est l'image par défaut
|
||||||
|
const icon = rune.img?.includes('/blank.png') || !rune.img
|
||||||
|
? "systems/fvtt-mournblade-cyd-2-0/assets/icons/rune.webp"
|
||||||
|
: rune.img;
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: `Rune: ${rune.name} (Prononcée)`,
|
||||||
|
icon: icon,
|
||||||
|
description: rune.system?.description || "",
|
||||||
|
changes: [], // Les modifications spécifiques peuvent être ajoutées par les appels
|
||||||
|
disabled: false,
|
||||||
|
duration: { type: "rounds", value: Math.ceil(pointsAme / 3) },
|
||||||
|
origin: rune.uuid || null,
|
||||||
|
tint: "#00ff00",
|
||||||
|
transfer: true,
|
||||||
|
flags: {
|
||||||
|
"mournblade-cyd2": {
|
||||||
|
runeId: rune._id,
|
||||||
|
runeType: "prononcee",
|
||||||
|
pointsAme: pointsAme
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée un effet de Rune tracée
|
||||||
|
* @param {Object} rune - Données de la rune
|
||||||
|
* @param {number} pointsAme - Points de pouvoir dépensés
|
||||||
|
* @returns {Object|null} - Données de l'effet ou null
|
||||||
|
*/
|
||||||
|
static createRuneTraceeEffect(rune, pointsAme) {
|
||||||
|
if (!rune || !rune.name || pointsAme == null) return null;
|
||||||
|
|
||||||
|
// Utiliser une icône par défaut si l'image de la rune est l'image par défaut
|
||||||
|
const icon = rune.img?.includes('/blank.png') || !rune.img
|
||||||
|
? "systems/fvtt-mournblade-cyd-2-0/assets/icons/rune.webp"
|
||||||
|
: rune.img;
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: `Rune: ${rune.name} (Tracée)`,
|
||||||
|
icon: icon,
|
||||||
|
description: rune.system?.description || "",
|
||||||
|
changes: [], // Les modifications spécifiques peuvent être ajoutées par les appels
|
||||||
|
disabled: false,
|
||||||
|
duration: { type: "rounds", value: Math.ceil(pointsAme / 3) * 2 },
|
||||||
|
origin: rune.uuid || null,
|
||||||
|
tint: "#0000ff",
|
||||||
|
transfer: true,
|
||||||
|
flags: {
|
||||||
|
"mournblade-cyd2": {
|
||||||
|
runeId: rune._id,
|
||||||
|
runeType: "tracee",
|
||||||
|
pointsAme: pointsAme
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialisation automatique
|
||||||
|
Hooks.once("init", () => {
|
||||||
|
MournbladeCYD2Effects.init();
|
||||||
|
});
|
||||||
@@ -5,7 +5,7 @@ export const defaultItemImg = {
|
|||||||
arme: "systems/fvtt-mournblade-cyd-2-0/assets/icons/melee.webp",
|
arme: "systems/fvtt-mournblade-cyd-2-0/assets/icons/melee.webp",
|
||||||
equipement: "systems/fvtt-mournblade-cyd-2-0/assets/icons/equipement.webp",
|
equipement: "systems/fvtt-mournblade-cyd-2-0/assets/icons/equipement.webp",
|
||||||
monnaie: "systems/fvtt-mournblade-cyd-2-0/assets/icons/monnaie.webp",
|
monnaie: "systems/fvtt-mournblade-cyd-2-0/assets/icons/monnaie.webp",
|
||||||
predilection: "systems/fvtt-mournblade-cyd-2-0/assets/icons/predilection.webp",
|
predilection: "systems/fvtt-mournblade-cyd-2-0/assets/icons/competence.webp",
|
||||||
protection: "systems/fvtt-mournblade-cyd-2-0/assets/icons/protection.webp",
|
protection: "systems/fvtt-mournblade-cyd-2-0/assets/icons/protection.webp",
|
||||||
talent: "systems/fvtt-mournblade-cyd-2-0/assets/icons/talent.webp",
|
talent: "systems/fvtt-mournblade-cyd-2-0/assets/icons/talent.webp",
|
||||||
historique: "systems/fvtt-mournblade-cyd-2-0/assets/icons/historique.webp",
|
historique: "systems/fvtt-mournblade-cyd-2-0/assets/icons/historique.webp",
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { MournbladeCYD2Item } from "./mournblade-cyd2-item.js";
|
|||||||
import { MournbladeCYD2Automation } from "./mournblade-cyd2-automation.js";
|
import { MournbladeCYD2Automation } from "./mournblade-cyd2-automation.js";
|
||||||
import { MournbladeCYD2TokenHud } from "./mournblade-cyd2-hud.js";
|
import { MournbladeCYD2TokenHud } from "./mournblade-cyd2-hud.js";
|
||||||
import { MOURNBLADECYD2_CONFIG } from "./mournblade-cyd2-config.js";
|
import { MOURNBLADECYD2_CONFIG } from "./mournblade-cyd2-config.js";
|
||||||
|
import { MournbladeCYD2Effects } from "./mournblade-cyd2-effects.js";
|
||||||
|
|
||||||
// Import DataModels
|
// Import DataModels
|
||||||
import * as models from "./models/index.mjs";
|
import * as models from "./models/index.mjs";
|
||||||
@@ -69,11 +70,15 @@ Hooks.once("init", async function () {
|
|||||||
runeeffect: models.RuneEffectDataModel,
|
runeeffect: models.RuneEffectDataModel,
|
||||||
tendance: models.TendanceDataModel,
|
tendance: models.TendanceDataModel,
|
||||||
traitchaotique: models.TraitChaotiqueDataModel,
|
traitchaotique: models.TraitChaotiqueDataModel,
|
||||||
traitespece: models.TraitEspeceDataModel
|
traitespece: models.TraitEspeceDataModel,
|
||||||
|
traitdemoniaque: models.TraitDemoniaqueDataModel,
|
||||||
|
pouvoirselementaire: models.PouvoirElementaireDataModel,
|
||||||
|
capaciteautomata: models.CapaciteAutomataDataModel
|
||||||
}
|
}
|
||||||
game.system.mournbladecyd2 = {
|
game.system.mournbladecyd2 = {
|
||||||
MournbladeCYD2Utility,
|
MournbladeCYD2Utility,
|
||||||
MournbladeCYD2Automation,
|
MournbladeCYD2Automation,
|
||||||
|
MournbladeCYD2Effects,
|
||||||
config: MOURNBLADECYD2_CONFIG
|
config: MOURNBLADECYD2_CONFIG
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,6 +104,9 @@ Hooks.once("init", async function () {
|
|||||||
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd-2-0", sheets.MournbladeCYD2TendanceSheet, { types: ["tendance"], makeDefault: true });
|
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd-2-0", sheets.MournbladeCYD2TendanceSheet, { types: ["tendance"], makeDefault: true });
|
||||||
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd-2-0", sheets.MournbladeCYD2TraitChaotiqueSheet, { types: ["traitchaotique"], makeDefault: true });
|
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd-2-0", sheets.MournbladeCYD2TraitChaotiqueSheet, { types: ["traitchaotique"], makeDefault: true });
|
||||||
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd-2-0", sheets.MournbladeCYD2TraitEspeceSheet, { types: ["traitespece"], makeDefault: true });
|
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd-2-0", sheets.MournbladeCYD2TraitEspeceSheet, { types: ["traitespece"], makeDefault: true });
|
||||||
|
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd-2-0", sheets.MournbladeCYD2TraitDemoniaqueSheet, { types: ["traitdemoniaque"], makeDefault: true });
|
||||||
|
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd-2-0", sheets.MournbladeCYD2PouvoirElementaireSheet, { types: ["pouvoirselementaire"], makeDefault: true });
|
||||||
|
foundry.documents.collections.Items.registerSheet("fvtt-mournblade-cyd-2-0", sheets.MournbladeCYD2CapaciteAutomataSheet, { types: ["capaciteautomata"], makeDefault: true });
|
||||||
|
|
||||||
MournbladeCYD2Utility.init()
|
MournbladeCYD2Utility.init()
|
||||||
MournbladeCYD2Automation.init()
|
MournbladeCYD2Automation.init()
|
||||||
|
|||||||
@@ -46,6 +46,9 @@ export class MournbladeCYD2Utility {
|
|||||||
Handlebars.registerHelper('mul', function (a, b) {
|
Handlebars.registerHelper('mul', function (a, b) {
|
||||||
return parseInt(a) * parseInt(b);
|
return parseInt(a) * parseInt(b);
|
||||||
})
|
})
|
||||||
|
Handlebars.registerHelper('subtract', function (a, b) {
|
||||||
|
return parseInt(a) - parseInt(b);
|
||||||
|
})
|
||||||
Handlebars.registerHelper('select', function(value, options) {
|
Handlebars.registerHelper('select', function(value, options) {
|
||||||
const html = options.fn(this);
|
const html = options.fn(this);
|
||||||
const escaped = String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
const escaped = String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||||
@@ -195,6 +198,8 @@ export class MournbladeCYD2Utility {
|
|||||||
'systems/fvtt-mournblade-cyd-2-0/templates/partial-item-nav.hbs',
|
'systems/fvtt-mournblade-cyd-2-0/templates/partial-item-nav.hbs',
|
||||||
'systems/fvtt-mournblade-cyd-2-0/templates/partial-item-prix.hbs',
|
'systems/fvtt-mournblade-cyd-2-0/templates/partial-item-prix.hbs',
|
||||||
'systems/fvtt-mournblade-cyd-2-0/templates/partial-automation.hbs',
|
'systems/fvtt-mournblade-cyd-2-0/templates/partial-automation.hbs',
|
||||||
|
'systems/fvtt-mournblade-cyd-2-0/templates/partial-active-effects.hbs',
|
||||||
|
'systems/fvtt-mournblade-cyd-2-0/templates/partial-item-effects.hbs',
|
||||||
'systems/fvtt-mournblade-cyd-2-0/templates/hud-adversites.hbs',
|
'systems/fvtt-mournblade-cyd-2-0/templates/hud-adversites.hbs',
|
||||||
]
|
]
|
||||||
return foundry.applications.handlebars.loadTemplates(templatePaths);
|
return foundry.applications.handlebars.loadTemplates(templatePaths);
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
MANIFEST-000384
|
MANIFEST-000431
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
2026/04/02-22:42:22.886542 7feec8bfd6c0 Recovering log #382
|
2026/06/07-00:21:50.466229 7f15cf3fe6c0 Recovering log #429
|
||||||
2026/04/02-22:42:22.897444 7feec8bfd6c0 Delete type=3 #380
|
2026/06/07-00:21:50.475486 7f15cf3fe6c0 Delete type=3 #427
|
||||||
2026/04/02-22:42:22.897515 7feec8bfd6c0 Delete type=0 #382
|
2026/06/07-00:21:50.475515 7f15cf3fe6c0 Delete type=0 #429
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2026/04/02-22:23:11.995579 7feec93fe6c0 Recovering log #378
|
2026/06/07-00:01:17.675368 7f15ce3fc6c0 Recovering log #425
|
||||||
2026/04/02-22:23:12.005529 7feec93fe6c0 Delete type=3 #376
|
2026/06/07-00:01:17.685411 7f15ce3fc6c0 Delete type=3 #423
|
||||||
2026/04/02-22:23:12.005581 7feec93fe6c0 Delete type=0 #378
|
2026/06/07-00:01:17.685428 7f15ce3fc6c0 Delete type=0 #425
|
||||||
2026/04/02-22:41:03.722884 7feeb37fe6c0 Level-0 table #383: started
|
2026/06/07-00:21:46.748268 7f15cdbfb6c0 Level-0 table #430: started
|
||||||
2026/04/02-22:41:03.722902 7feeb37fe6c0 Level-0 table #383: 0 bytes OK
|
2026/06/07-00:21:46.748282 7f15cdbfb6c0 Level-0 table #430: 0 bytes OK
|
||||||
2026/04/02-22:41:03.728999 7feeb37fe6c0 Delete type=0 #381
|
2026/06/07-00:21:46.755214 7f15cdbfb6c0 Delete type=0 #428
|
||||||
2026/04/02-22:41:03.736041 7feeb37fe6c0 Manual compaction at level-0 from '!journal!gVybbv17TFY8o3Y4' @ 72057594037927935 : 1 .. '!journal.pages!gVybbv17TFY8o3Y4.fQidyqfF1TbsZKHM' @ 0 : 0; will stop at (end)
|
2026/06/07-00:21:46.768389 7f15cdbfb6c0 Manual compaction at level-0 from '!journal!gVybbv17TFY8o3Y4' @ 72057594037927935 : 1 .. '!journal.pages!gVybbv17TFY8o3Y4.fQidyqfF1TbsZKHM' @ 0 : 0; will stop at (end)
|
||||||
2026/04/02-22:41:03.745674 7feeb37fe6c0 Manual compaction at level-1 from '!journal!gVybbv17TFY8o3Y4' @ 72057594037927935 : 1 .. '!journal.pages!gVybbv17TFY8o3Y4.fQidyqfF1TbsZKHM' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
-1
@@ -1 +1 @@
|
|||||||
MANIFEST-000381
|
MANIFEST-000426
|
||||||
|
|||||||
+3
-3
@@ -1,3 +1,3 @@
|
|||||||
2026/04/02-22:42:22.751579 7feeb3fff6c0 Recovering log #379
|
2026/06/07-00:21:50.343006 7f15cebfd6c0 Recovering log #424
|
||||||
2026/04/02-22:42:22.761248 7feeb3fff6c0 Delete type=3 #377
|
2026/06/07-00:21:50.352418 7f15cebfd6c0 Delete type=3 #422
|
||||||
2026/04/02-22:42:22.761291 7feeb3fff6c0 Delete type=0 #379
|
2026/06/07-00:21:50.352440 7f15cebfd6c0 Delete type=0 #424
|
||||||
|
|||||||
+7
-8
@@ -1,8 +1,7 @@
|
|||||||
2026/04/02-22:23:11.844533 7feec8bfd6c0 Recovering log #375
|
2026/06/07-00:01:17.549317 7f15ce3fc6c0 Recovering log #420
|
||||||
2026/04/02-22:23:11.854182 7feec8bfd6c0 Delete type=3 #373
|
2026/06/07-00:01:17.559821 7f15ce3fc6c0 Delete type=3 #418
|
||||||
2026/04/02-22:23:11.854243 7feec8bfd6c0 Delete type=0 #375
|
2026/06/07-00:01:17.559847 7f15ce3fc6c0 Delete type=0 #420
|
||||||
2026/04/02-22:41:03.650062 7feeb37fe6c0 Level-0 table #380: started
|
2026/06/07-00:21:46.679739 7f15cdbfb6c0 Level-0 table #425: started
|
||||||
2026/04/02-22:41:03.650092 7feeb37fe6c0 Level-0 table #380: 0 bytes OK
|
2026/06/07-00:21:46.679750 7f15cdbfb6c0 Level-0 table #425: 0 bytes OK
|
||||||
2026/04/02-22:41:03.656009 7feeb37fe6c0 Delete type=0 #378
|
2026/06/07-00:21:46.685835 7f15cdbfb6c0 Delete type=0 #423
|
||||||
2026/04/02-22:41:03.656115 7feeb37fe6c0 Manual compaction at level-0 from '!items!0swiE8k5zfUIqmXu' @ 72057594037927935 : 1 .. '!items!wv5EiePmPTpqFutt' @ 0 : 0; will stop at (end)
|
2026/06/07-00:21:46.698903 7f15cdbfb6c0 Manual compaction at level-0 from '!items!0swiE8k5zfUIqmXu' @ 72057594037927935 : 1 .. '!items!wv5EiePmPTpqFutt' @ 0 : 0; will stop at (end)
|
||||||
2026/04/02-22:41:03.656130 7feeb37fe6c0 Manual compaction at level-1 from '!items!0swiE8k5zfUIqmXu' @ 72057594037927935 : 1 .. '!items!wv5EiePmPTpqFutt' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
-1
@@ -1 +1 @@
|
|||||||
MANIFEST-000263
|
MANIFEST-000325
|
||||||
|
|||||||
+3
-3
@@ -1,3 +1,3 @@
|
|||||||
2026/04/02-22:42:22.787186 7feec8bfd6c0 Recovering log #261
|
2026/06/07-00:21:50.374568 7f15cf3fe6c0 Recovering log #323
|
||||||
2026/04/02-22:42:22.797121 7feec8bfd6c0 Delete type=3 #259
|
2026/06/07-00:21:50.384637 7f15cf3fe6c0 Delete type=3 #321
|
||||||
2026/04/02-22:42:22.797203 7feec8bfd6c0 Delete type=0 #261
|
2026/06/07-00:21:50.384658 7f15cf3fe6c0 Delete type=0 #323
|
||||||
|
|||||||
+7
-8
@@ -1,8 +1,7 @@
|
|||||||
2026/04/02-22:23:11.881302 7feec93fe6c0 Recovering log #257
|
2026/06/07-00:01:17.584289 7f15ce3fc6c0 Recovering log #319
|
||||||
2026/04/02-22:23:11.891971 7feec93fe6c0 Delete type=3 #255
|
2026/06/07-00:01:17.594286 7f15ce3fc6c0 Delete type=3 #317
|
||||||
2026/04/02-22:23:11.892014 7feec93fe6c0 Delete type=0 #257
|
2026/06/07-00:01:17.594301 7f15ce3fc6c0 Delete type=0 #319
|
||||||
2026/04/02-22:41:03.662117 7feeb37fe6c0 Level-0 table #262: started
|
2026/06/07-00:21:46.698908 7f15cdbfb6c0 Level-0 table #324: started
|
||||||
2026/04/02-22:41:03.662146 7feeb37fe6c0 Level-0 table #262: 0 bytes OK
|
2026/06/07-00:21:46.698917 7f15cdbfb6c0 Level-0 table #324: 0 bytes OK
|
||||||
2026/04/02-22:41:03.668307 7feeb37fe6c0 Delete type=0 #260
|
2026/06/07-00:21:46.704788 7f15cdbfb6c0 Delete type=0 #322
|
||||||
2026/04/02-22:41:03.680730 7feeb37fe6c0 Manual compaction at level-0 from '!items!5dGXNiL3WN4cAk7X' @ 72057594037927935 : 1 .. '!items!zzz9JrtWjELdoAfK' @ 0 : 0; will stop at (end)
|
2026/06/07-00:21:46.710794 7f15cdbfb6c0 Manual compaction at level-0 from '!items!5dGXNiL3WN4cAk7X' @ 72057594037927935 : 1 .. '!items!zzz9JrtWjELdoAfK' @ 0 : 0; will stop at (end)
|
||||||
2026/04/02-22:41:03.680782 7feeb37fe6c0 Manual compaction at level-1 from '!items!5dGXNiL3WN4cAk7X' @ 72057594037927935 : 1 .. '!items!zzz9JrtWjELdoAfK' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000263
|
MANIFEST-000325
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
2026/04/02-22:42:22.774883 7feec93fe6c0 Recovering log #261
|
2026/06/07-00:21:50.363711 7f15ce3fc6c0 Recovering log #323
|
||||||
2026/04/02-22:42:22.785249 7feec93fe6c0 Delete type=3 #259
|
2026/06/07-00:21:50.373124 7f15ce3fc6c0 Delete type=3 #321
|
||||||
2026/04/02-22:42:22.785297 7feec93fe6c0 Delete type=0 #261
|
2026/06/07-00:21:50.373150 7f15ce3fc6c0 Delete type=0 #323
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2026/04/02-22:23:11.869572 7feec8bfd6c0 Recovering log #257
|
2026/06/07-00:01:17.573032 7f15cfbff6c0 Recovering log #319
|
||||||
2026/04/02-22:23:11.878854 7feec8bfd6c0 Delete type=3 #255
|
2026/06/07-00:01:17.582308 7f15cfbff6c0 Delete type=3 #317
|
||||||
2026/04/02-22:23:11.878924 7feec8bfd6c0 Delete type=0 #257
|
2026/06/07-00:01:17.582329 7f15cfbff6c0 Delete type=0 #319
|
||||||
2026/04/02-22:41:03.674670 7feeb37fe6c0 Level-0 table #262: started
|
2026/06/07-00:21:46.660469 7f15cdbfb6c0 Level-0 table #324: started
|
||||||
2026/04/02-22:41:03.674691 7feeb37fe6c0 Level-0 table #262: 0 bytes OK
|
2026/06/07-00:21:46.660487 7f15cdbfb6c0 Level-0 table #324: 0 bytes OK
|
||||||
2026/04/02-22:41:03.680561 7feeb37fe6c0 Delete type=0 #260
|
2026/06/07-00:21:46.667102 7f15cdbfb6c0 Delete type=0 #322
|
||||||
2026/04/02-22:41:03.680749 7feeb37fe6c0 Manual compaction at level-0 from '!items!1cZd2hlTV9tykDED' @ 72057594037927935 : 1 .. '!items!y47dBO3Mf5Pn7tOd' @ 0 : 0; will stop at (end)
|
2026/06/07-00:21:46.679674 7f15cdbfb6c0 Manual compaction at level-0 from '!items!1cZd2hlTV9tykDED' @ 72057594037927935 : 1 .. '!items!y47dBO3Mf5Pn7tOd' @ 0 : 0; will stop at (end)
|
||||||
2026/04/02-22:41:03.680776 7feeb37fe6c0 Manual compaction at level-1 from '!items!1cZd2hlTV9tykDED' @ 72057594037927935 : 1 .. '!items!y47dBO3Mf5Pn7tOd' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000383
|
MANIFEST-000442
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
2026/04/02-22:42:22.739027 7feec8bfd6c0 Recovering log #381
|
2026/06/07-00:21:50.331328 7f15cf3fe6c0 Recovering log #440
|
||||||
2026/04/02-22:42:22.749357 7feec8bfd6c0 Delete type=3 #379
|
2026/06/07-00:21:50.341554 7f15cf3fe6c0 Delete type=3 #438
|
||||||
2026/04/02-22:42:22.749468 7feec8bfd6c0 Delete type=0 #381
|
2026/06/07-00:21:50.341580 7f15cf3fe6c0 Delete type=0 #440
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2026/04/02-22:23:11.832014 7feec93fe6c0 Recovering log #377
|
2026/06/07-00:01:17.537677 7f15cfbff6c0 Recovering log #436
|
||||||
2026/04/02-22:23:11.841719 7feec93fe6c0 Delete type=3 #375
|
2026/06/07-00:01:17.547496 7f15cfbff6c0 Delete type=3 #434
|
||||||
2026/04/02-22:23:11.841777 7feec93fe6c0 Delete type=0 #377
|
2026/06/07-00:01:17.547526 7f15cfbff6c0 Delete type=0 #436
|
||||||
2026/04/02-22:41:03.636791 7feeb37fe6c0 Level-0 table #382: started
|
2026/06/07-00:21:46.685907 7f15cdbfb6c0 Level-0 table #441: started
|
||||||
2026/04/02-22:41:03.636818 7feeb37fe6c0 Level-0 table #382: 0 bytes OK
|
2026/06/07-00:21:46.685917 7f15cdbfb6c0 Level-0 table #441: 0 bytes OK
|
||||||
2026/04/02-22:41:03.642955 7feeb37fe6c0 Delete type=0 #380
|
2026/06/07-00:21:46.691937 7f15cdbfb6c0 Delete type=0 #439
|
||||||
2026/04/02-22:41:03.656101 7feeb37fe6c0 Manual compaction at level-0 from '!items!15foLG7y3LUXNzkK' @ 72057594037927935 : 1 .. '!items!z1HtkvazCGHut7cz' @ 0 : 0; will stop at (end)
|
2026/06/07-00:21:46.704830 7f15cdbfb6c0 Manual compaction at level-0 from '!items!15foLG7y3LUXNzkK' @ 72057594037927935 : 1 .. '!items!z1HtkvazCGHut7cz' @ 0 : 0; will stop at (end)
|
||||||
2026/04/02-22:41:03.656120 7feeb37fe6c0 Manual compaction at level-1 from '!items!15foLG7y3LUXNzkK' @ 72057594037927935 : 1 .. '!items!z1HtkvazCGHut7cz' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000271
|
MANIFEST-000279
|
||||||
|
|||||||
+5
-8
@@ -1,8 +1,5 @@
|
|||||||
2025/10/26-12:29:06.663227 7fe805ffb6c0 Recovering log #269
|
2026/05/24-16:10:55.689768 7fcc763fd6c0 Recovering log #278
|
||||||
2025/10/26-12:29:06.672961 7fe805ffb6c0 Delete type=3 #267
|
2026/05/24-16:10:55.690275 7fcc763fd6c0 Level-0 table #280: started
|
||||||
2025/10/26-12:29:06.673033 7fe805ffb6c0 Delete type=0 #269
|
2026/05/24-16:10:55.701020 7fcc763fd6c0 Level-0 table #280: 59211 bytes OK
|
||||||
2025/10/26-13:28:40.186064 7fe804ff96c0 Level-0 table #274: started
|
2026/05/24-16:10:55.711573 7fcc763fd6c0 Delete type=0 #278
|
||||||
2025/10/26-13:28:40.186097 7fe804ff96c0 Level-0 table #274: 0 bytes OK
|
2026/05/24-16:10:55.711660 7fcc763fd6c0 Delete type=3 #277
|
||||||
2025/10/26-13:28:40.222366 7fe804ff96c0 Delete type=0 #272
|
|
||||||
2025/10/26-13:28:40.222620 7fe804ff96c0 Manual compaction at level-0 from '!folders!5d4Zn28TUcPxRyXd' @ 72057594037927935 : 1 .. '!items!zttESycGKltfwCzJ' @ 0 : 0; will stop at (end)
|
|
||||||
2025/10/26-13:28:40.222652 7fe804ff96c0 Manual compaction at level-1 from '!folders!5d4Zn28TUcPxRyXd' @ 72057594037927935 : 1 .. '!items!zttESycGKltfwCzJ' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
2025/10/26-11:43:11.873666 7fe8067fc6c0 Recovering log #265
|
2026/05/24-16:10:48.587218 7f8a723fe6c0 Recovering log #276
|
||||||
2025/10/26-11:43:11.939384 7fe8067fc6c0 Delete type=3 #263
|
2026/05/24-16:10:48.603666 7f8a723fe6c0 Delete type=0 #276
|
||||||
2025/10/26-11:43:11.939453 7fe8067fc6c0 Delete type=0 #265
|
2026/05/24-16:10:48.603736 7f8a723fe6c0 Delete type=3 #275
|
||||||
2025/10/26-12:28:57.839058 7fe804ff96c0 Level-0 table #270: started
|
|
||||||
2025/10/26-12:28:57.839085 7fe804ff96c0 Level-0 table #270: 0 bytes OK
|
|
||||||
2025/10/26-12:28:57.844954 7fe804ff96c0 Delete type=0 #268
|
|
||||||
2025/10/26-12:28:57.845097 7fe804ff96c0 Manual compaction at level-0 from '!folders!5d4Zn28TUcPxRyXd' @ 72057594037927935 : 1 .. '!items!zttESycGKltfwCzJ' @ 0 : 0; will stop at (end)
|
|
||||||
2025/10/26-12:28:57.845134 7fe804ff96c0 Manual compaction at level-1 from '!folders!5d4Zn28TUcPxRyXd' @ 72057594037927935 : 1 .. '!items!zttESycGKltfwCzJ' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000143
|
MANIFEST-000158
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
2025/10/26-11:41:45.070943 7fe805ffb6c0 Recovering log #141
|
2026/05/24-16:10:55.592869 7f188bbff6c0 Recovering log #157
|
||||||
2025/10/26-11:41:45.080807 7fe805ffb6c0 Delete type=3 #139
|
2026/05/24-16:10:55.611609 7f188bbff6c0 Delete type=0 #157
|
||||||
2025/10/26-11:41:45.080890 7fe805ffb6c0 Delete type=0 #141
|
2026/05/24-16:10:55.611670 7f188bbff6c0 Delete type=3 #156
|
||||||
2025/10/26-11:42:27.702876 7fe804ff96c0 Level-0 table #146: started
|
|
||||||
2025/10/26-11:42:27.702902 7fe804ff96c0 Level-0 table #146: 0 bytes OK
|
|
||||||
2025/10/26-11:42:27.753550 7fe804ff96c0 Delete type=0 #144
|
|
||||||
2025/10/26-11:42:27.787805 7fe804ff96c0 Manual compaction at level-0 from '!actors!00CKDCqVh5fLZbYo' @ 72057594037927935 : 1 .. '!folders!dwT9WnH0ZnpuZh92' @ 0 : 0; will stop at (end)
|
|
||||||
2025/10/26-11:42:27.787855 7fe804ff96c0 Manual compaction at level-1 from '!actors!00CKDCqVh5fLZbYo' @ 72057594037927935 : 1 .. '!folders!dwT9WnH0ZnpuZh92' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
2025/06/24-22:08:06.079240 7f151e7fc6c0 Recovering log #137
|
2026/05/24-16:10:48.573750 7f8a71bfd6c0 Recovering log #155
|
||||||
2025/06/24-22:08:06.090765 7f151e7fc6c0 Delete type=3 #135
|
2026/05/24-16:10:48.586902 7f8a71bfd6c0 Delete type=0 #155
|
||||||
2025/06/24-22:08:06.090897 7f151e7fc6c0 Delete type=0 #137
|
2026/05/24-16:10:48.586986 7f8a71bfd6c0 Delete type=3 #154
|
||||||
2025/06/24-22:11:08.184282 7f151d7fa6c0 Level-0 table #142: started
|
|
||||||
2025/06/24-22:11:08.184358 7f151d7fa6c0 Level-0 table #142: 0 bytes OK
|
|
||||||
2025/06/24-22:11:08.191832 7f151d7fa6c0 Delete type=0 #140
|
|
||||||
2025/06/24-22:11:08.192130 7f151d7fa6c0 Manual compaction at level-0 from '!actors!00CKDCqVh5fLZbYo' @ 72057594037927935 : 1 .. '!folders!dwT9WnH0ZnpuZh92' @ 0 : 0; will stop at (end)
|
|
||||||
2025/06/24-22:11:08.192195 7f151d7fa6c0 Manual compaction at level-1 from '!actors!00CKDCqVh5fLZbYo' @ 72057594037927935 : 1 .. '!folders!dwT9WnH0ZnpuZh92' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000383
|
MANIFEST-000442
|
||||||
|
|||||||
+3
-3
@@ -1,3 +1,3 @@
|
|||||||
2026/04/02-22:42:22.835807 7feec8bfd6c0 Recovering log #381
|
2026/06/07-00:21:50.420841 7f15cfbff6c0 Recovering log #440
|
||||||
2026/04/02-22:42:22.845258 7feec8bfd6c0 Delete type=3 #379
|
2026/06/07-00:21:50.430740 7f15cfbff6c0 Delete type=3 #438
|
||||||
2026/04/02-22:42:22.845300 7feec8bfd6c0 Delete type=0 #381
|
2026/06/07-00:21:50.430770 7f15cfbff6c0 Delete type=0 #440
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2026/04/02-22:23:11.945566 7feec93fe6c0 Recovering log #377
|
2026/06/07-00:01:17.628038 7f15cf3fe6c0 Recovering log #436
|
||||||
2026/04/02-22:23:11.954859 7feec93fe6c0 Delete type=3 #375
|
2026/06/07-00:01:17.637109 7f15cf3fe6c0 Delete type=3 #434
|
||||||
2026/04/02-22:23:11.954911 7feec93fe6c0 Delete type=0 #377
|
2026/06/07-00:01:17.637121 7f15cf3fe6c0 Delete type=0 #436
|
||||||
2026/04/02-22:41:03.686833 7feeb37fe6c0 Level-0 table #382: started
|
2026/06/07-00:21:46.761269 7f15cdbfb6c0 Level-0 table #441: started
|
||||||
2026/04/02-22:41:03.686856 7feeb37fe6c0 Level-0 table #382: 0 bytes OK
|
2026/06/07-00:21:46.761294 7f15cdbfb6c0 Level-0 table #441: 0 bytes OK
|
||||||
2026/04/02-22:41:03.693649 7feeb37fe6c0 Delete type=0 #380
|
2026/06/07-00:21:46.768307 7f15cdbfb6c0 Delete type=0 #439
|
||||||
2026/04/02-22:41:03.706286 7feeb37fe6c0 Manual compaction at level-0 from '!items!26mRstKhCJoXkhu1' @ 72057594037927935 : 1 .. '!items!tFQqcxmkS3MT6ASE' @ 0 : 0; will stop at (end)
|
2026/06/07-00:21:46.777465 7f15cdbfb6c0 Manual compaction at level-0 from '!items!26mRstKhCJoXkhu1' @ 72057594037927935 : 1 .. '!items!tFQqcxmkS3MT6ASE' @ 0 : 0; will stop at (end)
|
||||||
2026/04/02-22:41:03.706323 7feeb37fe6c0 Manual compaction at level-1 from '!items!26mRstKhCJoXkhu1' @ 72057594037927935 : 1 .. '!items!tFQqcxmkS3MT6ASE' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user