Message pour maîtrise Fleuve de l'Oubli

This commit is contained in:
Vincent Vandemeulebrouck 2021-02-06 21:53:25 +01:00
parent 4b88efa999
commit 863fc65844
11 changed files with 551 additions and 431 deletions

View File

@ -18,6 +18,23 @@ export class Grammar {
}
static toLowerCaseNoAccent(words) {
return words?.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "") ?? words;
return words?.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "") ?? words;
}
static articleDetermine(genre) {
switch (genre?.toLowerCase()) {
case 'f': case 'feminin': return 'la';
case 'p': case 'pluriel': return 'les';
default:
case 'm': case 'masculin': return 'le';
}
}
static articleIndétermine(genre) {
switch (genre?.toLowerCase()) {
case 'f': case 'feminin': return 'une';
case 'p': case 'pluriel': return 'des';
case 'n': case 'neutre': return 'du'
default:
case 'm': case 'masculin': return 'un';
}
}
}

View File

@ -68,13 +68,13 @@ export class RdDItemSort extends Item {
let list = [];
let caseCheck = {};
for(let i=0; i<formData.bonusValue.length; i++) {
let caseTMR = formData.caseValue[i] || 'A1';
caseTMR = caseTMR.toUpperCase();
if ( TMRUtility.verifyTMRCoord( caseTMR ) ) { // Sanity check
let coord = formData.caseValue[i] || 'A1';
coord = coord.toUpperCase();
if ( TMRUtility.verifyTMRCoord( coord ) ) { // Sanity check
let bonus = formData.bonusValue[i] || 0;
if ( bonus > 0 && caseCheck[caseTMR] == undefined ) {
caseCheck[caseTMR] = bonus;
list.push( caseTMR+":"+bonus );
if ( bonus > 0 && caseCheck[coord] == undefined ) {
caseCheck[coord] = bonus;
list.push( coord+":"+bonus );
}
}
}
@ -86,21 +86,21 @@ export class RdDItemSort extends Item {
}
/* -------------------------------------------- */
static incrementBonusCase( actor, sort, coordTMR ) {
static incrementBonusCase( actor, sort, coord ) {
let bonusCaseList = this.buildBonusCaseList(sort.data.bonuscase, false);
//console.log("ITEMSORT", sort, bonusCaseList);
let found = false;
let StringList = [];
for( let bc of bonusCaseList) {
if (bc.case == coordTMR) { // Case existante
if (bc.case == coord) { // Case existante
found = true;
bc.bonus = Number(bc.bonus) + 1;
}
StringList.push( bc.case+':'+bc.bonus );
}
if ( !found) { //Nouvelle case, bonus de 1
StringList.push(coordTMR+':1');
StringList.push(coord+':1');
}
// Sauvegarde/update
@ -110,10 +110,10 @@ export class RdDItemSort extends Item {
}
/* -------------------------------------------- */
static getCaseBonus( sort, coordTMR) {
static getCaseBonus( sort, coord) {
let bonusCaseList = this.buildBonusCaseList(sort.data.bonuscase, false);
for( let bc of bonusCaseList) {
if (bc.case == coordTMR) { // Case existante
if (bc.case == coord) { // Case existante
return Number(bc.bonus);
}
}

View File

@ -4,12 +4,14 @@
*/
import { RollDataAjustements } from "./rolldata-ajustements.js";
import { RdDUtility } from "./rdd-utility.js";
import { TMRUtility } from "./tmr-utility.js";
import { poesieCaseHumide, TMRUtility } from "./tmr-utility.js";
import { tmrConstants } from "./tmr-utility.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDTMRRencontreDialog } from "./rdd-tmr-rencontre-dialog.js";
import { TMRRencontres } from "./tmr-rencontres.js";
import { ChatUtility } from "./chat-utility.js";
import { RdDRoll } from "./rdd-roll.js";
/* -------------------------------------------- */
export class RdDTMRDialog extends Dialog {
@ -70,16 +72,16 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */
displaySpecificCase() {
for (let caseTMR of this.casesSpeciales) {
console.log("SPEC CASE ", caseTMR);
if (caseTMR.data.specific == 'trounoir') {
this._trackToken(this._tokenTrouNoir(caseTMR.data.coord));
} else if (caseTMR.data.specific == 'attache') {
this._trackToken(this._tokenTerreAttache(caseTMR.data.coord));
} else if (caseTMR.data.specific == 'debordement') {
this._trackToken(this._tokenDebordement(caseTMR.data.coord));
} else if (caseTMR.data.specific == 'maitrisee') {
this._trackToken(this._tokenMaitrisee(caseTMR.data.coord));
for (let caseSpeciale of this.casesSpeciales) {
console.log("SPEC CASE ", caseSpeciale);
if (caseSpeciale.data.specific == 'trounoir') {
this._trackToken(this._tokenTrouNoir(caseSpeciale.data.coord));
} else if (caseSpeciale.data.specific == 'attache') {
this._trackToken(this._tokenTerreAttache(caseSpeciale.data.coord));
} else if (caseSpeciale.data.specific == 'debordement') {
this._trackToken(this._tokenDebordement(caseSpeciale.data.coord));
} else if (caseSpeciale.data.specific == 'maitrisee') {
this._trackToken(this._tokenMaitrisee(caseSpeciale.data.coord));
}
}
}
@ -208,6 +210,7 @@ export class RdDTMRDialog extends Dialog {
competence: this.actor.getBestDraconic(),
rencontre: this.currentRencontre,
nbRounds: 1,
canClose: false,
tmr: TMRUtility.getTMR(this.actor.data.data.reve.tmrpos.coord)
}
@ -299,19 +302,25 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */
async _jetDeRencontre(tmr) {
if (TMRUtility.isForceRencontre()) {
return await TMRUtility.rencontreTMRRoll(tmr.coord, tmr);
}
let rencontre = this.rencontresExistantes.find(prev => prev.coord == tmr.coord);
if (rencontre) {
return rencontre;
}
let myRoll = new Roll("1d7").evaluate();
if (myRoll.total == 7) {
let isMauvaise = this.actor.isRencontreSpeciale();
return await TMRUtility.rencontreTMRRoll(tmr.coord, tmr, isMauvaise);
let myRoll = new Roll("1d7").evaluate().total;
if (TMRUtility.isForceRencontre() || myRoll== 7) {
return await this.rencontreTMRRoll(tmr, this.actor.isRencontreSpeciale());
}
this._tellToUser(myRoll.total + ": Pas de rencontre en " + tmr.label + " (" + tmr.coord + ")");
this._tellToUser(myRoll + ": Pas de rencontre en " + tmr.label + " (" + tmr.coord + ")");
}
/* -------------------------------------------- */
async rencontreTMRRoll(tmr, isMauvaise = false) {
let rencontre = TMRUtility.utiliseForceRencontre() ??
isMauvaise ? await TMRRencontres.getMauvaiseRencontre()
: await TMRRencontres.getRencontreAleatoire(tmr.type);
rencontre.coord = tmr.coord;
return rencontre;
}
/* -------------------------------------------- */
@ -352,79 +361,27 @@ export class RdDTMRDialog extends Dialog {
}
}
/* -------------------------------------------- */
isCaseMaitrisee(coordTMR) {
return this.casesSpeciales.find(it => it.data.coord = coordTMR && it.data.specific == 'maitrisee');
}
/* -------------------------------------------- */
manageCaseHumideResult() {
if (this.toclose)
this.close();
}
/* -------------------------------------------- */
async manageCaseHumide(tmr) {
if (this.viewOnly || this.currentRencontre) {
return;
}
if (this.isCaseHumide(tmr)) {
// TODO: permettre de choisir la voie de draconic?
let draconic = this.actor.getBestDraconic();
let rollData = {
actor: this.actor,
competence: duplicate(this.actor.getBestDraconic()),
tmr: tmr,
canClose: false,
diffLibre: -7,
forceCarac: { "reveactuel": { label: "Rêve Actuel", value: this.actor.getReveActuel() } }
}
rollData.competence.data.defaut_carac = "reveactuel";
let carac = this.actor.getReveActuel();
const etatGeneral = this.actor.getEtatGeneral();
let difficulte = draconic.data.niveau - 7;
let rolled = await RdDResolutionTable.roll(carac, difficulte);
// Gestion du souffle Double Résistance du Fleuve
if (this.actor.isDoubleResistanceFleuve()) {
let rolled2 = await RdDResolutionTable.roll(carac, difficulte);
if (rolled2.isEchec)
rolled = rolled;
}
console.log("manageCaseHumide >>", rolled);
let explication = "";
let msg2MJ = "";
this.toclose = rolled.isEchec;
if (rolled.isEchec) {
explication += "Vous êtes entré sur une case humide, et vous avez <strong>raté</strong> votre maîtrise ! Vous <strong>quittez les Terres Médianes</strong> !"
msg2MJ += game.user.name + " est rentré sur une case humides : Echec !";
}
else {
explication += "Vous êtes entré sur une case humide, et vous avez <strong>réussi</strong> votre maîtrise !"
msg2MJ += game.user.name + " est rentré sur une case humides : Réussite !";
}
explication += "<br><strong>Test : Rêve actuel / " + draconic.name + " / " + tmr.type + "</strong>"
+ RdDResolutionTable.explain(rolled);
if (rolled.isETotal) {
let souffle = await this.actor.ajouterSouffle({ chat: false });
explication += "<br>Vous avez fait un Echec Total. Vous subissez un Souffle de Dragon : " + souffle.name;
msg2MJ += "<br>Et a reçu un Souffle de Dragon : " + souffle.name;
}
if (rolled.isPart) {
explication += "<br>Vous avez fait une Réussite Particulière";
this.actor._appliquerAjoutExperience({ rolled: rolled, selectedCarac: { label: 'reve' }, competence: draconic.name })
msg2MJ += "<br>Et a fait une réussite particulière";
}
// Notification au MJ
ChatMessage.create({ content: msg2MJ, whisper: ChatMessage.getWhisperRecipients("GM") });
// Et au joueur (ca pourrait être un message de tchat d'ailleurs)
let humideDiag = new Dialog({
title: "Case humide",
content: explication,
buttons: {
choice: { icon: '<i class="fas fa-check"></i>', label: "Fermer", callback: () => this.manageCaseHumideResult() }
}
}
);
humideDiag.render(true);
await this._rollMaitriseCaseHumide(rollData);
}
}
/* -------------------------------------------- */
isCaseHumide(tmr) {
if (this.isCaseMaitrisee(tmr.coord)) {
ChatMessage.create({
@ -439,6 +396,60 @@ export class RdDTMRDialog extends Dialog {
return tmr.type == "lac" || tmr.type == "fleuve" || tmr.type == "marais";
}
/* -------------------------------------------- */
isCaseMaitrisee(coordTMR) {
return this.casesSpeciales.find(it => it.data.coord = coordTMR && it.data.specific == 'maitrisee');
}
async _rollMaitriseCaseHumide(rollData) {
this.minimize(); // Hide
const dialog = await RdDRoll.create(this.actor, rollData,
{
html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-tmr-humide.html',
options:{ height: 350 },
close: html => { this.maximize(); } // Re-display TMR
},
{
name: 'maitrise',
label: 'Maîtriser le fleuve',
callbacks: [
this.actor.createCallbackExperience(),
{ action: r => this._maitriseCaseHumide(r) }
]
}
);
dialog.render(true);
}
async _maitriseCaseHumide(rollData) {
if (rollData.rolled.isETotal) {
rollData.souffle = await this.actor.ajouterSouffle({ chat: false });
}
this.toclose = rollData.rolled.isEchec;
if (rollData.rolled.isSuccess) {
if (!rollData.previous && this.actor.isDoubleResistanceFleuve()) {
ChatMessage.create({
content: `Double résistance du fleuve: `,
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name)
});
rollData.previous = [rollData.rolled];
await this._rollMaitriseCaseHumide(rollData);
return;
}
}
rollData.poesie = poesieCaseHumide[new Roll("1d" + poesieCaseHumide.length).evaluate().total - 1];
const whisperTo = ChatUtility.getWhisperRecipientsAndGMs(game.user.name);
const content = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-fleuve-tmr.html`, rollData);
ChatMessage.create({
whisper: whisperTo,
content: content
});
if (rollData.rolled.isEchec) {
this.close();
}
}
/* -------------------------------------------- */
isReserveExtensible(coordTMR) {
for (let caseTMR of this.casesSpeciales) {
@ -625,7 +636,7 @@ export class RdDTMRDialog extends Dialog {
if (deplacementType == 'normal') { // Pas de rencontres après un saut de type passeur/changeur/...
await this.manageRencontre(tmr, () => this.postRencontre(tmr));
}
else{
else {
await this.postRencontre(tmr);
}
}

View File

@ -8,6 +8,7 @@ import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { RdDItemArme } from "./item-arme.js";
import { RdDItemCompetence } from "./item-competence.js";
import { Misc } from "./misc.js";
import { Grammar } from "./grammar.js";
/* -------------------------------------------- */
const categorieCompetences = {
@ -96,7 +97,6 @@ function _buildAllSegmentsFatigue(max) {
ligneFatigue[caseIncrementee + 6]++;
ligneFatigue.fatigueMax = 2 * (i + 1);
fatigue[i + 1] = ligneFatigue;
}
return fatigue;
}
@ -253,13 +253,10 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/chat-actor-carac-xp.html'
];
Handlebars.registerHelper('upperFirst', function (str) {
return Misc.upperFirst(str ?? 'null')
})
Handlebars.registerHelper('upper', function (str) {
return str?.toUpperCase() ?? 'NULL'
})
Handlebars.registerHelper('upperFirst', str=> Misc.upperFirst(str ?? 'Null'));
Handlebars.registerHelper('upper', str => str?.toUpperCase() ?? 'NULL' );
Handlebars.registerHelper('le', str => Grammar.articleDetermine(str) );
Handlebars.registerHelper('un', str => Grammar.articleIndetermine(str) );
return loadTemplates(templatePaths);
}

View File

@ -248,44 +248,44 @@ const typeRencontres = {
/* -------------------------------------------- */
const mauvaisesRencontres = [
{ code: "mangeur1d6", name: "Mangeur de Rêve", type: "mangeur", genre: "m", force: "1d6", refoulement: 2, isMauvaise: true },
{ 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: "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: "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: "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 }
{ 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: "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] }]
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] }]
}
@ -378,7 +378,8 @@ export class TMRRencontres {
/* -------------------------------------------- */
static async evaluerForceRencontre(rencontre) {
if (TMRRencontres.isReveDeDragon(rencontre)) {
rencontre.force = await DeDraconique.ddr("selfroll").total + 7;
const ddr = await DeDraconique.ddr("selfroll")
rencontre.force = 7 + ddr.total;
}
else {
rencontre.force = new Roll(rencontre.force).evaluate().total;

View File

@ -4,241 +4,303 @@ import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
/* -------------------------------------------- */
const TMRMapping = {
A1: { type: "cite", label: "Cité Vide"},
B1: { type: "plaines", label: "Plaines dAssorh"},
C1: { type: "necropole", label: "Nécropole de Kroak"},
D1: { type: "fleuve", label: "Fleuve"},
E1: { type: "monts", label: "Monts de Kanaï"},
F1: { type: "cite", label: "Cité Glauque"},
G1: { type: "desolation", label: "Désolation de Demain"},
H1: { type: "lac", label: "Lac dAnticalme"},
I1: { type: "plaines", label: "Plaines Grises"},
J1: { type: "monts", label: "Monts Fainéants"},
K1: { type: "cite", label: "Cité dOnkause"},
L1: { type: "fleuve", label: "Fleuve"},
M1: { type: "cite", label: "Cité Jalouse"},
A2: { type: "desert", label: "Désert de Mieux"},
B2: { type: "collines", label: "Collines de Dawell"},
C2: { type: "marais", label: "Marais Glignants"},
D2: { type: "cite", label: "Cité de Frost"},
E2: { type: "plaines", label: "Plaines de Fiask"},
F2: { type: "lac", label: "Lac de Misère"},
G2: { type: "marais", label: "Marais Nuisants"},
H2: { type: "collines", label: "Collines de Parta"},
I2: { type: "foret", label: "Forêt Fade"},
J2: { type: "desert", label: "Désert de Poly"},
K2: { type: "foret", label: "Forêt Tamée"},
L2: { type: "fleuve", label: "Fleuve"},
M2: { type: "necropole", label: "Nécropole de Logos"},
const TMRMapping = {
A1: { type: "cite", label: "Cité Vide" },
B1: { type: "plaines", label: "Plaines dAssorh" },
C1: { type: "necropole", label: "Nécropole de Kroak" },
D1: { type: "fleuve", label: "Fleuve de l'Oubli" },
E1: { type: "monts", label: "Monts de Kanaï" },
F1: { type: "cite", label: "Cité Glauque" },
G1: { type: "desolation", label: "Désolation de Demain" },
H1: { type: "lac", label: "Lac dAnticalme" },
I1: { type: "plaines", label: "Plaines Grises" },
J1: { type: "monts", label: "Monts Fainéants" },
K1: { type: "cite", label: "Cité dOnkause" },
L1: { type: "fleuve", label: "Fleuve de l'Oubli" },
M1: { type: "cite", label: "Cité Jalouse" },
A3: { type: "desolation", label: "Désolation de Demain"},
B3: { type: "plaines", label: "Plaines de Rubéga"},
C3: { type: "fleuve", label: "Fleuve"},
D3: { type: "gouffre", label: "Gouffre dOki"},
E3: { type: "foret", label: "Forêt dEstoubh"},
F3: { type: "fleuve", label: "Fleuve"},
G3: { type: "gouffre", label: "Gouffre de Sun"},
H3: { type: "foret", label: "Forêt de Ganna"},
I3: { type: "monts", label: "Monts Grinçants"},
J3: { type: "cite", label: "Cité Venin"},
K3: { type: "plaines", label: "Plaines de Dois"},
L3: { type: "lac", label: "Lac Laineux"},
M3: { type: "monts", label: "Monts de Vdah"},
A2: { type: "desert", label: "Désert de Mieux" },
B2: { type: "collines", label: "Collines de Dawell" },
C2: { type: "marais", label: "Marais Glignants" },
D2: { type: "cite", label: "Cité de Frost" },
E2: { type: "plaines", label: "Plaines de Fiask" },
F2: { type: "lac", label: "Lac de Misère" },
G2: { type: "marais", label: "Marais Nuisants" },
H2: { type: "collines", label: "Collines de Parta" },
I2: { type: "foret", label: "Forêt Fade" },
J2: { type: "desert", label: "Désert de Poly" },
K2: { type: "foret", label: "Forêt Tamée" },
L2: { type: "fleuve", label: "Fleuve de l'Oubli" },
M2: { type: "necropole", label: "Nécropole de Logos" },
A4: { type: "foret", label: "Forêt de Falconax"},
B4: { type: "monts", label: "Monts Crâneurs"},
C4: { type: "pont", label: "Pont de Giolii"},
D4: { type: "lac", label: "Lac de Foam"},
E4: { type: "plaines", label: "Plaines dOrti"},
F4: { type: "fleuve", label: "Fleuve"},
G4: { type: "sanctuaire", label: "Sanctuaire Blanc"},
H4: { type: "plaines", label: "Plaines de Psark"},
I4: { type: "plaines", label: "Plaines de Xiax"},
J4: { type: "collines", label: "Collines dEncre"},
K4: { type: "pont", label: "Pont de Fah"},
L4: { type: "sanctuaire", label: "Sanctuaire Mauve"},
M4: { type: "gouffre", label: "Gouffre Grisant"},
A3: { type: "desolation", label: "Désolation de Demain" },
B3: { type: "plaines", label: "Plaines de Rubéga" },
C3: { type: "fleuve", label: "Fleuve de l'Oubli" },
D3: { type: "gouffre", label: "Gouffre dOki" },
E3: { type: "foret", label: "Forêt dEstoubh" },
F3: { type: "fleuve", label: "Fleuve de l'Oubli" },
G3: { type: "gouffre", label: "Gouffre de Sun" },
H3: { type: "foret", label: "Forêt de Ganna" },
I3: { type: "monts", label: "Monts Grinçants" },
J3: { type: "cite", label: "Cité Venin" },
K3: { type: "plaines", label: "Plaines de Dois" },
L3: { type: "lac", label: "Lac Laineux" },
M3: { type: "monts", label: "Monts de Vdah" },
A5: { type: "plaines", label: "Plaines de Trilkh"},
B5: { type: "collines", label: "Collines de Tanegy"},
C5: { type: "marais", label: "Marais Flouants"},
D5: { type: "fleuve", label: "Fleuve"},
E5: { type: "monts", label: "Monts Brûlants"},
F5: { type: "cite", label: "Cité de Panople"},
G5: { type: "pont", label: "Pont dIk"},
H5: { type: "desert", label: "Désert de Krane"},
I5: { type: "desolation", label: "Désolation de Demain"},
J5: { type: "marais", label: "Marais de Jab"},
K5: { type: "fleuve", label: "Fleuve"},
L5: { type: "collines", label: "Collines Suaves"},
M5: { type: "cite", label: "Cité Rimarde"},
A4: { type: "foret", label: "Forêt de Falconax" },
B4: { type: "monts", label: "Monts Crâneurs" },
C4: { type: "pont", label: "Pont de Giolii" },
D4: { type: "lac", label: "Lac de Foam" },
E4: { type: "plaines", label: "Plaines dOrti" },
F4: { type: "fleuve", label: "Fleuve de l'Oubli" },
G4: { type: "sanctuaire", label: "Sanctuaire Blanc" },
H4: { type: "plaines", label: "Plaines de Psark" },
I4: { type: "plaines", label: "Plaines de Xiax" },
J4: { type: "collines", label: "Collines dEncre" },
K4: { type: "pont", label: "Pont de Fah" },
L4: { type: "sanctuaire", label: "Sanctuaire Mauve" },
M4: { type: "gouffre", label: "Gouffre Grisant" },
A6: { type: "necropole", label: "Nécropole de Zniak"},
B6: { type: "foret", label: "Forêt de Bust"},
C6: { type: "cite", label: "Cité Pavois"},
D6: { type: "fleuve", label: "Fleuve"},
E6: { type: "sanctuaire", label: "Sanctuaire de Plaine"},
F6: { type: "fleuve", label: "Fleuve"},
G6: { type: "marais", label: "Marais Glutants"},
H6: { type: "monts", label: "Monts Gurdes"},
I6: { type: "necropole", label: "Nécropole de Xotar"},
J6: { type: "lac", label: "Lac dIaupe"},
K6: { type: "desolation", label: "Désolation de Demain"},
L6: { type: "foret", label: "Forêt Gueuse"},
M6: { type: "desolation", label: "Désolation de Demain"},
A5: { type: "plaines", label: "Plaines de Trilkh" },
B5: { type: "collines", label: "Collines de Tanegy" },
C5: { type: "marais", label: "Marais Flouants" },
D5: { type: "fleuve", label: "Fleuve de l'Oubli" },
E5: { type: "monts", label: "Monts Brûlants" },
F5: { type: "cite", label: "Cité de Panople" },
G5: { type: "pont", label: "Pont dIk" },
H5: { type: "desert", label: "Désert de Krane" },
I5: { type: "desolation", label: "Désolation de Demain" },
J5: { type: "marais", label: "Marais de Jab" },
K5: { type: "fleuve", label: "Fleuve de l'Oubli" },
L5: { type: "collines", label: "Collines Suaves" },
M5: { type: "cite", label: "Cité Rimarde" },
A7: { type: "plaines", label: "Plaines de lArc"},
B7: { type: "marais", label: "Marais Bluants"},
C7: { type: "fleuve", label: "Fleuve"},
D7: { type: "plaines", label: "Plaines dA!a"},
E7: { type: "foret", label: "Forêt de Glusks"},
F7: { type: "fleuve", label: "Fleuve"},
G7: { type: "cite", label: "Cité de Terwa"},
H7: { type: "gouffre", label: "Gouffre de Kapfa"},
I7: { type: "plaines", label: "Plaines de Troo"},
J7: { type: "fleuve", label: "Fleuve"},
K7: { type: "cite", label: "Cité de Kolix"},
L7: { type: "gouffre", label: "Gouffre dEpisophe"},
M7: { type: "desert", label: "Désert de Lave"},
A6: { type: "necropole", label: "Nécropole de Zniak" },
B6: { type: "foret", label: "Forêt de Bust" },
C6: { type: "cite", label: "Cité Pavois" },
D6: { type: "fleuve", label: "Fleuve de l'Oubli" },
E6: { type: "sanctuaire", label: "Sanctuaire de Plaine" },
F6: { type: "fleuve", label: "Fleuve de l'Oubli" },
G6: { type: "marais", label: "Marais Glutants" },
H6: { type: "monts", label: "Monts Gurdes" },
I6: { type: "necropole", label: "Nécropole de Xotar" },
J6: { type: "lac", label: "Lac dIaupe" },
K6: { type: "desolation", label: "Désolation de Demain" },
L6: { type: "foret", label: "Forêt Gueuse" },
M6: { type: "desolation", label: "Désolation de Demain" },
A8: { type: "gouffre", label: "Gouffre de Shok"},
B8: { type: "fleuve", label: "Fleuve"},
C8: { type: "foret", label: "Forêt Turmide"},
D8: { type: "cite", label: "Cité dOlak"},
E8: { type: "plaines", label: "Plaines dIolise"},
F8: { type: "lac", label: "Lac des Chats"},
G8: { type: "plaines", label: "Plaines Sans Joie"},
H8: { type: "foret", label: "Forêt dOurf"},
I8: { type: "fleuve", label: "Fleuve"},
J8: { type: "monts", label: "Monts Barask"},
K8: { type: "desert", label: "Désert de Fumée"},
L8: { type: "monts", label: "Monts Tavelés"},
M8: { type: "plaines", label: "Plaines Lavées"},
A7: { type: "plaines", label: "Plaines de lArc" },
B7: { type: "marais", label: "Marais Bluants" },
C7: { type: "fleuve", label: "Fleuve de l'Oubli" },
D7: { type: "plaines", label: "Plaines dA!a" },
E7: { type: "foret", label: "Forêt de Glusks" },
F7: { type: "fleuve", label: "Fleuve de l'Oubli" },
G7: { type: "cite", label: "Cité de Terwa" },
H7: { type: "gouffre", label: "Gouffre de Kapfa" },
I7: { type: "plaines", label: "Plaines de Troo" },
J7: { type: "fleuve", label: "Fleuve de l'Oubli" },
K7: { type: "cite", label: "Cité de Kolix" },
L7: { type: "gouffre", label: "Gouffre dEpisophe" },
M7: { type: "desert", label: "Désert de Lave" },
A9: { type: "collines", label: "Collines de Korrex"},
B9: { type: "lac", label: "Lac de Lucre"},
C9: { type: "monts", label: "Monts Tuméfiés"},
D9: { type: "pont", label: "Pont dOrx"},
E9: { type: "fleuve", label: "Fleuve"},
F9: { type: "plaines", label: "Plaines de Foe"},
G9: { type: "desolation", label: "Désolation de Demain"},
H9: { type: "collines", label: "Collines de Noirseul"},
I9: { type: "fleuve", label: "Fleuve"},
J9: { type: "marais", label: "Marais Gronchants"},
K9: { type: "sanctuaire", label: "Sanctuaire Noir"},
L9: { type: "collines", label: "Collines Cornues"},
M9: { type: "necropole", label: "Nécropole de Zonar"},
A8: { type: "gouffre", label: "Gouffre de Shok" },
B8: { type: "fleuve", label: "Fleuve de l'Oubli" },
C8: { type: "foret", label: "Forêt Turmide" },
D8: { type: "cite", label: "Cité dOlak" },
E8: { type: "plaines", label: "Plaines dIolise" },
F8: { type: "lac", label: "Lac des Chats" },
G8: { type: "plaines", label: "Plaines Sans Joie" },
H8: { type: "foret", label: "Forêt dOurf" },
I8: { type: "fleuve", label: "Fleuve de l'Oubli" },
J8: { type: "monts", label: "Monts Barask" },
K8: { type: "desert", label: "Désert de Fumée" },
L8: { type: "monts", label: "Monts Tavelés" },
M8: { type: "plaines", label: "Plaines Lavées" },
A10: { type: "sanctuaire", label: "Sanctuaire dOlis"},
B10: { type: "monts", label: "Monts Salés"},
C10: { type: "marais", label: "Marais de Dom"},
D10: { type: "fleuve", label: "Fleuve"},
E10: { type: "gouffre", label: "Gouffre de Junk"},
F10: { type: "marais", label: "Marais Zultants"},
G10: { type: "cite", label: "Cité de Sergal"},
H10: { type: "plaines", label: "Plaines Noires"},
I10: { type: "lac", label: "Lac Wanito"},
J10: { type: "fleuve", label: "Fleuve"},
K10: { type: "plaines", label: "Plaines Jaunes"},
L10: { type: "desert", label: "Désert de Nicrop"},
M10: { type: "foret", label: "Forêt de Jajou"},
A9: { type: "collines", label: "Collines de Korrex" },
B9: { type: "lac", label: "Lac de Lucre" },
C9: { type: "monts", label: "Monts Tuméfiés" },
D9: { type: "pont", label: "Pont dOrx" },
E9: { type: "fleuve", label: "Fleuve de l'Oubli" },
F9: { type: "plaines", label: "Plaines de Foe" },
G9: { type: "desolation", label: "Désolation de Demain" },
H9: { type: "collines", label: "Collines de Noirseul" },
I9: { type: "fleuve", label: "Fleuve de l'Oubli" },
J9: { type: "marais", label: "Marais Gronchants" },
K9: { type: "sanctuaire", label: "Sanctuaire Noir" },
L9: { type: "collines", label: "Collines Cornues" },
M9: { type: "necropole", label: "Nécropole de Zonar" },
A11: { type: "desolation", label: "Désolation de Demain"},
B11: { type: "cite", label: "Cité de Brilz"},
C11: { type: "pont", label: "Pont de Roï"},
D11: { type: "desolation", label: "Désolation de Demain"},
E11: { type: "lac", label: "Lac de Glinster"},
F11: { type: "cite", label: "Cité de Noape"},
G11: { type: "fleuve", label: "Fleuve"},
H11: { type: "fleuve", label: "Fleuve"},
I11: { type: "pont", label: "Pont de Yalm"},
J11: { type: "plaines", label: "Plaines de Miltiar"},
K11: { type: "cite", label: "Cité Tonnerre"},
L11: { type: "collines", label: "Collines de Kol"},
M11: { type: "cite", label: "Cité Crapaud"},
A10: { type: "sanctuaire", label: "Sanctuaire dOlis" },
B10: { type: "monts", label: "Monts Salés" },
C10: { type: "marais", label: "Marais de Dom" },
D10: { type: "fleuve", label: "Fleuve de l'Oubli" },
E10: { type: "gouffre", label: "Gouffre de Junk" },
F10: { type: "marais", label: "Marais Zultants" },
G10: { type: "cite", label: "Cité de Sergal" },
H10: { type: "plaines", label: "Plaines Noires" },
I10: { type: "lac", label: "Lac Wanito" },
J10: { type: "fleuve", label: "Fleuve de l'Oubli" },
K10: { type: "plaines", label: "Plaines Jaunes" },
L10: { type: "desert", label: "Désert de Nicrop" },
M10: { type: "foret", label: "Forêt de Jajou" },
A12: { type: "plaines", label: "Plaines Sages"},
B12: { type: "fleuve", label: "Fleuve"},
C12: { type: "lac", label: "Lac de Fricassa"},
D12: { type: "collines", label: "Collines dHuaï"},
E12: { type: "monts", label: "Monts Ajourés"},
F12: { type: "necropole", label: "Nécropole de Troat"},
G12: { type: "plaines", label: "Plaines de Lufmil"},
H12: { type: "collines", label: "Collines de Tooth"},
I12: { type: "gouffre", label: "Gouffre Abimeux"},
J12: { type: "cite", label: "Cité Folle"},
K12: { type: "desolation", label: "Désolation de Demain"},
L12: { type: "plaines", label: "Plaines Venteuses"},
M12: { type: "collines", label: "Collines Révulsantes"},
A11: { type: "desolation", label: "Désolation de Demain" },
B11: { type: "cite", label: "Cité de Brilz" },
C11: { type: "pont", label: "Pont de Roï" },
D11: { type: "desolation", label: "Désolation de Demain" },
E11: { type: "lac", label: "Lac de Glinster" },
F11: { type: "cite", label: "Cité de Noape" },
G11: { type: "fleuve", label: "Fleuve de l'Oubli" },
H11: { type: "fleuve", label: "Fleuve de l'Oubli" },
I11: { type: "pont", label: "Pont de Yalm" },
J11: { type: "plaines", label: "Plaines de Miltiar" },
K11: { type: "cite", label: "Cité Tonnerre" },
L11: { type: "collines", label: "Collines de Kol" },
M11: { type: "cite", label: "Cité Crapaud" },
A13: { type: "fleuve", label: "Fleuve"},
B13: { type: "gouffre", label: "Gouffre des Litiges"},
C13: { type: "desert", label: "Désert de Neige"},
D13: { type: "cite", label: "Cité Sordide"},
E13: { type: "plaines", label: "Plaines de Xnez"},
F13: { type: "foret", label: "Forêt des Cris"},
G13: { type: "plaines", label: "Plaines Calcaires"},
H13: { type: "desolation", label: "Désolation de Demain"},
I13: { type: "monts", label: "Monts Bigleux"},
J13: { type: "gouffre", label: "Gouffre de Gromph"},
K13: { type: "foret", label: "Forêt de Kluth"},
L13: { type: "monts", label: "Monts Dormants"},
M13: { type: "plaines", label: "Plaines dAnjou"},
A12: { type: "plaines", label: "Plaines Sages" },
B12: { type: "fleuve", label: "Fleuve de l'Oubli" },
C12: { type: "lac", label: "Lac de Fricassa" },
D12: { type: "collines", label: "Collines dHuaï" },
E12: { type: "monts", label: "Monts Ajourés" },
F12: { type: "necropole", label: "Nécropole de Troat" },
G12: { type: "plaines", label: "Plaines de Lufmil" },
H12: { type: "collines", label: "Collines de Tooth" },
I12: { type: "gouffre", label: "Gouffre Abimeux" },
J12: { type: "cite", label: "Cité Folle" },
K12: { type: "desolation", label: "Désolation de Demain" },
L12: { type: "plaines", label: "Plaines Venteuses" },
M12: { type: "collines", label: "Collines Révulsantes" },
A14: { type: "collines", label: "Collines de Stolis"},
B14: { type: "necropole", label: "Nécropole de Gorlo"},
C14: { type: "foret", label: "Forêt de Bissam"},
D14: { type: "sanctuaire", label: "Sanctuaire Plat"},
E14: { type: "monts", label: "Monts de Quath"},
F14: { type: "plaines", label: "Plaines Brisées"},
G14: { type: "desert", label: "Désert de Sek"},
H14: { type: "plaines", label: "Plaines Blanches"},
I14: { type: "cite", label: "Cité Destituée"},
J14: { type: "desert", label: "Désert de Sank"},
K14: { type: "necropole", label: "Nécropole dAntinéar"},
L14: { type: "plaines", label: "Plaines de Jislith"},
M14: { type: "desolation", label: "Désolation de Demain"},
A13: { type: "fleuve", label: "Fleuve de l'Oubli" },
B13: { type: "gouffre", label: "Gouffre des Litiges" },
C13: { type: "desert", label: "Désert de Neige" },
D13: { type: "cite", label: "Cité Sordide" },
E13: { type: "plaines", label: "Plaines de Xnez" },
F13: { type: "foret", label: "Forêt des Cris" },
G13: { type: "plaines", label: "Plaines Calcaires" },
H13: { type: "desolation", label: "Désolation de Demain" },
I13: { type: "monts", label: "Monts Bigleux" },
J13: { type: "gouffre", label: "Gouffre de Gromph" },
K13: { type: "foret", label: "Forêt de Kluth" },
L13: { type: "monts", label: "Monts Dormants" },
M13: { type: "plaines", label: "Plaines dAnjou" },
A15: { type: "cite", label: "Cité de Mielh"},
C15: { type: "plaines", label: "Plaines de Toué"},
E15: { type: "foret", label: "Forêt des Furies"},
G15: { type: "plaines", label: "Plaines des Soupirs"},
I15: { type: "monts", label: "Monts des Dragées"},
K15: { type: "collines", label: "Collines Pourpres"},
M15: { type: "cite", label: "Cité de Klana"}
}
A14: { type: "collines", label: "Collines de Stolis" },
B14: { type: "necropole", label: "Nécropole de Gorlo" },
C14: { type: "foret", label: "Forêt de Bissam" },
D14: { type: "sanctuaire", label: "Sanctuaire Plat" },
E14: { type: "monts", label: "Monts de Quath" },
F14: { type: "plaines", label: "Plaines Brisées" },
G14: { type: "desert", label: "Désert de Sek" },
H14: { type: "plaines", label: "Plaines Blanches" },
I14: { type: "cite", label: "Cité Destituée" },
J14: { type: "desert", label: "Désert de Sank" },
K14: { type: "necropole", label: "Nécropole dAntinéar" },
L14: { type: "plaines", label: "Plaines de Jislith" },
M14: { type: "desolation", label: "Désolation de Demain" },
export const TMRType = {
cite: {name:"cité"},
sanctuaire: {name:"sanctuaire"},
plaines: {name:"plaines"},
pont: {name:"pont"},
collines: {name:"collines"},
foret: {name:"forêt"},
monts: {name:"monts"},
desert: {name:"désert"},
fleuve: {name:"fleuve"},
lac: {name:"lac"},
marais: {name:"marais"},
gouffre: {name:"gouffre"},
necropole: {name:"nécropole"},
desolation: {name:"désolation"}
A15: { type: "cite", label: "Cité de Mielh" },
C15: { type: "plaines", label: "Plaines de Toué" },
E15: { type: "foret", label: "Forêt des Furies" },
G15: { type: "plaines", label: "Plaines des Soupirs" },
I15: { type: "monts", label: "Monts des Dragées" },
K15: { type: "collines", label: "Collines Pourpres" },
M15: { type: "cite", label: "Cité de Klana" }
}
/* -------------------------------------------- */
const caseSpecificModes = [ "attache", "trounoir", "debordement", "reserve_extensible", "maitrisee" ];
export const TMRType = {
cite: { name: "cité", genre: "f" },
sanctuaire: { name: "sanctuaire" },
plaines: { name: "plaines", genre: "p" },
pont: { name: "pont", genre: "m" },
collines: { name: "collines", genre: "p" },
foret: { name: "forêt", genre: "f" },
monts: { name: "monts", genre: "p" },
desert: { name: "désert", genre: "m" },
fleuve: { name: "fleuve", genre: "m" },
lac: { name: "lac", genre: "m" },
marais: { name: "marais", genre: "m" },
gouffre: { name: "gouffre", genre: "m" },
necropole: { name: "nécropole", genre: "f" },
desolation: { name: "désolation", genre: "f" }
}
export const poesieCaseHumide = [
{
reference: 'Le Ratier Bretonien',
extrait: `Le courant du Fleuve
<br>Te domine et te Porte
<br>Avant que tu te moeuves
<br>Combat le, ou il t'emporte`
},
{
reference: 'Incompatibilité, Charles Beaudelaire',
extrait: `Et lorsque par hasard une nuée errante
<br>Assombrit dans son vol le lac silencieux,
<br>On croirait voir la robe ou l'ombre transparente
<br>D'un esprit qui voyage et passe dans les cieux.`
},
{
reference: 'Au fleuve de Loire, Joachim du Bellay',
extrait: `Ô de qui la vive course
<br>Prend sa bienheureuse source,
<br>Dune argentine fontaine,
<br>Qui dune fuite lointaine,
<br>Te rends au sein fluctueux
<br>De lOcéan monstrueux`
},
{
reference: 'Denis Gerfaud',
extrait: `Et l'on peut savoir qui est le maître d'Oniros, c'est le Fleuve de l'Oubli.
Et l'on sait qui est le créateur du Fleuve de l'Oubli, c'est Hypnos et Narcos.
Mais l'on ne sait pas qui est le maître du Fleuve de l'Oubli,
sinon peut-être lui-même, ou peut-être Thanatos` },
{
reference: 'Denis Gerfaud',
extrait: `Narcos est la source du Fleuve de l'Oubli et Hypnos l'embouchure
Remonter le Fleuve est la Voie de la Nuit, la Voie du Souvenir.
Descendre le Fleuve est la Voie du Jour, la Voie de l'Oubli`
},
{
reference: 'Denis Gerfaud',
extrait: `Narcos engendre le fils dont il est la mère à l'heure du Vaisseau,
car Oniros s'embarque pour redescendre le Fleuve
vers son père Hypnos sur la Voie de l'Oubli`
},
{
reference: 'Denis Gerfaud',
extrait: `Hypnos engendre le fils dont il est la mère à l'heure du Serpent, car
tel les serpents, Oniros commence à remonter le Fleuve
sur le Voie du Souvenir vers son père Narcos`
},
{
reference: 'Denis Gerfaud',
extrait: `Ainsi se cuccèdent les Jours et les Ages. Les jours des Dragons sont les Ages des Hommes`
},
{
reference: 'Denis Gerfaud',
extrait: `Ainsi parlent les sages:
&laquo;Les Dragons sont créateurs de leurs rêves, mais ils ne sont pas créateurs d'Oniros
Les Dragons ne sont pas les maîtres de leurs rêvezs, car ils ne sont pas maîtres d'Oniros.
Nul ne sait qui est le créateur des Dragons, ni qui est leur maître.
Mais l'on peut supposer qui est le maître du Rêve des Dragons, c'est Oniros&raquo;`
},
]
/* -------------------------------------------- */
const tmrRandomMovePatten =
[ { name: 'top', x: 0, y: -1 },
{ name: 'topright', x: 1, y: -1 },
{ name: 'botright', x: 1, y: 1 },
{ name: 'bot', x: 0, y: 1 },
{ name: 'botleft', x: -1, y: 1 },
{ name: 'topleft', x: -1, y: -1 }
]
const caseSpecificModes = ["attache", "trounoir", "debordement", "reserve_extensible", "maitrisee"];
/* -------------------------------------------- */
const tmrRandomMovePatten =
[{ name: 'top', x: 0, y: -1 },
{ name: 'topright', x: 1, y: -1 },
{ name: 'botright', x: 1, y: 1 },
{ name: 'bot', x: 0, y: 1 },
{ name: 'botleft', x: -1, y: 1 },
{ name: 'topleft', x: -1, y: -1 }
]
/* -------------------------------------------- */
export const tmrConstants = {
@ -253,7 +315,7 @@ export const tmrConstants = {
/* -------------------------------------------- */
/* -------------------------------------------- */
export class TMRUtility {
export class TMRUtility {
static init() {
for (let coord in TMRMapping) {
TMRMapping[coord].coord = coord;
@ -265,64 +327,68 @@ export class TMRUtility {
}
/* -------------------------------------------- */
static convertToTMRCoord( pos )
{
let letterX = String.fromCharCode(65+ (pos.x));
return letterX + (pos.y +1)
static convertToTMRCoord(pos) {
let letterX = String.fromCharCode(65 + (pos.x));
return letterX + (pos.y + 1)
}
/* -------------------------------------------- */
static verifyTMRCoord( coord ) {
static verifyTMRCoord(coord) {
let TMRregexp = new RegExp(/([A-M])(\d+)/g);
let res = TMRregexp.exec( coord );
let res = TMRregexp.exec(coord);
if (res && res[1] && res[2]) {
if (res[2] > 0 && res[2] < 16) {
return true;
}
}
return false;
}
}
/* -------------------------------------------- */
static convertToCellPos( coordTMR )
{
static convertToCellPos(coordTMR) {
let x = coordTMR.charCodeAt(0) - 65;
let y = coordTMR.substr(1) - 1;
return {x: x, y: y}
return { x: x, y: y }
}
/* -------------------------------------------- */
static getTMR( coordTMR)
{
static getTMR(coordTMR) {
return TMRMapping[coordTMR];
}
/* -------------------------------------------- */
/** Some debug functions */
static async setForceRencontre( index, force = undefined ) {
this.prochaineRencontre = TMRRencontres.getRencontre( index );
if (this.prochaineRencontre ) {
static async setForceRencontre(index, force = undefined) {
this.prochaineRencontre = TMRRencontres.getRencontre(index);
if (this.prochaineRencontre) {
if (force) {
this.prochaineRencontre.force = force;
}
else{
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);
ui.notifications.warn("Pas de prochaine rencontre valide pour " + index);
}
}
/* -------------------------------------------- */
static isForceRencontre() {
return this.prochaineRencontre
return this.prochaineRencontre;
}
/* -------------------------------------------- */
static utiliseForceRencontre() {
const rencontre = this.prochaineRencontre;
this.prochaineRencontre = undefined;
return rencontre;
}
/* -------------------------------------------- */
static getDirectionPattern() {
let roll = new Roll("1d"+tmrRandomMovePatten.length).evaluate().total;
return tmrRandomMovePatten[roll -1];
let roll = new Roll("1d" + tmrRandomMovePatten.length).evaluate().total;
return tmrRandomMovePatten[roll - 1];
}
static deplaceTMRAleatoire(coord) {
@ -330,12 +396,12 @@ export class TMRUtility {
}
/* -------------------------------------------- */
static deplaceTMRSelonPattern( coord, direction, nTime ) {
for (let i=0; i <nTime; i++) {
static deplaceTMRSelonPattern(coord, direction, nTime) {
for (let i = 0; i < nTime; i++) {
let currentPosXY = TMRUtility.convertToCellPos(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
if (this._checkTMRCoord(currentPosXY.x, currentPosXY.y)) { // Sortie de carte ! Ré-insertion aléatoire
coord = TMRUtility.convertToTMRCoord(currentPosXY);
} else {
coord = this.getTMRAleatoire().coord;
@ -345,65 +411,47 @@ export class TMRUtility {
return coord;
}
/* -------------------------------------------- */
static async rencontreTMRRoll( coordTMR, cellDescr, isMauvaise = false )
{
let rencontre;
if ( this.prochaineRencontre ) {
rencontre = this.prochaineRencontre;
rencontre.coord = coordTMR;
this.prochaineRencontre = undefined;
}
else if ( isMauvaise ) {
rencontre = await TMRRencontres.getMauvaiseRencontre();
} else {
rencontre = await TMRRencontres.getRencontreAleatoire(cellDescr.type);
}
rencontre.coord = coordTMR;
return rencontre;
}
/* -------------------------------------------- */
static getListTMR(terrain) {
return TMRType[terrain].list;
}
static getListCoordTMR(terrain) {
return this.getListTMR(terrain).map(it=>it.coord);
return this.getListTMR(terrain).map(it => it.coord);
}
static getTMRAleatoire(terrain = undefined) {
let list = terrain ? TMRUtility.getListTMR(terrain) : Object.values(TMRMapping);
let index = new Roll("1d" + list.length).evaluate().total - 1;
return list[index];
return list[index];
}
/* -------------------------------------------- */
static _checkTMRCoord( x, y ) {
if (x >= 0 && x < 13 && y >= 0 && y < 14 ) return true;
if (x >= 0 && x < 13 && x%2 == 0 && y == 14 ) return true;
static _checkTMRCoord(x, y) {
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;
}
/* -------------------------------------------- */
static computeRealPictureCoordinates( coordXY, tmrConstants ) {
static computeRealPictureCoordinates(coordXY, tmrConstants) {
let decallagePairImpair = (coordXY.x % 2 == 0) ? tmrConstants.col1_y : tmrConstants.col2_y;
return {
return {
x: tmrConstants.gridx + (coordXY.x * tmrConstants.cellw),
y: tmrConstants.gridy + (coordXY.y * tmrConstants.cellh) + decallagePairImpair
}
}
/* -------------------------------------------- */
static getSortReserveList( reserveList, coordTMR ) {
static getSortReserveList(reserveList, coordTMR) {
// TODO : Gérer les têtes spéciales réserve!
let sortReserveList
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.getTMR(it.coord).type == 'fleuve' );
if (tmrDescr.type == 'fleuve') { // Gestion de la reserve en Fleuve
sortReserveList = reserveList.filter(it => TMRUtility.getTMR(it.coord).type == 'fleuve');
} else { // Reserve sur un case "normale"
sortReserveList = reserveList.filter(it => it.coord == coordTMR);
sortReserveList = reserveList.filter(it => it.coord == coordTMR);
}
//console.log("Sort réserve : ", tmrDescr, sortReserve, reserveList);
return sortReserveList;
@ -417,18 +465,18 @@ export class TMRUtility {
return TMRUtility.getTMRArea(centerCoord, portee, tmrConstants);
}
static getTMRArea( centerCoord, distance, tmrConstants ) {
let centerPos = this.convertToCellPos( centerCoord );
let posPic = this.computeRealPictureCoordinates( centerPos, tmrConstants );
static getTMRArea(centerCoord, distance, tmrConstants) {
let centerPos = this.convertToCellPos(centerCoord);
let posPic = this.computeRealPictureCoordinates(centerPos, tmrConstants);
let caseList = [];
for (let dx=-distance; dx<=distance; dx++ ) { // Loop thru lines
for (let dy=-distance; dy<=distance; dy++ ) { // Loop thru lines
const currentPos = { x: centerPos.x+dx, y: centerPos.y+dy };
if ( this._checkTMRCoord(currentPos.x, currentPos.y) ) { // Coordinate is valie
let posPicNow = this.computeRealPictureCoordinates( currentPos, tmrConstants );
let dist = Math.sqrt(Math.pow(posPicNow.x - posPic.x,2) + Math.pow(posPicNow.y - posPic.y, 2)) / tmrConstants.cellw;
if ( dist < distance+0.5) {
caseList.push( this.convertToTMRCoord(currentPos) ); // Inside the area
for (let dx = -distance; dx <= distance; dx++) { // Loop thru lines
for (let dy = -distance; dy <= distance; dy++) { // Loop thru lines
const currentPos = { x: centerPos.x + dx, y: centerPos.y + dy };
if (this._checkTMRCoord(currentPos.x, currentPos.y)) { // Coordinate is valie
let posPicNow = this.computeRealPictureCoordinates(currentPos, tmrConstants);
let dist = Math.sqrt(Math.pow(posPicNow.x - posPic.x, 2) + Math.pow(posPicNow.y - posPic.y, 2)) / tmrConstants.cellw;
if (dist < distance + 0.5) {
caseList.push(this.convertToTMRCoord(currentPos)); // Inside the area
}
}
}

View File

@ -0,0 +1,30 @@
<img class="chat-icon" src="{{competence.img}}" alt="{{competence.name}}"/>
<h4 data-categorie="tmr" data-actor-id="{{actor._id}}">
{{alias}} tente de maîtriser {{le tmr.genre}} {{tmr.label}} ({{tmr.coord}})
</h4>
{{#if previous}}
{{#each previous as |rolled key|}}
{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.html"}}
<br>Double résistance du fleuve!
{{/each}}
{{/if}}
{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.html"}}
<hr>
<span>
{{#if rolled.isSuccess}}
Vous avez maîtrisé {{le tmr.genre}} {{#if (eq tmr.type 'fleuve')}}Fleuve de l'Oubli{{else}}{{tmr.label}}{{/if}} !
{{else}}
Vous ne parvenez pas à surmonter {{le tmr.genre}} {{#if (eq tmr.type 'fleuve')}}Fleuve de l'Oubli{{else}}{{tmr.label}}{{/if}}.
Vous <strong>quittez les Terres Médianes</strong> !
{{#if souffle}}
<br>De plus, votre échec total vous fait subir un Souffle de Dragon : {{souffle.name}}
{{/if}}
{{/if}}
</span>
{{#if poesie}}
<hr>
<span class="poesie-extrait">
{{{poesie.extrait}}}
<p class="poesie-reference">{{poesie.reference}}</p>
</span>
{{/if}}

View File

@ -0,0 +1,28 @@
<form class="skill-roll-dialog">
<div class="form-group">
<label for="categorie">{{tmr.label}} ({{tmr.coord}})</label>
<label for="categorie">Rêve actuel à {{diffLibre}}</label>
<span>
<label for="categorie">Conditions</label>
<select name="diffConditions" id="diffConditions" data-dtype="number">
{{#select diffConditions}}
{{#each ajustementsConditions as |key|}}
<option value={{key}}>{{numberFormat key decimals=0 sign=true}}</option>
{{/each}}
{{/select}}
</select>
</span>
</div>
{{>"systems/foundryvtt-reve-de-dragon/templates/dialog-roll-surenc.html"}}
<div id="tableAjustements">
</div>
<div id="tableResolution">
</div>
<div id="tableProbaReussite">
</div>
</form>
<script>
</script>

View File

@ -50,20 +50,7 @@
<label for="xp">Case TMR</label>
<select name="data.tmr" id="tmr" data-dtype="String">
{{#select item.data.tmr}}
<option value="cite">Cité</option>
<option value="collines">Collines</option>
<option value="desert">Désert</option>
<option value="desolation">Désolation</option>
<option value="fleuve">Fleuve</option>
<option value="foret">Forêt</option>
<option value="gouffre">Gouffre</option>
<option value="lac">Lac</option>
<option value="marais">Marais</option>
<option value="monts">Monts</option>
<option value="necropole">Nécropole</option>
<option value="plaines">Plaines</option>
<option value="pont">Pont</option>
<option value="sanctuaire">Sanctuaire</option>
{{>"systems/foundryvtt-reve-de-dragon/templates/sort-tmr.html"}}
{{/select}}
</select>
</div>

View File

@ -21,6 +21,7 @@
<select name="data.caseTMR" id="caseTMR" data-dtype="String">
{{#select item.data.caseTMR}}
{{>"systems/foundryvtt-reve-de-dragon/templates/sort-tmr.html"}}
<option value="special">Case spéciale TMR (saisie ci-dessous)</option>
{{/select}}
</select>
</div>

View File

@ -2,7 +2,7 @@
<option value="collines">Collines</option>
<option value="desert">Désert</option>
<option value="desolation">Désolation</option>
<option value="fleuve">Fleuve</option>
<option value="fleuve">Fleuve de l'Oubli</option>
<option value="foret">Forêt</option>
<option value="gouffre">Gouffre</option>
<option value="lac">Lac</option>
@ -12,4 +12,4 @@
<option value="plaines">Plaines</option>
<option value="pont">Pont</option>
<option value="sanctuaire">Sanctuaire</option>
<option value="special">Case spéciale TMR (saisie ci-dessous)</option>