18 Commits

Author SHA1 Message Date
uberwald 1b81b0a3ac Corrections§upgrade diverses 2026-06-07 09:43:37 +02:00
uberwald 3ff2b8e9bb Docs: Add MNBL i18n and effects tab fixes to documentation
- Documented missing MNBL.details and MNBL.description keys
- Documented effects tab visibility fix
- Updated file list and impact section

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-07 00:53:53 +02:00
uberwald 38525c3257 Fix: Add missing MNBL i18n keys and show effects tab always
- Added MNBL.details and MNBL.description to lang/fr.json
- Removed conditional display of effects tab in partial-item-nav.hbs
- Effects tab now always visible in item sheets
- Added MNBL i18n keys verification to test script

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-07 00:53:31 +02:00
uberwald f035bcfae2 Docs: Add i18n EFFECT keys fix to documentation
- Documented the missing i18n localization keys
- Updated file list and impact section

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-07 00:51:32 +02:00
uberwald a8bf356d20 Fix: Add missing i18n EFFECT keys to lang/fr.json
Added missing localization keys for ActiveEffect management:
- 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

Added test verification for EFFECT i18n keys

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-07 00:51:12 +02:00
uberwald cd70b70088 Docs: Add subtract helper fix to documentation
- Documented the missing subtract helper issue
- Updated file list and impact section

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-07 00:49:15 +02:00
uberwald 14763cc5b3 Fix: Add missing Handlebars subtract helper
- Added subtract helper: parseInt(a) - parseInt(b)
- Helper is used in partial-active-effects.hbs and partial-item-effects.hbs
- Registered in MournbladeCYD2Utility.init() alongside other helpers
- Added test verification for subtract helper registration

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-07 00:48:55 +02:00
uberwald 0258c2e8b7 Docs: Update with duration.type to duration.units fix
- Documented the ActiveEffectDuration property deprecation fix
- Updated file list and impact section

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-07 00:42:05 +02:00
uberwald 9b3d34c5d7 Fix: Replace deprecated duration.type with duration.units (Foundry v14+)
- ActiveEffectDuration#type was renamed to #units in Foundry VTT v14
- Updated partial-active-effects.hbs to use duration.units
- Updated partial-item-effects.hbs to use duration.units
- Added test verification for duration.type usage
- Support for duration.type will be removed in v16

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-07 00:41:46 +02:00
uberwald 335238df3d Docs: Update CORRECTIONS.md with effect.webp icon fix
- Documented the effect.webp missing icon issue
- Updated file list with all corrected files
- Updated impact section

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-07 00:36:40 +02:00
uberwald a1519e7a60 Fix: Replace missing effect.webp icon with existing capacite.webp
- effect.webp icon was missing, causing infinite 404 errors
- Replaced all references with capacite.webp which exists
- Fixed in base-actor-sheet.mjs, base-item-sheet.mjs, mournblade-cyd2-effects.js
- Fixed in partial-active-effects.hbs and partial-item-effects.hbs templates
- Updated test script to check for effect.webp references

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-07 00:36:12 +02:00
uberwald e55b5cbe15 Test: Add check for deprecated ActiveEffectDialog API usage
- Added verification for deprecated ActiveEffectDialog.create() calls
- Updated test script to check all critical fixes

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-07 00:34:06 +02:00
uberwald f28719fc6f Fix: Replace deprecated ActiveEffectDialog.create() with createEmbeddedDocuments
- ActiveEffectDialog.create() was removed in Foundry VTT v14
- Replaced with direct document.createEmbeddedDocuments() call
- After creation, opens the effect sheet for editing
- Fixed in both base-actor-sheet.mjs and base-item-sheet.mjs

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-07 00:33:44 +02:00
uberwald d0423b2017 Fix: Add missing Handlebars partials to preload function
- Added partial-active-effects.hbs and partial-item-effects.hbs to preloadHandlebarsTemplates()
- These partials were used in sheets but not preloaded, causing render errors
- Fixed lang/fr.json formatting (added closing brace and newline)
- Added test script to validate template loading
- Added CORRECTIONS.md documentation

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-07 00:26:07 +02:00
uberwald 156672d853 ActiveEffects: Add complete ActiveEffects management system
- New: modules/mournblade-cyd2-effects.js with utility methods for creating, applying, and managing effects
- New: templates/partial-active-effects.hbs for displaying actor effects
- New: templates/partial-item-effects.hbs for displaying item effects
- Update: modules/mournblade-cyd2-config.js with effect configuration (types, attribute keys, categories)
- Update: templates/actor-sheet.hbs and creature-sheet.hbs with Effects tab
- Update: templates/partial-item-nav.hbs with conditional Effects tab
- Update: templates/item-talent-sheet.hbs with Effects tab content
- Update: base-actor-sheet.mjs with effect action handlers (create, edit, delete, toggle)
- Update: base-item-sheet.mjs with effect action handlers and context
- Update: modules/mournblade-cyd2-main.js to import and expose MournbladeCYD2Effects
- Update: lang/fr.json with effect-related translations

Features:
- Support for creating permanent and temporary effects
- Support for attribute modifications (ADR, PUI, CLA, PRE, TRE, etc.)
- Support for health, soul, combat, and adversity modifications
- Support for status effects
- Support for runes (pronounced and traced) effects
- Toggle to enable/disable effects
- Duration tracking (rounds, turns, seconds, combat, scene)
- Display of all active modifications summary

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-06 22:51:31 +02:00
uberwald 5ab03920d6 Corrections diverses pour CYD2.0
- Fix: Remplacement de 'Points d'Âme' par 'Points de Pouvoir' dans les messages de chat
- Fix: Ajout de la case Âme avec Seuil de Pouvoir dans les fiches de créature
- Fix: Ajout du champ Seuil de Pouvoir éditable dans les fiches de créature
- Fix: Initiative, Défense et Protection maintenant éditables dans les fiches de créature
- Fix: Ajout du champ Bonus/Malus aux templates de Traits chaotiques et d'espèce
- Fix: Le champ coût en Pouvoir des Runes accepte maintenant du texte (StringField)
- Fix: Rafraîchissement des fiches après drop d'items pour afficher les Traits
- Fix: Ajout des nouveaux types d'items (Trait Démoniaque, Pouvoir Élémentaire, Capacité d'Automata)
- New: Ajout des modèles et templates pour les nouveaux types d'items
- New: Intégration complète des nouveaux types dans les fichiers de configuration

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-06 22:08:53 +02:00
uberwald 9dd6fbd2e7 Fix: Affichage des Traits et corrections diverses
- Fix: Ajout des sections Traits Chaotiques et Traits d'Espèce dans les fiches de créature
  - Ajout de context.traitsChaotiques et context.traitsEspeces dans la feuille de créature
  - Ajout des sections dans le template creature-sheet.hbs avec boutons d'ajout
- Fix: Bouton Ajouter Automatisation fonctionnel dans les Talents
  - Ajout des actions addAutomation et deleteAutomation dans base-item-sheet.mjs
  - Ajout des méthodes #onAddAutomation et #onDeleteAutomation
  - Ajout des attributs data-action sur les boutons du template partial-automation.hbs
  - Ajout des attributs name sur les champs d'automatisation
- Ajout du champ Don lié dans les Tendances
  - Ajout de donlie dans le modèle tendance.mjs
  - Ajout du champ Don lié dans le template item-tendance-sheet.hbs
- Ajout de la catégorie Balance dans les options d'allégeance
  - Ajout dans mournblade-cyd2-config.js
  - Ajout de la traduction dans lang/fr.json
- Correction du libellé Coût en Âme → Coût en points de pouvoir
- Correction du bug de l'éditeur Sacrifices dans les Dons
  - Ajout de owner et editable dans le contexte
  - Renommage de Sacrifices en Sacrifices et Tendances liées
- Ajout de la case Âme avec Seuil de Pouvoir dans les fiches de créature
- Rendre Initiative, Défense et Protection éditables dans les fiches de créature
  - Ajout des champs inittotal, defensetotal, protectiontotal dans creature.mjs
  - Modification du contexte pour prioriser les valeurs manuelles
  - Remplacement des spans par des inputs dans le template

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-06 20:30:04 +02:00
uberwald 76ed974352 Fix: Correction du libellé Coût en Âme et ajout de la catégorie Balance
- Correction du libellé 'Coût en Âme' en 'Coût en points de pouvoir' pour les runes
- Fix: Ajout des gestionnaires d'événements pour les automatisations des Talents
  - Ajout des actions addAutomation et deleteAutomation dans base-item-sheet.mjs
  - Ajout des attributs data-action sur les boutons du template partial-automation.hbs
  - Ajout des attributs name sur les champs d'automatisation pour la sauvegarde
- Ajout de la catégorie 'Balance' dans les options d'allégeance pour Dons et Tendances

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-06 18:32:10 +02:00
156 changed files with 2941 additions and 324 deletions
+458
View File
@@ -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
+57 -2
View File
@@ -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": {
@@ -32,10 +42,13 @@
"MNBL": { "MNBL": {
"all": "Tous", "all": "Tous",
"allegiance": "Allégeance", "allegiance": "Allégeance",
"balance": "Balance",
"beastslords": "Seigneurs des Bêtes", "beastslords": "Seigneurs des Bêtes",
"chaos": "Chaos", "chaos": "Chaos",
"difficulty": "Difficulté", "difficulty": "Difficulté",
"duration": "Durée", "duration": "Durée",
"details": "Détails",
"description": "Description",
"elementslords": "Seigneurs des Éléments", "elementslords": "Seigneurs des Éléments",
"equipment": "Equipement", "equipment": "Equipement",
"examples": "Exemples", "examples": "Exemples",
@@ -56,9 +69,51 @@
"pronouncerune": "Prononcer", "pronouncerune": "Prononcer",
"rune": "Rune", "rune": "Rune",
"soulcost": "Coût en points de pouvoir", "soulcost": "Coût en points de pouvoir",
"soulpoints": "Points d'Âme", "soulpoints": "Points de Pouvoir",
"traced": "Tracée", "traced": "Tracée",
"tracedrune": "Rune tracée", "tracedrune": "Rune tracée",
"tracerune": "Tracer" "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"
} }
} }
+3
View File
@@ -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) {}
@@ -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
} }
+195 -2
View File
@@ -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;
}
}
+12
View File
@@ -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: "" })
};
}
}
+4 -1
View File
@@ -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 }),
+3
View File
@@ -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';
+12
View File
@@ -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: "" })
};
}
}
+1 -1
View File
@@ -10,7 +10,7 @@ export default class RuneDataModel extends foundry.abstract.TypeDataModel {
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.NumberField({ initial: 0, integer: true }) coutAme: new fields.StringField({ initial: "" })
}; };
} }
} }
+2 -1
View File
@@ -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: "" })
}; };
} }
} }
+2 -1
View File
@@ -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: "" })
}; };
} }
} }
+12
View File
@@ -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: "" })
};
}
}
+2 -1
View File
@@ -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: "" })
}; };
} }
} }
+91
View File
@@ -12,6 +12,7 @@ export const MOURNBLADECYD2_CONFIG = {
tous: localizeOrFallback("MNBL.all", "Tous"), tous: localizeOrFallback("MNBL.all", "Tous"),
chaos: localizeOrFallback("MNBL.chaos", "Chaos"), chaos: localizeOrFallback("MNBL.chaos", "Chaos"),
loi: localizeOrFallback("MNBL.law", "Loi"), loi: localizeOrFallback("MNBL.law", "Loi"),
balance: localizeOrFallback("MNBL.balance", "Balance"),
betes: localizeOrFallback("MNBL.beastslords", "Seigneurs des Bêtes"), betes: localizeOrFallback("MNBL.beastslords", "Seigneurs des Bêtes"),
elementaires: localizeOrFallback("MNBL.elementslords", "Seigneurs des Éléments") elementaires: localizeOrFallback("MNBL.elementslords", "Seigneurs des Éléments")
}, },
@@ -118,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" },
+807
View File
@@ -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();
});
+9 -1
View File
@@ -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()
+5
View File
@@ -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
View File
@@ -1 +1 @@
MANIFEST-000410 MANIFEST-000431
+3 -7
View File
@@ -1,7 +1,3 @@
2026/05/24-16:13:27.948127 7fdf5bfff6c0 Recovering log #409 2026/06/07-00:21:50.466229 7f15cf3fe6c0 Recovering log #429
2026/05/24-16:13:27.958589 7fdf5bfff6c0 Delete type=0 #409 2026/06/07-00:21:50.475486 7f15cf3fe6c0 Delete type=3 #427
2026/05/24-16:13:27.958609 7fdf5bfff6c0 Delete type=3 #408 2026/06/07-00:21:50.475515 7f15cf3fe6c0 Delete type=0 #429
2026/05/24-16:49:30.908639 7fdf5affd6c0 Level-0 table #413: started
2026/05/24-16:49:30.908660 7fdf5affd6c0 Level-0 table #413: 0 bytes OK
2026/05/24-16:49:30.941518 7fdf5affd6c0 Manual compaction at level-0 from '!journal!gVybbv17TFY8o3Y4' @ 72057594037927935 : 1 .. '!journal.pages!gVybbv17TFY8o3Y4.fQidyqfF1TbsZKHM' @ 0 : 0; will stop at (end)
2026/05/24-16:49:30.959159 7fdf5affd6c0 Manual compaction at level-1 from '!journal!gVybbv17TFY8o3Y4' @ 72057594037927935 : 1 .. '!journal.pages!gVybbv17TFY8o3Y4.fQidyqfF1TbsZKHM' @ 0 : 0; will stop at (end)
+7 -3
View File
@@ -1,3 +1,7 @@
2026/05/24-16:10:55.778032 7f1c57fff6c0 Recovering log #407 2026/06/07-00:01:17.675368 7f15ce3fc6c0 Recovering log #425
2026/05/24-16:10:55.794066 7f1c57fff6c0 Delete type=0 #407 2026/06/07-00:01:17.685411 7f15ce3fc6c0 Delete type=3 #423
2026/05/24-16:10:55.794127 7f1c57fff6c0 Delete type=3 #406 2026/06/07-00:01:17.685428 7f15ce3fc6c0 Delete type=0 #425
2026/06/07-00:21:46.748268 7f15cdbfb6c0 Level-0 table #430: started
2026/06/07-00:21:46.748282 7f15cdbfb6c0 Level-0 table #430: 0 bytes OK
2026/06/07-00:21:46.755214 7f15cdbfb6c0 Delete type=0 #428
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)
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
MANIFEST-000402 MANIFEST-000426
+3 -20
View File
@@ -1,20 +1,3 @@
2026/05/24-16:13:27.805283 7fdf5bfff6c0 Recovering log #401 2026/06/07-00:21:50.343006 7f15cebfd6c0 Recovering log #424
2026/05/24-16:13:27.815296 7fdf5bfff6c0 Delete type=0 #401 2026/06/07-00:21:50.352418 7f15cebfd6c0 Delete type=3 #422
2026/05/24-16:13:27.815331 7fdf5bfff6c0 Delete type=3 #400 2026/06/07-00:21:50.352440 7f15cebfd6c0 Delete type=0 #424
2026/05/24-16:49:30.661093 7fdf5affd6c0 Level-0 table #405: started
2026/05/24-16:49:30.661158 7fdf5affd6c0 Level-0 table #405: 0 bytes OK
2026/05/24-16:49:30.698495 7fdf5affd6c0 Manual compaction at level-0 from '!items!0swiE8k5zfUIqmXu' @ 72057594037927935 : 1 .. '!items!wv5EiePmPTpqFutt' @ 0 : 0; will stop at '!items!wv5EiePmPTpqFutt' @ 287 : 1
2026/05/24-16:49:30.698499 7fdf5affd6c0 Compacting 1@0 + 0@1 files
2026/05/24-16:49:30.701559 7fdf5affd6c0 Generated table #406@0: 48 keys, 14533 bytes
2026/05/24-16:49:30.701564 7fdf5affd6c0 Compacted 1@0 + 0@1 files => 14533 bytes
2026/05/24-16:49:30.707420 7fdf5affd6c0 compacted to: files[ 0 1 1 0 0 0 0 ]
2026/05/24-16:49:30.707454 7fdf5affd6c0 Delete type=2 #392
2026/05/24-16:49:30.707535 7fdf5affd6c0 Manual compaction at level-0 from '!items!wv5EiePmPTpqFutt' @ 287 : 1 .. '!items!wv5EiePmPTpqFutt' @ 0 : 0; will stop at (end)
2026/05/24-16:49:30.707559 7fdf5affd6c0 Manual compaction at level-1 from '!items!0swiE8k5zfUIqmXu' @ 72057594037927935 : 1 .. '!items!wv5EiePmPTpqFutt' @ 0 : 0; will stop at '!items!wv5EiePmPTpqFutt' @ 287 : 1
2026/05/24-16:49:30.707561 7fdf5affd6c0 Compacting 1@1 + 1@2 files
2026/05/24-16:49:30.710996 7fdf5affd6c0 Generated table #407@1: 48 keys, 14533 bytes
2026/05/24-16:49:30.711014 7fdf5affd6c0 Compacted 1@1 + 1@2 files => 14533 bytes
2026/05/24-16:49:30.717230 7fdf5affd6c0 compacted to: files[ 0 0 1 0 0 0 0 ]
2026/05/24-16:49:30.717309 7fdf5affd6c0 Delete type=2 #235
2026/05/24-16:49:30.717368 7fdf5affd6c0 Delete type=2 #406
2026/05/24-16:49:30.739563 7fdf5affd6c0 Manual compaction at level-1 from '!items!wv5EiePmPTpqFutt' @ 287 : 1 .. '!items!wv5EiePmPTpqFutt' @ 0 : 0; will stop at (end)
+7 -3
View File
@@ -1,3 +1,7 @@
2026/05/24-16:10:54.653592 7f2f52bfe6c0 Recovering log #399 2026/06/07-00:01:17.549317 7f15ce3fc6c0 Recovering log #420
2026/05/24-16:10:54.665351 7f2f52bfe6c0 Delete type=0 #399 2026/06/07-00:01:17.559821 7f15ce3fc6c0 Delete type=3 #418
2026/05/24-16:10:54.665381 7f2f52bfe6c0 Delete type=3 #398 2026/06/07-00:01:17.559847 7f15ce3fc6c0 Delete type=0 #420
2026/06/07-00:21:46.679739 7f15cdbfb6c0 Level-0 table #425: started
2026/06/07-00:21:46.679750 7f15cdbfb6c0 Level-0 table #425: 0 bytes OK
2026/06/07-00:21:46.685835 7f15cdbfb6c0 Delete type=0 #423
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)
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
MANIFEST-000302 MANIFEST-000325
+3 -13
View File
@@ -1,13 +1,3 @@
2026/05/24-16:13:27.843303 7fdfa8dfe6c0 Recovering log #301 2026/06/07-00:21:50.374568 7f15cf3fe6c0 Recovering log #323
2026/05/24-16:13:27.854272 7fdfa8dfe6c0 Delete type=0 #301 2026/06/07-00:21:50.384637 7f15cf3fe6c0 Delete type=3 #321
2026/05/24-16:13:27.854314 7fdfa8dfe6c0 Delete type=3 #299 2026/06/07-00:21:50.384658 7f15cf3fe6c0 Delete type=0 #323
2026/05/24-16:49:30.749361 7fdf5affd6c0 Level-0 table #305: started
2026/05/24-16:49:30.749380 7fdf5affd6c0 Level-0 table #305: 0 bytes OK
2026/05/24-16:49:30.773159 7fdf5affd6c0 Manual compaction at level-0 from '!items!5dGXNiL3WN4cAk7X' @ 72057594037927935 : 1 .. '!items!zzz9JrtWjELdoAfK' @ 0 : 0; will stop at '!items!zzz9JrtWjELdoAfK' @ 150 : 1
2026/05/24-16:49:30.773164 7fdf5affd6c0 Compacting 1@0 + 1@1 files
2026/05/24-16:49:30.776884 7fdf5affd6c0 Generated table #306@0: 30 keys, 15949 bytes
2026/05/24-16:49:30.776900 7fdf5affd6c0 Compacted 1@0 + 1@1 files => 15949 bytes
2026/05/24-16:49:30.782834 7fdf5affd6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
2026/05/24-16:49:30.782894 7fdf5affd6c0 Delete type=2 #288
2026/05/24-16:49:30.782981 7fdf5affd6c0 Delete type=2 #300
2026/05/24-16:49:30.800757 7fdf5affd6c0 Manual compaction at level-0 from '!items!zzz9JrtWjELdoAfK' @ 150 : 1 .. '!items!zzz9JrtWjELdoAfK' @ 0 : 0; will stop at (end)
+7 -5
View File
@@ -1,5 +1,7 @@
2026/05/24-16:10:54.877151 7f57f93ff6c0 Recovering log #298 2026/06/07-00:01:17.584289 7f15ce3fc6c0 Recovering log #319
2026/05/24-16:10:54.877440 7f57f93ff6c0 Level-0 table #300: started 2026/06/07-00:01:17.594286 7f15ce3fc6c0 Delete type=3 #317
2026/05/24-16:10:54.881592 7f57f93ff6c0 Level-0 table #300: 15949 bytes OK 2026/06/07-00:01:17.594301 7f15ce3fc6c0 Delete type=0 #319
2026/05/24-16:10:54.891689 7f57f93ff6c0 Delete type=0 #298 2026/06/07-00:21:46.698908 7f15cdbfb6c0 Level-0 table #324: started
2026/05/24-16:10:54.891758 7f57f93ff6c0 Delete type=3 #297 2026/06/07-00:21:46.698917 7f15cdbfb6c0 Level-0 table #324: 0 bytes OK
2026/06/07-00:21:46.704788 7f15cdbfb6c0 Delete type=0 #322
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)
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
MANIFEST-000302 MANIFEST-000325
+3 -13
View File
@@ -1,13 +1,3 @@
2026/05/24-16:13:27.829466 7fdf5b7fe6c0 Recovering log #301 2026/06/07-00:21:50.363711 7f15ce3fc6c0 Recovering log #323
2026/05/24-16:13:27.840345 7fdf5b7fe6c0 Delete type=0 #301 2026/06/07-00:21:50.373124 7f15ce3fc6c0 Delete type=3 #321
2026/05/24-16:13:27.840390 7fdf5b7fe6c0 Delete type=3 #299 2026/06/07-00:21:50.373150 7f15ce3fc6c0 Delete type=0 #323
2026/05/24-16:49:30.733360 7fdf5affd6c0 Level-0 table #305: started
2026/05/24-16:49:30.733392 7fdf5affd6c0 Level-0 table #305: 0 bytes OK
2026/05/24-16:49:30.756430 7fdf5affd6c0 Manual compaction at level-0 from '!items!1cZd2hlTV9tykDED' @ 72057594037927935 : 1 .. '!items!y47dBO3Mf5Pn7tOd' @ 0 : 0; will stop at '!items!y47dBO3Mf5Pn7tOd' @ 275 : 1
2026/05/24-16:49:30.756454 7fdf5affd6c0 Compacting 1@0 + 1@1 files
2026/05/24-16:49:30.759808 7fdf5affd6c0 Generated table #306@0: 55 keys, 9796 bytes
2026/05/24-16:49:30.759829 7fdf5affd6c0 Compacted 1@0 + 1@1 files => 9796 bytes
2026/05/24-16:49:30.766114 7fdf5affd6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
2026/05/24-16:49:30.766193 7fdf5affd6c0 Delete type=2 #288
2026/05/24-16:49:30.766365 7fdf5affd6c0 Delete type=2 #300
2026/05/24-16:49:30.783021 7fdf5affd6c0 Manual compaction at level-0 from '!items!y47dBO3Mf5Pn7tOd' @ 275 : 1 .. '!items!y47dBO3Mf5Pn7tOd' @ 0 : 0; will stop at (end)
+7 -5
View File
@@ -1,5 +1,7 @@
2026/05/24-16:10:54.804401 7fc086bff6c0 Recovering log #298 2026/06/07-00:01:17.573032 7f15cfbff6c0 Recovering log #319
2026/05/24-16:10:54.804603 7fc086bff6c0 Level-0 table #300: started 2026/06/07-00:01:17.582308 7f15cfbff6c0 Delete type=3 #317
2026/05/24-16:10:54.809175 7fc086bff6c0 Level-0 table #300: 9796 bytes OK 2026/06/07-00:01:17.582329 7f15cfbff6c0 Delete type=0 #319
2026/05/24-16:10:54.820050 7fc086bff6c0 Delete type=0 #298 2026/06/07-00:21:46.660469 7f15cdbfb6c0 Level-0 table #324: started
2026/05/24-16:10:54.820128 7fc086bff6c0 Delete type=3 #297 2026/06/07-00:21:46.660487 7f15cdbfb6c0 Level-0 table #324: 0 bytes OK
2026/06/07-00:21:46.667102 7f15cdbfb6c0 Delete type=0 #322
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)
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
MANIFEST-000418 MANIFEST-000442
+3 -20
View File
@@ -1,20 +1,3 @@
2026/05/24-16:13:27.793795 7fdf5b7fe6c0 Recovering log #417 2026/06/07-00:21:50.331328 7f15cf3fe6c0 Recovering log #440
2026/05/24-16:13:27.803165 7fdf5b7fe6c0 Delete type=0 #417 2026/06/07-00:21:50.341554 7f15cf3fe6c0 Delete type=3 #438
2026/05/24-16:13:27.803205 7fdf5b7fe6c0 Delete type=3 #416 2026/06/07-00:21:50.341580 7f15cf3fe6c0 Delete type=0 #440
2026/05/24-16:49:30.654051 7fdf5affd6c0 Level-0 table #421: started
2026/05/24-16:49:30.654105 7fdf5affd6c0 Level-0 table #421: 0 bytes OK
2026/05/24-16:49:30.688223 7fdf5affd6c0 Manual compaction at level-0 from '!items!15foLG7y3LUXNzkK' @ 72057594037927935 : 1 .. '!items!z1HtkvazCGHut7cz' @ 0 : 0; will stop at '!items!z1HtkvazCGHut7cz' @ 336 : 1
2026/05/24-16:49:30.688226 7fdf5affd6c0 Compacting 1@0 + 0@1 files
2026/05/24-16:49:30.692355 7fdf5affd6c0 Generated table #422@0: 48 keys, 20398 bytes
2026/05/24-16:49:30.692374 7fdf5affd6c0 Compacted 1@0 + 0@1 files => 20398 bytes
2026/05/24-16:49:30.698404 7fdf5affd6c0 compacted to: files[ 0 1 1 0 0 0 0 ]
2026/05/24-16:49:30.698435 7fdf5affd6c0 Delete type=2 #410
2026/05/24-16:49:30.707532 7fdf5affd6c0 Manual compaction at level-0 from '!items!z1HtkvazCGHut7cz' @ 336 : 1 .. '!items!z1HtkvazCGHut7cz' @ 0 : 0; will stop at (end)
2026/05/24-16:49:30.717401 7fdf5affd6c0 Manual compaction at level-1 from '!items!15foLG7y3LUXNzkK' @ 72057594037927935 : 1 .. '!items!z1HtkvazCGHut7cz' @ 0 : 0; will stop at '!items!z1HtkvazCGHut7cz' @ 336 : 1
2026/05/24-16:49:30.717404 7fdf5affd6c0 Compacting 1@1 + 1@2 files
2026/05/24-16:49:30.720557 7fdf5affd6c0 Generated table #423@1: 48 keys, 20398 bytes
2026/05/24-16:49:30.720563 7fdf5affd6c0 Compacted 1@1 + 1@2 files => 20398 bytes
2026/05/24-16:49:30.726463 7fdf5affd6c0 compacted to: files[ 0 0 1 0 0 0 0 ]
2026/05/24-16:49:30.726537 7fdf5affd6c0 Delete type=2 #352
2026/05/24-16:49:30.726638 7fdf5affd6c0 Delete type=2 #422
2026/05/24-16:49:30.739587 7fdf5affd6c0 Manual compaction at level-1 from '!items!z1HtkvazCGHut7cz' @ 336 : 1 .. '!items!z1HtkvazCGHut7cz' @ 0 : 0; will stop at (end)
+7 -3
View File
@@ -1,3 +1,7 @@
2026/05/24-16:10:55.365745 7f834bfff6c0 Recovering log #415 2026/06/07-00:01:17.537677 7f15cfbff6c0 Recovering log #436
2026/05/24-16:10:55.376057 7f834bfff6c0 Delete type=0 #415 2026/06/07-00:01:17.547496 7f15cfbff6c0 Delete type=3 #434
2026/05/24-16:10:55.376117 7f834bfff6c0 Delete type=3 #414 2026/06/07-00:01:17.547526 7f15cfbff6c0 Delete type=0 #436
2026/06/07-00:21:46.685907 7f15cdbfb6c0 Level-0 table #441: started
2026/06/07-00:21:46.685917 7f15cdbfb6c0 Level-0 table #441: 0 bytes OK
2026/06/07-00:21:46.691937 7f15cdbfb6c0 Delete type=0 #439
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)
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
MANIFEST-000418 MANIFEST-000442
+3 -20
View File
@@ -1,20 +1,3 @@
2026/05/24-16:13:27.895777 7fdfa95ff6c0 Recovering log #417 2026/06/07-00:21:50.420841 7f15cfbff6c0 Recovering log #440
2026/05/24-16:13:27.904649 7fdfa95ff6c0 Delete type=0 #417 2026/06/07-00:21:50.430740 7f15cfbff6c0 Delete type=3 #438
2026/05/24-16:13:27.904673 7fdfa95ff6c0 Delete type=3 #416 2026/06/07-00:21:50.430770 7f15cfbff6c0 Delete type=0 #440
2026/05/24-16:49:30.833777 7fdf5affd6c0 Level-0 table #421: started
2026/05/24-16:49:30.833795 7fdf5affd6c0 Level-0 table #421: 0 bytes OK
2026/05/24-16:49:30.850864 7fdf5affd6c0 Manual compaction at level-0 from '!items!26mRstKhCJoXkhu1' @ 72057594037927935 : 1 .. '!items!tFQqcxmkS3MT6ASE' @ 0 : 0; will stop at '!items!tFQqcxmkS3MT6ASE' @ 105 : 1
2026/05/24-16:49:30.850868 7fdf5affd6c0 Compacting 1@0 + 0@1 files
2026/05/24-16:49:30.854607 7fdf5affd6c0 Generated table #422@0: 15 keys, 30233 bytes
2026/05/24-16:49:30.854633 7fdf5affd6c0 Compacted 1@0 + 0@1 files => 30233 bytes
2026/05/24-16:49:30.862029 7fdf5affd6c0 compacted to: files[ 0 1 1 0 0 0 0 ]
2026/05/24-16:49:30.862120 7fdf5affd6c0 Delete type=2 #410
2026/05/24-16:49:30.878767 7fdf5affd6c0 Manual compaction at level-0 from '!items!tFQqcxmkS3MT6ASE' @ 105 : 1 .. '!items!tFQqcxmkS3MT6ASE' @ 0 : 0; will stop at (end)
2026/05/24-16:49:30.890474 7fdf5affd6c0 Manual compaction at level-1 from '!items!26mRstKhCJoXkhu1' @ 72057594037927935 : 1 .. '!items!tFQqcxmkS3MT6ASE' @ 0 : 0; will stop at '!items!tFQqcxmkS3MT6ASE' @ 105 : 1
2026/05/24-16:49:30.890480 7fdf5affd6c0 Compacting 1@1 + 1@2 files
2026/05/24-16:49:30.895249 7fdf5affd6c0 Generated table #423@1: 15 keys, 30233 bytes
2026/05/24-16:49:30.895261 7fdf5affd6c0 Compacted 1@1 + 1@2 files => 30233 bytes
2026/05/24-16:49:30.908330 7fdf5affd6c0 compacted to: files[ 0 0 1 0 0 0 0 ]
2026/05/24-16:49:30.908435 7fdf5affd6c0 Delete type=2 #352
2026/05/24-16:49:30.908535 7fdf5affd6c0 Delete type=2 #422
2026/05/24-16:49:30.915370 7fdf5affd6c0 Manual compaction at level-1 from '!items!tFQqcxmkS3MT6ASE' @ 105 : 1 .. '!items!tFQqcxmkS3MT6ASE' @ 0 : 0; will stop at (end)
+7 -3
View File
@@ -1,3 +1,7 @@
2026/05/24-16:10:55.440137 7fc32b7ef6c0 Recovering log #415 2026/06/07-00:01:17.628038 7f15cf3fe6c0 Recovering log #436
2026/05/24-16:10:55.459685 7fc32b7ef6c0 Delete type=0 #415 2026/06/07-00:01:17.637109 7f15cf3fe6c0 Delete type=3 #434
2026/05/24-16:10:55.459751 7fc32b7ef6c0 Delete type=3 #414 2026/06/07-00:01:17.637121 7f15cf3fe6c0 Delete type=0 #436
2026/06/07-00:21:46.761269 7f15cdbfb6c0 Level-0 table #441: started
2026/06/07-00:21:46.761294 7f15cdbfb6c0 Level-0 table #441: 0 bytes OK
2026/06/07-00:21:46.768307 7f15cdbfb6c0 Delete type=0 #439
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)
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
MANIFEST-000302 MANIFEST-000325
+3 -13
View File
@@ -1,13 +1,3 @@
2026/05/24-16:13:27.817130 7fdfa8dfe6c0 Recovering log #301 2026/06/07-00:21:50.353793 7f15cfbff6c0 Recovering log #323
2026/05/24-16:13:27.827508 7fdfa8dfe6c0 Delete type=0 #301 2026/06/07-00:21:50.362811 7f15cfbff6c0 Delete type=3 #321
2026/05/24-16:13:27.827563 7fdfa8dfe6c0 Delete type=3 #299 2026/06/07-00:21:50.362829 7f15cfbff6c0 Delete type=0 #323
2026/05/24-16:49:30.726685 7fdf5affd6c0 Level-0 table #305: started
2026/05/24-16:49:30.726704 7fdf5affd6c0 Level-0 table #305: 0 bytes OK
2026/05/24-16:49:30.739601 7fdf5affd6c0 Manual compaction at level-0 from '!items!2hD1DQVeCIQIXFU7' @ 72057594037927935 : 1 .. '!items!veoS6Gtzj6Dq087V' @ 0 : 0; will stop at '!items!veoS6Gtzj6Dq087V' @ 35 : 1
2026/05/24-16:49:30.739606 7fdf5affd6c0 Compacting 1@0 + 1@1 files
2026/05/24-16:49:30.742829 7fdf5affd6c0 Generated table #306@0: 7 keys, 2881 bytes
2026/05/24-16:49:30.742848 7fdf5affd6c0 Compacted 1@0 + 1@1 files => 2881 bytes
2026/05/24-16:49:30.749097 7fdf5affd6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
2026/05/24-16:49:30.749193 7fdf5affd6c0 Delete type=2 #288
2026/05/24-16:49:30.749309 7fdf5affd6c0 Delete type=2 #300
2026/05/24-16:49:30.773136 7fdf5affd6c0 Manual compaction at level-0 from '!items!veoS6Gtzj6Dq087V' @ 35 : 1 .. '!items!veoS6Gtzj6Dq087V' @ 0 : 0; will stop at (end)
+7 -5
View File
@@ -1,5 +1,7 @@
2026/05/24-16:10:54.729976 7f0993fff6c0 Recovering log #298 2026/06/07-00:01:17.561757 7f15cf3fe6c0 Recovering log #319
2026/05/24-16:10:54.730135 7f0993fff6c0 Level-0 table #300: started 2026/06/07-00:01:17.571010 7f15cf3fe6c0 Delete type=3 #317
2026/05/24-16:10:54.734161 7f0993fff6c0 Level-0 table #300: 2881 bytes OK 2026/06/07-00:01:17.571033 7f15cf3fe6c0 Delete type=0 #319
2026/05/24-16:10:54.744747 7f0993fff6c0 Delete type=0 #298 2026/06/07-00:21:46.667152 7f15cdbfb6c0 Level-0 table #324: started
2026/05/24-16:10:54.744817 7f0993fff6c0 Delete type=3 #297 2026/06/07-00:21:46.667166 7f15cdbfb6c0 Level-0 table #324: 0 bytes OK
2026/06/07-00:21:46.673526 7f15cdbfb6c0 Delete type=0 #322
2026/06/07-00:21:46.679679 7f15cdbfb6c0 Manual compaction at level-0 from '!items!2hD1DQVeCIQIXFU7' @ 72057594037927935 : 1 .. '!items!veoS6Gtzj6Dq087V' @ 0 : 0; will stop at (end)
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
MANIFEST-000302 MANIFEST-000325
+3 -13
View File
@@ -1,13 +1,3 @@
2026/05/24-16:13:27.881867 7fdf5bfff6c0 Recovering log #301 2026/06/07-00:21:50.409088 7f15ce3fc6c0 Recovering log #323
2026/05/24-16:13:27.892914 7fdf5bfff6c0 Delete type=0 #301 2026/06/07-00:21:50.419461 7f15ce3fc6c0 Delete type=3 #321
2026/05/24-16:13:27.892950 7fdf5bfff6c0 Delete type=3 #299 2026/06/07-00:21:50.419490 7f15ce3fc6c0 Delete type=0 #323
2026/05/24-16:49:30.800774 7fdf5affd6c0 Level-0 table #305: started
2026/05/24-16:49:30.800796 7fdf5affd6c0 Level-0 table #305: 0 bytes OK
2026/05/24-16:49:30.823354 7fdf5affd6c0 Manual compaction at level-0 from '!items!1JqWbEkHUoKXbsgn' @ 72057594037927935 : 1 .. '!items!xnCf2xIPzdsUoBTy' @ 0 : 0; will stop at '!items!xnCf2xIPzdsUoBTy' @ 225 : 1
2026/05/24-16:49:30.823360 7fdf5affd6c0 Compacting 1@0 + 1@1 files
2026/05/24-16:49:30.827700 7fdf5affd6c0 Generated table #306@0: 45 keys, 33963 bytes
2026/05/24-16:49:30.827710 7fdf5affd6c0 Compacted 1@0 + 1@1 files => 33963 bytes
2026/05/24-16:49:30.833611 7fdf5affd6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
2026/05/24-16:49:30.833659 7fdf5affd6c0 Delete type=2 #288
2026/05/24-16:49:30.833739 7fdf5affd6c0 Delete type=2 #300
2026/05/24-16:49:30.850855 7fdf5affd6c0 Manual compaction at level-0 from '!items!xnCf2xIPzdsUoBTy' @ 225 : 1 .. '!items!xnCf2xIPzdsUoBTy' @ 0 : 0; will stop at (end)
+7 -5
View File
@@ -1,5 +1,7 @@
2026/05/24-16:10:54.953569 7f78713ff6c0 Recovering log #298 2026/06/07-00:01:17.617058 7f15ce3fc6c0 Recovering log #319
2026/05/24-16:10:54.953939 7f78713ff6c0 Level-0 table #300: started 2026/06/07-00:01:17.626625 7f15ce3fc6c0 Delete type=3 #317
2026/05/24-16:10:54.958319 7f78713ff6c0 Level-0 table #300: 33963 bytes OK 2026/06/07-00:01:17.626639 7f15ce3fc6c0 Delete type=0 #319
2026/05/24-16:10:54.968428 7f78713ff6c0 Delete type=0 #298 2026/06/07-00:21:46.716945 7f15cdbfb6c0 Level-0 table #324: started
2026/05/24-16:10:54.968509 7f78713ff6c0 Delete type=3 #297 2026/06/07-00:21:46.716955 7f15cdbfb6c0 Level-0 table #324: 0 bytes OK
2026/06/07-00:21:46.723471 7f15cdbfb6c0 Delete type=0 #322
2026/06/07-00:21:46.729892 7f15cdbfb6c0 Manual compaction at level-0 from '!items!1JqWbEkHUoKXbsgn' @ 72057594037927935 : 1 .. '!items!xnCf2xIPzdsUoBTy' @ 0 : 0; will stop at (end)
Binary file not shown.
View File
View File
+1 -1
View File
@@ -1 +1 @@
MANIFEST-000250 MANIFEST-000273
+3 -14
View File
@@ -1,14 +1,3 @@
2026/05/24-16:13:27.934950 7fdf5b7fe6c0 Recovering log #249 2026/06/07-00:21:50.454761 7f15ce3fc6c0 Recovering log #271
2026/05/24-16:13:27.944727 7fdf5b7fe6c0 Delete type=0 #249 2026/06/07-00:21:50.464634 7f15ce3fc6c0 Delete type=3 #269
2026/05/24-16:13:27.944766 7fdf5b7fe6c0 Delete type=3 #248 2026/06/07-00:21:50.464657 7f15ce3fc6c0 Delete type=0 #271
2026/05/24-16:49:30.868686 7fdf5affd6c0 Level-0 table #253: started
2026/05/24-16:49:30.871770 7fdf5affd6c0 Level-0 table #253: 1897 bytes OK
2026/05/24-16:49:30.908620 7fdf5affd6c0 Manual compaction at level-0 from '!scenes!dYKdGdh2PbtXs32a' @ 72057594037927935 : 1 .. '!scenes.levels!dYKdGdh2PbtXs32a.defaultLevel0000' @ 0 : 0; will stop at (end)
2026/05/24-16:49:30.915400 7fdf5affd6c0 Manual compaction at level-1 from '!scenes!dYKdGdh2PbtXs32a' @ 72057594037927935 : 1 .. '!scenes.levels!dYKdGdh2PbtXs32a.defaultLevel0000' @ 0 : 0; will stop at '!scenes.levels!mfosNsLsHN5Pf4TO.defaultLevel0000' @ 104 : 0
2026/05/24-16:49:30.915405 7fdf5affd6c0 Compacting 1@1 + 1@2 files
2026/05/24-16:49:30.918981 7fdf5affd6c0 Generated table #254@1: 2 keys, 1628 bytes
2026/05/24-16:49:30.918988 7fdf5affd6c0 Compacted 1@1 + 1@2 files => 1628 bytes
2026/05/24-16:49:30.925116 7fdf5affd6c0 compacted to: files[ 0 0 1 0 0 0 0 ]
2026/05/24-16:49:30.925157 7fdf5affd6c0 Delete type=2 #223
2026/05/24-16:49:30.925248 7fdf5affd6c0 Delete type=2 #253
2026/05/24-16:49:30.941527 7fdf5affd6c0 Manual compaction at level-1 from '!scenes.levels!mfosNsLsHN5Pf4TO.defaultLevel0000' @ 104 : 0 .. '!scenes.levels!dYKdGdh2PbtXs32a.defaultLevel0000' @ 0 : 0; will stop at (end)
+7 -3
View File
@@ -1,3 +1,7 @@
2026/05/24-16:10:55.855003 7fcff97ec6c0 Recovering log #247 2026/06/07-00:01:17.661008 7f15cf3fe6c0 Recovering log #267
2026/05/24-16:10:55.867026 7fcff97ec6c0 Delete type=0 #247 2026/06/07-00:01:17.670919 7f15cf3fe6c0 Delete type=3 #265
2026/05/24-16:10:55.867082 7fcff97ec6c0 Delete type=3 #246 2026/06/07-00:01:17.670935 7f15cf3fe6c0 Delete type=0 #267
2026/06/07-00:21:46.723582 7f15cdbfb6c0 Level-0 table #272: started
2026/06/07-00:21:46.723594 7f15cdbfb6c0 Level-0 table #272: 0 bytes OK
2026/06/07-00:21:46.729834 7f15cdbfb6c0 Delete type=0 #270
2026/06/07-00:21:46.742119 7f15cdbfb6c0 Manual compaction at level-0 from '!scenes!dYKdGdh2PbtXs32a' @ 72057594037927935 : 1 .. '!scenes.levels!dYKdGdh2PbtXs32a.defaultLevel0000' @ 0 : 0; will stop at (end)
Binary file not shown.
View File
View File
+1 -1
View File
@@ -1 +1 @@
MANIFEST-000208 MANIFEST-000231
+3 -13
View File
@@ -1,13 +1,3 @@
2026/05/24-16:13:27.781963 7fdf5b7fe6c0 Recovering log #207 2026/06/07-00:21:50.321397 7f15ce3fc6c0 Recovering log #229
2026/05/24-16:13:27.792095 7fdf5b7fe6c0 Delete type=0 #207 2026/06/07-00:21:50.330366 7f15ce3fc6c0 Delete type=3 #227
2026/05/24-16:13:27.792113 7fdf5b7fe6c0 Delete type=3 #205 2026/06/07-00:21:50.330389 7f15ce3fc6c0 Delete type=0 #229
2026/05/24-16:49:30.640321 7fdf5affd6c0 Level-0 table #211: started
2026/05/24-16:49:30.640388 7fdf5affd6c0 Level-0 table #211: 0 bytes OK
2026/05/24-16:49:30.668355 7fdf5affd6c0 Manual compaction at level-0 from '!items!6bmjc4MUduGs9s6n' @ 72057594037927935 : 1 .. '!items!t692JcsGHG4YJIlM' @ 0 : 0; will stop at '!items!t692JcsGHG4YJIlM' @ 49 : 1
2026/05/24-16:49:30.668380 7fdf5affd6c0 Compacting 1@0 + 1@1 files
2026/05/24-16:49:30.671868 7fdf5affd6c0 Generated table #212@0: 8 keys, 3873 bytes
2026/05/24-16:49:30.671886 7fdf5affd6c0 Compacted 1@0 + 1@1 files => 3873 bytes
2026/05/24-16:49:30.678060 7fdf5affd6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
2026/05/24-16:49:30.678393 7fdf5affd6c0 Delete type=2 #194
2026/05/24-16:49:30.678468 7fdf5affd6c0 Delete type=2 #206
2026/05/24-16:49:30.707523 7fdf5affd6c0 Manual compaction at level-0 from '!items!t692JcsGHG4YJIlM' @ 49 : 1 .. '!items!t692JcsGHG4YJIlM' @ 0 : 0; will stop at (end)
+7 -5
View File
@@ -1,5 +1,7 @@
2026/05/24-16:10:55.284487 7f38c97ee6c0 Recovering log #204 2026/06/07-00:01:17.527640 7f15cf3fe6c0 Recovering log #225
2026/05/24-16:10:55.284651 7f38c97ee6c0 Level-0 table #206: started 2026/06/07-00:01:17.536413 7f15cf3fe6c0 Delete type=3 #223
2026/05/24-16:10:55.296249 7f38c97ee6c0 Level-0 table #206: 3873 bytes OK 2026/06/07-00:01:17.536429 7f15cf3fe6c0 Delete type=0 #225
2026/05/24-16:10:55.307332 7f38c97ee6c0 Delete type=0 #204 2026/06/07-00:21:46.673575 7f15cdbfb6c0 Level-0 table #230: started
2026/05/24-16:10:55.307395 7f38c97ee6c0 Delete type=3 #203 2026/06/07-00:21:46.673592 7f15cdbfb6c0 Level-0 table #230: 0 bytes OK
2026/06/07-00:21:46.679599 7f15cdbfb6c0 Delete type=0 #228
2026/06/07-00:21:46.685902 7f15cdbfb6c0 Manual compaction at level-0 from '!items!6bmjc4MUduGs9s6n' @ 72057594037927935 : 1 .. '!items!t692JcsGHG4YJIlM' @ 0 : 0; will stop at (end)
Binary file not shown.
View File
+1 -1
View File
@@ -1 +1 @@
MANIFEST-000300 MANIFEST-000323
+3 -13
View File
@@ -1,13 +1,3 @@
2026/05/24-16:13:27.770260 7fdfa95ff6c0 Recovering log #299 2026/06/07-00:21:50.310068 7f15cfbff6c0 Recovering log #321
2026/05/24-16:13:27.780183 7fdfa95ff6c0 Delete type=0 #299 2026/06/07-00:21:50.320158 7f15cfbff6c0 Delete type=3 #319
2026/05/24-16:13:27.780244 7fdfa95ff6c0 Delete type=3 #297 2026/06/07-00:21:50.320186 7f15cfbff6c0 Delete type=0 #321
2026/05/24-16:49:30.647265 7fdf5affd6c0 Level-0 table #303: started
2026/05/24-16:49:30.647318 7fdf5affd6c0 Level-0 table #303: 0 bytes OK
2026/05/24-16:49:30.678500 7fdf5affd6c0 Manual compaction at level-0 from '!items!0LlzDyCurJedqeyG' @ 72057594037927935 : 1 .. '!items!tq6mEgXog7h4VyWk' @ 0 : 0; will stop at '!items!tq6mEgXog7h4VyWk' @ 75 : 1
2026/05/24-16:49:30.678503 7fdf5affd6c0 Compacting 1@0 + 1@1 files
2026/05/24-16:49:30.681724 7fdf5affd6c0 Generated table #304@0: 15 keys, 8091 bytes
2026/05/24-16:49:30.681731 7fdf5affd6c0 Compacted 1@0 + 1@1 files => 8091 bytes
2026/05/24-16:49:30.688059 7fdf5affd6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
2026/05/24-16:49:30.688095 7fdf5affd6c0 Delete type=2 #286
2026/05/24-16:49:30.688197 7fdf5affd6c0 Delete type=2 #298
2026/05/24-16:49:30.707528 7fdf5affd6c0 Manual compaction at level-0 from '!items!tq6mEgXog7h4VyWk' @ 75 : 1 .. '!items!tq6mEgXog7h4VyWk' @ 0 : 0; will stop at (end)
+7 -5
View File
@@ -1,5 +1,7 @@
2026/05/24-16:10:55.204766 7fed9e3ff6c0 Recovering log #296 2026/06/07-00:01:17.516491 7f15cf3fe6c0 Recovering log #317
2026/05/24-16:10:55.204926 7fed9e3ff6c0 Level-0 table #298: started 2026/06/07-00:01:17.526454 7f15cf3fe6c0 Delete type=3 #315
2026/05/24-16:10:55.209216 7fed9e3ff6c0 Level-0 table #298: 8091 bytes OK 2026/06/07-00:01:17.526475 7f15cf3fe6c0 Delete type=0 #317
2026/05/24-16:10:55.219909 7fed9e3ff6c0 Delete type=0 #296 2026/06/07-00:21:46.653448 7f15cdbfb6c0 Level-0 table #322: started
2026/05/24-16:10:55.219959 7fed9e3ff6c0 Delete type=3 #295 2026/06/07-00:21:46.653485 7f15cdbfb6c0 Level-0 table #322: 0 bytes OK
2026/06/07-00:21:46.660396 7f15cdbfb6c0 Delete type=0 #320
2026/06/07-00:21:46.679667 7f15cdbfb6c0 Manual compaction at level-0 from '!items!0LlzDyCurJedqeyG' @ 72057594037927935 : 1 .. '!items!tq6mEgXog7h4VyWk' @ 0 : 0; will stop at (end)
Binary file not shown.
View File

Some files were not shown because too many files have changed in this diff Show More