feat: combat-tracker-driven bleeding (HP loss per wound per round)
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
packs/** filter=lfs diff=lfs merge=lfs -text
|
||||||
Vendored
+6
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"cSpell.words": [
|
||||||
|
"biodata",
|
||||||
|
"LETHALFANTASY"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -117,6 +117,9 @@ Hooks.once("ready", function () {
|
|||||||
registerWorldCount("lethalFantasy")
|
registerWorldCount("lethalFantasy")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Saignement piloté par le combat tracker
|
||||||
|
_registerBleedingHooks()
|
||||||
|
|
||||||
_showUserGuide()
|
_showUserGuide()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -129,6 +132,93 @@ Hooks.once("ready", function () {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saignement piloté par le combat tracker.
|
||||||
|
* Chaque round = 1 seconde → les acteurs qui saignent perdent 1 HP/blessure.
|
||||||
|
* Hors combat, une notification prévient le MJ que des blessures saignent encore.
|
||||||
|
*/
|
||||||
|
function _registerBleedingHooks() {
|
||||||
|
if (!game.user.isGM) return
|
||||||
|
|
||||||
|
Hooks.on("combatRound", async (combat, previous, current) => {
|
||||||
|
if (previous === current) return
|
||||||
|
const processed = new Set()
|
||||||
|
for (const combatant of combat.combatants) {
|
||||||
|
const actor = combatant.actor
|
||||||
|
if (!actor || processed.has(actor.id)) continue
|
||||||
|
processed.add(actor.id)
|
||||||
|
await _applyBleedingTick(actor)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
Hooks.on("combatEnd", async (combat) => {
|
||||||
|
const bleeding = _findBleedingActors()
|
||||||
|
if (bleeding.length) {
|
||||||
|
ui.notifications.warn(
|
||||||
|
`Saignement actif hors combat : ${bleeding.map(a => a.name).join(", ")}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
Hooks.on("combatStart", async (combat) => {
|
||||||
|
const bleeding = _findBleedingActors()
|
||||||
|
if (bleeding.length) {
|
||||||
|
ui.notifications.warn(
|
||||||
|
`Saignement toujours actif sur : ${bleeding.map(a => a.name).join(", ")}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appliquer 1 HP de dégât par blessure active, décrémenter la durée.
|
||||||
|
* @param {import("foundry/common/documents.mjs").Actor} actor
|
||||||
|
*/
|
||||||
|
async function _applyBleedingTick(actor) {
|
||||||
|
if (!actor?.system?.hp?.wounds) return
|
||||||
|
const wounds = foundry.utils.duplicate(actor.system.hp.wounds)
|
||||||
|
let hpLoss = 0
|
||||||
|
let changed = false
|
||||||
|
for (const wound of wounds) {
|
||||||
|
if (wound.duration > 0 && wound.value > 0) {
|
||||||
|
hpLoss += 1
|
||||||
|
wound.duration -= 1
|
||||||
|
if (wound.duration <= 0) {
|
||||||
|
wound.value = 0
|
||||||
|
wound.description = ""
|
||||||
|
}
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!changed) return
|
||||||
|
const currentHp = actor.system.hp.value ?? 0
|
||||||
|
await actor.update({
|
||||||
|
"system.hp.value": currentHp - hpLoss,
|
||||||
|
"system.hp.wounds": wounds,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne les acteurs (monde + tokens) qui ont des blessures actives.
|
||||||
|
* @returns {import("foundry/common/documents.mjs").Actor[]}
|
||||||
|
*/
|
||||||
|
function _findBleedingActors() {
|
||||||
|
const actors = []
|
||||||
|
for (const actor of game.actors.values()) {
|
||||||
|
if (actor?.system?.hp?.wounds?.some(w => w.duration > 0 && w.value > 0)) {
|
||||||
|
actors.push(actor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const token of canvas.tokens?.placeables ?? []) {
|
||||||
|
if (token.actor && !actors.includes(token.actor)) {
|
||||||
|
if (token.actor?.system?.hp?.wounds?.some(w => w.duration > 0 && w.value > 0)) {
|
||||||
|
actors.push(token.actor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return actors
|
||||||
|
}
|
||||||
|
|
||||||
Hooks.on("renderChatMessageHTML", (message, html, data) => {
|
Hooks.on("renderChatMessageHTML", (message, html, data) => {
|
||||||
const typeMessage = data.message.flags.lethalFantasy?.typeMessage
|
const typeMessage = data.message.flags.lethalFantasy?.typeMessage
|
||||||
// Message de demande de jet de dés
|
// Message de demande de jet de dés
|
||||||
|
|||||||
Reference in New Issue
Block a user