6 Commits
14.0.5 ... main

Author SHA1 Message Date
8e5fb9aca1 Correction sur jauge de destin
All checks were successful
Release Creation / build (release) Successful in 1m26s
2026-04-16 22:26:44 +02:00
1b2a74969d Update READM.md 2026-04-16 08:39:52 +02:00
98a6a41078 Ajout README.md 2026-04-15 11:53:52 +02:00
c73136b3c9 Ajout README.md 2026-04-15 11:41:44 +02:00
49996104ce Roll and styles update
Some checks failed
Release Creation / build (release) Failing after 1m17s
2026-04-15 02:16:51 +02:00
b3cf0b0aa1 Corrections après tests de combat
Some checks failed
Release Creation / build (release) Failing after 1m34s
2026-04-14 18:59:09 +02:00
39 changed files with 653 additions and 271 deletions

84
README.md Normal file
View File

@@ -0,0 +1,84 @@
# Célestopol 1922 — Système FoundryVTT
Système [Foundry VTT](https://foundryvtt.com) pour **Célestopol 1922**, le jeu de rôle d'[Antre Monde Éditions](https://antremonde.fr).
Copyright 2025-2026 Antre Monde Editions All rights reserved
Celestopol 1922 is a game written by Emmanuel Chastellière and Julien Arnaud. The authors retain their moral rights to this work in both print and digital formats.
This system for FoundryVTT has been approved and authorized by Antre-Monde Edition
---
## ✨ Fonctionnalités
### Personnages joueurs (PJ)
- **4 attributs** (Âme, Corps, Cœur, Esprit) × **4 compétences** chacun (16 compétences au total)
- Gestion des **Blessures** (8 niveaux avec malus automatique aux jets)
- Suivi du **Destin** et du **Spleen** (jauges à 8 crans)
- **Anomalies** : 9 types, déclenchées sur certains résultats de dé
- **Factions** : 8 factions standard + 2 personnalisées, avec aspects liés
- **Équipement** : armes, armures, équipements génériques
- Onglets dédiés : Principal · Compétences · Factions · Équipement · Combat · Biographie
### Personnages non-joueurs (PNJ)
- Fiche simplifiée : compétences, blessures, équipement, biographie
### Items
- **Arme** : mêlée ou à distance, modificateurs de portée
- **Armure** : protection et malus éventuels
- **Aspect de faction** : lié à une faction, bonus / usage limité
- **Anomalie** : type, usages, description
- **Équipement** générique
### Mécanique de jet de désde démonstration
- **Pool de d6** : `max(1, compétence + malus_blessures)` dés
- **Bonus Phase de Lune** : automatique selon la phase en cours (0 à +3)
- **Modificateurs** : difficulté et bonus libres via DialogV2
- Seuil de succès standard : **7**
- Résultats spéciaux : **Brio** (+destin), **Contrecoup** (destin), **Triomphe** (+anomalie/spleen), **Catastrophe** (anomalie/+spleen)
### Dé de la Lune
- Jet de dé de lune indépendant (menu contextuel du token)
- 8 faces : Nouvelle Lune, Premiers Croissants, Dernier Croissant, Gibbeuses ×2, Pleine Lune, Lune de Feu, Lune Noire
- Sur certains résultats : **choix de contrepartie** via pop-up (perte d'anomalie, spleen, ou échec catastrophique)
- Carte de résultat avec boutons d'application directe
### Combat
- **Initiative Célestopol** : jet d'initiative avec dé spécial, insertion dans le tracker
- Attaque avec calcul automatique dommages / protection
- Chat de combat avec récapitulatif des dégâts et blessures appliqués
### Compendiums inclus
| Pack | Contenu |
| ------------ | ------------------------------ |
| Anomalies | Les 8 anomalies du jeu de base |
| Prétirés | 8 personnages prêts à jouer |
| Aides de jeu | Aide du système |
| Scènes | Scènes utiles |
## 🎨 Charte graphique
- Police de titre : **CopaseticNF** (Regular + Bold)
- Vert sombre en-tête : `#0c4c0c`
- Orange texte : `#e07b00`
- Fond parchemin : `#f0e8d4`
- Texture en-tête : `assets/ui/fond_cadrille.jpg`
---
## 👤 Auteur
**LeRatierBretonnien / Uberwald**
- Discord : `LeRatierBretonnien`
- Site : [uberwald.me](https://www.uberwald.me)
---
## 📜 Licence
Copyright 2025 Antre Monde Editions All rights reserved
Celestopol 1922 is a game written by Emmanuel Chastellière and Julien Arnaud. The authors retain their moral rights to this work in both print and digital formats.
This system for FoundryVTT has been approved and authorized by Antre-Monde Edition.

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

View File

@@ -39,6 +39,7 @@ import {
} from "./module/applications/_module.mjs" } from "./module/applications/_module.mjs"
const DAMAGE_APPLICATION_FLAG = "damageApplication" const DAMAGE_APPLICATION_FLAG = "damageApplication"
const MOON_EFFECT_FLAG = "moonEffectApplied"
const FACTION_ASPECT_STATE_SETTING = "factionAspectState" const FACTION_ASPECT_STATE_SETTING = "factionAspectState"
const PREGENS_IMPORTED_SETTING = "pregensImported" const PREGENS_IMPORTED_SETTING = "pregensImported"
const WELCOME_SCENE_IMPORTED_SETTING = "welcomeSceneImported" const WELCOME_SCENE_IMPORTED_SETTING = "welcomeSceneImported"
@@ -173,6 +174,9 @@ Hooks.once("ready", async () => {
if (foundry.utils.hasProperty(changed, `flags.${SYSTEM_ID}.${DAMAGE_APPLICATION_FLAG}`)) { if (foundry.utils.hasProperty(changed, `flags.${SYSTEM_ID}.${DAMAGE_APPLICATION_FLAG}`)) {
_updateRenderedChatMessageState(message) _updateRenderedChatMessageState(message)
} }
if (foundry.utils.hasProperty(changed, `flags.${SYSTEM_ID}.${MOON_EFFECT_FLAG}`)) {
_updateRenderedMoonEffectState(message)
}
}) })
_activateExistingChatCards() _activateExistingChatCards()
@@ -548,8 +552,9 @@ function _activateExistingChatCards() {
document.querySelectorAll(".message[data-message-id]").forEach(messageEl => { document.querySelectorAll(".message[data-message-id]").forEach(messageEl => {
const messageId = messageEl.dataset.messageId const messageId = messageEl.dataset.messageId
const message = game.messages.get(messageId) const message = game.messages.get(messageId)
const root = messageEl.querySelector(".celestopol.chat-roll") if (!message) return
if (!message || !root) return const root = messageEl.querySelector(".celestopol.chat-roll, .celestopol-roll.moon-standalone-card")
if (!root) return
_activateChatCardListeners(message, root) _activateChatCardListeners(message, root)
}) })
} }
@@ -559,12 +564,19 @@ function _activateChatCardListeners(message, html) {
if (!root) return if (!root) return
_renderWeaponDamageState(message, root) _renderWeaponDamageState(message, root)
_renderMoonEffectState(message, root)
root.querySelectorAll('[data-action="apply-weapon-damage"]').forEach(button => { root.querySelectorAll('[data-action="apply-weapon-damage"]').forEach(button => {
if (button.dataset.bound === "true") return if (button.dataset.bound === "true") return
button.dataset.bound = "true" button.dataset.bound = "true"
button.addEventListener("click", event => _onApplyWeaponDamageClick(event, message)) button.addEventListener("click", event => _onApplyWeaponDamageClick(event, message))
}) })
root.querySelectorAll('[data-action="apply-moon-effect"]').forEach(button => {
if (button.dataset.bound === "true") return
button.dataset.bound = "true"
button.addEventListener("click", event => _onApplyMoonEffectClick(event, message))
})
} }
async function _onApplyWeaponDamageClick(event, message) { async function _onApplyWeaponDamageClick(event, message) {
@@ -746,6 +758,126 @@ async function _applyWeaponDamage({ actorId, actorUuid = null, incomingWounds, c
return { actorName: actor.name, appliedWounds, armorProtection } return { actorName: actor.name, appliedWounds, armorProtection }
} }
/* ─── Dé de la Lune — contreparties ─────────────────────────────────────── */
function _getMoonEffectState(message) {
return message?.getFlag(SYSTEM_ID, MOON_EFFECT_FLAG) ?? null
}
function _renderMoonEffectState(message, root) {
const state = _getMoonEffectState(message)
const actionsDiv = root.querySelector(".moon-effect-actions")
if (!actionsDiv) return
if (!state?.applied) return
const NEGATIVE_EFFECTS = new Set(["lose-anomaly", "gain-spleen", "lose-destin"])
// Désactiver tous les boutons et afficher le statut
actionsDiv.querySelectorAll(".moon-effect-btn").forEach(btn => { btn.disabled = true })
let statusEl = actionsDiv.querySelector(".moon-effect-applied-status")
if (!statusEl) {
statusEl = document.createElement("span")
actionsDiv.append(statusEl)
}
statusEl.className = "moon-effect-applied-status" + (NEGATIVE_EFFECTS.has(state.effect) ? " is-negative" : "")
statusEl.textContent = state.effectLabel
? game.i18n.format("CELESTOPOL.Moon.effectApplied", { label: state.effectLabel })
: game.i18n.localize("CELESTOPOL.Moon.effectApplied")
}
function _updateRenderedMoonEffectState(message) {
const msgEl = document.querySelector(`.message[data-message-id="${message.id}"]`)
if (!msgEl) return
const root = msgEl.querySelector(".celestopol.chat-roll, .celestopol-roll.moon-standalone-card")
if (!root) return
_renderMoonEffectState(message, root)
}
async function _onApplyMoonEffectClick(event, message) {
event.preventDefault()
const state = _getMoonEffectState(message)
if (state?.applied) return
const button = event.currentTarget
const effect = button.dataset.effect
const actionsDiv = button.closest(".moon-effect-actions")
const actorId = actionsDiv?.dataset.moonActorId ?? ""
const actorUuid = actionsDiv?.dataset.moonActorUuid ?? ""
// Désactiver immédiatement pour éviter les double-clics
actionsDiv?.querySelectorAll(".moon-effect-btn").forEach(btn => { btn.disabled = true })
const actor = await CelestopolRoll.resolveActor({ actorId, actorUuid })
if (!actor) {
ui.notifications.warn(game.i18n.localize("CELESTOPOL.Moon.actorNotFound"))
actionsDiv?.querySelectorAll(".moon-effect-btn").forEach(btn => { btn.disabled = false })
return
}
const effectLabel = await _applyMoonEffect(actor, effect)
if (effectLabel === null) {
actionsDiv?.querySelectorAll(".moon-effect-btn").forEach(btn => { btn.disabled = false })
return
}
await message.setFlag(SYSTEM_ID, MOON_EFFECT_FLAG, { applied: true, effect, effectLabel })
}
async function _applyMoonEffect(actor, effect) {
const i18n = key => game.i18n.localize(`CELESTOPOL.Moon.${key}`)
const anomaly = actor.items.find(i => i.type === "anomaly")
switch (effect) {
case "regain-anomaly": {
if (!anomaly) { ui.notifications.warn(i18n("noAnomaly")); return null }
const max = anomaly.system?.level ?? 0
const cur = anomaly.system?.usesRemaining ?? 0
if (cur >= max) { ui.notifications.warn(i18n("anomalyFull")); return null }
await anomaly.update({ "system.usesRemaining": Math.min(max, cur + 1) })
ui.notifications.info(game.i18n.format("CELESTOPOL.Moon.effectApplied", { label: i18n("effectRegainAnomaly") }))
return i18n("effectRegainAnomaly")
}
case "lose-spleen": {
const cur = actor.system?.spleen?.lvl ?? 0
if (cur <= 0) { ui.notifications.warn(i18n("spleenEmpty")); return null }
await actor.update({ "system.spleen.lvl": Math.max(0, cur - 1) })
ui.notifications.info(game.i18n.format("CELESTOPOL.Moon.effectApplied", { label: i18n("effectLoseSpleen") }))
return i18n("effectLoseSpleen")
}
case "gain-destin": {
const cur = actor.system?.destin?.lvl ?? 0
await actor.update({ "system.destin.lvl": Math.min(8, cur + 2) })
ui.notifications.info(game.i18n.format("CELESTOPOL.Moon.effectApplied", { label: i18n("effectGainDestin") }))
return i18n("effectGainDestin")
}
case "lose-destin": {
const cur = actor.system?.destin?.lvl ?? 0
await actor.update({ "system.destin.lvl": Math.max(0, cur - 2) })
ui.notifications.info(game.i18n.format("CELESTOPOL.Moon.effectApplied", { label: i18n("effectLoseDestin") }))
return i18n("effectLoseDestin")
}
case "lose-anomaly": {
if (!anomaly) { ui.notifications.warn(i18n("noAnomaly")); return null }
const cur = anomaly.system?.usesRemaining ?? 0
if (cur <= 0) { ui.notifications.warn(i18n("anomalyEmpty")); return null }
await anomaly.update({ "system.usesRemaining": Math.max(0, cur - 1) })
ui.notifications.info(game.i18n.format("CELESTOPOL.Moon.effectApplied", { label: i18n("effectLoseAnomaly") }))
return i18n("effectLoseAnomaly")
}
case "gain-spleen": {
const cur = actor.system?.spleen?.lvl ?? 0
if (cur >= 8) { ui.notifications.warn(i18n("spleenFull")); return null }
await actor.update({ "system.spleen.lvl": Math.min(8, cur + 1) })
ui.notifications.info(game.i18n.format("CELESTOPOL.Moon.effectApplied", { label: i18n("effectGainSpleen") }))
return i18n("effectGainSpleen")
}
default:
return null
}
}
function _getDefaultFactionAspectState() { function _getDefaultFactionAspectState() {
return { return {
pointsMax: 8, pointsMax: 8,

View File

@@ -350,7 +350,22 @@
"mauvaiseFortune": "🔴 Mauvaise Fortune", "mauvaiseFortune": "🔴 Mauvaise Fortune",
"chanceInterpret": "Chance", "chanceInterpret": "Chance",
"narrativeInterpret": "Narratif", "narrativeInterpret": "Narratif",
"quantiteHint": "Valeur" "quantiteHint": "Valeur",
"applyChoose": "Choisissez la contrepartie :",
"effectNarrativeOnly": "(Narratif — sans effet mécanique)",
"effectRegainAnomaly": "🌟 Regain d'1 Anomalie",
"effectLoseSpleen": "💚 Perte d'1 Spleen",
"effectGainDestin": "⭐ Gain de 2 Destin",
"effectLoseDestin": "⭐ Perte de 2 Destin",
"effectLoseAnomaly": "❌ Perte d'1 Anomalie",
"effectGainSpleen": "💔 Gain d'1 Spleen",
"effectApplied": "Contrepartie appliquée : {label}",
"noAnomaly": "Ce personnage n'a pas d'anomalie",
"anomalyFull": "L'anomalie est déjà au maximum d'utilisations",
"anomalyEmpty": "L'anomalie n'a plus d'utilisation disponible",
"spleenEmpty": "Le Spleen est déjà à 0",
"spleenFull": "Le Spleen est déjà au maximum",
"actorNotFound": "Personnage introuvable"
}, },
"Difficulty": { "Difficulty": {
"unknown": "Aucun seuil", "unknown": "Aucun seuil",
@@ -449,7 +464,9 @@
"rangeLongue": "Longue portée", "rangeLongue": "Longue portée",
"type": "Type", "type": "Type",
"typeMelee": "Mêlée", "typeMelee": "Mêlée",
"typeDistance": "Distance" "typeDistance": "Distance",
"equip": "Équiper",
"unequip": "Retirer"
}, },
"Armure": { "Armure": {
"protection": "Protection", "protection": "Protection",

View File

@@ -46,6 +46,7 @@ export default class CelestopolActorSheet extends HandlebarsApplicationMixin(fou
skillLevel: CelestopolActorSheet.#onSkillLevel, skillLevel: CelestopolActorSheet.#onSkillLevel,
factionLevel: CelestopolActorSheet.#onFactionLevel, factionLevel: CelestopolActorSheet.#onFactionLevel,
toggleArmure: CelestopolActorSheet.#onToggleArmure, toggleArmure: CelestopolActorSheet.#onToggleArmure,
toggleWeapon: CelestopolActorSheet.#onToggleWeapon,
}, },
} }
@@ -237,6 +238,13 @@ export default class CelestopolActorSheet extends HandlebarsApplicationMixin(fou
if (item?.type === "armure") await item.update({ "system.equipped": !item.system.equipped }) if (item?.type === "armure") await item.update({ "system.equipped": !item.system.equipped })
} }
static async #onToggleWeapon(_event, target) {
const uuid = target.closest('[data-item-uuid]')?.dataset.itemUuid
if (!uuid) return
const item = await fromUuid(uuid)
if (item?.type === "weapon") await item.update({ "system.equipped": !item.system.equipped })
}
static #onFactionLevel(_event, target) { static #onFactionLevel(_event, target) {
if (!this.isEditable) return if (!this.isEditable) return
const factionId = target.dataset.faction const factionId = target.dataset.faction

View File

@@ -320,6 +320,8 @@ export class CelestopolRoll extends Roll {
: null : null
const resolvedWeaponName = (isRangedDefense && selectedCombatTarget?.weaponName) ? selectedCombatTarget.weaponName : weaponName const resolvedWeaponName = (isRangedDefense && selectedCombatTarget?.weaponName) ? selectedCombatTarget.weaponName : weaponName
const resolvedWeaponDegats = (isRangedDefense && selectedCombatTarget?.weaponDegats) ? selectedCombatTarget.weaponDegats : weaponDegats const resolvedWeaponDegats = (isRangedDefense && selectedCombatTarget?.weaponDegats) ? selectedCombatTarget.weaponDegats : weaponDegats
// Dégâts de l'arme adverse en cas d'échec (arme équipée du PNJ ciblé en mêlée, arme distance en esquive)
const incomingWeaponDegats = selectedCombatTarget?.weaponDegats ?? resolvedWeaponDegats
const targetActorId = selectedCombatTarget?.id || "" const targetActorId = selectedCombatTarget?.id || ""
const targetActorUuid = selectedCombatTarget?.uuid || "" const targetActorUuid = selectedCombatTarget?.uuid || ""
const targetActorName = selectedCombatTarget?.name || "" const targetActorName = selectedCombatTarget?.name || ""
@@ -373,6 +375,7 @@ export class CelestopolRoll extends Roll {
weaponType, weaponType,
weaponName: resolvedWeaponName, weaponName: resolvedWeaponName,
weaponDegats: resolvedWeaponDegats, weaponDegats: resolvedWeaponDegats,
incomingWeaponDegats,
targetActorId, targetActorId,
targetActorUuid, targetActorUuid,
targetActorName, targetActorName,
@@ -407,9 +410,9 @@ export class CelestopolRoll extends Roll {
} }
} }
// Mêlée échouée OU défense à distance échouée → le protagoniste subit les dégâts de l'arme PNJ // Mêlée échouée OU défense à distance échouée → le protagoniste (PJ uniquement) subit les dégâts de l'arme PNJ
if (isCombat && (weaponType === "melee" || isRangedDefense) && actor && roll.options.resultType === "failure") { if (isCombat && (weaponType === "melee" || isRangedDefense) && actor?.type === "character" && roll.options.resultType === "failure") {
const incomingWounds = this.getIncomingWounds(resolvedWeaponDegats) const incomingWounds = this.getIncomingWounds(roll.options.incomingWeaponDegats ?? resolvedWeaponDegats)
const protection = this.getActorArmorProtection(actor) const protection = this.getActorArmorProtection(actor)
const appliedWounds = incomingWounds === null const appliedWounds = incomingWounds === null
? 1 ? 1
@@ -555,6 +558,13 @@ export class CelestopolRoll extends Roll {
? Math.max(0, incomingWounds - selectedTargetProtection) ? Math.max(0, incomingWounds - selectedTargetProtection)
: null : null
// Type de l'acteur qui lance le jet (character | npc)
const rollingActor = await this.constructor.resolveActor({
actorUuid: this.options.actorUuid ?? null,
actorId: this.options.actorId ?? null,
})
const actorType = rollingActor?.type ?? this.options.actorType ?? null
// Libellé de difficulté : en combat "Corps PNJ : N", en opposition "vs ?", sinon "Seuil : 11" // Libellé de difficulté : en combat "Corps PNJ : N", en opposition "vs ?", sinon "Seuil : 11"
const difficultyLabel = this.options.isCombat const difficultyLabel = this.options.isCombat
? `${game.i18n.localize("CELESTOPOL.Combat.corpsPnj")} : ${threshold}` ? `${game.i18n.localize("CELESTOPOL.Combat.corpsPnj")} : ${threshold}`
@@ -600,6 +610,8 @@ export class CelestopolRoll extends Roll {
woundLabel, woundLabel,
isResistance: this.options.isResistance ?? false, isResistance: this.options.isResistance ?? false,
isCombat: this.options.isCombat ?? false, isCombat: this.options.isCombat ?? false,
actorType,
isNpcAttack: actorType === "npc",
weaponName: this.options.weaponName ?? null, weaponName: this.options.weaponName ?? null,
weaponDegats, weaponDegats,
weaponType: this.options.weaponType ?? null, weaponType: this.options.weaponType ?? null,
@@ -620,13 +632,17 @@ export class CelestopolRoll extends Roll {
selectedTargetAppliedWounds, selectedTargetAppliedWounds,
availableTargets, availableTargets,
// Dé de lune // Dé de lune
hasMoonDie: moonDieResult !== null, hasMoonDie: moonDieResult !== null,
moonDieResult, moonDieResult,
moonFaceSymbol: moonFace?.symbol ?? "", moonFaceSymbol: moonFace?.symbol ?? "",
moonFaceLabel: moonFace ? game.i18n.localize(moonFace.label) : "", moonFaceLabel: moonFace ? game.i18n.localize(moonFace.label) : "",
moonResultClass: moonResultType?.cssClass ?? "", moonResultClass: moonResultType?.cssClass ?? "",
moonResultLabel: moonResultType ? game.i18n.localize(moonResultType.label) : "", moonResultLabel: moonResultType ? game.i18n.localize(moonResultType.label) : "",
moonResultDesc: moonResultType ? game.i18n.localize(moonResultType.desc) : "", moonResultDesc: moonResultType ? game.i18n.localize(moonResultType.desc) : "",
moonResultTypeId: moonResultType?.id ?? null,
moonActorId: (actorType === "character") ? (this.options.actorId ?? null) : null,
moonActorUuid: (actorType === "character") ? (this.options.actorUuid ?? null) : null,
moonActorIsCharacter: actorType === "character",
isPrivate, isPrivate,
tooltip: isPrivate ? "" : await this.getTooltip(), tooltip: isPrivate ? "" : await this.getTooltip(),
} }
@@ -686,15 +702,20 @@ export class CelestopolRoll extends Roll {
const resultType = face ? SYSTEM.MOON_RESULT_TYPES[face.result] ?? null : null const resultType = face ? SYSTEM.MOON_RESULT_TYPES[face.result] ?? null : null
const isGoodFortune = result <= 4 const isGoodFortune = result <= 4
const actorIsCharacter = actor?.type === "character"
const templateData = { const templateData = {
result, result,
moonFaceSymbol: face?.symbol ?? "", moonFaceSymbol: face?.symbol ?? "",
moonFaceLabel: face ? game.i18n.localize(face.label) : "", moonFaceLabel: face ? game.i18n.localize(face.label) : "",
moonResultLabel: resultType ? game.i18n.localize(resultType.label) : "", moonResultLabel: resultType ? game.i18n.localize(resultType.label) : "",
moonResultDesc: resultType ? game.i18n.localize(resultType.desc) : "", moonResultDesc: resultType ? game.i18n.localize(resultType.desc) : "",
moonResultClass: resultType?.cssClass ?? "", moonResultClass: resultType?.cssClass ?? "",
moonResultTypeId: resultType?.id ?? null,
isGoodFortune, isGoodFortune,
actorName: actor?.name ?? null, actorName: actor?.name ?? null,
moonActorIsCharacter: actorIsCharacter,
moonActorId: actorIsCharacter ? (actor.id ?? null) : null,
moonActorUuid: actorIsCharacter ? (actor.uuid ?? null) : null,
} }
const content = await foundry.applications.handlebars.renderTemplate( const content = await foundry.applications.handlebars.renderTemplate(
@@ -709,7 +730,6 @@ export class CelestopolRoll extends Roll {
await ChatMessage.create({ await ChatMessage.create({
content, content,
speaker, speaker,
rolls: [roll],
style: CONST.CHAT_MESSAGE_STYLES.OTHER, style: CONST.CHAT_MESSAGE_STYLES.OTHER,
}) })
} }

View File

@@ -13,8 +13,6 @@
import { SYSTEM } from "../config/system.mjs" import { SYSTEM } from "../config/system.mjs"
const WEAPON_DAMAGE_PRIORITY = { "0": 0, "1": 1, "2": 2, X: 3 }
export default class CelestopolCharacter extends foundry.abstract.TypeDataModel { export default class CelestopolCharacter extends foundry.abstract.TypeDataModel {
static defineSchema() { static defineSchema() {
const fields = foundry.data.fields const fields = foundry.data.fields
@@ -233,7 +231,7 @@ export default class CelestopolCharacter extends foundry.abstract.TypeDataModel
woundLevel: this.blessures.lvl, woundLevel: this.blessures.lvl,
difficulty: this.prefs.difficulty, difficulty: this.prefs.difficulty,
rollMoonDie: this.prefs.rollMoonDie ?? false, rollMoonDie: this.prefs.rollMoonDie ?? false,
destGaugeFull: this.destin.lvl > 0, destGaugeFull: this.destin.lvl >= 8,
fortuneValue: this.attributs.fortune.value, fortuneValue: this.attributs.fortune.value,
}) })
} }
@@ -275,40 +273,39 @@ export default class CelestopolCharacter extends foundry.abstract.TypeDataModel
* Collecte les cibles de combat sur la scène active. * Collecte les cibles de combat sur la scène active.
* Pour un PJ attaquant, seules les cibles PNJ présentes sur la scène sont proposées. * Pour un PJ attaquant, seules les cibles PNJ présentes sur la scène sont proposées.
* @param {object} options * @param {object} options
* @param {boolean} [options.onlyRanged=false] * @param {boolean} [options.onlyRanged=false] - Filtrer sur les PNJ ayant une arme à distance équipée
* @param {boolean} [options.fallbackToAll=false] * @param {boolean} [options.fallbackToAll=false] - Revenir à tous les PNJ si aucune cible trouvée
* @param {boolean} [options.includeMeleeWeapon=false] - Inclure l'arme de mêlée équipée du PNJ (dégâts adverses)
* @returns {Array<{id:string, uuid:string, name:string, corps:number, weaponName?:string, weaponDegats?:string}>} * @returns {Array<{id:string, uuid:string, name:string, corps:number, weaponName?:string, weaponDegats?:string}>}
*/ */
_getCombatTargets({ onlyRanged = false, fallbackToAll = false } = {}) { _getCombatTargets({ onlyRanged = false, fallbackToAll = false, includeMeleeWeapon = false } = {}) {
const getBestRangedWeapon = actor => { const getEquippedWeapon = (actor, type) =>
const rangedWeapons = actor.itemTypes?.weapon?.filter(item => item.system.type === "distance") ?? [] actor.itemTypes?.weapon?.find(item => item.system.type === type && item.system.equipped) ?? null
if (!rangedWeapons.length) return null
return rangedWeapons.reduce((best, item) => { const toEntry = actor => {
if (!best) return item const entry = {
const bestPriority = WEAPON_DAMAGE_PRIORITY[best.system.degats] ?? -1 id: actor.id,
const itemPriority = WEAPON_DAMAGE_PRIORITY[item.system.degats] ?? -1 uuid: actor.uuid,
if (itemPriority !== bestPriority) return itemPriority > bestPriority ? item : best name: actor.name,
return item.name.localeCompare(best.name) < 0 ? item : best corps: actor.system.stats?.corps?.res ?? 0,
}, null) }
if (onlyRanged) {
const weapon = getEquippedWeapon(actor, "distance")
if (weapon) {
entry.weaponName = weapon.name
entry.weaponDegats = weapon.system.degats
}
} else if (includeMeleeWeapon) {
const weapon = getEquippedWeapon(actor, "melee")
entry.weaponDegats = weapon ? weapon.system.degats : "0"
}
return entry
} }
const toEntry = actor => ({
id: actor.id,
uuid: actor.uuid,
name: actor.name,
corps: actor.system.stats?.corps?.res ?? 0,
...(onlyRanged ? (() => {
const weapon = getBestRangedWeapon(actor)
return weapon ? {
weaponName: weapon.name,
weaponDegats: weapon.system.degats,
} : {}
})() : {}),
})
const sceneTokens = canvas?.scene?.isView ? (canvas.tokens?.placeables ?? []) : [] const sceneTokens = canvas?.scene?.isView ? (canvas.tokens?.placeables ?? []) : []
const targets = [...new Map(sceneTokens const targets = [...new Map(sceneTokens
.filter(t => t.actor?.type === "npc" && t.actor.id !== this.parent.id) .filter(t => t.actor?.type === "npc" && t.actor.id !== this.parent.id)
.filter(t => !onlyRanged || getBestRangedWeapon(t.actor)) .filter(t => !onlyRanged || getEquippedWeapon(t.actor, "distance"))
.map(t => { .map(t => {
const actor = t.actor const actor = t.actor
return [actor.uuid, toEntry(actor)] return [actor.uuid, toEntry(actor)]
@@ -346,20 +343,19 @@ export default class CelestopolCharacter extends foundry.abstract.TypeDataModel
armorMalus: this.getArmorMalusForRoll("corps", "echauffouree"), armorMalus: this.getArmorMalusForRoll("corps", "echauffouree"),
woundLevel: this.blessures.lvl, woundLevel: this.blessures.lvl,
rollMoonDie: this.prefs.rollMoonDie ?? false, rollMoonDie: this.prefs.rollMoonDie ?? false,
destGaugeFull: this.destin.lvl > 0, destGaugeFull: this.destin.lvl >= 8,
fortuneValue: this.attributs.fortune.value, fortuneValue: this.attributs.fortune.value,
isCombat: true, isCombat: true,
isRangedDefense: false, isRangedDefense: false,
weaponType: item.system.type, weaponType: item.system.type,
weaponName: item.name, weaponName: item.name,
weaponDegats: item.system.degats, weaponDegats: item.system.degats,
availableTargets: this._getCombatTargets(), availableTargets: this._getCombatTargets({ includeMeleeWeapon: item.system.type === "melee" }),
}) })
} }
/** /**
* Lance une attaque de mêlée à mains nues. * Lance une attaque à mains nues (Échauffourée sans arme).
* @returns {Promise<import("../documents/roll.mjs").CelestopolRoll|null>}
*/ */
async rollUnarmedAttack() { async rollUnarmedAttack() {
const { CelestopolRoll } = await import("../documents/roll.mjs") const { CelestopolRoll } = await import("../documents/roll.mjs")
@@ -380,14 +376,14 @@ export default class CelestopolCharacter extends foundry.abstract.TypeDataModel
armorMalus: this.getArmorMalusForRoll("corps", "echauffouree"), armorMalus: this.getArmorMalusForRoll("corps", "echauffouree"),
woundLevel: this.blessures.lvl, woundLevel: this.blessures.lvl,
rollMoonDie: this.prefs.rollMoonDie ?? false, rollMoonDie: this.prefs.rollMoonDie ?? false,
destGaugeFull: this.destin.lvl > 0, destGaugeFull: this.destin.lvl >= 8,
fortuneValue: this.attributs.fortune.value, fortuneValue: this.attributs.fortune.value,
isCombat: true, isCombat: true,
isRangedDefense: false, isRangedDefense: false,
weaponType: "melee", weaponType: "melee",
weaponName: game.i18n.localize("CELESTOPOL.Combat.unarmedAttack"), weaponName: game.i18n.localize("CELESTOPOL.Combat.unarmedAttack"),
weaponDegats: "0", weaponDegats: "0",
availableTargets: this._getCombatTargets(), availableTargets: this._getCombatTargets({ includeMeleeWeapon: true }),
}) })
} }
@@ -419,14 +415,14 @@ export default class CelestopolCharacter extends foundry.abstract.TypeDataModel
armorMalus: this.getArmorMalusForRoll("corps", "mobilite"), armorMalus: this.getArmorMalusForRoll("corps", "mobilite"),
woundLevel: this.blessures.lvl, woundLevel: this.blessures.lvl,
rollMoonDie: this.prefs.rollMoonDie ?? false, rollMoonDie: this.prefs.rollMoonDie ?? false,
destGaugeFull: this.destin.lvl > 0, destGaugeFull: this.destin.lvl >= 8,
fortuneValue: this.attributs.fortune.value, fortuneValue: this.attributs.fortune.value,
isCombat: true, isCombat: true,
isRangedDefense: true, isRangedDefense: true,
weaponType: "distance", weaponType: "distance",
weaponName: item.name, weaponName: item.name,
weaponDegats: "0", weaponDegats: "0",
availableTargets: this._getCombatTargets(), availableTargets: this._getCombatTargets({ onlyRanged: true, fallbackToAll: true }),
}) })
} }
@@ -453,7 +449,7 @@ export default class CelestopolCharacter extends foundry.abstract.TypeDataModel
armorMalus: this.getArmorMalusForRoll("corps", "mobilite"), armorMalus: this.getArmorMalusForRoll("corps", "mobilite"),
woundLevel: this.blessures.lvl, woundLevel: this.blessures.lvl,
rollMoonDie: this.prefs.rollMoonDie ?? false, rollMoonDie: this.prefs.rollMoonDie ?? false,
destGaugeFull: this.destin.lvl > 0, destGaugeFull: this.destin.lvl >= 8,
fortuneValue: this.attributs.fortune.value, fortuneValue: this.attributs.fortune.value,
isCombat: true, isCombat: true,
isRangedDefense: true, isRangedDefense: true,

View File

@@ -85,6 +85,7 @@ export class CelestopolWeapon extends foundry.abstract.TypeDataModel {
choices: Object.keys(SYSTEM.WEAPON_DAMAGE_TYPES) }), choices: Object.keys(SYSTEM.WEAPON_DAMAGE_TYPES) }),
portee: new fields.StringField({ required: true, nullable: false, initial: "contact", portee: new fields.StringField({ required: true, nullable: false, initial: "contact",
choices: Object.keys(SYSTEM.WEAPON_RANGE_TYPES) }), choices: Object.keys(SYSTEM.WEAPON_RANGE_TYPES) }),
equipped: new fields.BooleanField({ initial: false }),
description: new fields.HTMLField({ required: true, textSearch: true }), description: new fields.HTMLField({ required: true, textSearch: true }),
} }
} }

View File

@@ -1 +1 @@
MANIFEST-000070 MANIFEST-000076

View File

@@ -1,8 +1,8 @@
2026/04/14-00:55:24.427256 7f68497ed6c0 Recovering log #68 2026/04/14-21:45:17.258246 7fc1d9fbd6c0 Recovering log #75
2026/04/14-00:55:24.442232 7f68497ed6c0 Delete type=3 #66 2026/04/14-21:45:17.274015 7fc1d9fbd6c0 Delete type=0 #75
2026/04/14-00:55:24.442302 7f68497ed6c0 Delete type=0 #68 2026/04/14-21:45:17.274077 7fc1d9fbd6c0 Delete type=3 #74
2026/04/14-00:56:01.490011 7f6833fff6c0 Level-0 table #73: started 2026/04/15-02:16:16.676658 7fc1d8fbb6c0 Level-0 table #79: started
2026/04/14-00:56:01.490050 7f6833fff6c0 Level-0 table #73: 0 bytes OK 2026/04/15-02:16:16.676686 7fc1d8fbb6c0 Level-0 table #79: 0 bytes OK
2026/04/14-00:56:01.496026 7f6833fff6c0 Delete type=0 #71 2026/04/15-02:16:16.720642 7fc1d8fbb6c0 Delete type=0 #77
2026/04/14-00:56:01.502797 7f6833fff6c0 Manual compaction at level-0 from '!journal!eNYstmPK0mMmVJYC' @ 72057594037927935 : 1 .. '!journal.pages!eNYstmPK0mMmVJYC.r9h1ggd3G9hiqYJX' @ 0 : 0; will stop at (end) 2026/04/15-02:16:16.819908 7fc1d8fbb6c0 Manual compaction at level-0 from '!journal!eNYstmPK0mMmVJYC' @ 72057594037927935 : 1 .. '!journal.pages!eNYstmPK0mMmVJYC.r9h1ggd3G9hiqYJX' @ 0 : 0; will stop at (end)
2026/04/14-00:56:01.513341 7f6833fff6c0 Manual compaction at level-1 from '!journal!eNYstmPK0mMmVJYC' @ 72057594037927935 : 1 .. '!journal.pages!eNYstmPK0mMmVJYC.r9h1ggd3G9hiqYJX' @ 0 : 0; will stop at (end) 2026/04/15-02:16:16.881523 7fc1d8fbb6c0 Manual compaction at level-1 from '!journal!eNYstmPK0mMmVJYC' @ 72057594037927935 : 1 .. '!journal.pages!eNYstmPK0mMmVJYC.r9h1ggd3G9hiqYJX' @ 0 : 0; will stop at (end)

View File

@@ -1,8 +1,3 @@
2026/04/14-00:42:19.979759 7f68497ed6c0 Recovering log #64 2026/04/14-10:43:54.304360 7fddcbfff6c0 Recovering log #72
2026/04/14-00:42:19.989860 7f68497ed6c0 Delete type=3 #62 2026/04/14-10:43:54.314599 7fddcbfff6c0 Delete type=3 #70
2026/04/14-00:42:19.989918 7f68497ed6c0 Delete type=0 #64 2026/04/14-10:43:54.314647 7fddcbfff6c0 Delete type=0 #72
2026/04/14-00:50:27.807116 7f6833fff6c0 Level-0 table #69: started
2026/04/14-00:50:27.807197 7f6833fff6c0 Level-0 table #69: 0 bytes OK
2026/04/14-00:50:27.813335 7f6833fff6c0 Delete type=0 #67
2026/04/14-00:50:27.836261 7f6833fff6c0 Manual compaction at level-0 from '!journal!eNYstmPK0mMmVJYC' @ 72057594037927935 : 1 .. '!journal.pages!eNYstmPK0mMmVJYC.r9h1ggd3G9hiqYJX' @ 0 : 0; will stop at (end)
2026/04/14-00:50:27.836305 7f6833fff6c0 Manual compaction at level-1 from '!journal!eNYstmPK0mMmVJYC' @ 72057594037927935 : 1 .. '!journal.pages!eNYstmPK0mMmVJYC.r9h1ggd3G9hiqYJX' @ 0 : 0; will stop at (end)

View File

@@ -1 +1 @@
MANIFEST-000122 MANIFEST-000129

View File

@@ -1,15 +1,24 @@
2026/04/14-00:55:24.391968 7f6848fec6c0 Recovering log #119 2026/04/14-21:45:17.210322 7fc1dafbf6c0 Recovering log #128
2026/04/14-00:55:24.406978 7f6848fec6c0 Delete type=3 #117 2026/04/14-21:45:17.212264 7fc1dafbf6c0 Level-0 table #130: started
2026/04/14-00:55:24.407044 7f6848fec6c0 Delete type=0 #119 2026/04/14-21:45:17.217282 7fc1dafbf6c0 Level-0 table #130: 3524 bytes OK
2026/04/14-00:56:01.480723 7f6833fff6c0 Level-0 table #125: started 2026/04/14-21:45:17.232642 7fc1dafbf6c0 Delete type=0 #128
2026/04/14-00:56:01.483872 7f6833fff6c0 Level-0 table #125: 3524 bytes OK 2026/04/14-21:45:17.232776 7fc1dafbf6c0 Delete type=3 #127
2026/04/14-00:56:01.489828 7f6833fff6c0 Delete type=0 #123 2026/04/15-02:16:16.615618 7fc1d8fbb6c0 Level-0 table #133: started
2026/04/14-00:56:01.502786 7f6833fff6c0 Manual compaction at level-0 from '!items!anomCommMorts001' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at (end) 2026/04/15-02:16:16.640160 7fc1d8fbb6c0 Level-0 table #133: 3524 bytes OK
2026/04/14-00:56:01.502828 7f6833fff6c0 Manual compaction at level-1 from '!items!anomCommMorts001' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at '!items!null' @ 105 : 1 2026/04/15-02:16:16.676484 7fc1d8fbb6c0 Delete type=0 #131
2026/04/14-00:56:01.502835 7f6833fff6c0 Compacting 1@1 + 1@2 files 2026/04/15-02:16:16.763469 7fc1d8fbb6c0 Manual compaction at level-0 from '!items!anomCommMorts001' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at '!items!null' @ 109 : 1
2026/04/14-00:56:01.506551 7f6833fff6c0 Generated table #126@1: 9 keys, 6617 bytes 2026/04/15-02:16:16.763478 7fc1d8fbb6c0 Compacting 2@0 + 0@1 files
2026/04/14-00:56:01.506586 7f6833fff6c0 Compacted 1@1 + 1@2 files => 6617 bytes 2026/04/15-02:16:16.781648 7fc1d8fbb6c0 Generated table #134@0: 1 keys, 1363 bytes
2026/04/14-00:56:01.512723 7f6833fff6c0 compacted to: files[ 0 0 1 0 0 0 0 ] 2026/04/15-02:16:16.781712 7fc1d8fbb6c0 Compacted 2@0 + 0@1 files => 1363 bytes
2026/04/14-00:56:01.513072 7f6833fff6c0 Delete type=2 #121 2026/04/15-02:16:16.819583 7fc1d8fbb6c0 compacted to: files[ 0 1 1 0 0 0 0 ]
2026/04/14-00:56:01.513274 7f6833fff6c0 Delete type=2 #125 2026/04/15-02:16:16.819716 7fc1d8fbb6c0 Delete type=2 #130
2026/04/14-00:56:01.519560 7f6833fff6c0 Manual compaction at level-1 from '!items!null' @ 105 : 1 .. '!items!null' @ 0 : 0; will stop at (end) 2026/04/15-02:16:16.819841 7fc1d8fbb6c0 Delete type=2 #133
2026/04/15-02:16:16.881505 7fc1d8fbb6c0 Manual compaction at level-0 from '!items!null' @ 109 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
2026/04/15-02:16:16.881561 7fc1d8fbb6c0 Manual compaction at level-1 from '!items!anomCommMorts001' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at '!items!null' @ 116 : 1
2026/04/15-02:16:16.881568 7fc1d8fbb6c0 Compacting 1@1 + 1@2 files
2026/04/15-02:16:16.899721 7fc1d8fbb6c0 Generated table #135@1: 9 keys, 6617 bytes
2026/04/15-02:16:16.899762 7fc1d8fbb6c0 Compacted 1@1 + 1@2 files => 6617 bytes
2026/04/15-02:16:16.937990 7fc1d8fbb6c0 compacted to: files[ 0 0 1 0 0 0 0 ]
2026/04/15-02:16:16.938116 7fc1d8fbb6c0 Delete type=2 #126
2026/04/15-02:16:16.938278 7fc1d8fbb6c0 Delete type=2 #134
2026/04/15-02:16:17.092334 7fc1d8fbb6c0 Manual compaction at level-1 from '!items!null' @ 116 : 1 .. '!items!null' @ 0 : 0; will stop at (end)

View File

@@ -1,15 +1,3 @@
2026/04/14-00:42:19.950173 7f684a7ef6c0 Recovering log #114 2026/04/14-10:43:54.279048 7fddd97be6c0 Recovering log #124
2026/04/14-00:42:19.961639 7f684a7ef6c0 Delete type=3 #112 2026/04/14-10:43:54.288686 7fddd97be6c0 Delete type=3 #122
2026/04/14-00:42:19.961720 7f684a7ef6c0 Delete type=0 #114 2026/04/14-10:43:54.288755 7fddd97be6c0 Delete type=0 #124
2026/04/14-00:50:27.813444 7f6833fff6c0 Level-0 table #120: started
2026/04/14-00:50:27.816594 7f6833fff6c0 Level-0 table #120: 3524 bytes OK
2026/04/14-00:50:27.823812 7f6833fff6c0 Delete type=0 #118
2026/04/14-00:50:27.836273 7f6833fff6c0 Manual compaction at level-0 from '!items!anomCommMorts001' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
2026/04/14-00:50:27.836318 7f6833fff6c0 Manual compaction at level-1 from '!items!anomCommMorts001' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at '!items!null' @ 101 : 1
2026/04/14-00:50:27.836325 7f6833fff6c0 Compacting 1@1 + 1@2 files
2026/04/14-00:50:27.839513 7f6833fff6c0 Generated table #121@1: 9 keys, 6617 bytes
2026/04/14-00:50:27.839549 7f6833fff6c0 Compacted 1@1 + 1@2 files => 6617 bytes
2026/04/14-00:50:27.846476 7f6833fff6c0 compacted to: files[ 0 0 1 0 0 0 0 ]
2026/04/14-00:50:27.846640 7f6833fff6c0 Delete type=2 #116
2026/04/14-00:50:27.846851 7f6833fff6c0 Delete type=2 #120
2026/04/14-00:50:27.853500 7f6833fff6c0 Manual compaction at level-1 from '!items!null' @ 101 : 1 .. '!items!null' @ 0 : 0; will stop at (end)

Binary file not shown.

View File

@@ -1 +1 @@
MANIFEST-000031 MANIFEST-000037

View File

@@ -1,8 +1,8 @@
2026/04/14-00:55:24.409141 7f68497ed6c0 Recovering log #29 2026/04/14-21:45:17.237698 7fc1da7be6c0 Recovering log #36
2026/04/14-00:55:24.424702 7f68497ed6c0 Delete type=3 #27 2026/04/14-21:45:17.253057 7fc1da7be6c0 Delete type=0 #36
2026/04/14-00:55:24.424755 7f68497ed6c0 Delete type=0 #29 2026/04/14-21:45:17.253185 7fc1da7be6c0 Delete type=3 #35
2026/04/14-00:56:01.473754 7f6833fff6c0 Level-0 table #34: started 2026/04/15-02:16:16.720764 7fc1d8fbb6c0 Level-0 table #40: started
2026/04/14-00:56:01.473797 7f6833fff6c0 Level-0 table #34: 0 bytes OK 2026/04/15-02:16:16.720792 7fc1d8fbb6c0 Level-0 table #40: 0 bytes OK
2026/04/14-00:56:01.480607 7f6833fff6c0 Delete type=0 #32 2026/04/15-02:16:16.763312 7fc1d8fbb6c0 Delete type=0 #38
2026/04/14-00:56:01.502772 7f6833fff6c0 Manual compaction at level-0 from '!actors!6RZ6IzJUHm4dB5Ut' @ 72057594037927935 : 1 .. '!folders!MbFQgPdF6Gtbj5AU' @ 0 : 0; will stop at (end) 2026/04/15-02:16:16.819920 7fc1d8fbb6c0 Manual compaction at level-0 from '!actors!6RZ6IzJUHm4dB5Ut' @ 72057594037927935 : 1 .. '!folders!MbFQgPdF6Gtbj5AU' @ 0 : 0; will stop at (end)
2026/04/14-00:56:01.502817 7f6833fff6c0 Manual compaction at level-1 from '!actors!6RZ6IzJUHm4dB5Ut' @ 72057594037927935 : 1 .. '!folders!MbFQgPdF6Gtbj5AU' @ 0 : 0; will stop at (end) 2026/04/15-02:16:16.881536 7fc1d8fbb6c0 Manual compaction at level-1 from '!actors!6RZ6IzJUHm4dB5Ut' @ 72057594037927935 : 1 .. '!folders!MbFQgPdF6Gtbj5AU' @ 0 : 0; will stop at (end)

View File

@@ -1,8 +1,3 @@
2026/04/14-00:42:19.965653 7f684a7ef6c0 Recovering log #25 2026/04/14-10:43:54.291004 7fddd8fbd6c0 Recovering log #33
2026/04/14-00:42:19.975753 7f684a7ef6c0 Delete type=3 #23 2026/04/14-10:43:54.301929 7fddd8fbd6c0 Delete type=3 #31
2026/04/14-00:42:19.975845 7f684a7ef6c0 Delete type=0 #25 2026/04/14-10:43:54.301981 7fddd8fbd6c0 Delete type=0 #33
2026/04/14-00:50:27.823985 7f6833fff6c0 Level-0 table #30: started
2026/04/14-00:50:27.824016 7f6833fff6c0 Level-0 table #30: 0 bytes OK
2026/04/14-00:50:27.829926 7f6833fff6c0 Delete type=0 #28
2026/04/14-00:50:27.836282 7f6833fff6c0 Manual compaction at level-0 from '!actors!6RZ6IzJUHm4dB5Ut' @ 72057594037927935 : 1 .. '!folders!MbFQgPdF6Gtbj5AU' @ 0 : 0; will stop at (end)
2026/04/14-00:50:27.846965 7f6833fff6c0 Manual compaction at level-1 from '!actors!6RZ6IzJUHm4dB5Ut' @ 72057594037927935 : 1 .. '!folders!MbFQgPdF6Gtbj5AU' @ 0 : 0; will stop at (end)

Binary file not shown.

Binary file not shown.

View File

@@ -1 +1 @@
MANIFEST-000070 MANIFEST-000076

View File

@@ -1,8 +1,15 @@
2026/04/14-00:55:24.444791 7f684a7ef6c0 Recovering log #68 2026/04/14-21:45:17.278141 7fc1d97bc6c0 Recovering log #75
2026/04/14-00:55:24.460229 7f684a7ef6c0 Delete type=3 #66 2026/04/14-21:45:17.294441 7fc1d97bc6c0 Delete type=0 #75
2026/04/14-00:55:24.460280 7f684a7ef6c0 Delete type=0 #68 2026/04/14-21:45:17.294490 7fc1d97bc6c0 Delete type=3 #74
2026/04/14-00:56:01.496164 7f6833fff6c0 Level-0 table #73: started 2026/04/15-02:16:16.819929 7fc1d8fbb6c0 Level-0 table #79: started
2026/04/14-00:56:01.496194 7f6833fff6c0 Level-0 table #73: 0 bytes OK 2026/04/15-02:16:16.847375 7fc1d8fbb6c0 Level-0 table #79: 3342 bytes OK
2026/04/14-00:56:01.502678 7f6833fff6c0 Delete type=0 #71 2026/04/15-02:16:16.881351 7fc1d8fbb6c0 Delete type=0 #77
2026/04/14-00:56:01.502807 7f6833fff6c0 Manual compaction at level-0 from '!scenes!Jr7lGxYk2RETlXRv' @ 72057594037927935 : 1 .. '!scenes.tokens.delta.items!Jr7lGxYk2RETlXRv.6urwC5SVcou6UOAG.CTg4yBE12iMee1RU.BYT1CrA37R3Og0nu' @ 0 : 0; will stop at (end) 2026/04/15-02:16:16.881546 7fc1d8fbb6c0 Manual compaction at level-0 from '!scenes!0iGCRqkdJKjmmbl4' @ 72057594037927935 : 1 .. '!scenes.levels!Jr7lGxYk2RETlXRv.defaultLevel0000' @ 0 : 0; will stop at (end)
2026/04/14-00:56:01.513358 7f6833fff6c0 Manual compaction at level-1 from '!scenes!Jr7lGxYk2RETlXRv' @ 72057594037927935 : 1 .. '!scenes.tokens.delta.items!Jr7lGxYk2RETlXRv.6urwC5SVcou6UOAG.CTg4yBE12iMee1RU.BYT1CrA37R3Og0nu' @ 0 : 0; will stop at (end) 2026/04/15-02:16:16.938347 7fc1d8fbb6c0 Manual compaction at level-1 from '!scenes!0iGCRqkdJKjmmbl4' @ 72057594037927935 : 1 .. '!scenes.levels!Jr7lGxYk2RETlXRv.defaultLevel0000' @ 0 : 0; will stop at '!scenes.tokens.delta.items!Jr7lGxYk2RETlXRv.6urwC5SVcou6UOAG.CTg4yBE12iMee1RU.BYT1CrA37R3Og0nu' @ 49 : 0
2026/04/15-02:16:16.938354 7fc1d8fbb6c0 Compacting 1@1 + 1@2 files
2026/04/15-02:16:16.955205 7fc1d8fbb6c0 Generated table #80@1: 3 keys, 1810 bytes
2026/04/15-02:16:16.955236 7fc1d8fbb6c0 Compacted 1@1 + 1@2 files => 1810 bytes
2026/04/15-02:16:16.986128 7fc1d8fbb6c0 compacted to: files[ 0 0 1 0 0 0 0 ]
2026/04/15-02:16:16.986229 7fc1d8fbb6c0 Delete type=2 #57
2026/04/15-02:16:16.986351 7fc1d8fbb6c0 Delete type=2 #79
2026/04/15-02:16:17.092360 7fc1d8fbb6c0 Manual compaction at level-1 from '!scenes.tokens.delta.items!Jr7lGxYk2RETlXRv.6urwC5SVcou6UOAG.CTg4yBE12iMee1RU.BYT1CrA37R3Og0nu' @ 49 : 0 .. '!scenes.levels!Jr7lGxYk2RETlXRv.defaultLevel0000' @ 0 : 0; will stop at (end)

View File

@@ -1,8 +1,3 @@
2026/04/14-00:42:19.992614 7f684a7ef6c0 Recovering log #64 2026/04/14-10:43:54.317254 7fddd9fbf6c0 Recovering log #72
2026/04/14-00:42:20.003193 7f684a7ef6c0 Delete type=3 #62 2026/04/14-10:43:54.326872 7fddd9fbf6c0 Delete type=3 #70
2026/04/14-00:42:20.003267 7f684a7ef6c0 Delete type=0 #64 2026/04/14-10:43:54.326932 7fddd9fbf6c0 Delete type=0 #72
2026/04/14-00:50:27.830098 7f6833fff6c0 Level-0 table #69: started
2026/04/14-00:50:27.830137 7f6833fff6c0 Level-0 table #69: 0 bytes OK
2026/04/14-00:50:27.836136 7f6833fff6c0 Delete type=0 #67
2026/04/14-00:50:27.836294 7f6833fff6c0 Manual compaction at level-0 from '!scenes!Jr7lGxYk2RETlXRv' @ 72057594037927935 : 1 .. '!scenes.tokens.delta.items!Jr7lGxYk2RETlXRv.6urwC5SVcou6UOAG.CTg4yBE12iMee1RU.BYT1CrA37R3Og0nu' @ 0 : 0; will stop at (end)
2026/04/14-00:50:27.846944 7f6833fff6c0 Manual compaction at level-1 from '!scenes!Jr7lGxYk2RETlXRv' @ 72057594037927935 : 1 .. '!scenes.tokens.delta.items!Jr7lGxYk2RETlXRv.6urwC5SVcou6UOAG.CTg4yBE12iMee1RU.BYT1CrA37R3Og0nu' @ 0 : 0; will stop at (end)

Binary file not shown.

Binary file not shown.

View File

@@ -16,6 +16,7 @@
--cel-border: #7a5c20; // bordure dorée --cel-border: #7a5c20; // bordure dorée
--cel-accent: #6b1e28; // bordeaux profond (échecs, accents) --cel-accent: #6b1e28; // bordeaux profond (échecs, accents)
--cel-text: #2f2413; // texte de corps sur fond clair (parchemin)
--cel-shadow: rgba(10,15,10,0.5); --cel-shadow: rgba(10,15,10,0.5);

View File

@@ -30,7 +30,7 @@
.roll-actor { .roll-actor {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
color: var(--cel-orange-light, #ddb84a); color: var(--cel-orange-light, #ddb84a);
font-size: 0.78em; font-size: 0.82em;
letter-spacing: 0.07em; letter-spacing: 0.07em;
text-transform: uppercase; text-transform: uppercase;
opacity: 0.9; opacity: 0.9;
@@ -38,7 +38,7 @@
.roll-skill-line { .roll-skill-line {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 1.25em; font-size: 1.31em;
color: var(--cel-cream, #f0e8d4); color: var(--cel-cream, #f0e8d4);
margin-top: 2px; margin-top: 2px;
@@ -58,24 +58,24 @@
justify-content: center; justify-content: center;
flex-wrap: wrap; flex-wrap: wrap;
gap: 4px; gap: 4px;
font-size: 0.82em; font-size: 0.86em;
color: var(--cel-cream, #f0e8d4); color: var(--cel-cream, #f0e8d4);
.dval, .nb-dice { .dval, .nb-dice {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 1.7em; font-size: 1.78em;
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-weight: bold; font-weight: bold;
line-height: 1; line-height: 1;
} }
.dlabel { font-size: 0.78em; text-transform: uppercase; letter-spacing: 0.04em; opacity: 0.75; } .dlabel { font-size: 0.82em; text-transform: uppercase; letter-spacing: 0.04em; opacity: 0.75; }
.dminus { color: #f0a0a0; font-weight: bold; } .dminus { color: #f0a0a0; font-weight: bold; }
.deq { opacity: 0.55; } .deq { opacity: 0.55; }
.ddice { color: var(--cel-orange, #e07b00); } .ddice { color: var(--cel-orange, #e07b00); }
} }
.wound-info { .wound-info {
font-size: 0.73em; font-size: 0.77em;
color: #f0a0a0; color: #f0a0a0;
margin-top: 3px; margin-top: 3px;
} }
@@ -117,17 +117,17 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-size: 0.65em; font-size: 0.68em;
color: white; color: white;
} }
} }
} }
.moon-icon { font-size: 1.2em; flex-shrink: 0; } .moon-icon { font-size: 1.26em; flex-shrink: 0; }
.moon-text { .moon-text {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 0.88em; font-size: 0.92em;
color: var(--cel-green, #0c4c0c); color: var(--cel-green, #0c4c0c);
} }
} }
@@ -152,7 +152,7 @@
label { label {
flex: 0 0 110px; flex: 0 0 110px;
font-size: 0.78em; font-size: 0.82em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.04em; letter-spacing: 0.04em;
color: var(--cel-border, #7a5c20); color: var(--cel-border, #7a5c20);
@@ -165,8 +165,8 @@
padding: 3px 7px; padding: 3px 7px;
background: rgba(255,255,255,0.85); background: rgba(255,255,255,0.85);
font-family: inherit; font-family: inherit;
font-size: 0.85em; font-size: 0.89em;
color: #333; color: var(--cel-text, #2f2413);
&:focus { outline: 1px solid var(--cel-orange, #e07b00); } &:focus { outline: 1px solid var(--cel-orange, #e07b00); }
} }
@@ -233,7 +233,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-size: 0.65em; font-size: 0.68em;
color: white; color: white;
} }
} }
@@ -242,7 +242,7 @@
} }
.destin-icon { .destin-icon {
font-size: 1.1em; font-size: 1.16em;
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
flex-shrink: 0; flex-shrink: 0;
} }
@@ -252,20 +252,20 @@
.destin-main { .destin-main {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 0.9em; font-size: 0.95em;
color: var(--cel-green, #0c4c0c); color: var(--cel-green, #0c4c0c);
display: block; display: block;
} }
.destin-bonus { .destin-bonus {
font-size: 0.72em; font-size: 0.76em;
color: var(--cel-border, #7a5c20); color: var(--cel-border, #7a5c20);
font-style: italic; font-style: italic;
} }
} }
.destin-count { .destin-count {
font-size: 0.75em; font-size: 0.79em;
font-weight: bold; font-weight: bold;
color: var(--cel-green, #0c4c0c); color: var(--cel-green, #0c4c0c);
background: rgba(196,154,26,0.2); background: rgba(196,154,26,0.2);
@@ -275,7 +275,7 @@
white-space: nowrap; white-space: nowrap;
&.no-destin { &.no-destin {
color: #888; color: rgba(0,0,0,0.45);
background: rgba(0,0,0,0.05); background: rgba(0,0,0,0.05);
border-color: rgba(0,0,0,0.1); border-color: rgba(0,0,0,0.1);
} }
@@ -283,7 +283,7 @@
} }
} }
.form-visibility label { color: #888; } .form-visibility label { color: rgba(0,0,0,0.45); }
.form-faction-aspect select { .form-faction-aspect select {
font-weight: bold; font-weight: bold;
@@ -326,7 +326,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-size: 0.75em; font-size: 0.79em;
color: white; color: white;
} }
} }
@@ -338,19 +338,19 @@
flex: 1; flex: 1;
.puiser-main { .puiser-main {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 0.9em; font-size: 0.95em;
color: var(--cel-accent, #6b1e28); color: var(--cel-accent, #6b1e28);
display: block; display: block;
} }
.puiser-sub { .puiser-sub {
font-size: 0.7em; font-size: 0.73em;
color: #888; color: rgba(0,0,0,0.45);
font-style: italic; font-style: italic;
} }
} }
.puiser-cost { .puiser-cost {
font-size: 0.8em; font-size: 0.84em;
font-weight: bold; font-weight: bold;
color: var(--cel-accent, #6b1e28); color: var(--cel-accent, #6b1e28);
background: rgba(107,30,40,0.1); background: rgba(107,30,40,0.1);
@@ -398,14 +398,14 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-size: 0.6em; font-size: 0.63em;
color: white; color: white;
} }
} }
} }
.fortune-icon { .fortune-icon {
font-size: 1.1em; font-size: 1.16em;
color: var(--cel-green, #0c4c0c); color: var(--cel-green, #0c4c0c);
flex-shrink: 0; flex-shrink: 0;
} }
@@ -414,19 +414,19 @@
flex: 1; flex: 1;
.fortune-main { .fortune-main {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 0.9em; font-size: 0.95em;
color: var(--cel-green, #0c4c0c); color: var(--cel-green, #0c4c0c);
display: block; display: block;
} }
.fortune-bonus { .fortune-bonus {
font-size: 0.72em; font-size: 0.76em;
color: var(--cel-border, #7a5c20); color: var(--cel-border, #7a5c20);
font-style: italic; font-style: italic;
} }
} }
.fortune-badge { .fortune-badge {
font-size: 0.8em; font-size: 0.84em;
font-weight: bold; font-weight: bold;
color: var(--cel-green, #0c4c0c); color: var(--cel-green, #0c4c0c);
background: rgba(12,76,12,0.12); background: rgba(12,76,12,0.12);
@@ -450,7 +450,7 @@
gap: 10px; gap: 10px;
.preview-label { .preview-label {
font-size: 0.7em; font-size: 0.73em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.07em; letter-spacing: 0.07em;
color: var(--cel-border, #7a5c20); color: var(--cel-border, #7a5c20);
@@ -459,7 +459,7 @@
.preview-formula { .preview-formula {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 1.6em; font-size: 1.68em;
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-weight: bold; font-weight: bold;
letter-spacing: 0.04em; letter-spacing: 0.04em;
@@ -469,6 +469,90 @@
// ─── Chat message ───────────────────────────────────────────────────────────── // ─── Chat message ─────────────────────────────────────────────────────────────
// ── Contreparties dé de lune (partagé : chat-roll + moon-standalone-card) ──
.celestopol.chat-roll,
.celestopol-roll.moon-standalone-card {
.moon-effect-actions {
padding: 6px 10px 8px;
border-top: 2px solid rgba(122,92,32,0.18);
background: rgba(12,76,12,0.04);
border-radius: 0 0 3px 3px;
.moon-effect-label {
display: block;
font-family: var(--cel-font-title);
font-size: 0.76em;
font-weight: bold;
color: var(--cel-border, #7a5c20);
text-transform: uppercase;
letter-spacing: 0.07em;
margin-bottom: 6px;
}
.moon-effect-buttons {
display: flex;
flex-wrap: wrap;
gap: 5px;
align-items: center;
}
.moon-effect-btn {
font-family: var(--cel-font-title);
font-size: 0.82em;
font-weight: bold;
padding: 4px 11px;
border-radius: 4px;
cursor: pointer;
transition: filter 0.12s, opacity 0.12s;
line-height: 1.4;
letter-spacing: 0.02em;
// Positif par défaut : vert jade / or
background: var(--cel-green, #1b3828);
color: var(--cel-orange-light, #ddb84a);
border: 1px solid rgba(196,154,26,0.35);
&:hover:not(:disabled) { filter: brightness(1.18); }
&:disabled { opacity: 0.55; cursor: not-allowed; }
&.moon-effect-negative {
background: var(--cel-accent, #6b1e28);
color: var(--cel-cream, #f0e8d4);
border-color: rgba(139,30,46,0.4);
&:hover:not(:disabled) { filter: brightness(1.12); }
}
}
.moon-effect-narrative {
font-size: 0.76em;
color: var(--cel-border, #7a5c20);
font-style: italic;
align-self: center;
padding-left: 2px;
}
.moon-effect-applied-status {
display: inline-flex;
align-items: center;
gap: 4px;
margin-top: 6px;
font-size: 0.8em;
font-family: var(--cel-font-title);
font-style: italic;
padding: 3px 9px;
border-radius: 3px;
color: var(--cel-green, #1b3828);
background: rgba(12,76,12,0.09);
border: 1px solid rgba(12,76,12,0.22);
&.is-negative {
color: var(--cel-accent, #6b1e28);
background: rgba(107,30,40,0.09);
border-color: rgba(107,30,40,0.25);
}
}
}
}
.celestopol.chat-roll { .celestopol.chat-roll {
border: 1px solid var(--cel-border, #7a5c20); border: 1px solid var(--cel-border, #7a5c20);
border-radius: 3px; border-radius: 3px;
@@ -506,16 +590,16 @@
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-weight: bold; font-weight: bold;
letter-spacing: 0.05em; letter-spacing: 0.05em;
font-size: 0.92em; font-size: 0.97em;
} }
.skill-info { .skill-info {
color: var(--cel-cream, #f0e8d4); color: var(--cel-cream, #f0e8d4);
font-size: 0.77em; font-size: 0.81em;
font-style: italic; font-style: italic;
.stat-lbl { color: var(--cel-orange-light, #ddb84a); } .stat-lbl { color: var(--cel-orange-light, #ddb84a); }
.sep { margin: 0 2px; opacity: 0.5; } .sep { margin: 0 2px; opacity: 0.5; }
} }
.wound-info { font-size: 0.7em; color: #f0a0a0; } .wound-info { font-size: 0.73em; color: #f0a0a0; }
} }
.moon-badge { display: none; } .moon-badge { display: none; }
@@ -540,10 +624,10 @@
border-radius: 4px; border-radius: 4px;
background: white; background: white;
font-weight: bold; font-weight: bold;
font-size: 1.05em; font-size: 1.1em;
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
box-shadow: 1px 1px 2px rgba(0,0,0,0.12); box-shadow: 1px 1px 2px rgba(0,0,0,0.12);
color: #222; color: var(--cel-text, #2f2413);
&.max { &.max {
background: var(--cel-green, #0c4c0c); background: var(--cel-green, #0c4c0c);
@@ -569,15 +653,15 @@
padding: 5px 10px 4px; padding: 5px 10px 4px;
background: var(--cel-cream, #f0e8d4); background: var(--cel-cream, #f0e8d4);
border-top: 1px solid rgba(122,92,32,0.2); border-top: 1px solid rgba(122,92,32,0.2);
font-size: 0.83em; font-size: 0.87em;
color: #555; color: #555;
.fl-label { color: #999; font-size: 0.88em; text-transform: uppercase; letter-spacing: 0.04em; margin-right: 2px; } .fl-label { color: rgba(0,0,0,0.4); font-size: 0.92em; text-transform: uppercase; letter-spacing: 0.04em; margin-right: 2px; }
.fl-ndice { color: var(--cel-green, #0c4c0c); font-weight: bold; } .fl-ndice { color: var(--cel-green, #0c4c0c); font-weight: bold; }
.fl-sum { font-weight: bold; color: #333; } .fl-sum { font-weight: bold; color: var(--cel-text, #2f2413); }
.fl-total { .fl-total {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 1.5em; font-size: 1.58em;
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-weight: bold; font-weight: bold;
line-height: 1; line-height: 1;
@@ -588,8 +672,8 @@
.fl-asp { color: var(--cel-orange, #e07b00); font-weight: bold; } .fl-asp { color: var(--cel-orange, #e07b00); font-weight: bold; }
.fl-faction { color: var(--cel-green, #0c4c0c); font-weight: bold; } .fl-faction { color: var(--cel-green, #0c4c0c); font-weight: bold; }
.fl-sep { font-weight: bold; color: var(--cel-border, #7a5c20); margin: 0 2px; } .fl-sep { font-weight: bold; color: var(--cel-border, #7a5c20); margin: 0 2px; }
.fl-eq { color: #aaa; } .fl-eq { color: rgba(0,0,0,0.35); }
.fl-op { color: #aaa; } .fl-op { color: rgba(0,0,0,0.35); }
} }
// ── Seuil et marge ── // ── Seuil et marge ──
@@ -600,22 +684,22 @@
padding: 5px 12px 6px; padding: 5px 12px 6px;
background: var(--cel-cream, #f0e8d4); background: var(--cel-cream, #f0e8d4);
border-top: 1px solid rgba(122,92,32,0.2); border-top: 1px solid rgba(122,92,32,0.2);
font-size: 0.82em; font-size: 0.86em;
.vs-wrap { .vs-wrap {
display: flex; display: flex;
align-items: baseline; align-items: baseline;
gap: 5px; gap: 5px;
} }
.vs-label { color: #aaa; text-transform: uppercase; font-size: 0.8em; } .vs-label { color: rgba(0,0,0,0.35); text-transform: uppercase; font-size: 0.84em; }
.diff-label{ font-style: italic; color: var(--cel-green, #0c4c0c); } .diff-label{ font-style: italic; color: var(--cel-green, #0c4c0c); }
.diff-val { color: #888; } .diff-val { color: rgba(0,0,0,0.45); }
.margin-badge { .margin-badge {
padding: 2px 10px; padding: 2px 10px;
border-radius: 12px; border-radius: 12px;
font-weight: bold; font-weight: bold;
font-size: 1.05em; font-size: 1.1em;
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
letter-spacing: 0.05em; letter-spacing: 0.05em;
@@ -635,7 +719,7 @@
// ── Destin utilisé ── // ── Destin utilisé ──
.used-info { .used-info {
text-align: center; text-align: center;
font-size: 0.77em; font-size: 0.81em;
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
padding: 3px 8px; padding: 3px 8px;
background: rgba(196,154,26,0.1); background: rgba(196,154,26,0.1);
@@ -673,7 +757,7 @@
} }
.damage-header { .damage-header {
font-size: 0.72em; font-size: 0.76em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.08em; letter-spacing: 0.08em;
color: var(--cel-border, #7a5c20); color: var(--cel-border, #7a5c20);
@@ -690,13 +774,13 @@
.damage-value { .damage-value {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 1.9em; font-size: 1.99em;
line-height: 1; line-height: 1;
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
} }
.damage-unit { .damage-unit {
font-size: 0.82em; font-size: 0.86em;
color: var(--cel-green, #0c4c0c); color: var(--cel-green, #0c4c0c);
font-weight: bold; font-weight: bold;
} }
@@ -704,7 +788,7 @@
.damage-breakdown, .damage-breakdown,
.damage-note { .damage-note {
margin-top: 6px; margin-top: 6px;
font-size: 0.76em; font-size: 0.8em;
line-height: 1.4; line-height: 1.4;
color: #5c4630; color: #5c4630;
} }
@@ -730,7 +814,7 @@
background: var(--cel-green, #0c4c0c); background: var(--cel-green, #0c4c0c);
color: var(--cel-orange-light, #ddb84a); color: var(--cel-orange-light, #ddb84a);
padding: 4px 10px; padding: 4px 10px;
font-size: 0.78em; font-size: 0.82em;
font-weight: bold; font-weight: bold;
cursor: pointer; cursor: pointer;
@@ -745,7 +829,7 @@
margin-top: 8px; margin-top: 8px;
padding: 6px 8px; padding: 6px 8px;
border-radius: 4px; border-radius: 4px;
font-size: 0.76em; font-size: 0.8em;
line-height: 1.4; line-height: 1.4;
&.is-applied { &.is-applied {
@@ -774,7 +858,7 @@
background: rgba(12,76,12,0.1); background: rgba(12,76,12,0.1);
color: var(--cel-green, #0c4c0c); color: var(--cel-green, #0c4c0c);
font-weight: bold; font-weight: bold;
font-size: 0.9em; font-size: 0.95em;
} }
// ── Résultat dé de lune ── // ── Résultat dé de lune ──
@@ -787,7 +871,7 @@
font-family: var(--cel-font-body, serif); font-family: var(--cel-font-body, serif);
.moon-die-face { .moon-die-face {
font-size: 1.8em; font-size: 1.89em;
line-height: 1; line-height: 1;
flex-shrink: 0; flex-shrink: 0;
} }
@@ -800,7 +884,7 @@
} }
.moon-die-phase { .moon-die-phase {
font-size: 0.72em; font-size: 0.76em;
opacity: 0.75; opacity: 0.75;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.05em; letter-spacing: 0.05em;
@@ -815,7 +899,7 @@
} }
.moon-die-desc { .moon-die-desc {
font-size: 0.72em; font-size: 0.76em;
font-style: italic; font-style: italic;
opacity: 0.85; opacity: 0.85;
line-height: 1.3; line-height: 1.3;
@@ -852,13 +936,13 @@
border-top: 2px solid rgba(0,0,0,0.1); border-top: 2px solid rgba(0,0,0,0.1);
.result-icon { .result-icon {
font-size: 0.85em; font-size: 0.89em;
opacity: 0.85; opacity: 0.85;
letter-spacing: 0.15em; letter-spacing: 0.15em;
} }
.result-label { font-size: 1.2em; line-height: 1.2; } .result-label { font-size: 1.26em; line-height: 1.2; }
.result-desc { .result-desc {
font-size: 0.65em; font-size: 0.68em;
letter-spacing: 0.08em; letter-spacing: 0.08em;
margin-top: 2px; margin-top: 2px;
opacity: 0.8; opacity: 0.8;
@@ -919,22 +1003,22 @@
.welcome-mark { .welcome-mark {
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-size: 1.05em; font-size: 1.1em;
line-height: 1; line-height: 1;
} }
.welcome-title { .welcome-title {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-size: 0.98em; font-size: 1.03em;
letter-spacing: 0.05em; letter-spacing: 0.05em;
text-transform: uppercase; text-transform: uppercase;
} }
.welcome-body { .welcome-body {
padding: 9px 11px 10px; padding: 9px 11px 10px;
color: #3f3623; color: var(--cel-text, #2f2413);
font-size: 0.84em; font-size: 0.88em;
line-height: 1.45; line-height: 1.45;
p { p {
@@ -954,7 +1038,7 @@
display: block; display: block;
margin-bottom: 2px; margin-bottom: 2px;
color: var(--cel-border, #7a5c20); color: var(--cel-border, #7a5c20);
font-size: 0.72em; font-size: 0.76em;
font-weight: bold; font-weight: bold;
letter-spacing: 0.05em; letter-spacing: 0.05em;
text-transform: uppercase; text-transform: uppercase;
@@ -997,27 +1081,27 @@
.portrait-message-mark { .portrait-message-mark {
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-size: 1.05em; font-size: 1.1em;
line-height: 1; line-height: 1;
} }
.portrait-message-title { .portrait-message-title {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-size: 0.98em; font-size: 1.03em;
letter-spacing: 0.05em; letter-spacing: 0.05em;
text-transform: uppercase; text-transform: uppercase;
} }
.portrait-message-body { .portrait-message-body {
padding: 9px 11px 10px; padding: 9px 11px 10px;
color: #3f3623; color: var(--cel-text, #2f2413);
} }
.portrait-message-name { .portrait-message-name {
margin-bottom: 8px; margin-bottom: 8px;
color: var(--cel-green, #0c4c0c); color: var(--cel-green, #0c4c0c);
font-size: 0.84em; font-size: 0.88em;
font-weight: bold; font-weight: bold;
letter-spacing: 0.04em; letter-spacing: 0.04em;
text-transform: uppercase; text-transform: uppercase;
@@ -1100,7 +1184,7 @@
&:hover { &:hover {
border-color: var(--cel-orange, #e07b00); border-color: var(--cel-orange, #e07b00);
background: linear-gradient(180deg, rgba(224,123,0,0.18), rgba(224,123,0,0.06)); background: linear-gradient(180deg, rgba(224,123,0,0.18), rgba(224,123,0,0.06));
color: #7a3e00; color: var(--cel-border, #7a5c20);
} }
} }
} }
@@ -1124,7 +1208,7 @@
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.05em; letter-spacing: 0.05em;
font-size: 0.88em; font-size: 0.92em;
} }
.faction-aspect-points { .faction-aspect-points {
@@ -1132,7 +1216,7 @@
flex-wrap: wrap; flex-wrap: wrap;
gap: 5px; gap: 5px;
margin-bottom: 4px; margin-bottom: 4px;
font-size: 0.8em; font-size: 0.84em;
} }
.faction-aspect-point-card { .faction-aspect-point-card {
@@ -1146,7 +1230,7 @@
border: 1px solid rgba(122,92,32,0.18); border: 1px solid rgba(122,92,32,0.18);
strong { strong {
font-size: 0.72em; font-size: 0.76em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.04em; letter-spacing: 0.04em;
color: var(--cel-border, #7a5c20); color: var(--cel-border, #7a5c20);
@@ -1155,14 +1239,14 @@
em { em {
font-style: normal; font-style: normal;
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 1.05em; font-size: 1.1em;
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
line-height: 1; line-height: 1;
} }
} }
.faction-aspect-source-line { .faction-aspect-source-line {
font-size: 0.78em; font-size: 0.82em;
color: var(--cel-border, #7a5c20); color: var(--cel-border, #7a5c20);
} }
@@ -1171,8 +1255,8 @@
border-left: 3px solid #b84a2e; border-left: 3px solid #b84a2e;
border-radius: 4px; border-radius: 4px;
background: rgba(184, 74, 46, 0.08); background: rgba(184, 74, 46, 0.08);
color: #8b3e2b; color: var(--cel-accent, #6b1e28);
font-size: 0.8em; font-size: 0.84em;
} }
.faction-aspect-tag-list, .faction-aspect-tag-list,
@@ -1190,7 +1274,7 @@
background: rgba(12, 76, 12, 0.08); background: rgba(12, 76, 12, 0.08);
border: 1px solid rgba(12, 76, 12, 0.18); border: 1px solid rgba(12, 76, 12, 0.18);
color: var(--cel-green, #0c4c0c); color: var(--cel-green, #0c4c0c);
font-size: 0.72em; font-size: 0.76em;
font-weight: bold; font-weight: bold;
} }
@@ -1204,7 +1288,7 @@
label { label {
display: block; display: block;
margin-bottom: 2px; margin-bottom: 2px;
font-size: 0.68em; font-size: 0.71em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.04em; letter-spacing: 0.04em;
color: var(--cel-border, #7a5c20); color: var(--cel-border, #7a5c20);
@@ -1219,13 +1303,13 @@
border-radius: 3px; border-radius: 3px;
padding: 2px 6px; padding: 2px 6px;
background: rgba(255,255,255,0.9); background: rgba(255,255,255,0.9);
font-size: 0.78em; font-size: 0.82em;
color: #2f2413; color: var(--cel-text, #2f2413);
box-sizing: border-box; box-sizing: border-box;
} }
select option { select option {
color: #2f2413; color: var(--cel-text, #2f2413);
background: #fffaf0; background: #fffaf0;
} }
} }
@@ -1251,7 +1335,7 @@
background: rgba(224,123,0,0.12); background: rgba(224,123,0,0.12);
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 0.72em; font-size: 0.76em;
line-height: 1; line-height: 1;
cursor: help; cursor: help;
vertical-align: middle; vertical-align: middle;
@@ -1273,7 +1357,7 @@
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
margin-bottom: 4px; margin-bottom: 4px;
font-size: 0.82em; font-size: 0.86em;
} }
} }
@@ -1281,7 +1365,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
gap: 4px; gap: 4px;
font-size: 0.74em; font-size: 0.78em;
} }
.faction-aspect-active-list { .faction-aspect-active-list {
@@ -1298,8 +1382,8 @@
padding: 3px 6px; padding: 3px 6px;
border-radius: 4px; border-radius: 4px;
background: rgba(255,255,255,0.7); background: rgba(255,255,255,0.7);
color: #2f2413; color: var(--cel-text, #2f2413);
font-size: 0.76em; font-size: 0.8em;
&.is-relevant { &.is-relevant {
border-left: 3px solid var(--cel-green, #0c4c0c); border-left: 3px solid var(--cel-green, #0c4c0c);
@@ -1307,20 +1391,20 @@
} }
.faction-aspect-active-name { .faction-aspect-active-name {
color: #2f2413; color: var(--cel-text, #2f2413);
font-weight: 600; font-weight: 600;
} }
.faction-aspect-active-value { .faction-aspect-active-value {
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 0.92em; font-size: 0.97em;
} }
.faction-aspect-empty { .faction-aspect-empty {
color: #666; color: rgba(0,0,0,0.5);
font-style: italic; font-style: italic;
font-size: 0.74em; font-size: 0.78em;
} }
.faction-aspect-remove-block { .faction-aspect-remove-block {
@@ -1349,7 +1433,7 @@
border-left: 3px solid #c0392b; border-left: 3px solid #c0392b;
border-radius: 4px; border-radius: 4px;
color: #f0c0c0; color: #f0c0c0;
font-size: 0.85em; font-size: 0.89em;
.wound-icon { font-size: 1em; } .wound-icon { font-size: 1em; }
} }
} }
@@ -1358,7 +1442,7 @@
.celestopol.chat-roll { .celestopol.chat-roll {
.roll-result-banner.tie { .roll-result-banner.tie {
background: #3a2e1a; background: #3a2e1a;
color: #d4b870; color: var(--cel-orange-light, #ddb84a);
border-top: 2px solid #7a6230; border-top: 2px solid #7a6230;
border-bottom: 2px solid #7a6230; border-bottom: 2px solid #7a6230;
text-shadow: 0 1px 2px rgba(0,0,0,0.6); text-shadow: 0 1px 2px rgba(0,0,0,0.6);
@@ -1369,12 +1453,12 @@
align-items: center; align-items: center;
gap: 0.3em; gap: 0.3em;
margin-bottom: 1px; margin-bottom: 1px;
font-size: 0.85em; font-size: 0.89em;
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
.weapon-icon-small { font-size: 0.9em; } .weapon-icon-small { font-size: 0.95em; }
.weapon-degats-small { .weapon-degats-small {
font-weight: bold; font-weight: bold;
color: #f0c060; color: var(--cel-border, #7a5c20);
} }
} }
} }
@@ -1386,20 +1470,20 @@
align-items: center; align-items: center;
gap: 0.4em; gap: 0.4em;
margin-bottom: 2px; margin-bottom: 2px;
font-size: 0.9em; font-size: 0.95em;
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
.weapon-icon { font-size: 1em; } .weapon-icon { font-size: 1em; }
.weapon-degats { .weapon-degats {
font-weight: bold; font-weight: bold;
color: #f0c060; color: var(--cel-border, #7a5c20);
font-size: 0.85em; font-size: 0.89em;
} }
} }
.form-corps-pnj { .form-corps-pnj {
.corps-pnj-input { .corps-pnj-input {
width: 70px; width: 70px;
font-size: 1.1em; font-size: 1.16em;
font-weight: bold; font-weight: bold;
text-align: center; text-align: center;
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
@@ -1420,7 +1504,7 @@
label { label {
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-weight: bold; font-weight: bold;
font-size: 0.85em; font-size: 0.89em;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 5px; gap: 5px;
@@ -1435,7 +1519,7 @@
border: 1px solid rgba(196, 154, 26, 0.5); border: 1px solid rgba(196, 154, 26, 0.5);
border-radius: 3px; border-radius: 3px;
padding: 2px 4px; padding: 2px 4px;
font-size: 0.85em; font-size: 0.89em;
max-width: 200px; max-width: 200px;
} }
} }
@@ -1451,7 +1535,7 @@
align-items: center; align-items: center;
gap: 6px; gap: 6px;
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-size: 0.88em; font-size: 0.92em;
font-style: italic; font-style: italic;
i { opacity: 0.8; } i { opacity: 0.8; }
@@ -1465,14 +1549,14 @@
padding: 4px 8px; padding: 4px 8px;
label { label {
color: #e08060; color: var(--cel-accent, #6b1e28);
font-size: 0.85em; font-size: 0.89em;
font-weight: bold; font-weight: bold;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 5px; gap: 5px;
i { color: #e08060; } i { color: var(--cel-accent, #6b1e28); }
} }
select { select {
@@ -1482,13 +1566,13 @@
border: 1px solid rgba(200, 100, 60, 0.4); border: 1px solid rgba(200, 100, 60, 0.4);
border-radius: 3px; border-radius: 3px;
padding: 2px 4px; padding: 2px 4px;
font-size: 0.85em; font-size: 0.89em;
} }
} }
.form-threshold-fixed { .form-threshold-fixed {
.threshold-value { .threshold-value {
font-size: 1.2em; font-size: 1.26em;
font-weight: bold; font-weight: bold;
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
@@ -1514,7 +1598,7 @@
input[type="checkbox"] { flex-shrink: 0; } input[type="checkbox"] { flex-shrink: 0; }
.opposition-icon { .opposition-icon {
font-size: 1.2em; font-size: 1.26em;
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
} }
@@ -1525,13 +1609,13 @@
.opposition-main { .opposition-main {
font-weight: bold; font-weight: bold;
font-size: 0.9em; font-size: 0.95em;
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
} }
.opposition-sub { .opposition-sub {
font-size: 0.75em; font-size: 0.79em;
opacity: 0.7; opacity: 0.7;
font-style: italic; font-style: italic;
} }
@@ -1575,7 +1659,7 @@
} }
.moon-standalone-actor { .moon-standalone-actor {
font-size: 0.85em; font-size: 0.89em;
color: var(--cel-text, #333); color: var(--cel-text, #333);
font-style: italic; font-style: italic;
} }
@@ -1604,21 +1688,21 @@
.moon-standalone-phase { .moon-standalone-phase {
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 0.95em; font-size: 1.0em;
font-weight: bold; font-weight: bold;
color: var(--cel-text, #333); color: var(--cel-text, #333);
} }
.moon-standalone-value { .moon-standalone-value {
font-size: 0.8em; font-size: 0.84em;
color: var(--cel-text-light, #666); color: var(--cel-text-light, #666);
font-style: italic; font-style: italic;
} }
&.moon-triomphe { border-left-color: var(--cel-green, #0c4c0c); } &.moon-triomphe { border-left-color: var(--cel-green, #0c4c0c); }
&.moon-brio { border-left-color: var(--cel-border, #7a5c20); } &.moon-brio { border-left-color: var(--cel-border, #7a5c20); }
&.moon-contrecoup { border-left-color: #c07800; } &.moon-contrecoup { border-left-color: var(--cel-orange, #c49a1a); }
&.moon-catastrophe{ border-left-color: #8b1e2e; } &.moon-catastrophe{ border-left-color: var(--cel-accent, #6b1e28); }
} }
.moon-interpret-row { .moon-interpret-row {
@@ -1627,15 +1711,15 @@
gap: 8px; gap: 8px;
.moon-interpret-label { .moon-interpret-label {
font-size: 0.72em; font-size: 0.76em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.07em; letter-spacing: 0.07em;
color: #888; color: rgba(0,0,0,0.45);
white-space: nowrap; white-space: nowrap;
} }
.moon-fortune { .moon-fortune {
font-size: 0.85em; font-size: 0.89em;
font-weight: bold; font-weight: bold;
border-radius: 3px; border-radius: 3px;
padding: 1px 8px; padding: 1px 8px;
@@ -1648,7 +1732,7 @@
&.mauvaise-fortune { &.mauvaise-fortune {
background: rgba(139, 30, 46, 0.1); background: rgba(139, 30, 46, 0.1);
color: #8b1e2e; color: var(--cel-accent, #6b1e28);
border: 1px solid rgba(139,30,46,0.3); border: 1px solid rgba(139,30,46,0.3);
} }
} }
@@ -1659,6 +1743,7 @@
margin-top: 2px; margin-top: 2px;
padding: 6px 8px; padding: 6px 8px;
} }
} }
// ── Message d'initiative ────────────────────────────────────────────────────── // ── Message d'initiative ──────────────────────────────────────────────────────
@@ -1698,11 +1783,11 @@
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-weight: bold; font-weight: bold;
letter-spacing: 0.05em; letter-spacing: 0.05em;
font-size: 0.92em; font-size: 0.97em;
} }
.skill-info { .skill-info {
color: var(--cel-cream, #f0e8d4); color: var(--cel-cream, #f0e8d4);
font-size: 0.77em; font-size: 0.81em;
font-style: italic; font-style: italic;
} }
} }
@@ -1730,19 +1815,19 @@
} }
.initiative-icon { .initiative-icon {
font-size: 1.1em; font-size: 1.16em;
opacity: 0.9; opacity: 0.9;
font-style: normal; font-style: normal;
} }
.initiative-score { .initiative-score {
font-size: 2.4em; font-size: 2.52em;
font-weight: bold; font-weight: bold;
line-height: 1; line-height: 1;
} }
.initiative-detail { .initiative-detail {
font-size: 0.65em; font-size: 0.68em;
opacity: 0.75; opacity: 0.75;
font-style: italic; font-style: italic;
font-family: var(--cel-font-body, serif); font-family: var(--cel-font-body, serif);

View File

@@ -16,8 +16,8 @@
</span> </span>
{{/if}} {{/if}}
<span class="skill-info"> <span class="skill-info">
{{#if statLabel}}<span class="stat-lbl">{{statLabel}}</span><span class="sep"> </span>{{/if}} {{#if statLabel}}<span class="stat-lbl">{{localize statLabel}}</span><span class="sep"> </span>{{/if}}
<span class="skill-lbl">{{skillLabel}}</span> <span class="skill-lbl">{{localize skillLabel}}</span>
</span> </span>
{{#if woundLabel}}<span class="wound-info">⚠ {{woundLabel}}</span>{{/if}} {{#if woundLabel}}<span class="wound-info">⚠ {{woundLabel}}</span>{{/if}}
</div> </div>
@@ -122,7 +122,7 @@
</div> </div>
{{/if}} {{/if}}
{{!-- Résultat du Dé de la Lune (narratif) --}} {{!-- Résultat du Dé de la Lune (narratif + choix de contrepartie) --}}
{{#if hasMoonDie}} {{#if hasMoonDie}}
<div class="moon-die-result {{moonResultClass}}"> <div class="moon-die-result {{moonResultClass}}">
<span class="moon-die-face">{{moonFaceSymbol}}</span> <span class="moon-die-face">{{moonFaceSymbol}}</span>
@@ -132,6 +132,27 @@
<span class="moon-die-desc">{{moonResultDesc}}</span> <span class="moon-die-desc">{{moonResultDesc}}</span>
</div> </div>
</div> </div>
{{#if moonActorIsCharacter}}
<div class="moon-effect-actions" data-moon-actor-id="{{moonActorId}}" data-moon-actor-uuid="{{moonActorUuid}}">
<span class="moon-effect-label">{{localize "CELESTOPOL.Moon.applyChoose"}}</span>
<div class="moon-effect-buttons">
{{#if (eq moonResultTypeId "triomphe")}}
<button type="button" class="moon-effect-btn" data-action="apply-moon-effect" data-effect="regain-anomaly">{{localize "CELESTOPOL.Moon.effectRegainAnomaly"}}</button>
<button type="button" class="moon-effect-btn" data-action="apply-moon-effect" data-effect="lose-spleen">{{localize "CELESTOPOL.Moon.effectLoseSpleen"}}</button>
{{else if (eq moonResultTypeId "brio")}}
<button type="button" class="moon-effect-btn" data-action="apply-moon-effect" data-effect="gain-destin">{{localize "CELESTOPOL.Moon.effectGainDestin"}}</button>
<span class="moon-effect-narrative">{{localize "CELESTOPOL.Moon.effectNarrativeOnly"}}</span>
{{else if (eq moonResultTypeId "contrecoup")}}
<button type="button" class="moon-effect-btn moon-effect-negative" data-action="apply-moon-effect" data-effect="lose-destin">{{localize "CELESTOPOL.Moon.effectLoseDestin"}}</button>
<span class="moon-effect-narrative">{{localize "CELESTOPOL.Moon.effectNarrativeOnly"}}</span>
{{else if (eq moonResultTypeId "catastrophe")}}
<button type="button" class="moon-effect-btn moon-effect-negative" data-action="apply-moon-effect" data-effect="lose-anomaly">{{localize "CELESTOPOL.Moon.effectLoseAnomaly"}}</button>
<button type="button" class="moon-effect-btn moon-effect-negative" data-action="apply-moon-effect" data-effect="gain-spleen">{{localize "CELESTOPOL.Moon.effectGainSpleen"}}</button>
<span class="moon-effect-narrative">{{localize "CELESTOPOL.Moon.effectNarrativeOnly"}}</span>
{{/if}}
</div>
</div>
{{/if}}
{{/if}} {{/if}}
{{!-- Bandeau résultat --}} {{!-- Bandeau résultat --}}
@@ -162,7 +183,7 @@
<span class="result-label">{{localize "CELESTOPOL.Roll.failure"}}</span> <span class="result-label">{{localize "CELESTOPOL.Roll.failure"}}</span>
{{#if isCombat}} {{#if isCombat}}
{{#if (eq weaponType "melee")}} {{#if (eq weaponType "melee")}}
<span class="result-desc">{{localize "CELESTOPOL.Combat.failureHit"}}</span> {{#unless isNpcAttack}}<span class="result-desc">{{localize "CELESTOPOL.Combat.failureHit"}}</span>{{/unless}}
{{else if isRangedDefense}} {{else if isRangedDefense}}
<span class="result-desc">{{localize "CELESTOPOL.Combat.rangedDefenseFailure"}}</span> <span class="result-desc">{{localize "CELESTOPOL.Combat.rangedDefenseFailure"}}</span>
{{else}} {{else}}

View File

@@ -36,4 +36,27 @@
</div> </div>
</div> </div>
{{!-- Choix de la contrepartie --}}
{{#if moonActorIsCharacter}}
<div class="moon-effect-actions" data-moon-actor-id="{{moonActorId}}" data-moon-actor-uuid="{{moonActorUuid}}">
<span class="moon-effect-label">{{localize "CELESTOPOL.Moon.applyChoose"}}</span>
<div class="moon-effect-buttons">
{{#if (eq moonResultTypeId "triomphe")}}
<button type="button" class="moon-effect-btn" data-action="apply-moon-effect" data-effect="regain-anomaly">{{localize "CELESTOPOL.Moon.effectRegainAnomaly"}}</button>
<button type="button" class="moon-effect-btn" data-action="apply-moon-effect" data-effect="lose-spleen">{{localize "CELESTOPOL.Moon.effectLoseSpleen"}}</button>
{{else if (eq moonResultTypeId "brio")}}
<button type="button" class="moon-effect-btn" data-action="apply-moon-effect" data-effect="gain-destin">{{localize "CELESTOPOL.Moon.effectGainDestin"}}</button>
<span class="moon-effect-narrative">{{localize "CELESTOPOL.Moon.effectNarrativeOnly"}}</span>
{{else if (eq moonResultTypeId "contrecoup")}}
<button type="button" class="moon-effect-btn moon-effect-negative" data-action="apply-moon-effect" data-effect="lose-destin">{{localize "CELESTOPOL.Moon.effectLoseDestin"}}</button>
<span class="moon-effect-narrative">{{localize "CELESTOPOL.Moon.effectNarrativeOnly"}}</span>
{{else if (eq moonResultTypeId "catastrophe")}}
<button type="button" class="moon-effect-btn moon-effect-negative" data-action="apply-moon-effect" data-effect="lose-anomaly">{{localize "CELESTOPOL.Moon.effectLoseAnomaly"}}</button>
<button type="button" class="moon-effect-btn moon-effect-negative" data-action="apply-moon-effect" data-effect="gain-spleen">{{localize "CELESTOPOL.Moon.effectGainSpleen"}}</button>
<span class="moon-effect-narrative">{{localize "CELESTOPOL.Moon.effectNarrativeOnly"}}</span>
{{/if}}
</div>
</div>
{{/if}}
</div> </div>

View File

@@ -9,7 +9,7 @@
{{/if}} {{/if}}
</div> </div>
{{#each weapons as |item|}} {{#each weapons as |item|}}
<div class="item-row weapon" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true"> <div class="item-row weapon {{#if item.system.equipped}}is-equipped{{/if}}" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true">
<img src="{{item.img}}" class="item-icon"> <img src="{{item.img}}" class="item-icon">
<span class="item-name">{{item.name}}</span> <span class="item-name">{{item.name}}</span>
<span class="item-tag type">{{#if (eq item.system.type "melee")}}{{localize "CELESTOPOL.Weapon.typeMelee"}}{{else}}{{localize "CELESTOPOL.Weapon.typeDistance"}}{{/if}}</span> <span class="item-tag type">{{#if (eq item.system.type "melee")}}{{localize "CELESTOPOL.Weapon.typeMelee"}}{{else}}{{localize "CELESTOPOL.Weapon.typeDistance"}}{{/if}}</span>
@@ -18,6 +18,11 @@
{{#unless ../isEditMode}} {{#unless ../isEditMode}}
<a data-action="attack" data-item-id="{{item.id}}" title="{{localize 'CELESTOPOL.Combat.attack'}}"><i class="fas fa-khanda"></i></a> <a data-action="attack" data-item-id="{{item.id}}" title="{{localize 'CELESTOPOL.Combat.attack'}}"><i class="fas fa-khanda"></i></a>
{{/unless}} {{/unless}}
<a data-action="toggleWeapon" data-item-uuid="{{item.uuid}}"
title="{{#if item.system.equipped}}{{localize 'CELESTOPOL.Weapon.unequip'}}{{else}}{{localize 'CELESTOPOL.Weapon.equip'}}{{/if}}"
class="equip-toggle {{#if item.system.equipped}}equipped{{/if}}">
<i class="fas fa-khanda"></i>
</a>
<a data-action="edit" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a> <a data-action="edit" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
{{#if ../isEditMode}}<a data-action="delete" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>{{/if}} {{#if ../isEditMode}}<a data-action="delete" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>{{/if}}
</div> </div>