ChatMessage.create est async, il faut donc de préférence l'appeler avec un await. Des effets secondaires avaient lieu (ordre de messages, updates ultérieurs parfois pas pris en compte)
435 lines
15 KiB
JavaScript
435 lines
15 KiB
JavaScript
import { MAX_NOMBRE_ASTRAL, RdDTimestamp, WORLD_TIMESTAMP_SETTING } from "./rdd-timestamp.js";
|
|
import { RdDCalendrierEditor } from "./rdd-calendrier-editor.js";
|
|
import { RdDResolutionTable } from "../rdd-resolution-table.js";
|
|
import { RdDDice } from "../rdd-dice.js";
|
|
import { Misc } from "../misc.js";
|
|
import { DialogChronologie } from "../dialog-chronologie.js";
|
|
import { HIDE_DICE, renderTemplate, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "../constants.js";
|
|
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
|
|
import { DialogChateauDormant } from "../sommeil/dialog-chateau-dormant.js";
|
|
import { APP_ASTROLOGIE_REFRESH, AppAstrologie } from "../sommeil/app-astrologie.js";
|
|
import { AutoAdjustDarkness } from "./auto-adjust-darkness.js";
|
|
|
|
const TEMPLATE_CALENDRIER = "systems/foundryvtt-reve-de-dragon/templates/time/calendar.hbs";
|
|
|
|
const INITIAL_CALENDAR_POS = { top: 200, left: 200, horlogeAnalogique: true };
|
|
/* -------------------------------------------- */
|
|
export class RdDCalendrier extends Application {
|
|
static _warnedAppV1 = true
|
|
|
|
static initSettings() {
|
|
game.settings.register(SYSTEM_RDD, "liste-nombre-astral", {
|
|
name: "liste-nombre-astral",
|
|
scope: "world",
|
|
config: false,
|
|
default: [],
|
|
type: Object
|
|
});
|
|
|
|
game.settings.register(SYSTEM_RDD, "calendrier-pos", {
|
|
name: "calendrierPos",
|
|
scope: "client",
|
|
config: false,
|
|
default: INITIAL_CALENDAR_POS,
|
|
type: Object
|
|
});
|
|
}
|
|
|
|
static get defaultOptions() {
|
|
return foundry.utils.mergeObject(super.defaultOptions, {
|
|
title: "Calendrier",
|
|
template: TEMPLATE_CALENDRIER,
|
|
classes: ["calendar"],
|
|
popOut: true,
|
|
resizable: false,
|
|
width: 'fit-content',
|
|
height: 'fit-content',
|
|
}, { inplace: false })
|
|
}
|
|
|
|
constructor() {
|
|
super();
|
|
this.timestamp = RdDTimestamp.getWorldTime();
|
|
if (Misc.isFirstConnectedGM()) { // Uniquement si GM
|
|
RdDTimestamp.setWorldTime(this.timestamp);
|
|
this.rebuildNombresAstraux(); // Ensure always up-to-date
|
|
}
|
|
Hooks.on('updateSetting', async (setting, update, options, id) => this.onUpdateSetting(setting, update, options, id));
|
|
}
|
|
|
|
get title() {
|
|
const calendrier = this.timestamp.toCalendrier();
|
|
return `${calendrier.heure.label}, ${calendrier.jourDuMois} ${calendrier.mois.label} ${calendrier.annee} (${calendrier.mois.saison})`;
|
|
}
|
|
|
|
savePosition() {
|
|
game.settings.set(SYSTEM_RDD, "calendrier-pos", {
|
|
top: this.position.top,
|
|
left: this.position.left,
|
|
horlogeAnalogique: this.horlogeAnalogique
|
|
});
|
|
}
|
|
|
|
getSavePosition() {
|
|
const pos = game.settings.get(SYSTEM_RDD, "calendrier-pos");
|
|
if (pos?.top == undefined) {
|
|
return INITIAL_CALENDAR_POS;
|
|
}
|
|
this.horlogeAnalogique = pos.horlogeAnalogique;
|
|
return pos
|
|
}
|
|
|
|
setPosition(position) {
|
|
super.setPosition(position)
|
|
this.savePosition()
|
|
}
|
|
|
|
display() {
|
|
AutoAdjustDarkness.adjust(RdDTimestamp.getWorldTime().darkness);
|
|
const pos = this.getSavePosition()
|
|
this.render(true, { left: pos.left, top: pos.top });
|
|
return this;
|
|
}
|
|
|
|
_getHeaderButtons() {
|
|
if (game.user.isGM) {
|
|
return [
|
|
{ class: "button-calendar-astrologie", icon: "fa-solid fa-moon-over-sun", onclick: ev => this.showAstrologieEditor() },
|
|
{ class: "button-calendar-set-datetime", icon: "fa-solid fa-calendar-pen", onclick: ev => this.showCalendarEditor() },
|
|
]
|
|
}
|
|
return []
|
|
}
|
|
|
|
async close() { }
|
|
|
|
async onUpdateSetting(setting, update, options, id) {
|
|
if (setting.key == SYSTEM_RDD + '.' + WORLD_TIMESTAMP_SETTING) {
|
|
this.timestamp = RdDTimestamp.getWorldTime();
|
|
this.positionAiguilles()
|
|
this.render(false);
|
|
Hooks.callAll(APP_ASTROLOGIE_REFRESH)
|
|
}
|
|
if (setting.key == SYSTEM_RDD + '.' + "liste-nombre-astral") {
|
|
Hooks.callAll(APP_ASTROLOGIE_REFRESH)
|
|
}
|
|
}
|
|
|
|
getData() {
|
|
const formData = super.getData();
|
|
this.fillCalendrierData(formData);
|
|
return formData;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
fillCalendrierData(formData = {}) {
|
|
foundry.utils.mergeObject(formData, this.timestamp.toCalendrier());
|
|
formData.isGM = game.user.isGM
|
|
formData.heures = RdDTimestamp.definitions()
|
|
formData.horlogeAnalogique = this.horlogeAnalogique
|
|
formData.autoDarkness = AutoAdjustDarkness.isAuto()
|
|
return formData;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
/** @override */
|
|
async activateListeners(html) {
|
|
super.activateListeners(html);
|
|
this.html = html;
|
|
this.html.find('.ajout-chronologie').click(ev => DialogChronologie.create());
|
|
this.html.find('.toggle-horloge-analogique').click(ev => this.onToggleHorlogeAnalogique())
|
|
this.html.find('.toggle-auto-darkness').click(ev => this.onToggleAutoDarkness())
|
|
this.html.find('.calendar-btn').click(ev => this.onCalendarButton(ev));
|
|
this.html.find('.horloge-roue .horloge-heure').click(event => {
|
|
const h = this.html.find(event.currentTarget)?.data('heure');
|
|
this.positionnerHeure(Number(h));
|
|
})
|
|
this.html.find('.button-calendar-set-datetime').click(ev => {
|
|
ev.preventDefault();
|
|
this.showCalendarEditor();
|
|
});
|
|
|
|
this.html.find('.button-calendar-astrologie').click(ev => {
|
|
ev.preventDefault();
|
|
this.showAstrologieEditor();
|
|
});
|
|
this.positionAiguilles()
|
|
}
|
|
|
|
positionAiguilles() {
|
|
const timestamp = this.getTimestamp();
|
|
this.html.find(`div.horloge-roue div.horloge-aiguille-heure img`).css(Misc.cssRotation(timestamp.angleHeure));
|
|
this.html.find(`div.horloge-roue div.horloge-aiguille-minute img`).css(Misc.cssRotation(timestamp.angleMinute));
|
|
}
|
|
|
|
onToggleHorlogeAnalogique() {
|
|
this.horlogeAnalogique = !this.horlogeAnalogique;
|
|
this.savePosition()
|
|
this.display()
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
getNombresAstraux() {
|
|
return game.settings.get(SYSTEM_RDD, "liste-nombre-astral") ?? []
|
|
}
|
|
|
|
async setNombresAstraux(nombresAstraux) {
|
|
await game.settings.set(SYSTEM_RDD, "liste-nombre-astral", nombresAstraux)
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
dateCourante() {
|
|
return this.timestamp.formatDate();
|
|
}
|
|
|
|
dateReel() {
|
|
return new Date().toLocaleString("sv-SE", {
|
|
year: "numeric",
|
|
month: "2-digit",
|
|
day: "2-digit",
|
|
hour: "2-digit",
|
|
minute: "2-digit"
|
|
});
|
|
}
|
|
|
|
isAfterIndexDate(indexDate) {
|
|
// TODO: standardize
|
|
return indexDate < this.timestamp.indexDate;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
heureCourante() { return RdDTimestamp.definition(this.timestamp.heure); }
|
|
|
|
/* -------------------------------------------- */
|
|
getCurrentMinute() { return this.timestamp.indexMinute; }
|
|
|
|
getTimestamp() {
|
|
return this.timestamp;
|
|
}
|
|
getTimestampFinChateauDormant(nbJours = 0) {
|
|
return this.timestamp.nouveauJour().addJours(nbJours);
|
|
}
|
|
|
|
getTimestampFinHeure(nbHeures = 0) {
|
|
return this.timestamp.nouvelleHeure().addHeures(nbHeures);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
getIndexFromDate(jour, mois) {
|
|
const addYear = mois < this.timestamp.mois || (mois == this.timestamp.mois && jour < this.timestamp.jour)
|
|
const time = RdDTimestamp.timestamp(this.timestamp.annee + (addYear ? 1 : 0), mois, jour);
|
|
return time.indexDate;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
getJoursSuivants(count) {
|
|
return Misc.intArray(this.timestamp.indexDate, this.timestamp.indexDate + count)
|
|
.map(i => { return { label: RdDTimestamp.formatIndexDate(i), index: i } })
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
async ajouterNombreAstral(indexDate) {
|
|
const nombreAstral = await RdDDice.rollHeure( { showDice: HIDE_DICE, rollMode: "selfroll" });
|
|
return {
|
|
nombreAstral: nombreAstral,
|
|
lectures: [],
|
|
index: indexDate
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
async resetNombresAstraux() {
|
|
await Promise.all(game.actors.filter(it => it.type == "personnage").map(async it => await it.deleteNombresAstraux()))
|
|
await this.setNombresAstraux([])
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {*} indexDate la date pour laquelle obtenir le nombre astral. Si undefined, on prend la date du jour
|
|
* @returns le nombre astral pour la date, ou pour la date du jour si la date n'est pas fournie.
|
|
* Si aucun nombre astral n'est trouvé, retourne 0 (cas où l'on demanderait un nombre astral en dehors des 12 jours courant et à venir)
|
|
*/
|
|
getNombreAstral(indexDate = undefined) {
|
|
if (indexDate == undefined) {
|
|
indexDate = this.timestamp.indexDate;
|
|
}
|
|
const nombresAstraux = this.getNombresAstraux()
|
|
let astralData = nombresAstraux.find(it => it.index == indexDate);
|
|
return astralData?.nombreAstral ?? 0;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
async rebuildNombresAstraux() {
|
|
if (Misc.isFirstConnectedGM()) {
|
|
const nombresAstraux = this.getNombresAstraux()
|
|
let newNombresAstraux = [];
|
|
for (let i = 0; i < MAX_NOMBRE_ASTRAL; i++) {
|
|
let dayIndex = this.timestamp.indexDate + i;
|
|
let na = nombresAstraux.find(it => it.index == dayIndex);
|
|
if (na) {
|
|
newNombresAstraux[i] = na;
|
|
} else {
|
|
newNombresAstraux[i] = await this.ajouterNombreAstral(dayIndex);
|
|
}
|
|
}
|
|
game.actors.filter(it => it.isPersonnage()).forEach(actor => actor.supprimerAnciensNombresAstraux());
|
|
await this.setNombresAstraux(newNombresAstraux);
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
async setNewTimestamp(newTimestamp) {
|
|
const oldTimestamp = this.timestamp;
|
|
await Promise.all(game.actors.map(actor => actor.onTimeChanging(oldTimestamp, newTimestamp)))
|
|
RdDTimestamp.setWorldTime(newTimestamp);
|
|
if (oldTimestamp.indexDate + 1 == newTimestamp.indexDate && ReglesOptionnelles.isUsing("chateau-dormant-gardien")) {
|
|
await DialogChateauDormant.create();
|
|
}
|
|
this.timestamp = newTimestamp;
|
|
await this.rebuildNombresAstraux();
|
|
this.positionAiguilles()
|
|
this.display();
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
async onCalendarButton(ev) {
|
|
ev.preventDefault();
|
|
const calendarAvance = ev.currentTarget.attributes['data-calendar-avance'];
|
|
const calendarSet = ev.currentTarget.attributes['data-calendar-set'];
|
|
if (calendarAvance) {
|
|
await this.incrementTime(Number(calendarAvance.value));
|
|
}
|
|
else if (calendarSet) {
|
|
this.positionnerHeure(Number(calendarSet.value));
|
|
}
|
|
this.positionAiguilles()
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
async incrementTime(minutes = 0) {
|
|
if (game.user.isGM) {
|
|
await this.setNewTimestamp(this.timestamp.addMinutes(minutes));
|
|
Hooks.callAll(APP_ASTROLOGIE_REFRESH);
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
async incrementerJour() {
|
|
await this.setNewTimestamp(this.timestamp.nouveauJour());
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
async positionnerHeure(heure) {
|
|
if (game.user.isGM) {
|
|
const indexDate = this.timestamp.indexDate;
|
|
const addDay = this.timestamp.heure < heure ? 0 : 1;
|
|
const newTimestamp = new RdDTimestamp({ indexDate: indexDate + addDay }).addHeures(heure);
|
|
await this.setNewTimestamp(newTimestamp)
|
|
Hooks.callAll(APP_ASTROLOGIE_REFRESH);
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
getLectureAstrologieDifficulte(dateIndex) {
|
|
let indexNow = this.timestamp.indexDate;
|
|
let diffDay = dateIndex - indexNow;
|
|
return - Math.floor(diffDay / 2);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
async requestNombreAstral(request) {
|
|
const actor = game.actors.get(request.id);
|
|
if (Misc.isFirstConnectedGM()) { // Only once
|
|
console.log(request);
|
|
let jourDiff = this.getLectureAstrologieDifficulte(request.date);
|
|
let niveau = Number(request.astrologie.system.niveau) + Number(request.conditions) + Number(jourDiff) + Number(request.etat);
|
|
let rollData = {
|
|
caracValue: request.carac_vue,
|
|
finalLevel: niveau,
|
|
showDice: HIDE_DICE,
|
|
rollMode: "blindroll"
|
|
};
|
|
await RdDResolutionTable.rollData(rollData);
|
|
request.rolled = rollData.rolled;
|
|
request.isValid = request.rolled.isSuccess;
|
|
request.nbAstral = this.getNombreAstral(request.date);
|
|
|
|
if (request.rolled.isSuccess) {
|
|
if (request.rolled.isPart) {
|
|
// Gestion expérience (si existante)
|
|
request.competence = actor.getCompetence('Astrologie')
|
|
request.selectedCarac = actor.system.carac["vue"];
|
|
actor.ajoutExperience(request, 'hide');
|
|
}
|
|
}
|
|
else {
|
|
request.nbAstral = await RdDDice.rollTotal("1dhr" + request.nbAstral, {
|
|
rollMode: "selfroll", showDice: HIDE_DICE
|
|
});
|
|
}
|
|
// Mise à jour des nombres astraux du joueur
|
|
await this.addNbAstralJoueur(actor, request.date, request.nbAstral, request.isValid)
|
|
Hooks.callAll(APP_ASTROLOGIE_REFRESH)
|
|
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_app_astrologie_refresh", data: {} })
|
|
}
|
|
}
|
|
|
|
async addNbAstralJoueur(actor, date, nbAstral, isValid) {
|
|
const nombresAstraux = this.getNombresAstraux()
|
|
const astralData = nombresAstraux.find(it => it.index == date)
|
|
if (astralData) {
|
|
astralData.lectures.push({ actorId: actor.id, nombreAstral: nbAstral });
|
|
await this.setNombresAstraux(nombresAstraux);
|
|
await actor.ajouteNombreAstral(date, nbAstral, isValid);
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
getAjustementAstrologique(heureNaissance, name = undefined) {
|
|
const defHeure = RdDTimestamp.findHeure(heureNaissance);
|
|
if (defHeure) {
|
|
return RdDTimestamp.ajustementAstrologiqueHeure(defHeure.heure, this.getNombreAstral(), this.timestamp.heure);
|
|
}
|
|
else if (name) {
|
|
ui.notifications.warn(name + " n'a pas d'heure de naissance, ou elle est incorrecte : " + heureNaissance);
|
|
}
|
|
else {
|
|
ui.notifications.warn(heureNaissance + " ne correspond pas à une heure de naissance");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
async saveEditeur(calendrierData) {
|
|
const newTimestamp = RdDTimestamp.timestamp(
|
|
Number.parseInt(calendrierData.annee),
|
|
calendrierData.mois.heure,
|
|
Number.parseInt(calendrierData.jourMois),
|
|
calendrierData.heure.heure,
|
|
Number.parseInt(calendrierData.minutes)
|
|
);
|
|
await this.setNewTimestamp(newTimestamp);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
async showCalendarEditor() {
|
|
const calendrierData = this.fillCalendrierData();
|
|
if (this.editeur == undefined) {
|
|
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/time/calendar-editor.hbs', calendrierData);
|
|
this.editeur = new RdDCalendrierEditor(html, this, calendrierData)
|
|
}
|
|
this.editeur.updateData(calendrierData);
|
|
this.editeur.render(true);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
async showAstrologieEditor() {
|
|
await AppAstrologie.create();
|
|
}
|
|
|
|
async onToggleAutoDarkness() {
|
|
await AutoAdjustDarkness.toggle()
|
|
this.display()
|
|
}
|
|
}
|