Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd3c228b32 | ||
|
|
9b3eceb96b | ||
|
|
73b91285e3 | ||
|
|
1238460cc8 | ||
|
|
d590dfce7f | ||
|
|
332da735f8 | ||
|
|
4a6913a2ba |
@@ -1,5 +1,47 @@
|
||||
# 13.0
|
||||
|
||||
## 14.0.4 - Le sommeil de Tétragor
|
||||
|
||||
### Sommeil & Château Dormant (nouveau mode de repos)
|
||||
|
||||
- Insomnie (Queue de Dragon)
|
||||
- bannière d'avertissement dans le dialogue de repos
|
||||
- rafraîchissement du drapeau à l'ouverture du dialogue
|
||||
- vérification en direct dans la boucle de sommeil : si l'insomnie surgit en
|
||||
cours de nuit, la récupération de fatigue et de rêve est interrompue
|
||||
- drapeau remis à jour dans les deux sens (levée possible)
|
||||
- mention dans le dialogue Château Dormant
|
||||
- Château Dormant automatique : déclenché quand l'heure de fin de nuit (11) est
|
||||
réellement atteinte, au lieu de seulement après 12 heures de sommeil
|
||||
- Reprise de nuit après un Rêve de Dragon
|
||||
- la durée de sommeil est conservée
|
||||
- les heures restantes sont proposées à la réouverture du dialogue avec une
|
||||
bannière « Reprise de nuit »
|
||||
- remise à zéro après une nuit complète
|
||||
- don « double rêve » : second jet de récupération de rêve par heure (parité
|
||||
ancien mode)
|
||||
- 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é ; la gemme renvoie son
|
||||
nouveau total de points de rêve
|
||||
|
||||
### Commerces
|
||||
|
||||
- achat depuis un commerce en quantité illimitée : la quantité achetée est
|
||||
correctement utilisée au lieu de celle du commerce
|
||||
- fiche commerce : le champ Description utilise toute la largeur de la fiche
|
||||
|
||||
### Compétences
|
||||
|
||||
- ne plus créer d'item « Sans compétence » lors des migrations
|
||||
|
||||
## 14.0.3 - Les bases de Tétragor
|
||||
|
||||
- XP des compétences : les bases de catégorie peuvent être négatives
|
||||
(base stockée en entier signé, migration 14.0.3)
|
||||
- réorganisation des titres CSS
|
||||
|
||||
## 14.0.2 - Le grang ménage de Tétragor
|
||||
|
||||
### Migration Foundry V14
|
||||
|
||||
@@ -5777,6 +5777,9 @@ body {
|
||||
font-size: 0.8rem;
|
||||
padding: 0.15rem 0.3rem 0rem 0.3rem;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .tab:is(.combat, .connaissances, .hautreve) h4 {
|
||||
margin: 0.3rem 0;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .blessure-control {
|
||||
flex-grow: 1;
|
||||
flex-direction: row;
|
||||
@@ -6178,6 +6181,18 @@ body {
|
||||
.system-foundryvtt-reve-de-dragon .prosemirror menu {
|
||||
background-color: var(--color-background-chat-message);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .prosemirror menu button,
|
||||
.system-foundryvtt-reve-de-dragon .prosemirror menu .pm-dropdown > span {
|
||||
color: var(--rdd-color-text-primary);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .prosemirror menu button.source-code-action {
|
||||
background-color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .prosemirror menu button:hover,
|
||||
.system-foundryvtt-reve-de-dragon .prosemirror menu button.active {
|
||||
background-color: rgba(255, 255, 255, 0.4);
|
||||
color: var(--rdd-color-text-primary);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon :is(.app, .application).sheet fieldset :is(label, input) {
|
||||
font-family: CaslonAntique;
|
||||
text-align: justify;
|
||||
|
||||
@@ -545,6 +545,10 @@
|
||||
padding: 0.15rem 0.3rem 0rem 0.3rem;
|
||||
}
|
||||
|
||||
.tab:is(.combat, .connaissances, .hautreve) h4 {
|
||||
margin: 0.3rem 0;
|
||||
}
|
||||
|
||||
.blessure-control {
|
||||
flex-grow: 1;
|
||||
flex-direction: row;
|
||||
@@ -889,6 +893,23 @@
|
||||
.prosemirror {
|
||||
menu {
|
||||
background-color: var(--color-background-chat-message);
|
||||
|
||||
button,
|
||||
.pm-dropdown > span {
|
||||
color: var(--rdd-color-text-primary);
|
||||
}
|
||||
|
||||
button {
|
||||
&.source-code-action {
|
||||
background-color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&.active {
|
||||
background-color: rgba(255, 255, 255, 0.4);
|
||||
color: var(--rdd-color-text-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-10
@@ -221,14 +221,18 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
if (toUpdate.length > 0) {
|
||||
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) {
|
||||
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));
|
||||
}
|
||||
@@ -399,9 +403,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
}
|
||||
|
||||
async setInfoSommeilInsomnie() {
|
||||
if (EffetsDraconiques.isSujetInsomnie(this)) {
|
||||
await this.update({ 'system.sommeil.insomnie': true });
|
||||
}
|
||||
await this.update({ 'system.sommeil.insomnie': EffetsDraconiques.isSujetInsomnie(this) });
|
||||
}
|
||||
|
||||
async setInfoSommeilMoral(situationMoral) {
|
||||
|
||||
@@ -220,16 +220,16 @@ export class RdDBaseActor extends Actor {
|
||||
await this.delayedRenderSheet('_preUpdate', changed, options)
|
||||
return super._preUpdate(changed, options, user)
|
||||
}
|
||||
|
||||
|
||||
_onUpdate(changed, options, userId) {
|
||||
super._onUpdate(changed, options, userId)
|
||||
if (userId == game.user.id){
|
||||
if (userId == game.user.id) {
|
||||
this.delayedRenderSheet('_onUpdate', changed, options)
|
||||
}
|
||||
}
|
||||
|
||||
async delayedRenderSheet(caller, data, options) {
|
||||
this.refreshDelayCounter = (this.refreshDelayCounter ?? 0)+1
|
||||
this.refreshDelayCounter = (this.refreshDelayCounter ?? 0) + 1
|
||||
if (this.refreshDelayCounter == 1) {
|
||||
this.renderAfterDelay(this.refreshDelayCounter)
|
||||
}
|
||||
@@ -628,17 +628,20 @@ export class RdDBaseActor extends Actor {
|
||||
return
|
||||
}
|
||||
|
||||
const isItemEmpilable = "quantite" in item.system;
|
||||
const baseItem = {
|
||||
id: undefined,
|
||||
type: item.type,
|
||||
img: item.img,
|
||||
name: item.name,
|
||||
system: foundry.utils.mergeObject(item.system, { quantite: isItemEmpilable ? quantite : undefined }, { inplace: false })
|
||||
system: foundry.utils.duplicate(item.system)
|
||||
}
|
||||
const createItemArray = "quantite" in item.system
|
||||
? (it, qt) => { it.system.quantite = qt; return [it] }
|
||||
: (it, qt) => Array.from({ length: qt }, (_, i) => it)
|
||||
|
||||
const newItems = isItemEmpilable ? [baseItem] : Array.from({ length: quantite }, (_, i) => baseItem);
|
||||
const items = await this.createEmbeddedDocuments("Item", newItems);
|
||||
return newItems.length > 0 ? items[0].id : undefined;
|
||||
const newItems = createItemArray(baseItem, quantite)
|
||||
const items = await this.createEmbeddedDocuments("Item", newItems)
|
||||
return items.length > 0 ? items[0].id : undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
@@ -48,13 +48,20 @@ export class RdDItemCompetence extends RdDItem {
|
||||
static get defaultIcon() { return "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp" }
|
||||
|
||||
static async onReady(){
|
||||
RdDItemCompetence.SANS_COMPETENCE = await Item.create(BASE_SANS_COMPETENCE, { temporary: true })
|
||||
RdDItemCompetence.SANS_COMPETENCE = new RdDItemCompetence(BASE_SANS_COMPETENCE)
|
||||
}
|
||||
|
||||
isNiveauBase() {
|
||||
return this.system.niveau == this.system.base && this.system.xp == 0
|
||||
}
|
||||
|
||||
async _preCreate(data, options, user) {
|
||||
await super._preCreate(data, options, user)
|
||||
if (this.system.categorie && !Number(data.system?.base)) {
|
||||
this.updateSource({ 'system.base': RdDItemCompetence.getNiveauBase(this.system.categorie, this.type) })
|
||||
}
|
||||
}
|
||||
|
||||
getBaseInit() {
|
||||
const carac = this.getInitCarac()
|
||||
if (carac == undefined) {
|
||||
|
||||
@@ -100,6 +100,7 @@ export class RdDItemGemme extends RdDItem {
|
||||
return {
|
||||
alias: this.parent.getAlias(),
|
||||
item: this,
|
||||
nouveaupr: nouveauReve,
|
||||
update: {
|
||||
_id: this.id,
|
||||
'system.pr': nouveauReve,
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Grammar } from "./grammar.js";
|
||||
import { Monnaie } from "./item-monnaie.js";
|
||||
import { ITEM_TYPES, ACTOR_TYPES } from "./constants.js";
|
||||
import { RdDItem } from "./item.js";
|
||||
import { RdDItemCompetence } from "./item-competence.js";
|
||||
import { RdDTimestamp } from "./time/rdd-timestamp.js";
|
||||
import { RdDRaretes } from "./item/raretes.js";
|
||||
import { VOIES_DRACONIC } from "./item-sort.js";
|
||||
@@ -720,6 +721,20 @@ class _13_0_23_OmbreCategorieFalse extends Migration {
|
||||
}
|
||||
}
|
||||
|
||||
class _14_0_3_MigrationCompetenceBase extends Migration {
|
||||
get code() { return "competence-base-categorie" }
|
||||
get version() { return "14.0.3" }
|
||||
|
||||
async migrate() {
|
||||
await this.applyItemsUpdates(items => items
|
||||
.filter(it => it.type == ITEM_TYPES.competence
|
||||
&& it.system.categorie
|
||||
&& Number(it.system.base) == 0)
|
||||
.map(it => ({ _id: it.id, 'system.base': RdDItemCompetence.getNiveauBase(it.system.categorie, it.type) }))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export class Migrations {
|
||||
static getMigrations() {
|
||||
return [
|
||||
@@ -748,6 +763,7 @@ export class Migrations {
|
||||
new _13_0_21_AjoutAppreciation(),
|
||||
new _13_0_22_PoidsDesMonnaies(),
|
||||
new _13_0_23_OmbreCategorieFalse(),
|
||||
new _14_0_3_MigrationCompetenceBase(),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ export default class RdDModelCompetence extends foundry.abstract.TypeDataModel {
|
||||
{
|
||||
niveau: new fields.NumberField({ label: "Niveau", initial: 0, ...INTEGER_SIGNED, min: -11 }),
|
||||
default_diffLibre: new fields.NumberField({ label: "Difficulté libre par défaut", initial: 0, ...INTEGER_SIGNED, min: -10, max: 0 }),
|
||||
base: new fields.NumberField({ label: "Base", initial: 0, ...INTEGER }),
|
||||
base: new fields.NumberField({ label: "Base", initial: 0, ...INTEGER_SIGNED }),
|
||||
categorie: new fields.StringField({ label: "Catégorie", initial: "", ...STRING }),
|
||||
xp: new fields.NumberField({ label: "XP", initial: 0, ...INTEGER }),
|
||||
defaut_carac: new fields.StringField({ label: "Caractéristique par défaut", initial: "", ...STRING }),
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { renderTemplate } from "../constants.js"
|
||||
import { EffetsDraconiques } from "../tmr/effets-draconiques.js"
|
||||
|
||||
export class DialogNouveauReposCD {
|
||||
static async prompt(actor) {
|
||||
const date = game.system.rdd.calendrier.dateCourante()
|
||||
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(
|
||||
"systems/foundryvtt-reve-de-dragon/templates/sommeil/dialog-nouveau-repos-cd.hbs",
|
||||
data
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { renderTemplate } from "../constants.js"
|
||||
import { RdDTimestamp, RDD_HEURES_PAR_JOUR } from "../time/rdd-timestamp.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"
|
||||
|
||||
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 heureCourante = now.heure
|
||||
const hourDefs = RdDTimestamp.definitions()
|
||||
const insomnie = EffetsDraconiques.isSujetInsomnie(actor)
|
||||
const repriseHeures = Math.max(actor.system.sommeil?.heures ?? 0, 0)
|
||||
const data = {
|
||||
name: actor.name, img: actor.img, hourDefinitions: hourDefs,
|
||||
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)
|
||||
new DialogNouveauRepos(content, actor).render({ force: true })
|
||||
@@ -126,7 +137,7 @@ export class DialogNouveauRepos extends foundry.applications.api.DialogV2 {
|
||||
content: this.actor.name + ": "
|
||||
}
|
||||
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 })
|
||||
if (insomnie) {
|
||||
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) {
|
||||
duree = RDD_HEURES_PAR_JOUR - heureDebut + 1
|
||||
}
|
||||
await this.actor.update({ "system.sommeil": { heures: duree } })
|
||||
let cdProcessed = false
|
||||
let h = 0
|
||||
while (true) {
|
||||
@@ -142,12 +154,18 @@ export class DialogNouveauRepos extends foundry.applications.api.DialogV2 {
|
||||
if (reveilForce && dormi.heures >= heuresForce) break
|
||||
if (!avaitFatigue && h >= duree) 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.$recupererFatigue(message)
|
||||
await this.actor.$jetRecuperationReve(dormi, message)
|
||||
if (!EffetsDraconiques.isSujetInsomnie(this.actor)) {
|
||||
await this.actor.$recupererFatigue(message)
|
||||
await this.actor.$jetRecuperationReve(dormi, message)
|
||||
if (dormi.etat === "dort" && EffetsDraconiques.isDonDoubleReve(this.actor)) {
|
||||
await this.actor.$jetRecuperationReve(dormi, message)
|
||||
}
|
||||
}
|
||||
dormi.heures++
|
||||
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
|
||||
const cdData = await DialogNouveauReposCD.prompt(this.actor)
|
||||
if (cdData.stress.valeur > 0) {
|
||||
@@ -172,6 +190,8 @@ export class DialogNouveauRepos extends foundry.applications.api.DialogV2 {
|
||||
}
|
||||
if (dormi.etat === "eveil") {
|
||||
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")}. `
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
{{!-- Sheet Body --}}
|
||||
<section class="sheet-body">
|
||||
<div class="flexcol form-group medium-editor">
|
||||
<div class="flexcol medium-editor">
|
||||
<fieldset>
|
||||
<div>
|
||||
<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">
|
||||
<h2>Château Dormant — {{name}}</h2>
|
||||
<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">
|
||||
<label>Points de stress du jour</label>
|
||||
<input type="number" name="cd-stress" value="0" min="0" max="200">
|
||||
|
||||
@@ -17,9 +17,19 @@
|
||||
<div class="form-group">
|
||||
<span>Durée : <strong><span id="duree-sommeil">0</span> heures</strong></span>
|
||||
</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">
|
||||
<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>
|
||||
<span>heures</span>
|
||||
</div>
|
||||
|
||||
Regular → Executable
Regular → Executable
Reference in New Issue
Block a user