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
This commit is contained in:
Vincent Vandemeulebrouck 2023-01-05 00:55:04 +01:00
parent 11e4ad09d3
commit 912b1d3df3
41 changed files with 1020 additions and 576 deletions

View File

@ -18,7 +18,7 @@ import { RdDItemArme } from "./item-arme.js";
import { RdDAlchimie } from "./rdd-alchimie.js";
import { STATUSES, StatusEffects } from "./settings/status-effects.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { RdDItemSigneDraconique } from "./item-signedraconique.js";
import { RdDItemSigneDraconique } from "./item/item-signedraconique.js";
import { ReglesOptionelles } from "./settings/regles-optionelles.js";
import { EffetsDraconiques } from "./tmr/effets-draconiques.js";
import { Draconique } from "./tmr/draconique.js";
@ -30,10 +30,11 @@ import { RdDPossession } from "./rdd-possession.js";
import { ENTITE_BLURETTE, ENTITE_INCARNE, ENTITE_NONINCARNE, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { RdDConfirm } from "./rdd-confirm.js";
import { DialogValidationEncaissement } from "./dialog-validation-encaissement.js";
import { RdDRencontre } from "./item-rencontre.js";
import { RdDRencontre } from "./item/item-rencontre.js";
import { Targets } from "./targets.js";
import { DialogRepos } from "./dialog-repos.js";
import { RdDBaseActor } from "./actor/base-actor.js";
import { RdDTimestamp } from "./rdd-timestamp.js";
const POSSESSION_SANS_DRACONIC = {
img: 'systems/foundryvtt-reve-de-dragon/icons/entites/possession.webp',
@ -933,7 +934,7 @@ export class RdDActor extends RdDBaseActor {
let expLog = duplicate(this.system.experiencelog);
expLog.push({
mode: Misc.upperFirst(modeXP), valeur: valeurXP, raison: Misc.upperFirst(raisonXP),
daterdd: game.system.rdd.calendrier.getDateFromIndex(),
daterdd: game.system.rdd.calendrier.dateCourante(),
datereel: `${d.getDate()}/${d.getMonth() + 1}/${d.getFullYear()}`
});
await this.update({ [`system.experiencelog`]: expLog });
@ -2727,11 +2728,11 @@ export class RdDActor extends RdDBaseActor {
/* -------------------------------------------- */
getHeureNaissance() {
if (this.isCreatureEntite()) {
return 0;
}
if (this.isPersonnage()) {
return this.system.heure;
}
return 0;
}
/* -------------------------------------------- */
ajustementAstrologique() {
@ -2818,10 +2819,16 @@ export class RdDActor extends RdDBaseActor {
/* -------------------------------------------- */
async ajouteNombreAstral(callData) {
const indexDate = Number.parseInt(callData.date);
// Ajout du nombre astral
const item = {
name: "Nombre Astral", type: "nombreastral", system:
{ value: callData.nbAstral, istrue: callData.isvalid, jourindex: Number(callData.date), jourlabel: game.system.rdd.calendrier.getDateFromIndex(Number(callData.date)) }
{
value: callData.nbAstral,
istrue: callData.isvalid,
jourindex: indexDate,
jourlabel: RdDTimestamp.formatIndexDate(indexDate)
}
};
await this.createEmbeddedDocuments("Item", [item]);
// Affichage Dialog
@ -2830,7 +2837,7 @@ export class RdDActor extends RdDBaseActor {
async supprimerAnciensNombresAstraux() {
const toDelete = this.listItems('nombreastral')
.filter(it => it.system.jourindex < game.system.rdd.calendrier.getCurrentDayIndex())
.filter(it => game.system.rdd.calendrier.isAfterIndexDate(it.system.jourindex))
.map(it => it._id);
await this.deleteEmbeddedDocuments("Item", toDelete);
}
@ -3694,6 +3701,7 @@ export class RdDActor extends RdDBaseActor {
await this.onCreateOwnedDraconique(item, options, id);
break;
}
await item.onCreateItemTemporel(this);
await item.onCreateDecoupeComestible(this);
}

View File

@ -1,7 +1,6 @@
import { ChatUtility } from "../chat-utility.js";
import { SYSTEM_SOCKET_ID } from "../constants.js";
import { Monnaie } from "../item-monnaie.js";
import { RdDItem } from "../item.js";
import { Misc } from "../misc.js";
import { RdDAudio } from "../rdd-audio.js";
import { RdDUtility } from "../rdd-utility.js";

View File

@ -25,7 +25,7 @@ export class DialogChronologie extends Dialog {
journaux: game.journal.filter(it => it.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)),
dateRdD: dateRdD,
jourRdD: dateRdD.jour +1,
heureRdD: game.system.rdd.calendrier.getCurrentHeure(),
heureRdD: game.system.rdd.calendrier.heureCourante().key,
dateReel: DialogChronologie.getCurrentDateTime()
};
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-chronologie.html", dialogData);

View File

@ -1,6 +1,6 @@
import { ChatUtility } from "./chat-utility.js";
import { HtmlUtility } from "./html-utility.js";
import { RdDItemSigneDraconique } from "./item-signedraconique.js";
import { RdDItemSigneDraconique } from "./item/item-signedraconique.js";
import { TMRUtility } from "./tmr-utility.js";
export class DialogCreateSigneDraconique extends Dialog {

View File

@ -1,4 +1,4 @@
import { RdDRencontre } from "./item-rencontre.js";
import { RdDRencontre } from "./item/item-rencontre.js";
import { RdDItemSheet } from "./item-sheet.js";
export class RdDRencontreItemSheet extends RdDItemSheet {

View File

@ -10,6 +10,7 @@ import { SYSTEM_RDD } from "./constants.js";
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
import { SystemCompendiums } from "./settings/system-compendiums.js";
import { Misc } from "./misc.js";
import { RdDTimestamp } from "./rdd-timestamp.js";
/**
* Extend the basic ItemSheet for RdD specific items
@ -135,11 +136,7 @@ export class RdDItemSheet extends ItemSheet {
RdDGemme.calculDataDerivees(this.item);
}
if (this.item.type == 'potion') {
if (this.dateUpdated) {
formData.system.prdate = this.dateUpdated;
this.dateUpdated = undefined;
}
await RdDHerbes.updatePotionData(formData);
await RdDHerbes.addPotionFormData(formData);
}
if (formData.isOwned && this.item.type == 'herbe' && (formData.system.categorie == 'Soin' || formData.system.categorie == 'Repos')) {
formData.isIngredientPotionBase = true;
@ -185,10 +182,12 @@ export class RdDItemSheet extends ItemSheet {
}
})
this.html.find('.enchanteDate').change((event) => {
let jour = Number(this.html.find('[name="splitDate.day"]').val());
let mois = this.html.find('[name="splitDate.month"]').val();
this.dateUpdated = game.system.rdd.calendrier.getIndexFromDate(jour, mois);
this.html.find('.date-enchantement').change((event) => {
const jour = Number(this.html.find('input.date-enchantement[name="enchantement.jour"]').val());
const mois = RdDTimestamp.definition(this.html.find('select.date-enchantement[name="enchantement.mois"]').val());
const indexDate = game.system.rdd.calendrier.getIndexFromDate(jour, mois.heure);
this.item.update({'system.prdate': indexDate});
console.warn(`Date d'enchantement modifiée ${jour}/${mois.heure}: ${indexDate}`)
});
this.html.find('.creer-tache-livre').click((event) => this._getEventActor(event).creerTacheDepuisLivre(this.item));

View File

@ -1,5 +1,5 @@
import { RdDItemSheet } from "./item-sheet.js";
import { RdDItemSigneDraconique } from "./item-signedraconique.js";
import { RdDItemSigneDraconique } from "./item/item-signedraconique.js";
import { TMRUtility } from "./tmr-utility.js";
/**

View File

@ -2,6 +2,7 @@ import { DialogItemVente } from "./dialog-item-vente.js";
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
import { RdDHerbes } from "./rdd-herbes.js";
import { RdDTimestamp } from "./rdd-timestamp.js";
import { RdDUtility } from "./rdd-utility.js";
import { SystemCompendiums } from "./settings/system-compendiums.js";
@ -30,6 +31,7 @@ const typesObjetsDraconiques = ["queue", "ombre", "souffle", "tete", "signedraco
const typesObjetsConnaissance = ["meditation", "recettealchimique", "sort"]
const typesObjetsEffet = ["possession", "poison", "maladie"]
const typesObjetsCompetence = ["competence", "competencecreature"]
const typesObjetsTemporels = ["poison", "maladie", "queue", "ombre", "souffle", "signedraconique", "rencontre"]
const encBrin = 0.00005; // un brin = 1 décigramme = 1/10g = 1/10000kg = 1/20000 enc
const encPepin = 0.0007; /* un pépin de gemme = 1/10 cm3 = 1/1000 l = 3.5/1000 kg = 7/2000 kg = 7/1000 enc
densité 3.5 (~2.3 à 4, parfois plus) -- https://www.juwelo.fr/guide-des-pierres/faits-et-chiffres/
@ -152,24 +154,15 @@ export class RdDItem extends Item {
isMonnaie() { return this.type == 'monnaie'; }
isNourritureBoisson() { return this.type == 'nourritureboisson'; }
isService() { return this.type == 'service'; }
isCompetence() {
return typesObjetsCompetence.includes(this.type)
}
isInventaire(mode = 'materiel') {
return RdDItem.getItemTypesInventaire(mode).includes(this.type);
}
isOeuvre() {
return typesObjetsOeuvres.includes(this.type)
}
isDraconique() {
return typesObjetsDraconiques.includes(this.type)
}
isEffet() {
return typesObjetsEffet.includes(this.type)
}
isConnaissance() {
return typesObjetsConnaissance.includes(this.type)
}
isCompetence() { return typesObjetsCompetence.includes(this.type) }
isTemporel() { return typesObjetsTemporels.includes(this.type) }
isOeuvre() { return typesObjetsOeuvres.includes(this.type) }
isDraconique() { return typesObjetsDraconiques.includes(this.type) }
isEffet() { return typesObjetsEffet.includes(this.type) }
isConnaissance() { return typesObjetsConnaissance.includes(this.type) }
isInventaire(mode = 'materiel') { return RdDItem.getItemTypesInventaire(mode).includes(this.type); }
getItemGroup() {
if (this.isInventaire()) return "equipement";
@ -383,6 +376,40 @@ export class RdDItem extends Item {
await item.delete();
}
async onCreateItemTemporel(actor) {
if (this.isTemporel()) {
const timestampDebut = game.system.rdd.calendrier.timestamp;
const timestampFin = await this.calculerFinPeriodeTemporel(timestampDebut);
await actor.updateEmbeddedDocuments('Item', [{
_id: this.id,
'system.temporel.debut': duplicate(timestampDebut),
'system.temporel.fin': duplicate(timestampFin),
}])
}
}
async calculerFinPeriodeTemporel(timestampDebut) {
return timestampDebut;
}
async prolongerPeriode() {
if (this.actor) {
const current = game.system.rdd.calendrier.timestamp;
const finPeriode = new RdDTimestamp(this.system.temporel.fin)
const periodeSuivante = (finPeriode.compare(current)>0 ? finPeriode : current);
const timestampFin = await this.calculerFinPeriodeTemporel(periodeSuivante);
await this.actor.updateEmbeddedDocuments('Item', [{
_id: this.id,
'system.temporel.fin': duplicate(timestampFin),
}])
}
}
async onFinTemporel() {
await this.actor?.deleteEmbeddedDocuments('Item', [this.id]);
}
async quantiteIncDec(nombre, options = { supprimerSiZero: false }) {
const quantite = Number(this.system.quantite ?? -1);
if (quantite >= 0) {

View File

@ -1,4 +1,5 @@
import { EffetsRencontre } from "./effets-rencontres.js";
import { EffetsRencontre } from "../effets-rencontres.js";
import { RdDItem } from "../item.js";
const tableEffets = [
{ code: "messager", resultat: "succes", description: "Envoie un message à (force) cases", method: EffetsRencontre.messager },
@ -36,7 +37,11 @@ const tableEffets = [
// { code: "epart-souffle", resultat: "echec", description: "Souffle de dragon sur échec particulier" },
];
export class RdDRencontre {
export class RdDRencontre extends RdDItem {
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp";
}
static getEffetsSucces() { return RdDRencontre.getEffets("succes"); }
static getEffetsEchec() { return RdDRencontre.getEffets("echec"); }
@ -68,4 +73,8 @@ export class RdDRencontre {
}
}
async calculerFinPeriodeTemporel(debut) {
return await debut.nouvelleHeure().addHeures(12);
}
}

View File

@ -1,4 +1,4 @@
import { RdDItem } from "./item.js";
import { RdDItem } from "../item.js";
export class RdDItemService extends RdDItem {

View File

@ -1,8 +1,9 @@
import { defaultItemImg } from "./item.js";
import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js";
import { RdDRollTables } from "./rdd-rolltables.js";
import { TMRType, TMRUtility } from "./tmr-utility.js";
import { RdDItem, defaultItemImg } from "../item.js";
import { Misc } from "../misc.js";
import { RdDDice } from "../rdd-dice.js";
import { RdDRollTables } from "../rdd-rolltables.js";
import { RdDTimestamp } from "../rdd-timestamp.js";
import { TMRType, TMRUtility } from "../tmr-utility.js";
const tableSignesIndicatifs = [
{ rarete: "Très facile", difficulte: 0, xp: 6, nbCases: 14 },
@ -15,7 +16,17 @@ const tableSignesIndicatifs = [
const DIFFICULTE_LECTURE_SIGNE_MANQUE = +11;
export class RdDItemSigneDraconique {
export class RdDItemSigneDraconique extends RdDItem {
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/tmr/signe_draconique.webp";
}
async calculerFinPeriodeTemporel(debut) {
// TODO
return RdDTimestamp.formulesDuree().find(it => it.code == "").calcul(debut, this.actor);
}
static prepareSigneDraconiqueMeditation(meditation, rolled) {
return {

13
module/item/maladie.js Normal file
View File

@ -0,0 +1,13 @@
import { RdDItem } from "../item.js";
export class RdDItemMaladie extends RdDItem {
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/maladies_venins/maladie.webp";
}
async calculerFinPeriodeTemporel(debut) {
return await debut.addPeriode(this.system.periode.nombre, this.system.periode.unite) ;
}
}

18
module/item/ombre.js Normal file
View File

@ -0,0 +1,18 @@
import { RdDItem } from "../item.js";
export class RdDItemOmbre extends RdDItem {
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp";
}
async calculerFinPeriodeTemporel(debut) {
return await debut.appliquerDuree(this.system.duree, this.parent);
}
async onFinTemporel() {
// fin de période
await this.prolongerPeriode();
}
}

17
module/item/poison.js Normal file
View File

@ -0,0 +1,17 @@
import { RdDItem } from "../item.js";
export class RdDItemPoison extends RdDItem {
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/maladies_venins/venin.webp";
}
async calculerFinPeriodeTemporel(debut) {
return await debut.addPeriode(this.system.periode.nombre, this.system.periode.unite) ;
}
async onFinTemporel() {
// fin de période
await this.prolongerPeriode();
}
}

13
module/item/queue.js Normal file
View File

@ -0,0 +1,13 @@
import { RdDItem } from "../item.js";
export class RdDItemQueue extends RdDItem {
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp";
}
async calculerFinPeriodeTemporel(debut) {
return await debut.appliquerDuree(this.system.duree, this.parent);
}
}

13
module/item/souffle.js Normal file
View File

@ -0,0 +1,13 @@
import { RdDItem } from "../item.js";
export class RdDItemSouffle extends RdDItem {
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/souffle_dragon.webp";
}
async calculerFinPeriodeTemporel(debut) {
return await debut.appliquerDuree(this.system.duree, this.parent);
}
}

View File

@ -15,7 +15,7 @@
// Common conf
let dialogConf = { content: html, title: "Editeur d'Astrologie", buttons: myButtons, default: "saveButton" };
let dialogOptions = { classes: ["rdd-roll-dialog"], width: 600, height: 300, 'z-index': 99999 }
let dialogOptions = { classes: ["rdd-roll-dialog"], width: 600, height: 'fit-content', 'z-index': 99999 }
super(dialogConf, dialogOptions)
this.calendrier = calendrier;

View File

@ -1,4 +1,4 @@
import { Misc } from "./misc.js";
import { RdDTimestamp } from "./rdd-timestamp.js";
/**
* Extend the base Dialog entity by defining a custom window to perform roll.
@ -12,7 +12,7 @@ export class RdDCalendrierEditeur extends Dialog {
content: html,
title: "Editeur de date/heure",
buttons: {
save: { label: "Enregistrer", callback: html => this.fillData() }
save: { label: "Enregistrer", callback: html => this.saveCalendrier() }
},
default: "save"
};
@ -26,22 +26,42 @@ export class RdDCalendrierEditeur extends Dialog {
activateListeners(html) {
super.activateListeners(html);
this.html = html;
this.html.find("input[name='nomMois']").val(this.calendrierData.moisKey);
this.html.find("input[name='annee']").val(this.calendrierData.annee);
this.html.find("select[name='nomMois']").val(this.calendrierData.moisKey);
this.html.find("input[name='jourMois']").val(this.calendrierData.jourMois);
this.html.find("select[name='nomHeure']").val(this.calendrierData.heureKey);
this.html.find("select[name='jourMois']").val(this.calendrierData.jourMois);
this.html.find("select[name='minutesRelative']").val(this.calendrierData.minutesRelative);
this.html.find("select[name='annee']").val(this.calendrierData.annee);
this.html.find("input[name='minutesRelative']").val(this.calendrierData.minutesRelative);
this.html.find("input[name='jourMois']").change(event => {
const jour = Number.parseInt(this.html.find("input[name='jourMois']").val());
if (jour < 1) {
this.html.find("input[name='jourMois']").val(1);
}
if (jour > 28) {
this.html.find("input[name='jourMois']").val(28);
}
});
this.html.find("input[name='minutesRelative']").change(event => {
const minute = Number.parseInt(this.html.find("input[name='minutesRelative']").val());
if (minute < 0) {
this.html.find("input[name='minutesRelative']").val(0);
}
if (minute > 119) {
this.html.find("input[name='minutesRelative']").val(119);
}
});
}
/* -------------------------------------------- */
fillData() {
this.calendrierData.annee = this.html.find("input[name='annee']").val();
this.calendrierData.moisKey = this.html.find("select[name='nomMois']").val();
this.calendrierData.heureKey = this.html.find("select[name='nomHeure']").val();
this.calendrierData.jourMois = this.html.find("select[name='jourMois']").val();
this.calendrierData.minutesRelative = this.html.find("select[name='minutesRelative']").val();
saveCalendrier() {
const annee = Number.parseInt(this.html.find("input[name='annee']").val());
const mois = this.html.find("select[name='nomMois']").val();
const jour = Number.parseInt(this.html.find("input[name='jourMois']").val());
const heure = this.html.find("select[name='nomHeure']").val();
const minute = Number.parseInt(this.html.find("input[name='minutesRelative']").val());
this.calendrier.saveEditeur(this.calendrierData)
this.calendrier.setNewTimestamp(RdDTimestamp.timestamp(annee, mois, jour, heure, minute))
}
/* -------------------------------------------- */

View File

@ -1,32 +1,14 @@
/* -------------------------------------------- */
import { RdDCalendrierEditeur } from "./rdd-calendrier-editeur.js";
import { RdDAstrologieEditeur } from "./rdd-astrologie-editeur.js";
import { HtmlUtility } from "./html-utility.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDUtility } from "./rdd-utility.js";
import { Grammar } from "./grammar.js";
import { RdDDice } from "./rdd-dice.js";
import { Misc } from "./misc.js";
import { HIDE_DICE, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { DialogChronologie } from "./dialog-chronologie.js";
import { RdDTimestamp } from "./rdd-timestamp.js";
/* -------------------------------------------- */
const dossierIconesHeures = 'systems/foundryvtt-reve-de-dragon/icons/heures/'
const heuresList = ["vaisseau", "sirene", "faucon", "couronne", "dragon", "epees", "lyre", "serpent", "poissonacrobate", "araignee", "roseau", "chateaudormant"];
const heuresDef = {
"vaisseau": { key: "vaisseau", label: "Vaisseau", lettreFont: 'v', saison: "printemps", heure: 0, icon: 'hd01.svg' },
"sirene": { key: "sirene", label: "Sirène", lettreFont: 'i', saison: "printemps", heure: 1, icon: 'hd02.svg' },
"faucon": { key: "faucon", label: "Faucon", lettreFont: 'f', saison: "printemps", heure: 2, icon: 'hd03.svg' },
"couronne": { key: "couronne", label: "Couronne", lettreFont: '', saison: "ete", heure: 3, icon: 'hd04.svg' },
"dragon": { key: "dragon", label: "Dragon", lettreFont: 'd', saison: "ete", heure: 4, icon: 'hd05.svg' },
"epees": { key: "epees", label: "Epées", lettreFont: 'e', saison: "ete", heure: 5, icon: 'hd06.svg' },
"lyre": { key: "lyre", label: "Lyre", lettreFont: 'l', saison: "automne", heure: 6, icon: 'hd07.svg' },
"serpent": { key: "serpent", label: "Serpent", lettreFont: 's', saison: "automne", heure: 7, icon: 'hd08.svg' },
"poissonacrobate": { key: "poissonacrobate", label: "Poisson Acrobate", lettreFont: 'p', saison: "automne", heure: 8, icon: 'hd09.svg' },
"araignee": { key: "araignee", label: "Araignée", lettreFont: 'a', saison: "hiver", heure: 9, icon: 'hd10.svg' },
"roseau": { key: "roseau", label: "Roseau", lettreFont: 'r', saison: "hiver", heure: 10, icon: 'hd11.svg' },
"chateaudormant": { key: "chateaudormant", label: "Château Dormant", lettreFont: 'c', saison: "hiver", heure: 11, icon: 'hd12.svg' }
};
const saisonsDef = {
"printemps": { label: "Printemps" },
"ete": { label: "Eté" },
@ -34,11 +16,10 @@ const saisonsDef = {
"hiver": { label: "Hiver" }
};
const RDD_MOIS_PAR_AN = 12;
export const RDD_JOUR_PAR_MOIS = 28;
const RDD_JOUR_PAR_MOIS = 28;
const RDD_HEURES_PAR_JOUR = 12;
const RDD_MINUTES_PAR_HEURES = 120;
const MAX_NOMBRE_ASTRAL = 12;
const JOURS_DU_MOIS = Array(RDD_JOUR_PAR_MOIS).fill().map((item, index) => 1 + index);
/* -------------------------------------------- */
export class RdDCalendrier extends Application {
@ -55,57 +36,6 @@ export class RdDCalendrier extends Application {
return { top: 200, left: 200 };
}
static getDefSigne(chiffre) {
chiffre = chiffre % RDD_MOIS_PAR_AN;
return Object.values(heuresDef).find(h => h.heure == chiffre);
}
static getSigneAs(key, value) {
const heure = (typeof value == 'string' || typeof value == 'number') && Number.isInteger(Number(value))
? Number(value)
: (typeof value == 'string') ? RdDCalendrier.getChiffreFromSigne(value)
: undefined
if (heure != undefined && ['key', 'label', 'lettreFont', 'saison', 'heure', 'icon'].includes(key)) {
return RdDCalendrier.getDefSigne(heure)[key]
}
if (heure != undefined && ['webp'].includes(key)) {
return RdDCalendrier.getDefSigne(heure)['icon'].replace('svg', 'webp');
}
console.error(`Appel à getSigneAs('${key}', ${value}) avec une clé/heure incorrects`);
return value;
}
static getChiffreFromSigne(signe) {
return heuresList.indexOf(signe);
}
static createCalendrierInitial() {
return {
heureRdD: 0,
minutesRelative: 0,
indexJour: 0,
annee: 0,
moisRdD: 0,
moisLabel: heuresDef["vaisseau"].label,
jour: 0
}
}
getCalendrier(index) {
index = index ?? this.getCurrentDayIndex();
const mois = Math.floor(index / RDD_JOUR_PAR_MOIS) % RDD_MOIS_PAR_AN;
return {
heureRdD: 0, // Index dans heuresList / heuresDef[x].heure
minutesRelative: 0,
indexJour: index,
annee: Math.floor(index / (RDD_JOUR_PAR_MOIS * RDD_MOIS_PAR_AN)),
moisRdD: RdDCalendrier.getDefSigne(mois).heure,
moisLabel: RdDCalendrier.getDefSigne(mois).label,
jour: (index % RDD_JOUR_PAR_MOIS) // Le calendrier stocke le jour en 0-27, mais en 1-28 à l'affichage
}
}
constructor() {
super();
// position
@ -114,19 +44,19 @@ export class RdDCalendrier extends Application {
this.calendrierPos = RdDCalendrier.createCalendrierPos();
game.settings.set(SYSTEM_RDD, "calendrier-pos", this.calendrierPos);
}
// Calendrier
this.calendrier = duplicate(game.settings.get(SYSTEM_RDD, "calendrier") ?? RdDCalendrier.createCalendrierInitial());
this.calendrier.annee = this.calendrier.annee ?? Math.floor((this.calendrier.moisRdD ?? 0) / RDD_MOIS_PAR_AN);
this.calendrier.moisRdD = (this.calendrier.moisRdD ?? 0) % RDD_MOIS_PAR_AN;
this.timestamp = new RdDTimestamp({});
if (Misc.isUniqueConnectedGM()) { // Uniquement si GM
game.settings.set(SYSTEM_RDD, "calendrier", this.calendrier);
RdDTimestamp.setWorldTime(this.timestamp);
this.listeNombreAstral = this.getListeNombreAstral();
this.rebuildListeNombreAstral(HIDE_DICE); // Ensure always up-to-date
}
console.log('RdDCalendrier.constructor()', this.calendrier, this.calendrierPos, this.listeNombreAstral);
console.log('RdDCalendrier.constructor()', this.timestamp, this.timestamp.toOldCalendrier(), this.calendrierPos, this.listeNombreAstral);
}
getCalendrier() {
return this.timestamp.toOldCalendrier();
}
/* -------------------------------------------- */
@ -227,48 +157,49 @@ export class RdDCalendrier extends Application {
}
/* -------------------------------------------- */
getDateFromIndex(index) {
const dateRdD = this.getCalendrier(index);
return (dateRdD.jour + 1) + ' ' + dateRdD.moisLabel;
dateCourante() {
return this.timestamp.formatDate();
}
isAfterIndexDate(indexDate) {
return indexDate < this.timestamp.indexDate;
}
/* -------------------------------------------- */
getDayMonthFromIndex(index = undefined) {
const dateRdD = this.getCalendrier(index);
return {
day: dateRdD.jour + 1,
month: heuresList[dateRdD.moisRdD]
}
}
heureCourante() { return RdDTimestamp.definition(this.timestamp.heure); }
/* -------------------------------------------- */
getCurrentHeure() {
return heuresList[this.calendrier.heureRdD];
getCurrentMinute() { return this.timestamp.indexMinute; }
getTimestampFinChateauDormant(nbJours = 0) {
return this.timestamp.nouveauJour().addJour(nbJours);
}
/* -------------------------------------------- */
getCurrentDayIndex() {
return (((this.calendrier.annee ?? 0) * RDD_MOIS_PAR_AN + (this.calendrier.moisRdD ?? 0)) * RDD_JOUR_PAR_MOIS) + (this.calendrier.jour ?? 0);
getTimestampFinHeure(nbHeures = 0) {
return this.timestamp.nouvelleHeure().addHeures(nbHeures);
}
/* -------------------------------------------- */
getIndexFromDate(jour, mois) {
return (heuresDef[mois].heure * RDD_JOUR_PAR_MOIS) + jour - 1;
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(num) {
getJoursSuivants(count) {
let jours = [];
let index = this.getCurrentDayIndex();
for (let i = 0; i < num; i++) {
jours[i] = { label: this.getDateFromIndex(index + i), index: index + i };
let indexDate = this.timestamp.indexDate;
for (let i = 0; i < count; i++, indexDate++) {
jours[i] = { label: RdDTimestamp.formatIndexDate(indexDate), index: indexDate };
}
return jours;
}
/* -------------------------------------------- */
async ajouterNombreAstral(index, showDice = SHOW_DICE) {
async ajouterNombreAstral(indexDate, showDice = SHOW_DICE) {
const nombreAstral = await RdDDice.rollTotal("1dh", { showDice: showDice, rollMode: "selfroll" });
const dateFuture = this.getDateFromIndex(index);
const dateFuture = RdDTimestamp.formatIndexDate(indexDate);
if (showDice != HIDE_DICE) {
ChatMessage.create({
whisper: ChatMessage.getWhisperRecipients("GM"),
@ -278,14 +209,13 @@ export class RdDCalendrier extends Application {
return {
nombreAstral: nombreAstral,
valeursFausses: [],
index: index
index: indexDate
}
}
/* -------------------------------------------- */
getCurrentNombreAstral() {
let indexDate = this.getCurrentDayIndex();
return this.getNombreAstral(indexDate);
return this.getNombreAstral(this.timestamp.indexDate);
}
/* -------------------------------------------- */
@ -309,10 +239,9 @@ export class RdDCalendrier extends Application {
/* -------------------------------------------- */
async rebuildListeNombreAstral(showDice = HIDE_DICE) {
if (Misc.isUniqueConnectedGM()) {
let jourCourant = this.getCurrentDayIndex();
let newList = [];
for (let i = 0; i < MAX_NOMBRE_ASTRAL; i++) {
let dayIndex = jourCourant + i;
let dayIndex = this.timestamp.indexDate + i;
let na = this.listeNombreAstral.find(n => n.index == dayIndex);
if (na) {
newList[i] = na;
@ -320,25 +249,31 @@ export class RdDCalendrier extends Application {
newList[i] = await this.ajouterNombreAstral(dayIndex, showDice);
}
}
game.settings.set(SYSTEM_RDD, "liste-nombre-astral", newList);
this.listeNombreAstral = newList;
game.settings.set(SYSTEM_RDD, "liste-nombre-astral", newList);
}
}
/* -------------------------------------------- */
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));
async setNewTimestamp(newTimestamp) {
this.checkMaladiePoison(this.timestamp, newTimestamp);
this.checkMaladie("round");
this.checkMaladie("minute");
if (this.timestamp.heure != newTimestamp.heure || this.timestamp.indexDate != newTimestamp.indexDate) {
this.checkMaladie("heure");
}
else if (calendarSet) {
this.positionnerHeure(Number(calendarSet.value));
if (this.timestamp.indexDate != newTimestamp.indexDate) {
this.checkMaladie("jour");
}
RdDTimestamp.setWorldTime(newTimestamp);
this.timestamp = newTimestamp;
await this.rebuildListeNombreAstral();
this.updateDisplay();
}
/* -------------------------------------------- */
checkMaladie(periode) {
for (let actor of game.actors) {
@ -357,77 +292,94 @@ export class RdDCalendrier extends Application {
}
}
/* -------------------------------------------- */
async incrementTime(minutes = 0) {
this.calendrier.minutesRelative += minutes;
this.checkMaladie("round");
this.checkMaladie("minute");
if (this.calendrier.minutesRelative >= RDD_MINUTES_PAR_HEURES) {
this.calendrier.minutesRelative -= RDD_MINUTES_PAR_HEURES;
this.calendrier.heureRdD += 1;
this.checkMaladie("heure");
checkMaladiePoison(oldTimestamp, newTimestamp) {
// TODO
const isInPeriod = maladie => {
//TODO: utiliser les timestamp
return false;
}
if (this.calendrier.heureRdD >= RDD_HEURES_PAR_JOUR) {
this.calendrier.heureRdD -= RDD_HEURES_PAR_JOUR;
await this.incrementerJour();
this.checkMaladie("heure");
this.checkMaladie("jour");
game.actors.filter(it => it.type == 'personnage')
.forEach(actor => {
actor.items.filter(it => it.type == 'maladie' || (it.type == 'poison' && it.system.active))
.filter(m => isInPeriod(m))
.forEach(m => {
if (m.system.identifie) {
ChatMessage.create({ content: `${actor.name} souffre de ${m.name} (${m.type}): vérifiez que les effets ne se sont pas aggravés !` });
} else {
ChatMessage.create({ content: `${actor.name} souffre d'un mal inconnu (${m.type}): vérifiez que les effets ne se sont pas aggravés !` });
}
game.settings.set(SYSTEM_RDD, "calendrier", duplicate(this.calendrier));
// Notification aux joueurs // TODO: replace with Hook on game settings update
game.socket.emit(SYSTEM_SOCKET_ID, {
msg: "msg_sync_time",
data: duplicate(this.calendrier)
let itemMaladie = actor.getItem(m.id)
itemMaladie.postItemToChat('gmroll');
})
});
}
/* -------------------------------------------- */
async incrementerJour() {
const index = this.getCurrentDayIndex() + 1;
this.calendrier = this.getCalendrier(index);
await this.rebuildListeNombreAstral();
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.updateDisplay();
}
/* -------------------------------------------- */
syncPlayerTime(calendrier) {
this.calendrier = duplicate(calendrier); // Local copy update
async incrementTime(minutes = 0) {
await this.setNewTimestamp(this.timestamp.addMinutes(minutes));
}
/* -------------------------------------------- */
async incrementerJour() {
await this.setNewTimestamp(this.timestamp.nouveauJour());
}
/* -------------------------------------------- */
syncPlayerTime(timestamp) {
this.timestamp = new RdDTimestamp(timestamp);
this.updateDisplay();
}
/* -------------------------------------------- */
async positionnerHeure(indexHeure) {
if (indexHeure <= this.calendrier.heureRdD) {
await this.incrementerJour();
}
this.calendrier.heureRdD = indexHeure;
this.calendrier.minutesRelative = 0;
game.settings.set(SYSTEM_RDD, "calendrier", duplicate(this.calendrier));
await this.setNewTimestamp(new RdDTimestamp({ indexDate: this.timestamp.indexDate + (this.timestamp.heure < indexHeure ? 0 : 1) }).addHeures(indexHeure))
}
/* -------------------------------------------- */
fillCalendrierData(formData = {}) {
const mois = RdDCalendrier.getDefSigne(this.calendrier.moisRdD);
const heure = RdDCalendrier.getDefSigne(this.calendrier.heureRdD);
console.log('fillCalendrierData', this.calendrier, mois, heure);
const mois = RdDTimestamp.definition(this.timestamp.mois);
const heure = RdDTimestamp.definition(this.timestamp.heure);
formData.annee = this.timestamp.annee;
formData.moisKey = mois.key;
formData.nomMois = mois.label; // heures et mois nommés identiques
formData.iconMois = mois.icon;
formData.nomSaison = saisonsDef[mois.saison].label;
formData.jourMois = this.timestamp.jour + 1;
formData.heureKey = heure.key;
formData.moisKey = mois.key;
formData.jourMois = this.calendrier.jour + 1;
formData.nomMois = mois.label; // heures et mois nommés identiques
formData.annee = this.calendrier.annee;
formData.iconMois = dossierIconesHeures + mois.icon;
formData.heureRdD = this.timestamp.heure;
formData.nomHeure = heure.label;
formData.iconHeure = dossierIconesHeures + heure.icon;
formData.nomSaison = saisonsDef[mois.saison].label;
formData.heureRdD = this.calendrier.heureRdD;
formData.minutesRelative = this.calendrier.minutesRelative;
formData.iconHeure = heure.icon;
formData.minutesRelative = this.timestamp.minute;
formData.isGM = game.user.isGM;
console.log('fillCalendrierData', this.timestamp, mois, heure, formData);
return formData;
}
/* -------------------------------------------- */
getLectureAstrologieDifficulte(dateIndex) {
let indexNow = this.getCurrentDayIndex();
let indexNow = this.timestamp.indexDate;
let diffDay = dateIndex - indexNow;
return - Math.floor(diffDay / 2);
}
@ -483,55 +435,32 @@ export class RdDCalendrier extends Application {
game.settings.set(SYSTEM_RDD, "liste-nombre-astral", this.listeNombreAstral);
}
/* -------------------------------------------- */
findHeure(heure) {
heure = Grammar.toLowerCaseNoAccentNoSpace(heure);
let parHeureOuLabel = Object.values(heuresDef).filter(it => (it.heure + 1) == parseInt(heure) || Grammar.toLowerCaseNoAccentNoSpace(it.label) == heure);
if (parHeureOuLabel.length == 1) {
return parHeureOuLabel[0];
}
let parLabelPartiel = Object.values(heuresDef).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;
}
/* -------------------------------------------- */
getHeureNumber(hNum) {
let heure = Object.values(heuresDef).find(it => (it.heure) == hNum);
return heure
getHeureChance(heure) {
return heure + (this.getCurrentNombreAstral() ?? 1) - 1;
}
/* -------------------------------------------- */
getHeuresChanceMalchance(heureNaissance) {
let heuresChancesMalchances = [];
let defHeure = this.findHeure(heureNaissance);
let defHeure = RdDTimestamp.findHeure(heureNaissance);
if (defHeure) {
let hn = defHeure.heure;
let chiffreAstral = this.getCurrentNombreAstral() ?? 0;
heuresChancesMalchances[0] = { value: "+4", heures: [this.getHeureNumber((hn + chiffreAstral) % RDD_HEURES_PAR_JOUR).label] };
heuresChancesMalchances[1] = {
value: "+2", heures: [this.getHeureNumber((hn + chiffreAstral + 4) % RDD_HEURES_PAR_JOUR).label,
this.getHeureNumber((hn + chiffreAstral + 8) % RDD_HEURES_PAR_JOUR).label]
};
heuresChancesMalchances[2] = { value: "-4", heures: [this.getHeureNumber((hn + chiffreAstral + 6) % RDD_HEURES_PAR_JOUR).label] };
heuresChancesMalchances[3] = {
value: "-2", heures: [this.getHeureNumber((hn + chiffreAstral + 3) % RDD_HEURES_PAR_JOUR).label,
this.getHeureNumber((hn + chiffreAstral + 9) % RDD_HEURES_PAR_JOUR).label]
};
const signe = h => h % RDD_HEURES_PAR_JOUR;
const chance = this.getHeureChance(defHeure.heure);
return [
{ ajustement: "+4", heures: [signe(chance)] },
{ ajustement: "+2", heures: [signe(chance + 4), signe(chance + 8)] },
{ ajustement: "-4", heures: [signe(chance + 6)] },
{ ajustement: "-2", heures: [signe(chance + 3), signe(chance + 9)] }
];
}
return heuresChancesMalchances;
return [];
}
/* -------------------------------------------- */
getAjustementAstrologique(heureNaissance, name = undefined) {
let defHeure = this.findHeure(heureNaissance);
let defHeure = RdDTimestamp.findHeure(heureNaissance);
if (defHeure) {
let hn = defHeure.heure;
let chiffreAstral = this.getCurrentNombreAstral() ?? 0;
let heureCourante = this.calendrier.heureRdD;
let ecartChance = (hn + chiffreAstral - heureCourante) % RDD_HEURES_PAR_JOUR;
const chance = this.getHeureChance(defHeure.heure);
const ecartChance = (chance - this.timestamp.heure) % RDD_HEURES_PAR_JOUR;
switch (ecartChance) {
case 0: return 4;
case 4: case 8: return 2;
@ -551,9 +480,7 @@ export class RdDCalendrier extends Application {
/* -------------------------------------------- */
getData() {
let formData = super.getData();
this.fillCalendrierData(formData);
this.setPos(this.calendrierPos);
return formData;
}
@ -602,30 +529,20 @@ export class RdDCalendrier extends Application {
/* -------------------------------------------- */
async saveEditeur(calendrierData) {
this.calendrier.minutesRelative = Number(calendrierData.minutesRelative);
this.calendrier.jour = Number(calendrierData.jourMois) - 1;
this.calendrier.moisRdD = RdDCalendrier.getChiffreFromSigne(calendrierData.moisKey);
this.calendrier.annee = Number(calendrierData.annee);
this.calendrier.heureRdD = RdDCalendrier.getChiffreFromSigne(calendrierData.heureKey);
game.settings.set(SYSTEM_RDD, "calendrier", duplicate(this.calendrier));
await this.rebuildListeNombreAstral();
game.socket.emit(SYSTEM_SOCKET_ID, {
msg: "msg_sync_time",
data: duplicate(this.calendrier)
});
this.updateDisplay();
const newTimestamp = RdDTimestamp.timestamp(
Number.parseInt(calendrierData.annee),
RdDTimestamp.definition(calendrierData.moisKey).heure,
Number.parseInt(calendrierData.jourMois),
RdDTimestamp.definition(calendrierData.heureKey).heure,
Number.parseInt(calendrierData.minutesRelative)
);
await this.setNewTimestamp(newTimestamp);
}
/* -------------------------------------------- */
async showCalendarEditor() {
let calendrierData = duplicate(this.fillCalendrierData());
let calendrierData = this.fillCalendrierData();
if (this.editeur == undefined) {
calendrierData.jourMoisOptions = RdDCalendrier.buildJoursMois();
calendrierData.heuresOptions = [0, 1];
calendrierData.minutesOptions = Array(RDD_MINUTES_PAR_HEURES).fill().map((item, index) => 0 + index);
let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/calendar-editor-template.html', calendrierData);
this.editeur = new RdDCalendrierEditeur(html, this, calendrierData)
}
@ -633,33 +550,30 @@ export class RdDCalendrier extends Application {
this.editeur.render(true);
}
static buildJoursMois() {
return Array(RDD_JOUR_PAR_MOIS).fill().map((item, index) => 1 + index);
}
static buildJoursMois() { return JOURS_DU_MOIS; }
/* -------------------------------------------- */
async showAstrologieEditor() {
let calendrierData = duplicate(this.fillCalendrierData());
let astrologieArray = [];
const calendrierData = duplicate(this.fillCalendrierData());
this.listeNombreAstral = this.listeNombreAstral || [];
for (let astralData of this.listeNombreAstral) {
astralData.humanDate = this.getDateFromIndex(astralData.index);
for (let vf of astralData.valeursFausses) {
calendrierData.astrologieData = this.listeNombreAstral.map(astro => {
const timestamp = new RdDTimestamp({ indexDate: astro.index });
astro.date = { mois: timestamp.mois, jour: timestamp.jour + 1 }
for (let vf of astro.valeursFausses) {
let actor = game.actors.get(vf.actorId);
vf.actorName = (actor) ? actor.name : "Inconnu";
}
astrologieArray.push(duplicate(astralData));
}
let heuresParActeur = {};
for (let actor of game.actors) {
return astro;
});
calendrierData.heuresParActeur = {};
game.actors.filter(it => it.isPersonnage() && it.hasPlayerOwner).forEach(actor => {
let heureNaissance = actor.getHeureNaissance();
if (heureNaissance) {
heuresParActeur[actor.name] = this.getHeuresChanceMalchance(heureNaissance);
calendrierData.heuresParActeur[actor.name] = this.getHeuresChanceMalchance(heureNaissance);
}
}
//console.log("ASTRO", astrologieArray);
calendrierData.astrologieData = astrologieArray;
calendrierData.heuresParActeur = heuresParActeur;
})
let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/calendar-astrologie-template.html', calendrierData);
let astrologieEditeur = new RdDAstrologieEditeur(html, this, calendrierData)
astrologieEditeur.updateData(calendrierData);

View File

@ -1,7 +1,6 @@
import { RdDUtility } from "./rdd-utility.js";
import { RdDCalendrier } from "./rdd-calendrier.js";
import { Grammar } from "./grammar.js";
import { SystemCompendiums } from "./settings/system-compendiums.js";
import { RdDTimestamp } from "./rdd-timestamp.js";
/* -------------------------------------------- */
export class RdDHerbes extends Item {
@ -29,7 +28,7 @@ export class RdDHerbes extends Item {
}
/* -------------------------------------------- */
static async updatePotionData(formData) {
static async addPotionFormData(formData) {
formData.isSoins = formData.system.categorie.includes('Soin');
formData.isRepos = formData.system.categorie.includes('Repos');
if (formData.isSoins) {
@ -40,9 +39,8 @@ export class RdDHerbes extends Item {
}
formData.herbesSoins = RdDHerbes.buildHerbesList(this.herbesSoins, 12);
formData.herbesRepos = RdDHerbes.buildHerbesList(this.herbesRepos, 7);
formData.jourMoisOptions = RdDCalendrier.buildJoursMois();
formData.dateActuelle = game.system.rdd.calendrier.getDateFromIndex();
formData.splitDate = game.system.rdd.calendrier.getDayMonthFromIndex(formData.system.prdate);
formData.dateActuelle = game.system.rdd.calendrier.dateCourante();
formData.enchantement = RdDTimestamp.splitIndexDate(formData.system.prdate);
}
/* -------------------------------------------- */

View File

@ -1,10 +1,6 @@
import { SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { RdDActor } from "./actor.js";
import { RdDItemSheet } from "./item-sheet.js";
import { RdDActorSheet } from "./actor-sheet.js";
import { RdDActorCreatureSheet } from "./actor-creature-sheet.js";
import { RdDActorVehiculeSheet } from "./actor-vehicule-sheet.js";
import { RdDActorEntiteSheet } from "./actor-entite-sheet.js";
import { RdDItem } from "./item.js";
import { RdDUtility } from "./rdd-utility.js";
import { TMRUtility } from "./tmr-utility.js";
import { RdDCalendrier } from "./rdd-calendrier.js";
@ -19,26 +15,40 @@ import { ReglesOptionelles } from "./settings/regles-optionelles.js";
import { RdDHotbar } from "./rdd-hotbar-drop.js"
import { EffetsDraconiques } from "./tmr/effets-draconiques.js";
import { RdDHerbes } from "./rdd-herbes.js";
import { RdDItem } from "./item.js";
import { RdDDice } from "./rdd-dice.js";
import { RdDPossession } from "./rdd-possession.js";
import { RdDSigneDraconiqueItemSheet } from "./item-signedraconique-sheet.js";
import { Misc } from "./misc.js";
import { Migrations } from './migrations.js';
import { DialogChronologie } from "./dialog-chronologie.js";
import { SystemCompendiums } from "./settings/system-compendiums.js";
import { RdDRencontreItemSheet } from "./item-rencontre-sheet.js";
import { TMRRencontres } from "./tmr-rencontres.js";
import { RdDHerbeItemSheet } from "./item-herbe-sheet.js";
import { Environnement } from "./environnement.js";
import { RdDIngredientItemSheet } from "./item-ingredient-sheet.js";
import { RdDFauneItemSheet } from "./item-faune-sheet.js";
import { RdDConteneurItemSheet } from "./item-conteneur-sheet.js";
import { RdDServiceItemSheet } from "./item-service-sheet.js";
import { RdDItemService } from "./item-service.js";
import { RdDItemService } from "./item/item-service.js";
import { RdDBaseActor } from "./actor/base-actor.js";
import { RdDCommerceSheet } from "./actor/commerce-sheet.js";
import { RdDCommerce } from "./actor/commerce.js";
import { RdDTimestamp } from "./rdd-timestamp.js";
import { RdDItemMaladie } from "./item/maladie.js";
import { RdDItemPoison } from "./item/poison.js";
import { RdDItemSigneDraconique } from "./item/item-signedraconique.js";
import { RdDItemQueue } from "./item/queue.js";
import { RdDItemOmbre } from "./item/ombre.js";
import { RdDItemSouffle } from "./item/souffle.js";
import { RdDRencontre } from "./item/item-rencontre.js";
import { RdDActorSheet } from "./actor-sheet.js";
import { RdDActorCreatureSheet } from "./actor-creature-sheet.js";
import { RdDActorVehiculeSheet } from "./actor-vehicule-sheet.js";
import { RdDActorEntiteSheet } from "./actor-entite-sheet.js";
import { RdDItemSheet } from "./item-sheet.js";
import { RdDServiceItemSheet } from "./item-service-sheet.js";
import { RdDHerbeItemSheet } from "./item-herbe-sheet.js";
import { RdDRencontreItemSheet } from "./item-rencontre-sheet.js";
import { RdDIngredientItemSheet } from "./item-ingredient-sheet.js";
import { RdDFauneItemSheet } from "./item-faune-sheet.js";
import { RdDConteneurItemSheet } from "./item-conteneur-sheet.js";
import { RdDSigneDraconiqueItemSheet } from "./item-signedraconique-sheet.js";
import { TMRRencontres } from "./tmr-rencontres.js";
/**
* RdD system
@ -57,7 +67,14 @@ export class SystemReveDeDragon {
this.RdDUtility = RdDUtility;
this.RdDHotbar = RdDHotbar;
this.itemClasses = {
service: RdDItemService
service: RdDItemService,
maladie: RdDItemMaladie,
poison: RdDItemPoison,
queue: RdDItemQueue,
ombre: RdDItemOmbre,
souffle: RdDItemSouffle,
signedraconique: RdDItemSigneDraconique,
rencontre: RdDRencontre
}
this.actorClasses = {
creature: RdDActor,
@ -145,6 +162,7 @@ export class SystemReveDeDragon {
CONFIG.Combat.documentClass = RdDCombatManager;
// préparation des différents modules
RdDTimestamp.init();
SystemCompendiums.init();
DialogChronologie.init();
ReglesOptionelles.init();
@ -181,15 +199,6 @@ export class SystemReveDeDragon {
default: "avant-encaissement"
});
/* -------------------------------------------- */
game.settings.register(SYSTEM_RDD, "calendrier", {
name: "calendrier",
scope: "world",
config: false,
default: RdDCalendrier.createCalendrierInitial(),
type: Object
});
/* -------------------------------------------- */
game.settings.register(SYSTEM_RDD, "liste-nombre-astral", {
name: "liste-nombre-astral",

292
module/rdd-timestamp.js Normal file
View File

@ -0,0 +1,292 @@
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
}
}
}

View File

@ -15,8 +15,9 @@ import { HtmlUtility } from "./html-utility.js";
import { ReglesOptionelles } from "./settings/regles-optionelles.js";
import { RdDDice } from "./rdd-dice.js";
import { STATUSES } from "./settings/status-effects.js";
import { RdDRencontre } from "./item-rencontre.js";
import { RdDRencontre } from "./item/item-rencontre.js";
import { RdDCalendrier } from "./rdd-calendrier.js";
import { RdDTimestamp } from "./rdd-timestamp.js";
/* -------------------------------------------- */
@ -840,7 +841,7 @@ export class RdDTMRDialog extends Dialog {
async processSortReserve(sortReserve) {
await this.actor.deleteEmbeddedDocuments('Item', [sortReserve.id]);
console.log("declencheSortEnReserve", sortReserve);
const heureCible = RdDCalendrier.getSigneAs('label', sortReserve.system.heurecible);
const heureCible = RdDTimestamp.definition(sortReserve.system.heurecible).label;
this._tellToUserAndGM(`Vous avez déclenché
${sortReserve.system.echectotal ? "<strong>l'échec total!</strong>" : "le sort"}
en réserve <strong>${sortReserve.name}</strong>

View File

@ -12,11 +12,10 @@ import { Monnaie } from "./item-monnaie.js";
import { RdDPossession } from "./rdd-possession.js";
import { RdDNameGen } from "./rdd-namegen.js";
import { RdDConfirm } from "./rdd-confirm.js";
import { RdDCalendrier } from "./rdd-calendrier.js";
import { Environnement } from "./environnement.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDCommerce } from "./actor/commerce.js";
import { RdDTimestamp } from "./rdd-timestamp.js";
/* -------------------------------------------- */
// This table starts at 0 -> niveau -10
@ -177,9 +176,11 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/scripts/autocomplete-script.hbs',
'systems/foundryvtt-reve-de-dragon/templates/scripts/autocomplete.hbs',
'systems/foundryvtt-reve-de-dragon/templates/item/boutons-comestible.html',
'systems/foundryvtt-reve-de-dragon/templates/item/temporel.hbs',
'systems/foundryvtt-reve-de-dragon/templates/item/partial-inventaire.html',
'systems/foundryvtt-reve-de-dragon/templates/item/partial-environnement.html',
'systems/foundryvtt-reve-de-dragon/templates/item/partial-tab-environnement.html',
'systems/foundryvtt-reve-de-dragon/templates/item-queue-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/header-item.html',
// partial enums
'systems/foundryvtt-reve-de-dragon/templates/enum-caracteristiques.html',
@ -200,6 +201,8 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/enum-tmr-type.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-tmr-effet.html',
// Partials
'systems/foundryvtt-reve-de-dragon/templates/common/timestamp.hbs',
'systems/foundryvtt-reve-de-dragon/templates/common/enum-duree.hbs',
'systems/foundryvtt-reve-de-dragon/templates/common/compendium-link.hbs',
'systems/foundryvtt-reve-de-dragon/templates/partial-description-overflow.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-description-sort.html',
@ -279,7 +282,13 @@ export class RdDUtility {
Handlebars.registerHelper('caseTmr-type', coord => TMRUtility.getTMRType(coord));
Handlebars.registerHelper('typeTmr-name', type => TMRUtility.typeTmrName(type));
Handlebars.registerHelper('effetRencontre-name', coord => TMRUtility.typeTmrName(coord));
Handlebars.registerHelper('signeHeure', (key, heure) => RdDCalendrier.getSigneAs(key, heure));
// TODO: upgrade
Handlebars.registerHelper('signeHeure', (key, heure) => RdDTimestamp.signeHeure(key, heure));
Handlebars.registerHelper('timestamp-imgSigneHeure', (heure) => { return new Handlebars.SafeString(RdDTimestamp.imgSigneHeure(heure)) });
Handlebars.registerHelper('timestamp-imgSigne', (heure) => { return new Handlebars.SafeString(RdDTimestamp.imgSigne(heure)) });
Handlebars.registerHelper('timestamp-extract', timestamp => new RdDTimestamp(timestamp).toCalendrier());
Handlebars.registerHelper('timestamp-formulesDuree', () => RdDTimestamp.formulesDuree());
Handlebars.registerHelper('min', (...args) => Math.min(...args.slice(0, -1)));
Handlebars.registerHelper('regle-optionnelle', (option) => ReglesOptionelles.isUsing(option));
Handlebars.registerHelper('trier', list => list.sort((a, b) => a.name.localeCompare(b.name)));
@ -338,69 +347,6 @@ export class RdDUtility {
return undefined;
}
/* -------------------------------------------- */
static filterItemsPerTypeForSheet(formData, itemTypes) {
RdDUtility.filterEquipementParType(formData, itemTypes);
formData.sorts = this.arrayOrEmpty(itemTypes['sort']);
formData.rencontres = this.arrayOrEmpty(itemTypes['rencontre']);
formData.casestmr = this.arrayOrEmpty(itemTypes['casetmr']);
formData.signesdraconiques = this.arrayOrEmpty(itemTypes['signedraconique']);
formData.queues = this.arrayOrEmpty(itemTypes['queue']);
formData.souffles = this.arrayOrEmpty(itemTypes['souffle']);
formData.ombres = this.arrayOrEmpty(itemTypes['ombre']);
formData.tetes = this.arrayOrEmpty(itemTypes['tete']);
formData.taches = this.arrayOrEmpty(itemTypes['tache']);
formData.meditations = this.arrayOrEmpty(itemTypes['meditation']);
formData.chants = this.arrayOrEmpty(itemTypes['chant']);
formData.danses = this.arrayOrEmpty(itemTypes['danse']);
formData.musiques = this.arrayOrEmpty(itemTypes['musique']);
formData.oeuvres = this.arrayOrEmpty(itemTypes['oeuvre']);
formData.jeux = this.arrayOrEmpty(itemTypes['jeu']);
formData.services = this.arrayOrEmpty(itemTypes['service']);
formData.recettescuisine = this.arrayOrEmpty(itemTypes['recettecuisine']);
formData.recettesAlchimiques = this.arrayOrEmpty(itemTypes['recettealchimique']);
formData.maladies = this.arrayOrEmpty(itemTypes['maladie']);
formData.poisons = this.arrayOrEmpty(itemTypes['poison']);
formData.possessions = this.arrayOrEmpty(itemTypes['possession']);
formData.maladiesPoisons = formData.maladies.concat(formData.poisons);
formData.competences = (itemTypes['competence'] ?? []).concat(itemTypes['competencecreature'] ?? []);
formData.sortsReserve = this.arrayOrEmpty(itemTypes['sortreserve']);
}
static filterEquipementParType(formData, itemTypes) {
formData.conteneurs = this.arrayOrEmpty(itemTypes['conteneur']);
formData.materiel = this.arrayOrEmpty(itemTypes['objet']);
formData.armes = this.arrayOrEmpty(itemTypes['arme']);
formData.armures = this.arrayOrEmpty(itemTypes['armure']);
formData.munitions = this.arrayOrEmpty(itemTypes['munition']);
formData.livres = this.arrayOrEmpty(itemTypes['livre']);
formData.potions = this.arrayOrEmpty(itemTypes['potion']);
formData.ingredients = this.arrayOrEmpty(itemTypes['ingredient']);
formData.faunes = this.arrayOrEmpty(itemTypes['faune']);
formData.herbes = this.arrayOrEmpty(itemTypes['herbe']);
formData.monnaie = this.arrayOrEmpty(itemTypes['monnaie']).sort(Monnaie.triValeurEntiere());
formData.nourritureboissons = this.arrayOrEmpty(itemTypes['nourritureboisson']);
formData.gemmes = this.arrayOrEmpty(itemTypes['gemme']);
formData.objets = formData.conteneurs
.concat(formData.materiel)
.concat(formData.armes)
.concat(formData.armures)
.concat(formData.munitions)
.concat(formData.livres)
.concat(formData.potions)
.concat(formData.ingredients)
.concat(formData.herbes)
.concat(formData.faunes)
.concat(formData.monnaie)
.concat(formData.nourritureboissons)
.concat(formData.gemmes);
}
/* -------------------------------------------- */
static buildArbreDeConteneurs(conteneurs, objets) {
let objetVersConteneur = {};
@ -934,10 +880,10 @@ export class RdDUtility {
/* -------------------------------------------- */
static afficherHeuresChanceMalchance(heureNaissance) {
if (game.user.isGM) {
let heure = game.system.rdd.calendrier.findHeure(heureNaissance);
const heure = RdDTimestamp.findHeure(heureNaissance - 1);
if (heureNaissance && heure) {
let ajustement = game.system.rdd.calendrier.getAjustementAstrologique(heureNaissance);
const current = game.system.rdd.calendrier.findHeure(game.system.rdd.calendrier.getCurrentHeure());
const current = game.system.rdd.calendrier.heureCourante();
ChatMessage.create({
content: `A l'heure de <strong>${current.label}</strong>, le modificateur de Chance/Malchance est de <strong>${Misc.toSignedString(ajustement)}</strong> pour l'heure de naissance <strong>${heure.label}</strong>.`,
whisper: ChatMessage.getWhisperRecipients("GM")

View File

@ -59,24 +59,16 @@ export class TMRRencontres {
return rencontre.clone({
'system.force': await RdDDice.rollTotal(rencontre.system.formule),
'system.coord': tmr?.coord,
'system.date': game.system.rdd.calendrier.getDateFromIndex(),
'system.heure': game.system.rdd.calendrier.getCurrentHeure()
'system.date': game.system.rdd.calendrier.dateCourante(),
'system.heure': game.system.rdd.calendrier.heureCourante().key
}, { save: false });
}
async calculRencontre(rencontre, tmr = undefined) {
if (rencontre.system.coord == "") {
rencontre.system.coord = tmr?.coord;
}
if (rencontre.system.force == 0) {
rencontre.system.force = await RdDDice.rollTotal(rencontre.system.formule);
}
if (rencontre.system.date == "") {
rencontre.system.date = game.system.rdd.calendrier.getDateFromIndex();
}
if (rencontre.system.heure == "") {
rencontre.system.heure = game.system.rdd.calendrier.getCurrentHeure();
}
rencontre.system.coord = rencontre.system.coord ?? tmr?.coord;
rencontre.system.force = rencontre.system.force ?? await RdDDice.rollTotal(rencontre.system.formule);
rencontre.system.date = rencontre.system.date ?? game.system.rdd.calendrier.dateCourante();
rencontre.system.heure = rencontre.system.heure ?? game.system.rdd.calendrier.heureCourante().key;
return rencontre;
}

View File

@ -476,6 +476,12 @@ input:is(.blessure-premiers_soins, .blessure-soins_complets) {
border-width: 0;
border: 1px solid rgba(0, 0, 0, 0);
}
.img-signe-heure {
vertical-align: bottom;
max-width: 1.5rem;
max-height: 1.5rem;
border-width: 0;
}
.button-effect-img {
vertical-align: baseline;
max-width: 16px;
@ -1607,21 +1613,13 @@ div.competence-column div.categorie-competence{
.calendar-btn-edit{
grid-row: 1;
grid-column: 1;
margin: auto;
color: rgba(0, 0, 0, 0.5);
}
.astrologie-btn-edit:hover,
.calendar-btn-edit:hover {
color: #FFF;
border: 0px solid #000;
cursor: pointer;
}
.calendar-btn{
:is(.astrologie-btn-edit,.calendar-btn-edit,.calendar-btn){
margin: auto;
border: 1px solid rgba(0, 0, 0, 0);
color: rgba(255, 255, 255, 0.5);
}
.calendar-btn:hover {
:is(.astrologie-btn-edit,.calendar-btn-edit,.calendar-btn):hover {
color: var(--color-controls-hover);
border: 1px solid var(--color-control-border-hover);
cursor: pointer;

View File

@ -565,6 +565,18 @@
"description": "",
"descriptionmj": ""
},
"temporel": {
"temporel": {
"debut": {
"indexDate": 0,
"indexMinute": 0
},
"fin": {
"indexDate": 0,
"indexMinute": 0
}
}
},
"equipement": {
"equipe": false
},
@ -617,19 +629,27 @@
"date": 0
},
"maladie": {
"templates": [ "description" ],
"templates": ["description", "temporel"],
"identifie": false,
"malignite": 0,
"periodicite": "",
"periode": {
"unite": "",
"nombre": 0
},
"remedesconnus": false,
"remedes": "",
"dommages": ""
},
"poison": {
"templates": [ "description" ],
"templates": ["description", "temporel"],
"identifie": false,
"malignite": 0,
"periodicite": "",
"periode": {
"unite": "",
"nombre": 0
},
"remedesconnus": false,
"remedes": "",
"dommages": "",
@ -693,7 +713,7 @@
"force": 0
},
"herbe": {
"templates": [ "description", "inventaire", "environnement"],
"templates": ["description", "inventaire", "environnement", "comestible"],
"niveau": 0,
"base": 0,
"categorie": ""
@ -724,7 +744,7 @@
"niveau_maximum": 0
},
"potion": {
"templates": [ "description", "inventaire" ],
"templates": ["description", "inventaire", "temporel"],
"rarete": "",
"categorie": "",
"herbe": "",
@ -826,7 +846,7 @@
"echectotal": false
},
"rencontre": {
"templates": [ "description" ],
"templates": ["description", "temporel"],
"genre": "f",
"formule": "2d4",
"refoulement": 1,
@ -868,7 +888,7 @@
}
},
"queue": {
"templates": [ "description" ],
"templates": ["description", "temporel"],
"frequence": 0,
"hautrevant": false,
"categorie": "",
@ -877,7 +897,7 @@
"restant": 0
},
"ombre": {
"templates": [ "description" ],
"templates": ["description", "temporel"],
"frequence": 0,
"hautrevant": false,
"categorie": "false",
@ -886,7 +906,7 @@
"restant": 0
},
"souffle": {
"templates": [ "description" ],
"templates": ["description", "temporel"],
"frequence": 0,
"hautrevant": false,
"duree": "",
@ -918,7 +938,7 @@
"malus": 0
},
"signedraconique": {
"templates": [ "description" ],
"templates": ["description", "temporel"],
"typesTMR": [],
"ephemere": true,
"duree": "1 round",

View File

@ -0,0 +1,56 @@
<form class="{{cssClass}}" autocomplete="off">
<header class="sheet-header">
<div class="header-fields">
<h1 class="charname">Horoscope</h1>
</div>
</header>
{{!-- Sheet Body --}}
<section class="sheet-body">
<div class="form-group">
<table class='table-nombres-astraux'>
<tr class='table-nombres-astraux-td'>
<th>Date</th>
{{#each astrologieData as |nombreData key|}}
<td class='table-nombres-astraux-td'>{{nombreData.date.jour}}{{timestamp-imgSigneHeure nombreData.date.mois}}</td>
{{/each}}
</tr>
<tr class='table-nombres-astraux-td'>
<th>Nombre astral</th>
{{#each astrologieData as |nombreData key|}}
<td class='table-nombres-astraux-td'>
<ol>
<b>{{nombreData.nombreAstral}}</b>
{{#each nombreData.valeursFausses as |fausseVal key|}}
<li>{{fausseVal.actorName}} - {{fausseVal.nombreAstral}}</li>
{{/each}}
</ol>
</td>
{{/each}}
</tr>
</table>
</div>
<div>
<table>
<tr>
<td></td>
<td><strong>+4</strong></td>
<td><strong>+2</strong></td>
<td><strong>-2</strong></td>
<td><strong>-4</strong></td>
</tr>
{{#each heuresParActeur as |heuresDef name|}}
<tr>
<td><strong>{{name}}</strong>:</td>
{{#each heuresDef as |ajustement|}}
<td>
{{#each ajustement.heures as |heure|}}
{{timestamp-imgSigneHeure heure}}
{{/each}}
</td>
{{/each}}
</tr>
{{/each}}
</table>
</div>
</section>
</form>

View File

@ -4,17 +4,18 @@
<h1 class="charname">Horoscope</h1>
</div>
</header>
{{!-- Sheet Body --}}
<section class="sheet-body">
<div class="form-group">
<table class='table-nombres-astraux'>
<tr class='table-nombres-astraux-td'>
<th>Date</th>
{{#each astrologieData as |nombreData key|}}
<td class='table-nombres-astraux-td'>{{nombreData.humanDate}}</td>
<td class='table-nombres-astraux-td'>{{nombreData.date.jour}}{{timestamp-imgSigneHeure nombreData.date.mois}}</td>
{{/each}}
</tr>
<tr class='table-nombres-astraux-td'>
<th>Nombre astral</th>
{{#each astrologieData as |nombreData key|}}
<td class='table-nombres-astraux-td'>
<ol>
@ -29,22 +30,23 @@
</table>
</div>
<div>
<ul>
<ul class="alterne-list">
{{#each heuresParActeur as |heuresDef name|}}
<li><strong>{{name}} </strong></li>
<ul class="list-item-margin1">
{{#each heuresDef as |heure idx|}}
<li><strong>{{heure.value}}</strong> :
{{#each heure.heures as |heureName idx|}}
{{heureName}}&nbsp;
<li class="list-item flexrow">
<span><strong>{{name}}</strong>:</span>
<span class="flex-grow-2">
|{{#each heuresDef as |ajustement|}}
<span>
{{#each ajustement.heures as |heure|}}
{{timestamp-imgSigneHeure heure}}
{{/each}}
</li>
|
</span>
{{/each}}
</ul>
</span>
</li>
{{/each}}
</ul>
</div>
</section>
</form>

View File

@ -8,44 +8,36 @@
{{!-- Sheet Body --}}
<section class="sheet-body">
<div class="form-group">
<label for="annee">Année</label>
<input type="text" name="annee" value="{{annee}}" data-dtype="Number" min="0"/>
<div class="flexcol flex-shrink">
<label for="jourMois">Jour</label>
<input type="number" class="number-x4" name="jourMois" value="{{jourMois}}" data-dtype="Number" min="1" max="28"/>
</div>
<div class="form-group">
<label for="mois">Mois</label>
<div class="flexcol">
<label for="nomMois">Mois</label>
<select name="nomMois" data-dtype="String">
{{#select nomMois}}
{{>"systems/foundryvtt-reve-de-dragon/templates/enum-heures.html"}}
{{/select}}
</select>
</div>
<div class="form-group">
<label for="jour">Jour du mois </label>
<select name="jourMois" data-dtype="String">
{{#select jourMois}}
{{#each jourMoisOptions as |key|}}
<option value={{key}}>{{numberFormat key decimals=0}}</option>
{{/each}}
{{/select}}
</select>
<div class="flexcol flex-shrink">
<label for="annee">Année</label>
<input type="number" class="number-x4" name="annee" value="{{annee}}" data-dtype="Number" min="0"/>
</div>
</div>
<div class="form-group">
<label for="heure">Heure Draconique</label>
<div class="flexcol">
<label for="nomHeure">Heure</label>
<select name="nomHeure" data-dtype="String">
{{#select nomHeure}}
{{>"systems/foundryvtt-reve-de-dragon/templates/enum-heures.html"}}
{{/select}}
</select>
</div>
<div class="form-group">
<div class="flexcol flex-shrink">
<label for="minutesRelative">Minutes</label>
<select name="minutesRelative" data-dtype="String">
{{#select minutesRelative}}
{{#each minutesOptions as |key|}}
<option value={{key}}>{{numberFormat key decimals=0}}</option>
{{/each}}
{{/select}}
</select>
<input type="number" class="number-x4" name="minutesRelative" value="{{minutesRelative}}" data-dtype="Number" min="0" max="119"/>
</div>
</div>
</section>

View File

@ -1,8 +1,8 @@
<div id="calendar-time-container">
<div class="calendar">
{{#if isGM}}
<i class="calendar-btn calendar-btn-edit fas fa-cog" title="Editer"></i>
<i class="calendar-btn astrologie-btn-edit fas fa-cog" title="Astrologie"></i>
<i class="calendar-btn-edit fas fa-cog" title="Editer"></i>
<i class="astrologie-btn-edit fas fa-cog" title="Astrologie"></i>
{{/if}}
<div class="calendar-hdr">
<p id="calendar-move-handle" class="calendar-date-rdd" title="Deplacer">Jour {{jourMois}} de {{nomMois}} ({{nomSaison}})</p>

View File

@ -0,0 +1,3 @@
{{#each (timestamp-formulesDuree) as |duree|}}
<option value="{{duree.code}}">{{duree.label}}</option>
{{/each}}

View File

@ -0,0 +1,23 @@
<div class="flexcol">
<div class="flexrow">
<label>{{label}}</label>
<input {{#if disabled}}{{disabled}}{{/if}} type="number" class="flex-shrink number-x2" name="{{path}}.jour" value="{{jour}}" data-dtype="Number" min="1" max="28"/>
{{timestamp-imgSigne mois}}
<select {{#if disabled}}{{disabled}}{{/if}} name="{{path}}.mois" class="flex-shrink" data-dtype="String">
{{#select mois.key}}
{{>"systems/foundryvtt-reve-de-dragon/templates/enum-heures.html"}}
{{/select}}
</select>
<input {{#if disabled}}{{disabled}}{{/if}} type="number" class="number-x2" name="{{path}}.annee" value="{{annee}}" data-dtype="Number"/>
</div>
<div class="flexrow">
<label>à l'heure de</label>
{{timestamp-imgSigne heure}}
<select {{#if disabled}}{{disabled}}{{/if}} name="{{path}}.heure" class="flex-shrink" data-dtype="String">
{{#select heure.key}}
{{>"systems/foundryvtt-reve-de-dragon/templates/enum-heures.html"}}
{{/select}}
</select>
<input {{#if disabled}}{{disabled}}{{/if}} type="number" class="number-x2" name="{{path}}.minute" value="{{minute}}" data-dtype="Number"/>
</div>
</div>

View File

@ -0,0 +1,9 @@
<option value=""></option>
<option value="hn">Fin de l'Heure de Naissance</option>
<option value="1h">Une heure</option>
<option value="12h">12 heures</option>
<option value="chateaudormant">Fin Chateau dormant</option>
<option value="12chateau">12 heures après Chateau Dormant</option>
<option value="1ddr">Un dé draconique jours</option>
<option value="special">Spéciale</option>

View File

@ -14,35 +14,37 @@
<section class="sheet-body">
{{#if (or isGM system.identifie)}}
<div class="form-group">
<label for="xp">Identifiée ? </label>
<label for="system.identifie">Identifiée ? </label>
<input class="attribute-value" type="checkbox" name="system.identifie" {{#if system.identifie}}checked{{/if}}/>
</div>
<div class="form-group">
<label for="xp">Malignité </label>
<label for="system.malignite">Malignité </label>
<input class="attribute-value" type="text" name="system.malignite" value="{{system.malignite}}" data-dtype="Number"/>
</div>
<div class="form-group">
<label for="xp">Périodicité</label>
<label for="system.periodicite">Périodicité</label>
<input class="attribute-value" type="text" name="system.periodicite" value="{{system.periodicite}}" data-dtype="String"/>
</div>
<div class="form-group">
<label for="xp">Dommages</label>
<label for="system.dommages">Dommages</label>
<input class="attribute-value" type="text" name="system.dommages" value="{{system.dommages}}" data-dtype="String"/>
</div>
<div class="form-group">
<label for="xp">Remedes Connus ? </label>
<label for="system.remedesconnus">Remedes Connus ? </label>
<input class="attribute-value" type="checkbox" name="system.remedesconnus" {{#if system.remedesconnus}}checked{{/if}}/>
</div>
{{#if (or isGM system.remedesconnus)}}
<div class="form-group">
<label for="xp">Remèdes </label>
<label for="system.remedes">Remèdes </label>
<input class="attribute-value" type="text" name="system.remedes" value="{{system.remedes}}" data-dtype="String"/>
</div>
{{/if}}
{{/if}}
{{#if (and isGM isOwned)}}
{{>"systems/foundryvtt-reve-de-dragon/templates/item/temporel.hbs" this labeldebut="Contractée" labelfin="Prochain jet"}}
{{/if}}
{{>"systems/foundryvtt-reve-de-dragon/templates/partial-item-description.html"}}
</section>
</form>

View File

@ -13,37 +13,40 @@
{{!-- Sheet Body --}}
<section class="sheet-body">
<div class="form-group">
<label for="xp">Actif ? </label>
<input class="attribute-value" type="checkbox" name="system.active" {{#if system.active}}checked{{/if}}/>
<label for="system.active">Actif ? </label>
<input class="attribute-value" type="checkbox" name="system.active" {{#if system.active}}checked{{/if}} {{#unless isGM}}disabled{{/unless}}/>
</div>
{{#if (or isGM system.identifie)}}
<div class="form-group">
<label for="xp">Identifiée ? </label>
<label for="system.identifie">Identifiée ? </label>
<input class="attribute-value" type="checkbox" name="system.identifie" {{#if system.identifie}}checked{{/if}}/>
</div>
<div class="form-group">
<label for="xp">Malignité </label>
<label for="system.malignite">Malignité </label>
<input class="attribute-value" type="text" name="system.malignite" value="{{system.malignite}}" data-dtype="Number"/>
</div>
<div class="form-group">
<label for="xp">Périodicité</label>
<label for="system.periodicite">Périodicité</label>
<input class="attribute-value" type="text" name="system.periodicite" value="{{system.periodicite}}" data-dtype="String"/>
</div>
<div class="form-group">
<label for="xp">Dommages</label>
<label for="system.dommages">Dommages</label>
<input class="attribute-value" type="text" name="system.dommages" value="{{system.dommages}}" data-dtype="String"/>
</div>
<div class="form-group">
<label for="xp">Remedes Connus ? </label>
<label for="system.remedesconnus">Remedes Connus ? </label>
<input class="attribute-value" type="checkbox" name="system.remedesconnus" {{#if system.remedesconnus}}checked{{/if}}/>
</div>
{{#if (or isGM system.remedesconnus)}}
<div class="form-group">
<label for="xp">Remèdes </label>
<label for="system.remedes">Remèdes </label>
<input class="attribute-value" type="text" name="system.remedes" value="{{system.remedes}}" data-dtype="String"/>
</div>
{{/if}}
{{/if}}
{{#if (and isGM isOwned system.active)}}
{{>"systems/foundryvtt-reve-de-dragon/templates/item/temporel.hbs" this labeldebut="Contracté" labelfin="Prochain jet"}}
{{/if}}
{{>"systems/foundryvtt-reve-de-dragon/templates/partial-item-description.html"}}

View File

@ -85,15 +85,9 @@
<label>Date de l'Enchantement : Jour/Mois (date actuelle : {{dateActuelle}})</label>
</div>
<div class="form-group">
<select name="splitDate.day" class="enchanteDate" data-dtype="String">
{{#select splitDate.day}}
{{#each jourMoisOptions as |key|}}
<option value="{{key}}">{{numberFormat key decimals=0}}</option>
{{/each}}
{{/select}}
</select>
<select name="splitDate.month" class="enchanteDate" data-dtype="String">
{{#select splitDate.month}}
<input type="number" name="enchantement.jour" class="date-enchantement" value="{{enchantement.jour}}" data-dtype="Number" min="1" max="28"/>
<select name="enchantement.mois" class="date-enchantement" data-dtype="String">
{{#select enchantement.mois}}
{{>"systems/foundryvtt-reve-de-dragon/templates/enum-heures.html"}}
{{/select}}
</select>

View File

@ -19,11 +19,24 @@
</select>
</div>
<div class="form-group">
<label for="system.duree">Durée</label>
<select name="system.duree" data-dtype="String">
{{#select system.duree}}
{{>"systems/foundryvtt-reve-de-dragon/templates/common/enum-duree.hbs"}}
{{/select}}
</select>
</div>
<div class="form-group">
<label for="system.refoulement">Refoulement</label>
<input class="attribute-value" type="text" name="system.refoulement" value="{{system.refoulement}}" data-dtype="Number"/>
</div>
{{#if isOwned}}
{{>"systems/foundryvtt-reve-de-dragon/templates/item/temporel.hbs" this labeldebut="Depuis le" labelfin="Jusqu'au"}}
{{/if}}
{{>"systems/foundryvtt-reve-de-dragon/templates/partial-item-hautrevant.html"}}
{{>"systems/foundryvtt-reve-de-dragon/templates/partial-item-frequence.html"}}
{{>"systems/foundryvtt-reve-de-dragon/templates/partial-item-description.html"}}

View File

@ -27,6 +27,7 @@
<input class="attribute-value" type="text" name="system.heure" value="{{system.heure}}" data-dtype="String" {{#unless isGM}}disabled{{/unless}}/>
</div>
</div>
{{>"systems/foundryvtt-reve-de-dragon/templates/item/temporel.hbs" this labeldebut="Rencontrée le" labelfin="Disparaît le"}}
{{else}}
<div class="form-group">
<label for="system.formule">Rêve</label>

View File

@ -2,6 +2,18 @@
{{>"systems/foundryvtt-reve-de-dragon/templates/header-item.html"}}
{{!-- Sheet Body --}}
<section class="sheet-body">
<div class="form-group">
<label for="system.duree">Durée</label>
<select name="system.duree" data-dtype="String">
{{#select system.duree}}
{{>"systems/foundryvtt-reve-de-dragon/templates/common/enum-duree.hbs"}}
{{/select}}
</select>
</div>
{{#if isOwned}}
{{>"systems/foundryvtt-reve-de-dragon/templates/item/temporel.hbs" this labeldebut="Depuis le" labelfin="Jusqu'au"}}
{{/if}}
{{>"systems/foundryvtt-reve-de-dragon/templates/partial-item-hautrevant.html"}}
{{>"systems/foundryvtt-reve-de-dragon/templates/partial-item-frequence.html"}}

View File

@ -0,0 +1,17 @@
<div class="form-group">
{{>"systems/foundryvtt-reve-de-dragon/templates/common/timestamp.hbs"
(timestamp-extract system.temporel.debut)
path='system.temporel.debut'
label=(either labeldebut 'Date début')
disabled=''
}}
</div>
<div class="form-group">
{{>"systems/foundryvtt-reve-de-dragon/templates/common/timestamp.hbs"
(timestamp-extract system.temporel.fin)
path='system.temporel.fin'
label=(either labelfin 'Date fin')
disabled=''
}}
</div>