From 4a03c222d54bb1effe73149c8cc7b35a68310a5b Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Tue, 21 Nov 2023 21:07:37 +0100 Subject: [PATCH] Gestion des points de coeur MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Les suivants/compagnons/amoureux sont dans l'onglet description - si acteurs "liés", ils peuvent avoir des points de coeur - les jets de volonté peuvent être ajustés s'ils concernent un compagnon pour lequel on a du coeur - on peut ajouter des points de coeur (entre la gestion de Chateau dormant par le gardien et le jet de repos si ce mode est utilisé) - on peut retirer des points de coeur en perdant du moral (mêmes conditions) - on peut passer de tendres moments si les deux acteurs acceptent - les tendre moments font jouer un jet de moral adapté - on peut perdre un point de coeur suite à un tendre moment qui ne fait pas gagner de moral --- module/actor-sheet.js | 32 ++-- module/actor.js | 35 +++-- module/actor/base-actor.js | 3 +- module/coeur/rdd-coeur.js | 146 ++++++++++++++++++ module/rdd-roll.js | 19 ++- module/rdd-utility.js | 24 +-- module/rolldata-ajustements.js | 6 + styles/simple.css | 3 + templates/actor/liens-suivants.hbs | 16 ++ .../coeur/chat-accepter-tendre-moment.hbs | 26 ++++ templates/coeur/chat-effet-tendre-moment.hbs | 11 ++ .../coeur/chat-proposer-tendre-moment.hbs | 32 ++++ .../coeur/chat-refuser-tendre-moment.hbs | 23 +++ templates/dialog-roll-carac.html | 1 + templates/dialog-roll.html | 1 + templates/partial-roll-coeur.hbs | 14 ++ 16 files changed, 347 insertions(+), 45 deletions(-) create mode 100644 module/coeur/rdd-coeur.js create mode 100644 templates/coeur/chat-accepter-tendre-moment.hbs create mode 100644 templates/coeur/chat-effet-tendre-moment.hbs create mode 100644 templates/coeur/chat-proposer-tendre-moment.hbs create mode 100644 templates/coeur/chat-refuser-tendre-moment.hbs create mode 100644 templates/partial-roll-coeur.hbs diff --git a/module/actor-sheet.js b/module/actor-sheet.js index a81838c6..8a34d319 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -16,13 +16,14 @@ 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"; /* -------------------------------------------- */ /** * Extend the basic ActorSheet with some very simple modifications * @extends {ActorSheet} */ -export class RdDActorSheet extends RdDBaseActorSangSheet { /** @override */ static get defaultOptions() { @@ -127,9 +128,13 @@ export class RdDActorSheet extends RdDBaseActorSangSheet { }) this.html.find('.subacteur-coeur-toggle a').click(async event => { - const actorId = RdDSheetUtility.getEventItemData(event, 'actor-id') - const clickCoeurNombre = $(event.currentTarget).data("coeur-nombre") - this.toggleSubActeurCoeur(actorId, clickCoeurNombre) + const subActorIdactorId = RdDSheetUtility.getEventItemData(event, 'subactor-id') + const coeurNombre = $(event.currentTarget).data('coeur-nombre') + RdDCoeur.toggleSubActeurCoeur(this.actor.id, subActorIdactorId, coeurNombre) + }) + this.html.find('.subacteur-tendre-moment').click(async event => { + const subActorId = RdDSheetUtility.getEventItemData(event, 'subactor-id') + RdDCoeur.startSubActeurTendreMoment(this.actor.id, subActorId) }) this.html.find('.subacteur-open').click(async event => { const subActorId = RdDSheetUtility.getEventItemData(event, 'subactor-id'); @@ -297,10 +302,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet { } openSubActeur(actorId) { - let actor = game.actors.get(actorId); - if (actor) { - actor.sheet.render(true); - } + game.actors.get(actorId)?.sheet.render(true) } deleteSubActeur(actorId, li) { @@ -308,24 +310,12 @@ export class RdDActorSheet extends RdDBaseActorSangSheet { const subActor = game.actors.get(actorId); RdDUtility.confirmSubActeurDelete(this, subActor, li, () => { console.log('Delete : ', subActor.id); - this.actor.removeSubActeur(subActor.id); + this.actor.deleteSubActeur(subActor.id); RdDUtility.slideOnDelete(this, li); }); } } - toggleSubActeurCoeur(actorId, toggleCoeur) { - console.log(this.actor, 'toggleSubActeurCoeur', actorId, toggleCoeur) - const coeur = this.actor.getPointsCoeur(actorId) - if (toggleCoeur <= coeur) { - this.actor.jetDeMoral('malheureuse'); - this.actor.setPointsCoeur(actorId, Math.max(0, coeur - 1)) - } - else { - this.actor.setPointsCoeur(actorId, Math.min(4, toggleCoeur)) - } - } - /* -------------------------------------------- */ async selectTypeOeuvreToCreate() { let types = RdDItem.getTypesOeuvres(); diff --git a/module/actor.js b/module/actor.js index 911e0855..4182c5fa 100644 --- a/module/actor.js +++ b/module/actor.js @@ -1096,18 +1096,19 @@ export class RdDActor extends RdDBaseActorSang { /* -------------------------------------------- */ async moralIncDec(ajustementMoral) { if (ajustementMoral != 0) { - ajustementMoral = Math.sign(ajustementMoral) - let moral = Misc.toInt(this.system.compteurs.moral.value) + ajustementMoral - if (moral > 3) { // exaltation - const exaltation = Misc.toInt(this.system.compteurs.exaltation.value) + ajustementMoral; - await this.updateCompteurValue('exaltation', exaltation); + const startMoral = parseInt(this.system.compteurs.moral.value) + const moralTheorique = startMoral + ajustementMoral + if (moralTheorique > 3) { // exaltation + const ajoutExaltation = moralTheorique - 3 + const exaltation = parseInt(this.system.compteurs.exaltation.value) + ajoutExaltation + await this.updateCompteurValue('exaltation', exaltation) } - if (moral < -3) { // dissolution - const dissolution = Misc.toInt(this.system.compteurs.dissolution.value) - ajustementMoral; - await this.updateCompteurValue('dissolution', dissolution); + if (moralTheorique < -3) { // dissolution + const ajoutDissolution = -3 - moralTheorique + const dissolution = parseInt(this.system.compteurs.dissolution.value) + ajoutDissolution + await this.updateCompteurValue('dissolution', dissolution) } - moral = Math.max(-3, Math.min(moral, 3)); - await this.updateCompteurValue('moral', moral); + await this.updateCompteurValue('moral', Math.max(-3, Math.min(moralTheorique, 3))); } return this.system.compteurs.moral.value; } @@ -2634,6 +2635,7 @@ export class RdDActor extends RdDBaseActorSang { /* -------------------------------------------- */ static $transformSubActeurSuivant = (suivant, link) => { return mergeObject(RdDBaseActor.extractActorMin(suivant), { + ephemere: !suivant.prototypeToken.actorLink, coeur: link.coeur ?? 0 }) }; @@ -2652,6 +2654,19 @@ export class RdDActor extends RdDBaseActorSang { return undefined } + getPointsCoeur(actorId) { + return this.getSuivant(actorId)?.coeur ?? 0; + } + + async setPointsCoeur(actorId, coeur) { + const amoureux = this.getSuivant(actorId); + if (amoureux) { + const suivants = this.system.subacteurs.suivants; + let newSuivants = [...suivants.filter(it => it.id != actorId), { id: actorId, coeur: coeur }] + await this.update({ 'system.subacteurs.suivants': newSuivants }); + } + } + /* -------------------------------------------- */ static $transformSubActeurVehicule = (vehicle, link) => { return mergeObject(RdDBaseActor.extractActorMin(vehicle), { diff --git a/module/actor/base-actor.js b/module/actor/base-actor.js index ed43802e..6ae29da5 100644 --- a/module/actor/base-actor.js +++ b/module/actor/base-actor.js @@ -145,7 +145,6 @@ export class RdDBaseActor extends Actor { return RdDBaseActor._findCaracByName(this.system.carac, name); } - /* -------------------------------------------- */ /* -------------------------------------------- */ async _preCreate(data, options, user) { await super._preCreate(data, options, user); @@ -186,7 +185,9 @@ export class RdDBaseActor extends Actor { } return undefined; } + listeSuivants(filter = suivant => true) { return [] } + listeSuivants(filter = suivant =>true) { return [] } listItems(type = undefined) { return (type ? this.itemTypes[type] : this.items); } filterItems(filter, type = undefined) { return (type ? this.itemTypes[type] : this.items)?.filter(filter) ?? []; } findItemLike(idOrName, type) { diff --git a/module/coeur/rdd-coeur.js b/module/coeur/rdd-coeur.js new file mode 100644 index 00000000..7fdf7f9c --- /dev/null +++ b/module/coeur/rdd-coeur.js @@ -0,0 +1,146 @@ +import { RdDBaseActor } from "../actor/base-actor.js"; +import { ChatUtility } from "../chat-utility.js"; +import { ReglesOptionnelles } from "../settings/regles-optionnelles.js"; + +const INFO_COEUR = 'info-coeur'; + +export class RdDCoeur { + static registerChatCallbacks(html) { + html.on("click", 'a.accepter-tendre-moment', event => { + RdDCoeur.accepterTendreMoment(RdDCoeur.extractInfoCoeur(event)) + }) + html.on("click", 'a.refuser-tendre-moment', event => { + RdDCoeur.refuserTendreMoment(RdDCoeur.extractInfoCoeur(event)) + }) + html.on("click", 'a.perdre-point-coeur-douceur', event => { + RdDCoeur.perdreEnDouceur( + RdDCoeur.extractInfoCoeur(event), + event.currentTarget.attributes['data-actor-id'].value) + }) + } + + static addTagsInfoCoeur(infoCoeur, chatMessage = undefined) { + if (chatMessage) { + infoCoeur.chatMessageId = chatMessage.id + } + else { + chatMessage = game.messages.get(infoCoeur.chatMessageId) + } + ChatUtility.setMessageData(chatMessage, INFO_COEUR, infoCoeur); + } + + static extractInfoCoeur(event) { + return ChatUtility.getMessageData(ChatUtility.getChatMessage(event), INFO_COEUR) + } + + static getInfoCoeur(sourceActorId, targetActorId) { + const sourceActor = game.actors.get(sourceActorId) + const targetActor = game.actors.get(targetActorId) + if (sourceActor && targetActor) { + return { + source: { + actor: RdDBaseActor.extractActorMin(sourceActor), + coeur: sourceActor.getPointsCoeur(targetActorId), + }, + target: { + actor: RdDBaseActor.extractActorMin(targetActor), + coeur: targetActor.getPointsCoeur(sourceActorId), + } + } + } + return {} + } + + static async toggleSubActeurCoeur(actorId, subActorId, toggleCoeur) { + const actor = game.actors.get(actorId) + if (ReglesOptionnelles.isUsing("chateau-dormant-gardien") && !actor.system.sommeil.nouveaujour) { + ui.notifications.warn(`Les changements de points de coeur se font juste avant de gérer Château Dormant, juste avant de passer à un nouveau jour`) + return + } + const coeur = actor.getPointsCoeur(subActorId); + if (toggleCoeur <= coeur) { + // TODO: validation? + await actor.moralIncDec(-4); + actor.setPointsCoeur(subActorId, Math.max(0, coeur - 1)); + ChatMessage.create({ + whisper: ChatUtility.getWhisperRecipientsAndGMs(actor.name), + content: `Perte de points de coeur arbitraire: ${actor.name} perd 4 points de moral, pour finir à ${actor.getMoralTotal()}.` + }); + } + else { + actor.setPointsCoeur(subActorId, Math.min(4, toggleCoeur)); + } + } + + static async startSubActeurTendreMoment(actorId, subActeurId) { + const infoCoeur = RdDCoeur.getInfoCoeur(actorId, subActeurId) + if (infoCoeur.target?.actor.id) { + // TODO: passer par une fenêtre pour saisir sa proposition (lieu, heure, ...) + const chatHtml = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/coeur/chat-proposer-tendre-moment.hbs`, infoCoeur) + const chatMessage = await ChatMessage.create({ + whisper: ChatUtility.getWhisperRecipientsAndGMs(infoCoeur.target?.actor.name), + content: chatHtml + }) + RdDCoeur.addTagsInfoCoeur(infoCoeur, chatMessage) + } + } + + static async accepterTendreMoment(infoCoeur) { + const target = game.actors.get(infoCoeur.target.actor.id) + if (!target.isOwner) { + ui.notifications.warn(`vous ne pouvez pas accepter pour ${infoCoeur.target.actor.name}`) + return + } + ChatUtility.removeChatMessageId(infoCoeur.chatMessageId) + + infoCoeur.target.jetTendre = (await (new Roll('1d6').evaluate({ async: true }))).total + infoCoeur.source.jetTendre = (await (new Roll('1d6').evaluate({ async: true }))).total + const diff = Math.abs(infoCoeur.source.jetTendre - infoCoeur.target.jetTendre) + for (let amoureux of [infoCoeur.source, infoCoeur.target]) { + const actorAmoureux = game.actors.get(amoureux.actor.id); + amoureux.situation = diff <= amoureux.coeur ? 'heureux' : 'neutre' + amoureux.gainMoral = await actorAmoureux.jetDeMoral(amoureux.situation) + } + const chatHtml = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/coeur/chat-accepter-tendre-moment.hbs`, infoCoeur) + const chatMessage = await ChatMessage.create({ + whisper: ChatUtility.getWhisperRecipientsAndGMs(infoCoeur.source?.actor.name, infoCoeur.target?.actor.name), + content: chatHtml + }) + RdDCoeur.addTagsInfoCoeur(infoCoeur, chatMessage) + } + + static async refuserTendreMoment(infoCoeur) { + const target = game.actors.get(infoCoeur.target.actor.id) + if (!target.isOwner) { + ui.notifications.warn(`vous ne pouvez pas refuser pour ${infoCoeur.target.actor.name}`) + return + } + ChatUtility.removeChatMessageId(infoCoeur.chatMessageId) + const chatHtml = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/coeur/chat-refuser-tendre-moment.hbs`, infoCoeur) + await ChatMessage.create({ + whisper: ChatUtility.getWhisperRecipientsAndGMs(infoCoeur.source?.actor.name, infoCoeur.target?.actor.name), + content: chatHtml + }); + } + + static async perdreEnDouceur(infoCoeur, actorId) { + const [amoureux, partenaire] = (infoCoeur.source.actor.id == actorId + ? [infoCoeur.source, infoCoeur.target] + : (infoCoeur.target.actor.id == actorId + ? [infoCoeur.target, infoCoeur.source] + : [undefined, undefined])) + + const subActorId = partenaire?.actor.id; + if (amoureux.perteCoeur) { + ui.notifications.warn(`Un point de coeur a déjà été perdu`) + } + else if (amoureux.coeur > 0) { + const actor = game.actors.get(actorId) + if (actor.isOwner) { + await actor.setPointsCoeur(subActorId, amoureux.coeur - 1) + amoureux.perteCoeur = true + RdDCoeur.addTagsInfoCoeur(infoCoeur) + } + } + } +} \ No newline at end of file diff --git a/module/rdd-roll.js b/module/rdd-roll.js index 9a36c884..801d9175 100644 --- a/module/rdd-roll.js +++ b/module/rdd-roll.js @@ -22,7 +22,7 @@ export class RdDRoll extends Dialog { const html = await renderTemplate(dialogConfig.html, rollData); - let options = { classes: ["rdd-roll-dialog"], width: 650, height: 'fit-content', 'z-index': 99999, close: html => {} }; + let options = { classes: ["rdd-roll-dialog"], width: 650, height: 'fit-content', 'z-index': 99999, close: html => { } }; if (dialogConfig.close) { options.close = dialogConfig.close; } @@ -37,6 +37,7 @@ export class RdDRoll extends Dialog { difficultesLibres: CONFIG.RDD.difficultesLibres, etat: actor.getEtatGeneral(), moral: actor.getMoralTotal(), /* La valeur du moral pour les jets de volonté */ + amoureux: actor.listeSuivants(it => it.coeur > 0), carac: actor.system.carac, finalLevel: 0, diffConditions: 0, @@ -45,6 +46,7 @@ export class RdDRoll extends Dialog { use: { moral: false, /* Est-ce que le joueur demande d'utiliser le moral ? Utile si le joueur change plusieurs fois de carac associée. */ libre: true, + coeur: undefined, conditions: true, surenc: actor.isSurenc(), encTotal: true @@ -174,6 +176,15 @@ export class RdDRoll extends Dialog { this.rollData.competence = this.rollData.competences.find(it => it.name == competence); this.updateRollResult(html); }); + this.html.find('.select-suivant-coeur').change((event) => { + const selectedActorId = event.currentTarget.value; + this.rollData.use.coeur = this.actor.getSuivant(selectedActorId) + if (this.rollData.use.coeur) { + this.html.find(".utilisation-coeur img.selected-suivant-coeur").attr('src', this.rollData.use.coeur?.img) + this.html.find(".utilisation-coeur img.selected-suivant-coeur").attr('title', this.rollData.use.coeur?.name) + } + this.updateRollResult(html); + }); this.html.find('.roll-signedraconique').change((event) => { let sortKey = Misc.toInt(event.currentTarget.value); this.setSelectedSigneDraconique(this.rollData.signes[sortKey]); @@ -300,17 +311,19 @@ export class RdDRoll extends Dialog { const resolutionTable = await RdDResolutionTable.buildHTMLTable(RdDResolutionTable.subTable(rollData.caracValue, rollData.finalLevel)) const adjustements = await this.buildAjustements(rollData); - + HtmlUtility.showControlWhen(this.html.find(".use-encTotal"), rollData.ajustements.encTotal.visible && RdDCarac.isAgiliteOuDerobee(rollData.selectedCarac)); HtmlUtility.showControlWhen(this.html.find(".use-surenc"), rollData.ajustements.surenc.visible && RdDCarac.isActionPhysique(rollData.selectedCarac)); HtmlUtility.showControlWhen(this.html.find(".utilisation-moral"), rollData.use.appelAuMoral); HtmlUtility.showControlWhen(this.html.find(".divAppelAuMoral"), rollData.use.appelAuMoral); + HtmlUtility.showControlWhen(this.html.find(".utilisation-coeur"), rollData.ajustements.coeur.visible); + HtmlUtility.showControlWhen(this.html.find(".utilisation-coeur img.selected-suivant-coeur"), rollData.ajustements.coeur.visible && rollData.use.coeur != undefined) // HtmlUtility.showControlWhen(this.html.find(".diffMoral"), rollData.ajustements.moral.used); // Mise à jour valeurs this.html.find(".dialog-roll-title").text(this._getTitle(rollData)); this.html.find("input.check-mortalite").prop('checked', rollData.dmg.mortalite == 'non-mortel'); - this.html.find("label.dmg-arme-actor").text(rollData.dmg.mortalite == 'empoignade'? 'empoignade': Misc.toSignedString(rollData.dmg.total) ); + this.html.find("label.dmg-arme-actor").text(rollData.dmg.mortalite == 'empoignade' ? 'empoignade' : Misc.toSignedString(rollData.dmg.total)); this.html.find("label.arme-mortalite").text(rollData.dmg.mortalite); // this.html.find("[name='dmg-arme-actor']").text(rollData.dmg.mortalite == 'empoignade'? 'empoignade': Misc.toSignedString(rollData.dmg.total) ); // this.html.find("[name='arme-mortalite']").text(rollData.dmg.mortalite); diff --git a/module/rdd-utility.js b/module/rdd-utility.js index ce41a0c7..9f5a2170 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -17,6 +17,7 @@ import { RdDTimestamp } from "./time/rdd-timestamp.js"; import { RdDRaretes } from "./item/raretes.js"; import { RdDEmpoignade } from "./rdd-empoignade.js"; import { ExperienceLog } from "./actor/experience-log.js"; +import { RdDCoeur } from "./coeur/rdd-coeur.js"; /* -------------------------------------------- */ // This table starts at 0 -> niveau -10 @@ -75,22 +76,22 @@ const nomEthylisme = ["Emeché", "Gris", "Pinté", "Pas frais", "Ivre", "Bu", "C /* -------------------------------------------- */ const definitionsEncaissement = { "mortel": [ - { minimum: undefined, maximum: 0, endurance: "0", vie: "0", gravite: -1}, - { minimum: 1, maximum: 10, endurance: "1d4", vie: "0", gravite: 0}, - { minimum: 11, maximum: 15, endurance: "1d6", vie: "0", gravite: 2}, - { minimum: 16, maximum: 19, endurance: "2d6", vie: "2", gravite: 4}, - { minimum: 20, maximum: undefined, endurance: "100", vie: "4 + @over20", gravite: 6}, + { minimum: undefined, maximum: 0, endurance: "0", vie: "0", gravite: -1 }, + { minimum: 1, maximum: 10, endurance: "1d4", vie: "0", gravite: 0 }, + { minimum: 11, maximum: 15, endurance: "1d6", vie: "0", gravite: 2 }, + { minimum: 16, maximum: 19, endurance: "2d6", vie: "2", gravite: 4 }, + { minimum: 20, maximum: undefined, endurance: "100", vie: "4 + @over20", gravite: 6 }, ], "non-mortel": [ - { minimum: undefined, maximum: 0, endurance: "0", vie: "0", gravite: -1}, + { minimum: undefined, maximum: 0, endurance: "0", vie: "0", gravite: -1 }, { minimum: 1, maximum: 10, endurance: "1d4", vie: "0", gravite: 0 }, { minimum: 11, maximum: 15, endurance: "1d6", vie: "0", gravite: 0 }, { minimum: 16, maximum: 19, endurance: "2d6", vie: "0", gravite: 2 }, { minimum: 20, maximum: undefined, endurance: "100", vie: "0", gravite: 2 }, ], "entiteincarnee": [ - { minimum: undefined, maximum: 0, endurance: "0", vie: "0", gravite: -1}, - { minimum: 1, maximum: 10, endurance: "1d4", vie: "0", gravite: 0}, + { minimum: undefined, maximum: 0, endurance: "0", vie: "0", gravite: -1 }, + { minimum: 1, maximum: 10, endurance: "1d4", vie: "0", gravite: 0 }, { minimum: 11, maximum: 15, endurance: "1d6", vie: "0", gravite: 0 }, { minimum: 16, maximum: 19, endurance: "2d6", vie: "0", gravite: 0 }, { minimum: 20, maximum: undefined, endurance: "3d6 + @over20", vie: "0", gravite: 0 }, @@ -203,6 +204,7 @@ export class RdDUtility { 'systems/foundryvtt-reve-de-dragon/templates/enum-tmr-effet.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-tmr-type.html', // Partials + 'systems/foundryvtt-reve-de-dragon/templates/coeur/chat-effet-tendre-moment.hbs', 'systems/foundryvtt-reve-de-dragon/templates/tirage/liste-resultats-recherche.hbs', 'systems/foundryvtt-reve-de-dragon/templates/time/horloge.hbs', 'systems/foundryvtt-reve-de-dragon/templates/common/timestamp.hbs', @@ -218,6 +220,7 @@ export class RdDUtility { 'systems/foundryvtt-reve-de-dragon/templates/partial-roll-surenc.html', 'systems/foundryvtt-reve-de-dragon/templates/partial-roll-enctotal.html', 'systems/foundryvtt-reve-de-dragon/templates/partial-roll-moral.html', + 'systems/foundryvtt-reve-de-dragon/templates/partial-roll-coeur.hbs', 'systems/foundryvtt-reve-de-dragon/templates/partial-roll-forcer.html', 'systems/foundryvtt-reve-de-dragon/templates/partial-roll-competences.html', 'systems/foundryvtt-reve-de-dragon/templates/partial-select-carac.html', @@ -291,7 +294,7 @@ export class RdDUtility { Handlebars.registerHelper('uniteQuantite', (itemId, actorId) => RdDUtility.getItem(itemId, actorId)?.getUniteQuantite()); Handlebars.registerHelper('isFieldInventaireModifiable', (type, field) => RdDItem.isFieldInventaireModifiable(type, field)); Handlebars.registerHelper('rarete-getChamp', (rarete, field) => RdDRaretes.getChamp(rarete, field)); - + Handlebars.registerHelper('plusMoins', diff => (diff > 0 ? '+' : '') + Math.round(diff)) Handlebars.registerHelper('experienceLog-topic', topic => ExperienceLog.labelTopic(topic)); @@ -646,6 +649,7 @@ export class RdDUtility { static async chatListeners(html) { RdDCombat.registerChatCallbacks(html) RdDEmpoignade.registerChatCallbacks(html) + RdDCoeur.registerChatCallbacks(html) // Gestion spécifique message passeurs html.on("click", '.tmr-passeur-coord a', event => { @@ -804,7 +808,7 @@ export class RdDUtility { } /* -------------------------------------------- */ - static confirmSubActeurDelete(sheet, subActor, htmlToDelete, onSuppression = ()=>{}) { + static confirmSubActeurDelete(sheet, subActor, htmlToDelete, onSuppression = () => { }) { RdDConfirm.confirmer({ settingConfirmer: "confirmation-supprimer-lien-acteur", content: `

Etes vous certain de vouloir supprimer le lien vers ${subActor.name} ?

`, diff --git a/module/rolldata-ajustements.js b/module/rolldata-ajustements.js index 5eab750d..3484dc86 100644 --- a/module/rolldata-ajustements.js +++ b/module/rolldata-ajustements.js @@ -80,6 +80,12 @@ export const referenceAjustements = { getLabel: (rollData, actor) => 'Appel au moral', getValue: (rollData, actor) => 1 }, + coeur: { + isVisible: (rollData, actor) => actor.isPersonnage() && RdDCarac.isVolonte(rollData.selectedCarac), + isUsed: (rollData, actor) => rollData.use.coeur != undefined, + getLabel: (rollData, actor) => 'Ajustement de coeur', + getValue: (rollData, actor) => -2 * (rollData.use.coeur?.coeur ?? 0) + }, moralTotal: { isUsed: (rollData, actor) => RdDCarac.isVolonte(rollData.selectedCarac), getLabel: (rollData, actor) => 'Moral', diff --git a/styles/simple.css b/styles/simple.css index 0ea124ce..5752c9b0 100644 --- a/styles/simple.css +++ b/styles/simple.css @@ -1458,6 +1458,9 @@ table.table-nombres-astraux tr:hover { transition: opacity 0.3s; } +.tendre-moment { + color: hsla(293, 72%, 44%, 0.8); +} /* ======================================== */ /* Fatigue CSS */ diff --git a/templates/actor/liens-suivants.hbs b/templates/actor/liens-suivants.hbs index 356a13df..540c1e13 100644 --- a/templates/actor/liens-suivants.hbs +++ b/templates/actor/liens-suivants.hbs @@ -6,6 +6,22 @@ {{suivant.name}} + {{#if suivant.ephemere}} + + + {{else}} + + + + + + + + {{#if (gte suivant.coeur 1)}} + Tendre moment + {{/if}} + + {{/if}}
diff --git a/templates/coeur/chat-accepter-tendre-moment.hbs b/templates/coeur/chat-accepter-tendre-moment.hbs new file mode 100644 index 00000000..f23a0e7d --- /dev/null +++ b/templates/coeur/chat-accepter-tendre-moment.hbs @@ -0,0 +1,26 @@ +

+
+ {{source.actor.name}} + +
+ + + + +
+
+ + + + +
+
+ {{target.actor.name}} +
+

+

+ {{target.actor.name}} et {{source.actor.name}} passent un tendre moment. +

+
+{{>'systems/foundryvtt-reve-de-dragon/templates/coeur/chat-effet-tendre-moment.hbs' source}} +{{>'systems/foundryvtt-reve-de-dragon/templates/coeur/chat-effet-tendre-moment.hbs' target}} diff --git a/templates/coeur/chat-effet-tendre-moment.hbs b/templates/coeur/chat-effet-tendre-moment.hbs new file mode 100644 index 00000000..108d1123 --- /dev/null +++ b/templates/coeur/chat-effet-tendre-moment.hbs @@ -0,0 +1,11 @@ +

+ {{actor.name}} obtient {{jetTendre}} sur 1d6 et {{#if (eq situation 'heureux')}}peut{{else}}ne peut pas{{/if}} + ajuster pour atteindre le score de son partenaire. Avec son jet de moral {{situation}}, {{actor.name}} + {{#if (gt gainMoral 0)}}a apprécié ce tendre moment et gagné du moral + {{else}}n'a pas gagné de moral{{#if (gte coeur 1)}} et peut + + perdre un point de coeur + + {{/if}}. + {{/if}} +

\ No newline at end of file diff --git a/templates/coeur/chat-proposer-tendre-moment.hbs b/templates/coeur/chat-proposer-tendre-moment.hbs new file mode 100644 index 00000000..c059f1ed --- /dev/null +++ b/templates/coeur/chat-proposer-tendre-moment.hbs @@ -0,0 +1,32 @@ +

+
+ {{source.actor.name}} + +
+ + + + +
+
+ + + + +
+
+ {{target.actor.name}} +
+

+

+ {{source.actor.name}} propose à {{target.actor.name}} de passer un tendre moment +

+

+ + Accepter + +   + + Refuser + +

diff --git a/templates/coeur/chat-refuser-tendre-moment.hbs b/templates/coeur/chat-refuser-tendre-moment.hbs new file mode 100644 index 00000000..d5eede5b --- /dev/null +++ b/templates/coeur/chat-refuser-tendre-moment.hbs @@ -0,0 +1,23 @@ +

+
+ {{source.actor.name}} + +
+ + + + +
+
+ + + + +
+
+ {{target.actor.name}} +
+

+

+ {{target.actor.name}} a refusé de passer un tendre moment avec {{source.actor.name}} +

diff --git a/templates/dialog-roll-carac.html b/templates/dialog-roll-carac.html index 78bae97d..e981e997 100644 --- a/templates/dialog-roll-carac.html +++ b/templates/dialog-roll-carac.html @@ -8,6 +8,7 @@ {{>"systems/foundryvtt-reve-de-dragon/templates/partial-roll-competences.html"}} {{>"systems/foundryvtt-reve-de-dragon/templates/partial-roll-surenc.html"}} {{>"systems/foundryvtt-reve-de-dragon/templates/partial-roll-enctotal.html"}} + {{>"systems/foundryvtt-reve-de-dragon/templates/partial-roll-coeur.hbs"}}
{{>"systems/foundryvtt-reve-de-dragon/templates/partial-roll-diffLibre.html"}} diff --git a/templates/dialog-roll.html b/templates/dialog-roll.html index 71bc54af..3d7b98e1 100644 --- a/templates/dialog-roll.html +++ b/templates/dialog-roll.html @@ -10,6 +10,7 @@ {{>"systems/foundryvtt-reve-de-dragon/templates/partial-roll-competences.html"}} {{>"systems/foundryvtt-reve-de-dragon/templates/partial-roll-surenc.html"}} {{>"systems/foundryvtt-reve-de-dragon/templates/partial-roll-enctotal.html"}} + {{>"systems/foundryvtt-reve-de-dragon/templates/partial-roll-coeur.hbs"}}
{{>"systems/foundryvtt-reve-de-dragon/templates/partial-roll-diffLibre.html"}} diff --git a/templates/partial-roll-coeur.hbs b/templates/partial-roll-coeur.hbs new file mode 100644 index 00000000..6c4c26fd --- /dev/null +++ b/templates/partial-roll-coeur.hbs @@ -0,0 +1,14 @@ +
+ +
+ + +
+