165 lines
5.4 KiB
JavaScript
165 lines
5.4 KiB
JavaScript
/**
|
||
* 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.HTMLField({ required: true, 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
|
||
}
|
||
}
|
||
}
|