437 lines
15 KiB
JavaScript
437 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, 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 };
|
|
/* -------------------------------------------- */
|
|
const { HandlebarsApplicationMixin } = foundry.applications.api;
|
|
export class RdDCalendrier extends HandlebarsApplicationMixin(foundry.applications.api.ApplicationV2) {
|
|
static PARTS = {
|
|
main: { template: TEMPLATE_CALENDRIER }
|
|
}
|
|
|
|
static DEFAULT_OPTIONS = {
|
|
classes: ["calendar"],
|
|
window: {
|
|
title: "Calendrier",
|
|
controls: []
|
|
},
|
|
position: {
|
|
top: 200,
|
|
left: 200,
|
|
width: 400,
|
|
height: 400
|
|
}
|
|
}
|
|
|
|
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
|
|
});
|
|
}
|
|
|
|
constructor() {
|
|
super({});
|
|
this.horlogeAnalogique = true;
|
|
const savedPos = game.settings.get(SYSTEM_RDD, "calendrier-pos");
|
|
if (savedPos?.top != undefined) {
|
|
this.position = { top: savedPos.top, left: savedPos.left, width: 400, height: 400 }
|
|
this.horlogeAnalogique = savedPos.horlogeAnalogique;
|
|
}
|
|
this.timestamp = RdDTimestamp.getWorldTime();
|
|
if (Misc.isFirstConnectedGM()) {
|
|
RdDTimestamp.setWorldTime(this.timestamp);
|
|
this.rebuildNombresAstraux();
|
|
}
|
|
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()
|
|
}
|
|
|
|
async display() {
|
|
AutoAdjustDarkness.adjust(RdDTimestamp.getWorldTime().darkness);
|
|
this.getSavePosition()
|
|
await this.render({ force: true });
|
|
return this;
|
|
}
|
|
|
|
async close() { }
|
|
|
|
async onUpdateSetting(setting, update, options, id) {
|
|
if (setting.key == SYSTEM_RDD + '.' + WORLD_TIMESTAMP_SETTING) {
|
|
this.timestamp = RdDTimestamp.getWorldTime();
|
|
this.positionAiguilles()
|
|
this.render();
|
|
Hooks.callAll(APP_ASTROLOGIE_REFRESH)
|
|
}
|
|
if (setting.key == SYSTEM_RDD + '.' + "liste-nombre-astral") {
|
|
Hooks.callAll(APP_ASTROLOGIE_REFRESH)
|
|
}
|
|
}
|
|
|
|
_prepareContext() {
|
|
const formData = {};
|
|
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;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
_onRender(context, options) {
|
|
super._onRender(context, options);
|
|
this.html = $(this.element);
|
|
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.positionAiguilles()
|
|
if (!game.user.isGM) return;
|
|
const hdr = this.element.querySelector('.window-header');
|
|
if (!hdr) return;
|
|
if (hdr.querySelector('[data-action="edit-calendar"]')) return;
|
|
const refBtn = hdr.querySelector('[data-action="toggleControls"]');
|
|
if (!refBtn) return;
|
|
const astroBtn = document.createElement('button');
|
|
astroBtn.type = 'button';
|
|
astroBtn.className = 'header-control icon fa-solid fa-moon-over-sun';
|
|
astroBtn.dataset.tooltip = 'Astrologie';
|
|
astroBtn.dataset.action = 'edit-astrology';
|
|
astroBtn.addEventListener('click', () => this.showAstrologieEditor());
|
|
hdr.insertBefore(astroBtn, refBtn);
|
|
const editBtn = document.createElement('button');
|
|
editBtn.type = 'button';
|
|
editBtn.className = 'header-control icon fa-solid fa-calendar-pen';
|
|
editBtn.dataset.tooltip = 'Éditer date';
|
|
editBtn.dataset.action = 'edit-calendar';
|
|
editBtn.addEventListener('click', () => this.showCalendarEditor());
|
|
hdr.insertBefore(editBtn, refBtn);
|
|
}
|
|
|
|
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) {
|
|
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: "self" });
|
|
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([])
|
|
}
|
|
|
|
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()) {
|
|
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: "blind"
|
|
};
|
|
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) {
|
|
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: "self", showDice: HIDE_DICE
|
|
});
|
|
}
|
|
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 foundry.applications.handlebars.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({ force: true });
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
async showAstrologieEditor() {
|
|
await AppAstrologie.create();
|
|
}
|
|
|
|
async onToggleAutoDarkness() {
|
|
await AutoAdjustDarkness.toggle()
|
|
this.display()
|
|
}
|
|
}
|