From 68c01fc930347f2dd932a53e83b7a0e988130b73 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Wed, 15 Oct 2025 00:27:37 +0200 Subject: [PATCH] =?UTF-8?q?Mont=C3=A9e=20TMR=20sur=20m=C3=A9ditation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ajout d'un bouton pour aller dans les TMR lors d'une méditation réussie --- module/roll/chat-roll-result.mjs | 45 ++++++++-- module/roll/roll-dialog.mjs | 4 +- module/roll/roll-type-cuisine.mjs | 8 +- module/roll/roll-type-meditation.mjs | 8 +- module/technical/actor-impacts.mjs | 102 +++++++++++++--------- templates/roll/result/chat-cuisine.hbs | 10 +-- templates/roll/result/chat-meditation.hbs | 13 +++ 7 files changed, 129 insertions(+), 61 deletions(-) diff --git a/module/roll/chat-roll-result.mjs b/module/roll/chat-roll-result.mjs index 0371c911..3e3653d5 100644 --- a/module/roll/chat-roll-result.mjs +++ b/module/roll/chat-roll-result.mjs @@ -8,6 +8,7 @@ import { RDD_CONFIG, renderTemplate } from "../constants.js" import { EMPOIGNADE } from "../item/arme.js" import { RdDTextEditor } from "../apps/rdd-text-roll-editor.js" import { RollTypeCuisine } from "./roll-type-cuisine.mjs" +import { RollTypeMeditation } from "./roll-type-meditation.mjs" export default class ChatRollResult { static init() { @@ -38,7 +39,7 @@ export default class ChatRollResult { ) const save = RollDialog.saveParts(roll, impacts) - ChatUtility.setMessageData(chatMessage, 'rollData', save) + await this.saveChatMessageRoll(chatMessage, save) return chatMessage } @@ -112,6 +113,8 @@ export default class ChatRollResult { $(html).on("click", '.resister-recul', event => this.onClickRecul(event)) $(html).on("click", '.choix-particuliere', event => this.onClickChoixParticuliere(event)) $(html).on("click", '.faire-gouter', event => this.onClickFaireGouter(event)) + $(html).on("click", '.monter-tmr-normale', event => this.onClickMonteeTMR(event, 'normal')) + $(html).on("click", '.monter-tmr-rapide', event => this.onClickMonteeTMR(event, 'rapide')) } @@ -125,8 +128,16 @@ export default class ChatRollResult { return undefined } + async saveChatMessageRoll(chatMessage, savedRoll) { + await ChatUtility.setMessageData(chatMessage, 'rollData', savedRoll) + } + + loadChatMessageRoll(chatMessage) { + return ChatUtility.getMessageData(chatMessage, 'rollData') + } + async updateChatMessage(chatMessage, savedRoll) { - ChatUtility.setMessageData(chatMessage, 'rollData', savedRoll) + await this.saveChatMessageRoll(chatMessage, savedRoll) const copy = foundry.utils.duplicate(savedRoll) RollDialog.loadRollData(copy) this.prepareDisplay(copy) @@ -136,7 +147,7 @@ export default class ChatRollResult { onClickAppelChance(event) { const chatMessage = ChatUtility.getChatMessage(event) - const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData') + const savedRoll = this.loadChatMessageRoll(chatMessage) const actor = game.actors.get(savedRoll.ids.actorId) actor.rollAppelChance( () => this.onAppelChanceSuccess(savedRoll, chatMessage), @@ -144,11 +155,13 @@ export default class ChatRollResult { event.preventDefault() } - onAppelChanceSuccess(savedRoll, chatMessage) { + async onAppelChanceSuccess(savedRoll, chatMessage) { const reRoll = foundry.utils.duplicate(savedRoll) console.log('onAppelChanceSuccess savedRoll', savedRoll) reRoll.type.retry = true + await this.updateChatMessage(chatMessage, reRoll) const callbacks = [r => ChatUtility.removeChatMessageId(chatMessage.id)] + // TODO: annuler les effets switch (reRoll.type.current) { case ROLL_TYPE_DEFENSE: @@ -171,7 +184,7 @@ export default class ChatRollResult { onClickAppelDestinee(event) { const chatMessage = ChatUtility.getChatMessage(event) - const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData') + const savedRoll = this.loadChatMessageRoll(chatMessage) const actor = game.actors.get(savedRoll.ids.actorId) actor.appelDestinee(async () => { @@ -184,7 +197,7 @@ export default class ChatRollResult { async onClickEncaissement(event) { const chatMessage = ChatUtility.getChatMessage(event) - const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData') + const savedRoll = this.loadChatMessageRoll(chatMessage) const attaque = savedRoll.attackerRoll const defender = game.actors.get(savedRoll.ids.actorId) const attacker = game.actors.get(savedRoll.ids.opponentId) @@ -198,7 +211,7 @@ export default class ChatRollResult { async onClickRecul(event) { const chatMessage = ChatUtility.getChatMessage(event) - const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData') + const savedRoll = this.loadChatMessageRoll(chatMessage) const defender = game.actors.get(savedRoll.ids.actorId) const attacker = game.actors.get(savedRoll.ids.opponentId) savedRoll.done.recul = await defender.encaisserRecul(attacker.getForce(), savedRoll.attackerRoll.dmg.dmgArme) @@ -209,15 +222,29 @@ export default class ChatRollResult { async onClickChoixParticuliere(event) { const choix = event.currentTarget.attributes['data-particuliere'].value const chatMessage = ChatUtility.getChatMessage(event) - const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData') + const savedRoll = this.loadChatMessageRoll(chatMessage) savedRoll.particuliere = choix savedRoll.particulieres = [RDD_CONFIG.particuliere[choix]] await this.updateChatMessage(chatMessage, savedRoll) await this.getCombat(savedRoll)?.onAttaqueV2(savedRoll, callbacks) } + async onClickFaireGouter(event) { const chatMessage = ChatUtility.getChatMessage(event) - const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData') + const savedRoll = this.loadChatMessageRoll(chatMessage) + if (!savedRoll.type.retry) { + savedRoll.type.retry = true + await this.updateChatMessage(chatMessage, savedRoll) + } await new RollTypeCuisine().onFaireGouter(savedRoll) } + + async onClickMonteeTMR(event, mode) { + const chatMessage = ChatUtility.getChatMessage(event) + const savedRoll = this.loadChatMessageRoll(chatMessage) + if (await new RollTypeMeditation().onMonteeTMR(savedRoll, mode)) { + savedRoll.done.meditation = true + await this.updateChatMessage(chatMessage, savedRoll) + } + } } \ No newline at end of file diff --git a/module/roll/roll-dialog.mjs b/module/roll/roll-dialog.mjs index 03c6a1e5..5d73e2a1 100644 --- a/module/roll/roll-dialog.mjs +++ b/module/roll/roll-dialog.mjs @@ -443,7 +443,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 async roll() { const roll = RollDialog.saveParts(this.rollData) - this.loadRollData(roll) + RollDialog.loadRollData(roll) const selectedRollType = this.getSelectedType(roll); selectedRollType.onSelect(roll) roll.current.resultat = this.rollData.current[PART_TRICHER]?.resultat ?? -1 @@ -472,7 +472,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 this.rollOptions.onRollDone(this) } - loadRollData(roll) { + static loadRollData(roll) { RollDialog.$prepareRollData(roll) RollDialog.calculAjustements(roll) roll.v2 = true diff --git a/module/roll/roll-type-cuisine.mjs b/module/roll/roll-type-cuisine.mjs index bcb84ae6..0f92ecde 100644 --- a/module/roll/roll-type-cuisine.mjs +++ b/module/roll/roll-type-cuisine.mjs @@ -32,17 +32,17 @@ export class RollTypeCuisine extends RollType { if (current.fabriquer) { const plat = this.$prepareNourriture(rollData.active.name, current, result) result.messages.push(`${plat.system.quantite} ${plat.name} ont été préparés dans l'équipement`) - impacts.active.addCreatedItem(plat) + impacts.active.addCreated('Item', plat) result.plat = { id: plat.id } } if (current.ingredient) { const quantite = Math.min(current.proportions, current.ingredient.system.quantite) if (quantite == current.ingredient.system.quantite) { - impacts.active.addDeletedItem(current.ingredient) + impacts.active.addDeleted('Item', current.ingredient) result.messages.push(`Il n'y a plus de ${ingredient.name}`) } else { - impacts.active.addItemDelta(current.ingredient, 'system.quantite', -current.proportions) + impacts.active.addDelta('Item', current.ingredient, 'system.quantite', -current.proportions) result.messages.push(`${current.proportions} ${current.ingredient.name} ont été utilisés`) } } @@ -51,7 +51,7 @@ export class RollTypeCuisine extends RollType { onApplyImpacts(roll, impacts) { if (roll.result.plat) { // le plat n'est pas créé immédiatement, il faut donc retrouver l'id - roll.result.plat.id = impacts.active.itemCreates.find(it => it.id = roll.result.plat.id)?.createdId + roll.result.plat.id = impacts.active.findCreatedId('Item', roll.result.plat.id) } } diff --git a/module/roll/roll-type-meditation.mjs b/module/roll/roll-type-meditation.mjs index ab310ccc..c3238487 100644 --- a/module/roll/roll-type-meditation.mjs +++ b/module/roll/roll-type-meditation.mjs @@ -1,4 +1,5 @@ import { RdDItemSigneDraconique } from "../item/signedraconique.js" +import { RollBasicParts } from "./roll-basic-parts.mjs" import { DIFF, ROLL_TYPE_MEDITATION } from "./roll-constants.mjs" import { PART_MEDITATION } from "./roll-part-meditation.mjs" import { RollType } from "./roll-type.mjs" @@ -26,7 +27,7 @@ export class RollTypeMeditation extends RollType { const rolled = rollData.rolled if (meditation && rolled) { if (rolled.isSuccess) { - await actor.createEmbeddedDocuments("Item", [RdDItemSigneDraconique.prepareSigneDraconiqueMeditation(meditation, rolled)]) + await actor.createEmbeddedDocuments('Item', [RdDItemSigneDraconique.prepareSigneDraconiqueMeditation(meditation, rolled)]) } if (rolled.isEPart) { await actor.updateEmbeddedDocuments('Item', [{ _id: meditation._id, 'system.malus': meditation.system.malus - 1 }]) @@ -34,4 +35,9 @@ export class RollTypeMeditation extends RollType { await actor.santeIncDec("fatigue", 2) } } + + async onMonteeTMR(savedRoll, mode){ + const actor = RollBasicParts.getTokenActor(savedRoll).actor + return actor?.displayTMR(mode) + } } \ No newline at end of file diff --git a/module/technical/actor-impacts.mjs b/module/technical/actor-impacts.mjs index 43420384..31652ee6 100644 --- a/module/technical/actor-impacts.mjs +++ b/module/technical/actor-impacts.mjs @@ -1,15 +1,25 @@ +const ACTOR_EMBEDDED_DOCTYPES = ['Item', 'ActiveEffect'] /** * class designed to store actor modification instructions, to apply them in a single operation, and have the ability to revert these */ export class ActorImpacts { + static $newDocumentImpacts(docType) { + return { creates: [], deletes: [], updates: [], docType: docType } + } + static $checkDocType(docType) { + if (!ACTOR_EMBEDDED_DOCTYPES.includes(docType)) { + throw `Unsupported document type ${docType}` + } + } + constructor(actorToken) { this.actorToken = actorToken this.updates = [] this.deltas = [] - this.itemCreates = [] - this.itemUpdates = [] - this.itemDeletes = [] + ACTOR_EMBEDDED_DOCTYPES.forEach( + docType => this[docType] = ActorImpacts.$newDocumentImpacts(docType) + ) } addActorUpdate(path, value) { @@ -27,46 +37,55 @@ export class ActorImpacts { } } - addDeletedItem(item) { - this.itemDeletes.push(item) - } - addCreatedItem(item) { - this.itemCreates.push(item) + addDeleted(docType, document) { + ActorImpacts.$checkDocType(docType) + this[docType].deletes.push(document) } - addItemUpdate(item, path, value) { - const existing = this.itemUpdates.find(it => it.id == item.id) + addCreated(docType, document) { + ActorImpacts.$checkDocType(docType) + this[docType].creates.push(document) + } + + addUpdate(docType, document, path, value) { + ActorImpacts.$checkDocType(docType) const update = [path, value] + const existing = this[docType].updates.find(it => it.id == document.id) if (existing) { existing.updates.push(update) } else { - this.itemUpdates.push({ id: item.id, updates: [update], deltas: [] }) + this[docType].updates.push({ id: document.id, updates: [update], deltas: [] }) } } - addItemDelta(item, path, value) { + addDelta(document, path, value) { + ActorImpacts.$checkDocType(document) const intValue = Number.parseInt(value) if (Number.isInteger(intValue) && intValue != 0) { const delta = [path, intValue] - const existing = this.itemUpdates.find(it => it.id == item.id) + const existing = this[docType].updates.find(it => it.id == document.id) if (existing) { existing.deltas.push(delta) } else { - this.itemUpdates.push({ id: item.id, updates: [], deltas: [delta] }) + this[docType].updates.push({ id: document.id, updates: [], deltas: [delta] }) } } else { - console.error('Cannot use non integer value {} for delta update', value) + console.error('Cannot use non-integer value {} for delta update', value) } } reverseImpacts() { const reverse = ActorImpacts.$computeReverts(new ActorImpacts(this.actorToken), this, __ => this.actorToken.actor) - reverse.itemCreates = this.itemDeletes.map(it => foundry.utils.duplicate(it)) - reverse.itemDeletes = this.itemCreates.map(it => { return { id: it.id } }) - reverse.itemUpdates = this.itemUpdates.map(it => ActorImpacts.$computeReverts({ id: it.id }, it, id => this.$getActorItem(id))) + ACTOR_EMBEDDED_DOCTYPES.forEach( + docType => { + reverse[docType].creates = this[docType].deletes.map(it => foundry.utils.duplicate(it)) + reverse[docType].deletes = this[docType].creates.map(it => { return { id: it.id } }) + reverse[docType].updates = this[docType].updates.map(it => ActorImpacts.$computeReverts({ id: it.id }, it, id => this.$getEmbeddedDocument(docType, id))) + } + ) return reverse } @@ -77,40 +96,44 @@ export class ActorImpacts { async applyImpacts() { const actor = this.actorToken.actor - const isItemsDelete = this.itemDeletes.length > 0 - const isItemsCreate = this.itemCreates.length > 0 - const isItemsUpdate = this.itemUpdates.length > 0 - const isActorUpdate = this.updates.length > 0 || this.deltas.length > 0 + await Promise.all(ACTOR_EMBEDDED_DOCTYPES.map(async docType => await this.$applyDocumentsImpacts(actor, docType))) + const updates = ActorImpacts.$computeUpdates(this, id => actor) + await actor.update(updates, { render: true }) + } - if (isItemsDelete) { - const deletes = this.itemDeletes.map(it => it.id) - await actor.deleteEmbeddedDocuments('Item', deletes, { render: !(isItemsCreate || isItemsUpdate || isActorUpdate) }) + + async $applyDocumentsImpacts(actor, docType) { + if (this[docType].deletes.length > 0) { + const deletes = this[docType].deletes.map(it => it.id) + await actor.deleteEmbeddedDocuments(docType, deletes, { render: false }) } - if (isItemsCreate) { - const creates = this.itemCreates - const created = await actor.createEmbeddedDocuments('Item', creates, { render: !(isItemsUpdate || isActorUpdate)}) - for (let i=0; i 0) { + const creates = this[docType].creates + const created = await actor.createEmbeddedDocuments(docType, creates, { render: false }) + for (let i = 0; i < creates.length; i++) { creates[i].createdId = created[i].id } } - if (isItemsUpdate) { - const updates = this.itemUpdates.map(u => ActorImpacts.$computeUpdates(u, id => this.$getActorItem(id))) - await actor.updateEmbeddedDocuments('Item', updates, { render: !isActorUpdate }) - } - - if (isActorUpdate) { - const updates = ActorImpacts.$computeUpdates(this, id => actor) - await actor.update(updates, { render: true }) + if (this[docType].updates.length > 0) { + const updates = this[docType].updates.map(u => ActorImpacts.$computeUpdates(u, id => this.$getEmbeddedDocument(docType, id))) + await actor.updateEmbeddedDocuments(docType, updates, { render: false }) } } - $getActorItem(id) { - return this.actorToken.actor.items.get(id) + findCreatedId(docType, origId){ + return this[docType].creates.find(it => it.id = origId)?.createdId + } + + $getEmbeddedDocument(docType, id) { + return this.actorToken.actor.getEmbeddedDocument(docType, id) } static $computeUpdates(u, getSource) { + if (u.updates.length == 0 && u.deltas.length == 0) { + return {} + } const source = getSource(u.id) const instruction = { _id: u.id } u.updates.forEach(u => instruction[u[0]] = u[1]) @@ -124,5 +147,4 @@ export class ActorImpacts { target.deltas = u.deltas.map(d => [d[0], -d[1]]) return target } - } diff --git a/templates/roll/result/chat-cuisine.hbs b/templates/roll/result/chat-cuisine.hbs index d3c707a3..5e6e8c47 100644 --- a/templates/roll/result/chat-cuisine.hbs +++ b/templates/roll/result/chat-cuisine.hbs @@ -21,12 +21,12 @@

{{active.name}} {{#if rolled.isSuccess}} - réussit la recette, pour un plat de qualité {{result.qualite~}} - {{#if (lt result.exotisme 0)}}et d'exotisme {{result.exotisme}}{{/if~}} + réussit la recette, pour un plat de qualité {{result.qualite}} + {{#if (lt result.exotisme 0)}}et d'exotisme {{result.exotisme}}{{/if}} {{else}} - fait un piètre cuisinier, et obtient un plat de qualité {{result.qualite~}} - {{#if (lt result.exotisme 0)}}à l'exotisme certain ({{result.exotisme}}){{/if~}} - {{/if~}}. + fait un piètre cuisinier, et obtient un plat de qualité {{result.qualite}} + {{#if (lt result.exotisme 0)}}à l'exotisme certain ({{result.exotisme}}){{/if}} + {{~/if~}}. {{#if (lt result.exotisme 0)}}
Au vu de l'exotisme du plat, les convives devront réussir un jet de @roll[Volonté/Cuisine/{{result.exotisme}}]. En cas d'échec, ils peuvent se forcer à faire plaisir à {{active.name}}, mais devront faire un jet de moral Malheureux. diff --git a/templates/roll/result/chat-meditation.hbs b/templates/roll/result/chat-meditation.hbs index 7826a90f..7fb38db2 100644 --- a/templates/roll/result/chat-meditation.hbs +++ b/templates/roll/result/chat-meditation.hbs @@ -39,6 +39,19 @@ {{/if}} +

+ {{#if rolled.isSuccess}} + {{#unless done.meditation}} + +  Montée normale dans les TMR + + +  Montée rapide dans les TMR + + {{/unless}} + {{/if}} +
+