foundryvtt-reve-de-dragon/module/tmr-utility.js

485 lines
18 KiB
JavaScript
Raw Permalink Normal View History

import { TMRRencontres } from "./tmr-rencontres.js";
import { Misc } from "./misc.js";
2020-07-17 22:04:35 +02:00
/* -------------------------------------------- */
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" },
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" },
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" },
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" },
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" },
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" },
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 dAffa" },
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" },
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" },
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" },
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" },
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" },
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" },
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" },
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" },
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" }
}
2020-07-21 23:51:24 +02:00
export const TMRType = {
cite: { name: "cité", genre: "f" },
sanctuaire: { name: "sanctuaire", genre: 'm' },
plaines: { name: "plaines", genre: "fp" },
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" }
}
2020-07-17 22:04:35 +02:00
/* -------------------------------------------- */
const caseSpecificModes = ["attache", "trounoir", "debordement", "reserve_extensible", "maitrisee"];
2020-11-21 14:30:00 +01:00
/* -------------------------------------------- */
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 }
]
2020-11-21 14:30:00 +01:00
/* -------------------------------------------- */
export const tmrConstants = {
col1_y: 30,
col2_y: 55,
cellw: 55,
cellh: 55,
gridx: 28,
gridy: 28,
// tailles
third: 18,
half: 27.5,
twoThird: 36,
full: 55,
// decallages
center: { x: 0, y: 0 },
top: { x: 0, y: -11.5 },
topLeft: { x: -11.5, y: -11.5 },
left: { x: -11.5, y: 0 },
bottomLeft: { x: -11.5, y: 11.5 },
bottom: { x: 0, y: 11.5 },
bottomRight: { x: 11.5, y: 11.5 },
right: { x: 11.5, y: 0 },
topRight: { x: 11.5, y: -11.5 },
}
// couleurs
export const tmrColors = {
sort: 0xFF8800,
tetes: 0xA000FF,
souffle: 0x804040,
queues: 0xAA4040,
trounoir: 0x401060,
demireve: 0x00FFEE,
rencontre: 0xFF0000,
casehumide: 0x1050F0,
}
export const tmrTokenZIndex = {
sort: 40,
tetes: 20,
casehumide: 10,
conquete: 30,
rencontre: 50,
trounoir: 60,
demireve: 70,
tooltip: 100,
}
2020-12-04 20:52:04 +01:00
/* -------------------------------------------- */
2020-07-17 22:04:35 +02:00
/* -------------------------------------------- */
export class TMRUtility {
static init() {
for (let coord in TMRMapping) {
const tmr = TMRMapping[coord];
tmr.coord = coord;
tmr.genre = TMRType[tmr.type].genre;
}
let tmrByType = Misc.classify(Object.values(TMRMapping));
for (const [type, list] of Object.entries(tmrByType)) {
TMRType[type].list = list;
}
}
2020-12-04 20:52:04 +01:00
2020-07-17 22:04:35 +02:00
/* -------------------------------------------- */
static convertToTMRCoord(pos) {
let letterX = String.fromCharCode(65 + (pos.x));
return letterX + (pos.y + 1)
2020-07-17 22:04:35 +02:00
}
2020-12-04 20:52:04 +01:00
/* -------------------------------------------- */
static verifyTMRCoord(coord) {
2020-12-04 20:52:04 +01:00
let TMRregexp = new RegExp(/([A-M])(\d+)/g);
let res = TMRregexp.exec(coord);
2020-12-04 20:52:04 +01:00
if (res && res[1] && res[2]) {
if (res[2] > 0 && res[2] < 16) {
return true;
}
}
return false;
}
2020-12-04 20:52:04 +01:00
2020-07-17 22:04:35 +02:00
/* -------------------------------------------- */
static convertToCellPos(coordTMR) {
2020-07-17 22:04:35 +02:00
let x = coordTMR.charCodeAt(0) - 65;
let y = coordTMR.substr(1) - 1;
return { x: x, y: y }
2020-07-17 22:04:35 +02:00
}
2020-07-17 22:04:35 +02:00
/* -------------------------------------------- */
static getTMR(coord) {
return TMRMapping[coord];
2020-07-17 22:04:35 +02:00
}
static getTMRLabel(coord) {
return TMRMapping[coord]?.label ?? (coord + ": case inconnue");
}
static getTMRDescr(coord) {
const tmr = TMRMapping[coord];
return Grammar.articleDetermine(tmr.genre) + ' ' + tmr.label;
}
static isCaseHumide(tmr) {
return tmr.type == 'fleuve' || tmr.type == 'lac' || tmr.type == 'marais';
}
2020-11-20 16:45:20 +01:00
/* -------------------------------------------- */
/** Some debug functions */
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);
}
2020-11-20 16:45:20 +01:00
}
2020-11-20 16:45:20 +01:00
/* -------------------------------------------- */
static isForceRencontre() {
return this.prochaineRencontre;
}
/* -------------------------------------------- */
static utiliseForceRencontre() {
const rencontre = this.prochaineRencontre;
this.prochaineRencontre = undefined;
return rencontre;
2020-11-20 16:45:20 +01:00
}
2020-11-21 14:30:00 +01:00
/* -------------------------------------------- */
static getDirectionPattern() {
return Misc.rollOneOf(tmrRandomMovePatten);
2020-11-21 14:30:00 +01:00
}
static deplaceTMRAleatoire(actor, coord) {
return TMRUtility.deplaceTMRSelonPattern(actor, coord, TMRUtility.getDirectionPattern(), 1);
}
2020-11-21 18:16:18 +01:00
/* -------------------------------------------- */
static async deplaceTMRSelonPattern(actor, coord, direction, nTime) {
for (let i = 0; i < nTime; i++) {
let currentPos = TMRUtility.convertToCellPos(coord);
currentPos.x = currentPos.x + direction.x;
currentPos.y = currentPos.y + direction.y;
if (this._checkTMRCoord(currentPos.x, currentPos.y)) { // Sortie de carte ! Ré-insertion aléatoire
coord = TMRUtility.getTMR(TMRUtility.convertToTMRCoord(currentPos));
2020-11-21 18:16:18 +01:00
} else {
coord = await actor.reinsertionAleatoire('Sortie de carte');
2020-11-21 18:16:18 +01:00
}
console.log("Nouvelle case iteration !!!", i, coord);
2020-11-21 18:16:18 +01:00
}
return coord;
2020-11-21 18:16:18 +01:00
}
2020-11-17 16:30:03 +01:00
/* -------------------------------------------- */
static getListTMR(terrain) {
return TMRType[terrain].list;
}
static filterTMR(filter) {
return Object.values(TMRMapping).filter(filter);
}
static filterTMRCoord(filter) {
return TMRUtility.filterTMR(filter).map(it => it.coord);
2020-07-17 22:04:35 +02:00
}
static getTMRAleatoire(filter = it => true) {
return Misc.rollOneOf(TMRUtility.filterTMR(filter))
2020-09-13 23:08:52 +02:00
}
2020-11-18 23:49:05 +01:00
/* -------------------------------------------- */
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;
2020-11-18 23:49:05 +01:00
return false;
}
/* -------------------------------------------- */
static computeRealPictureCoordinates(coordXY, tmrConstants) {
2020-11-18 23:49:05 +01:00
let decallagePairImpair = (coordXY.x % 2 == 0) ? tmrConstants.col1_y : tmrConstants.col2_y;
return {
2020-11-18 23:49:05 +01:00
x: tmrConstants.gridx + (coordXY.x * tmrConstants.cellw),
y: tmrConstants.gridy + (coordXY.y * tmrConstants.cellh) + decallagePairImpair
}
}
2020-12-30 11:50:18 +01:00
/* -------------------------------------------- */
2021-03-20 00:09:29 +01:00
static getSortsReserve(reserveList, coord) {
2020-12-30 11:50:18 +01:00
// TODO : Gérer les têtes spéciales réserve!
let tmrDescr = this.getTMR(coord);
//console.log("Sort réserve : ", tmrDescr);
if (tmrDescr.type == 'fleuve') { // Gestion de la reserve en Fleuve
return reserveList.filter(it => TMRUtility.getTMR(it.coord).type == 'fleuve');
2020-12-30 11:50:18 +01:00
}
// Reserve sur un case "normale"
return reserveList.filter(it => it.coord == coord);
2020-12-30 11:50:18 +01:00
}
2020-11-18 23:49:05 +01:00
/* -------------------------------------------- */
/** Returns a list of case inside a given distance
*
*/
static getTMRPortee(coord, portee) {
let centerPos = this.convertToCellPos(coord);
let posPic = this.computeRealPictureCoordinates(centerPos, tmrConstants);
2020-11-18 23:49:05 +01:00
let caseList = [];
for (let dx = -portee; dx <= portee; dx++) { // Loop thru lines
for (let dy = -portee; dy <= portee; 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 dist = this.distancePosTMR(centerPos, currentPos);
if (dist <= portee) {
caseList.push(this.convertToTMRCoord(currentPos)); // Inside the area
2020-11-18 23:49:05 +01:00
}
}
}
}
return caseList;
}
static distanceTMR(coord1, coord2) {
let pos1 = this.convertToCellPos(coord1);
let pos2 = this.convertToCellPos(coord2);
return this.distancePosTMR(pos1, pos2);
}
static distancePosTMR(pos1, pos2) {
const dx = pos2.x - pos1.x;
const dy = pos2.y - pos1.y;
const abs_dx = Math.abs(dx);
const abs_dy = Math.abs(dy);
const distance = Math.sign(dx) == Math.sign(dy) ? Math.max(abs_dx, abs_dy) : (abs_dx + abs_dy);
return distance;
}
2020-07-17 22:04:35 +02:00
}