Compare commits

...
Author SHA1 Message Date
fabres 9b3eceb96b fix(commerce): description pleine largeur sur la fiche
Release Creation / build (release) Successful in 2m13s
Le champ Description était dans un wrapper form-group (flex-direction: row)
qui le réduisait à la largeur de son contenu (~90px) au lieu de toute la
fiche (592px). Retrait de la classe form-group : le fieldset s'étire à
nouveau sur toute la largeur, comme sur les autres feuilles.

Valide par TC-06 (acteur commerce, 14/14) lors de la passe de
non-régression.

Ajoute aussi les permissions d'exécution manquantes sur les scripts
TC-02 et TC-07 (l'orchestrateur les sautait silencieusement).
2026-08-07 15:54:09 +02:00
fabres 73b91285e3 fix(sommeil): insomnie, château dormant automatique et reprise de nuit
Nouveau mode de repos (nouveau-mode-repos) :
- Insomnie (Queue de Dragon) : bannière d'avertissement dans le dialogue,
  rafraîchissement du drapeau à l'ouverture, vérification en direct dans la
  boucle de sommeil (coupe la récupération fatigue/rêve si elle surgit en
  cours de nuit), drapeau bidirectionnel (setInfoSommeilInsomnie) et mention
  dans le dialogue Château Dormant.
- Château Dormant : déclenchement automatique quand l'heure absolue de fin
  de nuit (11) est atteinte, au lieu de seulement après 12 h de sommeil.
- Rêve de Dragon : reprise de nuit possible — system.sommeil.heures
  initialisé à la durée, heures restantes conservées au réveil, dialogue
  pré-rempli avec bannière 'Reprise de nuit' et remise à zéro après une
  nuit complète.
- Don 'double rêve' : second jet de récupération de rêve par heure.
- Garde anti-boucle infinie si l'insomnie apparaît pendant le sommeil.
- Info-bulle sur le réveil forcé.

Perte de rêve des enchantements au Château Dormant :
- Suppression du message en double (whisper dédié) : texte intégré au
  résumé du CD ; la gemme renvoie désormais nouveaupr.
2026-08-07 15:54:09 +02:00
10 changed files with 55 additions and 26 deletions
+12 -10
View File
@@ -221,14 +221,18 @@ export class RdDActor extends RdDBaseActorSang {
if (toUpdate.length > 0) { if (toUpdate.length > 0) {
console.log('perte de rêve des enchantements', toUpdate) console.log('perte de rêve des enchantements', toUpdate)
const messageUpdates = await Promise.all(
toUpdate.map(async it => await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-pertereve-enchantement-chateaudormant.hbs`, it)))
await ChatMessage.create({
whisper: ChatUtility.getOwners(this),
content: messageUpdates.reduce(Misc.joining('<br>'))
})
if (message) { if (message) {
message.content += messageUpdates.reduce(Misc.joining(' ')) + ' ' message.content += toUpdate
.map(it => {
const type = it.item.type === 'potion' ? 'potion' : 'gemme'
const nouveaupr = it.nouveaupr ?? it.item.system.pr
let texte = `La ${type} enchantée ${it.item.name} de ${it.alias} a perdu un Point de Rêve (nouveau total : ${nouveaupr}).`
if (type === 'potion' && nouveaupr === 0) {
texte += ` Sa potion étant désormais à 0 Point de Rêve, elle est inutilisable et peut être jetée.`
}
return texte
})
.reduce(Misc.joining(' ')) + ' '
} }
await this.updateEmbeddedDocuments('Item', toUpdate.map(it => it.update)); await this.updateEmbeddedDocuments('Item', toUpdate.map(it => it.update));
} }
@@ -399,9 +403,7 @@ export class RdDActor extends RdDBaseActorSang {
} }
async setInfoSommeilInsomnie() { async setInfoSommeilInsomnie() {
if (EffetsDraconiques.isSujetInsomnie(this)) { await this.update({ 'system.sommeil.insomnie': EffetsDraconiques.isSujetInsomnie(this) });
await this.update({ 'system.sommeil.insomnie': true });
}
} }
async setInfoSommeilMoral(situationMoral) { async setInfoSommeilMoral(situationMoral) {
+1
View File
@@ -100,6 +100,7 @@ export class RdDItemGemme extends RdDItem {
return { return {
alias: this.parent.getAlias(), alias: this.parent.getAlias(),
item: this, item: this,
nouveaupr: nouveauReve,
update: { update: {
_id: this.id, _id: this.id,
'system.pr': nouveauReve, 'system.pr': nouveauReve,
+2 -1
View File
@@ -1,10 +1,11 @@
import { renderTemplate } from "../constants.js" import { renderTemplate } from "../constants.js"
import { EffetsDraconiques } from "../tmr/effets-draconiques.js"
export class DialogNouveauReposCD { export class DialogNouveauReposCD {
static async prompt(actor) { static async prompt(actor) {
const date = game.system.rdd.calendrier.dateCourante() const date = game.system.rdd.calendrier.dateCourante()
let moralChoisi = actor.system.sommeil?.moral ?? "neutre" let moralChoisi = actor.system.sommeil?.moral ?? "neutre"
const data = { name: actor.name, moral: moralChoisi } const data = { name: actor.name, moral: moralChoisi, insomnie: EffetsDraconiques.isSujetInsomnie(actor) }
const content = await renderTemplate( const content = await renderTemplate(
"systems/foundryvtt-reve-de-dragon/templates/sommeil/dialog-nouveau-repos-cd.hbs", "systems/foundryvtt-reve-de-dragon/templates/sommeil/dialog-nouveau-repos-cd.hbs",
data data
+23 -3
View File
@@ -1,6 +1,8 @@
import { renderTemplate } from "../constants.js" import { renderTemplate } from "../constants.js"
import { RdDTimestamp, RDD_HEURES_PAR_JOUR } from "../time/rdd-timestamp.js" import { RdDTimestamp, RDD_HEURES_PAR_JOUR } from "../time/rdd-timestamp.js"
import { ChatUtility } from "../chat-utility.js" import { ChatUtility } from "../chat-utility.js"
import { EffetsDraconiques } from "../tmr/effets-draconiques.js"
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js"
import { DialogNouveauReposCD } from "./dialog-nouveau-repos-cd.js" import { DialogNouveauReposCD } from "./dialog-nouveau-repos-cd.js"
export class DialogNouveauRepos extends foundry.applications.api.DialogV2 { export class DialogNouveauRepos extends foundry.applications.api.DialogV2 {
@@ -9,10 +11,19 @@ export class DialogNouveauRepos extends foundry.applications.api.DialogV2 {
const now = game.system.rdd.calendrier.timestamp const now = game.system.rdd.calendrier.timestamp
const heureCourante = now.heure const heureCourante = now.heure
const hourDefs = RdDTimestamp.definitions() const hourDefs = RdDTimestamp.definitions()
const insomnie = EffetsDraconiques.isSujetInsomnie(actor)
const repriseHeures = Math.max(actor.system.sommeil?.heures ?? 0, 0)
const data = { const data = {
name: actor.name, img: actor.img, hourDefinitions: hourDefs, name: actor.name, img: actor.img, hourDefinitions: hourDefs,
heureDebutDefaut: heureCourante, heureDebutDefaut: heureCourante,
heureFinDefaut: Math.min(heureCourante + 7, 11), heureFinDefaut: repriseHeures > 0
? (heureCourante + repriseHeures - 1) % RDD_HEURES_PAR_JOUR
: Math.min(heureCourante + 7, 11),
insomnie,
repriseHeures,
}
if (!ReglesOptionnelles.isUsing("chateau-dormant-gardien") || !actor.isPersonnageJoueur()) {
await actor.update({ "system.sommeil.insomnie": insomnie })
} }
const content = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/sommeil/dialog-nouveau-repos.hbs", data) const content = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/sommeil/dialog-nouveau-repos.hbs", data)
new DialogNouveauRepos(content, actor).render({ force: true }) new DialogNouveauRepos(content, actor).render({ force: true })
@@ -126,7 +137,7 @@ export class DialogNouveauRepos extends foundry.applications.api.DialogV2 {
content: this.actor.name + ": " content: this.actor.name + ": "
} }
const dormi = { heures: 0, etat: "dort", jetsReve: [] } const dormi = { heures: 0, etat: "dort", jetsReve: [] }
const insomnie = this.actor.system.sommeil?.insomnie || duree === 0 const insomnie = this.actor.system.sommeil?.insomnie || EffetsDraconiques.isSujetInsomnie(this.actor) || duree === 0
await this.actor.recupereEndurance({ message, demi: insomnie }) await this.actor.recupereEndurance({ message, demi: insomnie })
if (insomnie) { if (insomnie) {
message.content += "Vous ne trouvez pas le sommeil" message.content += "Vous ne trouvez pas le sommeil"
@@ -135,6 +146,7 @@ export class DialogNouveauRepos extends foundry.applications.api.DialogV2 {
if (!avaitFatigue && heureDebut >= 6 && heureDebut <= 11) { if (!avaitFatigue && heureDebut >= 6 && heureDebut <= 11) {
duree = RDD_HEURES_PAR_JOUR - heureDebut + 1 duree = RDD_HEURES_PAR_JOUR - heureDebut + 1
} }
await this.actor.update({ "system.sommeil": { heures: duree } })
let cdProcessed = false let cdProcessed = false
let h = 0 let h = 0
while (true) { while (true) {
@@ -142,12 +154,18 @@ export class DialogNouveauRepos extends foundry.applications.api.DialogV2 {
if (reveilForce && dormi.heures >= heuresForce) break if (reveilForce && dormi.heures >= heuresForce) break
if (!avaitFatigue && h >= duree) break if (!avaitFatigue && h >= duree) break
if (avaitFatigue && this.actor.system.sante.fatigue.value <= this.actor.getFatigueMin()) break if (avaitFatigue && this.actor.system.sante.fatigue.value <= this.actor.getFatigueMin()) break
if (avaitFatigue && EffetsDraconiques.isSujetInsomnie(this.actor)) break
await this.actor.$recupererEthylisme(message) await this.actor.$recupererEthylisme(message)
if (!EffetsDraconiques.isSujetInsomnie(this.actor)) {
await this.actor.$recupererFatigue(message) await this.actor.$recupererFatigue(message)
await this.actor.$jetRecuperationReve(dormi, message) await this.actor.$jetRecuperationReve(dormi, message)
if (dormi.etat === "dort" && EffetsDraconiques.isDonDoubleReve(this.actor)) {
await this.actor.$jetRecuperationReve(dormi, message)
}
}
dormi.heures++ dormi.heures++
if (dormi.etat !== "dort") break if (dormi.etat !== "dort") break
if (h % RDD_HEURES_PAR_JOUR === RDD_HEURES_PAR_JOUR - 1 && !cdProcessed) { if ((heureDebut + h) % RDD_HEURES_PAR_JOUR === RDD_HEURES_PAR_JOUR - 1 && !cdProcessed) {
cdProcessed = true cdProcessed = true
const cdData = await DialogNouveauReposCD.prompt(this.actor) const cdData = await DialogNouveauReposCD.prompt(this.actor)
if (cdData.stress.valeur > 0) { if (cdData.stress.valeur > 0) {
@@ -172,6 +190,8 @@ export class DialogNouveauRepos extends foundry.applications.api.DialogV2 {
} }
if (dormi.etat === "eveil") { if (dormi.etat === "eveil") {
await this.actor.reveilReveDeDragon(message, dormi.heures) await this.actor.reveilReveDeDragon(message, dormi.heures)
} else if (this.actor.system.sommeil?.heures) {
await this.actor.update({ "system.sommeil": { heures: 0 } })
} }
message.content += `Vous avez dormi ${dormi.heures <= 1 ? "une heure" : (dormi.heures + " heures")}. ` message.content += `Vous avez dormi ${dormi.heures <= 1 ? "une heure" : (dormi.heures + " heures")}. `
} }
+1 -1
View File
@@ -35,7 +35,7 @@
{{!-- Sheet Body --}} {{!-- Sheet Body --}}
<section class="sheet-body"> <section class="sheet-body">
<div class="flexcol form-group medium-editor"> <div class="flexcol medium-editor">
<fieldset> <fieldset>
<div> <div>
<label>Description :</label> <label>Description :</label>
@@ -1,8 +0,0 @@
<h4><img class="chat-icon" src="{{item.img}}" data-tooltip="{{item.name}}" />
La {{item.type}} enchantée {{item.name}} de {{alias}} a perdu un Point de Rêve (nouveau total : {{nouveaupr}}).</h4>
<hr>
<p>
{{#if (and (eq item.type 'potion') (eq nouveaupr 0))}}
Sa {{item.type}} étant désormais à 0 Point de Rêve, elle est inutilisable et peut être jetée.
{{/if}}
</p>
@@ -2,6 +2,9 @@
<div class="flexcol"> <div class="flexcol">
<h2>Château Dormant — {{name}}</h2> <h2>Château Dormant — {{name}}</h2>
<p>La nuit touche à sa fin. Renseignez les informations pour le passage à Vaisseau.</p> <p>La nuit touche à sa fin. Renseignez les informations pour le passage à Vaisseau.</p>
{{#if insomnie}}
<p class="notification warning">Nuit d'insomnie (Queue de Dragon) : aucun sommeil n'est récupéré.</p>
{{/if}}
<div class="form-group"> <div class="form-group">
<label>Points de stress du jour</label> <label>Points de stress du jour</label>
<input type="number" name="cd-stress" value="0" min="0" max="200"> <input type="number" name="cd-stress" value="0" min="0" max="200">
+11 -1
View File
@@ -17,9 +17,19 @@
<div class="form-group"> <div class="form-group">
<span>Durée : <strong><span id="duree-sommeil">0</span> heures</strong></span> <span>Durée : <strong><span id="duree-sommeil">0</span> heures</strong></span>
</div> </div>
{{#if repriseHeures}}
<div id="avertissements-reprise">
<p class="notification info">Reprise de nuit : {{repriseHeures}} heures restantes après votre Rêve de Dragon.</p>
</div>
{{/if}}
{{#if insomnie}}
<div id="avertissements-insomnie">
<p class="notification warning">Insomnie cette nuit (Queue de Dragon) : vous ne trouverez pas le sommeil.</p>
</div>
{{/if}}
<div class="form-group"> <div class="form-group">
<input type="checkbox" name="reveil-force" id="reveil-force"> <input type="checkbox" name="reveil-force" id="reveil-force">
<label for="reveil-force">Réveil forcé après</label> <label for="reveil-force" data-tooltip="Vous serez réveillé après ce nombre d'heures, même si votre fatigue n'est pas totalement récupérée.">Réveil forcé après</label>
<input type="number" name="heures-force" value="1" min="1" max="12" disabled> <input type="number" name="heures-force" value="1" min="1" max="12" disabled>
<span>heures</span> <span>heures</span>
</div> </div>
View File
View File