Merge branch 'rencontres' into 'v1.3'
Rencontres See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!142
This commit is contained in:
commit
2fd2de29ad
@ -473,9 +473,15 @@ export class RdDActor extends Actor {
|
||||
await this._recupererEthylisme(message);
|
||||
await this.recupererFatigue(message);
|
||||
await this.recuperationReve(message);
|
||||
if (this.isDonDoubleReve()) {
|
||||
await this.recuperationReve(message);
|
||||
}
|
||||
}
|
||||
ChatMessage.create(message);
|
||||
}
|
||||
isDonDoubleReve() {
|
||||
return this.data.items.find(item => item.type == 'tete' && item.name == 'Don de double-rêve');
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async _recupererEthylisme(message) {
|
||||
@ -549,7 +555,7 @@ export class RdDActor extends Actor {
|
||||
if (deRecuperation >= 7) {
|
||||
// Rêve de Dragon !
|
||||
message.content += `<br>Vous faites un <strong>Rêve de Dragon</strong> de ${deRecuperation} Points de rêve`;
|
||||
message.content += await this.combattreReveDeDragon(deRecuperation);
|
||||
/*message.content += */await this.combattreReveDeDragon(deRecuperation);
|
||||
}
|
||||
else {
|
||||
message.content += `<br>Vous récupérez ${deRecuperation} Points de rêve`;
|
||||
@ -599,7 +605,11 @@ export class RdDActor extends Actor {
|
||||
if (roll.isETotal) {
|
||||
message += "<br>A cause de votre échec total, vous subissez une deuxième Queue de Dragon: " + await this.ajouterQueue();
|
||||
}
|
||||
return message;
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
content: message
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -1019,7 +1029,7 @@ export class RdDActor extends Actor {
|
||||
await this.createOwnedItem(souffle);
|
||||
if (options.chat) {
|
||||
ChatMessage.create({
|
||||
whisper: ChatMessage.getWhisperRecipients([ "GM", game.user.name] ),
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
|
||||
content: this.name + " subit un Souffle de Dragon : " + souffle.name
|
||||
});
|
||||
}
|
||||
@ -1041,7 +1051,7 @@ export class RdDActor extends Actor {
|
||||
await this.createOwnedItem(queue);
|
||||
if (options.chat) {
|
||||
ChatMessage.create({
|
||||
whisper: ChatMessage.getWhisperRecipients([ "GM", game.user.name] ),
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
|
||||
content: this.name + " subit une Queue de Dragon : " + queue.name
|
||||
});
|
||||
}
|
||||
@ -1075,7 +1085,7 @@ export class RdDActor extends Actor {
|
||||
}
|
||||
if (content) {
|
||||
ChatMessage.create({
|
||||
whisper: ChatMessage.getWhisperRecipients([ "GM", game.user.name] ),
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
|
||||
content: content
|
||||
});
|
||||
}
|
||||
@ -1704,7 +1714,7 @@ export class RdDActor extends Actor {
|
||||
competence: this.getBestDraconic(),
|
||||
selectedSort: sortList[0],
|
||||
coord: coord,
|
||||
coordLabel: TMRUtility.getTMRDescription(coord).label,
|
||||
coordLabel: TMRUtility.getTMR(coord).label,
|
||||
diffLibre: sortList[0].data.difficulte, // Per default at startup
|
||||
coutreve: Array(20).fill().map((item, index) => 1 + index)
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import { RdDResolutionTable } from "./rdd-resolution-table.js";
|
||||
import { RdDRollResolutionTable } from "./rdd-roll-resolution-table.js";
|
||||
import { RdDRollTables } from "./rdd-rolltables.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
import { TMRRencontres } from "./tmr-rencontres.js";
|
||||
import { TMRUtility } from "./tmr-utility.js";
|
||||
|
||||
const rddRollNumeric = /(\d+)\s*([\+\-]?\d+)?\s*(s)?/;
|
||||
@ -187,7 +188,7 @@ export class RdDCommands {
|
||||
/* -------------------------------------------- */
|
||||
async getRencontreTMR(params) {
|
||||
if (params.length == 1 || params.length ==2) {
|
||||
return TMRUtility.getRencontre(params[0], params[1])
|
||||
return TMRRencontres.rollRencontre(params[0], params[1])
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
|
@ -26,6 +26,7 @@ import { RdDItemCompetence } from "./item-competence.js";
|
||||
import { StatusEffects } from "./status-effects.js";
|
||||
import { RddCompendiumOrganiser } from "./rdd-compendium-organiser.js";
|
||||
import { ReglesOptionelles } from "./regles-optionelles.js";
|
||||
import { TMRRencontres } from "./tmr-rencontres.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Foundry VTT Initialization */
|
||||
@ -108,7 +109,10 @@ Hooks.once("init", async function () {
|
||||
// preload handlebars templates
|
||||
RdDUtility.preloadHandlebarsTemplates();
|
||||
// Create useful storage space
|
||||
game.system.rdd = { TMRUtility: TMRUtility }
|
||||
game.system.rdd = {
|
||||
TMRUtility,
|
||||
RdDUtility
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
game.settings.register("foundryvtt-reve-de-dragon", "accorder-entite-cauchemar", {
|
||||
@ -225,6 +229,8 @@ Hooks.once("init", async function () {
|
||||
RdDActor.init();
|
||||
RddCompendiumOrganiser.init();
|
||||
ReglesOptionelles.init();
|
||||
TMRUtility.init();
|
||||
TMRRencontres.init();
|
||||
});
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
@ -2,21 +2,14 @@
|
||||
* Extend the base Dialog entity by defining a custom window to perform spell.
|
||||
* @extends {Dialog}
|
||||
*/
|
||||
import { RollDataAjustements } from "./rolldata-ajustements.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
import { TMRUtility } from "./tmr-utility.js";
|
||||
import { RdDRollTables } from "./rdd-rolltables.js";
|
||||
import { tmrConstants } from "./tmr-utility.js";
|
||||
import { RdDResolutionTable } from "./rdd-resolution-table.js";
|
||||
import { RdDTMRRencontreDialog } from "./rdd-tmr-rencontre-dialog.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
const tmrConstants = {
|
||||
col1_y: 30,
|
||||
col2_y: 55,
|
||||
cellw: 55,
|
||||
cellh: 55,
|
||||
gridx: 28,
|
||||
gridy: 28
|
||||
}
|
||||
import { TMRRencontres } from "./tmr-rencontres.js";
|
||||
import { ChatUtility } from "./chat-utility.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class RdDTMRDialog extends Dialog {
|
||||
@ -120,16 +113,25 @@ export class RdDTMRDialog extends Dialog {
|
||||
this.close();
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async refouler(data) {
|
||||
async refouler() {
|
||||
this._tellToGM(this.actor.name + " a refoulé : " + this.currentRencontre.name);
|
||||
await this.actor.deleteTMRRencontreAtPosition(); // Remove the stored rencontre if necessary
|
||||
let result = await this.actor.ajouterRefoulement( this.currentRencontre.data.refoulement );
|
||||
await this.actor.ajouterRefoulement(this.currentRencontre.refoulement ?? 1);
|
||||
this.updatePreviousRencontres();
|
||||
console.log("-> refouler", this.currentRencontre)
|
||||
this.updateValuesDisplay();
|
||||
this.nettoyerRencontre();
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async ignorerRencontre() {
|
||||
this._tellToGM(this.actor.name + " a ignoré : " + this.currentRencontre.name);
|
||||
await this.actor.deleteTMRRencontreAtPosition(); // Remove the stored rencontre if necessary
|
||||
this.updatePreviousRencontres();
|
||||
this.updateValuesDisplay();
|
||||
this.nettoyerRencontre();
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
colorierZoneRencontre(locList) {
|
||||
this.currentRencontre.graphics = []; // Keep track of rectangles to delete it
|
||||
@ -148,132 +150,118 @@ export class RdDTMRDialog extends Dialog {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async gererTourbillon( value ) {
|
||||
this.nbFatigue += 1;
|
||||
await this.actor.reveActuelIncDec( -value );
|
||||
if ( !this.currentRencontre.tourbillonDirection ) {
|
||||
this.currentRencontre.tourbillonDirection = TMRUtility.getDirectionPattern();
|
||||
}
|
||||
let tmrPos = this.actor.data.data.reve.tmrpos;
|
||||
tmrPos.coord = TMRUtility.deplaceTMRSelonPattern( tmrPos.coord, this.currentRencontre.tourbillonDirection, value );
|
||||
await this.actor.update({ "data.reve.tmrpos": tmrPos });
|
||||
console.log("NEWPOS", tmrPos);
|
||||
// garder la trace de l'état en cours
|
||||
setStateRencontre(state) {
|
||||
this.rencontreState = state;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async gererTourbillonRouge( ) {
|
||||
this.nbFatigue += 1;
|
||||
await this.actor.reveActuelIncDec( -2 ); // -2 pts de Reve a chaque itération
|
||||
if ( !this.currentRencontre.tourbillonDirection ) {
|
||||
this.currentRencontre.tourbillonDirection = TMRUtility.getDirectionPattern();
|
||||
}
|
||||
let tmrPos = this.actor.data.data.reve.tmrpos;
|
||||
tmrPos.coord = TMRUtility.deplaceTMRSelonPattern( tmrPos.coord, this.currentRencontre.tourbillonDirection, 4 ); // Depl. 4 cases.
|
||||
await this.actor.update({ "data.reve.tmrpos": tmrPos });
|
||||
await this.actor.santeIncDec( "vie", -1); // Et -1 PV
|
||||
console.log("TOURBILLON ROUGE", tmrPos);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** Gère les rencontres avec du post-processing graphique (passeur, messagers, tourbillons, ...) */
|
||||
async rencontrePostProcess( rencontreData) {
|
||||
if (!rencontreData) return; // Sanity check
|
||||
this.rencontreState = rencontreData.state; // garder la trace de l'état en cours
|
||||
|
||||
let locList
|
||||
if ( this.rencontreState == 'passeur' || this.rencontreState == 'messager' ) {
|
||||
async choisirCasePortee(coord, portee) {
|
||||
// Récupère la liste des cases à portées
|
||||
locList = TMRUtility.getTMRArea(this.actor.data.data.reve.tmrpos.coord, this.currentRencontre.force, tmrConstants );
|
||||
|
||||
} else if ( this.rencontreState == 'passeurfou' ) { // Cas spécial du passeur fou
|
||||
let sortReserve = this.actor.data.data.reve.reserve[0];
|
||||
let tmrPos
|
||||
if ( sortReserve ) {
|
||||
tmrPos = sortReserve.coord; // Passeur fou positionne sur la case d'un ort en réserve (TODO : Choisir le plus loin)
|
||||
} else {
|
||||
let direction = TMRUtility.getDirectionPattern(); // Déplacement aléatoire de la force du Passeur Fou
|
||||
tmrPos = TMRUtility.deplaceTMRSelonPattern(this.actor.data.data.reve.tmrpos.coord, direction, this.currentRencontre.force );
|
||||
}
|
||||
await this.actor.update({ "data.reve.tmrpos": tmrPos });
|
||||
|
||||
} else if ( this.rencontreState == 'changeur' ) {
|
||||
// Liste des cases de même type
|
||||
locList = TMRUtility.getLocationTypeList( this.actor.data.data.reve.tmrpos.coord );
|
||||
|
||||
} else if ( this.rencontreState == 'reflet' ) {
|
||||
this.nbFatigue += 1;
|
||||
|
||||
} else if ( this.rencontreState == 'tourbillonblanc' ) {
|
||||
await this.gererTourbillon(1);
|
||||
|
||||
} else if ( this.rencontreState == 'tourbillonnoir' ) {
|
||||
await this.gererTourbillon(2);
|
||||
|
||||
} else if ( this.rencontreState == 'tourbillonrouge' ) {
|
||||
await this.gererTourbillonRouge();
|
||||
|
||||
} else {
|
||||
this.currentRencontre = undefined; // Cleanup, not used anymore
|
||||
}
|
||||
|
||||
if ( locList )
|
||||
let locList = TMRUtility.getTMRPortee(coord, portee);
|
||||
this.colorierZoneRencontre(locList);
|
||||
|
||||
}
|
||||
|
||||
async choisirCaseType(type) {
|
||||
const locList = TMRUtility.getListCoordTMR(type);
|
||||
this.colorierZoneRencontre(locList);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
checkQuitterTMR() {
|
||||
if ( this.actor.data.data.reve.reve.value == 0) {
|
||||
this._tellToGM("Vos Points de Rêve sont à 0 : vous quittez les Terres médianes !");
|
||||
|
||||
if (this.actor.isDead()) {
|
||||
this._tellToGM("Vous êtes mort : vous quittez les Terres médianes !");
|
||||
this.close();
|
||||
return true;
|
||||
}
|
||||
if ( this.nbFatigue == this.actor.data.data.sante.fatigue.max ) {
|
||||
const resteAvantInconscience = this.actor.getFatigueMax() - this.actor.getFatigueActuelle() - this.nbFatigue;
|
||||
if (resteAvantInconscience <= 0) {
|
||||
this._tellToGM("Vous vous écroulez de fatigue : vous quittez les Terres médianes !");
|
||||
this.close();
|
||||
this.quitterLesTMRInconscient();
|
||||
return true;
|
||||
}
|
||||
if ( this.actor.data.data.sante.vie.value == 0 ) {
|
||||
this._tellToGM("Vous n'avez plus de Points de Vie : vous quittez les Terres médianes !");
|
||||
this.close();
|
||||
if (this.actor.getReveActuel() == 0) {
|
||||
this._tellToGM("Vos Points de Rêve sont à 0 : vous quittez les Terres médianes !");
|
||||
this.quitterLesTMRInconscient();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async quitterLesTMRInconscient() {
|
||||
if (this.currentRencontre?.isPersistant) {
|
||||
await this.refouler();
|
||||
}
|
||||
this.close();
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async maitriser(data) {
|
||||
this.actor.deleteTMRRencontreAtPosition(); // Remove the stored rencontre if necessary
|
||||
async maitriser() {
|
||||
this.actor.deleteTMRRencontreAtPosition();
|
||||
this.updatePreviousRencontres();
|
||||
|
||||
const draconic = this.actor.getBestDraconic();
|
||||
const carac = this.actor.getReveActuel();
|
||||
const etatGeneral = this.actor.getEtatGeneral();
|
||||
const difficulte = draconic.data.niveau - this.currentRencontre.force + etatGeneral;
|
||||
console.log("Maitriser", carac, draconic.data.niveau, this.currentRencontre.force, etatGeneral);
|
||||
|
||||
let rolled = await RdDResolutionTable.roll(carac, difficulte);
|
||||
let message = "<br><strong>Test : Rêve actuel / " + draconic.name + " / " + this.currentRencontre.name + "</strong>" + "<br>"
|
||||
+ RdDResolutionTable.explain(rolled);
|
||||
|
||||
let rencontreData
|
||||
if (rolled.isEchec) {
|
||||
rencontreData = await TMRUtility.processRencontreEchec(this.actor, this.currentRencontre, rolled, this);
|
||||
message += rencontreData.message;
|
||||
this._tellToGM("Vous avez <strong>échoué</strong> à maîtriser un " + this.currentRencontre.name + " de force " + this.currentRencontre.force + message);
|
||||
|
||||
if (this.currentRencontre.data.quitterTMR) { // Selon les rencontres, quitter TMR ou pas
|
||||
this.close();
|
||||
}
|
||||
} else {
|
||||
rencontreData = await TMRUtility.processRencontreReussite(this.actor, this.currentRencontre, rolled);
|
||||
message += rencontreData.message;
|
||||
this._tellToGM("Vous avez <strong>réussi</strong> à maîtriser un " + this.currentRencontre.name + " de force " + this.currentRencontre.force + message);
|
||||
let rencontreData = {
|
||||
actor: this.actor,
|
||||
alias: this.actor.name,
|
||||
reveDepart: this.actor.getReveActuel(),
|
||||
competence: this.actor.getBestDraconic(),
|
||||
rencontre: this.currentRencontre,
|
||||
nbRounds: 1,
|
||||
tmr: TMRUtility.getTMR(this.actor.data.data.reve.tmrpos.coord)
|
||||
}
|
||||
|
||||
await this.rencontrePostProcess( rencontreData );
|
||||
await this._tentativeMaitrise(rencontreData);
|
||||
}
|
||||
|
||||
async _tentativeMaitrise(rencontreData) {
|
||||
console.log("-> matriser", rencontreData);
|
||||
|
||||
rencontreData.reve = this.actor.getReveActuel();
|
||||
rencontreData.etat = this.actor.getEtatGeneral();
|
||||
|
||||
RollDataAjustements.calcul(rencontreData, this.actor);
|
||||
|
||||
rencontreData.rolled = await RdDResolutionTable.roll(rencontreData.reve, RollDataAjustements.sum(rencontreData.ajustements));
|
||||
|
||||
let postProcess = await TMRRencontres.gererRencontre(this, rencontreData);
|
||||
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-rencontre-tmr.html`, rencontreData)
|
||||
});
|
||||
|
||||
if (postProcess) {
|
||||
/** Gère les rencontres avec du post-processing (passeur, messagers, tourbillons, ...) */
|
||||
await postProcess(this, rencontreData);
|
||||
}
|
||||
else {
|
||||
this.currentRencontre = undefined;
|
||||
}
|
||||
|
||||
console.log("-> matriser", this.currentRencontre);
|
||||
this.updateValuesDisplay();
|
||||
if (this.checkQuitterTMR()) {
|
||||
return;
|
||||
}
|
||||
else if (rencontreData.rolled.isEchec && rencontreData.rencontre.isPersistant) {
|
||||
setTimeout(() => {
|
||||
rencontreData.nbRounds++;
|
||||
this.nbFatigue += 1;
|
||||
this._tentativeMaitrise(rencontreData);
|
||||
setTimeout(() => this._deleteTmrMessages(rencontreData.actor, rencontreData.nbRounds), 500);
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
|
||||
this.checkQuitterTMR();
|
||||
if ( this.rencontreState == 'reflet' || this.rencontreState == 'tourbillonblanc' || this.rencontreState == 'tourbillonnoir' )
|
||||
this.maitriser();
|
||||
_deleteTmrMessages(actor, nbRounds = -1) {
|
||||
if (nbRounds < 0) {
|
||||
ChatUtility.removeChatMessageContaining(`<h4 data-categorie="tmr" data-actor-id="${actor._id}"`);
|
||||
}
|
||||
else {
|
||||
for (let i = 1; i < nbRounds; i++) {
|
||||
ChatUtility.removeChatMessageContaining(`<h4 data-categorie="tmr" data-actor-id="${actor._id}" data-rencontre-round="${i}">`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -306,22 +294,20 @@ export class RdDTMRDialog extends Dialog {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async _jetDeRencontre(coordTMR, cellDescr) {
|
||||
|
||||
let rencontre = this.rencontresExistantes.find(prev => prev.coord == coordTMR);
|
||||
if (rencontre == undefined) {
|
||||
let myRoll = new Roll("1d7").roll();
|
||||
if (myRoll.total == 7) {
|
||||
let isSpecial = this.actor.isRencontreSpeciale();
|
||||
rencontre = await TMRUtility.rencontreTMRRoll(coordTMR, cellDescr, isSpecial );
|
||||
} else {
|
||||
this._tellToUser(myRoll.total + ": Pas de rencontre en " + cellDescr.label + " (" + coordTMR + ")");
|
||||
}
|
||||
}
|
||||
if (TMRUtility.isForceRencontre()) {
|
||||
return await TMRUtility.rencontreTMRRoll(coordTMR, cellDescr);
|
||||
}
|
||||
let rencontre = this.rencontresExistantes.find(prev => prev.coord == coordTMR);
|
||||
if (rencontre) {
|
||||
return rencontre;
|
||||
}
|
||||
let myRoll = new Roll("1d7").evaluate();
|
||||
if (myRoll.total == 7) {
|
||||
let isMauvaise = this.actor.isRencontreSpeciale();
|
||||
return await TMRUtility.rencontreTMRRoll(coordTMR, cellDescr, isMauvaise);
|
||||
}
|
||||
this._tellToUser(myRoll.total + ": Pas de rencontre en " + cellDescr.label + " (" + coordTMR + ")");
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
updateValuesDisplay() {
|
||||
@ -329,7 +315,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
ptsreve.innerHTML = this.actor.data.data.reve.reve.value;
|
||||
|
||||
let tmrpos = document.getElementById("tmr-pos");
|
||||
let tmr = TMRUtility.getTMRDescription(this.actor.data.data.reve.tmrpos.coord);
|
||||
let tmr = TMRUtility.getTMR(this.actor.data.data.reve.tmrpos.coord);
|
||||
tmrpos.innerHTML = this.actor.data.data.reve.tmrpos.coord + " (" + tmr.label + ")";
|
||||
|
||||
let etat = document.getElementById("tmr-etatgeneral-value");
|
||||
@ -354,7 +340,8 @@ export class RdDTMRDialog extends Dialog {
|
||||
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) } );
|
||||
whisper: ChatMessage.getWhisperRecipients(game.user.name)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -378,7 +365,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async manageCaseHumide(cellDescr, coordTMR) {
|
||||
if (this.viewOnly) {
|
||||
if (this.viewOnly || this.currentRencontre) {
|
||||
return;
|
||||
}
|
||||
let isHumide = this.actor.checkIsAdditionnalHumide(cellDescr, coordTMR);
|
||||
@ -386,7 +373,8 @@ export class RdDTMRDialog extends Dialog {
|
||||
if (this.isCaseMaitrisee(coordTMR)) {
|
||||
ChatMessage.create({
|
||||
content: "Cette case humide est déja maitrisée grâce à votre Tête <strong>Quête des Eaux</strong>",
|
||||
whisper: ChatMessage.getWhisperRecipients(game.user.name) } );
|
||||
whisper: ChatMessage.getWhisperRecipients(game.user.name)
|
||||
});
|
||||
return;
|
||||
}
|
||||
// TODO: permettre de choisir la voie de draconic?
|
||||
@ -469,7 +457,8 @@ export class RdDTMRDialog extends Dialog {
|
||||
msg += "</ol>";
|
||||
ChatMessage.create({
|
||||
content: msg,
|
||||
whisper: ChatMessage.getWhisperRecipients(game.user.name) } );
|
||||
whisper: ChatMessage.getWhisperRecipients(game.user.name)
|
||||
});
|
||||
} else {
|
||||
await this.processSortReserve(sortReserveList[0]);
|
||||
}
|
||||
@ -485,7 +474,8 @@ export class RdDTMRDialog extends Dialog {
|
||||
} else {
|
||||
ChatMessage.create({
|
||||
content: "Une erreur est survenue : impossible de récupérer le sort en réserve demandé.",
|
||||
whisper: ChatMessage.getWhisperRecipients(game.user.name) } );
|
||||
whisper: ChatMessage.getWhisperRecipients(game.user.name)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -495,7 +485,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
this.updateSortReserve();
|
||||
console.log("declencheSortEnReserve", sortReserve)
|
||||
const declenchementSort = "Vous avez déclenché le sort <strong>" + sortReserve.sort.name
|
||||
+ "</strong> en réserve en " + sortReserve.coord + " (" + TMRUtility.getTMRDescription(sortReserve.coord).label
|
||||
+ "</strong> en réserve en " + sortReserve.coord + " (" + TMRUtility.getTMR(sortReserve.coord).label
|
||||
+ ") avec " + sortReserve.sort.data.ptreve_reel + " points de Rêve";
|
||||
this._tellToGM(declenchementSort);
|
||||
this.close();
|
||||
@ -515,15 +505,14 @@ export class RdDTMRDialog extends Dialog {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
processClickPostRencontre(coord) {
|
||||
let deplacementType = "erreur";
|
||||
if (this.rencontreState == 'passeur' || this.rencontreState == 'messager' || this.rencontreState == 'changeur') {
|
||||
console.log("Searching", this.currentRencontre.locList, coord);
|
||||
let isInArea = this.currentRencontre.locList.find(locCoord => locCoord == coord);
|
||||
if (isInArea) { // OK !
|
||||
deplacementType = (this.rencontreState == 'messager') ? 'messager' : 'saut';
|
||||
return (this.rencontreState == 'messager') ? 'messager' : 'saut';
|
||||
}
|
||||
}
|
||||
return deplacementType;
|
||||
return "erreur";
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -540,7 +529,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
checkConnaissanceFleuve(currentTMR, nextTMR) {
|
||||
if (this.actor.isConnaissanceFleuve()) {
|
||||
//console.log(currentTMR, nextTMR );
|
||||
if ( TMRUtility.getTMRDescription(currentTMR).type == 'fleuve' && TMRUtility.getTMRDescription(nextTMR).type == 'fleuve') {
|
||||
if (TMRUtility.getTMR(currentTMR).type == 'fleuve' && TMRUtility.getTMR(nextTMR).type == 'fleuve') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -577,7 +566,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
if (deplacementType == 'normal' || deplacementType == 'saut') {
|
||||
if (myself.currentRencontre != 'normal')
|
||||
myself.nettoyerRencontre();
|
||||
let cellDescr = TMRUtility.getTMRDescription(coordTMR);
|
||||
let cellDescr = TMRUtility.getTMR(coordTMR);
|
||||
|
||||
await myself.manageCaseSpeciale(cellDescr, coordTMR); // Gestion cases spéciales type Trou noir, etc
|
||||
|
||||
@ -629,8 +618,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
async forceDemiRevePosition(coordTMR) {
|
||||
await this.actor.updateCoordTMR(coordTMR);
|
||||
this._updateDemiReve(this);
|
||||
let cellDescr = TMRUtility.getTMRDescription(coordTMR);
|
||||
await this.manageRencontre(coordTMR, cellDescr);
|
||||
let cellDescr = TMRUtility.getTMR(coordTMR);
|
||||
this.manageCaseHumide(cellDescr, coordTMR);
|
||||
await this.declencheSortEnReserve(coordTMR);
|
||||
}
|
||||
@ -699,7 +687,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
// Le reste...
|
||||
this.updateValuesDisplay();
|
||||
let coordTMR = this.actor.data.data.reve.tmrpos.coord;
|
||||
let cellDescr = TMRUtility.getTMRDescription(coordTMR);
|
||||
let cellDescr = TMRUtility.getTMR(coordTMR);
|
||||
await this.manageRencontre(coordTMR, cellDescr);
|
||||
this.manageCaseHumide(cellDescr, coordTMR);
|
||||
// Mise à jour du nb de cases de Fatigue
|
||||
|
@ -2,10 +2,10 @@
|
||||
export class RdDTMRRencontreDialog extends Dialog {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(html, tmrApp, rencontreData) {
|
||||
constructor(html, tmrApp, rencontre) {
|
||||
const dialogConf = {
|
||||
title: "Rencontre en TMR!",
|
||||
content: "Vous recontrez un " + rencontreData.name + " de force " + rencontreData.force + "<br>",
|
||||
content: "Vous recontrez un " + rencontre.name + " de force " + rencontre.force + "<br>",
|
||||
buttons: {
|
||||
derober: { icon: '<i class="fas fa-check"></i>', label: "Se dérober", callback: () => { this.toClose = true; this.tmrApp.derober() } },
|
||||
refouler: { icon: '<i class="fas fa-check"></i>', label: "Refouler", callback: () => { this.toClose = true; this.tmrApp.refouler() } },
|
||||
@ -13,6 +13,9 @@ export class RdDTMRRencontreDialog extends Dialog {
|
||||
},
|
||||
default: "derober"
|
||||
}
|
||||
if (rencontre.ignorer) {
|
||||
dialogConf.buttons.ignorer = { icon: '<i class="fas fa-check"></i>', label: "Ignorer", callback: () => { this.toClose = true; this.tmrApp.ignorerRencontre() }};
|
||||
}
|
||||
|
||||
const dialogOptions = {
|
||||
classes: ["tmrrencdialog"],
|
||||
@ -22,7 +25,7 @@ export class RdDTMRRencontreDialog extends Dialog {
|
||||
super(dialogConf, dialogOptions);
|
||||
|
||||
this.toClose = false;
|
||||
this.rencontreData = duplicate(rencontreData);
|
||||
this.rencontreData = duplicate(rencontre);
|
||||
this.tmrApp = tmrApp;
|
||||
this.tmrApp.minimize();
|
||||
}
|
||||
|
@ -114,6 +114,12 @@ export const referenceAjustements = {
|
||||
bonusCase: {
|
||||
isUsed: (rollData, actor) => rollData.selectedSort && rollData.coord,
|
||||
getDescr: (rollData, actor) => rollData.selectedSort && rollData.coord ? `Bonus de case: ${RdDItemSort.getCaseBonus(rollData.selectedSort, rollData.coord)}%` : ''
|
||||
},
|
||||
rencontreTMR: {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
487
module/tmr-rencontres.js
Normal file
487
module/tmr-rencontres.js
Normal file
@ -0,0 +1,487 @@
|
||||
import { DeDraconique } from "./de-draconique.js";
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { TMRUtility } from "./tmr-utility.js";
|
||||
import { TMRType } from "./tmr-utility.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
const typeRencontres = {
|
||||
|
||||
messager: {
|
||||
msgSucces: (data) => `Le ${data.rencontre.name} vous propose d'emmener le message de votre un sort à ${data.rencontre.force} cases ${data.tmr.label}.`,
|
||||
msgEchec: (data) => `Le ${data.rencontre.name} est pressé et continue son chemin d'une traite sans vous accorder un regard.`,
|
||||
postSucces: (tmrDialog, data) => {
|
||||
tmrDialog.setStateRencontre(data.rencontre.type);
|
||||
tmrDialog.choisirCasePortee(data.tmr.coord, data.rencontre.force);
|
||||
},
|
||||
poesieSucces: {
|
||||
reference: "La chevelure, Charles Baudelaire",
|
||||
extrait: `J'irai là-bas où l'arbre et l'homme, pleins de sève,
|
||||
<br>Se pâment longuement sous l'ardeur des climats ;
|
||||
<br>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: (data) => `Le ${data.rencontre.name} vous propose de vous transporter à ${data.rencontre.force} cases des ${data.tmr.label}.`,
|
||||
msgEchec: (data) => `Le prix que demande le ${data.rencontre.name} est trop élevé, vous êtes réduit à poursuivre votre chemin par vos propres moyens.`,
|
||||
postSucces: (tmrDialog, data) => {
|
||||
tmrDialog.setStateRencontre(data.rencontre.type);
|
||||
tmrDialog.choisirCasePortee(data.tmr.coord, data.rencontre.force);
|
||||
},
|
||||
poesieSucces: {
|
||||
reference: "Femmes damnées (2), Charles Baudelaire",
|
||||
extrait: `Comme je descendais des Fleuves impassibles,
|
||||
<br>Je ne me sentis plus guidé par les haleurs :
|
||||
<br>Des Peaux-Rouges criards les avaient pris pour cibles,
|
||||
<br>Les ayant cloués nus aux poteaux de couleurs.`},
|
||||
poesieEchec: {
|
||||
reference: "Le bateau ivre, Arthur Rimbaud",
|
||||
extrait: `Loin des peuples vivants, errantes, condamnées,
|
||||
<br>A travers les déserts courez comme les loups ;
|
||||
<br>Faites votre destin, âmes désordonnées,
|
||||
<br>Et fuyez l'infini que vous portez en vous !`}
|
||||
},
|
||||
|
||||
fleur: {
|
||||
msgSucces: (data) => `Vous cueillez la ${data.rencontre.name}, son parfum vous apporte ${data.rencontre.force} points de Rêve.`,
|
||||
msgEchec: (data) => `La ${data.rencontre.name} se fâne et disparaît entre vos doigts.`,
|
||||
postSucces: (tmrDialog, data) => tmrDialog.actor.reveActuelIncDec(data.rencontre.force),
|
||||
poesieSucces: {
|
||||
reference: "L'Ennemi, Charles Baudelaire",
|
||||
extrait: `Et qui sait si les fleurs nouvelles que je rêve
|
||||
<br>Trouveront dans ce sol lavé comme une grève
|
||||
<br>Le mystique aliment qui ferait leur vigueur ?`},
|
||||
poesieEchec: {
|
||||
reference: "Une charogne, Charles Baudelaire",
|
||||
extrait: `Et le ciel regardait la carcasse superbe
|
||||
<br>Comme une fleur s'épanouir.
|
||||
<br>La puanteur était si forte, que sur l'herbe
|
||||
<br>Vous crûtes vous évanouir.`},
|
||||
},
|
||||
|
||||
mangeur: {
|
||||
msgSucces: (data) => `Le ${data.rencontre.name} claque de sa machoire dans le vide avant de fuir.`,
|
||||
msgEchec: (data) => `Le ${data.rencontre.name} croque votre Rêve ! Il emporte ${data.rencontre.force} de vos points de rêve actuels`,
|
||||
postEchec: (tmrDialog, data) => tmrDialog.actor.reveActuelIncDec(-data.rencontre.force),
|
||||
poesieSucces: {
|
||||
reference: "Conseil, Victor Hugo",
|
||||
extrait: `Rois ! la bure est souvent jalouse du velours.
|
||||
<br>Le peuple a froid l'hiver, le peuple a faim toujours.
|
||||
<br>Rendez-lui son sort plus facile.
|
||||
<br>Le peuple souvent porte un bien rude collier.
|
||||
<br>Ouvrez l'école aux fils, aux pères l'atelier,
|
||||
<br>À tous vos bras, auguste asile !`},
|
||||
poesieEchec: {
|
||||
reference: "El Desdichado, Gérard de Nerval",
|
||||
extrait: `Suis-je Amour ou Phébus ?... Lusignan ou Biron ?
|
||||
<br>Mon front est rouge encor du baiser de la Reine ;
|
||||
<br>J'ai rêvé dans la Grotte où nage la sirène...`}
|
||||
},
|
||||
|
||||
changeur: {
|
||||
msgSucces: (data) => `Le ${data.rencontre.name} vaincu accepte de vous déplacer sur une autre ${TMRType[data.tmr.type]} de votre choix en échange de sa liberté.`,
|
||||
msgEchec: (data) => {
|
||||
data.newTMR = TMRUtility.getTMRAleatoire(data.tmr.type);
|
||||
return `Le ${data.rencontre.name} vous embobine avec des promesses, et vous transporte en ${data.newTMR.label} sans attendre votre avis.`;
|
||||
},
|
||||
postSucces: (tmrDialog, data) => {
|
||||
tmrDialog.setStateRencontre(data.rencontre.type);
|
||||
tmrDialog.choisirCaseType(data.tmr.type);
|
||||
},
|
||||
postEchec: (tmrDialog, data) => tmrDialog.forceDemiRevePosition(data.newTMR.coord),
|
||||
poesieSucces: {
|
||||
reference: "Caligula - IIIème chant, Gérard de Nerval",
|
||||
extrait: `Allez, que le caprice emporte
|
||||
<br>Chaque âme selon son désir,
|
||||
<br>Et que, close après vous, la porte
|
||||
<br>Ne se rouvre plus qu'au plaisir.`},
|
||||
poesieEchec: {
|
||||
reference: "Rêve de Dragon, Denis Gerfaud",
|
||||
extrait: `Les sages ont encore coutume de dire :
|
||||
<br>« 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: (data) => `Le ${data.rencontre.name} tente vainement de vous déconcentrer, avant de fuir sans demander son reste.`,
|
||||
msgEchec: (data) => `Le ${data.rencontre.name} vous déconcentre au point de briser votre demi-rêve.`,
|
||||
postEchec: (tmrDialog, data) => 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,
|
||||
<br>Dans la plainte du jour,
|
||||
<br>Ma mémoire devient grise
|
||||
<br>Et sombre, tour à tour,
|
||||
<br>Dans le puits du silence
|
||||
<br>Et de la solitude ;
|
||||
<br>Elle reprend son errance
|
||||
<br>Parmi la multitude.`}
|
||||
},
|
||||
|
||||
reflet: {
|
||||
msgSucces: (data) => `Le ${data.rencontre.name} s'estompe dans l'oubli.`,
|
||||
msgEchec: (data) => `Vous êtes submergé par un ${data.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,
|
||||
<br>Une ébauche lente à venir
|
||||
<br>Sur la toile oubliée, et que l'artiste achève
|
||||
<br>Seulement par le souvenir.`},
|
||||
poesieEchec: {
|
||||
reference: "La chevelure, Charles Baudelaire",
|
||||
extrait: `Longtemps ! toujours ! ma main dans ta crinière lourde
|
||||
<br>Sèmera le rubis, la perle et le saphir,
|
||||
<br>Afin qu'à mon désir tu ne sois jamais sourde !
|
||||
<br>N'es-tu pas l'oasis où je rêve, et la gourde
|
||||
<br>Où je hume à longs traits le vin du souvenir`}
|
||||
},
|
||||
|
||||
passeurfou: {
|
||||
msgSucces: (data) => `Le ${data.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: (data) => TMRRencontres.msgEchecPasseurFou(data),
|
||||
postEchec: (tmrDialog, data) => TMRRencontres.postEchecPasseurFou(tmrDialog, data),
|
||||
poesieSucces: {
|
||||
reference: "Un Fou et un Sage, Jean de La Fontaine",
|
||||
extrait: `Certain Fou poursuivait à coups de pierre un Sage.
|
||||
<br>Le Sage se retourne et lui dit : Mon ami,
|
||||
<br>C'est fort bien fait à toi ; reçois cet écu-ci :
|
||||
<br>Tu fatigues assez pour gagner davantage.`},
|
||||
poesieEchec: {
|
||||
reference: "Guitare, Victor Hugo",
|
||||
extrait: `Je la voyais passer de ma demeure,
|
||||
<br>Et c'était tout.
|
||||
<br>Mais à présent je m'ennuie à toute heure,
|
||||
<br>Plein de dégoût,
|
||||
<br>Rêveur oisif, l'âme dans la campagne,
|
||||
<br>La dague au clou ... –
|
||||
<br>Le vent qui vient à travers la montagne
|
||||
<br>M'a rendu fou !`}
|
||||
},
|
||||
|
||||
tbblanc: {
|
||||
msgSucces: (data) => `Le ${data.rencontre.name} souleve une poussière blanche, vous tenez bon, et il tourbillonne en s'éloignant.`,
|
||||
msgEchec: (data) => `Le souffle du ${data.rencontre.name} vous déstabilise et vous emmène dans un nuage de poussière.`,
|
||||
postEchec: (tmrDialog, data) => TMRRencontres.onPostEchecTourbillon(tmrDialog, data, 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,
|
||||
<br>Et tourbillonne en sifflant !
|
||||
<br>Les ifs, que leur vol fracasse,
|
||||
<br>Craquent comme un pin brûlant.`},
|
||||
},
|
||||
|
||||
tbnoir: {
|
||||
msgSucces: (data) => `Le ${data.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: (data) => `Le ${data.rencontre.name} furieux vous secoue tel un fichu de paille malmené par les vents, et vous emporte dans la tourmente.`,
|
||||
postEchec: (tmrDialog, data) => TMRRencontres.onPostEchecTourbillon(tmrDialog, data, 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
|
||||
<br>Que la couleur du désespoir
|
||||
<br>Là-bas aussi ce fût le noir.`},
|
||||
},
|
||||
|
||||
tbrouge: {
|
||||
msgSucces: (data) => `Le ${data.rencontre.name} s'abat avec violence mais vous êtes plus rapide et parvenez à lui échapper.`,
|
||||
msgEchec: (data) => `Le ${data.rencontre.name} vous frappe de milliers de morsure et vous malmène à travers les terres médianes.`,
|
||||
postEchec: (tmrDialog, data) => TMRRencontres.onPostEchecTourbillonRouge(tmrDialog, data),
|
||||
poesieSucces: {
|
||||
reference: "Qu'est-ce de votre vie ? une bouteille molle, Jean-Baptiste Chassignet",
|
||||
extrait: `Qu'est-ce de votre vie ? un tourbillon rouant
|
||||
<br>De fumière à flot gris, parmi l'air se jouant,
|
||||
<br>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 !
|
||||
<br>L'horrible essaim, poussé par l'aquilon,
|
||||
<br>Sans doute, ô ciel ! s'abat sur ma demeure.
|
||||
<br>Le mur fléchit sous le noir bataillon.
|
||||
<br>La maison crie et chancelle penchée,
|
||||
<br>Et l'on dirait que, du sol arrachée,
|
||||
<br>Ainsi qu'il chasse une feuille séchée,
|
||||
<br>Le vent la roule avec leur tourbillon !`},
|
||||
},
|
||||
|
||||
rdd: {
|
||||
msgSucces: (data) => TMRRencontres.onSuccessReveDeDragon(data),
|
||||
msgEchec: (data) => TMRRencontres.onEchecReveDeDragon(data),
|
||||
postEchec: (tmrDialog, data) => tmrDialog.close(),
|
||||
poesieSucces: {
|
||||
reference: "Rêve de Dragon, Denis Gerfaud",
|
||||
extrait: `Le monde est Rêve de Dragons, mais nous ne savons
|
||||
<br>ni leur apparence ni qui sont les dragons.
|
||||
<br>En dépit de l'iconographie qui les clame
|
||||
<br>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é,
|
||||
<br>Le Prince d'Aquitaine à la Tour abolie :
|
||||
<br>Ma seule Etoile est morte, – et mon luth constellé
|
||||
<br>Porte le Soleil noir de la Mélancolie.`}
|
||||
},
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
const mauvaisesRencontres = [
|
||||
{ code: "mangeur1d6", 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: "reflet2d6+4", name: "Reflet d'ancien Rêve", type: "reflet", genre: "m", force: "2d6+4", refoulement: 2, isPersistant: true, isMauvaise: true },
|
||||
{ code: "tbblanc2d6+4", name: "Tourbillon blanc", type: "tbblanc", genre: "m", force: "2d6+4", refoulement: 2, isPersistant: true, isMauvaise: true },
|
||||
{ code: "tbnoir2d8+4", name: "Tourbillon noir", type: "tbnoir", genre: "m", force: "2d8+4", refoulement: 2, isPersistant: true, isMauvaise: true },
|
||||
{ code: "passfou2d8", name: "Passeur fou", type: "passeurfou", genre: "m", force: "2d8", refoulement: 2, isMauvaise: true },
|
||||
{ code: "tbrouge2d8", name: "Tourbillon rouge", type: "tbrouge", genre: "m", force: "2d8", refoulement: 3, isPersistant: true, isMauvaise: true }
|
||||
]
|
||||
|
||||
/* -------------------------------------------- */
|
||||
const rencontresStandard = [
|
||||
{ code: "messager2d4", name: "Messager des Rêves", type: "messager", genre: "m", force: "2d4", ignorer: true },
|
||||
{ code: "passeur2d4", name: "Passeur des Rêves", type: "passeur", genre: "m", force: "2d4", ignorer: true },
|
||||
{ code: "fleur1d6", name: "Fleur des Rêves", type: "fleur", genre: "f", force: "1d6", ignorer: true },
|
||||
{ code: "mangeur1d6", name: "Mangeur de Rêve", type: "mangeur", genre: "m", force: "1d6" },
|
||||
{ code: "changeur2d6", name: "Changeur de Rêve", type: "changeur", genre: "m", force: "2d6" },
|
||||
{ code: "briseur2d6", name: "Briseur de Rêve", type: "briseur", genre: "m", force: "2d6", quitterTMR: true },
|
||||
{ code: "reflet1d6", name: "Reflet d'ancien Rêve", type: "reflet", genre: "m", force: "2d6", isPersistant: true },
|
||||
{ code: "tbblanc2d6", name: "Tourbillon blanc", type: "tbblanc", genre: "m", force: "2d6", isPersistant: true },
|
||||
{ code: "tbnoir2d8", name: "Tourbillon noir", type: "tbnoir", genre: "m", force: "2d8", isPersistant: true },
|
||||
{ code: "rdd1ddr+7", name: "Rêve de Dragon", type: "rdd", genre: "m", force: "1ddr + 7", refoulement: 2, quitterTMR: true }
|
||||
];
|
||||
|
||||
const tableRencontres = {
|
||||
cite: [{ code: 'messager2d4', range: [1, 25] }, { code: 'passeur2d4', range: [26, 50] }, { code: 'fleur1d6', range: [51, 65] }, { code: 'mangeur1d6', range: [66, 70] }, { code: 'changeur2d6', range: [71, 80] }, { code: 'briseur2d6', range: [81, 85] }, { code: 'reflet2d6', range: [86, 90] }, { code: 'tbblanc2d6', range: [91, 94] }, { code: 'tbnoir2d8', range: [95, 97] }, { code: 'rdd1ddr+7', range: [98, 100] }],
|
||||
sanctuaire: [{ code: 'messager2d4', range: [1, 25] }, { code: 'passeur2d4', range: [26, 50] }, { code: 'fleur1d6', range: [51, 65] }, { code: 'mangeur1d6', range: [66, 70] }, { code: 'changeur2d6', range: [71, 80] }, { code: 'briseur2d6', range: [81, 85] }, { code: 'reflet2d6', range: [86, 90] }, { code: 'tbblanc2d6', range: [91, 94] }, { code: 'tbnoir2d8', range: [95, 97] }, { code: 'rdd1ddr+7', range: [98, 100] }],
|
||||
plaines: [{ code: 'messager2d4', range: [1, 20] }, { code: 'passeur2d4', range: [21, 40] }, { code: 'fleur1d6', range: [41, 55] }, { code: 'mangeur1d6', range: [56, 60] }, { code: 'changeur2d6', range: [61, 75] }, { code: 'briseur2d6', range: [76, 82] }, { code: 'reflet2d6', range: [83, 88] }, { code: 'tbblanc2d6', range: [89, 93] }, { code: 'tbnoir2d8', range: [94, 97] }, { code: 'rdd1ddr+7', range: [98, 100] }],
|
||||
pont: [{ code: 'messager2d4', range: [1, 20] }, { code: 'passeur2d4', range: [21, 40] }, { code: 'fleur1d6', range: [41, 55] }, { code: 'mangeur1d6', range: [56, 60] }, { code: 'changeur2d6', range: [61, 75] }, { code: 'briseur2d6', range: [76, 82] }, { code: 'reflet2d6', range: [83, 88] }, { code: 'tbblanc2d6', range: [89, 93] }, { code: 'tbnoir2d8', range: [94, 97] }, { code: 'rdd1ddr+7', range: [98, 100] }],
|
||||
collines: [{ code: 'messager2d4', range: [1, 15] }, { code: 'passeur2d4', range: [16, 30] }, { code: 'fleur1d6', range: [31, 42] }, { code: 'mangeur1d6', range: [43, 54] }, { code: 'changeur2d6', range: [55, 69] }, { code: 'briseur2d6', range: [70, 82] }, { code: 'reflet2d6', range: [83, 88] }, { code: 'tbblanc2d6', range: [89, 93] }, { code: 'tbnoir2d8', range: [94, 97] }, { code: 'rdd1ddr+7', range: [98, 100] }],
|
||||
foret: [{ code: 'messager2d4', range: [1, 15] }, { code: 'passeur2d4', range: [16, 30] }, { code: 'fleur1d6', range: [31, 42] }, { code: 'mangeur1d6', range: [43, 54] }, { code: 'changeur2d6', range: [55, 69] }, { code: 'briseur2d6', range: [70, 82] }, { code: 'reflet2d6', range: [83, 88] }, { code: 'tbblanc2d6', range: [89, 93] }, { code: 'tbnoir2d8', range: [94, 97] }, { code: 'rdd1ddr+7', range: [98, 100] }],
|
||||
monts: [{ code: 'messager2d4', range: [1, 10] }, { code: 'passeur2d4', range: [11, 20] }, { code: 'fleur1d6', range: [21, 26] }, { code: 'mangeur1d6', range: [27, 44] }, { code: 'changeur2d6', range: [45, 59] }, { code: 'briseur2d6', range: [60, 75] }, { code: 'reflet2d6', range: [76, 85] }, { code: 'tbblanc2d6', range: [86, 92] }, { code: 'tbnoir2d8', range: [93, 97] }, { code: 'rdd1ddr+7', range: [98, 100] }],
|
||||
desert: [{ code: 'messager2d4', range: [1, 10] }, { code: 'passeur2d4', range: [11, 20] }, { code: 'fleur1d6', range: [21, 26] }, { code: 'mangeur1d6', range: [27, 44] }, { code: 'changeur2d6', range: [45, 59] }, { code: 'briseur2d6', range: [60, 75] }, { code: 'reflet2d6', range: [76, 85] }, { code: 'tbblanc2d6', range: [86, 92] }, { code: 'tbnoir2d8', range: [93, 97] }, { code: 'rdd1ddr+7', range: [98, 100] }],
|
||||
fleuve: [{ code: 'messager2d4', range: [1, 5] }, { code: 'passeur2d4', range: [6, 10] }, { code: 'fleur1d6', range: [11, 13] }, { code: 'mangeur1d6', range: [14, 37] }, { code: 'changeur2d6', range: [38, 49] }, { code: 'briseur2d6', range: [50, 65] }, { code: 'reflet2d6', range: [66, 79] }, { code: 'tbblanc2d6', range: [80, 89] }, { code: 'tbnoir2d8', range: [90, 97] }, { code: 'rdd1ddr+7', range: [98, 100] }],
|
||||
lac: [{ code: 'messager2d4', range: [1, 5] }, { code: 'passeur2d4', range: [6, 10] }, { code: 'fleur1d6', range: [11, 13] }, { code: 'mangeur1d6', range: [14, 37] }, { code: 'changeur2d6', range: [38, 49] }, { code: 'briseur2d6', range: [50, 65] }, { code: 'reflet2d6', range: [66, 79] }, { code: 'tbblanc2d6', range: [80, 89] }, { code: 'tbnoir2d8', range: [90, 97] }, { code: 'rdd1ddr+7', range: [98, 100] }],
|
||||
marais: [{ code: 'messager2d4', range: [1, 2] }, { code: 'passeur2d4', range: [3, 4] }, { code: 'fleur1d6', range: [5, 5] }, { code: 'mangeur1d6', range: [6, 29] }, { code: 'changeur2d6', range: [30, 39] }, { code: 'briseur2d6', range: [40, 60] }, { code: 'reflet2d6', range: [61, 75] }, { code: 'tbblanc2d6', range: [76, 86] }, { code: 'tbnoir2d8', range: [87, 97] }, { code: 'rdd1ddr+7', range: [98, 100] }],
|
||||
gouffre: [{ code: 'messager2d4', range: [1, 2] }, { code: 'passeur2d4', range: [3, 4] }, { code: 'fleur1d6', range: [5, 5] }, { code: 'mangeur1d6', range: [6, 29] }, { code: 'changeur2d6', range: [30, 39] }, { code: 'briseur2d6', range: [40, 60] }, { code: 'reflet2d6', range: [61, 75] }, { code: 'tbblanc2d6', range: [76, 86] }, { code: 'tbnoir2d8', range: [87, 97] }, { code: 'rdd1ddr+7', range: [98, 100] }],
|
||||
necropole: [{ code: 'mangeur1d6', range: [1, 20] }, { code: 'changeur2d6', range: [21, 30] }, { code: 'briseur2d6', range: [31, 50] }, { code: 'reflet2d6', range: [51, 65] }, { code: 'tbblanc2d6', range: [66, 80] }, { code: 'tbnoir2d8', range: [81, 97] }, { code: 'rdd1ddr+7', range: [98, 100] }],
|
||||
desolation: [{ code: 'mangeur1d6', range: [1, 20] }, { code: 'changeur2d6', range: [21, 30] }, { code: 'briseur2d6', range: [31, 50] }, { code: 'reflet2d6', range: [51, 65] }, { code: 'tbblanc2d6', range: [66, 80] }, { code: 'tbnoir2d8', range: [81, 97] }, { code: 'rdd1ddr+7', 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
|
||||
*/
|
||||
static async rollRencontre(terrain, roll = undefined) {
|
||||
if (!terrain) {
|
||||
ChatMessage.create({ content: "Un type de case doit être indiqué (par exemple sanctuaire, desert ou cité)" });
|
||||
return false;
|
||||
}
|
||||
if (!roll || roll <= 0 || roll > 100) {
|
||||
roll = new Roll("1d100").evaluate().total;
|
||||
}
|
||||
let rencontre = TMRRencontres.getRencontreAleatoire(terrain, roll);
|
||||
ChatMessage.create({
|
||||
user: game.user._id,
|
||||
whisper: [game.user._id],
|
||||
content: `Rencontre en ${terrain} (jet : ${roll}%)<br>Vous rencontrez un ${rencontre.name} de ${force} Points de Rêve`
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getRencontre(index) {
|
||||
let rencontre;
|
||||
if (isNaN(index)) {
|
||||
rencontre = rencontresStandard.find(r => r.type == index)
|
||||
if (!rencontre) {
|
||||
rencontre = mauvaisesRencontres.find(r => r.type == index)
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (0 <= index && index < rencontresStandard.length) {
|
||||
rencontre = rencontresStandard[index];
|
||||
}
|
||||
else if (rencontresStandard.length <= index && index < rencontresStandard.length + mauvaisesRencontres.length) {
|
||||
rencontre = mauvaisesRencontres[index - rencontresStandard.length];
|
||||
}
|
||||
}
|
||||
if (rencontre) {
|
||||
return duplicate(rencontre);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async getRencontreAleatoire(terrain, roll = undefined) {
|
||||
if (!roll || roll <= 0 || roll > 100) {
|
||||
roll = new Roll("1d100").evaluate().total;
|
||||
}
|
||||
terrain = Grammar.toLowerCaseNoAccent(terrain);
|
||||
console.log("getRencontreAleatoire", terrain, roll);
|
||||
const code = tableRencontres[terrain].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);
|
||||
return rencontre;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async getMauvaiseRencontre(index = undefined) {
|
||||
if (index == undefined || index >= mauvaisesRencontres.length) {
|
||||
index = new Roll("1d" + mauvaisesRencontres.length).roll().total - 1;
|
||||
}
|
||||
const rencontre = duplicate(mauvaisesRencontres[index]);
|
||||
await TMRRencontres.evaluerForceRencontre(rencontre);
|
||||
return rencontre;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async evaluerForceRencontre(rencontre) {
|
||||
if (TMRRencontres.isReveDeDragon(rencontre)) {
|
||||
rencontre.force = await DeDraconique.ddr("selfroll").total + 7;
|
||||
}
|
||||
else {
|
||||
rencontre.force = new Roll(rencontre.force).evaluate().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, data) {
|
||||
let gestion = TMRRencontres.getGestionRencontre(data.rencontre.type);
|
||||
if (data.rolled.isSuccess) {
|
||||
data.message = gestion.msgSucces(data);
|
||||
if (data.nbRounds > 1) {
|
||||
data.message += ` Au total, vous avez passé ${data.nbRounds} rounds à vous battre!`;
|
||||
}
|
||||
data.poesie = gestion.poesieSucces;
|
||||
return gestion.postSucces;
|
||||
}
|
||||
|
||||
data.message = gestion.msgEchec(data);
|
||||
if (data.nbRounds > 1) {
|
||||
data.message += ` Vous avez passé ${data.nbRounds} rounds à lutter!`;
|
||||
}
|
||||
data.poesie = gestion.poesieEchec;
|
||||
return gestion.postEchec;
|
||||
}
|
||||
|
||||
static msgEchecPasseurFou(data) {
|
||||
data.sortReserve = data.actor.data.data.reve.reserve.list[0];
|
||||
if (data.sortReserve) {
|
||||
// Passeur fou positionne sur la case d'un ort en réserve // TODO : Choisir le sort le plus loin ou au hasard
|
||||
data.newTMR = TMRUtility.getTMR(data.sortReserve.coord);
|
||||
} else {
|
||||
// Déplacement aléatoire de la force du Passeur Fou
|
||||
const locList = TMRUtility.getTMRPortee(data.tmr.coord, data.rencontre.force);
|
||||
const newCoord = locList[new Roll("1d" + locList.length).evaluate().total - 1];
|
||||
data.newTMR = TMRUtility.getTMR(newCoord);
|
||||
}
|
||||
if (data.sortReserve) {
|
||||
return `Le ${data.rencontre.name} vous dérobe la clé de vos sorts. Vous vous saisissez de lui, mais dans un nuage violet, il vous emporte en ${data.newTMR.label} déclencher votre sort en réserve de ${data.sortReserve.name}.`;
|
||||
}
|
||||
else {
|
||||
return `Le ${data.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 ${data.newTMR.label}`;
|
||||
}
|
||||
}
|
||||
|
||||
static async postEchecPasseurFou(tmrDialog, data) {
|
||||
if (data.sortReserve) {
|
||||
await tmrDialog.processSortReserve(data.sortReserve);
|
||||
}
|
||||
await tmrDialog.forceDemiRevePosition(data.newTMR.coord);
|
||||
if (data.sortReserve) {
|
||||
tmrDialog.close();
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async onPostEchecTourbillon(tmrDialog, data, cases) {
|
||||
await data.actor.reveActuelIncDec(-cases);
|
||||
await TMRRencontres._toubillonner(tmrDialog, data.actor, cases);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async onPostEchecTourbillonRouge(tmrDialog, data) {
|
||||
await data.actor.reveActuelIncDec(-2); // -2 pts de Reve a chaque itération
|
||||
TMRRencontres._toubillonner(tmrDialog, data.actor, 4);
|
||||
await data.actor.santeIncDec("vie", -1); // Et -1 PV
|
||||
}
|
||||
|
||||
static async _toubillonner(tmrDialog, actor, cases) {
|
||||
let coord = actor.data.data.reve.tmrpos.coord;
|
||||
for (let i = 0; i < cases; i++) {
|
||||
coord = TMRUtility.deplaceTMRAleatoire(coord);
|
||||
}
|
||||
await tmrDialog.forceDemiRevePosition(coord)
|
||||
}
|
||||
|
||||
static async onSuccessReveDeDragon(data) {
|
||||
await data.actor.appliquerReveDeDragon(data.rolled, data.rencontre.force);
|
||||
if (data.rolled.isPart) {
|
||||
await data.actor.appliquerExperience(data.rolled, 'reve', data.competence);
|
||||
}
|
||||
return `A tout seigneur, tout honneur, vous faites face à un ${data.rencontre.name}. Vous le maîtrisez et récupérez ses rêves. Vous gagnez ses ${data.rencontre.force} points de rêve, votre nouveau total est de " + tmrDialog.actor.data.data.reve.reve.value `;
|
||||
}
|
||||
|
||||
static async onEchecReveDeDragon(data) {
|
||||
await data.actor.appliquerReveDeDragon(data.rolled, data.rencontre.force);
|
||||
const queues = data.rolled.isETotal ? 'deux queues' : 'une queue';
|
||||
return `A tout seigneur, tout honneur, vous faites face à un ${data.rencontre.name}. La rencontre tourne au cauchemar, dans la lutte épique, vous subissez ${queues} de dragon!`;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { DeDraconique } from "./de-draconique.js";
|
||||
import { TMRRencontres } from "./tmr-rencontres.js";
|
||||
import { Grammar } from "./grammar.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -208,71 +209,55 @@ const TMRMapping = {
|
||||
M15: { type: "cite", label: "Cité de Klana"}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
const rencontresSpeciale = [
|
||||
{name:"Mangeur de Rêve", data: { force: "1d6", ignorer: false, derober: true, refoulement: 2, quitterTMR: false } },
|
||||
{name:"Mangeur de Rêve", data: { force: "2d6", ignorer: false, derober: true, refoulement: 2, quitterTMR: false } },
|
||||
{name:"Reflet d'ancien Rêve", data: { force: "2d6+4", ignorer: false, derober: true, refoulement: 2, quitterTMR: false } },
|
||||
{name:"Tourbillon blanc", data: { force: "2d6+4", ignorer: false, derober: true, refoulement: 2, quitterTMR: false } },
|
||||
{name:"Tourbillon noir", data: { force: "2d8+4", ignorer: false, derober: true, refoulement: 2, quitterTMR: false } },
|
||||
{name:"Passeur fou", data: { force: "2d8", ignorer: false, derober: true, refoulement: 2, quitterTMR: false } },
|
||||
{name:"Tourbillon rouge", data: { force: "2d8", ignorer: false, derober: true, refoulement: 3, quitterTMR: false } }
|
||||
]
|
||||
|
||||
/* -------------------------------------------- */
|
||||
const rencontresTable = [
|
||||
{name:"Messagers des Rêves", data: { force: "2d4", ignorer: true, derober: true, refoulement: 1, quitterTMR: false,
|
||||
cite: "01-25", sanctuaire: "01-25", plaines: "01-20", pont: "01-20", collines: "01-15", foret: "01-15", monts: "01-10", desert: "01-10", fleuve: "01-05",
|
||||
lac: "01-05", marais: "01-02", gouffre: "01-02", necropole: "00-00", desolation: "00-00" } },
|
||||
{name:"Passeur des Rêves", data: { force: "2d4", ignorer: true, derober: true, refoulement: 1, quitterTMR: false,
|
||||
cite: "26-50", sanctuaire: "26-50", plaines: "21-40", pont: "21-40", collines: "16-30", foret: "16-30", monts: "11-20", desert: "11-20", fleuve: "06-10",
|
||||
lac: "06-10", marais: "03-04", gouffre: "03-04", necropole: "00-00", desolation: "00-00" } },
|
||||
{name:"Fleur des Rêves", data: { force: "1d6", ignorer: true, derober: true, refoulement: 1, quitterTMR: false,
|
||||
cite: "51-65", sanctuaire: "51-65", plaines: "41-55", pont: "41-55", collines: "31-42", foret: "31-42", monts: "21-26", desert: "21-26", fleuve: "11-13",
|
||||
lac: "11-13", marais: "05-05", gouffre: "05-05", necropole: "00-00", desolation: "00-00" } },
|
||||
{name:"Mangeur de Rêve", data: { force: "1d6", ignorer: false, derober: true, refoulement: 1, quitterTMR: false,
|
||||
cite: "66-70", sanctuaire: "66-70", plaines: "56-60", pont: "56-60", collines: "43-54", foret: "43-54", monts: "27-44", desert: "27-44", fleuve: "14-37",
|
||||
lac: "14-37", marais: "06-29", gouffre: "06-29", necropole: "01-20", desolation: "01-20" } },
|
||||
{name:"Changeur de Rêve", data: { force: "2d6", ignorer: false, derober: true, refoulement: 1, quitterTMR: false,
|
||||
cite: "71-80", sanctuaire: "71-80", plaines: "61-75", pont: "61-75", collines: "55-69", foret: "55-69", monts: "45-59", desert: "45-59", fleuve: "38-49",
|
||||
lac: "38-49", marais: "30-39", gouffre: "30-39", necropole: "21-30", desolation: "21-30" } },
|
||||
{name:"Briseur de Rêve", data: { force: "2d6", ignorer: false, derober: true, refoulement: 1, quitterTMR: true,
|
||||
cite: "81-85", sanctuaire: "81-85", plaines: "76-82", pont: "76-82", collines: "70-82", foret: "70-82", monts: "60-75", desert: "60-75", fleuve: "50-65",
|
||||
lac: "50-65", marais: "40-60", gouffre: "40-60", necropole: "31-50", desolation: "31-50" } },
|
||||
{name:"Reflet d'ancien Rêve", data: { force: "2d6", ignorer: false, derober: true, refoulement: 1,quitterTMR: false,
|
||||
cite: "86-90", sanctuaire: "86-90", plaines: "83-88", pont: "83-88", collines: "83-88", foret: "83-88", monts: "76-85", desert: "76-85", fleuve: "66-79",
|
||||
lac: "66-79", marais: "61-75", gouffre: "61-75", necropole: "51-65", desolation: "51-65" } },
|
||||
{name:"Tourbillon blanc", data: { force: "2d6", ignorer: false, derober: true, refoulement: 1, quitterTMR: false,
|
||||
cite: "91-94", sanctuaire: "91-94", plaines: "89-93", pont: "89-93", collines: "89-93", foret: "89-93", monts: "86-92", desert: "86-92", fleuve: "80-89",
|
||||
lac: "80-89", marais: "76-86", gouffre: "76-86", necropole: "66-80", desolation: "66-80" } },
|
||||
{name:"Tourbillon noir", data: { force: "2d8", ignorer: false, derober: true, refoulement: 1, quitterTMR: false,
|
||||
cite: "95-97", sanctuaire: "95-97", plaines: "94-97", pont: "94-97", collines: "94-97", foret: "94-97", monts: "93-97", desert: "93-97", fleuve: "90-97",
|
||||
lac: "90-97", marais: "87-97", gouffre: "90-97", necropole: "81-97", desolation: "81-97" } },
|
||||
{name:"Rêve de Dragon", data: { force: "1ddr + 7", ignorer: false, derober: true, refoulement: 2, quitterTMR: true,
|
||||
cite: "98-00", sanctuaire: "98-00", plaines: "98-00", pont: "98-00", collines: "98-00", foret: "98-00", monts: "98-00", desert: "98-00", fleuve: "98-00",
|
||||
lac: "98-00", marais: "98-00", gouffre: "98-00", necropole: "98-00", desolation: "98-00" } }
|
||||
]
|
||||
export const TMRType = {
|
||||
cite: "cité",
|
||||
sanctuaire: "sanctuaire",
|
||||
plaines: "plaines",
|
||||
pont: "pont",
|
||||
collines: "collines",
|
||||
foret: "forêt",
|
||||
monts: "monts",
|
||||
desert: "désert",
|
||||
fleuve: "fleuve",
|
||||
lac: "lac",
|
||||
marais: "marais",
|
||||
gouffre: "gouffre",
|
||||
necropole: "nécropole",
|
||||
desolation: "désolation"
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
const caseSpecificModes = [ "attache", "trounoir", "debordement", "reserve_extensible", "maitrisee" ];
|
||||
|
||||
/* -------------------------------------------- */
|
||||
const tmrMovePattern =
|
||||
const tmrRandomMovePatten =
|
||||
[ { name: 'top', x: 0, y: -1 },
|
||||
{ name: 'topright', x: 1, y: -1 },
|
||||
{ name: 'left', x: 1, y: 'alt' },
|
||||
{ name: 'botright', x: 1, y: 1 },
|
||||
{ name: 'bot', x: 0, y: 1 },
|
||||
{ name: 'botleft', x: -1, y: 1 },
|
||||
{ name: 'left', x: -1, y: 'alt' },
|
||||
{ name: 'topleft', x: -1, y: -1 }
|
||||
]
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export const tmrConstants = {
|
||||
col1_y: 30,
|
||||
col2_y: 55,
|
||||
cellw: 55,
|
||||
cellh: 55,
|
||||
gridx: 28,
|
||||
gridy: 28
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class TMRUtility {
|
||||
|
||||
static init() {
|
||||
for (let coord in TMRMapping) {
|
||||
TMRMapping[coord].coord = coord;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static convertToTMRCoord( x, y )
|
||||
@ -303,261 +288,100 @@ export class TMRUtility {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getTMRDescription( coordTMR)
|
||||
static getTMR( coordTMR)
|
||||
{
|
||||
return TMRMapping[coordTMR];
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** Some debug functions */
|
||||
static setForceRencontre( id, force ) {
|
||||
this.forceRencontre = { id: id, force: force}
|
||||
static async setForceRencontre( index, force = undefined ) {
|
||||
this.prochaineRencontre = TMRRencontres.getRencontre( index );
|
||||
if (this.prochaineRencontre ) {
|
||||
if (force) {
|
||||
this.prochaineRencontre.force = force;
|
||||
}
|
||||
else{
|
||||
await TMRRencontres.evaluerForceRencontre(this.prochaineRencontre)
|
||||
}
|
||||
console.log("La prochaine rencontre sera:", this.prochaineRencontre.name, " force:", this.prochaineRencontre.force);
|
||||
}
|
||||
else {
|
||||
ui.notifications.warn("Pas de prochaine rencontre valide pour "+index);
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static clearForceRencontre( id, force ) {
|
||||
this.forceRencontre = undefined
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static isForceRencontre() {
|
||||
return this.forceRencontre
|
||||
return this.prochaineRencontre
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getDirectionPattern() {
|
||||
let index = new Roll("1d"+tmrMovePattern.length+" -1").roll().total;
|
||||
return tmrMovePattern[index];
|
||||
let roll = new Roll("1d"+tmrRandomMovePatten.length).evaluate().total;
|
||||
return tmrRandomMovePatten[roll -1];
|
||||
}
|
||||
|
||||
static deplaceTMRAleatoire(coord) {
|
||||
return TMRUtility.deplaceTMRSelonPattern(coord, TMRUtility.getDirectionPattern(), 1);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static deplaceTMRSelonPattern( pos, pattern, nTime ) {
|
||||
static deplaceTMRSelonPattern( coord, direction, nTime ) {
|
||||
for (let i=0; i <nTime; i++) {
|
||||
let currentPosXY = TMRUtility.convertToCellCoord(pos);
|
||||
currentPosXY.x = currentPosXY.x + pattern.x;
|
||||
if (pattern.y == 'alt' ) { // Alternate version
|
||||
pattern.y += (pattern.x % 2 == 0 ) ? -1 : 1;
|
||||
} else {
|
||||
currentPosXY.y = currentPosXY.y + pattern.y;
|
||||
}
|
||||
let currentPosXY = TMRUtility.convertToCellCoord(coord);
|
||||
currentPosXY.x = currentPosXY.x + direction.x;
|
||||
currentPosXY.y = currentPosXY.y + direction.y;
|
||||
if ( this._checkTMRCoord(currentPosXY.x, currentPosXY.y) ) { // Sortie de carte ! Ré-insertion aléatoire
|
||||
pos = TMRUtility.convertToTMRCoord(currentPosXY.x, currentPosXY.y);
|
||||
coord = TMRUtility.convertToTMRCoord(currentPosXY.x, currentPosXY.y);
|
||||
} else {
|
||||
pos = this.getTMRAleatoire();
|
||||
coord = this.getTMRAleatoire();
|
||||
}
|
||||
console.log("Nouvelle case iteration !!!", i, pos);
|
||||
console.log("Nouvelle case iteration !!!", i, coord);
|
||||
}
|
||||
return pos;
|
||||
return coord;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async rencontreTMRRoll( coordTMR, cellDescr, isSpecial = false )
|
||||
static async rencontreTMRRoll( coordTMR, cellDescr, isMauvaise = false )
|
||||
{
|
||||
if ( this.forceRencontre ) {
|
||||
// Forced
|
||||
let rencontre = duplicate(rencontresTable[this.forceRencontre.id]);
|
||||
rencontre.force = this.forceRencontre.force;
|
||||
rencontre.coord = coordTMR;
|
||||
rencontre.nbCases = 0; // Utilisé pour les Tourbillons
|
||||
return rencontre;
|
||||
}
|
||||
let rencontre;
|
||||
if ( isSpecial ) {
|
||||
let index = new Roll("1d7").roll().total;
|
||||
rencontre = rencontresSpeciale[index-1];
|
||||
} else {
|
||||
rencontre = await this.rencontreTMRTypeCase(cellDescr.type);
|
||||
}
|
||||
//let rencontre = rencontresTable[4];
|
||||
if (rencontre) {
|
||||
rencontre = duplicate(rencontre);
|
||||
rencontre.force = await this.evaluerForceRencontre(rencontre);
|
||||
if ( this.prochaineRencontre ) {
|
||||
rencontre = this.prochaineRencontre;
|
||||
rencontre.coord = coordTMR;
|
||||
rencontre.nbCases = 0; // Utilisé pour les Tourbillons
|
||||
rencontre.isSpecial = isSpecial; // Garder l'information
|
||||
this.prochaineRencontre = undefined;
|
||||
}
|
||||
else if ( isMauvaise ) {
|
||||
rencontre = await TMRRencontres.getMauvaiseRencontre();
|
||||
} else {
|
||||
rencontre = await TMRRencontres.getRencontreAleatoire(cellDescr.type);
|
||||
}
|
||||
rencontre.coord = coordTMR;
|
||||
return rencontre;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async rencontreTMRTypeCase(typeTMR, roll=undefined) {
|
||||
if (!roll) {
|
||||
//roll = await RdDDice.show(new Roll("d100").evaluate()).total;
|
||||
roll = new Roll("1d100").roll().total;
|
||||
console.log("rencontreTMRTypeCase", roll);
|
||||
}
|
||||
typeTMR = Grammar.toLowerCaseNoAccent(typeTMR);
|
||||
for( let rencontre of rencontresTable) {
|
||||
console.log("TMR !!!", typeTMR, roll);
|
||||
let scoreDef = rencontre.data[typeTMR];
|
||||
let min = scoreDef.substr(0,2);
|
||||
let max = scoreDef.substr(3,2);
|
||||
if (min=="00") min = 101;
|
||||
if (max=="00") max = 100;
|
||||
if (roll >= min && roll <= max) {
|
||||
return rencontre;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/**
|
||||
* Retourne une recontre en fonction de la case et du tirage
|
||||
* @param {*} terrain
|
||||
* @param {*} roll
|
||||
*/
|
||||
static async getRencontre( terrain, roll ) {
|
||||
if ( !terrain) {
|
||||
ChatMessage.create({ content: "Un nom de case doit être indiqué (ie /tmrr desert ou /tmrr cite)" });
|
||||
return false;
|
||||
}
|
||||
|
||||
roll = roll ?? new Roll("1d100").evaluate().total;
|
||||
roll = Math.max(1, Math.min(roll, 100));
|
||||
|
||||
let rencontre = await this.rencontreTMRTypeCase(terrain, roll);
|
||||
if (rencontre) {
|
||||
let force = await this.evaluerForceRencontre(rencontre);
|
||||
ChatMessage.create({
|
||||
user: game.user._id,
|
||||
whisper: [game.user._id],
|
||||
content: `Rencontre en ${terrain} (jet : ${roll}%)<br>Vous rencontrez un ${rencontre.name} de ${force} Points de Rêve`});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getLocationTypeList( coordTMR ) {
|
||||
let descr = this.getTMRDescription( coordTMR );
|
||||
let typeList = [];
|
||||
static getListTMR(terrain) {
|
||||
let list = [];
|
||||
for (let index in TMRMapping) {
|
||||
let caseTMR = TMRMapping[index];
|
||||
if (caseTMR.type == descr.type)
|
||||
typeList.push(index)
|
||||
if (TMRMapping[index].type == terrain){
|
||||
list.push(TMRMapping[index]);
|
||||
}
|
||||
return typeList;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
static getListCoordTMR(terrain) {
|
||||
return this.getListTMR(terrain).map(it=>it.coord);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async evaluerForceRencontre(rencontre) {
|
||||
if (this.isReveDeDragon(rencontre)) {
|
||||
let ddr = await DeDraconique.ddr("selfroll");
|
||||
return ddr.total + 7;
|
||||
}
|
||||
else {
|
||||
const roll = new Roll(rencontre.data.force).evaluate();
|
||||
return roll.total;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isReveDeDragon(rencontre) {
|
||||
return rencontre.name.toLowerCase() == "Rêve de Dragon".toLowerCase();
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async processRencontreReussite( actor, rencontre, rolled ) {
|
||||
let message = "<br>";
|
||||
let state = "aucune";
|
||||
|
||||
console.log("processRencontreReussite", actor, rencontre);
|
||||
if (rencontre.name == "Messagers des Rêves") {
|
||||
message += "Le Messager des Rêves vous permet de lancer votre sort à " + rencontre.force + " cases !";
|
||||
state = 'messager';
|
||||
|
||||
} else if (rencontre.name == "Passeur des Rêves") {
|
||||
message += "Le Passeur des Rêves vous permet de vous téléporter à " + rencontre.force + " cases !";
|
||||
state = 'passeur';
|
||||
|
||||
} else if (rencontre.name == "Fleur des Rêves") {
|
||||
await actor.reveActuelIncDec( rencontre.force );
|
||||
message += "La Fleur des rêves s'évanouit en vous fournissant " + rencontre.force + " Points de Rêve";
|
||||
|
||||
} else if (rencontre.name == "Mangeur de Rêve") {
|
||||
message += "Ce Mangeur des Rêves disparait !"
|
||||
|
||||
} else if (rencontre.name == "Changeur de Rêve") {
|
||||
message += "Ce Changeur des Rêves vous propose de vous déplacer sur une autre case de même type."
|
||||
state = 'changeur';
|
||||
|
||||
} else if (rencontre.name == "Briseur de Rêve") {
|
||||
message += "Ce Briseur des Rêves disparait !"
|
||||
|
||||
} else if (rencontre.name == "Reflet d'ancien Rêve") {
|
||||
message += "Ce Reflet d'ancien Rêve disparait !"
|
||||
|
||||
} else if (rencontre.name == "Tourbillon blanc") {
|
||||
message += "Ce Tourbillon Blanc disparait !"
|
||||
|
||||
} else if (rencontre.name == "Tourbillon noir") {
|
||||
message += "Ce Tourbillon Noir disparait !"
|
||||
|
||||
} else if (rencontre.name == "Rêve de Dragon") {
|
||||
// TODO: xp particulière
|
||||
message += "Vous maîtrisez le Rêve de Dragon !"
|
||||
message += await actor.appliquerReveDeDragon(rolled, rencontre.force);
|
||||
}
|
||||
return { message: message, state: state };
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async processRencontreEchec( actor, rencontre, rolled, tmrDialog ) {
|
||||
let message = "<br>";
|
||||
let state = "aucune";
|
||||
|
||||
if (rencontre.name == "Messagers des Rêves") {
|
||||
message += "Le Messager des Rêves s'éloigne de vous !";
|
||||
|
||||
} else if (rencontre.name == "Passeur des Rêves") {
|
||||
message += "Le Passeur des Rêves s'éloigne de vous !";
|
||||
|
||||
} else if (rencontre.name == "Fleur des Rêves") {
|
||||
message += "La Fleur des rêves s'éloigne de vous et se perd dans les Terres Médianes";
|
||||
|
||||
} else if (rencontre.name == "Mangeur de Rêve") {
|
||||
await actor.reveActuelIncDec( -rencontre.force );
|
||||
message += "Ce Mangeur des Rêves croque votre Rêve ! Vous perdez " + rencontre.force + " points de rêve actuels, votre nouveau total est de " + actor.data.data.reve.reve.value;
|
||||
|
||||
} else if (rencontre.name == "Changeur de Rêve") {
|
||||
message += "Ce Changeur des Rêves vous déplace sur un autre case du même type.<br>"
|
||||
let locList = this.getLocationTypeList( actor.data.data.reve.tmrpos.coord );
|
||||
let index = new Roll("1d"+locList.length + " - 1").roll().total;
|
||||
let newCoord = locList[index];
|
||||
tmrDialog.forceDemiRevePosition(newCoord);
|
||||
let cellDescr = TMRUtility.getTMRDescription(newCoord);
|
||||
message += "Vous avez été téléporté en " + newCoord + " - " + cellDescr.label;
|
||||
|
||||
} else if (rencontre.name == "Briseur de Rêve") {
|
||||
message += "Votre Rêve est Brisé, vous quittez les Terres Médianes";
|
||||
|
||||
} else if (rencontre.name == "Passeur fou") {
|
||||
message += "Vous êtes déplacé sur la case de votre sort en réserve le plus proche, ou sinon aléatoirement dans une direction";
|
||||
state = "passeurfou";
|
||||
|
||||
} else if (rencontre.name == "Reflet d'ancien Rêve") {
|
||||
message += "Votre Rêve est figé, vous restez sur cette case tant que ce Reflet n'est pas vaincu!";
|
||||
state = "reflet";
|
||||
|
||||
} else if (rencontre.name == "Tourbillon blanc") {
|
||||
message += "Vous êtes emporté par le Tourbillon...";
|
||||
state = "tourbillonblanc";
|
||||
|
||||
} else if (rencontre.name == "Tourbillon noir") {
|
||||
message += "Vous êtes emporté par le Tourbillon...";
|
||||
state = "tourbillonnoir";
|
||||
|
||||
} else if (rencontre.name == "Tourbillon rouge") {
|
||||
message += "Vous êtes emporté par le Tourbillon...";
|
||||
state = "tourbillonrouge";
|
||||
|
||||
} else if (rencontre.name == "Rêve de Dragon") {
|
||||
message += "Le Rêve de Dragon tourne au cauchemar !"
|
||||
message += actor.appliquerReveDeDragon(rolled, rencontre.force);
|
||||
}
|
||||
return { message: message, state: state };
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getTMRAleatoire()
|
||||
static getTMRAleatoire(terrain=undefined)
|
||||
{
|
||||
if (terrain) {
|
||||
let list = TMRUtility.getListTMR(terrain);
|
||||
let index = new Roll("1d" + list.length).evaluate().total - 1;
|
||||
return list[index];
|
||||
}
|
||||
let num = new Roll("1d15").roll().total;
|
||||
let letter, letterValue;
|
||||
if ( num == 15) {
|
||||
@ -575,7 +399,8 @@ export class TMRUtility {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _checkTMRCoord( x, y ) {
|
||||
if (x >= 0 && x < 13 && y >= 0 && y < 15 ) return true;
|
||||
if (x >= 0 && x < 13 && y >= 0 && y < 14 ) return true;
|
||||
if (x >= 0 && x < 13 && x%2 == 0 && y == 14 ) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -592,10 +417,10 @@ export class TMRUtility {
|
||||
static getSortReserveList( reserveList, coordTMR ) {
|
||||
// TODO : Gérer les têtes spéciales réserve!
|
||||
let sortReserveList
|
||||
let tmrDescr = this.getTMRDescription(coordTMR);
|
||||
let tmrDescr = this.getTMR(coordTMR);
|
||||
//console.log("Sort réserve : ", tmrDescr);
|
||||
if ( tmrDescr.type == 'fleuve') { // Gestion de la reserve en Fleuve
|
||||
sortReserveList = reserveList.filter(it => TMRUtility.getTMRDescription(it.coord).type == 'fleuve' );
|
||||
sortReserveList = reserveList.filter(it => TMRUtility.getTMR(it.coord).type == 'fleuve' );
|
||||
} else { // Reserve sur un case "normale"
|
||||
sortReserveList = reserveList.filter(it => it.coord == coordTMR);
|
||||
}
|
||||
@ -607,6 +432,10 @@ export class TMRUtility {
|
||||
/** Returns a list of case inside a given distance
|
||||
*
|
||||
*/
|
||||
static getTMRPortee(coord, portee) {
|
||||
return TMRUtility.getTMRArea(coord, portee, tmrConstants);
|
||||
}
|
||||
|
||||
static getTMRArea( coord, distance, tmrConstants ) {
|
||||
let pos = this.convertToCellCoord( coord );
|
||||
let posPic = this.computeRealPictureCoordinates( pos, tmrConstants );
|
||||
|
@ -431,6 +431,14 @@ table {border: 1px solid #7a7971;}
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.poesie-extrait {
|
||||
font-size: 0.85rem;
|
||||
font-style: italic;
|
||||
}
|
||||
.poesie-reference{
|
||||
font-size: 0.70rem;
|
||||
text-align: right;
|
||||
}
|
||||
/* ======================================== */
|
||||
/* Sheet */
|
||||
.window-app.sheet .window-content .sheet-header{
|
||||
|
16
templates/chat-rencontre-tmr.html
Normal file
16
templates/chat-rencontre-tmr.html
Normal file
@ -0,0 +1,16 @@
|
||||
<img class="chat-icon" src="{{competence.img}}" alt="{{competence.name}}"/>
|
||||
<h4 data-categorie="tmr" data-actor-id="{{actor._id}}" data-rencontre-round="{{nbRounds}}">
|
||||
{{alias}} rencontre {{#if (eq genre 'f')}}une{{else}}un{{/if}} {{rencontre.name}} de force {{rencontre.force}}
|
||||
</h4>
|
||||
{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.html"}}
|
||||
<hr>
|
||||
<span>
|
||||
{{message}}
|
||||
</span>
|
||||
{{#if poesie}}
|
||||
<hr>
|
||||
<span class="poesie-extrait">
|
||||
{{{poesie.extrait}}}
|
||||
<p class="poesie-reference">{{poesie.reference}}</p>
|
||||
</span>
|
||||
{{/if}}
|
Loading…
Reference in New Issue
Block a user