Correction compendiums

This commit is contained in:
2026-04-27 21:30:33 +02:00
parent 1e252ff6f2
commit bc49286f91
76 changed files with 1645 additions and 73 deletions
+87
View File
@@ -0,0 +1,87 @@
/**
* Chroniques de l'Étrange — Système FoundryVTT
*
* Chroniques de l'Étrange est un jeu de rôle édité par Antre-Monde Éditions.
* Ce système FoundryVTT est une implémentation indépendante et n'est pas
* affilié à Antre-Monde Éditions,
* mais a été réalisé avec l'autorisation d'Antre-Monde Éditions.
*
* @author LeRatierBretonnien
* @copyright 20242026 LeRatierBretonnien
* @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
*/
import { rollInitiativePC, rollInitiativeNPC } from "../ui/initiative.js"
import { ACTOR_TYPES } from "../config/constants.js"
/**
* Custom Combat document for Chroniques de l'Étrange.
*
* The initiative wheel has 24 crans (positions). The character with the
* highest initiative acts first (furthest counter-clockwise from reference).
* After each action, their position advances clockwise by the action's cran cost
* (initiative decreases, wrapping from 1 → 24).
*
* Sort order: descending by initiative (highest acts first).
*/
export class CDECombat extends Combat {
/**
* Override rollInitiative to open the PC or NPC initiative dialog
* for each selected combatant, then sync the result to the Combatant document.
*/
async rollInitiative(ids, options = {}) {
const combatantIds = typeof ids === "string" ? [ids] : ids
for (const id of combatantIds) {
const combatant = this.combatants.get(id)
if (!combatant) continue
const actor = combatant.actor
if (!actor) continue
if (actor.type === ACTOR_TYPES.character) {
await rollInitiativePC(actor)
} else {
await rollInitiativeNPC(actor)
}
// combatant.initiative is synced by the updateActor hook in system.js
// (triggered by actor.update inside rollInitiativePC/NPC)
}
return this
}
/**
* Sort combatants: highest initiative first (furthest counter-clockwise = acts first).
* Ties: PCs before NPCs; among PCs, by name; among NPCs, by name.
* Calls super.setupTurns() first to ensure this.current is properly initialized.
*/
setupTurns() {
super.setupTurns()
this.turns = this.turns.slice().sort((a, b) => {
const ia = a.initiative ?? 0
const ib = b.initiative ?? 0
if (ia !== ib) return ib - ia // descending — highest acts first
// Tie-break: PCs before NPCs
const aIsPC = a.actor?.type === ACTOR_TYPES.character ? 1 : 0
const bIsPC = b.actor?.type === ACTOR_TYPES.character ? 1 : 0
if (aIsPC !== bIsPC) return bIsPC - aIsPC
return (a.name ?? "").localeCompare(b.name ?? "")
})
return this.turns
}
}
/**
* Advance a combatant's wheel position by the given action cran cost.
* Position wraps: after reaching 1, it continues from 24.
*
* @param {Combatant} combatant
* @param {number} cranCost
*/
export async function advanceCombatantPosition(combatant, cranCost) {
const current = combatant.initiative ?? combatant.actor?.system?.initiative ?? 1
const newValue = ((current - cranCost - 1 + 48) % 24) + 1
// Update combatant only; the updateCombatant hook in system.js syncs actor.initiative.
await combatant.update({ initiative: newValue })
}