foundryvtt-reve-de-dragon/module/rdd-timestamp.js
Vincent Vandemeulebrouck 912b1d3df3 Gestion d'items temporels
- Séparation des timestamp / calendrier

Les poisons/maladies/souffles/queues/rencontres/signes peuvent
être temporaires.

- Ajout de champs pour stocker les timestamps de début et fin
- définition de la durée (selon les items)
- extraction des classes spécialisées des items
- initialisation des dates de début/fin des effets temporaires à
  l'ajout d'un item temporel
- préparation de la suppression automatique
- Fix de mauvaise présentations sur les dialog d'astrologie
  et d'édition du calendrier
2023-01-07 02:22:44 +01:00

292 lines
10 KiB
JavaScript

import { SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js";
const RDD_MOIS_PAR_AN = 12;
const RDD_JOURS_PAR_MOIS = 28;
const RDD_JOURS_PAR_AN = 336; //RDD_JOURS_PAR_MOIS * RDD_MOIS_PAR_AN;
const RDD_HEURES_PAR_JOUR = 12;
const RDD_MINUTES_PAR_HEURES = 120;
const RDD_MINUTES_PAR_JOUR = 1440; //RDD_HEURES_PAR_JOUR * RDD_MINUTES_PAR_HEURES;
const ROUNDS_PAR_MINUTE = 10;
const CALENDRIER = "calendrier";
const DEFINITION_HEURES = [
{ key: "vaisseau", label: "Vaisseau", lettreFont: 'v', saison: "printemps" },
{ key: "sirene", label: "Sirène", lettreFont: 'i', saison: "printemps" },
{ key: "faucon", label: "Faucon", lettreFont: 'f', saison: "printemps" },
{ key: "couronne", label: "Couronne", lettreFont: '', saison: "ete" },
{ key: "dragon", label: "Dragon", lettreFont: 'd', saison: "ete" },
{ key: "epees", label: "Epées", lettreFont: 'e', saison: "ete" },
{ key: "lyre", label: "Lyre", lettreFont: 'l', saison: "automne" },
{ key: "serpent", label: "Serpent", lettreFont: 's', saison: "automne" },
{ key: "poissonacrobate", label: "Poisson Acrobate", lettreFont: 'p', saison: "automne" },
{ key: "araignee", label: "Araignée", lettreFont: 'a', saison: "hiver" },
{ key: "roseau", label: "Roseau", lettreFont: 'r', saison: "hiver" },
{ key: "chateaudormant", label: "Château Dormant", lettreFont: 'c', saison: "hiver" },
]
const FORMULES_DUREE = [
{ code: "", label: "", calcul: async (t, actor) => t.addJours(100 * RDD_JOURS_PAR_AN) },
{ code: "jour", label: "1 jour", calcul: async (t, actor) => t.nouveauJour().addJours(1) },
{ code: "1d7jours", label: "1d7 jour", calcul: async (t, actor) => t.nouveauJour().addJours(await RdDDice.rollTotal('1d7', { showDice: SHOW_DICE })) },
{ code: "1ddr", label: "Un dé draconique jours", calcul: async (t, actor) => t.nouveauJour().addJours(await RdDDice.rollTotal('1dr+7', { showDice: SHOW_DICE })) },
{ code: "hn", label: "Fin de l'Heure de Naissance", calcul: async (t, actor) => t.finHeure(actor.getHeureNaissance()) },
// { code: "1h", label: "Une heure", calcul: async (t, actor) => t.nouvelleHeure().addHeures(1) },
// { code: "12h", label: "12 heures", calcul: async (t, actor) => t.nouvelleHeure().addHeures(12) },
// { code: "chateaudormant", label: "Fin Chateau dormant", calcul: async (t, actor) => t.nouveauJour() },
// { code: "special", label: "Spéciale", calcul: async (t, actor) => t.addJours(100 * RDD_JOURS_PAR_AN) },
]
export class RdDTimestamp {
static iconeHeure(heure) {
return `systems/foundryvtt-reve-de-dragon/icons/heures/hd${heure < 9 ? '0' : ''}${heure + 1}.svg`;
}
static init() {
game.settings.register(SYSTEM_RDD, CALENDRIER, {
name: CALENDRIER,
scope: "world",
config: false,
default: { indexJour: 0, heureRdD: 0, minutesRelative: 0 },
type: Object
});
for (let i = 0; i < DEFINITION_HEURES.length; i++) {
DEFINITION_HEURES[i].heure = i;
DEFINITION_HEURES[i].icon = RdDTimestamp.iconeHeure(i);
DEFINITION_HEURES[i].webp = DEFINITION_HEURES[i].icon.replace(".svg", ".webp");
}
// TODO: positionner les calculs de FORMULES_DUREE
}
/**
* @param signe
* @returns L'entrée de DEFINITION_HEURES correspondant au signe
*/
static definition(signe) {
if (Number.isInteger(signe)) {
return DEFINITION_HEURES[signe % RDD_HEURES_PAR_JOUR];
}
let definition = DEFINITION_HEURES.find(it => it.key == signe);
if (!definition) {
definition = Misc.findFirstLike(signe, DEFINITION_HEURES, { mapper: it => it.label, description: 'signe' });
}
return definition
}
static formulesDuree() {
return FORMULES_DUREE
}
static imgSigneHeure(heure) {
return RdDTimestamp.imgSigne(RdDTimestamp.definition(heure));
}
static imgSigne(signe) {
return `<img class="img-signe-heure" src="${signe.webp}" alt="${signe.label}"/>`
}
static findHeure(heure) {
heure = Grammar.toLowerCaseNoAccentNoSpace(heure);
let parHeureOuLabel = DEFINITION_HEURES.filter(it => (it.heure) == parseInt(heure) % RDD_HEURES_PAR_JOUR || Grammar.toLowerCaseNoAccentNoSpace(it.label) == heure);
if (parHeureOuLabel.length == 1) {
return parHeureOuLabel[0];
}
let parLabelPartiel = DEFINITION_HEURES.filter(it => Grammar.toLowerCaseNoAccentNoSpace(it.label).includes(heure));
if (parLabelPartiel.length > 0) {
parLabelPartiel.sort(Misc.ascending(h => h.label.length));
return parLabelPartiel[0];
}
return undefined;
}
static signeHeure(key, value) {
const signe = RdDTimestamp.definition(value);
if (signe && ['key', 'webp', 'label', 'lettreFont', 'saison', 'heure', 'icon'].includes(key)) {
return signe[key];
}
console.error(`Appel à getSigneAs('${key}', ${value}) avec une clé/heure incorrects`);
return value;
}
static getCalendrier(indexDate, indexMinute = 0) {
return new RdDTimestamp({ indexDate, indexMinute }).toOldCalendrier();
}
/**
*
* @param indexMinute: la version formattée de la date
*/
static formatIndexDate(indexDate) {
return new RdDTimestamp({ indexDate }).formatDate()
}
static splitIndexDate(indexDate) {
const timestamp = new RdDTimestamp({ indexDate });
return {
jour: timestamp.jour + 1,
mois: RdDTimestamp.definition(timestamp.mois).key
}
}
static getWorldTime() {
return game.settings.get(SYSTEM_RDD, CALENDRIER);
}
static setWorldTime(timestamp) {
game.settings.set(SYSTEM_RDD, CALENDRIER, timestamp.toOldCalendrier());
game.socket.emit(SYSTEM_SOCKET_ID, {
msg: "msg_sync_time",
data: duplicate(timestamp)
});
}
/** construit un RdDTimestamp à partir de l'année/mois/jour/heure?/minute? */
static timestamp(annee, mois, jour, heure = 0, minute = 0) {
mois = this.definition(mois)?.heure
heure = this.definition(heure)?.heure
return new RdDTimestamp({
indexDate: (jour - 1) + (mois + annee * RDD_MOIS_PAR_AN) * RDD_JOURS_PAR_MOIS,
indexMinute: heure * RDD_MINUTES_PAR_HEURES + minute
})
}
/**
* Constructeur d'un timestamp.
* Selon les paramètres, l'objet construit se base su:
* - le timestamp
* - la date numérique + minute (dans la journée)
* @param indexDate: la date à utiliser pour ce timestamp
* @param indexMinute: la minute de la journée à utiliser pour ce timestamp
*
*/
constructor({ indexDate = undefined, indexMinute = undefined }) {
function fromSettings() {
const fromSettings = RdDTimestamp.getWorldTime();
return { indexDate: fromSettings.indexJour, indexMinute: fromSettings.heureRdD * RDD_MINUTES_PAR_HEURES + fromSettings.minutesRelative };
}
const val = Number.isInteger(indexDate) ? { indexDate, indexMinute: indexMinute ?? 0 } : fromSettings();
this.indexDate = val.indexDate
this.indexMinute = val.indexMinute
}
toCalendrier() {
return {
timestamp: this,
annee: this.annee,
mois: RdDTimestamp.definition(this.mois),
jour: this.jour,
heure: RdDTimestamp.definition(this.heure),
minute: this.minute
};
}
/**
* Convertit un timestamp en donnée utile à l'affichage d'un calendrier
*/
toOldCalendrier() {
const calendrier = {
indexJour: this.indexDate,
annee: this.annee,
moisRdD: this.mois,
jour: this.jour,
heureRdD: this.heure,
moisLabel: RdDTimestamp.definition(this.mois).label,
heureLabel: RdDTimestamp.definition(this.heure).label,
minutesRelative: this.minute,
};
return calendrier
}
get annee() { return Math.floor(this.indexDate / RDD_JOURS_PAR_AN) }
get mois() { return Math.floor((this.indexDate % RDD_JOURS_PAR_AN) / RDD_JOURS_PAR_MOIS) }
get jour() { return (this.indexDate % RDD_JOURS_PAR_AN) % RDD_JOURS_PAR_MOIS }
get heure() { return Math.floor(this.indexMinute / RDD_MINUTES_PAR_HEURES) }
get minute() { return this.indexMinute % RDD_MINUTES_PAR_HEURES }
get round() { return ROUNDS_PAR_MINUTE * (this.indexMinute - Math.floor(this.indexMinute)) }
formatDate() {
const jour = this.jour + 1;
const mois = RdDTimestamp.definition(this.mois).label;
const annee = this.annee ?? '';
return `${jour} ${mois}` + (annee ? ' ' + annee : '');
}
nouveauJour() { return new RdDTimestamp({ indexDate: this.indexDate + 1, indexMinute: 0 }) }
nouvelleHeure() {
return this.heure >= RDD_HEURES_PAR_JOUR ? this.nouveauJour() : new RdDTimestamp({
indexDate: this.indexDate,
indexMinute: (this.heure + 1) * RDD_MINUTES_PAR_HEURES
})
}
addJours(jours) {
return jours == 0 ? this : new RdDTimestamp({
indexDate: this.indexDate + jours,
indexMinute: this.indexMinute
})
}
addHeures(heures) {
if (heures == 0) {
return this
}
const heure = this.heure + heures;
return new RdDTimestamp({
indexDate: this.indexDate + Math.floor(heure / RDD_HEURES_PAR_JOUR),
indexMinute: (this.indexMinute + (heure % RDD_HEURES_PAR_JOUR)) % (RDD_MINUTES_PAR_JOUR)
})
}
addMinutes(minutes) {
if (minutes == 0) {
return this;
}
const indexMinute = this.indexMinute + minutes;
const jours = Math.floor(indexMinute / RDD_MINUTES_PAR_JOUR)
return new RdDTimestamp({
indexDate: this.indexDate + jours,
indexMinute: indexMinute - (jours * RDD_MINUTES_PAR_JOUR)
})
}
addPeriode(nombre, unite) {
switch (unite) {
case 'heures': return this.addHeures(nombre)
case 'minutes': return this.addMinutes(nombre)
case 'jours': return this.addJours(nombre)
case 'rounds': return this.addMinutes(nombre / 10)
}
return this;
}
finHeure(heure) {
return this.nouvelleHeure().addHeures((12 + heure - this.heure) % 12);
}
async appliquerDuree(duree, actor) {
const formule = FORMULES_DUREE.find(it => it.code == duree) ?? FORMULES_DUREE.find(it => it.code == "");
return await formule.calcul(this, actor);
}
compare(timestamp) {
let diff = (this.indexDate - timestamp.indexDate) ?? (this.indexMinute - timestamp.indexMinute);
return diff < 0 ? -1 : diff > 0 ? 1 : 0;
}
difference(timestamp) {
const jours = this.indexDate - timestamp.indexDate;
const minutes = this.indexMinute - timestamp.indexMinute;
return {
jours: jours,
heures: Math.floor(minutes / RDD_MINUTES_PAR_HEURES),
minutes: minutes % RDD_MINUTES_PAR_HEURES
}
}
}