/** * DataModel pour les acteurs de type "group" (groupe). * Étend foundry.abstract.TypeDataModel. */ import { woundSchema, combatStatusSchema, equipmentSchema, attributeSchema, levelSchema } from "./_shared.mjs" export default class VermineGroupData extends foundry.abstract.TypeDataModel { /** @override */ static LOCALIZATION_PREFIXES = ["VERMINE.group"] /** @override */ static defineSchema() { const fields = foundry.data.fields return { // Blessures (base) minorWound: new fields.SchemaField(woundSchema(1, 5)), majorWound: new fields.SchemaField(woundSchema(4, 4)), deadlyWound: new fields.SchemaField(woundSchema(8, 2)), // Statut de combat (base) combatStatus: combatStatusSchema(), // Identité du groupe identity: new fields.SchemaField({ totem: new fields.StringField({ required: true, nullable: false, initial: "" }), profile: new fields.StringField({ required: true, nullable: false, initial: "" }), origin: new fields.StringField({ required: true, nullable: false, initial: "" }), theme: new fields.StringField({ required: true, nullable: false, initial: "" }), instincts: new fields.StringField({ required: true, nullable: false, initial: "" }), prohibits: new fields.StringField({ required: true, nullable: false, initial: "" }), notes: new fields.StringField({ required: true, nullable: false, initial: "" }) }), // Équipement equipment: equipmentSchema(), // Niveau du groupe (1-10) level: levelSchema(1, 1, 10), // Réputation reputation: new fields.SchemaField({ value: new fields.NumberField({ required: true, nullable: true, integer: true, initial: 10, min: 2 }), min: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 2, min: 0 }), max: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 10, min: 0 }) }), // Moral morale: new fields.SchemaField({ level: new fields.StringField({ required: true, nullable: false, initial: "high" }), value: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 7, min: 0, max: 7 }), min: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 0, min: 0 }), max: new fields.NumberField({ required: true, nullable: false, integer: true, initial: 7, min: 0 }) }), // Réserve reserve: attributeSchema(0, 0, 10), // Objectifs (majeurs et mineurs) objectives: new fields.SchemaField({ major: new fields.ArrayField(new fields.StringField({ required: true, nullable: false, initial: "" })), minor: new fields.ArrayField(new fields.StringField({ required: true, nullable: false, initial: "" })) }), // Capacités de groupe groupAbilities: new fields.ArrayField(new fields.StringField({ required: true, nullable: false, initial: "" })), // Membres (IDs d'acteurs) members: new fields.ArrayField(new fields.StringField({ required: true, nullable: false, initial: "" })), // Rencontres encounters: new fields.ArrayField(new fields.StringField({ required: true, nullable: false, initial: "" })) } } /** @override */ prepareDerivedData() { super.prepareDerivedData() // 1. Initialiser les données de groupe si absentes this._initGroupData() // 2. Calculer la réserve max selon le niveau this._calculateGroupReserve() // 3. Mettre à jour le moral selon la valeur de dés this._updateGroupMorale() // 4. Mettre à jour le statut de combat this._updateCombatStatus() } /** * Initialise les champs optionnels du groupe s'ils ne sont pas présents. */ _initGroupData() { if (!this.objectives) { this.objectives = { major: [], minor: [] } } if (!this.groupAbilities) { this.groupAbilities = [] } if (!this.reserve) { this.reserve = { value: 0, min: 0, max: 10 } } } /** * Calcule la réserve max en fonction du niveau du groupe. * Règle simplifiée : niveau × 2, plafonné à 10. */ _calculateGroupReserve() { const level = this.level?.value || 1 this.reserve.max = Math.min(10, level * 2) if (this.reserve.value > this.reserve.max) { this.reserve.value = this.reserve.max } } /** * Met à jour le niveau de moral en fonction de la valeur de dés. * Règles : 7D+ = Haut, 6-3D = Normal, 2-1D = Bas, 0D = Crise. */ _updateGroupMorale() { const moraleValue = this.morale?.value || 0 // Ne pas écraser un niveau explicitement défini (sauf "high" qui est la valeur par défaut) if (this.morale.level && this.morale.level !== "high") return if (moraleValue >= 7) { this.morale.level = "high" } else if (moraleValue >= 3) { this.morale.level = "normal" } else if (moraleValue >= 1) { this.morale.level = "low" } else { this.morale.level = "crisis" } } /** * Met à jour le label du statut de combat en fonction de la difficulté. */ _updateCombatStatus() { const difficulty = parseInt(this.combatStatus.difficulty) || 9 let newLabel = "Passif" switch (difficulty) { case 5: newLabel = "Offensif"; break case 7: newLabel = "Actif"; break case 9: newLabel = "Passif"; break } if (this.combatStatus.label !== newLabel) { this.combatStatus.label = newLabel } } }