diff --git a/changelog.md b/changelog.md index 1b2a0447..04facd2a 100644 --- a/changelog.md +++ b/changelog.md @@ -1,11 +1,16 @@ # 11.2 -## 11.2.20 - Le soulagement d'Akarlikarlikar +## 11.2.21 - Le questionnement d'Akarlikarlikar +- Une confirmation spécifique est demandée pour monter dans les terres médianes en cas de rencontre en attente +- L'expérience en caractéristique sur les jets de chance et rêve actuels est mise dans la caractéristique correspondante +- Les effets s'appliquent correctement sur les créatures +- La date et l'heure (draconiques) sont affichées dans les messages du tchat -- L'option 'ajout de la difficulté d'attaque à l'encaissement est affichée comme un modificateur d'encaissement -- Les options d'encaissement alternative fonctionnent avec la validation du gardien +## 11.2.20 - Le soulagement d'Akarlikarlikar +- L'option "ajout de la difficulté d'attaque à l'encaissement" est affichée comme un modificateur d'encaissement +- Les options d'encaissement alternatives fonctionnent avec la validation de l'encaissement par le gardien - La fenêtre d'astrologie du gardien affiche toutes les heures lues par un personnage - Si aucune expérience n'est gagnée, les autres effets à appliquer (comme la récupération de seuil après avoir vaincu un rêve de Dragon) s'appliquent normalement -- Les tooltips de Foundry sont maintenant lisibles +- Les tooltips de Foundry sont lisibles - On n'accorde plus les entités de cauchemar deux fois quand le gardien valide les encaissements - Les messages de récupération de rêve en cas de Rêve de Dragon sont clarifiés diff --git a/module/actor-sheet.js b/module/actor-sheet.js index d69bdadc..8b042f4c 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -16,7 +16,6 @@ import { RdDItem } from "./item.js"; import { RdDItemBlessure } from "./item/blessure.js"; import { RdDEmpoignade } from "./rdd-empoignade.js"; import { RdDBaseActorSangSheet } from "./actor/base-actor-sang-sheet.js"; -import { ChatUtility } from "./chat-utility.js"; import { RdDCoeur } from "./coeur/rdd-coeur.js"; /* -------------------------------------------- */ @@ -43,7 +42,6 @@ export class RdDActorSheet extends RdDBaseActorSangSheet { { editable: this.isEditable, cssClass: this.isEditable ? "editable" : "locked", - effects: this.actor.effects.map(e => foundry.utils.deepClone(e)), limited: this.actor.limited, owner: this.actor.isOwner, biographie: await TextEditor.enrichHTML(this.actor.system.biographie, { async: true }), diff --git a/module/actor.js b/module/actor.js index 19d4c101..e9429298 100644 --- a/module/actor.js +++ b/module/actor.js @@ -991,25 +991,33 @@ export class RdDActor extends RdDBaseActorSang { /* -------------------------------------------- */ buildTMRInnaccessible() { - const tmrInnaccessibles = this.filterItems(it => Draconique.isCaseTMR(it) && - EffetsDraconiques.isInnaccessible(it)); - return tmrInnaccessibles.map(it => it.system.coord); + return this.items[TYPES.casetmr] + .filter(it => EffetsDraconiques.isInnaccessible(it)) + .map(it => it.system.coord) } /* -------------------------------------------- */ - getTMRRencontres() { - return this.itemTypes['rencontre']; + getRencontresTMR() { + return this.itemTypes[TYPES.rencontre]; } /* -------------------------------------------- */ - async deleteTMRRencontreAtPosition() { - const demiReve = this.getDemiReve() - let rencontreIds = this.items.filter(it => it.type == 'rencontre' && it.system.coord == demiReve).map(it => it.id); + async deleteRencontreTMRAtPosition() { + const rencontreIds = this.itemTypes[TYPES.rencontre].filter(this.filterRencontreTMRDemiReve()).map(it => it.id) if (rencontreIds.length > 0) { - await this.deleteEmbeddedDocuments('Item', rencontreIds); + await this.deleteEmbeddedDocuments('Item', rencontreIds) } } + getRencontreTMREnAttente() { + return this.itemTypes[TYPES.rencontre].find(this.filterRencontreTMRDemiReve()) + } + + filterRencontreTMRDemiReve() { + const position = this.getDemiReve() + return it => it.system.coord == position + } + /* -------------------------------------------- */ async addTMRRencontre(currentRencontre) { const toCreate = currentRencontre.toObject(); @@ -2353,6 +2361,8 @@ export class RdDActor extends RdDBaseActorSang { static _getComposantsCaracDerivee(caracName) { switch (Grammar.toLowerCaseNoAccent(caracName)) { + case 'reve-actuel': case 'reve actuel': return ['reve'] + case 'chance-actuelle': case 'chance actuelle': return ['chance'] case 'vie': return ['constitution'] case 'tir': return ['vue', 'dexterite'] case 'lancer': return ['force', 'dexterite', 'vue'] @@ -2423,22 +2433,29 @@ export class RdDActor extends RdDBaseActorSang { /* -------------------------------------------- */ async displayTMR(mode = "normal") { if (this.tmrApp) { - ui.notifications.warn("Vous êtes déja dans les TMR...."); - this.tmrApp.forceTMRDisplay(); + ui.notifications.warn("Vous êtes déja dans les TMR....") + this.tmrApp.forceTMRDisplay() return } if (mode != 'visu' && this.getEffect(STATUSES.StatusDemiReve)) { - ui.notifications.warn("Le joueur ou le MJ est déja dans les Terres Médianes avec ce personnage ! Visualisation uniquement"); + ui.notifications.warn("Les personnage est déjà dans les Terres Médianes, elles s'affichent en visualisation") mode = "visu"; // bascule le mode en visu automatiquement } - RdDConfirm.confirmer({ - bypass: mode == 'visu', - settingConfirmer: "confirmation-tmr", - content: `

Voulez vous monter dans les TMR en mode ${mode}?

`, - title: 'Confirmer la montée dans les TMR', - buttonLabel: 'Monter dans les TMR', - onAction: async () => await this._doDisplayTMR(mode) - }); + if (mode == 'visu') { + await this._doDisplayTMR(mode) + } + else { + const rencontre = this.getRencontreTMREnAttente(); + const settingConfirmer = rencontre ? "confirmation-tmr-rencontre" : "confirmation-tmr"; + const messageRencontre = rencontre ? `

Vous devrez combattre ${rencontre.system.genre == 'f' ? 'la' : 'le'} ${rencontre.name} de ${rencontre.system.force} points de Rêve

` : ''; + RdDConfirm.confirmer({ + settingConfirmer: settingConfirmer, + content: `

Voulez vous monter dans les TMR en mode ${mode}?

` + messageRencontre, + title: 'Confirmer la montée dans les TMR', + buttonLabel: 'Monter dans les TMR', + onAction: async () => await this._doDisplayTMR(mode) + }) + } } async _doDisplayTMR(mode) { @@ -2967,9 +2984,6 @@ export class RdDActor extends RdDBaseActorSang { } } - /* -------------------------------------------- */ - isEffectAllowed(effectId) { return true } - /* -------------------------------------------- */ async onPreUpdateItem(item, change, options, id) { if (item.isCompetencePersonnage() && item.system.defaut_carac && item.system.xp) { diff --git a/module/actor/base-actor-reve.js b/module/actor/base-actor-reve.js index cd9640c3..38155403 100644 --- a/module/actor/base-actor-reve.js +++ b/module/actor/base-actor-reve.js @@ -180,7 +180,7 @@ export class RdDBaseActorReve extends RdDBaseActor { } /* -------------------------------------------- */ - isEffectAllowed(effectId) { return true } + isEffectAllowed(effectId) { return false } getEffects(filter = e => true) { return this.getEmbeddedCollection("ActiveEffect").filter(filter); diff --git a/module/actor/base-actor-sang.js b/module/actor/base-actor-sang.js index 693a57f2..2131666f 100644 --- a/module/actor/base-actor-sang.js +++ b/module/actor/base-actor-sang.js @@ -269,6 +269,8 @@ export class RdDBaseActorSang extends RdDBaseActorReve { return this.getEffect(STATUSES.StatusStunned); } + isEffectAllowed(effectId) { return true } + /* -------------------------------------------- */ async computeEtatGeneral() { this.system.compteurs.etat.value = this.malusVie() + this.malusFatigue() + this.malusEthylisme() } getEtatGeneral(options = { ethylisme: false }) { return this.system.compteurs.etat.value } diff --git a/module/actor/base-actor-sheet.js b/module/actor/base-actor-sheet.js index c8085789..eef49787 100644 --- a/module/actor/base-actor-sheet.js +++ b/module/actor/base-actor-sheet.js @@ -37,7 +37,8 @@ export class RdDBaseActorSheet extends ActorSheet { system: this.actor.system, description: await TextEditor.enrichHTML(this.actor.system.description, { async: true }), notesmj: await TextEditor.enrichHTML(this.actor.system.notesmj, { async: true }), - options: RdDSheetUtility.mergeDocumentRights(this.options, this.actor, this.isEditable) + options: RdDSheetUtility.mergeDocumentRights(this.options, this.actor, this.isEditable), + effects: this.actor.effects } RdDBaseActorSheet.filterItemsPerTypeForSheet(formData, this.actor.itemTypes); diff --git a/module/actor/base-actor.js b/module/actor/base-actor.js index b0a46de0..a9913159 100644 --- a/module/actor/base-actor.js +++ b/module/actor/base-actor.js @@ -8,7 +8,6 @@ import { RdDAudio } from "../rdd-audio.js"; import { RdDConfirm } from "../rdd-confirm.js"; import { RdDUtility } from "../rdd-utility.js"; import { SystemCompendiums } from "../settings/system-compendiums.js"; -import { APP_ASTROLOGIE_REFRESH } from "../sommeil/app-astrologie.js"; export class RdDBaseActor extends Actor { @@ -16,7 +15,7 @@ export class RdDBaseActor extends Actor { return Object.entries(carac) .filter(it => Grammar.equalsInsensitive(it[1].label, name)) .map(it => it[0]) - .find(it => it); + .find(it => it) } static $findCaracByName(carac, name) { const caracList = Object.entries(carac); diff --git a/module/actor/creature.js b/module/actor/creature.js index e60be24b..b50c1e43 100644 --- a/module/actor/creature.js +++ b/module/actor/creature.js @@ -33,10 +33,6 @@ export class RdDCreature extends RdDBaseActorSang { } } - isEffectAllowed(effectId) { - return [STATUSES.StatusComma].includes(effectId); - } - isEntiteAccordee(attacker) { if (this.isEntite([ENTITE_INCARNE])) { let resonnance = this.system.sante.resonnance diff --git a/module/chat-utility.js b/module/chat-utility.js index 24ff43da..a4f1f96d 100644 --- a/module/chat-utility.js +++ b/module/chat-utility.js @@ -1,5 +1,6 @@ import { Misc } from "./misc.js"; import { SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; +import { RdDTimestamp } from "./time/rdd-timestamp.js"; /** @@ -163,4 +164,17 @@ export class ChatUtility { return game.messages.get(chatMessageId); } + static async onRenderChatMessage(chatMessage, html, data) { + const rddTimestamp = chatMessage.getFlag(SYSTEM_RDD, 'rdd-timestamp') + if (rddTimestamp) { + const timestamp = new RdDTimestamp(rddTimestamp); + const timestampData = timestamp.toCalendrier(); + const dateHeure = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/common/date-heure.hbs', timestampData); + html.find('header.message-header .message-sender').after(dateHeure) + } + } + + static async onCreateChatMessage(chatMessage, options, id) { + await chatMessage.setFlag(SYSTEM_RDD, 'rdd-timestamp', game.system.rdd.calendrier.getTimestamp()); + } } diff --git a/module/item.js b/module/item.js index 62b019d9..e52970e0 100644 --- a/module/item.js +++ b/module/item.js @@ -177,7 +177,7 @@ export class RdDItem extends Item { constructor(docData, context = {}) { if (!context.rdd?.ready) { - mergeObject(context, { rdd: { ready: true } }); + foundry.utils.mergeObject(context, { rdd: { ready: true } }); const ItemConstructor = game.system.rdd.itemClasses[docData.type]; if (ItemConstructor) { if (!docData.img) { diff --git a/module/rdd-confirm.js b/module/rdd-confirm.js index 84a2781f..7e701432 100644 --- a/module/rdd-confirm.js +++ b/module/rdd-confirm.js @@ -4,29 +4,23 @@ import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; export class RdDConfirm { /* -------------------------------------------- */ static confirmer(options, autresActions) { - options.bypass = options.bypass || !(options.settingConfirmer == undefined || ReglesOptionnelles.isUsing(options.settingConfirmer)); - if (options.bypass) { - options.onAction(); + let buttons = { + "action": RdDConfirm._createButtonAction(options), + "cancel": RdDConfirm._createButtonCancel() + }; + if (options.settingConfirmer) { + buttons = foundry.utils.mergeObject(RdDConfirm._createButtonActionSave(options), buttons); } - else { - let buttons = { - "action": RdDConfirm._createButtonAction(options), - "cancel": RdDConfirm._createButtonCancel() - }; - if (options.settingConfirmer) { - buttons = foundry.utils.mergeObject(RdDConfirm._createButtonActionSave(options), buttons); - } - if (autresActions) { - buttons = foundry.utils.mergeObject(autresActions, buttons); - } - const dialogDetails = { - title: options.title, - content: options.content, - default: "cancel", - buttons: buttons - }; - new Dialog(dialogDetails, { width: 150 * Object.keys(buttons).length }).render(true); + if (autresActions) { + buttons = foundry.utils.mergeObject(autresActions, buttons); } + const dialogDetails = { + title: options.title, + content: options.content, + default: "cancel", + buttons: buttons + }; + new Dialog(dialogDetails, { width: 150 * Object.keys(buttons).length }).render(true); } static _createButtonCancel() { diff --git a/module/rdd-tmr-dialog.js b/module/rdd-tmr-dialog.js index f49be4fb..f53962dd 100644 --- a/module/rdd-tmr-dialog.js +++ b/module/rdd-tmr-dialog.js @@ -212,7 +212,7 @@ export class RdDTMRDialog extends Dialog { /* -------------------------------------------- */ loadRencontres() { - this.rencontresExistantes = this.actor.getTMRRencontres(); + this.rencontresExistantes = this.actor.getRencontresTMR(); } /* -------------------------------------------- */ @@ -382,7 +382,7 @@ export class RdDTMRDialog extends Dialog { async refouler() { console.log("-> refouler", this.currentRencontre); await this.actor.ajouterRefoulement(this.currentRencontre.system.refoulement, `${this.currentRencontre.system.genre == 'f' ? 'une' : 'un'} ${this.currentRencontre.name}`); - await this.actor.deleteTMRRencontreAtPosition(); // Remove the stored rencontre if necessary + await this.actor.deleteRencontreTMRAtPosition() this.updateTokens(); this.updateValuesDisplay(); this.nettoyerRencontre(); @@ -392,7 +392,7 @@ export class RdDTMRDialog extends Dialog { async ignorerRencontre() { console.log("-> ignorer", this.currentRencontre); this._tellToGM(this.actor.name + " a ignoré: " + this.currentRencontre.name); - await this.actor.deleteTMRRencontreAtPosition(); // Remove the stored rencontre if necessary + await this.actor.deleteRencontreTMRAtPosition() this.updateTokens(); this.updateValuesDisplay(); this.nettoyerRencontre(); @@ -446,7 +446,7 @@ export class RdDTMRDialog extends Dialog { async maitriserRencontre() { console.log("-> maitriser", this.currentRencontre); - await this.actor.deleteTMRRencontreAtPosition(); + await this.actor.deleteRencontreTMRAtPosition() this.updateTokens(); let rencontreData = { diff --git a/module/rdd-utility.js b/module/rdd-utility.js index 884be00c..35e50a5d 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -99,8 +99,9 @@ export class RdDUtility { static afficheContenu = {} /* -------------------------------------------- */ static async init() { - Hooks.on("renderChatMessage", async (app, html, msg) => RdDUtility.onRenderChatMessage(app, html, msg)); - Hooks.on('renderChatLog', (log, html, chatLog) => RdDUtility.chatListeners(html)); + Hooks.on("renderChatMessage", async (app, html, msg) => await ChatUtility.onRenderChatMessage(app, html, msg)) + Hooks.on("createChatMessage", async (chatMessage, options, id) => await ChatUtility.onCreateChatMessage(chatMessage, options, id)) + Hooks.on('renderChatLog', (log, html, chatLog) => RdDUtility.chatListeners(html)) } /* -------------------------------------------- */ @@ -206,6 +207,7 @@ export class RdDUtility { 'systems/foundryvtt-reve-de-dragon/templates/voyage/fatigue-actor.hbs', 'systems/foundryvtt-reve-de-dragon/templates/voyage/option-vitesse-fatigue.hbs', 'systems/foundryvtt-reve-de-dragon/templates/common/timestamp.hbs', + 'systems/foundryvtt-reve-de-dragon/templates/common/date-heure.hbs', 'systems/foundryvtt-reve-de-dragon/templates/common/periodicite.hbs', 'systems/foundryvtt-reve-de-dragon/templates/common/enum-duree.hbs', 'systems/foundryvtt-reve-de-dragon/templates/common/compendium-link.hbs', @@ -890,10 +892,4 @@ export class RdDUtility { } } - /*-------------------------------------------- */ - static async onRenderChatMessage(app, html, msg) { - // TODO - //console.log(app, html, msg); - } - } diff --git a/module/settings/regles-optionnelles.js b/module/settings/regles-optionnelles.js index bf40c95c..2d2f36bd 100644 --- a/module/settings/regles-optionnelles.js +++ b/module/settings/regles-optionnelles.js @@ -26,6 +26,7 @@ const listeReglesOptionnelles = [ { group: 'Confirmations', name: 'confirmer-combat-sans-cible', descr: "Confirmer avant une attaque sans cible", scope: "client"}, { group: 'Confirmations', name: 'confirmation-tmr', descr: "Confirmer pour monter dans les TMR", scope: "client"}, + { group: 'Confirmations', name: 'confirmation-tmr-rencontre', descr: "Confirmer pour monter dans les TMR avec rencontre en attente", scope: "client"}, { group: 'Confirmations', name: 'confirmation-refouler', descr: "Confirmer avant de refouler", scope: "client"}, { group: 'Confirmations', name: 'confirmation-vider', descr: "Confirmer pour vider l'équipement", scope: "client"}, { group: 'Confirmations', name: 'confirmation-supprimer-lien-acteur', descr: "Confirmer pour détacher un animal/suivant/véhicule", scope: "client"}, diff --git a/module/settings/status-effects.js b/module/settings/status-effects.js index 9a51b70f..b8d4592a 100644 --- a/module/settings/status-effects.js +++ b/module/settings/status-effects.js @@ -18,8 +18,8 @@ const rddStatusEffects = [ { rdd: true, id: STATUSES.StatusStunned, label: 'EFFECT.StatusStunned', icon: 'icons/svg/stoned.svg', "duration.rounds": 1 }, { rdd: true, id: STATUSES.StatusBleeding, label: 'EFFECT.StatusBleeding', icon: 'icons/svg/blood.svg' }, { rdd: true, id: STATUSES.StatusProne, label: 'EFFECT.StatusProne', icon: 'icons/svg/falling.svg' }, - { rdd: true, id: STATUSES.StatusGrappling, tint: '#33cc33', label: 'EFFECT.StatusGrappling', icon: 'systems/foundryvtt-reve-de-dragon/icons/empoignade.svg' }, - { rdd: true, id: STATUSES.StatusGrappled, tint: '#ff9900', label: 'EFFECT.StatusGrappled', icon: 'systems/foundryvtt-reve-de-dragon/icons/empoignade.svg' }, + { rdd: true, id: STATUSES.StatusGrappling, tint: '#33cc33', label: 'EFFECT.StatusGrappling', icon: 'systems/foundryvtt-reve-de-dragon/icons/empoignade.webp' }, + { rdd: true, id: STATUSES.StatusGrappled, tint: '#ff9900', label: 'EFFECT.StatusGrappled', icon: 'systems/foundryvtt-reve-de-dragon/icons/empoignade.webp' }, { rdd: true, id: STATUSES.StatusRestrained, label: 'EFFECT.StatusRestrained', icon: 'icons/svg/net.svg' }, { rdd: true, id: STATUSES.StatusUnconscious, label: 'EFFECT.StatusUnconscious', icon: 'icons/svg/unconscious.svg' }, { rdd: true, id: STATUSES.StatusBlind, label: 'EFFECT.StatusBlind', icon: 'icons/svg/blind.svg' }, @@ -65,7 +65,7 @@ export class StatusEffects extends FormApplication { static valeurSurprise(effect, isCombat) { if (statusSurpriseTotale.intersects(effect.statuses)) { - return 2; + return 2 } if (statusDemiSurprise.intersects(effect.statuses)) { return 1 @@ -110,7 +110,7 @@ export class StatusEffects extends FormApplication { static get defaultOptions() { const options = super.defaultOptions; - mergeObject(options, { + foundry.utils.mergeObject(options, { id: "status-effects", template: "systems/foundryvtt-reve-de-dragon/templates/settings/status-effects.html", height: 800, diff --git a/module/time/rdd-timestamp.js b/module/time/rdd-timestamp.js index c7a9b602..2f12d5c3 100644 --- a/module/time/rdd-timestamp.js +++ b/module/time/rdd-timestamp.js @@ -231,6 +231,7 @@ export class RdDTimestamp { get annee() { return Math.floor(this.indexDate / RDD_JOURS_PAR_AN) } get mois() { return Math.floor(Misc.modulo(this.indexDate, RDD_JOURS_PAR_AN) / RDD_JOURS_PAR_MOIS) } + get nomMois() { return Math.floor(Misc.modulo(this.indexDate, RDD_JOURS_PAR_AN) / RDD_JOURS_PAR_MOIS) } get jour() { return Misc.modulo(Misc.modulo(this.indexDate, RDD_JOURS_PAR_AN), RDD_JOURS_PAR_MOIS) } get heure() { return Math.floor(this.indexMinute / RDD_MINUTES_PAR_HEURES) } get minute() { return Misc.modulo(this.indexMinute, RDD_MINUTES_PAR_HEURES) } diff --git a/module/tmr/rencontre.js b/module/tmr/rencontre.js index d8d2d47e..9884b6c4 100644 --- a/module/tmr/rencontre.js +++ b/module/tmr/rencontre.js @@ -16,7 +16,7 @@ export class Rencontre extends Draconique { return pixiTMR.sprite(this.code(), { zIndex: tmrTokenZIndex.rencontre, decallage: pixiTMR.sizes.decallage(0, 0), - taille: () => pixiTMR.sizes.twoThird, + taille: () => pixiTMR.sizes.full, }) } } diff --git a/styles/simple.css b/styles/simple.css index 931fb9de..0a14100c 100644 --- a/styles/simple.css +++ b/styles/simple.css @@ -1527,6 +1527,11 @@ div.control-icon.token-hud-icon { font-size: 1rem; } +.chat-message header.message-header .heure-rdd { + font-size: 0.7rem; + flex-grow: 3; +} + .chat-message.whisper { background: rgba(220,220,210,0.75); border: 2px solid #545469; diff --git a/system.json b/system.json index 1e7866c7..e85c0a4d 100644 --- a/system.json +++ b/system.json @@ -1,8 +1,8 @@ { "id": "foundryvtt-reve-de-dragon", "title": "Rêve de Dragon", - "version": "11.2.20", - "download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-11.2.20.zip", + "version": "11.2.21", + "download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-11.2.21.zip", "manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/v11/system.json", "changelog": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/branch/v11/changelog.md", "compatibility": { diff --git a/templates/common/date-heure.hbs b/templates/common/date-heure.hbs new file mode 100644 index 00000000..a0f209fa --- /dev/null +++ b/templates/common/date-heure.hbs @@ -0,0 +1,3 @@ + + {{this.jourDuMois}} {{this.mois.label}} - {{timestamp-imgSigne this.heure}} + \ No newline at end of file