diff --git a/module/actor.js b/module/actor.js index 42ca2438..6e993730 100644 --- a/module/actor.js +++ b/module/actor.js @@ -1121,6 +1121,24 @@ export class RdDActor extends Actor { return queue; } + /* -------------------------------------------- */ + async reinsertionAleatoire(raison) { + ChatMessage.create({ + content: `${raison} : ré-insertion aléatoire.`, + whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name) + }); + const innaccessible = this.buildTMRInnaccessible(); + let tmr = TMRUtility.getTMRAleatoire(tmr => !innaccessible.includes(tmr.coord) ); + this.updateCoordTMR(tmr.coord); + return tmr; + } + + buildTMRInnaccessible() { + const tmrInnaccessibles = this.data.items.filter(it => Draconique.isCaseTMR(it) && + EffetsDraconiques.isInnaccessible(it)); + return tmrInnaccessibles.map(it => it.data.coord); + } + /* -------------------------------------------- */ displayTMRQueueSouffleInformation() { let messages = []; @@ -1137,9 +1155,6 @@ export class RdDActor extends Actor { if (EffetsDraconiques.isPeriple(item)) { messages.push("Vous souffrez du Souffle Périple. Vous devez gérer manuellement le détail du Périple.
" + item.data.description); } - if (EffetsDraconiques.isDesorientation(item)) { - messages.push("Vous souffrez du Souffle Désorientation. Vous devez gérer avec votre MJ les effets de ce souffle.
" + item.data.description); - } } if (messages.length > 0) { @@ -1796,6 +1811,10 @@ export class RdDActor extends Actor { ui.notifications.info("Aucun sort disponible pour cette case !"); return; } + if (EffetsDraconiques.isConquete(this)) { + ui.notifications.error("Vous ne pouvez pas lancer de sort sous l'effet d'une conquête!"); + return; + } if (this.currentTMR) this.currentTMR.minimize(); // Hide let draconicList = this.filterDraconicList(sortList); diff --git a/module/rdd-tmr-dialog.js b/module/rdd-tmr-dialog.js index 05bf2113..823e8679 100644 --- a/module/rdd-tmr-dialog.js +++ b/module/rdd-tmr-dialog.js @@ -10,6 +10,7 @@ import { Poetique } from "./poetique.js"; import { EffetsDraconiques } from "./tmr/effets-draconiques.js"; import { PixiTMR } from "./tmr/pixi-tmr.js"; import { Draconique } from "./tmr/draconique.js"; +import { Grammar } from "./grammar.js"; /* -------------------------------------------- */ export class RdDTMRDialog extends Dialog { @@ -50,7 +51,7 @@ export class RdDTMRDialog extends Dialog { this.cumulFatigue = 0; this.loadRencontres(); this.loadSortsReserve(); - this.casesSpeciales = this.actor.data.items.filter(item => Draconique.isCaseTMR(item)); + this.loadCasesSpeciales(); this.allTokens = []; this.rencontreState = 'aucune'; this.pixiApp = new PIXI.Application({ width: 720, height: 860 }); @@ -66,6 +67,10 @@ export class RdDTMRDialog extends Dialog { this.pixiTMR.load((loader, resources) => this.createPixiSprites()); } + loadCasesSpeciales() { + this.casesSpeciales = this.actor.data.items.filter(item => Draconique.isCaseTMR(item)); + } + loadSortsReserve() { this.sortsReserves = duplicate(this.actor.data.data.reve.reserve.list); } @@ -99,6 +104,7 @@ export class RdDTMRDialog extends Dialog { this._removeTokens(t => true); this.loadRencontres(); this.loadSortsReserve(); + this.loadCasesSpeciales(); this._createTokens(); } @@ -396,10 +402,13 @@ export class RdDTMRDialog extends Dialog { if (rencontre) { return rencontre; } - // TODO: dialog pour remplacer la rencontre par un présent - //if (this.casesSpeciales.find(c => EffetsDraconiques.isPresentCite(c, tmr.coord))) { - - + if (this.casesSpeciales.find(c => EffetsDraconiques.isPresentCite(c, tmr.coord))) { + + // TODO: dialog pour remplacer la rencontre par un présent + + } + + let myRoll = new Roll("1d7").evaluate().total; if (TMRUtility.isForceRencontre() || myRoll == 7) { return await this.rencontreTMRRoll(tmr, this.actor.isRencontreSpeciale()); @@ -415,30 +424,22 @@ export class RdDTMRDialog extends Dialog { ? await TMRRencontres.getMauvaiseRencontre() : await TMRRencontres.getRencontreAleatoire(tmr.type)); rencontre.coord = tmr.coord; - rencontre.date = game.system.rdd.calendrier.getDateFromIndex(); + rencontre.date = game.system.rdd.calendrier.getDateFromIndex(); rencontre.heure = game.system.rdd.calendrier.getCurrentHeure(); return rencontre; } /* -------------------------------------------- */ - async manageCaseSpeciale(tmr) { - if (this.casesSpeciales.find(c => EffetsDraconiques.isCaseTrouNoir(c, tmr.coord))) { - let newTMR = TMRUtility.getTMRAleatoire(); - let tmrPos = duplicate(this.actor.data.data.reve.tmrpos); - tmrPos.coord = newTMR.coord; - await this.actor.update({ "data.reve.tmrpos": tmrPos }); - ChatMessage.create({ - content: "Vous êtes rentré sur un Trou Noir : ré-insertion aléatoire.", - whisper: ChatMessage.getWhisperRecipients(game.user.name) - }); + async manageTmrInnaccessible(tmr) { + const caseTmrInnaccessible = this.casesSpeciales.find(c => EffetsDraconiques.isInnaccessible(c, tmr.coord)); + if (caseTmrInnaccessible) { + return await this.actor.reinsertionAleatoire(caseTmrInnaccessible.name); } + return tmr; } /* -------------------------------------------- */ async manageCaseHumide(tmr) { - if (this.viewOnly || this.currentRencontre) { - return; - } if (this.isCaseHumide(tmr)) { let rollData = { actor: this.actor, @@ -517,26 +518,52 @@ export class RdDTMRDialog extends Dialog { /* -------------------------------------------- */ async conquerirCiteFermee(tmr) { - if (this.viewOnly || this.currentRencontre) { - return; - } - const citeFermee = this.isCiteFermee(tmr.coord); - if (citeFermee) { - let rollData = { - actor: this.actor, - competence: duplicate(this.actor.getBestDraconic()), - tmr: tmr, - canClose: false, - diffLibre: -9, - forceCarac: { 'reve-actuel': { label: "Rêve Actuel", value: this.actor.getReveActuel() } }, - maitrise: { verbe: 'conquérir', action: 'Conquérir la cité' } - } - rollData.competence.data.defaut_carac = 'reve-actuel'; - - await this._maitriserTMR(rollData, r => this._resultatConqueteCiteFermee(r)); + if (EffetsDraconiques.fermetureCites.find(this.casesSpeciales, tmr.coord)) { + await this._conquerir(tmr, { + difficulte: -9, + action: 'Conquérir la cité', + onConqueteReussie: r => EffetsDraconiques.fermetureCites.onConquete(r.actor, tmr.coord), + onConqueteEchec: r => this.close(), + canClose: false + }); } } - async _resultatConqueteCiteFermee(rollData) { + + removeToken(tmr, casetmr) { + this._removeTokens(t => t.coordTMR() == tmr.coord && t.caseSpeciale?._id == casetmr._id); + this.updateTokens() + } + + /* -------------------------------------------- */ + async conquerirTMR(tmr) { + if (EffetsDraconiques.conquete.find(this.casesSpeciales, tmr.coord)) { + await this._conquerir(tmr, { + difficulte: -7, + action: 'Conquérir', + onConqueteReussie: r => EffetsDraconiques.conquete.onConquete(r.actor, tmr.coord, (casetmr) => this.removeToken(tmr, casetmr)), + onConqueteEchec: r => {}, + canClose: false + }); + } + } + + /* -------------------------------------------- */ + async _conquerir(tmr, options) { + let rollData = { + actor: this.actor, + competence: duplicate(this.actor.getBestDraconic()), + tmr: tmr, + canClose: options.canClose ?? false, + diffLibre: options.difficulte ?? -7, + forceCarac: { 'reve-actuel': { label: "Rêve Actuel", value: this.actor.getReveActuel() } }, + maitrise: { verbe: 'conquérir', action: options.action } + }; + rollData.competence.data.defaut_carac = 'reve-actuel'; + + await this._maitriserTMR(rollData, r => this._onResultatConquerir(r, options)); + } + + async _onResultatConquerir(rollData, options) { if (rollData.rolled.isETotal) { rollData.souffle = await this.actor.ajouterSouffle({ chat: false }); } @@ -548,12 +575,11 @@ export class RdDTMRDialog extends Dialog { content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-maitrise-tmr.html`, rollData) }); if (rollData.rolled.isEchec) { - this.close(); + options.onConqueteEchec(rollData, options.effetDraconique); } else { - const citeFermee = this.actor.data.items.find(it => EffetsDraconiques.isCiteFermee(it, rollData.tmr.coord)); - this.actor.deleteOwnedItem(citeFermee._id); - this._removeTokens(t => t.coordTMR() == citeFermee.data.coord && t.caseSpeciale?._id == citeFermee._id); + await options.onConqueteReussie(rollData, options.effetDraconique); + this.updateTokens(); } } @@ -578,17 +604,18 @@ export class RdDTMRDialog extends Dialog { } /* -------------------------------------------- */ - async declencheSortEnReserve(coordTMR) { - if (this.viewOnly) { - return; - } - - let sortReserveList = TMRUtility.getSortReserveList(this.sortsReserves, coordTMR); + async declencheSortEnReserve(coord) { + + let sortReserveList = TMRUtility.getSortReserveList(this.sortsReserves, coord); if (sortReserveList.length > 0) { - if (EffetsDraconiques.isReserveEnSecurite(this.actor) || this.isReserveExtensible(coordTMR)) { + if (EffetsDraconiques.isConquete(this.actor)) { + ui.notifications.error("Vous ne pouvez pas déclencher de sort sous l'effet d'une conquête!"); + return; + } + if (EffetsDraconiques.isReserveEnSecurite(this.actor) || this.isReserveExtensible(coord)) { let msg = "Vous êtes sur une case avec un Sort en Réserve. Grâce à votre Tête Reserve en Sécurité ou Réserve Exensible, vous pouvez contrôler le déclenchement. Cliquez si vous souhaitez le déclencher :