From f659a7508a011051127f16ed1ac88a17129a60ca Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Mon, 7 Nov 2022 00:04:43 +0100 Subject: [PATCH] Remplacement progressif rencontres --- module/actor-sheet.js | 4 - module/actor.js | 69 +-- module/effets-rencontres.js | 111 ++++ module/item-rencontre-sheet.js | 1 - module/item-rencontre.js | 72 ++- module/migrations.js | 2 +- module/rdd-calendrier.js | 8 +- module/rdd-main.js | 1 - module/rdd-tmr-dialog.js | 234 ++++---- module/rdd-tmr-rencontre-dialog.js | 31 +- module/rolldata-ajustements.js | 2 +- module/settings/system-compendiums.js | 11 +- module/tmr-rencontres.js | 581 ++++---------------- module/tmr-utility.js | 29 +- module/tmr/present-cites.js | 13 +- module/tmr/rencontre.js | 2 +- template.json | 6 - templates/actor/hr-rencontres.html | 23 +- templates/chat-rencontre-tmr.html | 2 +- templates/chat-resultat-reve-de-dragon.html | 2 +- templates/dialog-roll-reve-de-dragon.html | 2 +- 21 files changed, 460 insertions(+), 746 deletions(-) create mode 100644 module/effets-rencontres.js diff --git a/module/actor-sheet.js b/module/actor-sheet.js index 0ee4994f..6b103ad2 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -101,7 +101,6 @@ export class RdDActorSheet extends ActorSheet { formData.hautreve = { isDemiReve: this.actor.getEffect(STATUSES.StatusDemiReve), - rencontres: duplicate(formData.system.reve.rencontre.list), cacheTMR: this.actor.isTMRCache() } @@ -170,9 +169,6 @@ export class RdDActorSheet extends ActorSheet { const item = RdDSheetUtility.getItem(event, this.actor); item.sheet.render(true); }); - html.find('.rencontre-delete').click(async event => { - this.actor.deleteTMRRencontre(RdDSheetUtility.getItemId(event)); - }); html.find('.item-delete').click(async event => { const li = RdDSheetUtility.getEventElement(event); const item = this.actor.getObjet(li.data("item-id")); diff --git a/module/actor.js b/module/actor.js index 37f90e46..b0e46eb0 100644 --- a/module/actor.js +++ b/module/actor.js @@ -36,6 +36,7 @@ import { RdDPossession } from "./rdd-possession.js"; import { ENTITE_BLURETTE, ENTITE_INCARNE, ENTITE_NONINCARNE, HIDE_DICE, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; import { RdDConfirm } from "./rdd-confirm.js"; import { DialogValidationEncaissement } from "./dialog-validation-encaissement.js"; +import { RdDRencontre } from "./item-rencontre.js"; const POSSESSION_SANS_DRACONIC = { img: 'systems/foundryvtt-reve-de-dragon/icons/entites/possession.webp', @@ -757,25 +758,24 @@ export class RdDActor extends Actor { actor: this, competence: duplicate(this.getDraconicOuPossession()), canClose: false, - rencontre: duplicate(TMRRencontres.getRencontre('rdd')), + rencontre: await TMRRencontres.getReveDeDragon(force), tmr: true, use: { libre: false, conditions: false }, forceCarac: { 'reve-actuel': { label: "Rêve Actuel", value: this.getReveActuel() } } } - rollData.rencontre.force = force; rollData.competence.system.defaut_carac = 'reve-actuel'; const dialog = await RdDRoll.create(this, rollData, { html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-reve-de-dragon.html', - options: { height: 400 } + options: { height: 'fit-content' } }, { name: 'maitrise', label: 'Maîtriser le Rêve de Dragon', callbacks: [ - this.createCallbackExperience(), - { action: async r => this.resultCombatReveDeDragon(r) } + { action: async r => + this.resultCombatReveDeDragon(r) } ] } ); @@ -784,27 +784,11 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ async resultCombatReveDeDragon(rollData) { - rollData.queues = []; - if (rollData.rolled.isEchec) { - rollData.queues.push(await this.ajouterQueue()); - } - if (rollData.rolled.isETotal) { - rollData.queues.push(await this.ajouterQueue()); - } - if (rollData.rolled.isSuccess) { - await this.updatePointDeSeuil(); - await this.reveActuelIncDec(rollData.rencontre.force); - } - if (rollData.rolled.isPart) { - // TODO: un dialogue pour demander le type de tête? - rollData.tete = true; - } - rollData.poesie = await Poetique.getExtrait(); + const result = rollData.rolled.isSuccess + ? rollData.rencontre.system.succes + : rollData.rencontre.system.echec; - ChatMessage.create({ - whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), - content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-reve-de-dragon.html`, rollData) - }); + RdDRencontre.appliquer(result.effets, {}, rollData) } /* -------------------------------------------- */ @@ -1541,42 +1525,27 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ getTMRRencontres() { - return this.system.reve.rencontre.list; + return this.itemTypes['rencontre']; } /* -------------------------------------------- */ async deleteTMRRencontreAtPosition() { - let rencontres = this.getTMRRencontres(); - let newRencontres = rencontres.filter(it => it.coord != this.getDemiReve()); - if (newRencontres.length != rencontres.length) { - await this.update({ "system.reve.rencontre.list": newRencontres }); + const demiReve = this.getDemiReve() + let rencontreIds = this.items.filter(it => it.type == 'rencontre' && it.system.coord == demiReve).map(it => it.id); + if (rencontreIds.length>0) { + await this.deleteEmbeddedDocuments('Item', rencontreIds); } } /* -------------------------------------------- */ async addTMRRencontre(currentRencontre) { - let rencontres = this.getTMRRencontres(); - let newRencontres = rencontres.filter(it => it.coord != this.getDemiReve()); - if (newRencontres.length == rencontres.length) { - newRencontres.push(currentRencontre); - await this.update({ "system.reve.rencontre.list": newRencontres }); - } - } - - /* -------------------------------------------- */ - async deleteTMRRencontre(rencontreKey) { - let list = duplicate(this.system.reve.rencontre.list); - let newList = []; - for (let i = 0; i < list.length; i++) { - if (i != rencontreKey) - newList.push(list[i]); - } - await this.update({ "system.reve.rencontre.list": newList }); + const toCreate = currentRencontre.toObject(); + console.log('actor.addTMRRencontre(', toCreate,')'); + this.createEmbeddedDocuments('Item', [toCreate]); } /* -------------------------------------------- */ async updateCoordTMR(coord) { - //console.log("UPDATE TMR", coord); await this.update({ "system.reve.tmrpos.coord": coord }); } @@ -2383,7 +2352,7 @@ export class RdDActor extends Actor { } /* -------------------------------------------- */ - isRencontreSpeciale() { // Gestion queue/souffle 'Mauvaise Rencontre en Perpective' + isMauvaiseRencontre() { // Gestion queue/souffle 'Mauvaise Rencontre en Perpective' let addMsg = ""; let rencSpecial = EffetsDraconiques.mauvaiseRencontre(this); if (rencSpecial) { @@ -3825,7 +3794,7 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ _buildActorLinksList(links, actorTransformation = it => RdDActor._buildActorData(it)) { return links.map(link => game.actors.get(link.id)) - .filter(it => it != null) + .filter(it => it != undefined) .map(actorTransformation); } diff --git a/module/effets-rencontres.js b/module/effets-rencontres.js new file mode 100644 index 00000000..a0697d74 --- /dev/null +++ b/module/effets-rencontres.js @@ -0,0 +1,111 @@ +import { ChatUtility } from "./chat-utility.js"; +import { Poetique } from "./poetique.js"; +import { RdDDice } from "./rdd-dice.js"; +import { TMRUtility } from "./tmr-utility.js"; + +export class EffetsRencontre { + + static messager = async (dialog, context) => { + dialog.setRencontreState('messager', TMRUtility.getTMRPortee(context.tmr.coord, context.rencontre.system.force)); + } + + static passeur = async (dialog, context) => { + dialog.setRencontreState('passeur', TMRUtility.getTMRPortee(context.tmr.coord, context.rencontre.system.force)); + } + + static teleportation_typecase = async (dialog, context) => { + dialog.setRencontreState('changeur', TMRUtility.getCasesType(context.tmr.type)); + } + + static rencontre_persistante = async (dialog, context) => { + dialog.setRencontreState('persistant', []); + } + + static reve_plus_f = async (dialog, context) => { await EffetsRencontre.$reve_plus(context.actor, context.rencontre.system.force) } + static reve_plus_1 = async (dialog, context) => { await EffetsRencontre.$reve_plus(context.actor, 1) } + static reve_moins_f = async (dialog, context) => { await EffetsRencontre.$reve_plus(context.actor, -context.rencontre.system.force) } + static reve_moins_1 = async (dialog, context) => { await EffetsRencontre.$reve_plus(context.actor, -1) } + + static vie_moins_1 = async (dialog, context) => { await EffetsRencontre.$vie_plus(context.actor, -1) } + + + static reinsertion = async (dialog, context) => { + await EffetsRencontre.$reinsertion(dialog, context.actor, it => true) + } + + static teleportation_aleatoire_typecase = async (dialog, context) => { + await EffetsRencontre.$reinsertion(dialog, context.actor, it => it.type == context.tmr.type && it.coord != context.tmr.coord) + } + + static demireve_rompu = async (dialog, context) => { + dialog.close() + } + + static sort_aleatoire = async (dialog, context) => { + context.sortReserve = await RdDDice.rollOneOf(context.actor.itemTypes['sortreserve']); + if (context.sortReserve) { + context.newTMR = TMRUtility.getTMR(context.sortReserve.system.coord); + await dialog.positionnerDemiReve(context.newTMR.coord); + await dialog.processSortReserve(context.sortReserve); + dialog.close(); + } + else { + await EffetsRencontre.$reinsertion(dialog, context.actor, it => true); + } + } + + static deplacement_aleatoire = async (dialog, context) => { + const oldCoord = context.actor.system.reve.tmrpos.coord; + const newTmr = await TMRUtility.deplaceTMRAleatoire(context.actor, oldCoord); + await dialog.positionnerDemiReve(newTmr.coord) + } + + static rdd_part_tete = async (dialog, context) => { + mergeObject(context, { + tete: context.rolled.isPart, + poesie: await Poetique.getExtrait() + }) + ChatMessage.create({ + whisper: ChatUtility.getWhisperRecipientsAndGMs(context.actor.name), + content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-reve-de-dragon.html`, context) + }); + } + + static rdd_echec_queue = async (dialog, context) => { + mergeObject(context, { + queues: [await context.actor.ajouterQueue()], + poesie: await Poetique.getExtrait() + }) + if (context.rolled.isETotal) { + context.queues.push(await context.actor.ajouterQueue()); + } + + ChatMessage.create({ + whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), + content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-reve-de-dragon.html`, context) + }); + } + + static experience_particuliere = async (dialog, context) => { + await context.actor.appliquerAjoutExperience(context) + } + + static regain_seuil = async (dialog, context) => { + await context.actor.regainPointDeSeuil() + } + + static $reve_plus = async (actor, valeur) => { + await actor.reveActuelIncDec(valeur); + } + + static $vie_plus = async (actor, valeur) => { + await actor.santeIncDec("vie", valeur); + } + + static async $reinsertion(dialog, actor, filter) { + const newTMR = await TMRUtility.getTMRAleatoire(filter); + await actor.forcerPositionTMRInconnue(newTMR); + await dialog.positionnerDemiReve(newTMR.coord); + } + +} diff --git a/module/item-rencontre-sheet.js b/module/item-rencontre-sheet.js index 46b2b54b..baaf5d8d 100644 --- a/module/item-rencontre-sheet.js +++ b/module/item-rencontre-sheet.js @@ -1,4 +1,3 @@ -import { SYSTEM_RDD } from "./constants.js"; import { RdDRencontre } from "./item-rencontre.js"; /** diff --git a/module/item-rencontre.js b/module/item-rencontre.js index 66454b34..0b07ddf7 100644 --- a/module/item-rencontre.js +++ b/module/item-rencontre.js @@ -1,52 +1,38 @@ -import { RdDRollTables } from "./rdd-rolltables.js"; +import { EffetsRencontre } from "./effets-rencontres.js"; const tableEffets = [ - { code: "messager", resultat: "succes", description: "Envoie un message à (force) cases" }, - { code: "passeur", resultat: "succes", description: "Déplacer le demi-rêve à (force) cases" }, - { code: "reve+f", resultat: "succes", description: "Gain de (force) points de rêve" }, - { code: "teleport", resultat: "succes", description: "Déplacer le demi-rêve (même type de case)" }, - { code: "part+tete", resultat: "succes", description: "Tête de dragon sur réussite particulière" }, - { code: "part+xp", resultat: "succes", description: "Expérience sur réussite particulière" }, + { code: "messager", resultat: "succes", description: "Envoie un message à (force) cases", method: EffetsRencontre.messager }, + { code: "passeur", resultat: "succes", description: "Déplacer le demi-rêve à (force) cases", method: EffetsRencontre.passeur}, + { code: "reve+f", resultat: "succes", description: "Gain de (force) points de rêve" , method: EffetsRencontre.reve_plus_f}, + { code: "teleport", resultat: "succes", description: "Déplacer le demi-rêve (même type)", method: EffetsRencontre.teleportation_typecase }, + { code: "part+tete", resultat: "succes", description: "Tête de dragon sur réussite particulière", method: EffetsRencontre.rdd_part_tete }, + { code: "part+xp", resultat: "succes", description: "Expérience sur réussite particulière", method: EffetsRencontre.experience_particuliere }, + { code: "seuil", resultat: "succes", description: "Récupération de seuil de rêve", method: EffetsRencontre.regain_seuil }, - { code: "reve-1", resultat: "echec", description: "Perte de 1 point de rêve" }, - { code: "reve-f", resultat: "echec", description: "Perte de (force) points de rêve" }, - { code: "vie-1", resultat: "echec", description: "Perte de 1 point de vie" }, - { code: "reinsere", resultat: "echec", description: "Réinsertion aléatoire" }, - { code: "declenhe", resultat: "echec", description: "Déclenche un sort aléatoire" }, - { code: "persistant", resultat: "echec", description: "Bloque le demi-rêve" }, - { code: "teleport-aleatoire", resultat: "echec", description: "Déplacement aléatoire (même type de case)" }, - { code: "aleatoire", resultat: "echec", description: "Déplacement aléatoire" }, - { code: "sort-aleatoire", resultat: "echec", description: "Déplacement pour déclencher un sort en réserve aléatoire" }, - { code: "rompu", resultat: "echec", description: "Demi-rêve interrompu" }, - { code: "echec-queue", resultat: "echec", description: "Queue de dragon sur échec" }, - { code: "etotal-queue", resultat: "echec", description: "Queue de dragon sur échec total" }, - - { code: "moral+1", resultat: "succes", description: "Gain de 1 point de moral" }, - { code: "reve+1", resultat: "succes", description: "Gain de 1 point de rêve" }, - { code: "vie-f", resultat: "echec", description: "Perte de (force) point de vie" }, - { code: "endurance-1", resultat: "echec", description: "Perte de 1 point d'endurance" }, - { code: "endurance-f", resultat: "echec", description: "Perte de (force) point d'endurance" }, - { code: "fatigue-1", resultat: "echec", description: "Perte de 1 point de fatigue" }, - { code: "fatigue-f", resultat: "echec", description: "Perte de (force) point de fatigue" }, - { code: "moral-1", resultat: "echec", description: "Perte de 1 point de moral" }, - { code: "chance-1", resultat: "echec", description: "Perte de 1 point de chance actuelle" }, - { code: "chance-f", resultat: "echec", description: "Perte de (force) point de chance" }, - { code: "epart-queue", resultat: "echec", description: "Queue de dragon sur échec particulier" }, - { code: "etotal-souffle", resultat: "echec", description: "Souffle de dragon sur échec total" }, - { code: "epart-souffle", resultat: "echec", description: "Souffle de dragon sur échec particulier" }, + { code: "reve-1", resultat: "echec", description: "Perte de 1 point de rêve", method: EffetsRencontre.reve_moins_1 }, + { code: "reve-f", resultat: "echec", description: "Perte de (force) points de rêve", method: EffetsRencontre.reve_moins_f }, + { code: "vie-1", resultat: "echec", description: "Perte de 1 point de vie", method: EffetsRencontre.vie_moins_1 }, + { code: "reinsere", resultat: "echec", description: "Réinsertion aléatoire", method: EffetsRencontre.reinsertion }, + { code: "persistant", resultat: "echec", description: "Bloque le demi-rêve", method: EffetsRencontre.rencontre_persistante }, + { code: "teleport-aleatoire", resultat: "echec", description: "Déplacement aléatoire (même type)", method: EffetsRencontre.teleportation_aleatoire_typecase }, + { code: "aleatoire", resultat: "echec", description: "Déplacement aléatoire", method: EffetsRencontre.deplacement_aleatoire }, + { code: "sort-aleatoire", resultat: "echec", description: "Déclenche un sort en réserve aléatoire", method: EffetsRencontre.sort_aleatoire }, + { code: "rompu", resultat: "echec", description: "Demi-rêve interrompu", method: EffetsRencontre.demireve_rompu }, + { code: "echec-queue", resultat: "echec", description: "Queue(s) de dragon sur échec", method: EffetsRencontre.rdd_echec_queue }, ]; export class RdDRencontre { + + static getEffetsSucces() { return RdDRencontre.getEffets("succes"); } + static getEffetsEchec() { return RdDRencontre.getEffets("echec"); } static getEffets(resultat) { return tableEffets.filter(e => resultat == e.resultat); } - static getEffetsSucces() { return RdDRencontre.getEffets("succes"); } - static getEffetsEchec() { return RdDRencontre.getEffets("echec"); } - + static mapEffets(liste) { - return liste.map(it => tableEffets.find(e => it == e.code)); + return liste.map(it => RdDRencontre.getEffet(it)); } - + static getListeEffets(item, reussite) { if (reussite == 'echec') { return [...item.system.echec.effets]; @@ -57,4 +43,14 @@ export class RdDRencontre { return []; } + static getEffet(code) { + return tableEffets.find(it => code == it.code) + } + + static async appliquer(codes, tmrDialog, rencData) { + for(const effet of RdDRencontre.mapEffets(codes)){ + await effet.method(tmrDialog, rencData); + } + } + } diff --git a/module/migrations.js b/module/migrations.js index 9e3fd2f2..f04c9e43 100644 --- a/module/migrations.js +++ b/module/migrations.js @@ -43,7 +43,7 @@ class _10_0_16_MigrationSortsReserve extends Migration { await actor.createEmbeddedDocuments("Item", sortsReserve, { renderSheet: false, }); - await actor.update({ 'system.reve.reserve.list': [] }) + await actor.update({ 'system.reve.reserve': undefined }) }); } diff --git a/module/rdd-calendrier.js b/module/rdd-calendrier.js index 05459e94..b5221454 100644 --- a/module/rdd-calendrier.js +++ b/module/rdd-calendrier.js @@ -86,14 +86,14 @@ export class RdDCalendrier extends Application { getCalendrier(index) { index = index ?? this.getCurrentDayIndex(); - const moisRdD = Math.floor(index / RDD_JOUR_PAR_MOIS) % RDD_MOIS_PAR_AN; + const mois = Math.floor(index / RDD_JOUR_PAR_MOIS) % RDD_MOIS_PAR_AN; return { heureRdD: 0, // Index dans heuresList / heuresDef[x].heure minutesRelative: 0, indexJour: index, annee: Math.floor(index / (RDD_JOUR_PAR_MOIS * RDD_MOIS_PAR_AN)), - moisRdD: RdDCalendrier.getDefSigne(moisRdD), - moisLabel: RdDCalendrier.getDefSigne(moisRdD).label, + moisRdD: RdDCalendrier.getDefSigne(mois), + moisLabel: RdDCalendrier.getDefSigne(mois).label, jour: (index % RDD_JOUR_PAR_MOIS) // Le calendrier stocke le jour en 0-27, mais en 1-28 à l'affichage } } @@ -138,7 +138,7 @@ export class RdDCalendrier extends Application { /* -------------------------------------------- */ getDateFromIndex(index) { const dateRdD = this.getCalendrier(index); - return (dateRdD.jour + 1) + ' ' + RdDCalendrier.getDefSigne(dateRdD.moisRdD).label; + return (dateRdD.jour + 1) + ' ' + dateRdD.moisLabel; } /* -------------------------------------------- */ diff --git a/module/rdd-main.js b/module/rdd-main.js index 81a80311..86a15f4d 100644 --- a/module/rdd-main.js +++ b/module/rdd-main.js @@ -221,7 +221,6 @@ Hooks.once("init", async function () { RddCompendiumOrganiser.init(); EffetsDraconiques.init() TMRUtility.init(); - TMRRencontres.init(); RdDHotbar.initDropbar(); RdDPossession.init(); }); diff --git a/module/rdd-tmr-dialog.js b/module/rdd-tmr-dialog.js index 893cabbb..80d129be 100644 --- a/module/rdd-tmr-dialog.js +++ b/module/rdd-tmr-dialog.js @@ -1,3 +1,4 @@ +import { SHOW_DICE } from "./constants.js"; import { RollDataAjustements } from "./rolldata-ajustements.js"; import { RdDUtility } from "./rdd-utility.js"; import { TMRUtility } from "./tmr-utility.js"; @@ -11,11 +12,12 @@ 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 { Misc } from "./misc.js"; import { HtmlUtility } from "./html-utility.js"; import { ReglesOptionelles } from "./settings/regles-optionelles.js"; import { RdDDice } from "./rdd-dice.js"; import { STATUSES } from "./settings/status-effects.js"; +import { RdDRencontre } from "./item-rencontre.js"; + /* -------------------------------------------- */ export class RdDTMRDialog extends Dialog { @@ -89,7 +91,7 @@ export class RdDTMRDialog extends Dialog { TMRUtility.getTMR(coord).type == 'fleuve' ? it => TMRUtility.getTMR(it.system.coord).type == 'fleuve' : it => it.system.coord == coord - ); + ); } /* -------------------------------------------- */ @@ -146,7 +148,7 @@ export class RdDTMRDialog extends Dialog { /* -------------------------------------------- */ _tokenRencontre(rencontre) { - return EffetsDraconiques.rencontre.token(this.pixiTMR, rencontre, () => rencontre.coord); + return EffetsDraconiques.rencontre.token(this.pixiTMR, rencontre, () => rencontre.system.coord); } _tokenCaseSpeciale(casetmr) { const caseData = casetmr; @@ -248,7 +250,7 @@ export class RdDTMRDialog extends Dialog { let tmrpos = document.getElementById("tmr-pos"); if (this.isDemiReveCache()) { - tmrpos.innerHTML = `?? ( ${ TMRUtility.getTMRType(coord)})`; + tmrpos.innerHTML = `?? ( ${TMRUtility.getTMRType(coord)})`; } else { tmrpos.innerHTML = `${coord} ( ${TMRUtility.getTMRLabel(coord)})`; } @@ -280,25 +282,44 @@ export class RdDTMRDialog extends Dialog { } /* -------------------------------------------- */ + async onActionRencontre(action, tmr) { + switch (action) { + case 'derober': + await this.derober(); + return; + case 'refouler': + await this.refouler(); + break; + case 'maitriser': + await this.maitriserRencontre(); + break; + case 'ignorer': + await this.ignorerRencontre(); + break; + } + await this.postRencontre(tmr); + } + async derober() { - await this.actor.addTMRRencontre(this.currentRencontre); console.log("-> derober", this.currentRencontre); + await this.actor.addTMRRencontre(this.currentRencontre); this._tellToGM(this.actor.name + " s'est dérobé et quitte les TMR."); this.close(); } /* -------------------------------------------- */ async refouler() { - await this.actor.ajouterRefoulement(this.currentRencontre.refoulement ?? 1, `une rencontre ${this.currentRencontre.name}`); + 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 this.updateTokens(); - console.log("-> refouler", this.currentRencontre) this.updateValuesDisplay(); this.nettoyerRencontre(); } /* -------------------------------------------- */ 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 this.updateTokens(); @@ -307,7 +328,14 @@ export class RdDTMRDialog extends Dialog { } /* -------------------------------------------- */ - colorierZoneRencontre(listCoordTMR) { + // garder la trace de l'état en cours + setRencontreState(state, listCoordTMR) { + this.rencontreState = state; + this.$marquerCasesTMR(listCoordTMR ?? []); + } + + /* -------------------------------------------- */ + $marquerCasesTMR(listCoordTMR) { this.currentRencontre.graphics = []; // Keep track of rectangles to delete it this.currentRencontre.locList = duplicate(listCoordTMR); // And track of allowed location for (let coordTMR of listCoordTMR) { @@ -323,23 +351,6 @@ export class RdDTMRDialog extends Dialog { } } - /* -------------------------------------------- */ - // garder la trace de l'état en cours - setStateRencontre(state) { - this.rencontreState = state; - } - - /* -------------------------------------------- */ - async choisirCasePortee(coord, portee) { - // Récupère la liste des cases à portées - this.colorierZoneRencontre(TMRUtility.getTMRPortee(coord, portee)); - } - - /* -------------------------------------------- */ - async choisirCaseType(type) { - this.colorierZoneRencontre(TMRUtility.filterTMR(it => it.type == type).map(it => it.coord)); - } - /* -------------------------------------------- */ checkQuitterTMR() { @@ -370,7 +381,9 @@ export class RdDTMRDialog extends Dialog { /* -------------------------------------------- */ async maitriserRencontre() { - this.actor.deleteTMRRencontreAtPosition(); + console.log("-> maitriser", this.currentRencontre); + + await this.actor.deleteTMRRencontreAtPosition(); this.updateTokens(); let rencontreData = { @@ -381,7 +394,7 @@ export class RdDTMRDialog extends Dialog { rencontre: this.currentRencontre, nbRounds: 1, canClose: false, - selectedCarac: {label: "reve-actuel"}, + selectedCarac: { label: "reve-actuel" }, tmr: TMRUtility.getTMR(this._getActorCoord()) } @@ -390,8 +403,6 @@ export class RdDTMRDialog extends Dialog { /* -------------------------------------------- */ async _tentativeMaitrise(rencData) { - console.log("-> matriser", rencData); - rencData.reve = this.actor.getReveActuel(); rencData.etat = this.actor.getEtatGeneral(); @@ -401,41 +412,67 @@ export class RdDTMRDialog extends Dialog { ? this._rollPresentCite(rencData) : await RdDResolutionTable.roll(rencData.reve, RollDataAjustements.sum(rencData.ajustements)); - let postProcess = await TMRRencontres.gererRencontre(this, rencData); + const result = rencData.rolled.isSuccess + ? rencData.rencontre.system.succes + : rencData.rencontre.system.echec; + + await RdDRencontre.appliquer(result.effets, this, rencData); + + rencData.poesie = { extrait: result.poesie, reference: result.reference }; + rencData.message = this.formatMessageRencontre(rencData, result.message); ChatMessage.create({ whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name), content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-rencontre-tmr.html`, rencData) }); - if (postProcess) { - /** Gère les rencontres avec du post-processing (passeur, messagers, tourbillons, ...) */ - await postProcess(this, rencData); - } - else { - this.currentRencontre = undefined; - } - this.updateValuesDisplay(); if (this.checkQuitterTMR()) { return; } - else if (rencData.rolled.isEchec && rencData.rencontre.isPersistant) { - setTimeout(() => { - rencData.nbRounds++; - if (ReglesOptionelles.isUsing("appliquer-fatigue")) { - this.cumulFatigue += this.fatigueParCase; - } - this._tentativeMaitrise(rencData); - this._deleteTmrMessages(rencData.actor, rencData.nbRounds); - }, 2000); + if (this.rencontreState == 'persistant') { + this._nouvelleTentativeMaitrise(rencData); + } + else if (!this.isRencontreDeplacement()) { + this.nettoyerRencontre(); + } + } + + _nouvelleTentativeMaitrise(rencData) { + setTimeout(() => { + // TODO: remplacer par une boucle while(this.currentRencontre) ? + rencData.nbRounds++; + if (ReglesOptionelles.isUsing("appliquer-fatigue")) { + this.cumulFatigue += this.fatigueParCase; + } + this._tentativeMaitrise(rencData); + this._deleteTmrMessages(rencData.actor, rencData.nbRounds); + }, 2000); + this.rencontreState == 'normal'; + } + + formatMessageRencontre(rencData, template) { + let messageDuree = '' + if (rencData.nbRounds > 1) { + if (rencData.rolled.isSuccess) { + messageDuree = ` Au total, vous avez passé ${rencData.nbRounds} rounds à vous battre!`; + } + else { + messageDuree = ` Vous avez passé ${rencData.nbRounds} rounds à lutter!`; + } + } + try { + const compiled = Handlebars.compile(template); + return compiled(rencData) + messageDuree ; + } catch (error) { + return template + messageDuree ; } } /* -------------------------------------------- */ - _rollPresentCite(rencontreData) { - let rolled = RdDResolutionTable.computeChances(rencontreData.reve, 0); - mergeObject(rolled, { caracValue: rencontreData.reve, finalLevel: 0, roll: rolled.score }); + _rollPresentCite(rencData) { + let rolled = RdDResolutionTable.computeChances(rencData.reve, 0); + mergeObject(rolled, { caracValue: rencData.reve, finalLevel: 0, roll: rolled.score }); RdDResolutionTable.succesRequis(rolled); return rolled; } @@ -479,15 +516,16 @@ export class RdDTMRDialog extends Dialog { if (this._presentCite(tmr)) { return; } - let rencontre = await this._jetDeRencontre(tmr); - - if (rencontre) { // Manages it - if (rencontre.rencontre) rencontre = rencontre.rencontre; // Manage stored rencontres - console.log("manageRencontre", rencontre); - this.currentRencontre = duplicate(rencontre); - - let dialog = new RdDTMRRencontreDialog(this, this.currentRencontre, () => this.postRencontre(tmr)); - dialog.render(true); + this.currentRencontre = await this._jetDeRencontre(tmr); + if (this.currentRencontre) { + if (this.rencontresExistantes.find(it => it.id == this.currentRencontre.id)){ + // rencontre en attente suite à dérobade + await this.maitriserRencontre(); + } + else { + let dialog = new RdDTMRRencontreDialog(this, this.currentRencontre, tmr); + dialog.render(true); + } } else { this.postRencontre(tmr); @@ -500,15 +538,18 @@ export class RdDTMRDialog extends Dialog { if (presentCite) { this.minimize(); const caseData = presentCite; - EffetsDraconiques.presentCites.choisirUnPresent(caseData, (type => this._utiliserPresentCite(presentCite, type, tmr))); + EffetsDraconiques.presentCites.choisirUnPresent(caseData, (present => this._utiliserPresentCite(presentCite, present, tmr))); } return presentCite; } /* -------------------------------------------- */ - async _utiliserPresentCite(presentCite, typeRencontre, tmr) { - this.currentRencontre = TMRRencontres.getRencontre(typeRencontre); - await TMRRencontres.evaluerForceRencontre(this.currentRencontre); + async _utiliserPresentCite(presentCite, present, tmr) { + this.currentRencontre = present.clone({ + 'system.force': await RdDDice.rollTotal(present.system.formule), + 'system.coord': tmr.coord + }, {save: false}); + await EffetsDraconiques.presentCites.ouvrirLePresent(this.actor, presentCite); this.removeToken(tmr, presentCite); @@ -530,32 +571,27 @@ export class RdDTMRDialog extends Dialog { /* -------------------------------------------- */ async _jetDeRencontre(tmr) { - let rencontre = this.rencontresExistantes.find(prev => prev.coord == tmr.coord); + let rencontre = this.lookupRencontreExistente(tmr); if (rencontre) { - return rencontre; + return TMRRencontres.calculRencontre(rencontre, tmr); } let locTMR = (this.isDemiReveCache() - ? Misc.upperFirst(tmr.type) + " ??" + ? TMRUtility.getTMRType(tmr.coord) + " ??" : tmr.label + " (" + tmr.coord + ")"); - let myRoll = await RdDDice.rollTotal("1dt"); - if (TMRUtility.isForceRencontre() || myRoll == 7) { + let myRoll = await RdDDice.rollTotal("1dt", { showDice: SHOW_DICE }); + console.warn('// TODO: remettre myRoll==7'); + if (myRoll <= 7) { this._tellToUser(myRoll + ": Rencontre en " + locTMR); - return await this.rencontreTMRRoll(tmr, this.actor.isRencontreSpeciale()); + return await TMRRencontres.getRencontreAleatoire(tmr, this.actor.isMauvaiseRencontre()) } else { this._tellToUser(myRoll + ": Pas de rencontre en " + locTMR); } } - /* -------------------------------------------- */ - async rencontreTMRRoll(tmr, isMauvaise = false) { - let rencontre = (isMauvaise - ? await TMRRencontres.getMauvaiseRencontre() - : await TMRRencontres.getRencontreAleatoire(tmr)); - rencontre.coord = tmr.coord; - rencontre.date = game.system.rdd.calendrier.getDateFromIndex(); - rencontre.heure = game.system.rdd.calendrier.getCurrentHeure(); - return rencontre; + lookupRencontreExistente(tmr) { + return this.rencontresExistantes.find(it => it.system.coord == tmr.coord) + ?? this.rencontresExistantes.find(it => it.system.coord == ""); } /* -------------------------------------------- */ @@ -583,7 +619,7 @@ export class RdDTMRDialog extends Dialog { maitrise: { verbe: 'maîtriser', action: 'Maîtriser le fleuve' } } rollData.double = EffetsDraconiques.isDoubleResistanceFleuve(this.actor) ? true : undefined, - rollData.competence.system.defaut_carac = 'reve-actuel'; + rollData.competence.system.defaut_carac = 'reve-actuel'; await this._rollMaitriseCaseHumide(rollData); } } @@ -874,16 +910,14 @@ export class RdDTMRDialog extends Dialog { if (this.isDemiReveCache()) { if (this.isTerreAttache(targetCoord) - || this.isConnaissanceFleuve(currentCoord, targetCoord) - || deplacementType == 'changeur') - { + || this.isConnaissanceFleuve(currentCoord, targetCoord) + || deplacementType == 'changeur') { // déplacement possible await this.actor.setTMRVisible(true); this.demiReve = this._tokenDemiReve(); this._trackToken(this.demiReve); } - else - { + else { ui.notifications.error(`Vous ne connaissez plus votre position dans les TMR. Vous devez utiliser les boutons de direction pour vous déplacer. Une fois que vous aurez retrouvé votre demi-rêve, demandez au gardien de vérifier et rendre les TMR visibles. @@ -892,20 +926,18 @@ export class RdDTMRDialog extends Dialog { } } - switch (deplacementType){ + switch (deplacementType) { case 'normal': + case 'changeur': + case 'passeur': await this._deplacerDemiReve(targetCoord, deplacementType); break; case 'messager': await this._messagerDemiReve(targetCoord); break; - case 'changeur': - case 'passeur': - await this._deplacerDemiReve(targetCoord, deplacementType); - break; default: - ui.notifications.error("Vous ne pouvez pas vous déplacer que sur des cases adjacentes à votre position ou valides dans le cas d'une rencontre"); - console.log("STATUS :", this.rencontreState, this.currentRencontre); + ui.notifications.error("Vous ne pouvez pas vous déplacer que sur des cases adjacentes à votre position ou valides dans le cas d'une rencontre"); + console.log("STATUS :", this.rencontreState, this.currentRencontre); } this.checkQuitterTMR(); @@ -913,19 +945,23 @@ export class RdDTMRDialog extends Dialog { /* -------------------------------------------- */ _calculDeplacement(targetCoord, currentCoord, fromOddq, toOddq) { - - const isInArea = this.rencontreState == 'aucune' - ? (this.isTerreAttache(targetCoord) || this.isConnaissanceFleuve(currentCoord, targetCoord) || TMRUtility.distanceOddq(fromOddq, toOddq) <= 1) - : this.currentRencontre?.locList?.find(coord => coord == targetCoord) ?? false - if (isInArea) { - switch (this.rencontreState) { - case 'aucune': return 'normal'; - case 'passeur': case 'changeur': case 'messager': return this.rencontreState; + if (this.isRencontreDeplacement()) { + if (this.currentRencontre?.locList?.find(coord => coord == targetCoord)) { + return this.rencontreState; + } + } + else { + if (this.isTerreAttache(targetCoord) || this.isConnaissanceFleuve(currentCoord, targetCoord) || TMRUtility.distanceOddq(fromOddq, toOddq) <= 1) { + return 'normal' } } return 'erreur'; } + isRencontreDeplacement() { + return ['passeur', 'changeur', 'messager'].includes(this.rencontreState); + } + /* -------------------------------------------- */ async _messagerDemiReve(targetCoord) { /* diff --git a/module/rdd-tmr-rencontre-dialog.js b/module/rdd-tmr-rencontre-dialog.js index ac21f161..72c65558 100644 --- a/module/rdd-tmr-rencontre-dialog.js +++ b/module/rdd-tmr-rencontre-dialog.js @@ -2,20 +2,22 @@ export class RdDTMRRencontreDialog extends Dialog { /* -------------------------------------------- */ - constructor(tmrApp, rencontre, postRencontre) { + constructor(tmrApp, rencontre, tmr) { const dialogConf = { title: "Rencontre en TMR!", - content: "Vous rencontrez un " + rencontre.name + " de force " + rencontre.force + "
", + content: "Vous rencontrez un " + rencontre.name + " de force " + rencontre.system.force + "
", buttons: { - derober: { icon: '', label: "Se dérober", callback: () => { this.onButtonFuir(() => tmrApp.derober()); } }, - refouler: { icon: '', label: "Refouler", callback: () => this.onButtonAction(() => tmrApp.refouler()) }, - maitiser: { icon: '', label: "Maîtriser", callback: () => this.onButtonAction(() => tmrApp.maitriserRencontre()) } + derober: { icon: '', label: "Se dérober", callback: () => this.onButtonAction('derober') }, + maitiser: { icon: '', label: "Maîtriser", callback: () => this.onButtonAction('maitriser') } }, default: "derober" - }; - if (rencontre.ignorer) { - dialogConf.buttons.ignorer = { icon: '', label: "Ignorer", callback: () => this.onButtonAction(() => tmrApp.ignorerRencontre()) } - }; + } + if ((rencontre.system.refoulement ?? 0) == 0) { + dialogConf.buttons.ignorer = { icon: '', label: "Ignorer", callback: () => this.onButtonAction('ignorer') } + } + else { + dialogConf.buttons.refouler = { icon: '', label: "Refouler", callback: () => this.onButtonAction('refouler') } + } const dialogOptions = { classes: ["tmrrencdialog"], @@ -25,23 +27,16 @@ export class RdDTMRRencontreDialog extends Dialog { super(dialogConf, dialogOptions); this.toClose = false; - this.rencontreData = duplicate(rencontre); - this.postRencontre = postRencontre; + this.tmr = tmr; this.tmrApp = tmrApp; this.tmrApp.minimize(); } async onButtonAction(action) { this.toClose = true; - await action(); - this.postRencontre(); + this.tmrApp.onActionRencontre(action, this.tmr) } - async onButtonFuir(action) { - this.toClose = true; - await action(); - } - /* -------------------------------------------- */ close() { if (this.toClose) { diff --git a/module/rolldata-ajustements.js b/module/rolldata-ajustements.js index 7ba8b0b5..2807065a 100644 --- a/module/rolldata-ajustements.js +++ b/module/rolldata-ajustements.js @@ -120,7 +120,7 @@ export const referenceAjustements = { isVisible: (rollData, actor) => rollData.tmr && rollData.rencontre?.name, isUsed: (rollData, actor) => rollData.tmr && rollData.rencontre?.name, getLabel: (rollData, actor) => rollData.rencontre?.name, - getValue: (rollData, actor) => - (rollData.rencontre?.force ?? 0) + getValue: (rollData, actor) => - (rollData.rencontre?.system.force ?? 0) }, ethylismeAlcool: { isVisible: (rollData, actor) => rollData.nbDoses != undefined, diff --git a/module/settings/system-compendiums.js b/module/settings/system-compendiums.js index 17474e3d..21bdbe9d 100644 --- a/module/settings/system-compendiums.js +++ b/module/settings/system-compendiums.js @@ -48,8 +48,7 @@ export class SystemCompendiums extends FormApplication { static async getContent(compendium, docType) { const pack = SystemCompendiums.getPack(compendium); - if (pack.metadata.type == docType) - { + if (pack.metadata.type == docType) { return await pack.getDocuments(); } return []; @@ -59,6 +58,14 @@ export class SystemCompendiums extends FormApplication { return await SystemCompendiums.getContent(compendium, 'Item') } + static async getDefaultItems(compendium) { + const pack = game.packs.get(SystemCompendiums._getDefaultCompendium(compendium)); + if (pack.metadata.type == 'Item') { + return await pack.getDocuments(); + } + return []; + } + static getCompendium(compendium) { const setting = CONFIGURABLE_COMPENDIUMS[compendium]?.setting; return setting ? game.settings.get(SYSTEM_RDD, setting) : SystemCompendiums._getDefaultCompendium(compendium); diff --git a/module/tmr-rencontres.js b/module/tmr-rencontres.js index d8634310..14f94dc2 100644 --- a/module/tmr-rencontres.js +++ b/module/tmr-rencontres.js @@ -1,335 +1,22 @@ import { Grammar } from "./grammar.js"; +import { Misc } from "./misc.js"; import { RdDDice } from "./rdd-dice.js"; +import { SystemCompendiums } from "./settings/system-compendiums.js"; import { TMRUtility } from "./tmr-utility.js"; -import { TMRType } from "./tmr-utility.js"; - -/* -------------------------------------------- */ -const typeRencontres = { - - messager: { - msgSucces: async (rencData) => { - if (rencData.actor.isTMRCache()){ - return `Le ${rencData.rencontre.name} vous propose d'emmener le message de votre un sort, mais vous ne savez pas où vous êtes.`; - } - return `Le ${rencData.rencontre.name} vous propose d'emmener le message de votre un sort à ${rencData.rencontre.force} cases de ${rencData.tmr.label}.`; - }, - msgEchec: async (rencData)=> `Le ${rencData.rencontre.name} est pressé et continue son chemin d'une traite sans vous accorder un regard.`, - postSucces: async (tmrDialog, rencData) => { - tmrDialog.setStateRencontre(rencData.rencontre.type); - tmrDialog.choisirCasePortee(rencData.tmr.coord, rencData.rencontre.force); - }, - poesieSucces: { - reference: "La chevelure, Charles Baudelaire", - extrait: `J'irai là-bas où l'arbre et l'homme, pleins de sève, -
Se pâment longuement sous l'ardeur des climats ; -
Fortes tresses, soyez la houle qui m'enlève !` - }, - poesieEchec: { - reference: "Rêve de Dragon, Denis Gerfaud", - extrait: `En réalité, tous les éléments du rêve des Dragons expriment - le Draconic : chaque pierre, chaque fleur, chaque goutte d'eau, - chaque nuage est porteur d'un message dans la langue des Dragons`} - }, - - passeur: { - msgSucces: async (rencData) => { - if (rencData.actor.isTMRCache()){ - return `Le ${rencData.rencontre.name} vous propose de vous transporter, mais vous ne savez pas où vous êtes.`; - } - return `Le ${rencData.rencontre.name} vous propose de vous transporter à ${rencData.rencontre.force} cases des ${rencData.tmr.label}.`; - }, - msgEchec: async (rencData)=> `Le prix que demande le ${rencData.rencontre.name} est trop élevé, vous êtes réduit à poursuivre votre chemin par vos propres moyens.`, - postSucces: async (tmrDialog, rencData) => { - tmrDialog.setStateRencontre(rencData.rencontre.type); - tmrDialog.choisirCasePortee(rencData.tmr.coord, rencData.rencontre.force); - }, - poesieSucces: { - reference: "Le bateau ivre, Arthur Rimbaud", - extrait: `Comme je descendais des Fleuves impassibles, -
Je ne me sentis plus guidé par les haleurs : -
Des Peaux-Rouges criards les avaient pris pour cibles, -
Les ayant cloués nus aux poteaux de couleurs.`}, - poesieEchec: { - reference: "Femmes damnées (2), Charles Baudelaire", - extrait: `Loin des peuples vivants, errantes, condamnées, -
A travers les déserts courez comme les loups ; -
Faites votre destin, âmes désordonnées, -
Et fuyez l'infini que vous portez en vous !`} - }, - - fleur: { - msgSucces: async (rencData) => `Vous cueillez la ${rencData.rencontre.name}, son parfum vous apporte ${rencData.rencontre.force} points de Rêve.`, - msgEchec: async (rencData)=> `La ${rencData.rencontre.name} se fâne et disparaît entre vos doigts.`, - postSucces: async (tmrDialog, rencData) => tmrDialog.actor.reveActuelIncDec(rencData.rencontre.force), - poesieSucces: { - reference: "L'Ennemi, Charles Baudelaire", - extrait: `Et qui sait si les fleurs nouvelles que je rêve -
Trouveront dans ce sol lavé comme une grève -
Le mystique aliment qui ferait leur vigueur ?`}, - poesieEchec: { - reference: "Une charogne, Charles Baudelaire", - extrait: `Et le ciel regardait la carcasse superbe -
Comme une fleur s'épanouir. -
La puanteur était si forte, que sur l'herbe -
Vous crûtes vous évanouir.`}, - }, - - mangeur: { - msgSucces: async (rencData) => `Le ${rencData.rencontre.name} claque de sa machoire dans le vide avant de fuir.`, - msgEchec: async (rencData)=> `Le ${rencData.rencontre.name} croque votre Rêve ! Il emporte ${rencData.rencontre.force} de vos points de rêve actuels`, - postEchec: async (tmrDialog, rencData) => tmrDialog.actor.reveActuelIncDec(-rencData.rencontre.force), - poesieSucces: { - reference: "Conseil, Victor Hugo", - extrait: `Rois ! la bure est souvent jalouse du velours. -
Le peuple a froid l'hiver, le peuple a faim toujours. -
Rendez-lui son sort plus facile. -
Le peuple souvent porte un bien rude collier. -
Ouvrez l'école aux fils, aux pères l'atelier, -
À tous vos bras, auguste asile !`}, - poesieEchec: { - reference: "El Desdichado, Gérard de Nerval", - extrait: `Suis-je Amour ou Phébus ?... Lusignan ou Biron ? -
Mon front est rouge encor du baiser de la Reine ; -
J'ai rêvé dans la Grotte où nage la sirène...`} - }, - - changeur: { - msgSucces: async (rencData) => `Le ${rencData.rencontre.name} vaincu accepte de vous déplacer sur une autre ${TMRType[rencData.tmr.type].name} de votre choix en échange de sa liberté.`, - msgEchec: async (rencData) => `Le ${rencData.rencontre.name} vous embobine avec des promesses, et vous transporte sur une autre ${TMRType[rencData.tmr.type].name} sans attendre votre avis.`, - postSucces: async (tmrDialog, rencData) => { - tmrDialog.setStateRencontre(rencData.rencontre.type); - tmrDialog.choisirCaseType(rencData.tmr.type); - }, - postEchec: async (tmrDialog, rencData) => { - const newTMR = await TMRUtility.getTMRAleatoire(it => it.type == rencData.tmr.type && it.coord != rencData.tmr.coord); - await tmrDialog.actor.forcerPositionTMRInconnue(newTMR); - tmrDialog.positionnerDemiReve(newTMR.coord); - }, - poesieSucces: { - reference: "Caligula - IIIème chant, Gérard de Nerval", - extrait: `Allez, que le caprice emporte -
Chaque âme selon son désir, -
Et que, close après vous, la porte -
Ne se rouvre plus qu'au plaisir.`}, - poesieEchec: { - reference: "Rêve de Dragon, Denis Gerfaud", - extrait: `Les sages ont encore coutume de dire : -
« Mais comment les Dragons peuvent-ils - être influencés par une créature qui, tout - bien considéré, n'existe pas vraiment pour eux, - qui n'est que le fantasme de leur activité nocturne ? »`} - }, - - briseur: { - msgSucces: async (rencData) => `Le ${rencData.rencontre.name} tente vainement de vous déconcentrer, avant de fuir sans demander son reste.`, - msgEchec: async (rencData)=> `Le ${rencData.rencontre.name} vous déconcentre au point de briser votre demi-rêve.`, - postEchec: async (tmrDialog, rencData) => tmrDialog.close(), - poesieSucces: { - reference: "Rêve de Dragon, Denis Gerfaud", - extrait: `La légende affirme que ce sont les Gnomes qui furent - les premiers haut-rêvants. En observant les pierres précieuses, - les gemmes qui sont les larmes de joie des Dragons, ils parvinrent à - en comprendre la langue. Et l'ayant comprise, ils purent s'en servir - pour influencer le cours du rêve`}, - poesieEchec: { - reference: "Quand le rêve se brise, Cypora Sebagh", - extrait: `Quand le rêve se brise, -
Dans la plainte du jour, -
Ma mémoire devient grise -
Et sombre, tour à tour, -
Dans le puits du silence -
Et de la solitude ; -
Elle reprend son errance -
Parmi la multitude.`} - }, - - reflet: { - msgSucces: async (rencData) => `Le ${rencData.rencontre.name} s'estompe dans l'oubli.`, - msgEchec: async (rencData)=> `Vous êtes submergé par un ${rencData.rencontre.name}, les souvenirs vous retiennent tant qu'il ne sera pas vaincu!`, - poesieSucces: { - reference: "Une charogne, Charles Baudelaire", - extrait: `Les formes s'effaçaient et n'étaient plus qu'un rêve, -
Une ébauche lente à venir -
Sur la toile oubliée, et que l'artiste achève -
Seulement par le souvenir.`}, - poesieEchec: { - reference: "La chevelure, Charles Baudelaire", - extrait: `Longtemps ! toujours ! ma main dans ta crinière lourde -
Sèmera le rubis, la perle et le saphir, -
Afin qu'à mon désir tu ne sois jamais sourde ! -
N'es-tu pas l'oasis où je rêve, et la gourde -
Où je hume à longs traits le vin du souvenir`} - }, - - passeurfou: { - msgSucces: async (rencData) => `Le ${rencData.rencontre.name} tente vainement de découvrir où vous avez caché vos réserves. Vous le chassez, et en déroute il part harceler un autre voyageur du rêve.`, - msgEchec: async (rencData)=> TMRRencontres.msgEchecPasseurFou(rencData), - postEchec: async (tmrDialog, rencData) => TMRRencontres.postEchecPasseurFou(tmrDialog, rencData), - poesieSucces: { - reference: "Un Fou et un Sage, Jean de La Fontaine", - extrait: `Certain Fou poursuivait à coups de pierre un Sage. -
Le Sage se retourne et lui dit : Mon ami, -
C'est fort bien fait à toi ; reçois cet écu-ci : -
Tu fatigues assez pour gagner davantage.`}, - poesieEchec: { - reference: "Guitare, Victor Hugo", - extrait: `Je la voyais passer de ma demeure, -
Et c'était tout. -
Mais à présent je m'ennuie à toute heure, -
Plein de dégoût, -
Rêveur oisif, l'âme dans la campagne, -
La dague au clou ... – -
Le vent qui vient à travers la montagne -
M'a rendu fou !`} - }, - - tbblanc: { - msgSucces: async (rencData) => `Le ${rencData.rencontre.name} souleve une poussière blanche, vous tenez bon, et il tourbillonne en s'éloignant.`, - msgEchec: async (rencData)=> `Le souffle du ${rencData.rencontre.name} vous déstabilise et vous emmène dans un nuage de poussière.`, - postEchec: async (tmrDialog, rencData) => TMRRencontres.onPostEchecTourbillon(tmrDialog, rencData, 1), - poesieSucces: { - reference: "Rêve de Dragon, Denis Gerfaud", - extrait: `Le Premier Âge fut appelé l'Âge des Dragons. Ce fut le commencement - des temps, le commencement des rêves. Durant cette période plus mythique - que réellement historique, les Dragons aimaient à se rêver eux-mêmes.`}, - poesieEchec: { - reference: "Les Djinns, Victor Hugo", - extrait: `C'est l'essaim des Djinns qui passe, -
Et tourbillonne en sifflant ! -
Les ifs, que leur vol fracasse, -
Craquent comme un pin brûlant.`}, - }, - - tbnoir: { - msgSucces: async (rencData) => `Le ${rencData.rencontre.name} orageux vous enveloppe de fureur et d'éclairs, vous tenez bon face à la tempête qui s'éloigne sans vous éloigner de votre chemin.`, - msgEchec: async (rencData)=> `Le ${rencData.rencontre.name} furieux vous secoue tel un fichu de paille malmené par les vents, et vous emporte dans la tourmente.`, - postEchec: async (tmrDialog, rencData) => TMRRencontres.onPostEchecTourbillon(tmrDialog, rencData, 2), - poesieSucces: { - reference: "Rêve de Dragon, Denis Gerfaud", - extrait: `Car le Second Âge fut bel et bien celui des Magiciens. Durant cette période, les - Gnomes s'enfoncèrent profondément sous les montagnes et la magie passa aux - mains des Humains qui en usèrent et abusèrent, se croyant devenus les maîtres du monde`}, - poesieEchec: { - reference: "Lily, Pierre Perret", - extrait: `Elle aurait pas cru sans le voir -
Que la couleur du désespoir -
Là-bas aussi ce fût le noir.`}, - }, - - tbrouge: { - msgSucces: async (rencData) => `Le ${rencData.rencontre.name} s'abat avec violence mais vous êtes plus rapide et parvenez à lui échapper.`, - msgEchec: async (rencData)=> `Le ${rencData.rencontre.name} vous frappe de milliers de morsure et vous malmène à travers les terres médianes.`, - postEchec: async (tmrDialog, rencData) => TMRRencontres.onPostEchecTourbillonRouge(tmrDialog, rencData), - poesieSucces: { - reference: "Qu'est-ce de votre vie ? une bouteille molle, Jean-Baptiste Chassignet", - extrait: `Qu'est-ce de votre vie ? un tourbillon rouant -
De fumière à flot gris, parmi l'air se jouant, -
Qui passe plus soudain que foudre meurtrière.`}, - poesieEchec: { - reference: "Les Djinns, poème Victor Hugo", - extrait: `Cris de l'enfer! voix qui hurle et qui pleure ! -
L'horrible essaim, poussé par l'aquilon, -
Sans doute, ô ciel ! s'abat sur ma demeure. -
Le mur fléchit sous le noir bataillon. -
La maison crie et chancelle penchée, -
Et l'on dirait que, du sol arrachée, -
Ainsi qu'il chasse une feuille séchée, -
Le vent la roule avec leur tourbillon !`}, - }, - - rdd: { - msgSucces: async (rencData) => `A tout seigneur, tout honneur, vous faites face à un ${rencData.rencontre.name}. Vous le maîtrisez et récupérez ses rêves. Vous gagnez ses ${rencData.rencontre.force} points de rêve`, - msgEchec: async (rencData)=> `A tout seigneur, tout honneur, vous faites face à un ${rencData.rencontre.name}. La rencontre tourne au cauchemar, dans la lutte épique, vous subissez ${rencData.rolled.isETotal ? 'deux queues' : 'une queue'} de dragon!`, - postSucces: async (tmrDialog, rencData) => TMRRencontres.onPostSuccessReveDeDragon(tmrDialog, rencData), - postEchec: async (tmrDialog, rencData) => TMRRencontres.onPostEchecReveDeDragon(tmrDialog, rencData), - poesieSucces: { - reference: "Rêve de Dragon, Denis Gerfaud", - extrait: `Le monde est Rêve de Dragons, mais nous ne savons -
ni leur apparence ni qui sont les dragons. -
En dépit de l'iconographie qui les clame -
immenses créatures ailées crachant des flammes`}, - poesieEchec: { - reference: "El Desdichado, Gérard de Nerval", - extrait: `Je suis le Ténébreux, – le Veuf, – l'Inconsolé, -
Le Prince d'Aquitaine à la Tour abolie : -
Ma seule Etoile est morte, – et mon luth constellé -
Porte le Soleil noir de la Mélancolie.`} - }, -} - -/* -------------------------------------------- */ -const mauvaisesRencontres = [ - { code: "mangeur", name: "Mangeur de Rêve", type: "mangeur", genre: "m", force: "1d6", refoulement: 2, isMauvaise: true }, - { code: "mangeur2d6", name: "Mangeur de Rêve", type: "mangeur", genre: "m", force: "2d6", refoulement: 2, isMauvaise: true }, - { code: "reflet+4", name: "Reflet d'ancien Rêve", type: "reflet", genre: "m", force: "2d6+4", refoulement: 2, isPersistant: true, isMauvaise: true }, - { code: "tbblanc+4", name: "Tourbillon blanc", type: "tbblanc", genre: "m", force: "2d6+4", refoulement: 2, isPersistant: true, isMauvaise: true }, - { code: "tbnoir+4", name: "Tourbillon noir", type: "tbnoir", genre: "m", force: "2d8+4", refoulement: 2, isPersistant: true, isMauvaise: true }, - { code: "passfou", name: "Passeur fou", type: "passeurfou", genre: "m", force: "2d8", refoulement: 2, isMauvaise: true }, - { code: "tbrouge", name: "Tourbillon rouge", type: "tbrouge", genre: "m", force: "2d8", refoulement: 3, isPersistant: true, isMauvaise: true } -] - -/* -------------------------------------------- */ -const rencontresStandard = [ - { code: "messager", name: "Messager des Rêves", type: "messager", genre: "m", force: "2d4", ignorer: true }, - { code: "passeur", name: "Passeur des Rêves", type: "passeur", genre: "m", force: "2d4", ignorer: true }, - { code: "fleur", name: "Fleur des Rêves", type: "fleur", genre: "f", force: "1d6", ignorer: true }, - { code: "mangeur", name: "Mangeur de Rêve", type: "mangeur", genre: "m", force: "1d6" }, - { code: "changeur", name: "Changeur de Rêve", type: "changeur", genre: "m", force: "2d6" }, - { code: "briseur", name: "Briseur de Rêve", type: "briseur", genre: "m", force: "2d6", quitterTMR: true }, - { code: "reflet", name: "Reflet d'ancien Rêve", type: "reflet", genre: "m", force: "2d6", isPersistant: true }, - { code: "tbblanc", name: "Tourbillon blanc", type: "tbblanc", genre: "m", force: "2d6", isPersistant: true }, - { code: "tbnoir", name: "Tourbillon noir", type: "tbnoir", genre: "m", force: "2d8", isPersistant: true }, - { code: "rdd", name: "Rêve de Dragon", type: "rdd", genre: "m", force: "1dr + 7", refoulement: 2, quitterTMR: true } -]; - -const rencontresPresentCite = [ - { code: "messager2d6", name: "Messager des Rêves", type: "messager", genre: "m", force: "2d6", ignorer: true }, - { code: "passeur2d6", name: "Passeur des Rêves", type: "passeur", genre: "m", force: "2d6", ignorer: true }, - { code: "fleur2d6", name: "Fleur des Rêves", type: "fleur", genre: "f", force: "2d6", ignorer: true } -] -const rencontresAll = [].concat(rencontresStandard).concat(mauvaisesRencontres).concat(rencontresPresentCite); - -const tableRencontres = { - cite: [{ code: 'messager', range: [1, 25] }, { code: 'passeur', range: [26, 50] }, { code: 'fleur', range: [51, 65] }, { code: 'mangeur', range: [66, 70] }, { code: 'changeur', range: [71, 80] }, { code: 'briseur', range: [81, 85] }, { code: 'reflet', range: [86, 90] }, { code: 'tbblanc', range: [91, 94] }, { code: 'tbnoir', range: [95, 97] }, { code: 'rdd', range: [98, 100] }], - sanctuaire: [{ code: 'messager', range: [1, 25] }, { code: 'passeur', range: [26, 50] }, { code: 'fleur', range: [51, 65] }, { code: 'mangeur', range: [66, 70] }, { code: 'changeur', range: [71, 80] }, { code: 'briseur', range: [81, 85] }, { code: 'reflet', range: [86, 90] }, { code: 'tbblanc', range: [91, 94] }, { code: 'tbnoir', range: [95, 97] }, { code: 'rdd', range: [98, 100] }], - plaines: [{ code: 'messager', range: [1, 20] }, { code: 'passeur', range: [21, 40] }, { code: 'fleur', range: [41, 55] }, { code: 'mangeur', range: [56, 60] }, { code: 'changeur', range: [61, 75] }, { code: 'briseur', range: [76, 82] }, { code: 'reflet', range: [83, 88] }, { code: 'tbblanc', range: [89, 93] }, { code: 'tbnoir', range: [94, 97] }, { code: 'rdd', range: [98, 100] }], - pont: [{ code: 'messager', range: [1, 20] }, { code: 'passeur', range: [21, 40] }, { code: 'fleur', range: [41, 55] }, { code: 'mangeur', range: [56, 60] }, { code: 'changeur', range: [61, 75] }, { code: 'briseur', range: [76, 82] }, { code: 'reflet', range: [83, 88] }, { code: 'tbblanc', range: [89, 93] }, { code: 'tbnoir', range: [94, 97] }, { code: 'rdd', range: [98, 100] }], - collines: [{ code: 'messager', range: [1, 15] }, { code: 'passeur', range: [16, 30] }, { code: 'fleur', range: [31, 42] }, { code: 'mangeur', range: [43, 54] }, { code: 'changeur', range: [55, 69] }, { code: 'briseur', range: [70, 82] }, { code: 'reflet', range: [83, 88] }, { code: 'tbblanc', range: [89, 93] }, { code: 'tbnoir', range: [94, 97] }, { code: 'rdd', range: [98, 100] }], - foret: [{ code: 'messager', range: [1, 15] }, { code: 'passeur', range: [16, 30] }, { code: 'fleur', range: [31, 42] }, { code: 'mangeur', range: [43, 54] }, { code: 'changeur', range: [55, 69] }, { code: 'briseur', range: [70, 82] }, { code: 'reflet', range: [83, 88] }, { code: 'tbblanc', range: [89, 93] }, { code: 'tbnoir', range: [94, 97] }, { code: 'rdd', range: [98, 100] }], - monts: [{ code: 'messager', range: [1, 10] }, { code: 'passeur', range: [11, 20] }, { code: 'fleur', range: [21, 26] }, { code: 'mangeur', range: [27, 44] }, { code: 'changeur', range: [45, 59] }, { code: 'briseur', range: [60, 75] }, { code: 'reflet', range: [76, 85] }, { code: 'tbblanc', range: [86, 92] }, { code: 'tbnoir', range: [93, 97] }, { code: 'rdd', range: [98, 100] }], - desert: [{ code: 'messager', range: [1, 10] }, { code: 'passeur', range: [11, 20] }, { code: 'fleur', range: [21, 26] }, { code: 'mangeur', range: [27, 44] }, { code: 'changeur', range: [45, 59] }, { code: 'briseur', range: [60, 75] }, { code: 'reflet', range: [76, 85] }, { code: 'tbblanc', range: [86, 92] }, { code: 'tbnoir', range: [93, 97] }, { code: 'rdd', range: [98, 100] }], - fleuve: [{ code: 'messager', range: [1, 5] }, { code: 'passeur', range: [6, 10] }, { code: 'fleur', range: [11, 13] }, { code: 'mangeur', range: [14, 37] }, { code: 'changeur', range: [38, 49] }, { code: 'briseur', range: [50, 65] }, { code: 'reflet', range: [66, 79] }, { code: 'tbblanc', range: [80, 89] }, { code: 'tbnoir', range: [90, 97] }, { code: 'rdd', range: [98, 100] }], - lac: [{ code: 'messager', range: [1, 5] }, { code: 'passeur', range: [6, 10] }, { code: 'fleur', range: [11, 13] }, { code: 'mangeur', range: [14, 37] }, { code: 'changeur', range: [38, 49] }, { code: 'briseur', range: [50, 65] }, { code: 'reflet', range: [66, 79] }, { code: 'tbblanc', range: [80, 89] }, { code: 'tbnoir', range: [90, 97] }, { code: 'rdd', range: [98, 100] }], - marais: [{ code: 'messager', range: [1, 2] }, { code: 'passeur', range: [3, 4] }, { code: 'fleur', range: [5, 5] }, { code: 'mangeur', range: [6, 29] }, { code: 'changeur', range: [30, 39] }, { code: 'briseur', range: [40, 60] }, { code: 'reflet', range: [61, 75] }, { code: 'tbblanc', range: [76, 86] }, { code: 'tbnoir', range: [87, 97] }, { code: 'rdd', range: [98, 100] }], - gouffre: [{ code: 'messager', range: [1, 2] }, { code: 'passeur', range: [3, 4] }, { code: 'fleur', range: [5, 5] }, { code: 'mangeur', range: [6, 29] }, { code: 'changeur', range: [30, 39] }, { code: 'briseur', range: [40, 60] }, { code: 'reflet', range: [61, 75] }, { code: 'tbblanc', range: [76, 86] }, { code: 'tbnoir', range: [87, 97] }, { code: 'rdd', range: [98, 100] }], - necropole: [{ code: 'mangeur', range: [1, 20] }, { code: 'changeur', range: [21, 30] }, { code: 'briseur', range: [31, 50] }, { code: 'reflet', range: [51, 65] }, { code: 'tbblanc', range: [66, 80] }, { code: 'tbnoir', range: [81, 97] }, { code: 'rdd', range: [98, 100] }], - desolation: [{ code: 'mangeur', range: [1, 20] }, { code: 'changeur', range: [21, 30] }, { code: 'briseur', range: [31, 50] }, { code: 'reflet', range: [51, 65] }, { code: 'tbblanc', range: [66, 80] }, { code: 'tbnoir', range: [81, 97] }, { code: 'rdd', range: [98, 100] }] -} /* -------------------------------------------- */ export class TMRRencontres { - static gestionRencontre = {} - - /* -------------------------------------------- */ - static init() { - for (let type in typeRencontres) { - TMRRencontres.register(type, typeRencontres[type]); - } - } - - /* -------------------------------------------- */ - static register(type, rencontre) { - TMRRencontres.gestionRencontre[type] = rencontre; - } /* -------------------------------------------- */ /** * Retourne une recontre en fonction de la case et du tirage * @param {*} terrain - * @param {*} roll + * @param {*} forcedRoll */ - static async rollRencontre(terrain, roll = undefined) { + static async rollRencontre(terrain, forcedRoll) { + // TODO: recherche parmi les types de terrains + mauvaise, rejet si plusieurs choix + const codeTerrain = Grammar.toLowerCaseNoAccent(terrain); if (!terrain) { ChatMessage.create({ user: game.user.id, @@ -338,170 +25,118 @@ export class TMRRencontres { }); return false; } - TMRRencontres.selectRencontre(terrain); - const codeTerrain = Grammar.toLowerCaseNoAccent(terrain); - - if (!roll || roll <= 0 || roll > 100) { - roll = await RdDDice.rollTotal("1d100"); + + if (forcedRoll && (forcedRoll <= 0 || forcedRoll > 100)) { + forcedRoll = undefined; } + + const table = await TMRRencontres.$buildTableRencontre(codeTerrain); + const [selected, roll] = await TMRRencontres.$selectRencontre(codeTerrain, table, forcedRoll); + const rencontre = await TMRRencontres.createRencontre(selected.rencontre); + TMRRencontres.$chatRolledRencontre(rencontre, terrain, table, roll, true); + return false; + } + + /* -------------------------------------------- */ + static async $buildTableRencontre(codeTerrain) { + let max = 0; + const items = await SystemCompendiums.getItems('rencontres'); + const filtreMauvaise = codeTerrain == 'mauvaise' ? it => it.system.mauvaiseRencontre : it => !it.system.mauvaiseRencontre; + const rencontres = items.filter(it => it.type == 'rencontre') + .filter(filtreMauvaise) + .filter(it => it.system.frequence[codeTerrain] > 0) + .sort(Misc.ascending(it => it.system.ordreTri)) + .map(it => { + const frequence = it.system.frequence[codeTerrain]; + max += frequence; + return { rencontre: it, min: max - frequence + 1, max: max,frequence: frequence }; + }); + return rencontres; + } + + /* -------------------------------------------- */ + static async $selectRencontre(terrain, table, roll = undefined) { + const total = table.map(it => it.frequence).reduce(Misc.sum(), 0); + if (total == 0){ + ui.notifications.warn(`Pas de rencontres définies pour ${terrain}`); + return undefined; + } + if (roll != undefined && (roll > total || roll <= 0)) { + ui.notifications.warn(`Jet de rencontre ${roll} en dehors de la table [1..${total}], le jet est relancé`); + roll = undefined; + } + if (!roll) { + roll = await RdDDice.rollTotal(`1d${total}`); + } + return [table.find(it => it.min <= roll && roll <= it.max), roll]; + } + + /* -------------------------------------------- */ + static async createRencontre(rencontre, tmr = undefined) { + return rencontre.clone({ + 'system.force': await RdDDice.rollTotal(rencontre.system.formule), + 'system.coord': tmr?.coord, + 'system.date': game.system.rdd.calendrier.getDateFromIndex(), + 'system.heure': game.system.rdd.calendrier.getCurrentHeure() + }, {save: false}); + } - let rencontre = await TMRRencontres.getRencontreAleatoire({type: codeTerrain, coord:''}, roll); + static async calculRencontre(rencontre, tmr = undefined) { + if (rencontre.system.coord == ""){ + rencontre.system.coord = tmr?.coord; + } + if (rencontre.system.force == 0){ + rencontre.system.force = await RdDDice.rollTotal(rencontre.system.formule); + } + if (rencontre.system.date == "" ) { + rencontre.system.date = game.system.rdd.calendrier.getDateFromIndex(); + } + if (rencontre.system.heure == "") { + rencontre.system.heure = game.system.rdd.calendrier.getCurrentHeure(); + } + return rencontre; + } + + /* -------------------------------------------- */ + static $chatRolledRencontre(rencontre, terrain, table, roll = 0, displayTable=false){ + const total = table.map(it => it.frequence).reduce(Misc.sum(), 0); + const namesPercent = displayTable ? + table.map(it => `
${it.rencontre.name} : ${it.frequence}${total == 100 ? '%' : ''} (${it.min} - ${it.max})`).reduce((a, b) => a + b, '
') + : ''; + const chances = game.user.isGM + ? (roll ? `Jet: ${roll} / ${total}` : `Valeurs: [1..${total}]`) + : (roll ? `Jet: ${Math.ceil(roll*100/total)} / 100` : ''); ChatMessage.create({ user: game.user.id, whisper: [game.user.id], - content: `Rencontre en ${terrain} (jet : ${roll}%)
Vous rencontrez un ${rencontre.name} de ${rencontre.force} Points de Rêve` + content: `Compendium: ${SystemCompendiums.getCompendium('rencontres')} +
Rencontre en ${terrain}: + ${namesPercent}
+
${chances} +
Rencontre: ${rencontre.name} ${rencontre.system.force} (${rencontre.system.formule})` }); - return false; + } + + static async getPresentsCite() { + const rencontres = await SystemCompendiums.getDefaultItems('rencontres'); + return rencontres.filter(it => !it.system.mauvaiseRencontre && it.system.presentCite).map(it => + it.clone({ 'system.formule': "2d6" }, {save: false})); + } + + static async getReveDeDragon(force) { + const rencontres = await SystemCompendiums.getDefaultItems('rencontres'); + const reveDeDragon = rencontres.find(it => Grammar.equalsInsensitive(it.name, 'Rêve de Dragon')); + return reveDeDragon?.clone({ 'system.force': force }, {save: false}); } /* -------------------------------------------- */ - static getRencontre(index) { - let rencontre; - if (isNaN(index)) { - rencontre = rencontresAll.find(r => r.type == index) ?? rencontresAll.find(r => r.code == index) - } - else if (0 <= index && index < rencontresAll.length) { - rencontre = rencontresAll[index]; - } - if (rencontre) { - return duplicate(rencontre); - } - else { - ui.notifications.info(`Pas de rencontre pour ${index}, seulement ${rencontresAll.length} rencontres sont connues.
Vous pouvez aussi essayer par type (ie: mangeur, fleur, fleur2d6, ...)`) - } - return undefined; - } - - /* -------------------------------------------- */ - static async getRencontreAleatoire(tmr, roll = undefined) { - if (!roll || roll <= 0 || roll > 100) { - roll = await RdDDice.rollTotal("1d100"); - } - const codeTerrain = Grammar.toLowerCaseNoAccent(tmr.type); - const code = tableRencontres[codeTerrain].find(it => it.range[0] <= roll && roll <= it.range[1]).code; - const rencontre = duplicate(rencontresStandard.find(it => it.code == code)); - rencontre.roll = roll; - await TMRRencontres.evaluerForceRencontre(rencontre); + static async getRencontreAleatoire(tmr, mauvaise) { + const codeTerrain = mauvaise ? 'mauvaise' : tmr.type; + const table = await TMRRencontres.$buildTableRencontre(codeTerrain); + const [selected, roll] = await TMRRencontres.$selectRencontre(codeTerrain, table); + const rencontre = await TMRRencontres.createRencontre(selected.rencontre, tmr); + TMRRencontres.$chatRolledRencontre(rencontre, TMRUtility.getTMRType(tmr.coord), table, roll); return rencontre; } - /* -------------------------------------------- */ - static async getMauvaiseRencontre(index = undefined) { - const rencontre = duplicate( - (index && index >= 0 && index < mauvaisesRencontres.length) - ? mauvaisesRencontres[index] - : await RdDDice.rollOneOf(mauvaisesRencontres)); - await TMRRencontres.evaluerForceRencontre(rencontre); - return rencontre; - } - - /* -------------------------------------------- */ - static async evaluerForceRencontre(rencontre) { - const rollForce = new Roll(rencontre.force); - await rollForce.evaluate({ async: true }); - rencontre.force = rollForce.total; - return rencontre.force; - } - - /* -------------------------------------------- */ - static isReveDeDragon(rencontre) { - return rencontre.type == "rdd"; - } - - /* -------------------------------------------- */ - static getGestionRencontre(name) { - let gestion = TMRRencontres.gestionRencontre[name]; - if (!gestion) { - ui.notifications.error(`La rencontre ${name} est inconnue, pas de méthode de gestion associée`) - gestion = TMRRencontres.gestionRencontre['messager']; - } - return gestion; - } - - /* -------------------------------------------- */ - static async gererRencontre(tmrDialog, rencData) { - let gestion = TMRRencontres.getGestionRencontre(rencData.rencontre.type); - if (rencData.rolled.isSuccess) { - rencData.message = await gestion.msgSucces(rencData); - if (rencData.nbRounds > 1) { - rencData.message += ` Au total, vous avez passé ${rencData.nbRounds} rounds à vous battre!`; - } - rencData.poesie = gestion.poesieSucces; - return gestion.postSucces; - } - - rencData.message = await gestion.msgEchec(rencData); - if (rencData.nbRounds > 1) { - rencData.message += ` Vous avez passé ${rencData.nbRounds} rounds à lutter!`; - } - rencData.poesie = gestion.poesieEchec; - return gestion.postEchec; - } - - /* -------------------------------------------- */ - static async msgEchecPasseurFou(tmrData) { - tmrData.sortReserve = RdDDice.rollOneOf(tmrData.actor.itemTypes['sortreserve']); - if (tmrData.sortReserve) { - // Passeur fou positionne sur la case d'un sort en réserve - tmrData.newTMR = TMRUtility.getTMR(tmrData.sortReserve.coord); - } else { - // Déplacement aléatoire de la force du Passeur Fou - const newCoord = await RdDDice.rollOneOf(TMRUtility.getTMRPortee(tmrData.tmr.coord, tmrData.rencontre.force)); - tmrData.newTMR = TMRUtility.getTMR(newCoord); - } - if (tmrData.sortReserve) { - return `Le ${tmrData.rencontre.name} vous dérobe la clé de vos sorts. Vous vous saisissez de lui, mais dans un nuage violet, il vous emporte en ${tmrData.newTMR.label} déclencher votre sort en réserve de ${tmrData.sortReserve.name}.`; - } - else { - return `Le ${tmrData.rencontre.name} tente de vous dérober la clé de vos sorts. Ne la trouvant pas, il déclenche un nuage violet et vous emporte en ${tmrData.newTMR.label}`; - } - } - - /* -------------------------------------------- */ - static async postEchecPasseurFou(tmrDialog, tmrData) { - if (tmrData.sortReserve) { - await tmrDialog.processSortReserve(tmrData.sortReserve); - } - await tmrDialog.positionnerDemiReve(tmrData.newTMR.coord); - if (tmrData.sortReserve) { - tmrDialog.close(); - } - } - - /* -------------------------------------------- */ - static async onPostEchecTourbillon(tmrDialog, tmrData, cases) { - await tmrData.actor.reveActuelIncDec(-cases); - await TMRRencontres._toubillonner(tmrDialog, tmrData.actor, cases); - } - - /* -------------------------------------------- */ - static async onPostEchecTourbillonRouge(tmrDialog, rencontre) { - await rencontre.actor.reveActuelIncDec(-2); // -2 pts de Reve a chaque itération - TMRRencontres._toubillonner(tmrDialog, rencontre.actor, 4); - await rencontre.actor.santeIncDec("vie", -1); // Et -1 PV - } - - /* -------------------------------------------- */ - static async _toubillonner(tmrDialog, actor, cases) { - let coord = actor.system.reve.tmrpos.coord; - for (let i = 0; i < cases; i++) { - coord = await TMRUtility.deplaceTMRAleatoire(actor, coord).coord; - } - await tmrDialog.positionnerDemiReve(coord) - } - - /* -------------------------------------------- */ - static async onPostSuccessReveDeDragon(tmrDialog, tmrData) { - if (tmrData.rolled.isPart) { - await tmrData.actor.appliquerAjoutExperience(tmrData); - } - await tmrData.actor.resultCombatReveDeDragon(tmrData); - } - - /* -------------------------------------------- */ - static async onPostEchecReveDeDragon(tmrDialog, tmrData) { - await tmrData.actor.resultCombatReveDeDragon(tmrData); - tmrDialog.close(); - } } - diff --git a/module/tmr-utility.js b/module/tmr-utility.js index 6e37fad1..3ec336df 100644 --- a/module/tmr-utility.js +++ b/module/tmr-utility.js @@ -314,24 +314,15 @@ export class TMRUtility { /* -------------------------------------------- */ static async deplaceTMRAleatoire(actor, coord) { - return TMRUtility.deplaceTMRSelonPattern(actor, coord, await TMRUtility.getDirectionPattern(), 1); - } - - /* -------------------------------------------- */ - static async deplaceTMRSelonPattern(actor, coordTMR, direction, nTime) { - let coord; - for (let i = 0; i < nTime; i++) { - let currentOddq = TMRUtility.coordTMRToOddq(coordTMR); - currentOddq.col = currentOddq.col + direction.col; - currentOddq.row = currentOddq.row + direction.row; - if (this.isOddqInTMR(currentOddq)) { // Sortie de carte ! Ré-insertion aléatoire - coord = TMRUtility.getTMR(TMRUtility.oddqToCoordTMR(currentOddq)); - } else { - coord = await actor.reinsertionAleatoire('Sortie de carte'); - } - console.log("Nouvelle case iteration !!!", i, coord); + const currentOddq = TMRUtility.coordTMRToOddq(coord); + const direction = await TMRUtility.getDirectionPattern(); + currentOddq.col = currentOddq.col + direction.col; + currentOddq.row = currentOddq.row + direction.row; + if (this.isOddqInTMR(currentOddq)) { // Sortie de carte ! Ré-insertion aléatoire + return TMRUtility.getTMR(TMRUtility.oddqToCoordTMR(currentOddq)); + } else { + return await actor.reinsertionAleatoire('Sortie de carte'); } - return coord; } /* -------------------------------------------- */ @@ -343,6 +334,10 @@ export class TMRUtility { return Object.values(TMRMapping).filter(filter); } + static getCasesType(type) { + return TMRUtility.filterTMR(it => it.type == type).map(it => it.coord); + } + static findTMR(search) { const labelSearch = Grammar.toLowerCaseNoAccent(search) return TMRUtility.filterTMR(it => Grammar.toLowerCaseNoAccent(it.label).match(labelSearch) || it.coord == search); diff --git a/module/tmr/present-cites.js b/module/tmr/present-cites.js index 2ebf4b10..4cb83afa 100644 --- a/module/tmr/present-cites.js +++ b/module/tmr/present-cites.js @@ -3,6 +3,7 @@ import { Grammar } from "../grammar.js"; import { TMRUtility } from "../tmr-utility.js"; import { tmrConstants, tmrTokenZIndex } from "../tmr-constants.js"; import { Draconique } from "./draconique.js"; +import { TMRRencontres } from "../tmr-rencontres.js"; export class PresentCites extends Draconique { @@ -46,15 +47,13 @@ export class PresentCites extends Draconique { } async choisirUnPresent(casetmr, onChoixPresent) { + const presents = await TMRRencontres.getPresentsCite() + const buttons = {}; + presents.forEach(r => buttons['present'+r.id] = { icon: '', label: r.name, callback: async () => onChoixPresent(r) }); let d = new Dialog({ title: "Présent des cités", - content: `La ${this.tmrLabel(casetmr)} vous offre un présent, faite votre choix`, - buttons: { - messager: { icon: '', label: "Un Messager des rêves", callback: () => onChoixPresent('messager2d6') }, - passeur: { icon: '', label: "Un Passeur des rêves", callback: () => onChoixPresent('passeur2d6') }, - fleur: { icon: '', label: "Une Fleur des rêves", callback: () => onChoixPresent('fleur2d6') }, - }, - default: "fleur" + content: `La ${this.tmrLabel(casetmr)} vous offre un présent, faites votre choix`, + buttons: buttons }); d.render(true); } diff --git a/module/tmr/rencontre.js b/module/tmr/rencontre.js index d71f2f66..7d38e017 100644 --- a/module/tmr/rencontre.js +++ b/module/tmr/rencontre.js @@ -13,7 +13,7 @@ export class Rencontre extends Draconique { async onActorCreateOwned(actor, item) { } code() { return 'rencontre' } - tooltip(rencontre) { return `${rencontre.name} de force ${rencontre.force}` } + tooltip(rencontre) { return `${rencontre.name} de force ${rencontre.system.force}` } img() { return 'systems/foundryvtt-reve-de-dragon/icons/heures/hd06.webp' } createSprite(pixiTMR) { diff --git a/template.json b/template.json index 525206b4..940c2bf3 100644 --- a/template.json +++ b/template.json @@ -467,12 +467,6 @@ "label": "Position TMR", "cache": false }, - "reserve": { - "list": [] - }, - "rencontre": { - "list": [] - }, "refoulement": { "value": 0, "label": "Points de Refoulement" diff --git a/templates/actor/hr-rencontres.html b/templates/actor/hr-rencontres.html index 0962a0f3..7d9a2a7e 100644 --- a/templates/actor/hr-rencontres.html +++ b/templates/actor/hr-rencontres.html @@ -1,28 +1,12 @@ -{{#if hautreve.rencontres.length}} -

Rencontres en attente dans les TMR

- -{{/if}} {{#if rencontres.length}}

Rencontres en attente dans les TMR

{{/if}} - diff --git a/templates/chat-rencontre-tmr.html b/templates/chat-rencontre-tmr.html index 4d49510d..4ea13ef3 100644 --- a/templates/chat-rencontre-tmr.html +++ b/templates/chat-rencontre-tmr.html @@ -1,6 +1,6 @@ {{competence.name}}

- {{alias}} rencontre {{#if (eq genre 'f')}}une{{else}}un{{/if}} {{rencontre.name}} de force {{rencontre.force}} + {{alias}} rencontre {{#if (eq rencontre.system.genre 'f')}}une{{else}}un{{/if}} {{rencontre.name}} de force {{rencontre.system.force}}

{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.html"}}
diff --git a/templates/chat-resultat-reve-de-dragon.html b/templates/chat-resultat-reve-de-dragon.html index 3a1300f5..ae2614af 100644 --- a/templates/chat-resultat-reve-de-dragon.html +++ b/templates/chat-resultat-reve-de-dragon.html @@ -6,7 +6,7 @@
{{#if rolled.isSuccess}} - {{alias}} maîtrise le Rêve de Dragon! ll gagne {{rencontre.force}} points de Rêve. + {{alias}} maîtrise le Rêve de Dragon! ll gagne {{rencontre.system.force}} points de Rêve. {{#if tete}}
{{alias}} doit demander au Gardien des Rêves de faire un tirage sur une des tables des têtes de dragon (Haut-rêvant ou Tous personnages). diff --git a/templates/dialog-roll-reve-de-dragon.html b/templates/dialog-roll-reve-de-dragon.html index 308c6fdf..c9f2d630 100644 --- a/templates/dialog-roll-reve-de-dragon.html +++ b/templates/dialog-roll-reve-de-dragon.html @@ -1,5 +1,5 @@
-

Rêve de Dragon de force {{rencontre.force}}!

+

{{rencontre.name}} de force {{rencontre.system.force}}!

{{competence.name}}