Correction compendiums
This commit is contained in:
@@ -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 2024–2026 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 })
|
||||
}
|
||||
Reference in New Issue
Block a user