446 lines
15 KiB
JavaScript
446 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 { RdDUtility } from "../rdd-utility.js";
|
|
import { RdDDice } from "../rdd-dice.js";
|
|
import { Misc } from "../misc.js";
|
|
import { DialogChronologie } from "../dialog-chronologie.js";
|
|
import { HIDE_DICE, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "../constants.js";
|
|
import { ReglesOptionelles } from "../settings/regles-optionelles.js";
|
|
import { DialogChateauDormant } from "../sommeil/dialog-chateau-dormant.js";
|
|
import { APP_ASTROLOGIE_REFRESH, AppAstrologie } from "../sommeil/app-astrologie.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 init() {
|
|
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 mergeObject(super.defaultOptions, {
|
|
title: "Calendrier",
|
|
template: TEMPLATE_CALENDRIER,
|
|
classes: ["calendar"],
|
|
popOut: true,
|
|
resizable: false,
|
|
width: 'fit-content',
|
|
height: 'fit-content',
|
|
});
|
|
}
|
|
|
|
constructor() {
|
|
super();
|
|
this.timestamp = RdDTimestamp.getWorldTime();
|
|
if (Misc.isUniqueConnectedGM()) { // Uniquement si GM
|
|
RdDTimestamp.setWorldTime(this.timestamp);
|
|
this.nombresAstraux = this.getNombresAstraux();
|
|
this.rebuildNombresAstraux(HIDE_DICE); // 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() {
|
|
const pos = this.getSavePosition()
|
|
this.render(true, { left: pos.left, top: pos.top });
|
|
return this;
|
|
}
|
|
|
|
_getHeaderButtons() {
|
|
const buttons = [];
|
|
if (game.user.isGM) {
|
|
buttons.unshift({
|
|
class: "calendar-astrologie",
|
|
icon: "fa-solid fa-moon-over-sun",
|
|
onclick: ev => this.showAstrologieEditor()
|
|
},
|
|
{
|
|
class: "calendar-set-datetime",
|
|
icon: "fa-solid fa-calendar-pen",
|
|
onclick: ev => this.showCalendarEditor()
|
|
});
|
|
}
|
|
return buttons
|
|
}
|
|
|
|
/*async maximize() {
|
|
await super.maximize()
|
|
this.render(true)
|
|
}*/
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
getData() {
|
|
const formData = super.getData();
|
|
this.fillCalendrierData(formData);
|
|
return formData;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
fillCalendrierData(formData = {}) {
|
|
mergeObject(formData, this.timestamp.toCalendrier());
|
|
formData.isGM = game.user.isGM;
|
|
formData.heures = RdDTimestamp.definitions()
|
|
formData.horlogeAnalogique = this.horlogeAnalogique;
|
|
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('.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('.calendar-set-datetime').click(ev => {
|
|
ev.preventDefault();
|
|
this.showCalendarEditor();
|
|
});
|
|
|
|
this.html.find('.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") ?? [];
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
dateCourante() {
|
|
return this.timestamp.formatDate();
|
|
}
|
|
|
|
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, showDice = SHOW_DICE) {
|
|
const nombreAstral = await RdDDice.rollTotal("1dh", { showDice: showDice, rollMode: "selfroll" });
|
|
const dateFuture = RdDTimestamp.formatIndexDate(indexDate);
|
|
if (showDice != HIDE_DICE) {
|
|
ChatMessage.create({
|
|
whisper: ChatMessage.getWhisperRecipients("GM"),
|
|
content: `Le chiffre astrologique du ${dateFuture} sera le ${nombreAstral}`
|
|
});
|
|
}
|
|
return {
|
|
nombreAstral: nombreAstral,
|
|
valeursFausses: [],
|
|
index: indexDate
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
resetNombresAstraux() {
|
|
this.nombresAstraux = [];
|
|
game.settings.set(SYSTEM_RDD, "liste-nombre-astral", []);
|
|
|
|
game.socket.emit(SYSTEM_SOCKET_ID, {
|
|
msg: "msg_reset_nombre_astral",
|
|
data: {}
|
|
});
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @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;
|
|
}
|
|
this.nombresAstraux = this.getNombresAstraux();
|
|
let astralData = this.nombresAstraux.find((nombreAstral, i) => nombreAstral.index == indexDate);
|
|
return astralData?.nombreAstral ?? 0;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
async rebuildNombresAstraux(showDice = HIDE_DICE) {
|
|
if (Misc.isUniqueConnectedGM()) {
|
|
console.log("Astral rebuild")
|
|
let newList = [];
|
|
for (let i = 0; i < MAX_NOMBRE_ASTRAL; i++) {
|
|
let dayIndex = this.timestamp.indexDate + i;
|
|
let na = this.nombresAstraux.find(n => n.index == dayIndex);
|
|
if (na) {
|
|
newList[i] = na;
|
|
} else {
|
|
newList[i] = await this.ajouterNombreAstral(dayIndex, showDice);
|
|
}
|
|
}
|
|
this.nombresAstraux = newList;
|
|
game.settings.set(SYSTEM_RDD, "liste-nombre-astral", newList);
|
|
game.actors.filter(it => it.isPersonnage()).forEach(actor => actor.supprimerAnciensNombresAstraux());
|
|
this.notifyChangeNombresAstraux();
|
|
}
|
|
}
|
|
|
|
notifyChangeNombresAstraux() {
|
|
Hooks.callAll(APP_ASTROLOGIE_REFRESH);
|
|
game.socket.emit(SYSTEM_SOCKET_ID, {
|
|
msg: "msg_refresh_nombre_astral",
|
|
data: {}
|
|
});
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
async setNewTimestamp(newTimestamp) {
|
|
const oldTimestamp = this.timestamp;
|
|
await Promise.all(game.actors.map(async actor => await actor.onTimeChanging(oldTimestamp, newTimestamp)));
|
|
RdDTimestamp.setWorldTime(newTimestamp);
|
|
if (oldTimestamp.indexDate + 1 == newTimestamp.indexDate && ReglesOptionelles.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.isUniqueConnectedGM()) { // 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.appliquerAjoutExperience(request, 'hide');
|
|
}
|
|
}
|
|
else {
|
|
request.nbAstral = await RdDDice.rollTotal("1dhr" + request.nbAstral, {
|
|
rollMode: "selfroll", showDice: HIDE_DICE
|
|
});
|
|
// Mise à jour des nombres astraux du joueur
|
|
this.addNbAstralIncorect(request.id, request.date, request.nbAstral);
|
|
}
|
|
|
|
if (Misc.getActiveUser(request.userId)?.isGM) {
|
|
RdDUtility.responseNombreAstral(request);
|
|
} else {
|
|
game.socket.emit(SYSTEM_SOCKET_ID, {
|
|
msg: "msg_response_nombre_astral",
|
|
data: request
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
addNbAstralIncorect(actorId, date, nbAstral) {
|
|
const astralData = this.nombresAstraux.find((nombreAstral, i) => nombreAstral.index == date);
|
|
astralData.valeursFausses.push({ actorId: actorId, nombreAstral: nbAstral });
|
|
game.settings.set(SYSTEM_RDD, "liste-nombre-astral", this.nombresAstraux);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
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();
|
|
}
|
|
}
|