Compare commits

..

7 Commits

Author SHA1 Message Date
773b3756a6 Fix odorat-gout 2022-10-28 08:46:46 +02:00
d57cdc2af4 Merge pull request 'Fix: rollCarac pour odorat-goût' (#569) from VincentVk/foundryvtt-reve-de-dragon:v1.5 into v1.5
Reviewed-on: #569
2022-10-28 08:45:31 +02:00
f2d1879135 Fix: rollCarac pour odorat-goût
Recherche d'abord par clé (name)
2022-10-27 22:37:55 +02:00
ea7132468d Merge conteneur 2022-09-25 21:23:50 +02:00
2391fbc4bc Merge pull request 'Drop sur un objet met dans le conteneur parent' (#558) from VincentVk/foundryvtt-reve-de-dragon:v1.5 into v1.5
Reviewed-on: #558
2022-09-25 21:22:46 +02:00
0d2bb2d9a3 Drop sur un objet met dans le conteneur parent
Augmenter la zone pour lacher un objet:
* si c'est un objet similaire, on regroupe
* si c'est un conteneur: on met dans le conteneur
* si c'est un objet dans un conteneur, on met dans le conteneur
* si c'est un objet porté, on met dans les objets portés
2022-09-25 17:47:58 +02:00
7198eb621d Fix entite 2022-09-11 16:11:13 +02:00
419 changed files with 12279 additions and 15730 deletions

6
.gitignore vendored
View File

@ -1,9 +1,5 @@
.vscode/settings.json .vscode/settings.json
.idea .idea
todo.txt
todo.md todo.md
/.vscode /.vscode
/ignored/
/node_modules/
/jsconfig.json
/package.json
/package-lock.json

1
foundryvtt-reve-de-dragon Symbolic link
View File

@ -0,0 +1 @@
foundryvtt-reve-de-dragon

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -3,7 +3,6 @@
"TypePersonnage": "Personnage", "TypePersonnage": "Personnage",
"TypeCreature": "Créature", "TypeCreature": "Créature",
"TypeEntite": "Entité de cauchemar", "TypeEntite": "Entité de cauchemar",
"TypeCommerce": "Commerce",
"TypeVehicule": "Véhicule" "TypeVehicule": "Véhicule"
}, },
"ITEM": { "ITEM": {
@ -16,19 +15,17 @@
"TypeNombreastral": "Nombre astral", "TypeNombreastral": "Nombre astral",
"TypeTarot": "Carte de tarot", "TypeTarot": "Carte de tarot",
"TypeCasetmr": "TMR spéciale", "TypeCasetmr": "TMR spéciale",
"TypeRencontre": "Rencontre TMR", "TypeRencontrestmr": "Rencontre TMR",
"TypeMunition": "Munition", "TypeMunition": "Munition",
"TypeMonnaie": "Monnaie", "TypeMonnaie": "Monnaie",
"TypeHerbe": "Herbe ou plante", "TypeHerbe": "Herbe ou plante",
"TypeIngredient": "Ingrédient", "TypeIngredient": "Ingrédient",
"TypeFaune": "Faune",
"TypeLivre": "Livre", "TypeLivre": "Livre",
"TypePotion": "Potion", "TypePotion": "Potion",
"TypeArme": "Arme", "TypeArme": "Arme",
"TypeArmure": "Armure", "TypeArmure": "Armure",
"TypeConteneur": "Conteneur", "TypeConteneur": "Conteneur",
"TypeNourritureboisson": "Nourriture & boisson", "TypeNourritureboisson": "Nourriture & boisson",
"TypeService": "Service",
"TypeChant": "Chant", "TypeChant": "Chant",
"TypeDanse": "Danse", "TypeDanse": "Danse",
"TypeMusique": "Musique", "TypeMusique": "Musique",
@ -44,9 +41,7 @@
"TypeOmbre": "Ombre de Thanatos", "TypeOmbre": "Ombre de Thanatos",
"TypeSouffle": "Souffle de Dragon", "TypeSouffle": "Souffle de Dragon",
"TypeTete": "Tête de Dragon", "TypeTete": "Tête de Dragon",
"TypePossession": "Possession", "TypePossession": "Possession"
"TypeSortreserve": "Sort en réserve",
"TypeExtraitpoetique": "Extrait poetique"
}, },
"EFFECT": { "EFFECT": {
"StatusStunned": "Sonné", "StatusStunned": "Sonné",

View File

@ -1,9 +1,15 @@
import { RdDActorSheet } from "./actor-sheet.js";
/** /**
* Extend the basic ActorSheet with some very simple modifications * Extend the basic ActorSheet with some very simple modifications
* @extends {ActorSheet} * @extends {ActorSheet}
*/ */
import { HtmlUtility } from "./html-utility.js";
import { RdDUtility } from "./rdd-utility.js";
import { RdDActorSheet } from "./actor-sheet.js";
import { RdDCarac } from "./rdd-carac.js";
/* -------------------------------------------- */
export class RdDActorCreatureSheet extends RdDActorSheet { export class RdDActorCreatureSheet extends RdDActorSheet {
/** @override */ /** @override */
@ -14,30 +20,60 @@ export class RdDActorCreatureSheet extends RdDActorSheet {
width: 640, width: 640,
height: 720, height: 720,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }], tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }] dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }]
}); });
} }
/* -------------------------------------------- */
async getData() {
let formData = await super.getData();
console.log("Creature : ", formData);
formData.calc = {
caracTotal: RdDCarac.computeTotal(formData.data.carac),
resumeBlessures: this.actor.computeResumeBlessure(formData.data.blessures),
encTotal: await this.actor.computeEncombrementTotalEtMalusArmure(),
surEncombrementMessage: this.actor.getMessageSurEncombrement()
}
RdDUtility.filterItemsPerTypeForSheet(formData);
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs);
console.log("Creature : ", this.objetVersConteneur, formData);
return formData;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @override */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
HtmlUtility._showControlWhen($(".gm-only"), game.user.isGM);
// Everything below here is only needed if the sheet is editable // Everything below here is only needed if the sheet is editable
if (!this.options.editable) return; if (!this.options.editable) return;
// On competence change // On competence change
this.html.find('.creature-carac').change(async event => { html.find('.creature-carac').change(async event => {
let compName = event.currentTarget.attributes.compname.value; let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCreatureCompetence(compName, "carac_value", parseInt(event.target.value)); this.actor.updateCreatureCompetence(compName, "carac_value", parseInt(event.target.value));
}); });
this.html.find('.creature-niveau').change(async event => { html.find('.creature-niveau').change(async event => {
let compName = event.currentTarget.attributes.compname.value; let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCreatureCompetence(compName, "niveau", parseInt(event.target.value)); this.actor.updateCreatureCompetence(compName, "niveau", parseInt(event.target.value));
}); });
this.html.find('.creature-dommages').change(async event => { html.find('.creature-dommages').change(async event => {
let compName = event.currentTarget.attributes.compname.value; let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCreatureCompetence(compName, "dommages", parseInt(event.target.value)); this.actor.updateCreatureCompetence(compName, "dommages", parseInt(event.target.value));
}); });
} }
/* -------------------------------------------- */
/** @override */
_updateObject(event, formData) {
// Update the Actor
return this.object.update(formData);
}
} }

View File

@ -1,40 +1,146 @@
import { RdDActorSheet } from "./actor-sheet.js"; /**
* Extend the basic ActorSheet with some very simple modifications
* @extends {ActorSheet}
*/
export class RdDActorEntiteSheet extends RdDActorSheet { import { HtmlUtility } from "./html-utility.js";
import { Misc } from "./misc.js";
import { RdDUtility } from "./rdd-utility.js";
/* -------------------------------------------- */
export class RdDActorEntiteSheet extends ActorSheet {
/** @override */ /** @override */
static get defaultOptions() { static get defaultOptions() {
return mergeObject(super.defaultOptions, { return mergeObject(super.defaultOptions, {
classes: ["rdd", "sheet", "actor"], classes: ["rdd", "sheet", "actor"],
template: "systems/foundryvtt-reve-de-dragon/templates/actor-entite-sheet.html", template: "systems/foundryvtt-reve-de-dragon/templates/actor-entite-sheet.html",
width: 640, width: 640,
height: 720, height: 720,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }], tabs: [{navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac"}],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }] dragDrop: [{dragSelector: ".item-list .item", dropSelector: null}]
}); });
} }
/* -------------------------------------------- */
async getData() {
const objectData = Misc.data(this.object);
let formData = {
title: this.title,
id: objectData.id,
type: objectData.type,
img: objectData.img,
name: objectData.name,
// actor: this.object,
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
data: foundry.utils.deepClone(Misc.templateData(this.object)),
effects: this.object.effects.map(e => foundry.utils.deepClone(e.data)),
// items: items,
limited: this.object.limited,
options: this.options,
owner: this.document.isOwner,
itemsByType: Misc.classify(this.object.items.map(i => foundry.utils.deepClone(i.data))),
};
formData.options.isGM = game.user.isGM;
RdDUtility.filterItemsPerTypeForSheet(formData);
return formData;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @override */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
HtmlUtility._showControlWhen($(".gm-only"), game.user.isGM);
// Everything below here is only needed if the sheet is editable // Everything below here is only needed if the sheet is editable
if (!this.options.editable) return; if (!this.options.editable) return;
// Update Inventory Item
html.find('.item-edit').click(event => {
const li = $(event.currentTarget).parents(".item");
const item = this.actor.getEmbeddedDocument('Item', li.data("itemId"));
item.sheet.render(true);
});
// Delete Inventory Item
html.find('.item-delete').click(event => {
const li = $(event.currentTarget).parents(".item");
this.actor.deleteEmbeddedDocuments('Item', [li.data("itemId")]);
li.slideUp(200, () => this.render(false));
});
// Roll Carac
html.find('.carac-label a').click(async event => {
let caracName = event.currentTarget.attributes.name.value;
this.actor.rollCarac( caracName.toLowerCase() );
});
// On competence change // On competence change
this.html.find('.creature-carac').change(async event => { html.find('.creature-carac').change(async event => {
let compName = event.currentTarget.attributes.compname.value; let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCreatureCompetence(compName, "carac_value", parseInt(event.target.value)); this.actor.updateCreatureCompetence( compName, "carac_value", parseInt(event.target.value) );
} );
html.find('.creature-niveau').change(async event => {
let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCreatureCompetence( compName, "niveau", parseInt(event.target.value) );
} );
html.find('.creature-dommages').change(async event => {
let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCreatureCompetence( compName, "dommages", parseInt(event.target.value) );
} );
// Roll Skill
html.find('.competence-label a').click(async event => {
let compName = event.currentTarget.text;
this.actor.rollCompetence( compName );
}); });
this.html.find('.creature-niveau').change(async event => {
let compName = event.currentTarget.attributes.compname.value; html.find('.endurance-plus').click(event => {
this.actor.updateCreatureCompetence(compName, "niveau", parseInt(event.target.value)); this.actor.santeIncDec("endurance", 1);
this.render(true);
}); });
this.html.find('.creature-dommages').change(async event => { html.find('.endurance-moins').click(event => {
let compName = event.currentTarget.attributes.compname.value; this.actor.santeIncDec("endurance", -1);
this.actor.updateCreatureCompetence(compName, "dommages", parseInt(event.target.value)); this.render(true);
});
html.find('.encaisser-direct').click(event => {
this.actor.encaisser();
});
html.find('.remise-a-neuf').click(event => {
if (game.user.isGM) {
this.actor.remiseANeuf();
}
}); });
} }
/* -------------------------------------------- */
/** @override */
setPosition(options = {}) {
const position = super.setPosition(options);
const sheetHeader = this.element.find(".sheet-header");
const sheetTabs = this.element.find(".sheet-tabs");
const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - sheetHeader[0].clientHeight - sheetTabs[0].clientHeight;
sheetBody.css("height", bodyHeight);
return position;
}
/* -------------------------------------------- */
/** @override */
_updateObject(event, formData) {
// Update the Actor
return this.object.update(formData);
}
} }

View File

@ -1,3 +1,8 @@
/**
* Extend the basic ActorSheet with some very simple modifications
* @extends {ActorSheet}
*/
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";
import { HtmlUtility } from "./html-utility.js"; import { HtmlUtility } from "./html-utility.js";
import { RdDItemArme } from "./item-arme.js"; import { RdDItemArme } from "./item-arme.js";
@ -7,19 +12,12 @@ import { Misc } from "./misc.js";
import { RdDCombatManager } from "./rdd-combat.js"; import { RdDCombatManager } from "./rdd-combat.js";
import { RdDCarac } from "./rdd-carac.js"; import { RdDCarac } from "./rdd-carac.js";
import { DialogSplitItem } from "./dialog-split-item.js"; import { DialogSplitItem } from "./dialog-split-item.js";
import { ReglesOptionelles } from "./settings/regles-optionelles.js"; import { ReglesOptionelles } from "./regles-optionelles.js";
import { DialogRepos } from "./dialog-repos.js";
import { RdDSheetUtility } from "./rdd-sheet-utility.js"; import { RdDSheetUtility } from "./rdd-sheet-utility.js";
import { STATUSES } from "./settings/status-effects.js";
import { MAINS_DIRECTRICES } from "./actor.js";
import { RdDBaseActorSheet } from "./actor/base-actor-sheet.js";
import { RdDItem } from "./item.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
/** export class RdDActorSheet extends ActorSheet {
* Extend the basic ActorSheet with some very simple modifications
* @extends {ActorSheet}
*/
export class RdDActorSheet extends RdDBaseActorSheet {
/** @override */ /** @override */
static get defaultOptions() { static get defaultOptions() {
@ -27,9 +25,10 @@ export class RdDActorSheet extends RdDBaseActorSheet {
return mergeObject(super.defaultOptions, { return mergeObject(super.defaultOptions, {
classes: ["rdd", "sheet", "actor"], classes: ["rdd", "sheet", "actor"],
template: "systems/foundryvtt-reve-de-dragon/templates/actor-sheet.html", template: "systems/foundryvtt-reve-de-dragon/templates/actor-sheet.html",
width: 550, width: 640,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }], tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }], dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
editCaracComp: false,
showCompNiveauBase: false, showCompNiveauBase: false,
vueDetaillee: false vueDetaillee: false
}); });
@ -37,137 +36,211 @@ export class RdDActorSheet extends RdDBaseActorSheet {
/* -------------------------------------------- */ /* -------------------------------------------- */
async getData() { async getData() {
let formData = await super.getData(); const objectData = Misc.data(this.object);
mergeObject(formData,
{
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
effects: this.actor.effects.map(e => foundry.utils.deepClone(e)),
limited: this.actor.limited,
owner: this.actor.isOwner,
biographie: await TextEditor.enrichHTML(this.actor.system.biographie, { async: true }),
notes: await TextEditor.enrichHTML(this.actor.system.notes, { async: true }),
});
mergeObject(formData.calc, {
surenc: this.actor.computeMalusSurEncombrement(),
surprise: RdDBonus.find(this.actor.getSurprise(false)).descr,
resumeBlessures: this.actor.computeResumeBlessure(this.actor.system.blessures),
caracTotal: RdDCarac.computeTotal(this.actor.system.carac, this.actor.system.beaute),
surEncombrementMessage: this.actor.getMessageSurEncombrement(),
})
this.timerRecherche = undefined; this.timerRecherche = undefined;
if (formData.type == 'personnage') { let formData = {
formData.options.mainsDirectrices = MAINS_DIRECTRICES; title: this.title,
formData.byCateg = Misc.classify(formData.competences, it => it.system.categorie) id: objectData.id,
formData.calc.comptageArchetype = RdDItemCompetence.computeResumeArchetype(formData.competences); type: objectData.type,
formData.calc.competenceXPTotal = RdDItemCompetence.computeTotalXP(formData.competences); img: objectData.img,
formData.calc.fatigue = RdDUtility.calculFatigueHtml(formData.system.sante.fatigue.value, formData.system.sante.endurance.max); name: objectData.name,
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
data: foundry.utils.deepClone(Misc.templateData(this.object)),
effects: this.object.effects.map(e => foundry.utils.deepClone(e.data)),
limited: this.object.limited,
options: this.options,
owner: this.document.isOwner,
itemsByType: Misc.classify(this.object.items.map(i => foundry.utils.deepClone(i.data))),
};
formData.competences.forEach(item => { RdDUtility.filterItemsPerTypeForSheet(formData);
item.system.isVisible = this.options.recherche
? RdDItemCompetence.nomContientTexte(item, this.options.recherche.text)
: (!this.options.showCompNiveauBase || !RdDItemCompetence.isNiveauBase(item));
RdDItemCompetence.levelUp(item, formData.system.compteurs.experience.value);
});
Object.values(formData.system.carac).forEach(c => { formData.options.isGM = game.user.isGM;
RdDCarac.levelUp(c);
});
// toujours avoir une liste d'armes (pour mettre esquive et corps à corps) if (formData.type == 'creature') return formData; // Shortcut
formData.combat = duplicate(formData.armes ?? []);
RdDItemArme.computeNiveauArmes(formData.combat, formData.competences);
RdDItemArme.ajoutCorpsACorps(formData.combat, formData.competences, formData.system.carac);
formData.esquives = this.actor.getCompetences("Esquive");
formData.combat = RdDCombatManager.listActionsArmes(formData.combat, formData.competences, formData.system.carac);
this.armesList = formData.combat; formData.competenceByCategory = Misc.classify(formData.competences, it => it.data.categorie);
// Common data formData.calc = {
formData.ajustementsConditions = CONFIG.RDD.ajustementsConditions; comptageArchetype: RdDItemCompetence.computeResumeArchetype(formData.competences),
formData.difficultesLibres = CONFIG.RDD.difficultesLibres; competenceXPTotal: RdDItemCompetence.computeTotalXP(formData.competences),
caracTotal: RdDCarac.computeTotal(formData.data.carac, formData.data.beaute),
// Mise à jour de l'encombrement total et du prix de l'équipement
encTotal: await this.actor.computeEncombrementTotalEtMalusArmure(),
prixTotalEquipement: this.actor.computePrixTotalEquipement(),
surprise: RdDBonus.find(this.actor.getSurprise(false)).descr,
fatigue: RdDUtility.calculFatigueHtml(formData.data.sante.fatigue.value, formData.data.sante.endurance.max),
resumeBlessures: this.actor.computeResumeBlessure(formData.data.blessures),
surEncombrementMessage: this.actor.getMessageSurEncombrement()
};
formData.hautreve = { formData.competences.forEach(item => {
isDemiReve: this.actor.getEffect(STATUSES.StatusDemiReve), item.visible = this.options.recherche
cacheTMR: this.actor.isTMRCache() ? RdDItemCompetence.nomContientTexte(item, this.options.recherche.text)
} : (!this.options.showCompNiveauBase || !RdDItemCompetence.isNiveauBase(item));
RdDItemCompetence.levelUp(item, formData.data.compteurs.experience.value);
});
formData.subacteurs = { Object.values(formData.data.carac).forEach(c => {
vehicules: this.actor.listeVehicules(), RdDCarac.levelUp(c);
montures: this.actor.listeMontures(), });
suivants: this.actor.listeSuivants()
}
if (this.actor.getBestDraconic().system.niveau > -11 && !this.actor.isHautRevant()) { // toujours avoir une liste d'armes (pour mettre esquive et corps à corps)
ui.notifications.error(`${this.actor.name} a des compétences draconiques, mais pas le don de Haut-Rêve! formData.combat = duplicate(formData.armes ?? []);
<br>Ajoutez-lui la tête "Don de Haut-Rêve" pour lui permettre d'utiliser ses compétences et d'accéder aux terres médianes du rêve`); RdDItemArme.computeNiveauArmes(formData.combat, formData.competences);
} RdDItemArme.ajoutCorpsACorps(formData.combat, formData.competences, formData.data.carac);
formData.esquives = this.actor.getCompetences("Esquive").map(i => foundry.utils.deepClone(i.data));
formData.combat = RdDCombatManager.listActionsArmes(formData.combat, formData.competences, formData.data.carac);
this.armesList = formData.combat;
// Common data
formData.ajustementsConditions = CONFIG.RDD.ajustementsConditions;
formData.difficultesLibres = CONFIG.RDD.difficultesLibres;
formData.hautreve = {
isDemiReve: this.actor.getEffectByLabel("Demi-rêve"),
sortsReserve: formData.data.reve.reserve.list,
rencontres: duplicate(formData.data.reve.rencontre.list),
casesTmr: formData.itemsByType.casetmr,
cacheTMR: this.actor.isTMRCache()
}
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs);
formData.subacteurs = {
vehicules: this.actor.listeVehicules(),
montures: this.actor.listeMontures(),
suivants: this.actor.listeSuivants()
}
if (this.actor.getBestDraconic().data.niveau > -11 && !this.actor.isHautRevant()) {
ui.notifications.error(`${this.actor.name} a des compétences draconiques, mais pas le don de Haut-Rêve!
<br>Ajoutez-lui la tête "Don de Haut-Rêve" pour lui permettre d'utiliser ses compétences et d'accéder aux terres médianes du rêve`);
} }
return formData; return formData;
} }
isCompetenceAffichable(competence) {
return !this.options.showCompNiveauBase || !RdDItemCompetence.isNiveauBase(competence);
}
/* -------------------------------------------- */
async _onDropActor(event, dragData) {
console.log("_onDropActor", this.actor.id, dragData);
this.actor.addSubActeur(dragData.id || dragData.data._id);
super._onDropActor(event, dragData);
}
/* -------------------------------------------- */
async _onDropItem(event, dragData) {
const destItemId = $(event.target)?.closest('.item').attr('data-item-id');
const dropParams = RdDSheetUtility.prepareItemDropParameters(destItemId, this.actor.id, dragData, this.objetVersConteneur);
const callSuper = await this.actor.processDropItem(dropParams);
if (callSuper) {
await super._onDropItem(event, dragData)
}
}
/* -------------------------------------------- */
async createItem(name, type) {
await this.actor.createEmbeddedDocuments('Item', [{ name: name, type: type }], { renderSheet: true });
}
/* -------------------------------------------- */
async createEmptyTache() {
await this.createItem('Nouvelle tache', 'tache');
}
/* -------------------------------------------- */ /** @override */ /* -------------------------------------------- */ /** @override */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
HtmlUtility._showControlWhen(this.html.find(".appliquerFatigue"), ReglesOptionelles.isUsing("appliquer-fatigue")); HtmlUtility._showControlWhen($(".gm-only"), game.user.isGM);
HtmlUtility._showControlWhen($(".appliquerFatigue"), ReglesOptionelles.isUsing("appliquer-fatigue"));
// Everything below here is only needed if the sheet is editable // Everything below here is only needed if the sheet is editable
if (!this.options.editable) return; if (!this.options.editable) return;
this.html.find('.item-action').click(async event => RdDSheetUtility.getItem(event, this.actor)?.actionPrincipale(this.actor)); html.find('.item-split').click(async event => {
const item = RdDSheetUtility.getItem(event, this.actor);
this.html.find('.subacteur-delete').click(async event => { RdDSheetUtility.splitItem(item, this.actor);
});
html.find('.item-edit').click(async event => {
const item = RdDSheetUtility.getItem(event, this.actor)
console.log("ITEM :", item)
item.sheet.render(true)
})
html.find('.display-label a').click(async event => {
const item = RdDSheetUtility.getItem(event, this.actor);
item.sheet.render(true);
});
html.find('.rencontre-delete').click(async event => {
this.actor.deleteTMRRencontre(RdDSheetUtility.getItemId(event));
});
html.find('.item-delete').click(async event => {
const li = RdDSheetUtility.getEventElement(event); const li = RdDSheetUtility.getEventElement(event);
const actorId = li.data("actor-id"); RdDUtility.confirmerSuppression(this, li);
if (actorId) {
const subActor = game.actors.get(actorId);
RdDUtility.confirmerSuppressionSubacteur(this, subActor, li);
}
}); });
this.html.find('.experiencelog-delete').click(async event => { html.find('.item-vendre').click(async event => {
const li = this.html.find(event.currentTarget)?.parents(".experiencelog"); const item = RdDSheetUtility.getItem(event, this.actor);
const key = Number(li.data("key") ?? -1); item?.proposerVente();
await this.actor.deleteExperienceLog(key, 1);
}); });
this.html.find('.experiencelog-delete-previous').click(async event => { html.find('.item-montrer').click(async event => {
const li = this.html.find(event.currentTarget)?.parents(".experiencelog"); const item = RdDSheetUtility.getItem(event, this.actor);
const key = Number(li.data("key") ?? -1); item?.postItem();
await this.actor.deleteExperienceLog(0, key + 1);
}); });
this.html.find('.encaisser-direct').click(async event => {
html.find('.item-action').click(async event => {
const item = RdDSheetUtility.getItem(event, this.actor)
this.actor.actionItem(item);
});
html.find('.subacteur-delete').click(async event => {
const li = RdDSheetUtility.getEventElement(event);
RdDUtility.confirmerSuppressionSubacteur(this, li);
});
html.find('.encaisser-direct').click(async event => {
this.actor.encaisser(); this.actor.encaisser();
}) })
this.html.find('.sheet-possession-attack').click(async event => { html.find('.sheet-possession-attack').click(async event => {
const poss = RdDSheetUtility.getItem(event, this.actor) const poss = RdDSheetUtility.getItem(event, this.actor)
this.actor.conjurerPossession(poss) this.actor.conjurerPossession(poss)
}) })
this.html.find('.remise-a-neuf').click(async event => { html.find('.remise-a-neuf').click(async event => {
if (game.user.isGM) { if (game.user.isGM) {
this.actor.remiseANeuf(); this.actor.remiseANeuf();
} }
}); });
this.html.find('.creer-tache').click(async event => { html.find('.creer-tache').click(async event => {
this.createEmptyTache(); this.createEmptyTache();
}); });
this.html.find('.creer-une-oeuvre').click(async event => { html.find('.creer-un-objet').click(async event => {
this.selectTypeOeuvreToCreate(); RdDUtility.selectObjetType(this);
});
html.find('.creer-une-oeuvre').click(async event => {
RdDUtility.selectTypeOeuvre(this);
});
html.find('#nettoyer-conteneurs').click(async event => {
this.actor.nettoyerConteneurs();
}); });
// Blessure control // Blessure control
this.html.find('.blessure-control').click(async event => { html.find('.blessure-control').click(async event => {
const tr = this.html.find(event.currentTarget).parents(".item"); const tr = $(event.currentTarget).parents(".item");
let btype = tr.data("blessure-type"); let btype = tr.data("blessure-type");
let index = tr.data('blessure-index'); let index = tr.data('blessure-index');
let active = this.html.find(event.currentTarget).data('blessure-active'); let active = $(event.currentTarget).data('blessure-active');
//console.log(btype, index, active); //console.log(btype, index, active);
await this.actor.manageBlessureFromSheet(btype, index, active); await this.actor.manageBlessureFromSheet(btype, index, active);
}); });
// Blessure data // Blessure data
this.html.find('.blessure-soins').change(async event => { html.find('.blessures-soins').change(async event => {
const tr = this.html.find(event.currentTarget).parents(".item"); const tr = $(event.currentTarget).parents(".item");
let btype = tr.data('blessure-type'); let btype = tr.data('blessure-type');
let index = tr.data('blessure-index'); let index = tr.data('blessure-index');
let psoins = tr.find('.blessure-premiers_soins').val(); let psoins = tr.find('.blessure-premiers_soins').val();
@ -181,57 +254,57 @@ export class RdDActorSheet extends RdDBaseActorSheet {
}); });
// Equip Inventory Item // Equip Inventory Item
this.html.find('.item-equip').click(async event => { html.find('.item-equip').click(async event => {
this.actor.equiperObjet(RdDSheetUtility.getItemId(event)); this.actor.equiperObjet(RdDSheetUtility.getItemId(event));
}); });
// Roll Carac // Roll Carac
this.html.find('.carac-label a').click(async event => { html.find('.carac-label a').click(async event => {
let caracName = event.currentTarget.attributes.name.value; let caracName = event.currentTarget.attributes.name.value;
this.actor.rollCarac(caracName.toLowerCase()); this.actor.rollCarac(caracName.toLowerCase());
}); });
this.html.find('.chance-actuelle').click(async event => { html.find('.chance-actuelle').click(async event => {
this.actor.rollCarac('chance-actuelle'); this.actor.rollCarac('chance-actuelle');
}); });
this.html.find('.chance-appel').click(async event => { html.find('.chance-appel').click(async event => {
this.actor.rollAppelChance(); this.actor.rollAppelChance();
}); });
this.html.find('[name="jet-astrologie"]').click(async event => { html.find('#jet-astrologie').click(async event => {
this.actor.astrologieNombresAstraux(); this.actor.astrologieNombresAstraux();
}); });
// Roll Skill // Roll Skill
this.html.find('a.competence-label').click(async event => { html.find('a.competence-label').click(async event => {
this.actor.rollCompetence(RdDSheetUtility.getItemId(event)); this.actor.rollCompetence(RdDSheetUtility.getItemId(event));
}); });
this.html.find('.tache-label a').click(async event => { html.find('.tache-label a').click(async event => {
this.actor.rollTache(RdDSheetUtility.getItemId(event)); this.actor.rollTache(RdDSheetUtility.getItemId(event));
}); });
this.html.find('.meditation-label a').click(async event => { html.find('.meditation-label a').click(async event => {
this.actor.rollMeditation(RdDSheetUtility.getItemId(event)); this.actor.rollMeditation(RdDSheetUtility.getItemId(event));
}); });
this.html.find('.chant-label a').click(async event => { html.find('.chant-label a').click(async event => {
this.actor.rollChant(RdDSheetUtility.getItemId(event)); this.actor.rollChant(RdDSheetUtility.getItemId(event));
}); });
this.html.find('.danse-label a').click(async event => { html.find('.danse-label a').click(async event => {
this.actor.rollDanse(RdDSheetUtility.getItemId(event)); this.actor.rollDanse(RdDSheetUtility.getItemId(event));
}); });
this.html.find('.musique-label a').click(async event => { html.find('.musique-label a').click(async event => {
this.actor.rollMusique(RdDSheetUtility.getItemId(event)); this.actor.rollMusique(RdDSheetUtility.getItemId(event));
}); });
this.html.find('.oeuvre-label a').click(async event => { html.find('.oeuvre-label a').click(async event => {
this.actor.rollOeuvre(RdDSheetUtility.getItemId(event)); this.actor.rollOeuvre(RdDSheetUtility.getItemId(event));
}); });
this.html.find('.jeu-label a').click(async event => { html.find('.jeu-label a').click(async event => {
this.actor.rollJeu(RdDSheetUtility.getItemId(event)); this.actor.rollJeu(RdDSheetUtility.getItemId(event));
}); });
this.html.find('.recettecuisine-label a').click(async event => { html.find('.recettecuisine-label a').click(async event => {
this.actor.rollRecetteCuisine(RdDSheetUtility.getItemId(event)); this.actor.rollRecetteCuisine(RdDSheetUtility.getItemId(event));
}); });
this.html.find('.subacteur-label a').click(async event => { html.find('.subacteur-label a').click(async event => {
let actorId = RdDSheetUtility.getEventItemData(event, 'actor-id'); let actorId = RdDSheetUtility.getEventItemData(event, 'actor-id');
let actor = game.actors.get(actorId); let actor = game.actors.get(actorId);
if (actor) { if (actor) {
@ -240,26 +313,26 @@ export class RdDActorSheet extends RdDBaseActorSheet {
}); });
// Boutons spéciaux MJs // Boutons spéciaux MJs
this.html.find('.forcer-tmr-aleatoire').click(async event => { html.find('.forcer-tmr-aleatoire').click(async event => {
this.actor.reinsertionAleatoire("Action MJ"); this.actor.reinsertionAleatoire("Action MJ");
}); });
this.html.find('.afficher-tmr').click(async event => { html.find('.afficher-tmr').click(async event => {
this.actor.changeTMRVisible(); this.actor.afficheTMRetMessage();
}); });
// Points de reve actuel // Points de reve actuel
this.html.find('.ptreve-actuel a').click(async event => { html.find('.ptreve-actuel a').click(async event => {
this.actor.rollCarac('reve-actuel'); this.actor.rollCarac('reve-actuel');
}); });
// Roll Weapon1 // Roll Weapon1
this.html.find('.arme-label a').click(async event => { html.find('.arme-label a').click(async event => {
let arme = this._getEventArmeCombat(event); let arme = this._getEventArmeCombat(event);
this.actor.rollArme(duplicate(arme)); this.actor.rollArme(duplicate(arme));
}); });
// Initiative pour l'arme // Initiative pour l'arme
this.html.find('.arme-initiative a').click(async event => { html.find('.arme-initiative a').click(async event => {
let combatant = game.combat.combatants.find(c => c.actor.id == this.actor.id); let combatant = game.combat.data.combatants.find(c => c.actor.data._id == this.actor.data._id);
if (combatant) { if (combatant) {
let action = this._getEventArmeCombat(event); let action = this._getEventArmeCombat(event);
RdDCombatManager.rollInitiativeAction(combatant._id, action); RdDCombatManager.rollInitiativeAction(combatant._id, action);
@ -268,84 +341,90 @@ export class RdDActorSheet extends RdDBaseActorSheet {
} }
}); });
// Display TMR, visualisation // Display TMR, visualisation
this.html.find('.visu-tmr').click(async event => { html.find('.visu-tmr').click(async event => {
this.actor.displayTMR("visu"); this.actor.displayTMR("visu");
}); });
// Display TMR, normal // Display TMR, normal
this.html.find('.monte-tmr').click(async event => { html.find('.monte-tmr').click(async event => {
this.actor.displayTMR("normal"); this.actor.displayTMR("normal");
}); });
// Display TMR, fast // Display TMR, fast
this.html.find('.monte-tmr-rapide').click(async event => { html.find('.monte-tmr-rapide').click(async event => {
this.actor.displayTMR("rapide"); this.actor.displayTMR("rapide");
}); });
this.html.find('.repos').click(async event => { html.find('.repos').click(async event => {
await this.actor.repos(); await DialogRepos.create(this.actor);
}); });
this.html.find('.delete-active-effect').click(async event => { html.find('.delete-active-effect').click(async event => {
if (game.user.isGM) { let id = $(event.currentTarget).parents(".active-effect").data('id');
let effect = this.html.find(event.currentTarget).parents(".active-effect").data('effect'); this.actor.enleverActiveEffectById(id);
this.actor.removeEffect(effect);
}
}); });
this.html.find('.enlever-tous-effets').click(async event => { html.find('.enlever-tous-effets').click(async event => {
if (game.user.isGM) { this.actor.enleverTousLesEffets();
await this.actor.removeEffects();
}
}); });
this.html.find('.carac-xp-augmenter').click(async event => { html.find('.conteneur-name a').click(async event => {
RdDUtility.toggleAfficheContenu(RdDSheetUtility.getItemId(event));
this.render(true);
});
html.find('.carac-xp-augmenter').click(async event => {
let caracName = event.currentTarget.name.replace("augmenter.", ""); let caracName = event.currentTarget.name.replace("augmenter.", "");
this.actor.updateCaracXPAuto(caracName); this.actor.updateCaracXPAuto(caracName);
}); });
this.html.find('.competence-xp-augmenter').click(async event => { html.find('.competence-xp-augmenter').click(async event => {
this.actor.updateCompetenceXPAuto(RdDSheetUtility.getItemId(event)); this.actor.updateCompetenceXPAuto(RdDSheetUtility.getItemId(event));
}); });
this.html.find('.competence-stress-augmenter').click(async event => { html.find('.competence-stress-augmenter').click(async event => {
this.actor.updateCompetenceStress(RdDSheetUtility.getItemId(event)); this.actor.updateCompetenceStress(RdDSheetUtility.getItemId(event));
}); });
if (this.options.vueDetaillee) { if (this.options.editCaracComp) {
// On carac change // On carac change
this.html.find('.carac-value').change(async event => { html.find('.carac-value').change(async event => {
let caracName = event.currentTarget.name.replace(".value", "").replace("system.carac.", ""); let caracName = event.currentTarget.name.replace(".value", "").replace("data.carac.", "");
//console.log("Value changed :", event, caracName);
this.actor.updateCarac(caracName, parseInt(event.target.value)); this.actor.updateCarac(caracName, parseInt(event.target.value));
}); });
this.html.find('input.carac-xp').change(async event => { html.find('.carac-xp').change(async event => {
let caracName = event.currentTarget.name.replace(".xp", "").replace("system.carac.", ""); let caracName = event.currentTarget.name.replace(".xp", "").replace("data.carac.", "");
//console.log("Value changed :", event, caracName);
this.actor.updateCaracXP(caracName, parseInt(event.target.value)); this.actor.updateCaracXP(caracName, parseInt(event.target.value));
}); });
// On competence change // On competence change
this.html.find('.competence-value').change(async event => { html.find('.competence-value').change(async event => {
let compName = event.currentTarget.attributes.compname.value; let compName = event.currentTarget.attributes.compname.value;
//console.log("Competence changed :", compName); //console.log("Competence changed :", compName);
this.actor.updateCompetence(compName, parseInt(event.target.value)); this.actor.updateCompetence(compName, parseInt(event.target.value));
}); });
// On competence xp change // On competence xp change
this.html.find('input.competence-xp').change(async event => { html.find('.competence-xp').change(async event => {
let compName = event.currentTarget.attributes.compname.value; let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCompetenceXP(compName, parseInt(event.target.value)); this.actor.updateCompetenceXP(compName, parseInt(event.target.value));
}); });
// On competence xp change // On competence xp change
this.html.find('input.competence-xp-sort').change(async event => { html.find('.competence-xp-sort').change(async event => {
let compName = event.currentTarget.attributes.compname.value; let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCompetenceXPSort(compName, parseInt(event.target.value)); this.actor.updateCompetenceXPSort(compName, parseInt(event.target.value));
}); });
// On competence archetype change // On competence archetype change
this.html.find('.competence-archetype').change(async event => { html.find('.competence-archetype').change(async event => {
let compName = event.currentTarget.attributes.compname.value; let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCompetenceArchetype(compName, parseInt(event.target.value)); this.actor.updateCompetenceArchetype(compName, parseInt(event.target.value));
}); });
} }
this.html.find('.show-hide-competences').click(async event => { html.find('.show-hide-competences').click(async event => {
this.options.showCompNiveauBase = !this.options.showCompNiveauBase; this.options.showCompNiveauBase = !this.options.showCompNiveauBase;
this.render(true); this.render(true);
}); });
html.find('.lock-unlock-sheet').click(async event => {
this.options.editCaracComp = !this.options.editCaracComp;
this.render(true);
});
this.html.find('.recherche') html.find('.recherche')
.each((index, field) => { .each((index, field) => {
if (this.options.recherche) { if (this.options.recherche) {
field.focus(); field.focus();
@ -354,7 +433,7 @@ export class RdDActorSheet extends RdDBaseActorSheet {
}) })
.keyup(async event => { .keyup(async event => {
const nouvelleRecherche = this._optionRecherche(event.currentTarget); const nouvelleRecherche = this._optionRecherche(event.currentTarget);
if (this.options.recherche?.text != nouvelleRecherche?.text) { if (this.options.recherche?.text != nouvelleRecherche?.text){
this.options.recherche = nouvelleRecherche; this.options.recherche = nouvelleRecherche;
if (this.timerRecherche) { if (this.timerRecherche) {
clearTimeout(this.timerRecherche); clearTimeout(this.timerRecherche);
@ -368,118 +447,94 @@ export class RdDActorSheet extends RdDBaseActorSheet {
.change(async event => .change(async event =>
this.options.recherche = this._optionRecherche(event.currentTarget) this.options.recherche = this._optionRecherche(event.currentTarget)
); );
this.html.find('.vue-detaillee').click(async event => { html.find('.vue-detaillee').click(async event => {
this.options.vueDetaillee = !this.options.vueDetaillee; this.options.vueDetaillee = !this.options.vueDetaillee;
this.render(true); this.render(true);
}); });
// On pts de reve change // On pts de reve change
this.html.find('.pointsreve-value').change(async event => { html.find('.pointsreve-value').change(async event => {
let reveValue = event.currentTarget.value; let reveValue = event.currentTarget.value;
this.actor.update({ "system.reve.reve.value": reveValue }); this.actor.update({ "data.reve.reve.value": reveValue });
}); });
// On seuil de reve change // On seuil de reve change
this.html.find('.seuil-reve-value').change(async event => { html.find('.seuil-reve-value').change(async event => {
console.log("seuil-reve-value", event.currentTarget) console.log("seuil-reve-value", event.currentTarget)
this.actor.setPointsDeSeuil(event.currentTarget.value); this.actor.setPointsDeSeuil(event.currentTarget.value);
}); });
html.find('#attribut-protection-edit').change(async event => {
this.actor.updateAttributeValue(event.currentTarget.attributes.name.value, parseInt(event.target.value));
});
// On stress change // On stress change
this.html.find('.compteur-edit').change(async event => { html.find('.compteur-edit').change(async event => {
let fieldName = event.currentTarget.attributes.name.value; let fieldName = event.currentTarget.attributes.name.value;
this.actor.updateCompteurValue(fieldName, parseInt(event.target.value)); this.actor.updateCompteurValue(fieldName, parseInt(event.target.value));
}); });
this.html.find('.stress-test').click(async event => { html.find('#ethylisme').change(async event => {
this.actor.setEthylisme(parseInt(event.target.value));
});
html.find('.stress-test').click(async event => {
this.actor.transformerStress(); this.actor.transformerStress();
}); });
this.html.find('.moral-malheureux').click(async event => { html.find('.moral-malheureux').click(async event => {
this.actor.jetDeMoral('malheureuse'); this.actor.jetDeMoral('malheureuse');
}); });
this.html.find('.moral-neutre').click(async event => { html.find('.moral-neutre').click(async event => {
this.actor.jetDeMoral('neutre'); this.actor.jetDeMoral('neutre');
}); });
this.html.find('.moral-heureux').click(async event => { html.find('.moral-heureux').click(async event => {
this.actor.jetDeMoral('heureuse'); this.actor.jetDeMoral('heureuse');
}); });
this.html.find('.ethylisme-test').click(async event => { html.find('#ethylisme-test').click(async event => {
this.actor.jetEthylisme(); this.actor.jetEthylisme();
}); });
this.html.find('.jet-vie').click(async event => { html.find('.jet-vie').click(async event => {
this.actor.jetVie(); this.actor.jetVie();
}); });
this.html.find('.jet-endurance').click(async event => { html.find('.jet-endurance').click(async event => {
this.actor.jetEndurance(); this.actor.jetEndurance();
}); });
this.html.find('.vie-plus').click(async event => { html.find('.monnaie-plus').click(async event => {
this.actor.monnaieIncDec(RdDSheetUtility.getItemId(event), 1);
});
html.find('.monnaie-moins').click(async event => {
this.actor.monnaieIncDec(RdDSheetUtility.getItemId(event), -1);
});
html.find('.vie-plus').click(async event => {
this.actor.santeIncDec("vie", 1); this.actor.santeIncDec("vie", 1);
}); });
this.html.find('.vie-moins').click(async event => { html.find('.vie-moins').click(async event => {
this.actor.santeIncDec("vie", -1); this.actor.santeIncDec("vie", -1);
}); });
this.html.find('.endurance-plus').click(async event => { html.find('.endurance-plus').click(async event => {
this.actor.santeIncDec("endurance", 1); this.actor.santeIncDec("endurance", 1);
}); });
this.html.find('.endurance-moins').click(async event => { html.find('.endurance-moins').click(async event => {
this.actor.santeIncDec("endurance", -1); this.actor.santeIncDec("endurance", -1);
}); });
this.html.find('.ptreve-actuel-plus').click(async event => { html.find('.ptreve-actuel-plus').click(async event => {
this.actor.reveActuelIncDec(1); this.actor.reveActuelIncDec(1);
}); });
this.html.find('.ptreve-actuel-moins').click(async event => { html.find('.ptreve-actuel-moins').click(async event => {
this.actor.reveActuelIncDec(-1); this.actor.reveActuelIncDec(-1);
}); });
this.html.find('.fatigue-plus').click(async event => { html.find('.fatigue-plus').click(async event => {
this.actor.santeIncDec("fatigue", 1); this.actor.santeIncDec("fatigue", 1);
}); });
this.html.find('.fatigue-moins').click(async event => { html.find('.fatigue-moins').click(async event => {
this.actor.santeIncDec("fatigue", -1); this.actor.santeIncDec("fatigue", -1);
}); });
} }
isCompetenceAffichable(competence) {
return !this.options.showCompNiveauBase || !RdDItemCompetence.isNiveauBase(competence);
}
/* -------------------------------------------- */
async _onDropActor(event, dragData) {
const dropActor = fromUuidSync(dragData.uuid);
this.actor.addSubActeur(dropActor);
super._onDropActor(event, dragData);
}
/* -------------------------------------------- */
async selectTypeOeuvreToCreate() {
let typeObjets = RdDItem.getTypesOeuvres();
let content = `<span class="competence-label">Selectionnez le type d'oeuvre</span><select class="item-type">`;
for (let typeName of typeObjets) {
content += `<option value="${typeName}">${Misc.typeName('Item', typeName)}</option>`
}
content += '</select>';
let dialog = new Dialog({
title: "Créer une oeuvre",
content: content,
buttons: {
create: {
icon: '<i class="fas fa-check"></i>',
label: "Créer l'oeuvre",
callback: () => this.actor.createItem($(".item-type").val())
}
}
});
dialog.render(true);
}
/* -------------------------------------------- */
async createEmptyTache() {
await this.actor.createItem('tache', 'Nouvelle tache');
}
_optionRecherche(target) { _optionRecherche(target) {
if (!target.value?.length) { if (!target.value?.length){
return undefined; return undefined;
} }
return { return {
@ -490,12 +545,12 @@ export class RdDActorSheet extends RdDBaseActorSheet {
} }
_getEventArmeCombat(event) { _getEventArmeCombat(event) {
const li = this.html.find(event.currentTarget)?.parents(".item"); const li = $(event.currentTarget)?.parents(".item");
let armeName = li.data("arme-name"); let armeName = li.data("arme-name");
let compName = li.data('competence-name'); let compName = li.data('competence-name');
const arme = this.armesList.find(a => a.name == armeName && a.system.competence == compName); const arme = this.armesList.find(a => a.name == armeName && a.data.competence == compName);
if (!arme) { if (!arme) {
return { name: armeName, system: { competence: compName } }; return { name: armeName, data: { competence: compName } };
} }
return arme; return arme;
} }
@ -507,10 +562,7 @@ export class RdDActorSheet extends RdDBaseActorSheet {
const sheetHeader = this.element.find(".sheet-header"); const sheetHeader = this.element.find(".sheet-header");
const sheetTabs = this.element.find(".sheet-tabs"); const sheetTabs = this.element.find(".sheet-tabs");
const sheetBody = this.element.find(".sheet-body"); const sheetBody = this.element.find(".sheet-body");
let bodyHeight = position.height - sheetHeader[0].clientHeight; const bodyHeight = position.height - sheetHeader[0].clientHeight - sheetTabs[0].clientHeight;
if (sheetTabs.length > 0) {
bodyHeight -= sheetTabs[0].clientHeight;
}
sheetBody.css("height", bodyHeight); sheetBody.css("height", bodyHeight);
return position; return position;
} }
@ -520,7 +572,7 @@ export class RdDActorSheet extends RdDBaseActorSheet {
/** @override */ /** @override */
_updateObject(event, formData) { _updateObject(event, formData) {
// Update the Actor // Update the Actor
return this.actor.update(formData); return this.object.update(formData);
} }
async splitItem(item) { async splitItem(item) {
@ -529,11 +581,11 @@ export class RdDActorSheet extends RdDBaseActorSheet {
} }
async _onSplitItem(item, split) { async _onSplitItem(item, split) {
if (split >= 1 && split < item.system.quantite) { if (split >= 1 && split < Misc.data(item).data.quantite) {
await item.diminuerQuantite(split); await item.diminuerQuantite(split);
const splitItem = duplicate(item); const itemData = duplicate(Misc.data(item));
splitItem.system.quantite = split; itemData.data.quantite = split;
await this.actor.createEmbeddedDocuments('Item', [splitItem]) await this.actor.createEmbeddedDocuments('Item', [itemData])
} }
} }

View File

@ -1,8 +1,15 @@
/**
* Extend the basic ActorSheet with some very simple modifications
* @extends {ActorSheet}
*/
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";
import { RdDActorSheet } from "./actor-sheet.js"; import { HtmlUtility } from "./html-utility.js";
import { Misc } from "./misc.js";
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDActorVehiculeSheet extends RdDActorSheet { export class RdDActorVehiculeSheet extends ActorSheet {
/** @override */ /** @override */
static get defaultOptions() { static get defaultOptions() {
@ -14,26 +21,145 @@ export class RdDActorVehiculeSheet extends RdDActorSheet {
width: 640, width: 640,
height: 720, height: 720,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }], tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }] dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }]
}); });
} }
/* -------------------------------------------- */
async getData() {
const objectData = Misc.data(this.object);
let formData = {
title: this.title,
id: objectData.id,
type: objectData.type,
img: objectData.img,
name: objectData.name,
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
data: foundry.utils.deepClone(Misc.templateData(this.object)),
effects: this.object.effects.map(e => foundry.utils.deepClone(e.data)),
limited: this.object.limited,
options: this.options,
owner: this.document.isOwner,
itemsByType: Misc.classify(this.object.items.map(i => foundry.utils.deepClone(i.data))),
};
RdDUtility.filterItemsPerTypeForSheet(formData);
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs);
formData.options.isGM = game.user.isGM;
formData.calc = {
encTotal: await this.actor.computeEncombrementTotalEtMalusArmure(),
surEncombrementMessage: this.actor.getMessageSurEncombrement()
}
console.log("DATA", formData);
return formData;
}
async computeMalusArmure() {
// pas de malus armure
}
/* -------------------------------------------- */
async _onDropItem(event, dragData) {
const destItemId = $(event.target)?.closest('.item').attr('data-item-id');
const dropParams = RdDSheetUtility.prepareItemDropParameters(destItemId, this.actor.id, dragData, this.objetVersConteneur);
const callSuper = await this.actor.processDropItem(dropParams);
if (callSuper) {
await super._onDropItem(event, dragData)
}
}
/* -------------------------------------------- */
async createItem(name, type) {
await this.actor.createEmbeddedDocuments('Item', [{ name: name, type: type }], { renderSheet: true });
}
/* -------------------------------------------- */
async monnaieIncDec(id, value) {
let monnaie = this.getMonnaie(id);
if (monnaie) {
const quantite = Math.max(0, Misc.templateData(monnaie).quantite + value);
await this.updateEmbeddedDocuments('Item', [{ _id: monnaie.id, 'data.quantite': quantite }]);
}
}
/* -------------------------------------------- */
/** @override */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
HtmlUtility._showControlWhen($(".gm-only"), game.user.isGM);
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) return; if (!this.options.editable) return;
this.html.find('.resistance-moins').click(async event => { // Update Inventory Item
this.actor.vehicleIncDec("resistance", -1); html.find('.item-edit').click(async event => {
const item = RdDSheetUtility.getItem(event, this.actor);
item.sheet.render(true);
}); });
this.html.find('.resistance-plus').click(async event => { // Delete Inventory Item
this.actor.vehicleIncDec("resistance", 1); html.find('.item-delete').click(async event => {
const li = RdDSheetUtility.getEventElement(event);
RdDUtility.confirmerSuppression(this, li);
}); });
this.html.find('.structure-moins').click(async event => { html.find('.item-vendre').click(async event => {
this.actor.vehicleIncDec("structure", -1); const item = RdDSheetUtility.getItem(event, this.actor);
item?.proposerVente();
}); });
this.html.find('.structure-plus').click(async event => { html.find('.item-montrer').click(async event => {
this.actor.vehicleIncDec("structure", 1); const item = RdDSheetUtility.getItem(event, this.actor);
item?.postItem();
}); });
html.find('.item-action').click(async event => {
const item = RdDSheetUtility.getItem(event, this.actor);
this.actor.actionItem(item);
});
html.find('.creer-un-objet').click(async event => {
RdDUtility.selectObjetType(this);
});
html.find('#nettoyer-conteneurs').click(async event => {
this.actor.nettoyerConteneurs();
});
html.find('.monnaie-plus').click(async event => {
this.actor.monnaieIncDec(RdDSheetUtility.getItemId(event), 1);
});
html.find('.monnaie-moins').click(async event => {
this.actor.monnaieIncDec(RdDSheetUtility.getItemId(event), -1);
});
// Display info about queue
html.find('.conteneur-name a').click((event) => {
RdDUtility.toggleAfficheContenu(RdDSheetUtility.getItemId(event));
this.render(true);
});
} }
/* -------------------------------------------- */
/** @override */
setPosition(options = {}) {
const position = super.setPosition(options);
const sheetHeader = this.element.find(".sheet-header");
const sheetTabs = this.element.find(".sheet-tabs");
const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - sheetHeader[0].clientHeight - sheetTabs[0].clientHeight;
sheetBody.css("height", bodyHeight);
return position;
}
/* -------------------------------------------- */
/** @override */
_updateObject(event, formData) {
// Update the Actor
return this.object.update(formData);
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,260 +0,0 @@
import { RdDUtility } from "../rdd-utility.js";
import { Misc } from "../misc.js";
import { DialogSplitItem } from "../dialog-split-item.js";
import { RdDSheetUtility } from "../rdd-sheet-utility.js";
import { Monnaie } from "../item-monnaie.js";
import { RdDItem } from "../item.js";
/* -------------------------------------------- */
/**
* Extend the basic ActorSheet with some very simple modifications
* @extends {ActorSheet}
*/
export class RdDBaseActorSheet extends ActorSheet {
/** @override */
static get defaultOptions() {
RdDUtility.initAfficheContenu();
return mergeObject(super.defaultOptions, {
classes: ["rdd", "sheet", "actor"],
template: "systems/foundryvtt-reve-de-dragon/templates/actor-sheet.html",
width: 550,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }],
showCompNiveauBase: false,
vueDetaillee: false
});
}
/* -------------------------------------------- */
async getData() {
Monnaie.validerMonnaies(this.actor.itemTypes['monnaie']);
this.actor.recompute();
const userRightLevel = game.user.isGM ? CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER : this.actor.getUserLevel(game.user)
const options = duplicate(this.options);
mergeObject(options, {
isGM: game.user.isGM,
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
isLimited: userRightLevel >= CONST.DOCUMENT_OWNERSHIP_LEVELS.LIMITED,
isObserver: userRightLevel >= CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER,
isOwner: userRightLevel >= CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER,
owner: this.actor.isOwner,
});
let formData = {
title: this.title,
id: this.actor.id,
type: this.actor.type,
img: this.actor.img,
name: this.actor.name,
system: foundry.utils.deepClone(this.actor.system),
description: await TextEditor.enrichHTML(this.actor.system.description, { async: true }),
notesmj: await TextEditor.enrichHTML(this.actor.system.notesmj, { async: true }),
options: options,
}
this.filterItemsPerTypeForSheet(formData, this.actor.itemTypes);
formData.calc = {
fortune: this.toSolsDeniers(this.actor.getFortune()),
prixTotalEquipement: this.actor.computePrixTotalEquipement(),
encTotal: await this.actor.computeEncTotal(),
}
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs);
return formData;
}
toSolsDeniers(fortune) {
return {
sols: Math.floor(fortune),
deniers: Math.round(100 * (fortune - Math.floor(fortune)))
};
}
/* -------------------------------------------- */
filterItemsPerTypeForSheet(formData, itemTypes) {
formData.recettescuisine = Misc.arrayOrEmpty(itemTypes['recettecuisine']);
formData.recettesAlchimiques = Misc.arrayOrEmpty(itemTypes['recettealchimique']);
formData.maladies = Misc.arrayOrEmpty(itemTypes['maladie']);
formData.poisons = Misc.arrayOrEmpty(itemTypes['poison']);
formData.possessions = Misc.arrayOrEmpty(itemTypes['possession']);
formData.maladiesPoisons = formData.maladies.concat(formData.poisons);
formData.competences = (itemTypes['competence'] ?? []).concat(itemTypes['competencecreature'] ?? []);
formData.sortsReserve = Misc.arrayOrEmpty(itemTypes['sortreserve']);
formData.sorts = Misc.arrayOrEmpty(itemTypes['sort']);
formData.rencontres = Misc.arrayOrEmpty(itemTypes['rencontre']);
formData.casestmr = Misc.arrayOrEmpty(itemTypes['casetmr']);
formData.signesdraconiques = Misc.arrayOrEmpty(itemTypes['signedraconique']);
formData.queues = Misc.arrayOrEmpty(itemTypes['queue']);
formData.souffles = Misc.arrayOrEmpty(itemTypes['souffle']);
formData.ombres = Misc.arrayOrEmpty(itemTypes['ombre']);
formData.tetes = Misc.arrayOrEmpty(itemTypes['tete']);
formData.taches = Misc.arrayOrEmpty(itemTypes['tache']);
formData.meditations = Misc.arrayOrEmpty(itemTypes['meditation']);
formData.chants = Misc.arrayOrEmpty(itemTypes['chant']);
formData.danses = Misc.arrayOrEmpty(itemTypes['danse']);
formData.musiques = Misc.arrayOrEmpty(itemTypes['musique']);
formData.oeuvres = Misc.arrayOrEmpty(itemTypes['oeuvre']);
formData.jeux = Misc.arrayOrEmpty(itemTypes['jeu']);
formData.services = Misc.arrayOrEmpty(itemTypes['service']);
formData.conteneurs = Misc.arrayOrEmpty(itemTypes['conteneur']);
formData.materiel = Misc.arrayOrEmpty(itemTypes['objet']);
formData.armes = Misc.arrayOrEmpty(itemTypes['arme']);
formData.armures = Misc.arrayOrEmpty(itemTypes['armure']);
formData.munitions = Misc.arrayOrEmpty(itemTypes['munition']);
formData.livres = Misc.arrayOrEmpty(itemTypes['livre']);
formData.potions = Misc.arrayOrEmpty(itemTypes['potion']);
formData.ingredients = Misc.arrayOrEmpty(itemTypes['ingredient']);
formData.faunes = Misc.arrayOrEmpty(itemTypes['faune']);
formData.herbes = Misc.arrayOrEmpty(itemTypes['herbe']);
formData.nourritureboissons = Misc.arrayOrEmpty(itemTypes['nourritureboisson']);
formData.gemmes = Misc.arrayOrEmpty(itemTypes['gemme']);
formData.monnaie = Misc.arrayOrEmpty(itemTypes['monnaie']).sort(Monnaie.triValeurEntiere());
formData.objets = RdDItem.getItemTypesInventaire('all')
.map(t => Misc.arrayOrEmpty(itemTypes[t]))
.reduce((a, b) => a.concat(b), [])
.sort(Misc.ascending(it => it.name));
}
/* -------------------------------------------- */ /** @override */
activateListeners(html) {
super.activateListeners(html);
this.html = html;
this.html.find('.conteneur-name a').click(async event => {
RdDUtility.toggleAfficheContenu(this.getItemId(event));
this.render(true);
});
this.html.find('.item-edit').click(async event => this.getItem(event)?.sheet.render(true))
this.html.find('.item-montrer').click(async event => this.getItem(event)?.postItemToChat());
this.html.find('.actor-montrer').click(async event => this.actor.postActorToChat());
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) return;
this.html.find('.item-split').click(async event => {
const item = this.getItem(event);
RdDSheetUtility.splitItem(item, this.actor);
});
this.html.find('.item-delete').click(async event => RdDUtility.confirmActorItemDelete(this, this.getItem(event)));
this.html.find('.item-vendre').click(async event => this.vendre(this.getItem(event)));
this.html.find('.creer-un-objet').click(async event => {
this.selectObjetTypeToCreate();
});
this.html.find('.nettoyer-conteneurs').click(async event => {
this.actor.nettoyerConteneurs();
});
this.html.find('.monnaie-plus').click(async event => {
this.actor.monnaieIncDec(this.getItemId(event), 1);
});
this.html.find('.monnaie-moins').click(async event => {
this.actor.monnaieIncDec(this.getItemId(event), -1);
});
}
getItemId(event) {
return RdDSheetUtility.getItemId(event);
}
getItem(event) {
return RdDSheetUtility.getItem(event, this.actor);
}
/* -------------------------------------------- */
_getHeaderButtons() {
let buttons = super._getHeaderButtons();
buttons.unshift({
class: "montrer",
icon: "fas fa-comment",
onclick: ev => this.actor.postActorToChat()
});
return buttons
}
/* -------------------------------------------- */
async _onDropItem(event, dragData) {
const destItemId = this.html.find(event.target)?.closest('.item').attr('data-item-id')
const dropParams = await RdDSheetUtility.prepareItemDropParameters(destItemId, this.actor, dragData, this.objetVersConteneur)
if (dropParams) {
const callSuper = await this.actor.processDropItem(dropParams)
if (callSuper) {
await super._onDropItem(event, dragData)
}
}
}
/* -------------------------------------------- */
async selectObjetTypeToCreate() {
let typeObjets = this.getTypesInventaire().sort(Misc.ascending(type => Misc.typeName('Item', type)));
let content = `<span class="competence-label">Selectionnez le type d'équipement</span><select class="item-type">`;
for (let typeName of typeObjets) {
content += `<option value="${typeName}">${Misc.typeName('Item', typeName)}</option>`
}
content += '</select>';
let d = new Dialog({
title: "Créer un équipement",
content: content,
buttons: {
create: {
icon: '<i class="fas fa-check"></i>',
label: "Créer l'objet",
callback: () => this.actor.createItem($(".item-type").val())
}
}
});
d.render(true);
}
getTypesInventaire() {
return RdDItem.getItemTypesInventaire();
}
/** @override */
setPosition(options = {}) {
const position = super.setPosition(options);
const sheetHeader = this.element.find(".sheet-header");
const sheetTabs = this.element.find(".sheet-tabs");
const sheetBody = this.element.find(".sheet-body");
let bodyHeight = position.height - sheetHeader[0].clientHeight;
if (sheetTabs.length > 0) {
bodyHeight -= sheetTabs[0].clientHeight;
}
sheetBody.css("height", bodyHeight);
return position;
}
/* -------------------------------------------- */
/** @override */
_updateObject(event, formData) {
// Update the Actor
return this.actor.update(formData);
}
async splitItem(item) {
const dialog = await DialogSplitItem.create(item, (item, split) => this._onSplitItem(item, split));
dialog.render(true);
}
async _onSplitItem(item, split) {
if (split >= 1 && split < item.system.quantite) {
await item.diminuerQuantite(split);
const splitItem = duplicate(item);
splitItem.system.quantite = split;
await this.actor.createEmbeddedDocuments('Item', [splitItem])
}
}
vendre(item) {
item?.proposerVente(this.actor.getQuantiteDisponible(item));
}
}

View File

@ -1,619 +0,0 @@
import { ChatUtility } from "../chat-utility.js";
import { SYSTEM_SOCKET_ID } from "../constants.js";
import { Monnaie } from "../item-monnaie.js";
import { Misc } from "../misc.js";
import { RdDAudio } from "../rdd-audio.js";
import { RdDUtility } from "../rdd-utility.js";
import { SystemCompendiums } from "../settings/system-compendiums.js";
export class RdDBaseActor extends Actor {
static getDefaultImg(itemType) {
return game.system.rdd.actorClasses[itemType]?.defaultIcon ?? defaultItemImg[itemType];
}
/* -------------------------------------------- */
static init() {
Hooks.on("preUpdateItem", (item, change, options, id) => RdDBaseActor.getParentActor(item)?.onPreUpdateItem(item, change, options, id));
Hooks.on("createItem", (item, options, id) => RdDBaseActor.getParentActor(item)?.onCreateItem(item, options, id));
Hooks.on("deleteItem", (item, options, id) => RdDBaseActor.getParentActor(item)?.onDeleteItem(item, options, id));
Hooks.on("updateActor", (actor, change, options, actorId) => actor.onUpdateActor(change, options, actorId));
}
static onSocketMessage(sockmsg) {
switch (sockmsg.msg) {
case "msg_remote_actor_call":
return RdDBaseActor.onRemoteActorCall(sockmsg.data, sockmsg.userId);
case "msg_reset_nombre_astral":
console.log("RESET ASTRAL", game.user.character);
game.user.character.resetNombreAstral();
return;
}
}
static remoteActorCall(callData, userId = undefined) {
userId = userId ?? Misc.firstConnectedGMId();
if (userId == game.user.id) {
RdDBaseActor.onRemoteActorCall(callData, userId);
return false;
}
else {
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_remote_actor_call", data: callData, userId: userId });
return true;
}
}
static onRemoteActorCall(callData, userId) {
if (userId == game.user.id) {
const actor = game.actors.get(callData?.actorId);
if (Misc.isOwnerPlayerOrUniqueConnectedGM(actor)) { // Seul le joueur choisi effectue l'appel: le joueur courant si propriétaire de l'actor, ou le MJ sinon
const args = callData.args;
console.info(`RdDBaseActor.onRemoteActorCall: pour l'Actor ${callData.actorId}, appel de RdDBaseActor.${callData.method}(`, ...args, ')');
actor[callData.method](...args);
}
}
}
static getParentActor(document) {
return document?.parent instanceof Actor ? document.parent : undefined
}
/**
* Cet methode surcharge Actor.create() pour ajouter si besoin des Items par défaut:
* compétences et monnaies.
*
* @param {Object} actorData template d'acteur auquel ajouter des informations.
* @param {Object} options optionspour customiser la création
*/
static async create(actorData, options) {
// import depuis un compendium
if (actorData instanceof Array) {
return super.create(actorData, options);
}
// Création d'un acteur avec des items (uniquement en cas de duplication): pas besoin d'ajouter d'items
if (actorData.items) {
return await super.create(actorData, options);
}
actorData.items = [];
if (actorData.type == "personnage") {
const competences = await SystemCompendiums.getCompetences(actorData.type);
actorData.items = actorData.items.concat(competences.map(i => i.toObject()))
.concat(Monnaie.monnaiesStandard());
}
else if (actorData.type == "commerce") {
actorData.items = actorData.items.concat(Monnaie.monnaiesStandard());
}
return super.create(actorData, options);
}
constructor(docData, context = {}) {
if (!context.rdd?.ready) {
mergeObject(context, { rdd: { ready: true } });
const ActorConstructor = game.system.rdd.actorClasses[docData.type];
if (ActorConstructor) {
if (!docData.img) {
docData.img = ActorConstructor.defaultIcon;
}
return new ActorConstructor(docData, context);
}
}
super(docData, context);
}
isCreatureEntite() { return this.type == 'creature' || this.type == 'entite'; }
isCreature() { return this.type == 'creature'; }
isEntite() { return this.type == 'entite'; }
isPersonnage() { return this.type == 'personnage'; }
isVehicule() { return this.type == 'vehicule'; }
getItem(id, type = undefined) {
const item = this.items.get(id);
if (type == undefined || (item?.type == type)) {
return item;
}
return undefined;
}
listItems(type = undefined) { return (type ? this.itemTypes[type] : this.items); }
filterItems(filter, type = undefined) { return this.listItems(type)?.filter(filter) ?? []; }
findItemLike(idOrName, type) {
return this.getItem(idOrName, type)
?? Misc.findFirstLike(idOrName, this.listItems(type), { description: Misc.typeName('Item', type) });
}
getMonnaie(id) { return this.findItemLike(id, 'monnaie'); }
recompute() { }
/* -------------------------------------------- */
async onPreUpdateItem(item, change, options, id) { }
async onCreateItem(item, options, id) { }
async onDeleteItem(item, options, id) { }
async onUpdateActor(update, options, actorId) { }
async onTimeChanging(oldTimestamp, newTimestamp) {
this.items.filter(it => it.isFinPeriode(oldTimestamp, newTimestamp))
.forEach(async it => await it.onFinPeriodeTemporel(oldTimestamp, newTimestamp))
}
/* -------------------------------------------- */
getFortune() {
return Monnaie.getFortune(this.itemTypes['monnaie']);
}
/* -------------------------------------------- */
async monnaieIncDec(id, value) {
let monnaie = this.getMonnaie(id);
if (monnaie) {
const quantite = Math.max(0, monnaie.system.quantite + value);
await this.updateEmbeddedDocuments('Item', [{ _id: monnaie.id, 'system.quantite': quantite }]);
}
}
computePrixTotalEquipement() {
return this.items.filter(it => it.isInventaire())
.filter(it => !it.isMonnaie())
.map(it => it.valeurTotale())
.reduce(Misc.sum(), 0);
}
async payerSols(depense) {
depense = Number(depense);
if (depense == 0) {
return;
}
let fortune = this.getFortune();
console.log("payer", game.user.character, depense, fortune);
let msg = "";
if (fortune >= depense) {
await Monnaie.optimiserFortune(this, fortune - depense);
msg = `Vous avez payé <strong>${depense} Sols</strong>, qui ont été soustraits de votre argent.`;
RdDAudio.PlayContextAudio("argent"); // Petit son
} else {
msg = "Vous n'avez pas assez d'argent pour payer cette somme !";
}
let message = {
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
content: msg
};
ChatMessage.create(message);
}
async depenserSols(sols) {
let reste = this.getFortune() - Number(sols);
if (reste >= 0) {
await Monnaie.optimiserFortune(this, reste);
}
return reste;
}
async ajouterSols(sols, fromActorId = undefined) {
sols = Number(sols);
if (sols == 0) {
return;
}
if (sols < 0) {
ui.notifications.error(`Impossible d'ajouter un gain de ${sols} <0`);
return;
}
if (fromActorId && !game.user.isGM) {
RdDBaseActor.remoteActorCall({
userId: Misc.connectedGMOrUser(),
actorId: this.id,
method: 'ajouterSols', args: [sols, fromActorId]
});
}
else {
const fromActor = game.actors.get(fromActorId)
await Monnaie.optimiserFortune(this, sols + this.getFortune());
RdDAudio.PlayContextAudio("argent"); // Petit son
ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
content: `Vous avez reçu <strong>${sols} Sols</strong> ${fromActor ? " de " + fromActor.name : ''}, qui ont été ajoutés à votre argent.`
});
}
}
/* -------------------------------------------- */
getQuantiteDisponible(item) {
return item?.isService() ? undefined : item?.getQuantite();
}
/* -------------------------------------------- */
async achatVente(achat) {
if (achat.vendeurId == achat.acheteurId) {
ui.notifications.info("Inutile de se vendre à soi-même");
return;
}
if (!Misc.isUniqueConnectedGM()) {
RdDBaseActor.remoteActorCall({
actorId: achat.vendeurId ?? achat.acheteurId,
method: 'achatVente',
args: [achat]
});
return;
}
const cout = Number(achat.prixTotal ?? 0);
const vendeur = achat.vendeurId ? game.actors.get(achat.vendeurId) : undefined;
const acheteur = achat.acheteurId ? game.actors.get(achat.acheteurId) : undefined;
const vente = achat.vente;
const quantite = (achat.choix.nombreLots ?? 1) * (vente.tailleLot);
const itemVendu = vendeur?.getItem(vente.item._id);
if (!this.verifierQuantite(vendeur, itemVendu, quantite)) {
ChatUtility.notifyUser(achat.userId, 'warn', `Le vendeur n'a pas assez de ${itemVendu.name} !`);
return
}
if (acheteur && !acheteur.verifierFortune(cout)) {
ChatUtility.notifyUser(achat.userId, 'warn', `Vous n'avez pas assez d'argent pour payer ${Math.ceil(cout / 100)} sols !`);
return;
}
await this.decrementerVente(vendeur, itemVendu, quantite, cout);
if (acheteur) {
await acheteur.depenserSols(cout);
const createdItemId = await acheteur.creerQuantiteItem(vente.item, quantite);
await acheteur.consommerNourritureAchetee(achat, vente, createdItemId);
}
if (cout > 0) {
RdDAudio.PlayContextAudio("argent");
}
const chatAchatItem = duplicate(vente);
chatAchatItem.quantiteTotal = quantite;
ChatMessage.create({
user: achat.userId,
speaker: { alias: (acheteur ?? vendeur).name },
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-achat-item.html', chatAchatItem)
});
if (!vente.quantiteIllimite) {
if (vente.quantiteNbLots <= achat.choix.nombreLots) {
ChatUtility.removeChatMessageId(achat.chatMessageIdVente);
}
else if (achat.chatMessageIdVente) {
vente["properties"] = itemVendu.getProprietes();
vente.quantiteNbLots -= achat.choix.nombreLots;
vente.jsondata = JSON.stringify(vente.item);
const messageVente = game.messages.get(achat.chatMessageIdVente);
messageVente.update({ content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', vente) });
messageVente.render(true);
}
}
}
async decrementerVente(vendeur, itemVendu, quantite, cout) {
if (vendeur) {
await vendeur.ajouterSols(cout);
await vendeur.decrementerQuantiteItem(itemVendu, quantite);
}
}
verifierFortune(cout) {
return this.getFortune() >= cout;
}
verifierQuantite(vendeur, item, quantiteTotal) {
const disponible = vendeur?.getQuantiteDisponible(item);
return disponible == undefined || disponible >= quantiteTotal;
}
async consommerNourritureAchetee(achat, vente, createdItemId) {
if (achat.choix.consommer && vente.item.type == 'nourritureboisson' && createdItemId != undefined) {
achat.choix.doses = achat.choix.nombreLots;
await this.consommerNourritureboisson(createdItemId, achat.choix, vente.actingUserId);
}
}
async decrementerQuantiteItem(item, quantite, options = { supprimerSiZero: true }) {
if (item.isService()) {
return;
}
let resteQuantite = (item.system.quantite ?? 1) - quantite;
if (resteQuantite <= 0) {
if (options.supprimerSiZero) {
await this.deleteEmbeddedDocuments("Item", [item.id]);
}
else {
await this.updateEmbeddedDocuments("Item", [{ _id: item.id, 'system.quantite': 0 }]);
}
if (resteQuantite < 0) {
ui.notifications.warn(`La quantité de ${item.name} était insuffisante, l'objet a donc été supprimé`)
}
}
else if (resteQuantite > 0) {
await this.updateEmbeddedDocuments("Item", [{ _id: item.id, 'system.quantite': resteQuantite }]);
}
}
async creerQuantiteItem(item, quantite) {
if (this.canReceive(item)) {
const isItemEmpilable = "quantite" in item.system;
const baseItem = {
type: item.type,
img: item.img,
name: item.name,
system: mergeObject(item.system, { quantite: isItemEmpilable ? quantite : undefined })
};
const newItems = isItemEmpilable ? [baseItem] : Array.from({ length: quantite }, (_, i) => baseItem);
const items = await this.createEmbeddedDocuments("Item", newItems);
return items.length > 0 ? items[0].id : undefined;
}
}
/* -------------------------------------------- */
async computeEncTotal() {
if (!this.pack) {
this.encTotal = this.items.map(it => it.getEncTotal()).reduce(Misc.sum(), 0);
return this.encTotal;
}
return 0;
}
async createItem(type, name = undefined) {
if (!name) {
name = 'Nouveau ' + Misc.typeName('Item', type);
}
await this.createEmbeddedDocuments('Item', [{ name: name, type: type }], { renderSheet: true });
}
canReceive(item) {
return false;
}
async processDropItem(params) {
const targetActorId = this.id;
const sourceActorId = params.sourceActorId;
const itemId = params.itemId;
const destId = params.destId;
const srcId = params.srcId;
if (sourceActorId && sourceActorId != targetActorId) {
console.log("Moving objects", sourceActorId, targetActorId, itemId);
this.moveItemsBetweenActors(itemId, sourceActorId);
return false;
}
let result = true;
const item = this.getItem(itemId);
if (item?.isInventaire('all') && sourceActorId == targetActorId) {
// rangement
if (srcId != destId && itemId != destId) { // déplacement de l'objet
const src = this.getItem(srcId);
const dest = this.getItem(destId);
const cible = this.getContenantOrParent(dest);
const [empilable, message] = item.isInventaireEmpilable(dest);
if (empilable) {
await dest.empiler(item)
result = false;
}
// changer de conteneur
else if (!cible || this.conteneurPeutContenir(cible, item)) {
await this.enleverDeConteneur(item, src, params.onEnleverConteneur);
await this.ajouterDansConteneur(item, cible, params.onAjouterDansConteneur);
if (message && !dest.isConteneur()) {
ui.notifications.info(cible
? `${message}<br>${item.name} a été déplacé dans: ${cible.name}`
: `${message}<br>${item.name} a été sorti du conteneur`);
}
}
}
}
await this.computeEncTotal();
return result;
}
getContenantOrParent(dest) {
if (!dest || dest.isConteneur()) {
return dest;
}
return this.getContenant(dest);
}
getContenant(item) {
return this.itemTypes['conteneur'].find(it => it.system.contenu.includes(item.id));
}
/* -------------------------------------------- */
conteneurPeutContenir(dest, item) {
if (!dest) {
return true;
}
if (!dest.isConteneur()) {
return false;
}
const destData = dest
if (this._isConteneurContenu(item, dest)) {
ui.notifications.warn(`Impossible de déplacer un conteneur parent (${item.name}) dans un de ses contenus ${destData.name} !`);
return false; // Loop detected !
}
// Calculer le total actuel des contenus
let encContenu = this.getRecursiveEnc(dest) - Number(destData.system.encombrement);
let newEnc = this.getRecursiveEnc(item); // Calculer le total actuel du nouvel objet
// Teste si le conteneur de destination a suffisament de capacité pour recevoir le nouvel objet
if (Number(destData.system.capacite) < encContenu + newEnc) {
ui.notifications.warn(
`Le conteneur ${dest.name} a une capacité de ${destData.system.capacite}, et contient déjà ${encContenu}.
Impossible d'y ranger: ${item.name} d'encombrement ${newEnc}!`);
return false;
}
return true;
}
/* -------------------------------------------- */
_isConteneurContenu(item, conteneur) {
if (item?.isConteneur()) { // Si c'est un conteneur, il faut vérifier qu'on ne le déplace pas vers un sous-conteneur lui appartenant
for (let id of item.system.contenu) {
let subObjet = this.getItem(id);
if (subObjet?.id == conteneur.id) {
return true; // Loop detected !
}
if (subObjet?.isConteneur()) {
return this._isConteneurContenu(subObjet, conteneur);
}
}
}
return false;
}
/* -------------------------------------------- */
getRecursiveEnc(objet) {
if (!objet) {
return 0;
}
const tplData = objet.system;
if (objet.type != 'conteneur') {
return Number(tplData.encombrement) * Number(tplData.quantite);
}
const encContenus = tplData.contenu.map(idContenu => this.getRecursiveEnc(this.getItem(idContenu)));
return encContenus.reduce(Misc.sum(), 0)
+ Number(tplData.encombrement) /* TODO? Number(tplData.quantite) -- on pourrait avoir plusieurs conteneurs...*/
}
/* -------------------------------------------- */
/** Ajoute un item dans un conteneur, sur la base
* de leurs ID */
async ajouterDansConteneur(item, conteneur, onAjouterDansConteneur) {
if (!conteneur) {
// TODO: afficher
item.estContenu = false;
}
else if (conteneur.isConteneur()) {
item.estContenu = true;
await this.updateEmbeddedDocuments('Item', [{
_id: conteneur.id,
'system.contenu': [...conteneur.system.contenu, item.id]
}]);
onAjouterDansConteneur(item.id, conteneur.id);
}
}
/* -------------------------------------------- */
/** Fonction de remise à plat de l'équipement (ie vide les champs 'contenu') */
async nettoyerConteneurs() {
RdDConfirm.confirmer({
settingConfirmer: "confirmation-vider",
content: `<p>Etes vous certain de vouloir vider tous les conteneurs ?</p>`,
title: 'Vider les conteneurs',
buttonLabel: 'Vider',
onAction: async () => {
const corrections = [];
for (let item of this.items) {
if (item.estContenu) {
item.estContenu = undefined;
}
if (item.type == 'conteneur' && item.system.contenu.length > 0) {
corrections.push({ _id: item.id, 'system.contenu': [] });
}
}
if (corrections.length > 0) {
await this.updateEmbeddedDocuments('Item', corrections);
}
}
});
}
/* -------------------------------------------- */
buildSubConteneurObjetList(conteneurId, deleteList) {
let conteneur = this.getItem(conteneurId);
if (conteneur?.type == 'conteneur') { // Si c'est un conteneur
for (let subId of conteneur.system.contenu) {
let subObj = this.getItem(subId);
if (subObj) {
if (subObj.type == 'conteneur') {
this.buildSubConteneurObjetList(subId, deleteList);
}
deleteList.push({ id: subId, conteneurId: conteneurId });
}
}
}
}
/* -------------------------------------------- */
async deleteAllConteneur(itemId, options) {
let list = [];
list.push({ id: itemId, conteneurId: undefined }); // Init list
this.buildSubConteneurObjetList(itemId, list);
await this.deleteEmbeddedDocuments('Item', list.map(it => it.id), options);
}
/* -------------------------------------------- */
/** Supprime un item d'un conteneur, sur la base
* de leurs ID */
async enleverDeConteneur(item, conteneur, onEnleverDeConteneur) {
if (conteneur?.isConteneur()) {
item.estContenu = false;
await this.updateEmbeddedDocuments('Item', [{
_id: conteneur.id,
'system.contenu': conteneur.system.contenu.filter(id => id != item.id)
}]);
onEnleverDeConteneur();
}
}
/* -------------------------------------------- */
async moveItemsBetweenActors(itemId, sourceActorId) {
let itemsList = []
let sourceActor = game.actors.get(sourceActorId);
itemsList.push({ id: itemId, conteneurId: undefined }); // Init list
sourceActor.buildSubConteneurObjetList(itemId, itemsList); // Get itemId list
const itemsDataToCreate = itemsList.map(it => sourceActor.getItem(it.id))
.map(it => duplicate(it))
.map(it => { it.system.contenu = []; return it; });
let newItems = await this.createEmbeddedDocuments('Item', itemsDataToCreate);
let itemMap = this._buildMapOldNewId(itemsList, newItems);
for (let item of itemsList) { // Second boucle pour traiter la remise en conteneurs
// gestion conteneur/contenu
if (item.conteneurId) { // l'Objet était dans un conteneur
let newConteneurId = itemMap[item.conteneurId]; // Get conteneur
let newConteneur = this.getItem(newConteneurId);
let newItemId = itemMap[item.id]; // Get newItem
console.log('New conteneur filling!', newConteneur, newItemId, item);
let contenu = duplicate(newConteneur.system.contenu);
contenu.push(newItemId);
await this.updateEmbeddedDocuments('Item', [{ _id: newConteneurId, 'system.contenu': contenu }]);
}
}
for (let item of itemsList) {
await sourceActor.deleteEmbeddedDocuments('Item', [item.id]);
}
}
_buildMapOldNewId(itemsList, newItems) {
let itemMap = {};
for (let i = 0; i < itemsList.length; i++) {
itemMap[itemsList[i].id] = newItems[i].id; // Pour garder le lien ancien / nouveau
}
return itemMap;
}
/* -------------------------------------------- */
async postActorToChat(modeOverride) {
let chatData = {
doctype: 'Actor',
id: this.id,
type: this.type,
img: this.img,
pack: this.pack,
name: this.name,
system: { description: this.system.description }
}
renderTemplate('systems/foundryvtt-reve-de-dragon/templates/post-actor.html', chatData)
.then(html => ChatMessage.create(RdDUtility.chatDataSetup(html, modeOverride)));
}
}

View File

@ -1,74 +0,0 @@
import { DialogItemAchat } from "../dialog-item-achat.js";
import { RdDItem } from "../item.js";
import { RdDSheetUtility } from "../rdd-sheet-utility.js";
import { RdDUtility } from "../rdd-utility.js";
import { RdDBaseActorSheet } from "./base-actor-sheet.js";
import { RdDCommerce } from "./commerce.js";
/**
* Extend the basic ActorSheet with some very simple modifications
* @extends {ActorSheet}
*/
export class RdDCommerceSheet extends RdDBaseActorSheet {
/** @override */
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
classes: ["rdd", "sheet", "actor"],
template: "systems/foundryvtt-reve-de-dragon/templates/actor/commerce-actor-sheet.html",
width: 600,
height: 720,
tabs: [],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }]
});
}
/* -------------------------------------------- */
/** @override */
activateListeners(html) {
super.activateListeners(html);
this.html.find('a.item-acheter').click(async event => await this.vente(this.getItem(event)));
if (!this.options.editable) return;
this.html.find('a.item-quantite-moins').click(async event => await this.getItem(event)?.quantiteIncDec(-1, { supprimerSiZero: false}));
this.html.find('a.item-quantite-plus').click(async event => await this.getItem(event)?.quantiteIncDec(1));
this.html.find('input.item-quantite').change(async event => {
const newQuantite = Math.max(0, Number.parseInt(this.html.find(event.currentTarget).val()));
await this.getItem(event)?.update({ "system.quantite": newQuantite });
})
this.html.find('input.item-cout').change(async event => {
const newCout = Math.max(0, Number(this.html.find(event.currentTarget).val()));
await this.getItem(event)?.update({ "system.cout": newCout });
})
}
getTypesInventaire() {
return RdDItem.getItemTypesInventaire('all');
}
async vente(item) {
const acheteur = RdDUtility.getSelectedActor();
if (!acheteur) {
ui.notifications.warn(`Pas d'acheteur sélectionné`);
return;
}
const disponible = this.actor.getQuantiteDisponible(item)
if (disponible == 0) {
ui.notifications.warn(`${this.name} n'a plus de ${item.name} en vente`);
return;
}
await DialogItemAchat.onAcheter({
item,
vendeur: this.actor,
acheteur,
quantiteIllimite: disponible == undefined,
nbLots: disponible ?? 1,
tailleLot: 1,
prixLot: item.calculerPrixCommercant()
});
}
}

View File

@ -1,53 +0,0 @@
import { Misc } from "../misc.js";
import { RdDBaseActor } from "./base-actor.js";
export class RdDCommerce extends RdDBaseActor {
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/services/commerce.webp";
}
prepareData() {
super.prepareData();
}
prepareDerivedData() {
super.prepareDerivedData();
}
canReceive(item) {
if (item.isInventaire('all')) {
return true;
}
return super.canReceive(item);
}
getQuantiteDisponible(item) {
return this.system.illimite || item.isService() ? undefined : item.getQuantite();
}
verifierFortune(cout) {
return this.system.illimite || super.verifierFortune(cout);
}
async depenserSols(cout) {
if (this.system.illimite) {
return
}
await super.depenserSols(cout)
}
async consommerNourritureAchetee(achat, vente, createdItemId) {
// ne pas consommer pour un commerce
}
async decrementerQuantiteItem(item, quantite) {
if (this.system.illimite) {
return;
}
await super.decrementerQuantiteItem(item, quantite, { supprimerSiZero: false });
}
calculerPrix(item) {
const pourcentage = this.system.pourcentage ?? 100;
return Misc.keepDecimals(Math.ceil(item.system.cout * pourcentage) / 100, 2);
}
}

View File

@ -1,6 +1,7 @@
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; import { SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
export const MESSAGE_DATA = 'message-data';
/** /**
* Class providing helper methods to get the list of users, and * Class providing helper methods to get the list of users, and
@ -18,50 +19,61 @@ export class ChatUtility {
/* -------------------------------------------- */ /* -------------------------------------------- */
static notifyUser(userId, level = 'info', message) { static notifyUser(userId, level = 'info', message) {
const socketData = { const data = {
userId: userId, level: level, message: message userId: userId, level: level, message: message
}; };
if (game.user.id == userId) { if (game.user.id == userId) {
ChatUtility.onNotifyUser(socketData); ChatUtility.onNotifyUser(data);
} }
else { else {
game.socket.emit(SYSTEM_SOCKET_ID, { game.socket.emit(SYSTEM_SOCKET_ID, {
msg: "msg_user_ui_notifications", data: socketData msg: "msg_user_ui_notifications", data: data
}); });
} }
} }
static onNotifyUser(socketData) { static onNotifyUser(data) {
if (game.user.id == socketData.userId) { if (game.user.id == data.userId) {
switch (socketData.level) { switch (data.level) {
case 'warn': ui.notifications.warn(socketData.message); break; case 'warn': ui.notifications.warn(data.message); break;
case 'error': ui.notifications.error(socketData.message); break; case 'error': ui.notifications.error(data.message); break;
default: ui.notifications.info(socketData.message); break; default: ui.notifications.info(data.message); break;
} }
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static onRemoveMessages(socketData) { static onRemoveMessages(data) {
if (Misc.isUniqueConnectedGM()) { if (Misc.isUniqueConnectedGM()) {
if (socketData.part) { if (data.part) {
const toDelete = game.messages.filter(it => it.content.includes(socketData.part)); const toDelete = game.messages.filter(it => it.data.content.includes(data.part));
toDelete.forEach(it => it.delete()); toDelete.forEach(it => it.delete());
} }
if (socketData.messageId) { if (data.messageId) {
game.messages.get(socketData.messageId)?.delete(); game.messages.get(data.messageId)?.delete();
} }
} }
} }
static onRemoveMessages(data) {
if (Misc.isUniqueConnectedGM()) {
if (data.part) {
const toDelete = game.messages.filter(it => it.data.content.includes(data.part));
toDelete.forEach(it => it.delete());
}
if (data.messageId) {
game.messages.get(data.messageId)?.delete();
}
}
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static removeMessages(socketData) { static removeMessages(data) {
if (Misc.isUniqueConnectedGM()) { if (Misc.isUniqueConnectedGM()) {
ChatUtility.onRemoveMessages(socketData); ChatUtility.onRemoveMessages(data);
} }
else { else {
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_delete_chat_message", data: socketData }); game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_delete_chat_message", data: data });
} }
} }
@ -129,7 +141,7 @@ export class ChatUtility {
/* -------------------------------------------- */ /* -------------------------------------------- */
static getUsers(filter) { static getUsers(filter) {
return game.users.filter(filter).map(user => user.id); return Misc.getUsers().filter(filter).map(user => user.data._id);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -142,17 +154,17 @@ export class ChatUtility {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static handleGMChatMessage(socketData) { static handleGMChatMessage(data) {
console.log("blindMessageToGM", socketData); console.log("blindMessageToGM", data);
if (game.user.isGM) { // message privé pour GM only if (game.user.isGM) { // message privé pour GM only
socketData.user = game.user.id; data.user = game.user.id;
ChatMessage.create(socketData); ChatMessage.create(data);
} }
} }
static async setMessageData(chatMessage, key, flag) { static async setMessageData(chatMessage, key, data) {
if (flag) { if (data) {
await chatMessage.setFlag(SYSTEM_RDD, key, JSON.stringify(flag)); await chatMessage.setFlag(SYSTEM_RDD, key, JSON.stringify(data));
} }
} }

View File

@ -1,6 +1,5 @@
export const SYSTEM_RDD = 'foundryvtt-reve-de-dragon'; export const SYSTEM_RDD = 'foundryvtt-reve-de-dragon';
export const SYSTEM_SOCKET_ID = 'system.foundryvtt-reve-de-dragon'; export const SYSTEM_SOCKET_ID = 'system.foundryvtt-reve-de-dragon';
export const LOG_HEAD = 'RdD | ';
export const HIDE_DICE = 'hide'; export const HIDE_DICE = 'hide';
export const SHOW_DICE = 'show'; export const SHOW_DICE = 'show';

View File

@ -1,126 +0,0 @@
import { SYSTEM_RDD } from "./constants.js";
import { Grammar } from "./grammar.js";
import { RdDTimestamp } from "./rdd-timestamp.js";
const LATEST_USED_JOURNAL_ID = "chronologie-dernier-journal";
export class DialogChronologie extends Dialog {
static init() {
game.settings.register(SYSTEM_RDD, LATEST_USED_JOURNAL_ID, {
name: "Dernier article de journal utilisé pour enregistrer la chronologie",
scope: "client",
config: false,
default: "",
type: String
});
}
static async create() {
const dialogData = {
auteur: game.user.name,
isGM: game.user.isGM,
information: "",
journalId: game.settings.get(SYSTEM_RDD, LATEST_USED_JOURNAL_ID),
journaux: game.journal.filter(it => it.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)),
timestamp: game.system.rdd.calendrier.timestamp,
dateReel: DialogChronologie.getCurrentDateTime()
};
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-chronologie.html", dialogData);
const dialog = new DialogChronologie(html);
dialog.render(true);
}
constructor(html) {
const options = {
classes: ["DialogChronologie"],
width: 500,
height: 'fit-content',
'z-index': 99999
};
const conf = {
title: "Chronologie",
content: html,
buttons: {
ajout: { label: "Ajouter", callback: it => this.ajouter() },
}
};
super(conf, options);
}
static getCurrentDateTime() {
return new Date().toLocaleString("sv-SE", {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit"
}).replace(" ", "T");
}
activateListeners(html) {
super.activateListeners(html);
this.html = html;
}
async ajouter() {
await this.forceValidation();
const { journalId, journalEntry } = this.findJournal();
// ajouter à la page ou créer une page
this.addContentToJournal(journalEntry, await this.prepareChronologieEntry());
this.storeLatestUsedJournalEntry(journalId);
}
async forceValidation() {
await this.html.find("form.rdddialogchrono :input").change();
}
findJournal() {
const journalId = this.html.find("form.rdddialogchrono :input[name='journalId']").val();
const journalEntry = game.journal.get(journalId);
return { journalId, journalEntry };
}
async prepareChronologieEntry() {
return await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/chronologie-entry.html", this.extractJournalParameters());
}
extractJournalParameters() {
return {
auteur: this.html.find("form.rdddialogchrono :input[name='auteur']").val(),
information: this.html.find("form.rdddialogchrono :input[name='information']").val(),
dateRdD: {
jour: this.html.find("form.rdddialogchrono :input[name='chronologie.jourDuMois']").val(),
mois: RdDTimestamp.definition(this.html.find("form.rdddialogchrono :input[name='chronologie.mois']").val()),
annee: this.html.find("form.rdddialogchrono :input[name='chronologie.annee']").val(),
heure: RdDTimestamp.definition(this.html.find("form.rdddialogchrono :input[name='chronologie.heure']").val()),
minute: this.html.find("form.rdddialogchrono :input[name='chronologie.minute']").val(),
},
dateReel: this.html.find("form.rdddialogchrono :input[name='dateReel']").val().replace('T', ' ')
}
}
addContentToJournal(journalEntry, content) {
let page = journalEntry.pages.find(p => p.type == 'text' && Grammar.equalsInsensitive(p.name, 'Chronologie'));
if (page) {
page.update({ 'text.content': content + '\n' + page.text.content });
}
else {
journalEntry.createEmbeddedDocuments('JournalEntryPage', [this.newPageChronologie(content)]);
}
}
newPageChronologie(content) {
return new JournalEntryPage({
name: 'Chronologie',
type: 'text',
title: { show: true, level: 1 },
text: { content: content, format: 1 }
});
}
storeLatestUsedJournalEntry(journalId) {
game.settings.set(SYSTEM_RDD, LATEST_USED_JOURNAL_ID, journalId);
}
}

View File

@ -1,6 +1,7 @@
import { ChatUtility } from "./chat-utility.js"; import { ChatUtility } from "./chat-utility.js";
import { HtmlUtility } from "./html-utility.js"; import { HtmlUtility } from "./html-utility.js";
import { RdDItemSigneDraconique } from "./item/item-signedraconique.js"; import { RdDItemSigneDraconique } from "./item-signedraconique.js";
import { Misc } from "./misc.js";
import { TMRUtility } from "./tmr-utility.js"; import { TMRUtility } from "./tmr-utility.js";
export class DialogCreateSigneDraconique extends Dialog { export class DialogCreateSigneDraconique extends Dialog {
@ -9,13 +10,12 @@ export class DialogCreateSigneDraconique extends Dialog {
const signe = await RdDItemSigneDraconique.randomSigneDraconique({ephemere: true}); const signe = await RdDItemSigneDraconique.randomSigneDraconique({ephemere: true});
let dialogData = { let dialogData = {
signe: signe, signe: signe,
tmrs: TMRUtility.buildSelectionTypesTMR(signe.system.typesTMR), tmrs: TMRUtility.listSelectedTMR(signe.data.typesTMR ?? []),
actors: game.actors.filter(actor => actor.isPersonnage() && actor.isHautRevant()) actors: game.actors.filter(actor => actor.isHautRevant()).map(actor => {
.map(actor => ({ let actorData = duplicate(Misc.data(actor));
id: actor.id, actorData.selected = actor.hasPlayerOwner;
name: actor.name, return actorData;
selected: true })
}))
}; };
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-create-signedraconique.html", dialogData); const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-create-signedraconique.html", dialogData);
@ -23,11 +23,12 @@ export class DialogCreateSigneDraconique extends Dialog {
.render(true); .render(true);
} }
constructor(dialogData, html) { constructor(dialogData, html, callback) {
let options = { classes: ["DialogCreateSigneDraconiqueActorsActors"], width: 500, height: 650, 'z-index': 99999 }; let options = { classes: ["DialogCreateSigneDraconiqueActorsActors"], width: 500, height: 650, 'z-index': 99999 };
let conf = { let conf = {
title: "Créer un signe", title: "Créer un signe",
content: html, content: html,
default: "Ajouter aux haut-rêvants",
buttons: { buttons: {
"Ajouter aux haut-rêvants": { label: "Ajouter aux haut-rêvants", callback: it => { this._onCreerSigneActeurs(); } } "Ajouter aux haut-rêvants": { label: "Ajouter aux haut-rêvants", callback: it => { this._onCreerSigneActeurs(); } }
} }
@ -35,94 +36,83 @@ export class DialogCreateSigneDraconique extends Dialog {
super(conf, options); super(conf, options);
this.dialogData = dialogData; this.dialogData = dialogData;
} }
async _onCreerSigneActeurs() { async _onCreerSigneActeurs() {
await this.html.find("[name='signe.system.ephemere']").change(); await $("[name='signe.data.ephemere']").change();
await this.html.find(".signe-xp-sort").change(); await $(".signe-xp-sort").change();
this.validerSigne(); this.validerSigne();
this.dialogData.actors.filter(it => it.selected) this.dialogData.actors.filter(it => it.selected).map(it => game.actors.get(it._id))
.map(it => game.actors.get(it.id)) .forEach(actor => this._createSigneForActor(actor, this.dialogData.signe));
.forEach(actor => this._createSigneForActor(actor, this.dialogData.signe));
} }
async _createSigneForActor(actor, signe) { async _createSigneForActor(actor, signe) {
actor.createEmbeddedDocuments("Item", [signe]); actor.createEmbeddedDocuments("Item", [signe]);
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(actor.name), whisper: ChatUtility.getWhisperRecipientsAndGMs(Misc.data(actor).name),
content: await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-actor.html", { content: await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-actor.html", {
signe: signe, signe: signe,
alias: actor.name alias: Misc.data(actor).name
}) })
}); });
} }
validerSigne() { validerSigne() {
this.dialogData.signe.name = this.html.find("[name='signe.name']").val(); this.dialogData.signe.name = $("[name='signe.name']").val();
this.dialogData.signe.system.valeur.norm = this.html.find("[name='signe.system.valeur.norm']").val(); this.dialogData.signe.data.valeur.norm = $("[name='signe.data.valeur.norm']").val();
this.dialogData.signe.system.valeur.sign = this.html.find("[name='signe.system.valeur.sign']").val(); this.dialogData.signe.data.valeur.sign = $("[name='signe.data.valeur.sign']").val();
this.dialogData.signe.system.valeur.part = this.html.find("[name='signe.system.valeur.part']").val(); this.dialogData.signe.data.valeur.part = $("[name='signe.data.valeur.part']").val();
this.dialogData.signe.system.difficulte = this.html.find("[name='signe.system.difficulte']").val(); this.dialogData.signe.data.difficulte = $("[name='signe.data.difficulte']").val();
this.dialogData.signe.system.ephemere = this.html.find("[name='signe.system.ephemere']").prop("checked"); this.dialogData.signe.data.ephemere = $("[name='signe.data.ephemere']").prop("checked");
this.dialogData.signe.system.duree = this.html.find("[name='signe.system.duree']").val(); this.dialogData.signe.data.duree = $("[name='signe.data.duree']").val();
this.dialogData.signe.system.typesTMR = TMRUtility.buildListTypesTMRSelection(this.dialogData.tmrs); this.dialogData.signe.data.typesTMR = $(".select-tmr").val();
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
this.html = html; this.setEphemere(this.dialogData.signe.data.ephemere);
this.setEphemere(this.dialogData.signe.system.ephemere);
html.find(".signe-aleatoire").click(event => this.setSigneAleatoire()); html.find(".signe-aleatoire").click(event => this.setSigneAleatoire());
html.find("[name='signe.system.ephemere']").change((event) => this.setEphemere(event.currentTarget.checked)); html.find("[name='signe.data.ephemere']").change((event) => this.setEphemere(event.currentTarget.checked));
html.find(".select-actor").change((event) => this.onSelectActor(event));
html.find(".signe-xp-sort").change((event) => this.onValeurXpSort(event)); html.find(".signe-xp-sort").change((event) => this.onValeurXpSort(event));
html.find("input.select-actor").change((event) => this.onSelectActor(event));
html.find("input.select-tmr").change((event) => this.onSelectTmr(event));
} }
async setSigneAleatoire() { async setSigneAleatoire() {
const newSigne = await RdDItemSigneDraconique.randomSigneDraconique({ephemere: true}); const newSigne = await RdDItemSigneDraconique.randomSigneDraconique({ephemere: true});
this.html.find("[name='signe.name']").val(newSigne.name); $("[name='signe.name']").val(newSigne.name);
this.html.find("[name='signe.system.valeur.norm']").val(newSigne.system.valeur.norm); $("[name='signe.data.valeur.norm']").val(newSigne.data.valeur.norm);
this.html.find("[name='signe.system.valeur.sign']").val(newSigne.system.valeur.sign); $("[name='signe.data.valeur.sign']").val(newSigne.data.valeur.sign);
this.html.find("[name='signe.system.valeur.part']").val(newSigne.system.valeur.part); $("[name='signe.data.valeur.part']").val(newSigne.data.valeur.part);
this.html.find("[name='signe.system.difficulte']").val(newSigne.system.difficulte); $("[name='signe.data.difficulte']").val(newSigne.data.difficulte);
this.html.find("[name='signe.system.duree']").val(newSigne.system.duree); $("[name='signe.data.duree']").val(newSigne.data.duree);
this.html.find("[name='signe.system.ephemere']").prop("checked", newSigne.system.ephemere); $("[name='signe.data.ephemere']").prop("checked", newSigne.data.ephemere);
this.dialogData.tmrs = TMRUtility.buildSelectionTypesTMR(newSigne.system.typesTMR); $(".select-tmr").val(newSigne.data.typesTMR);
this.dialogData.tmrs.forEach(t => { this.setEphemere(newSigne.data.ephemere);
this.html.find(`[data-tmr-name='${t.name}']`).prop( "checked", t.selected);
})
this.setEphemere(newSigne.system.ephemere);
} }
async setEphemere(ephemere) { async setEphemere(ephemere) {
this.dialogData.signe.system.ephemere = ephemere; this.dialogData.signe.data.ephemere = ephemere;
HtmlUtility._showControlWhen(this.html.find(".signe-system-duree"), ephemere); HtmlUtility._showControlWhen($(".signe-data-duree"), ephemere);
} }
async onSelectActor(event) { async onSelectActor(event) {
const actorId = this.html.find(event.currentTarget)?.data("actor-id"); event.preventDefault();
const actor = this.dialogData.actors.find(it => it.id == actorId); const options = event.currentTarget.options;
if (actor) { for (var i = 0; i < options.length; i++) { // looping over the options
actor.selected = event.currentTarget.checked; const actorId = options[i].attributes["data-actor-id"].value;
} const actor = this.dialogData.actors.find(it => it._id == actorId);
if (actor) {
actor.selected = options[i].selected;
}
};
} }
onSelectTmr(event) {
const tmrName = this.html.find(event.currentTarget)?.data("tmr-name");
const onTmr = this.tmrs.find(it => it.name == tmrName);
if (onTmr){
onTmr.selected = event.currentTarget.checked;
}
}
onValeurXpSort(event) { onValeurXpSort(event) {
const codeReussite = event.currentTarget.attributes['data-typereussite']?.value ?? 0; const codeReussite = event.currentTarget.attributes['data-typereussite']?.value ?? 0;
const xp = Number(event.currentTarget.value); const xp = Number(event.currentTarget.value);
const oldValeur = this.dialogData.signe.system.valeur; const oldValeur = this.dialogData.signe.data.valeur;
this.dialogData.signe.system.valeur = RdDItemSigneDraconique.calculValeursXpSort(codeReussite, xp, oldValeur); this.dialogData.signe.data.valeur = RdDItemSigneDraconique.calculValeursXpSort(codeReussite, xp, oldValeur);
} }
} }

View File

@ -6,43 +6,36 @@ export class DialogFabriquerPotion extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
static async create(actor, item, dialogConfig) { static async create(actor, item, dialogConfig) {
const min = DialogFabriquerPotion.nombreBrinsMinimum(item);
if (item.system.quantite < min) {
ui.notifications.warn(`Vous avez ${item.system.quantite} brins de ${item.name}, il en faut au moins ${min} pour faire une potion!`);
return;
}
let potionData = DialogFabriquerPotion.prepareData(actor, item); let potionData = DialogFabriquerPotion.prepareData(actor, item);
const html = await renderTemplate(dialogConfig.html, potionData); let conf = {
title: `Fabriquer une potion de ${potionData.data.categorie}`,
content: await renderTemplate(dialogConfig.html, potionData),
default: potionData.buttonName,
};
let options = { classes: ["dialogfabriquerpotion"], width: 600, height: 160, 'z-index': 99999 }; let options = { classes: ["dialogfabriquerpotion"], width: 600, height: 160, 'z-index': 99999 };
mergeObject(options, dialogConfig.options ?? {}, { overwrite: true }) mergeObject(options, dialogConfig.options ?? {}, { overwrite: true })
new DialogFabriquerPotion(actor, potionData, html, options).render(true); const dialog = new DialogFabriquerPotion(actor, potionData, conf, options);
dialog.render(true);
return dialog;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static prepareData(actor, item) { static prepareData(actor, item) {
let potionData = duplicate(item) let potionData = duplicate(Misc.data(item));
potionData.nbBrinsSelect = RdDUtility.buildListOptions( potionData.nbBrinsSelect = RdDUtility.buildListOptions(1, potionData.data.quantite);
DialogFabriquerPotion.nombreBrinsMinimum(item), potionData.nbBrins = Math.min(potionData.data.quantite, DialogFabriquerPotion.getNombreBrinOptimal(potionData));
DialogFabriquerPotion.nombreBrinsOptimal(item));
potionData.nbBrins = Math.min(potionData.system.quantite, DialogFabriquerPotion.nombreBrinsOptimal(potionData));
potionData.herbebonus = item.system.niveau;
potionData.buttonName = "Fabriquer"; potionData.buttonName = "Fabriquer";
return potionData; return potionData;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
constructor(actor, potionData, html, options) { constructor(actor, potionData, conf, options) {
const conf = { conf.buttons = {
title: `Fabriquer une potion de ${potionData.system.categorie}`, [potionData.buttonName]: {
content: html, label: potionData.buttonName, callback: it => this.onFabriquer(it)
default: 'fabriquer',
buttons: {
'fabriquer': {
label: potionData.buttonName, callback: it => this.onFabriquer(html)
}
} }
}; };
@ -52,37 +45,27 @@ export class DialogFabriquerPotion extends Dialog {
this.potionData = potionData; this.potionData = potionData;
} }
static getNombreBrinOptimal(herbeData) {
switch (herbeData.data.categorie ?? '') {
case "Soin": return 12 - herbeData.data.niveau;
case "Repos": return 7 - herbeData.data.niveau;
}
return 1;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
this.html = html;
this.html.find("[name='nbBrins']").change(event => { html.find("#nbBrins").change(event => {
this.potionData.nbBrins = Misc.toInt(event.currentTarget.value); this.potionData.nbBrins = Misc.toInt(event.currentTarget.value);
const brinsManquants = Math.max(0, DialogFabriquerPotion.nombreBrinsOptimal(this.potionData) - this.potionData.nbBrins);
this.potionData.herbebonus = Math.max(0, this.potionData.system.niveau - brinsManquants)
}); });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async onFabriquer(html) { async onFabriquer(it) {
await this.html.find("[name='nbBrins']").change(); await $("#nbBrins").change();
this.actor.fabriquerPotion(this.potionData); this.actor.fabriquerPotion(this.potionData);
this.close(); this.close();
} }
static nombreBrinsMinimum(herbeData) {
switch (herbeData.system.categorie ?? '') {
case "Soin": return 1 + Math.max(0, 12 - 2 * herbeData.system.niveau);
case "Repos": return 1 + Math.max(0, 7 - 2 * herbeData.system.niveau);
}
return 1;
}
static nombreBrinsOptimal(herbeData) {
switch (herbeData.system.categorie ?? '') {
case "Soin": return 12 - herbeData.system.niveau;
case "Repos": return 7 - herbeData.system.niveau;
}
return 1;
}
} }

View File

@ -1,105 +1,93 @@
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";
export class DialogItemAchat extends Dialog { export class DialogItemAchat extends Dialog {
static preparerAchat(chatButton) { static async onButtonAcheter(event) {
const vendeurId = chatButton.attributes['data-vendeurId']?.value; const buttonAcheter = event.currentTarget;
if (!buttonAcheter.attributes['data-jsondata']?.value) {
ui.notifications.warn("Impossible d'acheter: informations sur l'objet manquantes")
return;
}
const chatMessageIdVente = RdDUtility.findChatMessageId(buttonAcheter);
const vendeurId = buttonAcheter.attributes['data-vendeurId']?.value;
const vendeur = vendeurId ? game.actors.get(vendeurId) : undefined; const vendeur = vendeurId ? game.actors.get(vendeurId) : undefined;
const acheteur = RdDUtility.getSelectedActor(); const acheteur = RdDUtility.getSelectedActor();
const json = chatButton.attributes['data-jsondata']?.value;
if (!acheteur && !vendeur) { if (!acheteur && !vendeur) {
ui.notifications.info("Pas d'acheteur ni de vendeur, aucun changement"); ui.notifications.info("Pas d'acheteur ni de vendeur, aucun changement");
return undefined; return;
}
if (!json) {
ui.notifications.warn("Impossible d'acheter: informations sur l'objet manquantes")
return undefined;
} }
return { let venteData = DialogItemAchat.prepareVenteData(buttonAcheter, vendeurId, vendeur, acheteur);
item: (json ? JSON.parse(json) : undefined),
vendeur,
acheteur,
nbLots: parseInt(chatButton.attributes['data-quantiteNbLots']?.value),
tailleLot: parseInt(chatButton.attributes['data-tailleLot']?.value ?? 1),
prixLot: Number(chatButton.attributes['data-prixLot']?.value ?? 0),
quantiteIllimite: chatButton.attributes['data-quantiteIllimite']?.value == 'true',
chatMessageIdVente: RdDUtility.findChatMessageId(chatButton),
};
}
static async onAcheter({ item, vendeur, acheteur, tailleLot, prixLot, nbLots, quantiteIllimite, chatMessageIdVente }) {
const venteData = {
item,
actingUserId: game.user.id,
vendeurId: vendeur?.id,
vendeur,
acheteur,
tailleLot,
quantiteIllimite,
quantiteNbLots: nbLots,
choix: { seForcer: false, supprimerSiZero: true },
prixLot,
isVente: prixLot > 0,
isConsommable: item.type == 'nourritureboisson' && acheteur?.isPersonnage(),
chatMessageIdVente
};
DialogItemAchat.changeNombreLots(venteData, 1);
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-achat.html`, venteData); const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-achat.html`, venteData);
new DialogItemAchat(html, venteData).render(true); const dialog = new DialogItemAchat(html, vendeur, acheteur, venteData, chatMessageIdVente);
dialog.render(true);
} }
static changeNombreLots(venteData, nombreLots) { constructor(html, vendeur, acheteur, venteData, chatMessageIdVente) {
venteData.choix.nombreLots = nombreLots; const isConsommable = venteData.item.type == 'nourritureboisson';
venteData.prixTotal = (nombreLots * venteData.prixLot).toFixed(2); let options = { classes: ["dialogachat"], width: 400, height: isConsommable ? 450 : 350, 'z-index': 99999 };
if (venteData.isConsommable) {
const doses = nombreLots * venteData.tailleLot;
venteData.totalSust = Misc.keepDecimals(doses * (venteData.item.system.sust ?? 0), 2);
venteData.totalDesaltere = venteData.item.system.boisson
? Misc.keepDecimals(doses * (venteData.item.system.desaltere ?? 0), 2)
: 0;
}
}
constructor(html, venteData) {
let options = { classes: ["dialogachat"], width: 400, height: 'fit-content', 'z-index': 99999 };
const actionAchat = venteData.prixLot > 0 ? "Acheter" : "Prendre"; const actionAchat = venteData.prixLot > 0 ? "Acheter" : "Prendre";
const buttons = {}; const buttons = {};
if (venteData.isConsommable) { if (isConsommable) {
buttons["consommer"] = { label: venteData.item.system.boisson ? "Boire" : "Manger", callback: it => this.onAchatConsommer() } buttons["consommer"] = { label: venteData.item.data.boisson ? "Boire" : "Manger", callback: it => { this.onAchatConsommer(); } }
} }
buttons[actionAchat] = { label: actionAchat, callback: it => { this.onAchat(); } }; buttons[actionAchat] = { label: actionAchat, callback: it => { this.onAchat(); } };
buttons["decliner"] = { label: "Décliner", callback: it => { } }; buttons["decliner"] = { label: "Décliner", callback: it => { } };
const acheteur = venteData.acheteur?.name ?? 'Un acheteur';
const vendeur = venteData.vendeur?.name ?? 'Un vendeur';
let conf = { let conf = {
title: `${acheteur} - ${actionAchat} à ${vendeur}`, title: venteData.acheteur? venteData.acheteur.name + " - " + actionAchat : actionAchat,
content: html, content: html,
default: actionAchat, default: actionAchat,
buttons: buttons buttons: buttons
}; };
super(conf, options); super(conf, options);
this.vendeur = vendeur;
this.acheteur = acheteur;
this.chatMessageIdVente = chatMessageIdVente;
this.venteData = venteData; this.venteData = venteData;
} }
async onAchat() { static prepareVenteData(buttonAcheter, vendeurId, vendeur, acheteur) {
await this.html.find(".nombreLots").change(); const jsondata = buttonAcheter.attributes['data-jsondata']?.value;
(this.venteData.vendeur ?? this.venteData.acheteur).achatVente({ const prixLot = parseInt(buttonAcheter.attributes['data-prixLot']?.value ?? 0);
userId: game.user.id, let venteData = {
vendeurId: this.venteData.vendeur?.id, item: JSON.parse(jsondata),
acheteurId: this.venteData.acheteur?.id, vendeurId: vendeurId,
prixTotal: this.venteData.prixTotal, vendeur: Misc.data(vendeur),
chatMessageIdVente: this.venteData.chatMessageIdVente, acheteur: Misc.data(acheteur),
choix: this.venteData.choix, tailleLot: parseInt(buttonAcheter.attributes['data-tailleLot']?.value ?? 1),
vente: this.venteData quantiteIllimite: buttonAcheter.attributes['data-quantiteIllimite']?.value == 'true',
}); quantiteNbLots: parseInt(buttonAcheter.attributes['data-quantiteNbLots']?.value),
choix: {
nombreLots: 1,
seForcer: false,
supprimerSiZero: true
},
prixLot: prixLot,
prixTotal: prixLot,
isVente: prixLot > 0
};
return venteData;
} }
async onAchat() {
await $(".nombreLots").change();
(this.vendeur ?? this.acheteur).achatVente({
userId: game.user.id,
vendeurId: this.vendeur?.id,
acheteurId: this.acheteur?.id,
prixTotal: this.venteData.prixTotal,
chatMessageIdVente: this.chatMessageIdVente,
choix: this.venteData.choix
});
}
async onAchatConsommer() { async onAchatConsommer() {
this.venteData.choix.consommer = true; this.venteData.choix.consommer = true;
await this.onAchat(); await this.onAchat();
@ -108,9 +96,9 @@ export class DialogItemAchat extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
this.html = html;
this.html.find(".nombreLots").change(event => this.setNombreLots(Number(event.currentTarget.value))); html.find(".nombreLots").change(event => this.setNombreLots(Number(event.currentTarget.value)));
this.html.find(".se-forcer").change(event => this.setSeForcer(event)); html.find(".se-forcer").change(event => this.setSeForcer(event));
} }
setSeForcer(event) { setSeForcer(event) {
@ -118,21 +106,9 @@ export class DialogItemAchat extends Dialog {
} }
setNombreLots(nombreLots) { setNombreLots(nombreLots) {
this.venteData.choix.nombreLots = nombreLots;
if (!this.venteData.quantiteIllimite) { this.venteData.prixTotal = (nombreLots * this.venteData.prixLot).toFixed(2);
if (!this.venteData.quantiteIllimite && nombreLots > this.venteData.quantiteNbLots) { $(".prixTotal").text(this.venteData.prixTotal);
ui.notifications.warn(`Seulement ${this.venteData.quantiteNbLots} lots disponibles, vous ne pouvez pas en prendre ${nombreLots}`)
}
nombreLots = Math.min(nombreLots, this.venteData.quantiteNbLots);
}
DialogItemAchat.changeNombreLots(this.venteData, nombreLots);
this.html.find(".nombreLots").val(nombreLots);
this.html.find(".prixTotal").text(this.venteData.prixTotal);
this.html.find("span.total-sust").text(this.venteData.totalSust);
this.html.find("span.total-desaltere").text(this.venteData.totalDesaltere);
} }
} }

View File

@ -2,14 +2,14 @@ import { Misc } from "./misc.js";
export class DialogConsommer extends Dialog { export class DialogConsommer extends Dialog {
static async create(actor, item, onActionItem = async () => { }) { static async create(actor, item, onActionItem = async ()=>{}) {
const consommerData = DialogConsommer.prepareData(actor, item); const consommerData = DialogConsommer.prepareData(actor, item);
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-item-consommer.html', consommerData); const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-item-consommer.html', consommerData);
return new DialogConsommer(actor, item, consommerData, html, onActionItem) return new DialogConsommer(actor, item, consommerData, html, onActionItem)
} }
constructor(actor, item, consommerData, html, onActionItem = async () => { }) { constructor(actor, item, consommerData, html, onActionItem = async ()=>{}) {
const options = { classes: ["dialogconsommer"], width: 350, height: 'fit-content', 'z-index': 99999 }; const options = { classes: ["dialogconsommer"], width: 350, height: 450, 'z-index': 99999 };
let conf = { let conf = {
title: consommerData.title, title: consommerData.title,
content: html, content: html,
@ -17,9 +17,8 @@ export class DialogConsommer extends Dialog {
buttons: { buttons: {
[consommerData.buttonName]: { [consommerData.buttonName]: {
label: consommerData.buttonName, callback: async it => { label: consommerData.buttonName, callback: async it => {
await this.onConsommer(); await this.onConsommer(it);
await onActionItem(); await onActionItem();}
}
} }
} }
}; };
@ -31,71 +30,51 @@ export class DialogConsommer extends Dialog {
this.consommerData = consommerData; this.consommerData = consommerData;
} }
activateListeners(html) { async onConsommer(event) {
super.activateListeners(html); await $(".se-forcer").change();
this.html = html; await $(".consommer-doses").change();
this.html.find(".se-forcer").change(event => this.setSeForcer(event));
this.html.find(".consommer-doses").change(event => this.selectDoses(event));
}
async onConsommer() {
await this.html.find(".se-forcer").change();
await this.html.find(".consommer-doses").change();
await this.actor.consommer(this.item, this.consommerData.choix); await this.actor.consommer(this.item, this.consommerData.choix);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static prepareData(actor, item) { static prepareData(actor, item) {
const itemData = duplicate(Misc.data(item));
let consommerData = { let consommerData = {
item: duplicate(item), item: itemData,
cuisine: actor.getCompetence('cuisine'), cuisine: Misc.data(actor.getCompetence('cuisine')),
choix: { choix: {
doses: 1, doses: 1,
seForcer: false, seForcer: false,
} }
} }
switch (item.type) { switch (itemData.type) {
case 'herbe': case 'faune':
consommerData.title = 'Manger une portion crue: ';
consommerData.buttonName = "Manger";
break;
case 'nourritureboisson': case 'nourritureboisson':
consommerData.title = item.system.boisson ? 'Boire une dose: ' : 'Manger une portion: '; consommerData.title = itemData.data.boisson ? `${itemData.name}: boire une dose` : `${itemData.name}: manger une portion`;
consommerData.buttonName = item.system.boisson ? "Boire" : "Manger"; consommerData.buttonName = itemData.data.boisson ? "Boire" : "Manger";
break; break;
case 'potion': case 'potion':
consommerData.title = 'Boire la potion: '; consommerData.title = `${itemData.name}: boire la potion`;
consommerData.buttonName = "Boire"; consommerData.buttonName = "Boire";
break; break;
} }
consommerData.title += item.name; DialogConsommer.calculDoses(consommerData, consommerData.choix.doses)
DialogConsommer.calculDoses(consommerData, item)
return consommerData; return consommerData;
} }
static calculDoses(consommer, item) { static calculDoses(consommerData) {
const doses = consommer.choix.doses; const doses = consommerData.choix.doses;
switch (item.type) { consommerData.totalSust = Misc.keepDecimals(doses * (consommerData.item.data.sust ?? 0), 2);
case 'herbe': case 'faune': consommerData.totalDesaltere = consommerData.item.data.boisson
consommer.totalSust = doses; ? Misc.keepDecimals(doses * (consommerData.item.data.desaltere ?? 0), 2)
consommer.totalDesaltere = 0; : 0;
consommer.choix.sust = 1; }
consommer.choix.quantite = 0;
consommer.choix.encombrement = Misc.keepDecimals(consommer.item.system.encombrement / item.system.sust, 2);
return; /* -------------------------------------------- */
case 'nourritureboisson': activateListeners(html) {
consommer.choix.sust = consommer.item.system.sust; super.activateListeners(html);
consommer.choix.quantite = doses; html.find(".se-forcer").change(event => this.setSeForcer(event));
consommer.choix.encombrement = 0 html.find(".consommer-doses").change(event => this.selectDoses(event));
consommer.totalSust = Misc.keepDecimals(doses * (consommer.item.system.sust ?? 0), 2);
consommer.totalDesaltere = consommer.item.system.boisson
? Misc.keepDecimals(doses * (consommer.item.system.desaltere ?? 0), 2)
: 0;
break;
case 'potion':
consommer.totalSust = 0
consommer.totalDesaltere = 0
}
} }
@ -105,8 +84,8 @@ export class DialogConsommer extends Dialog {
selectDoses(event) { selectDoses(event) {
this.consommerData.choix.doses = Number(event.currentTarget.value); this.consommerData.choix.doses = Number(event.currentTarget.value);
DialogConsommer.calculDoses(this.consommerData, this.item); DialogConsommer.calculDoses(this.consommerData);
this.html.find(".total-sust").text(this.consommerData.totalSust); $(".total-sust").text(this.consommerData.totalSust);
this.html.find(".total-desaltere").text(this.consommerData.totalDesaltere); $(".total-desaltere").text(this.consommerData.totalDesaltere);
} }
} }

View File

@ -1,30 +1,31 @@
import { HtmlUtility } from "./html-utility.js"; import { HtmlUtility } from "./html-utility.js";
import { Misc } from "./misc.js";
export class DialogItemVente extends Dialog { export class DialogItemVente extends Dialog {
static async display({ item, callback, quantiteMax = undefined }) { static async create(item, callback) {
const quantite = quantiteMax ?? item.getQuantite() ?? 1; const itemData = Misc.data(item);
const isOwned = item.parent; const quantite = item.isConteneur() ? 1 : itemData.data.quantite;
const venteData = { const venteData = {
item: item, item: itemData,
alias: item.actor?.name ?? game.user.name, alias: item.actor?.name ?? game.user.name,
vendeurId: item.actor?.id , vendeurId: item.actor?.id,
prixOrigine: item.calculerPrixCommercant(), prixOrigine: itemData.data.cout,
prixUnitaire: item.calculerPrixCommercant(), prixUnitaire: itemData.data.cout,
prixLot: item.calculerPrixCommercant(), prixLot: itemData.data.cout,
tailleLot: 1, tailleLot: 1,
quantiteNbLots: quantite, quantiteNbLots: quantite,
quantiteMaxLots: quantite, quantiteMaxLots: quantite,
quantiteMax: quantite, quantiteMax: quantite ,
quantiteIllimite: item.isItemCommerce() ? quantiteMax == undefined : !isOwned, quantiteIllimite: !item.isOwned,
isOwned: isOwned, isOwned: item.isOwned,
}; };
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-vente.html`, venteData); const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-vente.html`, venteData);
return new DialogItemVente(venteData, html, callback).render(true); return new DialogItemVente(venteData, html, callback);
} }
constructor(venteData, html, callback) { constructor(venteData, html, callback) {
let options = { classes: ["dialogvente"], width: 400, height: 'fit-content', 'z-index': 99999 }; let options = { classes: ["dialogvente"], width: 400, height: 300, 'z-index': 99999 };
let conf = { let conf = {
title: "Proposer", title: "Proposer",
@ -38,25 +39,26 @@ export class DialogItemVente extends Dialog {
this.venteData = venteData; this.venteData = venteData;
} }
activateListeners(html) {
super.activateListeners(html);
this.html = html;
this.setQuantiteIllimite(this.venteData.quantiteIllimite);
this.html.find(".tailleLot").change(event => this.setTailleLot(Number(event.currentTarget.value)));
this.html.find(".quantiteNbLots").change(event => this.setNbLots(Number(event.currentTarget.value)));
this.html.find(".quantiteIllimite").change(event => this.setQuantiteIllimite(event.currentTarget.checked));
this.html.find(".prixLot").change(event => this.setPrixLot(Number(event.currentTarget.value)));
}
async onProposer(it) { async onProposer(it) {
await this.html.find(".tailleLot").change(); await $(".tailleLot").change();
await this.html.find(".quantiteNbLots").change(); await $(".quantiteNbLots").change();
await this.html.find(".quantiteIllimite").change(); await $(".quantiteIllimite").change();
await this.html.find(".prixLot").change(); await $(".prixLot").change();
this.callback(this.venteData); this.callback(this.venteData);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
HtmlUtility._showControlWhen($(".quantiteNbLots"), !this.venteData.quantiteIllimite)
html.find(".tailleLot").change(event => this.setTailleLot(Number(event.currentTarget.value)));
html.find(".quantiteNbLots").change(event => this.setNbLots(Number(event.currentTarget.value)));
html.find(".quantiteIllimite").change(event => this.setQuantiteIllimite(event.currentTarget.checked));
html.find(".prixLot").change(event => this.setPrixLot(Number(event.currentTarget.value)));
}
setPrixLot(prixLot) { setPrixLot(prixLot) {
this.venteData.prixLot = prixLot; this.venteData.prixLot = prixLot;
} }
@ -65,14 +67,16 @@ export class DialogItemVente extends Dialog {
// recalculer le prix du lot // recalculer le prix du lot
if (tailleLot != this.venteData.tailleLot) { if (tailleLot != this.venteData.tailleLot) {
this.venteData.prixLot = (tailleLot * this.venteData.prixOrigine).toFixed(2); this.venteData.prixLot = (tailleLot * this.venteData.prixOrigine).toFixed(2);
this.html.find(".prixLot").val(this.venteData.prixLot); $(".prixLot").val(this.venteData.prixLot);
} }
this.venteData.tailleLot = tailleLot; this.venteData.tailleLot = tailleLot;
// recalculer le nombre de lots max if (this.venteData.isOwned) {
this.venteData.quantiteMaxLots = Math.floor(this.venteData.quantiteMax / tailleLot); // recalculer le nombre de lots max
this.venteData.quantiteNbLots = Math.min(this.venteData.quantiteMaxLots, this.venteData.quantiteNbLots); this.venteData.quantiteMaxLots = Math.floor(this.venteData.quantiteMax / tailleLot);
this.html.find(".quantiteNbLots").val(this.venteData.quantiteNbLots); this.venteData.quantiteNbLots = Math.min(this.venteData.quantiteMaxLots, this.venteData.quantiteNbLots);
this.html.find(".quantiteNbLots").attr("max", this.venteData.quantiteMaxLots) $(".quantiteNbLots").val(this.venteData.quantiteNbLots);
$(".quantiteNbLots").attr("max", this.venteData.quantiteMaxLots)
}
} }
setNbLots(nbLots) { setNbLots(nbLots) {
@ -80,12 +84,12 @@ export class DialogItemVente extends Dialog {
nbLots = Math.max(0, Math.min(nbLots, this.venteData.quantiteMaxLots)); nbLots = Math.max(0, Math.min(nbLots, this.venteData.quantiteMaxLots));
} }
this.venteData.quantiteNbLots = nbLots; this.venteData.quantiteNbLots = nbLots;
this.html.find(".quantiteNbLots").val(this.venteData.quantiteNbLots); $(".quantiteNbLots").val(this.venteData.quantiteNbLots);
} }
setQuantiteIllimite(checked) { setQuantiteIllimite(checked) {
this.venteData.quantiteIllimite = checked; this.venteData.quantiteIllimite = checked;
this.html.find(".label-quantiteIllimite").text(this.venteData.quantiteIllimite ? "Illimités" : "disponibles"); $(".label-quantiteIllimite").text(this.venteData.quantiteIllimite ? "Illimités" : "disponibles");
HtmlUtility._showControlWhen(this.html.find(".quantiteNbLots"), !this.venteData.quantiteIllimite) HtmlUtility._showControlWhen($(".quantiteNbLots"), !this.venteData.quantiteIllimite)
} }
} }

View File

@ -1,14 +1,15 @@
import { Misc } from "./misc.js";
export class DialogRepos extends Dialog { export class DialogRepos extends Dialog {
static async create(actor) { static async create(actor) {
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-repos.html", actor); let actorData = Misc.data(actor)
const dialog = new DialogRepos(html, actor); const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-repos.html", actorData);
dialog.render(true); new DialogRepos(html, actor).render(true);
} }
constructor(html, actor) { constructor(html, actor) {
let options = { classes: ["DialogCreateSigneDraconiqueActorsActors"], width: 400, height: 'fit-content', 'z-index': 99999 }; let options = { classes: ["DialogCreateSigneDraconiqueActorsActors"], width: 500, height: 400, 'z-index': 99999 };
let conf = { let conf = {
title: "Se reposer", title: "Se reposer",
content: html, content: html,
@ -20,19 +21,13 @@ export class DialogRepos extends Dialog {
super(conf, options); super(conf, options);
this.actor = actor; this.actor = actor;
} }
activateListeners(html) {
super.activateListeners(html);
this.html = html;
}
/* -------------------------------------------- */
async repos() { async repos() {
await this.html.find("[name='nb-heures']").change(); await $("[name='nb-heures']").change();
await this.html.find("[name='nb-jours']").change(); await $("[name='nb-jours']").change();
const selection = await this.html.find("[name='repos']:checked").val(); const selection = await $("[name='repos']:checked").val();
const nbHeures = Number.parseInt(await this.html.find("[name='nb-heures']").val()); const nbHeures = Number.parseInt(await $("[name='nb-heures']").val());
const nbJours = Number.parseInt(await this.html.find("[name='nb-jours']").val()); const nbJours = Number.parseInt(await $("[name='nb-jours']").val());
console.log("ACTOR", this.actor)
switch (selection) { switch (selection) {
case "sieste": { case "sieste": {
await this.actor.dormir(nbHeures); await this.actor.dormir(nbHeures);
@ -40,7 +35,7 @@ export class DialogRepos extends Dialog {
} }
case "nuit": { case "nuit": {
let heuresDormies = await this.actor.dormir(nbHeures); let heuresDormies = await this.actor.dormir(nbHeures);
if (heuresDormies == nbHeures) { if (heuresDormies == nbHeures){
await this.actor.dormirChateauDormant(); await this.actor.dormirChateauDormant();
} }
return; return;
@ -54,4 +49,8 @@ export class DialogRepos extends Dialog {
} }
} }
} }
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
}
} }

View File

@ -1,37 +0,0 @@
export class DialogSelectTarget extends Dialog {
constructor(html, onSelectTarget, targets) {
const options = {
classes: ["rdd-dialog-select-target"],
width: 'fit-content',
height: 'fit-content',
'max-height': 600,
'z-index': 99999
};
const conf = {
title: "Choisir une cible",
content: html,
buttons: {}
};
super(conf, options);
this.onSelectTarget = onSelectTarget;
this.targets = targets;
}
activateListeners(html) {
super.activateListeners(html);
this.html = html;
this.html.find("li.select-target").click((event) => {
this.targetSelected(this.html.find(event.currentTarget)?.data("token-id"));
});
}
targetSelected(tokenId) {
const target = this.targets.find(it => it.id == tokenId);
this.close();
if (target) {
this.onSelectTarget(target);
}
}
}

View File

@ -3,43 +3,50 @@ import { Misc } from "./misc.js";
export class DialogSplitItem extends Dialog { export class DialogSplitItem extends Dialog {
static async create(item, callback) { static async create(item, callback) {
const itemData = Misc.data(item);
const splitData = { const splitData = {
item: item, item: itemData,
choix: { quantite: 1, max: item.system.quantite - 1 } choix: { quantite: 1, max: itemData.data.quantite - 1 }
}; };
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-split.html`, splitData); const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-split.html`, splitData);
return new DialogSplitItem(item, splitData, html, callback) return new DialogSplitItem(item, splitData, html, callback)
} }
constructor(item, splitData, html, callback) { constructor(item, splitData, html, callback) {
let options = { classes: ["dialogsplit"], width: 300, height: 'fit-content', 'z-index': 99999 }; let options = { classes: ["dialogsplit"], width: 300, height: 160, 'z-index': 99999 };
let conf = { let conf = {
title: "Séparer en deux", title: "Séparer en deux",
content: html, content: html,
default: "separer", default: "separer",
buttons: { buttons: {
"separer": { label: "Séparer", callback: it => this.onSplit() } "separer": {
label: "Séparer", callback: it => {
this.onSplit();
}
}
} }
}; };
super(conf, options); super(conf, options);
this.callback = callback; this.callback = callback;
this.item = item; this.item = item;
this.splitData = splitData; this.splitData = splitData;
} }
async onSplit(){
await $(".choix-quantite").change();
this.callback(this.item, this.splitData.choix.quantite);
}
/* -------------------------------------------- */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
this.html = html;
this.html.find(".choix-quantite").change(event => { html.find(".choix-quantite").change(event => {
this.splitData.choix.quantite = Number(event.currentTarget.value); this.splitData.choix.quantite = Number(event.currentTarget.value);
}); });
} }
/* -------------------------------------------- */
async onSplit() {
await this.html.find(".choix-quantite").change();
this.callback(this.item, this.splitData.choix.quantite);
}
} }

View File

@ -1,18 +1,18 @@
import { Misc } from "./misc.js";
export class DialogStress extends Dialog { export class DialogStress extends Dialog {
static async distribuerStress() { static async distribuerStress() {
const dialogData = { let dialogData = {
motif: "Motif", motif: "Motif",
stress: 10, stress: 10,
immediat: false, immediat: false,
actors: game.actors.filter(actor => actor.hasPlayerOwner && actor.isPersonnage()) actors: game.actors.filter(actor => actor.hasPlayerOwner && actor.isPersonnage())
.map(actor => ({ .map(actor => {
id: actor.id, let actorData = duplicate(Misc.data(actor));
name: actor.name, actorData.selected = actor.hasPlayerOwner;
selected: true return actorData;
}) })
)
}; };
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-stress.html", dialogData); const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-stress.html", dialogData);
@ -21,43 +21,52 @@ export class DialogStress extends Dialog {
} }
constructor(dialogData, html) { constructor(dialogData, html) {
const options = { classes: ["DialogStress"], let options = { classes: ["DialogStress"], width: 400, height: 320, 'z-index': 99999 };
width: 400, let conf = {
height: 'fit-content',
'z-index': 99999
};
const conf = {
title: "Donner du stress", title: "Donner du stress",
content: html, content: html,
buttons: { buttons: {
stress: { label: "Stress !", callback: it => { this.onStress(); } } "Stress": { label: "Stress !", callback: it => { this._onStress(); } }
} }
}; };
super(conf, options); super(conf, options);
this.dialogData = dialogData; this.dialogData = dialogData;
} }
activateListeners(html) { async _onStress() {
super.activateListeners(html); this.validerStress();
this.html = html; const compteur = this.dialogData.immediat ? 'experience' : 'stress';
this.html.find("input.select-actor").change((event) => this.onSelectActor(event)); const stress = this.dialogData.stress;
} const motif = this.dialogData.motif;
async onStress() {
const motif = this.html.find("form.rdddialogstress input[name='motif']").val();
const stress = Number(this.html.find("form.rdddialogstress input[name='stress']").val());
const compteur = (this.html.find("form.rdddialogstress input[name='immediat']").prop("checked")) ? 'experience' : 'stress';
this.dialogData.actors.filter(it => it.selected) this.dialogData.actors.filter(it => it.selected)
.map(it => game.actors.get(it.id)) .map(it => game.actors.get(it._id))
.forEach(actor => actor.distribuerStress(compteur, stress, motif)); .forEach(actor => actor.distribuerStress(compteur, stress, motif));
} }
async onSelectActor(event) {
const actorId = this.html.find(event.currentTarget)?.data("actor-id"); validerStress() {
const actor = this.dialogData.actors.find(it => it.id == actorId); this.dialogData.motif = $("form.rdddialogstress input[name='motif']").val();
if (actor) { this.dialogData.stress = $("form.rdddialogstress input[name='stress']").val();
actor.selected = event.currentTarget.checked; this.dialogData.immediat = $("form.rdddialogstress input[name='immediat']").prop("checked");;
}
} }
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
html.find(".select-actor").change((event) => this.onSelectActor(event));
}
async onSelectActor(event) {
event.preventDefault();
const options = event.currentTarget.options;
for (var i = 0; i < options.length; i++) { // looping over the options
const actorId = options[i].attributes["data-actor-id"].value;
const actor = this.dialogData.actors.find(it => it._id == actorId);
if (actor) {
actor.selected = options[i].selected;
}
};
}
} }

View File

@ -1,71 +0,0 @@
import { HIDE_DICE, SHOW_DICE } from "./constants.js";
import { RdDUtility } from "./rdd-utility.js";
/**
* Extend the base Dialog entity by defining a custom window to perform roll.
* @extends {Dialog}
*/
export class DialogValidationEncaissement extends Dialog {
static async validerEncaissement(actor, rollData, armure, show, onEncaisser) {
let encaissement = await RdDUtility.jetEncaissement(rollData, armure, { showDice: HIDE_DICE });
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-validation-encaissement.html', {
actor: actor,
rollData: rollData,
encaissement: encaissement,
show: show
});
const dialog = new DialogValidationEncaissement(html, actor, rollData, armure, encaissement, show, onEncaisser);
dialog.render(true);
}
/* -------------------------------------------- */
constructor(html, actor, rollData, armure, encaissement, show, onEncaisser) {
// Common conf
let buttons = {
"valider": { label: "Valider", callback: html => this.validerEncaissement() },
"annuler": { label: "Annuler", callback: html => { } },
};
let dialogConf = {
title: "Validation d'encaissement",
content: html,
buttons: buttons,
default: "valider"
}
let dialogOptions = {
classes: ["rdd-roll-dialog"],
width: 350,
height: 290
}
// Select proper roll dialog template and stuff
super(dialogConf, dialogOptions);
this.actor = actor
this.rollData = rollData;
this.armure = armure;
this.encaissement = encaissement;
this.show = show;
this.onEncaisser = onEncaisser;
this.forceDiceResult = {total: encaissement.roll.result };
}
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
this.html = html;
this.html.find('input.encaissement-roll-result').keyup(async event => {
this.forceDiceResult.total = event.currentTarget.value;
this.encaissement = await RdDUtility.jetEncaissement(this.rollData, this.armure, { showDice: HIDE_DICE, forceDiceResult: this.forceDiceResult});
this.html.find('label.encaissement-total').text(this.encaissement.total);
this.html.find('label.encaissement-blessure').text(this.encaissement.blessures)
});
}
async validerEncaissement() {
this.encaissement = await RdDUtility.jetEncaissement(this.rollData, this.armure, { showDice: SHOW_DICE, forceDiceResult: this.forceDiceResult});
this.onEncaisser(this.encaissement, this.show)
}
}

View File

@ -1,137 +0,0 @@
import { ChatUtility } from "./chat-utility.js";
import { Poetique } from "./poetique.js";
import { RdDDice } from "./rdd-dice.js";
import { TMRUtility } from "./tmr-utility.js";
export class EffetsRencontre {
static messager = async (dialog, context) => {
dialog.setRencontreState('messager', TMRUtility.getTMRPortee(context.tmr.coord, context.rencontre.system.force));
}
static passeur = async (dialog, context) => {
dialog.setRencontreState('passeur', TMRUtility.getTMRPortee(context.tmr.coord, context.rencontre.system.force));
}
static teleportation_typecase = async (dialog, context) => {
dialog.setRencontreState('changeur', TMRUtility.getCasesType(context.tmr.type));
}
static rencontre_persistante = async (dialog, context) => {
dialog.setRencontreState('persistant', []);
}
static reve_plus_force = async (dialog, context) => { await EffetsRencontre.$reve_plus(context.actor, context.rencontre.system.force) }
static reve_plus_1 = async (dialog, context) => { await EffetsRencontre.$reve_plus(context.actor, 1) }
static reve_moins_force = async (dialog, context) => { await EffetsRencontre.$reve_plus(context.actor, -context.rencontre.system.force) }
static reve_moins_1 = async (dialog, context) => { await EffetsRencontre.$reve_plus(context.actor, -1) }
static $reve_plus = async (actor, valeur) => { await actor.reveActuelIncDec(valeur) }
static vie_moins_1 = async (dialog, context) => { await EffetsRencontre.$vie_plus(context.actor, -1) }
static vie_moins_force = async (dialog, context) => { await EffetsRencontre.$vie_plus(context.actor, -context.rencontre.system.force) }
static $vie_plus = async (actor, valeur) => { await actor.santeIncDec("vie", valeur) }
static moral_plus_1 = async (dialog, context) => { await EffetsRencontre.$vie_plus(context.actor, 1) }
static moral_moins_1 = async (dialog, context) => { await EffetsRencontre.$vie_plus(context.actor, -1) }
static $moral_plus = async (actor, valeur) => { await actor.moralIncDec(valeur) }
static end_moins_1 = async (dialog, context) => { await EffetsRencontre.$vie_plus(context.actor, -1) }
static end_moins_force = async (dialog, context) => { await EffetsRencontre.$vie_plus(context.actor, -context.rencontre.system.force) }
static $end_plus = async (actor, valeur) => { await actor.santeIncDec("endurance", valeur) }
static fatigue_plus_1 = async (dialog, context) => { await EffetsRencontre.$fatigue_plus(context.actor, 1) }
static fatigue_plus_force = async (dialog, context) => { await EffetsRencontre.$fatigue_plus(context.actor, context.rencontre.system.force) }
static fatigue_moins_1 = async (dialog, context) => { await EffetsRencontre.$fatigue_plus(context.actor, -1) }
static fatigue_moins_force = async (dialog, context) => { await EffetsRencontre.$fatigue_plus(context.actor, -context.rencontre.system.force) }
static $fatigue_plus = async (actor, valeur) => { await actor.santeIncDec("fatigue", valeur) }
static perte_chance = async (dialog, context) => {
const perte = context.rolled.isETotal ? context.rencontre.system.force : 1;
await context.actor.chanceActuelleIncDec("fatigue", -perte);
}
static xp_sort_force = async (dialog, context) => {
let competence = context.competence;
if (competence) {
const xpSort = Misc.toInt(competence.system.xp_sort) + context.rencontre.system.force;
await this.updateEmbeddedDocuments("Item", [{ _id: compData._id, 'system.xp_sort': xpSort }]);
await this.updateExperienceLog("XP Sort", xpSort, `Rencontre d'un ${context.rencontre.name} en TMR`);
}
}
static stress_plus_1 = async (dialog, context) => {
await context.actor.addCompteurValue('stress', 1, `Rencontre d'un ${context.rencontre.name} en TMR`);
}
static reinsertion = async (dialog, context) => {
await EffetsRencontre.$reinsertion(dialog, context.actor, it => true)
}
static teleportation_aleatoire_typecase = async (dialog, context) => {
await EffetsRencontre.$reinsertion(dialog, context.actor, it => it.type == context.tmr.type && it.coord != context.tmr.coord)
}
static demireve_rompu = async (dialog, context) => {
dialog.close()
}
static sort_aleatoire = async (dialog, context) => {
context.sortReserve = await RdDDice.rollOneOf(context.actor.itemTypes['sortreserve']);
if (context.sortReserve) {
context.newTMR = TMRUtility.getTMR(context.sortReserve.system.coord);
await dialog.positionnerDemiReve(context.newTMR.coord);
await dialog.processSortReserve(context.sortReserve);
dialog.close();
}
else {
await EffetsRencontre.$reinsertion(dialog, context.actor, it => true);
}
}
static deplacement_aleatoire = async (dialog, context) => {
const oldCoord = context.actor.system.reve.tmrpos.coord;
const newTmr = await TMRUtility.deplaceTMRAleatoire(context.actor, oldCoord);
await dialog.positionnerDemiReve(newTmr.coord)
}
static rdd_part_tete = async (dialog, context) => {
mergeObject(context, {
tete: context.rolled.isPart,
poesie: await Poetique.getExtrait()
})
ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(context.actor.name),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-reve-de-dragon.html`, context)
});
}
static rdd_echec_queue = async (dialog, context) => {
mergeObject(context, {
queues: [await context.actor.ajouterQueue()],
poesie: await Poetique.getExtrait()
})
if (context.rolled.isETotal) {
context.queues.push(await context.actor.ajouterQueue());
}
ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-reve-de-dragon.html`, context)
});
}
static experience_particuliere = async (dialog, context) => {
await context.actor.appliquerAjoutExperience(context)
}
static regain_seuil = async (dialog, context) => {
await context.actor.regainPointDeSeuil()
}
static async $reinsertion(dialog, actor, filter) {
const newTMR = await TMRUtility.getTMRAleatoire(filter);
await actor.forcerPositionTMRInconnue(newTMR);
await dialog.positionnerDemiReve(newTMR.coord);
}
}

View File

@ -1,223 +0,0 @@
import { SYSTEM_RDD } from "./constants.js";
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
import { CompendiumTableHelpers, CompendiumTable } from "./settings/system-compendiums.js";
const RARETES = [
{ name: 'Commune', frequence: 54, min: 27, max: 108 },
{ name: 'Frequente', frequence: 18, min: 9, max: 36 },
{ name: 'Rare', frequence: 6, min: 3, max: 12 },
{ name: 'Rarissime', frequence: 2, min: 1, max: 4 }]
const DEFAULT_RARETE = 1;
const SETTINGS_LISTE_MILIEUX = "liste-milieux";
const MILIEUX = [
"Collines",
"Cours d'eau",
"Déserts",
"Forêts",
"Marais",
"Maritimes",
"Montagnes",
"Plaines",
"Sous-sols"
]
const ITEM_ENVIRONNEMENT_TYPES = [
'herbe', 'ingredient', 'faune'
]
export class Environnement {
static init() {
game.settings.register(SYSTEM_RDD, SETTINGS_LISTE_MILIEUX, {
name: "Liste des milieux proposés",
hint: "Liste des milieux proposés pour la faune&flore, séparés par des virgules",
scope: "world",
config: true,
default: MILIEUX.reduce(Misc.joining(',')),
type: String
});
game.system.rdd.environnement = new Environnement();
}
constructor() {
this.table = new CompendiumTable('faune-flore-mineraux', 'Item', ITEM_ENVIRONNEMENT_TYPES)
}
static getRarete(name = undefined) {
return RARETES.find(it => it.name == name) ?? RARETES[DEFAULT_RARETE];
}
static getFrequenceRarete(rarete, field = undefined) {
const selected = this.getRarete(rarete);
return selected[field];
}
async milieux() {
return Object.values(await this.mapMilieux());
}
async mapMilieux() {
const compendiumItems = await this.getElements(it => 1, it => ITEM_ENVIRONNEMENT_TYPES.includes(it.type));
return Misc.indexLowercase(this.getMilieuxSettings().concat(Environnement.listMilieux(compendiumItems)));
}
static listMilieux(items) {
return Misc.concat(items.map(it => Environnement.$itemToMilieux(it).filter(m => m)));
}
async autresMilieux(item) {
const mapMilieux = await this.mapMilieux();
const milieuxExistants = Environnement.$itemToMilieux(item).map(it => Grammar.toLowerCaseNoAccent(it));
return Object.keys(mapMilieux)
.filter(it => !milieuxExistants.includes(it))
.map(it => mapMilieux[it]);
}
static $itemToMilieux(item) {
return item.system.environnement.map(env => env.milieu);
}
getMilieuxSettings() {
return game.settings.get(SYSTEM_RDD, SETTINGS_LISTE_MILIEUX).split(',').map(it => it.trim()).filter(it => it != '');
}
async findEnvironnementsLike(search) {
const milieux = await this.mapMilieux();
const searchLower = Grammar.toLowerCaseNoAccent(search);
const keys = Object.keys(milieux).filter(it => it.includes(searchLower));
if (keys.length > 1) {
const milieuExact = milieux[searchLower];
if (milieuExact) {
return [milieuExact];
}
}
return keys.map(k => milieux[k]);
}
async searchToChatMessage(milieux, typeName) {
const table = await this.buildEnvironnementTable(milieux);
await CompendiumTableHelpers.tableToChatMessage(table, 'Item', ITEM_ENVIRONNEMENT_TYPES, typeName);
return true
}
async getRandom(milieux, typeName) {
const table = await this.buildEnvironnementTable(milieux);
return await CompendiumTableHelpers.getRandom(table, 'Item', ITEM_ENVIRONNEMENT_TYPES, undefined, typeName);
}
async buildEnvironnementTable(milieux) {
const filterMilieux = item => item.system?.environnement.filter(env => milieux.includes(env.milieu));
const itemRareteEnMilieu = item => {
const raretes = filterMilieux(item);
const frequenceMax = Math.max(raretes.map(env => env.frequence));
return raretes.find(env => env.frequence == frequenceMax);
}
const itemFrequenceEnMilieu = item => itemRareteEnMilieu(item)?.frequence ?? 0;
const isPresentEnMilieu = item => itemFrequenceEnMilieu(item) > 0;
return await this.table.buildTable(itemFrequenceEnMilieu, isPresentEnMilieu);
}
async getElements(itemFrequence, filter) {
return await this.table.getContent(itemFrequence, filter);
}
}
export class EnvironmentSheetHelper {
static defaultOptions(defaultOptions) {
return mergeObject(defaultOptions, {
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "informations" }]
});
}
static setPosition(sheet, superPosition) {
const position = superPosition;
const sheetHeader = sheet.element.find(".sheet-header");
const sheetBody = sheet.element.find(".sheet-body");
sheetBody.css("height", position.height - sheetHeader[0].clientHeight)
return position;
}
/* -------------------------------------------- */
static async getData(sheet, formData) {
return mergeObject(formData, {
milieux: await game.system.rdd.environnement.autresMilieux(sheet.item)
});
}
static activateListeners(sheet) {
if (!sheet.options.editable) return;
sheet.html.find("input.input-selection-milieu").keypress(event => {
if (event.keyCode == '13') {
EnvironmentSheetHelper.onAddMilieu(sheet, event);
}
event.stopPropagation();
})
sheet.html.find("a.milieu-add").click(event => EnvironmentSheetHelper.onAddMilieu(sheet, event));
sheet.html.find("div.environnement-milieu a.milieu-delete").click(event => EnvironmentSheetHelper.onDeleteMilieu(sheet, event));
sheet.html.find("div.environnement-milieu select.environnement-rarete").change(event => EnvironmentSheetHelper.onChange(sheet, event,
updated => EnvironmentSheetHelper.$changeRarete(sheet, event, updated)));
sheet.html.find("div.environnement-milieu input[name='environnement-frequence']").change(event => EnvironmentSheetHelper.onChange(sheet, event,
updated => EnvironmentSheetHelper.$changeFrequence(sheet, event, updated)));
}
static $changeFrequence(sheet, event, updated) {
updated.frequence = Number(sheet.html.find(event.currentTarget).val());
}
static $changeRarete(sheet, event, updated) {
const name = sheet.html.find(event.currentTarget).val();
const rarete = Environnement.getRarete(name);
updated.rarete = rarete.name;
updated.frequence = rarete.frequence;
// updated.frequence = Math.min(
// Math.max(rarete.min, updated.frequence ?? rarete.frequence),
// rarete.max);
}
static async onAddMilieu(sheet, event) {
const milieu = sheet.html.find('input.input-selection-milieu').val();
if (!milieu) {
ui.notifications.warn(`Choisissez le milieu dans lequel se trouve le/la ${sheet.item.name}`);
return
}
const list = sheet.item.system.environnement;
const exists = list.find(it => it.milieu == milieu);
if (exists) {
ui.notifications.warn(`${sheet.item.name} a déjà une rareté ${exists.rarete} en ${milieu} (fréquence: ${exists.frequence})`);
return
}
const rarete = Environnement.getRarete();
const newList = [...list, { milieu, rarete: rarete.name, frequence: rarete.frequence }].sort(Misc.ascending(it => it.milieu))
await sheet.item.update({ 'system.environnement': newList })
}
static async onDeleteMilieu(sheet, event) {
const milieu = EnvironmentSheetHelper.$getEventMilieu(sheet, event);
if (milieu != undefined) {
const newList = sheet.item.system.environnement.filter(it => it.milieu != milieu)
.sort(Misc.ascending(it => it.milieu));
await sheet.item.update({ 'system.environnement': newList });
}
}
static async onChange(sheet, event, doMutation) {
const list = sheet.item.system.environnement;
const milieu = EnvironmentSheetHelper.$getEventMilieu(sheet, event);
const updated = list.find(it => it.milieu == milieu);
if (updated) {
doMutation(updated);
const newList = [...list.filter(it => it.milieu != milieu), updated]
.sort(Misc.ascending(it => it.milieu));
await sheet.item.update({ 'system.environnement': newList });
}
}
static $getEventMilieu(sheet, event) {
return sheet.html.find(event.currentTarget)?.parents("div.environnement-milieu").data("milieu");
}
}

View File

@ -19,14 +19,10 @@ export class Grammar {
return word.match(/^[aeiouy]/i) return word.match(/^[aeiouy]/i)
} }
static equalsInsensitive(a, b) {
return Grammar.toLowerCaseNoAccent(a) == Grammar.toLowerCaseNoAccent(b)
}
static includesLowerCaseNoAccent(value, content) { static includesLowerCaseNoAccent(value, content) {
return Grammar.toLowerCaseNoAccent(value).includes(Grammar.toLowerCaseNoAccent(content)); return Grammar.toLowerCaseNoAccent(value).includes(Grammar.toLowerCaseNoAccent(content));
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static toLowerCaseNoAccent(words) { static toLowerCaseNoAccent(words) {
return words?.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "") ?? words; return words?.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "") ?? words;

View File

@ -0,0 +1,9 @@
/* -------------------------------------------- */
import { RdDUtility } from "./rdd-utility.js";
/* -------------------------------------------- */
// Activate chat listeners defined
// Hooks.on('renderChatLog', (log, html, data) => {
// RdDUtility.chatListeners(html);
// });

View File

@ -1,10 +1,10 @@
export class HtmlUtility{ export class HtmlUtility{
static _showControlWhen(jQuerySelector, condition) { static _showControlWhen(control, condition) {
if (condition) { if (condition) {
jQuerySelector.show(); control.show();
} }
else { else {
jQuerySelector.hide(); control.hide();
} }
} }
} }

View File

@ -19,34 +19,36 @@ const nomCategorieParade = {
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDItemArme extends Item { export class RdDItemArme extends Item {
static isArme(item) { static isArme(itemData) {
return (item.type == 'competencecreature' && item.system.iscombat) || item.type == 'arme'; itemData = Misc.data(itemData);
return (itemData.type == 'competencecreature' && itemData.data.iscombat) || itemData.type == 'arme';
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static getArme(arme) { static getArmeData(armeData) {
switch (arme ? arme.type : '') { armeData = Misc.data(armeData);
case 'arme': return arme; switch (armeData ? armeData.type : '') {
case 'arme': return armeData;
case 'competencecreature': case 'competencecreature':
return RdDItemCompetenceCreature.armeNaturelle(arme); return RdDItemCompetenceCreature.toActionArme(armeData);
} }
return RdDItemArme.mainsNues(); return RdDItemArme.mainsNues();
} }
static computeNiveauArmes(armes, competences) { static computeNiveauArmes(armes, competences) {
for (const arme of armes) { for (const arme of armes) {
arme.system.niveau = RdDItemArme.niveauCompetenceArme(arme, competences); arme.data.niveau = RdDItemArme.niveauCompetenceArme(arme, competences);
} }
} }
static niveauCompetenceArme(arme, competences) { static niveauCompetenceArme(arme, competences) {
const compArme = competences.find(it => it.name == arme.system.competence); const compArme = competences.find(it => it.name == arme.data.competence);
return compArme?.system.niveau ?? -8; return compArme?.data.niveau ?? -8;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static getNomCategorieParade(arme) { static getNomCategorieParade(arme) {
const categorie = arme?.system ? RdDItemArme.getCategorieParade(arme) : arme; const categorie = arme?.data ? RdDItemArme.getCategorieParade(arme) : arme;
return nomCategorieParade[categorie]; return nomCategorieParade[categorie];
} }
@ -64,20 +66,21 @@ export class RdDItemArme extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
static getCategorieParade(armeData) { static getCategorieParade(armeData) {
if (armeData.system.categorie_parade) { armeData = Misc.data(armeData);
return armeData.system.categorie_parade; if (armeData.data.categorie_parade) {
return armeData.data.categorie_parade;
} }
// pour compatibilité avec des personnages existants // pour compatibilité avec des personnages existants
if (armeData.type == 'competencecreature' || armeData.system.categorie == 'creature') { if (armeData.type == 'competencecreature' || armeData.data.categorie == 'creature') {
return armeData.system.categorie_parade || (armeData.system.isparade ? 'armes-naturelles' : ''); return armeData.data.categorie_parade || (armeData.data.isparade ? 'armes-naturelles' : '');
} }
if (!armeData.type.match(/arme|competencecreature/)) { if (!armeData.type.match(/arme|competencecreature/)) {
return ''; return '';
} }
if (armeData.system.competence == undefined) { if (armeData.data.competence == undefined) {
return 'competencecreature'; return 'competencecreature';
} }
let compname = armeData.system.competence.toLowerCase(); let compname = armeData.data.competence.toLowerCase();
if (compname.match(/^(dague de jet|javelot|fouet|arc|arbalête|fronde|hache de jet|fléau)$/)) return ''; if (compname.match(/^(dague de jet|javelot|fouet|arc|arbalête|fronde|hache de jet|fléau)$/)) return '';
if (compname.match('hache')) return 'haches'; if (compname.match('hache')) return 'haches';
@ -134,21 +137,22 @@ export class RdDItemArme extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
static armeUneOuDeuxMains(armeData, aUneMain) { static armeUneOuDeuxMains(armeData, aUneMain) {
if (armeData && !armeData.system.cac) { armeData = Misc.data(armeData);
armeData.system.unemain = armeData.system.unemain || !armeData.system.deuxmains; if (armeData && !armeData.data.cac) {
const uneOuDeuxMains = armeData.system.unemain && armeData.system.deuxmains; armeData.data.unemain = armeData.data.unemain || !armeData.data.deuxmains;
const containsSlash = !Number.isInteger(armeData.system.dommages) && armeData.system.dommages.includes("/"); const uneOuDeuxMains = armeData.data.unemain && armeData.data.deuxmains;
const containsSlash = !Number.isInteger(armeData.data.dommages) && armeData.data.dommages.includes("/");
if (containsSlash) { // Sanity check if (containsSlash) { // Sanity check
armeData = duplicate(armeData); armeData = duplicate(armeData);
const tableauDegats = armeData.system.dommages.split("/"); const tableauDegats = armeData.data.dommages.split("/");
if (aUneMain) if (aUneMain)
armeData.system.dommagesReels = Number(tableauDegats[0]); armeData.data.dommagesReels = Number(tableauDegats[0]);
else // 2 mains else // 2 mains
armeData.system.dommagesReels = Number(tableauDegats[1]); armeData.data.dommagesReels = Number(tableauDegats[1]);
} }
else { else {
armeData.system.dommagesReels = Number(armeData.system.dommages); armeData.data.dommagesReels = Number(armeData.data.dommages);
} }
if (uneOuDeuxMains != containsSlash) { if (uneOuDeuxMains != containsSlash) {
@ -158,50 +162,51 @@ export class RdDItemArme extends Item {
return armeData; return armeData;
} }
static isArmeUtilisable(arme) { static isArmeUtilisable(itemData) {
return arme.type == 'arme' && arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0); itemData = Misc.data(itemData);
return itemData.type == 'arme' && itemData.data.equipe && (itemData.data.resistance > 0 || itemData.data.portee_courte > 0);
} }
static ajoutCorpsACorps(armes, competences, carac) { static ajoutCorpsACorps(armes, competences, carac) {
let corpsACorps = competences.find(it => it.name == 'Corps à corps') ?? { system: { niveau: -6 } }; let corpsACorps = competences.find(it => it.name == 'Corps à corps') ?? { data: { niveau: -6 } };
let init = RdDCombatManager.calculInitiative(corpsACorps.system.niveau, carac['melee'].value); let init = RdDCombatManager.calculInitiative(corpsACorps.data.niveau, carac['melee'].value);
armes.push(RdDItemArme.mainsNues({ niveau: corpsACorps.system.niveau, initiative: init })); armes.push(RdDItemArme.mainsNues({ niveau: corpsACorps.data.niveau, initiative: init }));
//armes.push(RdDItemArme.empoignade({ niveau: corpsACorps.system.niveau, initiative: init })); //armes.push(RdDItemArme.empoignade({ niveau: corpsACorps.data.niveau, initiative: init }));
} }
static corpsACorps(mainsNuesActor) { static corpsACorps(actorData) {
const corpsACorps = { const corpsACorps = {
name: 'Corps à corps', name: 'Corps à corps',
img: 'systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp', img: 'systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp',
system: { data: {
equipe: true, equipe: true,
rapide: true, rapide: true,
force: 0, force: 0,
dommages: "0", dommages: 0,
dommagesReels: 0, dommagesReels: 0,
mortalite: 'non-mortel', mortalite: 'non-mortel',
competence: 'Corps à corps', competence: 'Corps à corps',
categorie_parade: 'sans-armes' categorie_parade: 'sans-armes'
} }
}; };
mergeObject(corpsACorps.system, mainsNuesActor ?? {}, { overwrite: false }); mergeObject(corpsACorps.data, actorData ?? {}, { overwrite: false });
return corpsACorps; return corpsACorps;
} }
static mainsNues(mainsNuesActor) { static mainsNues(actorData) {
const mainsNues = RdDItemArme.corpsACorps(mainsNuesActor) const mainsNues = RdDItemArme.corpsACorps(actorData);
mainsNues.name = 'Mains nues' mainsNues.name = 'Mains nues';
mainsNues.system.cac = 'pugilat' mainsNues.data.cac = 'pugilat';
mainsNues.system.baseInit = 4 mainsNues.data.baseInit = 4;
return mainsNues; return mainsNues;
} }
static empoignade(mainsNuesActor) { static empoignade(actorData) {
const empoignade = RdDItemArme.corpsACorps(mainsNuesActor) const empoignade = RdDItemArme.corpsACorps(actorData);
empoignade.name = 'Empoignade' empoignade.name = 'Empoignade';
empoignade.system.cac = 'empoignade' empoignade.data.cac = 'empoignade';
empoignade.system.baseInit = 3 empoignade.data.baseInit = 3;
empoignade.system.mortalite = 'empoignade' empoignade.data.mortalite = 'empoignade';
return empoignade return empoignade;
} }
} }

View File

@ -8,18 +8,18 @@ const xp_par_niveau = [5, 5, 5, 10, 10, 10, 10, 15, 15, 15, 15, 20, 20, 20, 20,
const niveau_max = xp_par_niveau.length - 10; const niveau_max = xp_par_niveau.length - 10;
/* -------------------------------------------- */ /* -------------------------------------------- */
const limitesArchetypes = [ const limitesArchetypes = [
{ "niveau": 0, "nombreMax": 100, "reste": 100 }, { "niveau": 0, "nombreMax": 100, "nombre": 0 },
{ "niveau": 1, "nombreMax": 10, "reste": 10 }, { "niveau": 1, "nombreMax": 10, "nombre": 0 },
{ "niveau": 2, "nombreMax": 9, "reste": 9 }, { "niveau": 2, "nombreMax": 9, "nombre": 0 },
{ "niveau": 3, "nombreMax": 8, "reste": 8 }, { "niveau": 3, "nombreMax": 8, "nombre": 0 },
{ "niveau": 4, "nombreMax": 7, "reste": 7 }, { "niveau": 4, "nombreMax": 7, "nombre": 0 },
{ "niveau": 5, "nombreMax": 6, "reste": 6 }, { "niveau": 5, "nombreMax": 6, "nombre": 0 },
{ "niveau": 6, "nombreMax": 5, "reste": 5 }, { "niveau": 6, "nombreMax": 5, "nombre": 0 },
{ "niveau": 7, "nombreMax": 4, "reste": 4 }, { "niveau": 7, "nombreMax": 4, "nombre": 0 },
{ "niveau": 8, "nombreMax": 3, "reste": 3 }, { "niveau": 8, "nombreMax": 3, "nombre": 0 },
{ "niveau": 9, "nombreMax": 2, "reste": 2 }, { "niveau": 9, "nombreMax": 2, "nombre": 0 },
{ "niveau": 10, "nombreMax": 1, "reste": 1 }, { "niveau": 10, "nombreMax": 1, "nombre": 0 },
{ "niveau": 11, "nombreMax": 1, "reste": 1 } { "niveau": 11, "nombreMax": 1, "nombre": 0 }
]; ];
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -34,6 +34,13 @@ const categorieCompetences = {
"lancer": { base: -8, label: "Lancer" } "lancer": { base: -8, label: "Lancer" }
} }
const compendiumCompetences = {
"personnage": "foundryvtt-reve-de-dragon.competences",
"creature": "foundryvtt-reve-de-dragon.competences-creatures",
"entite": "foundryvtt-reve-de-dragon.competences-entites"
};
function _buildCumulXP() { function _buildCumulXP() {
let cumulXP = { "-11": 0 }; let cumulXP = { "-11": 0 };
let cumul = 0; let cumul = 0;
@ -48,6 +55,12 @@ function _buildCumulXP() {
const competence_xp_cumul = _buildCumulXP(); const competence_xp_cumul = _buildCumulXP();
export class RdDItemCompetence extends Item { export class RdDItemCompetence extends Item {
/* -------------------------------------------- */
static actorCompendium(actorType) {
return compendiumCompetences[actorType];
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static getCategorieCompetences() { static getCategorieCompetences() {
return categorieCompetences; return categorieCompetences;
@ -63,49 +76,40 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
static getCategorie(competence) { static getCategorie(competence) {
return competence?.system.categorie; return Misc.data(competence)?.data.categorie;
} }
static isDraconic(competence) { static isDraconic(competence) {
return competence?.system.categorie == 'draconic'; return Misc.data(competence)?.data.categorie == 'draconic';
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static getVoieDraconic(competences, voie) { static getVoieDraconic(competences, voie) {
return RdDItemCompetence.findFirstItem(competences, voie, { return RdDItemCompetence.findCompetence(competences.filter(it => RdDItemCompetence.isDraconic(it)), voie);
preFilter: it => it.isCompetence() && RdDItemCompetence.isDraconic(it),
description: 'Draconic',
});
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static isCompetenceArme(competence) { static isCompetenceArme(competence) {
if (competence.isCompetence()) { switch (Misc.templateData(competence).categorie) {
switch (competence.system.categorie) { case 'melee':
case 'melee': return Misc.data(competence).name != 'Esquive';
return !Grammar.toLowerCaseNoAccent(competence.name).includes('esquive'); case 'tir':
case 'tir': case 'lancer':
case 'lancer': return true;
return true;
}
} }
return false; return false;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static isArmeUneMain(competence) { static isArmeUneMain(competence) {
return RdDItemCompetence.isCompetenceArme(competence) && competence.name.toLowerCase().includes("1 main"); return Misc.data(competence)?.name.toLowerCase().includes("1 main");
} }
static isArme2Main(competence) { static isArme2Main(competence) {
return RdDItemCompetence.isCompetenceArme(competence) && competence.name.toLowerCase().includes("2 main"); return Misc.data(competence)?.name.toLowerCase().includes("2 main");
}
static isThanatos(competence) {
return competence.isCompetencePersonnage() && Grammar.toLowerCaseNoAccent(competence.name).includes('thanatos');
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static isMalusEncombrementTotal(competence) { static isMalusEncombrementTotal(competence) {
return competence?.name.toLowerCase().match(/(natation|acrobatie)/) || 0; return Misc.data(competence)?.name.toLowerCase().match(/(natation|acrobatie)/);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -129,10 +133,11 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
static computeXP(competence) { static computeXP(competence) {
const factor = RdDItemCompetence.isThanatos(competence) ? 2 : 1; // Thanatos compte double ! const itemData = Misc.data(competence);
const xpNiveau = RdDItemCompetence.computeDeltaXP(competence.system.base, competence.system.niveau ?? competence.system.base); const factor = itemData.name.includes('Thanatos') ? 2 : 1; // Thanatos compte double !
const xp = competence.system.xp ?? 0; const xpNiveau = RdDItemCompetence.computeDeltaXP(itemData.data.base, itemData.data.niveau ?? itemData.data.base);
const xpSort = competence.system.xp_sort ?? 0; const xp = itemData.data.xp ?? 0;
const xpSort = itemData.data.xp_sort ?? 0;
return factor * (xpNiveau + xp) + xpSort; return factor * (xpNiveau + xp) + xpSort;
} }
@ -141,7 +146,7 @@ export class RdDItemCompetence extends Item {
return competenceTroncs.map( return competenceTroncs.map(
list => list.map(name => RdDItemCompetence.findCompetence(competences, name)) list => list.map(name => RdDItemCompetence.findCompetence(competences, name))
// calcul du coût xp jusqu'au niveau 0 maximum // calcul du coût xp jusqu'au niveau 0 maximum
.map(it => RdDItemCompetence.computeDeltaXP(it?.system.base ?? -11, Math.min(it?.system.niveau ?? -11, 0))) .map(it => RdDItemCompetence.computeDeltaXP(it?.data.base ?? -11, Math.min(it?.data.niveau ?? -11, 0)))
.sort(Misc.ascending()) .sort(Misc.ascending())
.splice(0, list.length - 1) // prendre toutes les valeurs sauf l'une des plus élevées .splice(0, list.length - 1) // prendre toutes les valeurs sauf l'une des plus élevées
.reduce(Misc.sum(), 0) .reduce(Misc.sum(), 0)
@ -157,10 +162,11 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
static computeCompetenceXPCost(competence) { static computeCompetenceXPCost(competence) {
let xp = RdDItemCompetence.getDeltaXp(competence.system.base, competence.system.niveau ?? competence.system.base); const compData = Misc.data(competence);
xp += competence.system.xp ?? 0; let xp = RdDItemCompetence.getDeltaXp(compData.data.base, compData.data.niveau ?? compData.data.base);
xp += compData.data.xp ?? 0;
if (compData.name.includes('Thanatos')) xp *= 2; /// Thanatos compte double ! if (compData.name.includes('Thanatos')) xp *= 2; /// Thanatos compte double !
xp += competence.system.xp_sort ?? 0; xp += compData.data.xp_sort ?? 0;
return xp; return xp;
} }
@ -169,75 +175,61 @@ export class RdDItemCompetence extends Item {
let economie = 0; let economie = 0;
for (let troncList of competenceTroncs) { for (let troncList of competenceTroncs) {
let list = troncList.map(name => RdDItemCompetence.findCompetence(competences, name)) let list = troncList.map(name => RdDItemCompetence.findCompetence(competences, name))
.sort(Misc.descending(c => this.system.niveau)); // tri du plus haut au plus bas .sort(Misc.descending(c => Misc.templateData(c).niveau)); // tri du plus haut au plus bas
list.splice(0, 1); // ignorer la plus élevée list.splice(0, 1); // ignorer la plus élevée
list.map(c => c).forEach(c => { list.map(c => Misc.templateData(c)).forEach(tplData => {
economie += RdDItemCompetence.getDeltaXp(c.system.base, Math.min(c.system.niveau, 0)) economie += RdDItemCompetence.getDeltaXp(tplData.base, Math.min(tplData.niveau, 0));
}); });
} }
return economie; return economie;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static levelUp(item, stressTransforme) { static levelUp(itemData, stressTransforme) {
item.system.xpNext = RdDItemCompetence.getCompetenceNextXp(item.system.niveau); itemData.data.xpNext = RdDItemCompetence.getCompetenceNextXp(itemData.data.niveau);
const xpManquant = item.system.xpNext - item.system.xp; const xpManquant = itemData.data.xpNext - itemData.data.xp;
item.system.isLevelUp = xpManquant <= 0; itemData.data.isLevelUp = xpManquant <= 0;
item.system.isStressLevelUp = (xpManquant > 0 && stressTransforme >= xpManquant && item.system.niveau < item.system.niveau_archetype); itemData.data.isStressLevelUp = (xpManquant > 0 && stressTransforme >= xpManquant && itemData.data.niveau < itemData.data.niveau_archetype);
item.system.stressXpMax = 0; itemData.data.stressXpMax = 0;
if (xpManquant > 0 && stressTransforme > 0 && item.system.niveau < item.system.niveau_archetype) { if (xpManquant > 0 && stressTransforme > 0 && itemData.data.niveau < itemData.data.niveau_archetype) {
item.system.stressXpMax = Math.min(xpManquant, stressTransforme); itemData.data.stressXpMax = Math.min(xpManquant , stressTransforme);
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static isVisible(item) { static isVisible(itemData) {
return Number(item.system.niveau) != RdDItemCompetence.getNiveauBase(item.system.categorie); return Number(itemData.data.niveau) != RdDItemCompetence.getNiveauBase(itemData.data.categorie);
} }
static nomContientTexte(item, texte) { static nomContientTexte(itemData, texte) {
return Grammar.toLowerCaseNoAccent(item.name).includes(Grammar.toLowerCaseNoAccent(texte)) return Grammar.toLowerCaseNoAccent(itemData.name).includes(Grammar.toLowerCaseNoAccent(texte))
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static isNiveauBase(item) { static isNiveauBase(itemData) {
return Number(item.system.niveau) == RdDItemCompetence.getNiveauBase(item.system.categorie); return Number(itemData.data.niveau) == RdDItemCompetence.getNiveauBase(itemData.data.categorie);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static findCompetence(list, idOrName, options = {}) { static findCompetence(list, idOrName, options = {}) {
if (idOrName == undefined || idOrName == "") { if (idOrName == undefined) {
return RdDItemCompetence.sansCompetence(); return undefined;
} }
options = mergeObject(options, { preFilter: it => it.isCompetence(), description: 'compétence' }, { overwrite: false }); options = mergeObject(options, {
return RdDItemCompetence.findFirstItem(list, idOrName, options); preFilter: it => RdDItemCompetence.isCompetence(it),
description: 'compétence',
});
return list.find(it => it.id == idOrName && RdDItemCompetence.isCompetence(it))
?? Misc.findFirstLike(idOrName, list, options);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static findCompetences(list, name) { static findCompetences(list, name) {
return Misc.findAllLike(name, list, { filter: it => it.isCompetence(), description: 'compétence' }); return Misc.findAllLike(name, list, { filter: it => RdDItemCompetence.isCompetence(it), description: 'compétence' });
} }
static sansCompetence() { static isCompetence(item) {
return { return item.type == 'competence' || item.type == 'competencecreature';
name: "Sans compétence",
type: "competence",
img: "systems/foundryvtt-reve-de-dragon/icons/templates/icone_parchement_vierge.webp",
system: {
niveau: 0,
default_diffLibre: 0,
base: 0,
categorie: "Aucune",
description: "",
descriptionmj: "",
defaut_carac: "",
}
};
}
static findFirstItem(list, idOrName, options) {
return list.find(it => it.id == idOrName && options.preFilter(it))
?? Misc.findFirstLike(idOrName, list, options);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -267,47 +259,18 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
static computeResumeArchetype(competences) { static computeResumeArchetype(competences) {
const computed = duplicate(limitesArchetypes); const archetype = RdDItemCompetence.getLimitesArchetypes();
competences.map(it => Math.max(0, it.system.niveau_archetype)) competences.map(it => Math.max(0, Misc.templateData(it).niveau_archetype))
.filter(n => n > 0) .forEach(niveau => {
.forEach(n => { archetype[niveau] = archetype[niveau] ?? { "niveau": niveau, "nombreMax": 0, "nombre": 0 };
computed[n] = computed[n] ?? { niveau: n, nombreMax: 0, reste: 0 }; archetype[niveau].nombre = (archetype[niveau]?.nombre ?? 0) + 1;
computed[n].reste = computed[n].reste - 1;
}); });
return computed.filter(it => it.reste > 0 && it.niveau > 0); return archetype;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static triVisible(competences) { static getLimitesArchetypes() {
return competences.filter(it => it.system.isVisible) return duplicate(limitesArchetypes);
.sort((a, b) => RdDItemCompetence.compare(a, b))
}
static $positionTri(comp) {
if (comp.name.startsWith("Survie")) {
if (comp.name.includes("Cité")) return 0;
if (comp.name.includes("Extérieur")) return 1;
return 2;
}
if (comp.system.categorie.startsWith("melee")) {
if (comp.name.includes("Corps")) return 0;
if (comp.name.includes("Dague")) return 1;
if (comp.name.includes("Esquive")) return 2;
return 3;
}
if (comp.system.categorie.startsWith("draconic")) {
if (comp.name.includes("Oniros")) return 0;
if (comp.name.includes("Hypnos")) return 1;
if (comp.name.includes("Narcos")) return 2;
if (comp.name.includes("Thanatos")) return 3;
return 4;
}
return 0;
}
static compare(a, b) {
const diff = RdDItemCompetence.$positionTri(a) - RdDItemCompetence.$positionTri(b);
return diff ? diff : a.name.localeCompare(b.name);
} }
} }

View File

@ -1,53 +1,51 @@
import { Misc } from "./misc.js";
import { RdDCombatManager } from "./rdd-combat.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDItemCompetenceCreature extends Item { export class RdDItemCompetenceCreature extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
static setRollDataCreature(rollData) { static setRollDataCreature(rollData) {
rollData.competence = rollData.competence rollData.competence = Misc.data(rollData.competence);
rollData.carac = { "carac_creature": { label: rollData.competence.name, value: rollData.competence.system.carac_value } } rollData.carac = { "carac_creature": { label: rollData.competence.name, value: rollData.competence.data.carac_value } };
rollData.competence.system.defaut_carac = "carac_creature" rollData.competence.data.defaut_carac = "carac_creature"
rollData.competence.system.categorie = "creature" rollData.competence.data.categorie = "creature"
rollData.selectedCarac = rollData.carac.carac_creature rollData.selectedCarac = rollData.carac.carac_creature
if (rollData.competence.system.iscombat) { if (rollData.competence.data.iscombat) {
rollData.arme = RdDItemCompetenceCreature.armeNaturelle(rollData.competence); rollData.arme = RdDItemCompetenceCreature.toActionArme(rollData.competence);
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static armeNaturelle(competencecreature) { static toActionArme(item) {
if (RdDItemCompetenceCreature.isCompetenceAttaque(competencecreature)) { if (RdDItemCompetenceCreature.isCompetenceAttaque(item)) {
// si c'est un Item compétence: cloner pour ne pas modifier lma compétence // si c'est un Item compétence: cloner pour ne pas modifier la compétence
let arme = (competencecreature instanceof Item) ? competencecreature.clone(): competencecreature; let arme = Misc.data( (item instanceof Item) ? item.clone(): item);
mergeObject(arme.system, mergeObject(arme.data,
{ {
competence: arme.name, competence: arme.name,
initiative: RdDCombatManager.calculInitiative(competencecreature.system.niveau, competencecreature.system.carac_value),
niveau: competencecreature.system.niveau,
equipe: true,
resistance: 100, resistance: 100,
dommagesReels: arme.system.dommages, equipe: true,
dommagesReels: arme.data.dommages,
penetration: 0, penetration: 0,
force: 0, force: 0,
rapide: true, rapide: true,
cac: competencecreature.system.isnaturelle ? "naturelle" : "",
action: 'attaque' action: 'attaque'
}); });
return arme; return arme;
} }
console.error("RdDItemCompetenceCreature.toActionArme(", competencecreature, ") : impossible de transformer l'Item en arme"); console.error("RdDItemCompetenceCreature.toActionArme(", item, ") : impossible de transformer l'Item en arme");
return undefined; return undefined;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static isCompetenceAttaque(item) { static isCompetenceAttaque(itemData) {
return item.type == 'competencecreature' && item.system.iscombat; itemData = Misc.data(itemData);
return itemData.type == 'competencecreature' && itemData.data.iscombat;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static isCompetenceParade(item) { static isCompetenceParade(itemData) {
return item.type == 'competencecreature' && item.system.categorie_parade !== ""; itemData = Misc.data(itemData);
return itemData.type == 'competencecreature' && itemData.data.isparade;
} }
} }

View File

@ -1,60 +0,0 @@
import { RdDItemSheet } from "./item-sheet.js";
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
import { RdDUtility } from "./rdd-utility.js";
export class RdDConteneurItemSheet extends RdDItemSheet {
static get ITEM_TYPE() { return "conteneur" };
async getData() {
const formData = await super.getData();
if (this.actor) {
this.prepareConteneurData(formData);
}
return formData;
}
activateListeners(html) {
super.activateListeners(html);
if (!this.options.editable) return;
this.html.find('.conteneur-name a').click(async event => {
RdDUtility.toggleAfficheContenu(RdDSheetUtility.getItemId(event));
this.render(true);
});
}
/* -------------------------------------------- */
prepareConteneurData(formData) {
RdDUtility.filterEquipementParType(formData, this.actor.itemTypes);
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
formData.subItems = formData.conteneurs.find(it => it._id == this.item.id)?.subItems;
}
async _onDragStart(event) {
console.log("_onDragStart", event);
if (event.target.classList.contains("entity-link")) return;
const itemId = event.srcElement?.attributes["data-item-id"].value;
const item = this.actor.items.get(itemId);
// Create drag data
const dragData = {
actorId: this.actor.id,
type: "Item",
data: item.system
};
event.dataTransfer.setData("text/plain", JSON.stringify(dragData));
}
async _onDropItem(event, dragData) {
if (this.actor) {
const dropParams = await RdDSheetUtility.prepareItemDropParameters(this.item.id, this.actor, dragData, this.objetVersConteneur);
await this.actor.processDropItem(dropParams);
await this.render(true);
}
}
}

View File

@ -1,67 +0,0 @@
import { EnvironmentSheetHelper } from "./environnement.js";
import { RdDItemSheet } from "./item-sheet.js";
import { RdDUtility } from "./rdd-utility.js";
export class RdDFauneItemSheet extends RdDItemSheet {
static get ITEM_TYPE() { return "faune" };
static get defaultOptions() {
return EnvironmentSheetHelper.defaultOptions(super.defaultOptions);
}
setPosition(options = {}) {
return EnvironmentSheetHelper.setPosition(this, super.setPosition(options));
}
async getData() {
const formData = await super.getData();
return await EnvironmentSheetHelper.getData(this, formData);
}
activateListeners(html) {
super.activateListeners(html);
if (!this.options.editable) return;
EnvironmentSheetHelper.activateListeners(this);
html.find("a.linked-actor-delete").click(event => this.onDeleteLinkedActor());
html.find("a.preparer-nourriture").click(event => this.preparerNourriture(event));
html.find("a.manger-nourriture").click(event => this.mangerNourriture(event));
}
async _onDropActor(event, dragData) {
console.log('faune:dropActor', event, dragData)
const linkedActor = fromUuidSync(dragData.uuid);
if (linkedActor?.pack) {
this.item.update({
'system.actor.pack': linkedActor.pack,
'system.actor.id': linkedActor._id,
'system.actor.name': linkedActor.name
});
}
else {
ui.notifications.warn(`${linkedActor.name} ne provient pas d'un compendium.
<br>Choisissez une créature du compendium pour représenter un élément de faune générique`)
}
}
async onDeleteLinkedActor() {
this.item.update({
'system.actor.pack': '',
'system.actor.id': '',
'system.actor.name': ''
});
}
async preparerNourriture(event) {
if (this.actor) {
await this.actor.preparerNourriture(this.item);
}
}
async mangerNourriture(event) {
if (this.actor) {
await this.actor.mangerNourriture(this.item);
}
}
}

View File

@ -1,25 +0,0 @@
import { EnvironmentSheetHelper } from "./environnement.js";
import { RdDItemSheet } from "./item-sheet.js";
export class RdDHerbeItemSheet extends RdDItemSheet {
static get ITEM_TYPE() { return "herbe" };
static get defaultOptions() {
return EnvironmentSheetHelper.defaultOptions(super.defaultOptions);
}
setPosition(options = {}) {
return EnvironmentSheetHelper.setPosition(this, super.setPosition(options));
}
async getData() {
const formData = await super.getData();
return await EnvironmentSheetHelper.getData(this, formData);
}
activateListeners(html) {
super.activateListeners(html);
EnvironmentSheetHelper.activateListeners(this);
}
}

View File

@ -1,25 +0,0 @@
import { EnvironmentSheetHelper } from "./environnement.js";
import { RdDItemSheet } from "./item-sheet.js";
export class RdDIngredientItemSheet extends RdDItemSheet {
static get ITEM_TYPE() { return "ingredient" };
static get defaultOptions() {
return EnvironmentSheetHelper.defaultOptions(super.defaultOptions);
}
setPosition(options = {}) {
return EnvironmentSheetHelper.setPosition(this, super.setPosition(options));
}
async getData() {
const formData = await super.getData();
return await EnvironmentSheetHelper.getData(this, formData);
}
activateListeners(html) {
super.activateListeners(html);
EnvironmentSheetHelper.activateListeners(this);
}
}

View File

@ -3,7 +3,7 @@ export class RdDItemMeditation {
static calculDifficulte(rollData) { static calculDifficulte(rollData) {
if (rollData.meditation) { if (rollData.meditation) {
// Malus permanent éventuel // Malus permanent éventuel
let diff = rollData.meditation.system.malus ?? 0; let diff = rollData.meditation.data.malus ?? 0;
if (!rollData.conditionMeditation.isHeure) diff -= 2; if (!rollData.conditionMeditation.isHeure) diff -= 2;
if (!rollData.conditionMeditation.isVeture) diff -= 2; if (!rollData.conditionMeditation.isVeture) diff -= 2;
if (!rollData.conditionMeditation.isComportement) diff -= 2; if (!rollData.conditionMeditation.isComportement) diff -= 2;

View File

@ -1,106 +1,61 @@
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { LOG_HEAD } from "./constants.js";
const MONNAIE_ETAIN = { const monnaiesData = [
name: "Denier (étain)", type: 'monnaie', {
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_etain_poisson.webp", name: "Etain (1 denier)", type: 'monnaie',
system: { quantite: 0, cout: 0.01, encombrement: 0.001, description: "" } img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_etain_poisson.webp",
}; data: { quantite: 0, valeur_deniers: 1, encombrement: 0.001, description: "" }
const MONNAIE_BRONZE = { },
name: "Sou (bronze)", type: 'monnaie', {
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_bronze_epees.webp", name: "Bronze (10 deniers)", type: 'monnaie',
system: { quantite: 0, cout: 0.10, encombrement: 0.002, description: "" } img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_bronze_epees.webp",
}; data: { quantite: 0, valeur_deniers: 10, encombrement: 0.002, description: "" }
const MONNAIE_ARGENT = { },
name: "Sol (argent)", type: 'monnaie', {
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_argent_sol.webp", name: "Argent (1 sol)", type: 'monnaie',
system: { quantite: 0, cout: 1, encombrement: 0.003, description: "" } img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_argent_sol.webp",
}; data: { quantite: 0, valeur_deniers: 100, encombrement: 0.003, description: "" }
const MONNAIE_OR = { },
name: "Dreagon (or)", type: 'monnaie', {
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_or_sol.webp", name: "Or (10 sols)", type: 'monnaie',
system: { quantite: 0, cout: 10, encombrement: 0.004, description: "" } img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_or_sol.webp",
}; data: { quantite: 0, valeur_deniers: 1000, encombrement: 0.004, description: "" }
}
const MONNAIES_STANDARD = [MONNAIE_ETAIN, MONNAIE_BRONZE, MONNAIE_ARGENT, MONNAIE_OR]; ]
const VALEUR_DENIERS = sols => Math.max(Math.floor((sols ?? 0) * 100), 0);
export class Monnaie { export class Monnaie {
static monnaiesStandard() { static isSystemMonnaie(item) {
return MONNAIES_STANDARD; let present = monnaiesData.find(monnaie => monnaie.data.valeur_deniers == Misc.data(item)?.data?.valeur_deniers);
return present;
} }
static monnaiesManquantes(actor) { static monnaiesData() {
const disponibles = actor.itemTypes['monnaie']; return monnaiesData;
const manquantes = MONNAIES_STANDARD.filter(standard => !disponibles.find(disponible => Monnaie.deValeur(disponible, standard.system?.cout)));
if (manquantes.length > 0) {
console.error(`${LOG_HEAD} monnaiesManquantes pour ${actor.name}`, manquantes, ' avec monnaies', disponibles, MONNAIES_STANDARD);
}
return manquantes;
} }
static deValeur(monnaie, valeur) { static filtrerMonnaies(items) {
return VALEUR_DENIERS(valeur) == VALEUR_DENIERS(monnaie.system.cout) return items.filter(it => Misc.data(it).type == 'monnaie');
} }
static triValeurEntiere() { static monnaiesManquantes(items) {
return Misc.ascending(item => VALEUR_DENIERS(item.system.cout)) const valeurs = Monnaie.filtrerMonnaies(items)
.map(it => Misc.templateData(it).valeur_deniers);
const manquantes = monnaiesData.filter(monnaie => !valeurs.find(v => v != Misc.templateData(monnaie).valeur_deniers));
//const manquantes = monnaiesData.filter(monnaie => !valeurs.find(v => v != Misc.templateData(monnaie).valeur_deniers) );
//console.log("Valeurs : ", valeurs, manquantes);
return []; //manquantes;
} }
static async creerMonnaiesStandard(actor) { static deValeur(monnaie, v) {
await actor.createEmbeddedDocuments('Item', MONNAIES_STANDARD, { renderSheet: false }); return v != monnaie.data.valeur_deniers;
} }
static async creerMonnaiesDeniers(actor, fortune) { static arrondiDeniers(sols) {
await actor.createEmbeddedDocuments('Item', [Monnaie.creerDeniers(fortune)], { renderSheet: false }); return sols.toFixed(2);
} }
static creerDeniers(fortune) { static triValeurDenier() {
const deniers = duplicate(MONNAIE_ETAIN); return Misc.ascending(item => Misc.data(item).data.valeur_deniers);
deniers.system.quantite = fortune;
return deniers;
}
static getFortune(monnaies) {
return (monnaies??[])
.map(m => Number(m.system.cout) * Number(m.system.quantite))
.reduce(Misc.sum(), 0);
}
static async optimiserFortune(actor, fortune) {
let resteEnDeniers = Math.round(fortune * 100);
let monnaies = actor.itemTypes['monnaie'];
let updates = [];
Monnaie.validerMonnaies(monnaies, actor);
let parValeur = Misc.classifyFirst(monnaies, it => VALEUR_DENIERS(it.system.cout));
for (let valeurDeniers of [1000, 100, 10, 1]) {
const itemPiece = parValeur[valeurDeniers];
if (itemPiece) {
const quantite = Math.floor(resteEnDeniers / valeurDeniers);
if (quantite != itemPiece.system.quantite) {
updates.push({ _id: parValeur[valeurDeniers].id, 'system.quantite': quantite });
}
resteEnDeniers -= quantite * valeurDeniers;
}
}
console.log('Monnaie.optimiserFortune', actor.name, 'total', fortune, 'parValeur', parValeur, 'updates', updates, 'reste', resteEnDeniers);
if (updates.length > 0) {
await actor.updateEmbeddedDocuments('Item', updates);
}
if (resteEnDeniers > 0) {
// créer le reste en deniers fortune en deniers
await Monnaie.creerMonnaiesDeniers(actor, resteEnDeniers);
}
}
static validerMonnaies(monnaies, actor = undefined) {
monnaies.filter(it => VALEUR_DENIERS(it.system.cout) == 0)
.map(it => `La monnaie ${it.name} de l'acteur ${actor?.name ?? 'sélectionné'} a une valeur de 0!`)
.forEach(message => {
ui.notifications.warn(message);
console.warn(message);
});
} }
} }

View File

@ -1,78 +0,0 @@
import { RdDRencontre } from "./item/item-rencontre.js";
import { RdDItemSheet } from "./item-sheet.js";
export class RdDRencontreItemSheet extends RdDItemSheet {
static get ITEM_TYPE() { return "rencontre" };
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }]
});
}
/* -------------------------------------------- */
/** @override */
setPosition(options = {}) {
const position = super.setPosition(options);
const sheetHeader = this.element.find(".sheet-header");
const sheetBody = this.element.find(".sheet-body");
sheetBody.css("height", position.height - sheetHeader[0].clientHeight)
return position;
}
/* -------------------------------------------- */
async getData() {
const formData = await super.getData();
mergeObject(formData, {
effets: {
succes: {
liste: RdDRencontre.getEffetsSucces(),
select: RdDRencontre.mapEffets(this.item.system.succes.effets)
},
echec: {
liste: RdDRencontre.getEffetsEchec(),
select: RdDRencontre.mapEffets(this.item.system.echec.effets)
}
}
});
return formData;
}
/* -------------------------------------------- */
/** @override */
activateListeners(html) {
super.activateListeners(html);
if (!this.options.editable) return;
this.html.find("a.effet-add").click(event => this.onAddEffet(event));
this.html.find("a.effet-delete").click(event => this.onDeleteEffet(event));
}
async onAddEffet(event) {
const resultat = this.html.find(event.currentTarget)?.data("effet-resultat");
const keyEffets = `system.${resultat}.effets`;
const code = this.html.find(event.currentTarget)?.data("effet-code");
const liste = RdDRencontre.getListeEffets(this.item, resultat);
liste.push(code);
await this._updateEffetsRencontre(keyEffets, liste);
}
async onDeleteEffet(event) {
const resultat = this.html.find(event.currentTarget)?.data("effet-resultat");
const keyEffets = `system.${resultat}.effets`;
const pos = this.html.find(event.currentTarget)?.data("effet-pos");
const liste = RdDRencontre.getListeEffets(this.item, resultat);
liste.splice(pos, 1);
await this._updateEffetsRencontre(keyEffets, liste);
}
async _updateEffetsRencontre(key, liste) {
const updates = {};
updates[key] = liste;
this.item.update(updates);
}
}

View File

@ -1,16 +0,0 @@
import { RdDItemSheet } from "./item-sheet.js";
export class RdDServiceItemSheet extends RdDItemSheet {
static get ITEM_TYPE() { return "service" };
async getData() {
const formData = await super.getData();
formData.disabled = formData.isGM || formData.isOwned ? '' : 'disabled';
return formData;
}
activateListeners(html) {
super.activateListeners(html);
}
}

View File

@ -4,70 +4,45 @@ import { RdDAlchimie } from "./rdd-alchimie.js";
import { RdDItemCompetence } from "./item-competence.js"; import { RdDItemCompetence } from "./item-competence.js";
import { RdDHerbes } from "./rdd-herbes.js"; import { RdDHerbes } from "./rdd-herbes.js";
import { RdDGemme } from "./rdd-gemme.js"; import { RdDGemme } from "./rdd-gemme.js";
import { Misc } from "./misc.js";
import { HtmlUtility } from "./html-utility.js"; import { HtmlUtility } from "./html-utility.js";
import { ReglesOptionelles } from "./settings/regles-optionelles.js"; import { ReglesOptionelles } from "./regles-optionelles.js";
import { SYSTEM_RDD } from "./constants.js"; import { SYSTEM_RDD } from "./constants.js";
import { RdDSheetUtility } from "./rdd-sheet-utility.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 * Extend the basic ItemSheet with some very simple modifications
* @extends {ItemSheet}
*/ */
export class RdDItemSheet extends ItemSheet { export class RdDItemSheet extends ItemSheet {
static get ITEM_TYPE() {
return undefined
}
static defaultTemplate(type) {
return type ?
`systems/foundryvtt-reve-de-dragon/templates/item-${type}-sheet.html` :
"systems/foundryvtt-reve-de-dragon/templates/item-sheet.html";
}
static register(sheetClass) {
Items.registerSheet(SYSTEM_RDD, sheetClass, {
label: Misc.typeName('Item', sheetClass.ITEM_TYPE),
types: [sheetClass.ITEM_TYPE],
makeDefault: true
})
}
/** @override */ /** @override */
static get defaultOptions() { static get defaultOptions() {
return mergeObject(super.defaultOptions, { return mergeObject(super.defaultOptions, {
classes: [SYSTEM_RDD, "sheet", "item"], classes: [SYSTEM_RDD, "sheet", "item"],
template: RdDItemSheet.defaultTemplate(RdDItemSheet.ITEM_TYPE), template: "systems/foundryvtt-reve-de-dragon/templates/item-sheet.html",
width: 550, width: 550,
height: 550 height: 550
}); });
} }
/* -------------------------------------------- */
get template() {
return RdDItemSheet.defaultTemplate(this.item.type);
}
get title() {
return `${Misc.typeName('Item', this.item.type)}: ${this.item.name}`;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
_getHeaderButtons() { _getHeaderButtons() {
let buttons = super._getHeaderButtons(); let buttons = super._getHeaderButtons();
if (this.item.isInventaire() && this.item.isVideOuNonConteneur()) { // Add "Post to chat" button
// We previously restricted this to GM and editable items only. If you ever find this comment because it broke something: eh, sorry!
if ("cout" in Misc.templateData(this.object) && this.object.isVideOuNonConteneur()) {
buttons.unshift({ buttons.unshift({
class: "vendre", class: "vendre",
icon: "fas fa-comments-dollar", icon: "fas fa-comments-dollar",
onclick: ev => this.item.proposerVente(1) onclick: ev => this.item.proposerVente()
}); });
} }
buttons.unshift({ buttons.unshift({
class: "montrer", class: "montrer",
icon: "fas fa-comment", icon: "fas fa-comment",
onclick: ev => this.item.postItemToChat() onclick: ev => this.item.postItem()
}); });
return buttons return buttons
} }
@ -85,204 +60,233 @@ export class RdDItemSheet extends ItemSheet {
/* -------------------------------------------- */ /* -------------------------------------------- */
async getData() { async getData() {
const objectData = Misc.data(this.object)
let formData = { let formData = {
id: this.item.id, id: this.object.id,
title: this.item.name, title: objectData.name,
type: this.item.type, type: objectData.type,
img: this.item.img, img: objectData.img,
name: this.item.name, name: objectData.name,
system: this.item.system, data: objectData.data,
isGM: game.user.isGM, isGM: game.user.isGM,
actorId: this.actor?.id, actorId: this.actor?.id,
isOwned: this.actor ? true : false, owner: this.document.isOwner,
owner: this.item.isOwner,
editable: this.isEditable, editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked", cssClass: this.isEditable ? "editable" : "locked",
isSoins: false, isSoins: false
description: await TextEditor.enrichHTML(this.item.system.description, { async: true }), }
descriptionmj: await TextEditor.enrichHTML(this.item.system.descriptionmj, { async: true }), if (this.actor) {
isComestible: this.item.isComestible() formData.isOwned = true;
if (objectData.type == 'conteneur') {
this.prepareConteneurData(formData);
}
} }
const competences = await SystemCompendiums.getCompetences(this.actor?.type);
formData.categorieCompetences = RdDItemCompetence.getCategorieCompetences() formData.categorieCompetences = RdDItemCompetence.getCategorieCompetences()
if (this.item.type == 'tache' || this.item.type == 'livre' || this.item.type == 'meditation' || this.item.type == 'oeuvre') { if (formData.type == 'tache' || formData.type == 'livre' || formData.type == 'meditation' || formData.type == 'oeuvre') {
formData.caracList = duplicate(game.system.model.Actor.personnage.carac) formData.caracList = duplicate(game.system.model.Actor.personnage.carac)
formData.caracList["reve-actuel"] = duplicate(game.system.model.Actor.personnage.reve.reve) formData.caracList["reve-actuel"] = duplicate(game.system.model.Actor.personnage.reve.reve)
formData.competences = competences; formData.competences = await RdDUtility.loadCompendium('foundryvtt-reve-de-dragon.competences')
} }
if (this.item.type == 'arme') { if (formData.type == 'arme') {
formData.competences = competences.filter(it => RdDItemCompetence.isCompetenceArme(it)); formData.competences = await RdDUtility.loadCompendium('foundryvtt-reve-de-dragon.competences', it => RdDItemCompetence.isCompetenceArme(it));
console.log(formData.competences)
} }
if (['sort', 'sortreserve'].includes(this.item.type)) { if (formData.type == 'recettealchimique') {
formData.competences = competences.filter(it => RdDItemCompetence.isDraconic(it)); RdDAlchimie.processManipulation(objectData, this.actor && this.actor.id);
} }
if (this.item.type == 'recettecuisine') { if (formData.type == 'gemme') {
formData.ingredients = await TextEditor.enrichHTML(this.object.system.ingredients, { async: true })
}
if (this.item.type == 'extraitpoetique') {
formData.extrait = await TextEditor.enrichHTML(this.object.system.extrait, { async: true })
formData.texte = await TextEditor.enrichHTML(this.object.system.texte, { async: true })
}
if (this.item.type == 'recettealchimique') {
RdDAlchimie.processManipulation(this.item, this.actor && this.actor.id);
formData.manipulation_update = await TextEditor.enrichHTML(this.object.system.manipulation_update, { async: true })
formData.utilisation = await TextEditor.enrichHTML(this.object.system.utilisation, { async: true })
formData.enchantement = await TextEditor.enrichHTML(this.object.system.enchantement, { async: true })
formData.sureffet = await TextEditor.enrichHTML(this.object.system.sureffet, { async: true })
}
if (this.item.type == 'gemme') {
formData.gemmeTypeList = RdDGemme.getGemmeTypeOptionList(); formData.gemmeTypeList = RdDGemme.getGemmeTypeOptionList();
RdDGemme.calculDataDerivees(this.item); RdDGemme.calculDataDerivees(formData.data);
} }
if (this.item.type == 'potion') { if (formData.type == 'potion') {
await RdDHerbes.addPotionFormData(formData); if (this.dateUpdated) {
formData.data.prdate = this.dateUpdated;
this.dateUpdated = undefined;
}
RdDHerbes.updatePotionData(formData);
} }
if (formData.isOwned && this.item.type == 'herbe' && (formData.system.categorie == 'Soin' || formData.system.categorie == 'Repos')) { if (formData.isOwned && formData.type == 'herbe' && (formData.data.categorie == 'Soin' || formData.data.categorie == 'Repos')) {
formData.isIngredientPotionBase = true; formData.isIngredientPotionBase = true;
} }
if (this.item.type == 'sortreserve') {
const sortId = this.item.system.sortid;
formData.sort = formData.isOwned ? this.item.actor.items.get(sortId) : game.items.get(sortId);
}
formData.bonusCaseList = RdDItemSort.getBonusCaseList(formData, true); formData.bonusCaseList = RdDItemSort.getBonusCaseList(formData, true);
return formData; return formData;
} }
/* -------------------------------------------- */
prepareConteneurData(formData) {
formData.itemsByType = Misc.classify(this.actor.items.map(i => foundry.utils.deepClone(i.data)));
RdDUtility.filterEquipementParType(formData);
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
formData.subItems = formData.conteneurs.find(it => it._id == this.object.id)?.subItems;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @override */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
this.html = html;
HtmlUtility._showControlWhen(this.html.find(".item-cout"), ReglesOptionelles.isUsing('afficher-prix-joueurs') || game.user.isGM || !this.item.isOwned); if (this.object.type == 'conteneur') {
HtmlUtility._showControlWhen(this.html.find(".item-magique"), this.item.isMagique()); this.form.ondragstart = (event) => this._onDragStart(event);
this.form.ondrop = (event) => this._onDrop(event);
}
let itemSheetDialog = this;
HtmlUtility._showControlWhen($(".item-cout"), ReglesOptionelles.isUsing('afficher-prix-joueurs') || game.user.isGM || !this.object.isOwned);
HtmlUtility._showControlWhen($(".item-magique"), this.object.isMagique());
// Everything below here is only needed if the sheet is editable // Everything below here is only needed if the sheet is editable
if (!this.options.editable) return; if (!this.options.editable) return;
this.form.ondragstart = (event) => this._onDragStart(event);
this.form.ondrop = (event) => this._onDrop(event);
// Select competence categorie // Select competence categorie
this.html.find(".categorie").change(event => this._onSelectCategorie(event)); html.find(".categorie").change(event => this._onSelectCategorie(event));
this.html.find('.sheet-competence-xp').change((event) => { html.find('.sheet-competence-xp').change((event) => {
if (this.item.isCompetencePersonnage()) { if (this.object.data.type == 'competence') {
RdDUtility.checkThanatosXP(this.item.name); RdDUtility.checkThanatosXP(this.object.data.name);
} }
}); });
this.html.find(".item-cout input[name='system.cout']").change(event => {
if (this.item.isMonnaie()) {
const value = event.currentTarget.value;
if (Number(value) == 0) {
ui.notifications.error(`${this.actor?.name ?? 'Monnaie'}: La monnaie ${this.item.name} a maintenant une valeur de 0, et ne peut plus être utilisée pour payer!`)
}
}
})
this.html.find('.date-enchantement').change((event) => { html.find('.enchanteDate').change((event) => {
const jour = Number(this.html.find('input.date-enchantement[name="enchantement.jour"]').val()); let jour = Number($('#jourMois').val());
const mois = RdDTimestamp.definition(this.html.find('select.date-enchantement[name="enchantement.mois"]').val()); let mois = $('#nomMois').val();
const indexDate = game.system.rdd.calendrier.getIndexFromDate(jour, mois.heure); this.dateUpdated = game.system.rdd.calendrier.getIndexFromDate(jour, mois);
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)); html.find('.creer-tache-livre').click((event) => {
this.html.find('.consommer-potion').click((event) => this._getEventActor(event).consommerPotion(this.item)); let actorId = event.currentTarget.attributes['data-actor-id'].value;
this.html.find('.creer-potion-base').click((event) => this._getEventActor(event).dialogFabriquerPotion(this.item)); let actor = game.actors.get(actorId);
actor.creerTacheDepuisLivre(this.item);
});
html.find('.consommer-potion').click((event) => {
let actorId = event.currentTarget.attributes['data-actor-id'].value;
let actor = game.actors.get(actorId);
actor.consommerPotion(this.item);
});
html.find('.creer-potion-base').click((event) => {
let actorId = event.currentTarget.attributes['data-actor-id'].value;
let actor = game.actors.get(actorId);
actor.dialogFabriquerPotion(this.item);
});
this.html.find('.alchimie-tache a').click((event) => { html.find('.alchimie-tache a').click((event) => {
let actor = this._getEventActor(event); let actorId = event.currentTarget.attributes['data-actor-id'].value;
let recetteId = event.currentTarget.attributes['data-recette-id'].value;
let tacheName = event.currentTarget.attributes['data-alchimie-tache'].value;
let tacheData = event.currentTarget.attributes['data-alchimie-data'].value;
let actor = game.actors.get(actorId);
if (actor) { if (actor) {
let recetteId = event.currentTarget.attributes['data-recette-id'].value;
let tacheName = event.currentTarget.attributes['data-alchimie-tache'].value;
let tacheData = event.currentTarget.attributes['data-alchimie-data'].value;
actor.effectuerTacheAlchimie(recetteId, tacheName, tacheData); actor.effectuerTacheAlchimie(recetteId, tacheName, tacheData);
} else { } else {
ui.notifications.info("Impossible trouver un acteur pour réaliser cette tache Alchimique."); ui.notifications.info("Impossible trouver un actur pour réaliser cette tache Alchimique.");
} }
}); });
this.html.find('.item-split').click(async event => RdDSheetUtility.splitItem(RdDSheetUtility.getItem(event, this.actor), this.actor, async () => this.render(true))); html.find('.item-split').click(async event => {
this.html.find('.item-edit').click(async event => RdDSheetUtility.getItem(event, this.actor)?.sheet.render(true)); const item = RdDSheetUtility.getItem(event, this.actor);
this.html.find('.item-delete').click(async event => RdDUtility.confirmActorItemDelete(this, RdDSheetUtility.getItem(event, this.actor))); await RdDSheetUtility.splitItem(item, this.actor, async () => itemSheetDialog.render(true));
this.html.find('.item-vendre').click(async event => RdDSheetUtility.getItem(event, this.actor)?.proposerVente()); });
this.html.find('.item-montrer').click(async event => RdDSheetUtility.getItem(event, this.actor)?.postItemToChat()); html.find('.item-edit').click(async event => {
this.html.find('.item-action').click(async event => RdDSheetUtility.getItem(event, this.actor)?.actionPrincipale(this.actor, async () => this.render(true))); const item = RdDSheetUtility.getItem(event, this.actor);
item.sheet.render(true);
const updateItemTimestamp = (path, timestamp) => this.item.update({ [path]: duplicate(timestamp) }) });
html.find('.item-delete').click(async event => {
RdDTimestamp.handleTimestampEditor(this.html, 'system.temporel.debut', updateItemTimestamp); const li = RdDSheetUtility.getEventElement(event);
RdDTimestamp.handleTimestampEditor(this.html, 'system.temporel.fin', updateItemTimestamp); RdDUtility.confirmerSuppression(this, li);
});
html.find('.item-vendre').click(async event => {
const item = RdDSheetUtility.getItem(event, this.actor);
item?.proposerVente();
});
html.find('.item-montrer').click(async event => {
const item = RdDSheetUtility.getItem(event, this.actor);
item?.postItem();
});
html.find('.item-action').click(async event => {
const item = RdDSheetUtility.getItem(event, this.actor);
this.actor.actionItem(item, async () => itemSheetDialog.render(true));
});
html.find('.conteneur-name a').click(async event => {
RdDUtility.toggleAfficheContenu(RdDSheetUtility.getItemId(event));
this.render(true);
});
} }
_getEventActor(event) {
let actorId = event.currentTarget.attributes['data-actor-id'].value;
let actor = game.actors.get(actorId);
return actor;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async _onSelectCategorie(event) { async _onSelectCategorie(event) {
event.preventDefault(); event.preventDefault();
if (this.item.isCompetence()) { if (this.object.isCompetence()) {
let level = RdDItemCompetence.getNiveauBase(event.currentTarget.value); let level = RdDItemCompetence.getNiveauBase(event.currentTarget.value);
this.item.system.base = level; Misc.templateData(this.object).base = level;
this.html.find('[name="system.base"]').val(level); $("#base").val(level);
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
get template() {
let type = this.object.data.type;
return `systems/foundryvtt-reve-de-dragon/templates/item-${type}-sheet.html`;
}
/* -------------------------------------------- */
/** @override */ /** @override */
_updateObject(event, formData) { _updateObject(event, formData) { // Deprecated en v0.8 à clarifier
if (this.item.type == 'sort') { // Données de bonus de cases ?
// Données de bonus de cases ? formData = RdDItemSort.buildBonusCaseStringFromFormData(formData);
formData['system.bonuscase'] = RdDItemSort.buildBonusCaseStringFromFormData(formData.bonusValue, formData.caseValue);
}
return this.item.update(formData); return this.object.update(formData);
} }
/* -------------------------------------------- */
async _onDragStart(event) { async _onDragStart(event) {
console.log("_onDragStart", event);
if (event.target.classList.contains("entity-link")) return;
const itemId = event.srcElement?.attributes["data-item-id"].value;
const item = this.actor.items.get(itemId);
// Create drag data
const dragData = {
actorId: this.actor.id,
type: "Item",
data: item.data
};
event.dataTransfer.setData("text/plain", JSON.stringify(dragData));
} }
async _onDrop(event) { async _onDrop(event) {
// Try to extract the dragData // Try to extract the data
let dragData = RdDItemSheet.$extractDragData(event); let data;
if (!dragData) return false; try {
const allowed = Hooks.call("dropActorSheetData", this.actor, this, dragData); data = JSON.parse(event.dataTransfer.getData('text/plain'));
if (allowed === false) return false; } catch (err) {
return false;
}
// Handle different dragData types const allowed = Hooks.call("dropActorSheetData", this.actor, this, data);
switch (dragData.type) { if (allowed === false) return;
// Handle different data types
switch (data.type) {
case "Item": case "Item":
return this._onDropItem(event, dragData); return this._onDropItem(event, data);
case "Actor":
return this._onDropActor(event, dragData);
} }
return super._onDrop(event); return super._onDrop(event);
} }
static $extractDragData(event) { /* -------------------------------------------- */
try {
const eventData = event?.dataTransfer?.getData('text/plain');
if (eventData) {
return JSON.parse(eventData);
}
} catch (err) { }
return undefined;
}
async _onDropItem(event, dragData) { async _onDropItem(event, dragData) {
if (this.actor) {
const dropParams = RdDSheetUtility.prepareItemDropParameters(this.object.id, this.actor.id, dragData, this.objetVersConteneur);
await this.actor.processDropItem(dropParams);
await this.render(true);
}
} }
async _onDropActor(event, dragData) {
}
} }

View File

@ -1,14 +1,30 @@
import { RdDItemSheet } from "./item-sheet.js"; import { SYSTEM_RDD } from "./constants.js";
import { RdDItemSigneDraconique } from "./item/item-signedraconique.js"; import { RdDItemSigneDraconique } from "./item-signedraconique.js";
import { TMRUtility } from "./tmr-utility.js"; import { Misc } from "./misc.js";
import { TMRType, TMRUtility } from "./tmr-utility.js";
/** /**
* Item sheet pour signes draconiques * Item sheet pour signes draconiques
* @extends {RdDItemSheet} * @extends {ItemSheet}
*/ */
export class RdDSigneDraconiqueItemSheet extends RdDItemSheet { export class RdDSigneDraconiqueItemSheet extends ItemSheet {
static get ITEM_TYPE() { return "signedraconique" } /** @override */
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
classes: [SYSTEM_RDD, "sheet", "item"],
template: "systems/foundryvtt-reve-de-dragon/templates/item-signedraconique-sheet.html",
width: 550,
height: 550
});
}
/* -------------------------------------------- */
_getHeaderButtons() {
let buttons = super._getHeaderButtons();
buttons.unshift({ class: "post", icon: "fas fa-comment", onclick: ev => this.item.postItem() });
return buttons;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @override */
@ -16,16 +32,25 @@ export class RdDSigneDraconiqueItemSheet extends RdDItemSheet {
const position = super.setPosition(options); const position = super.setPosition(options);
const sheetHeader = this.element.find(".sheet-header"); const sheetHeader = this.element.find(".sheet-header");
const sheetBody = this.element.find(".sheet-body"); const sheetBody = this.element.find(".sheet-body");
sheetBody.css("height", position.height - sheetHeader[0].clientHeight) const bodyHeight = position.height - sheetHeader[0].clientHeight;
sheetBody.css("height", bodyHeight);
return position; return position;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async getData() { async getData() {
const formData = await super.getData(); const formData = duplicate(Misc.data(this.object));
this.tmrs = TMRUtility.buildSelectionTypesTMR(this.item.system.typesTMR); mergeObject(formData, {
formData.tmrs = this.tmrs; title: formData.name,
isGM: game.user.isGM,
owner: this.document.isOwner,
isOwned: this.actor ? true : false,
actorId: this.actor?.id,
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
});
formData.tmrs = TMRUtility.listSelectedTMR(formData.data.typesTMR ?? []);
return formData; return formData;
} }
@ -37,32 +62,35 @@ export class RdDSigneDraconiqueItemSheet extends RdDItemSheet {
if (!this.options.editable) return; if (!this.options.editable) return;
html.find(".signe-aleatoire").click(event => this.setSigneAleatoire()); html.find(".signe-aleatoire").click(event => this.setSigneAleatoire());
html.find("input.select-tmr").change(event => this.onSelectTmr(event)); html.find(".select-tmr").change((event) => this.onSelectTmr(event));
html.find(".signe-xp-sort").change(event => this.onValeurXpSort(event.currentTarget.attributes['data-typereussite']?.value, Number(event.currentTarget.value))); html.find(".signe-xp-sort").change((event) => this.onValeurXpSort(event.currentTarget.attributes['data-typereussite']?.value, Number(event.currentTarget.value)));
} }
async setSigneAleatoire() { async setSigneAleatoire() {
const newSigne = await RdDItemSigneDraconique.randomSigneDraconique(); const newSigne = await RdDItemSigneDraconique.randomSigneDraconique();
newSigne.name = this.item.name; this.object.update(newSigne);
this.item.update(newSigne);
} }
async onSelectTmr(event) { async onSelectTmr(event) {
const tmrName = $(event.currentTarget)?.data("tmr-name"); event.preventDefault();
const onTmr = this.tmrs.find(it => it.name == tmrName); const selectedTMR = $(".select-tmr").val();
if (onTmr){ this.object.update({ 'data.typesTMR': selectedTMR });
onTmr.selected = event.currentTarget.checked;
}
this.item.update({ 'system.typesTMR': TMRUtility.buildListTypesTMRSelection(this.tmrs) });
} }
async onValeurXpSort(event) { async onValeurXpSort(event) {
const codeReussite = event.currentTarget.attributes['data-typereussite']?.value ?? 0; const codeReussite = event.currentTarget.attributes['data-typereussite']?.value ?? 0;
const xp = Number(event.currentTarget.value); const xp = Number(event.currentTarget.value);
const oldValeur = this.item.system.valeur; const oldValeur = Misc.templateData(this.object).valeur;
const newValeur = RdDItemSigneDraconique.calculValeursXpSort(codeReussite, xp, oldValeur); const newValeur = RdDItemSigneDraconique.calculValeursXpSort(codeReussite, xp, oldValeur);
await this.item.update({ 'system.valeur': newValeur }); await this.object.update({ 'data.valeur': newValeur });
} }
/* -------------------------------------------- */
get template() {
return `systems/foundryvtt-reve-de-dragon/templates/item-signedraconique-sheet.html`;
}
get title() {
return `Signe draconique: ${this.object.name}`;
}
} }

View File

@ -1,9 +1,8 @@
import { RdDItem, defaultItemImg } from "../item.js"; import { defaultItemImg } from "./item.js";
import { Misc } from "../misc.js"; import { Misc } from "./misc.js";
import { RdDDice } from "../rdd-dice.js"; import { RdDDice } from "./rdd-dice.js";
import { RdDRollTables } from "../rdd-rolltables.js"; import { RdDRollTables } from "./rdd-rolltables.js";
import { RdDTimestamp } from "../rdd-timestamp.js"; import { TMRType, TMRUtility } from "./tmr-utility.js";
import { TMRType, TMRUtility } from "../tmr-utility.js";
const tableSignesIndicatifs = [ const tableSignesIndicatifs = [
{ rarete: "Très facile", difficulte: 0, xp: 6, nbCases: 14 }, { rarete: "Très facile", difficulte: 0, xp: 6, nbCases: 14 },
@ -16,25 +15,16 @@ const tableSignesIndicatifs = [
const DIFFICULTE_LECTURE_SIGNE_MANQUE = +11; const DIFFICULTE_LECTURE_SIGNE_MANQUE = +11;
export class RdDItemSigneDraconique extends RdDItem { export class RdDItemSigneDraconique {
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) { static prepareSigneDraconiqueMeditation(meditation, rolled) {
meditation = Misc.data(meditation);
return { return {
name: "de la " + meditation.name, name: "de la " + meditation.name,
type: "signedraconique", type: "signedraconique",
img: meditation.img, img: meditation.img,
system: { data: {
typesTMR: [TMRUtility.typeTmrName(meditation.system.tmr)], typesTMR: [TMRUtility.typeTmrName(meditation.data.tmr)],
difficulte: rolled.isSuccess ? RdDItemSigneDraconique.getDiffSigneMeditation(rolled.code) : DIFFICULTE_LECTURE_SIGNE_MANQUE, difficulte: rolled.isSuccess ? RdDItemSigneDraconique.getDiffSigneMeditation(rolled.code) : DIFFICULTE_LECTURE_SIGNE_MANQUE,
ephemere: true, ephemere: true,
duree: "1 round", duree: "1 round",
@ -53,7 +43,7 @@ export class RdDItemSigneDraconique extends RdDItem {
} }
static getXpSortSigneDraconique(code, signe) { static getXpSortSigneDraconique(code, signe) {
return Misc.toInt(signe.system.valeur[code] ?? 0); return Misc.toInt(Misc.data(signe).data.valeur[code] ?? 0);
} }
static calculValeursXpSort(qualite, valeur, avant) { static calculValeursXpSort(qualite, valeur, avant) {
@ -85,7 +75,7 @@ export class RdDItemSigneDraconique extends RdDItem {
name: await RdDItemSigneDraconique.randomSigneDescription(), name: await RdDItemSigneDraconique.randomSigneDescription(),
type: "signedraconique", type: "signedraconique",
img: defaultItemImg.signedraconique, img: defaultItemImg.signedraconique,
system: { data: {
typesTMR: await RdDItemSigneDraconique.randomTmrs(modele.nbCases), typesTMR: await RdDItemSigneDraconique.randomTmrs(modele.nbCases),
ephemere: options?.ephemere == undefined ? RdDDice.rollTotal("1d2") == 2 : options.ephemere, ephemere: options?.ephemere == undefined ? RdDDice.rollTotal("1d2") == 2 : options.ephemere,
duree: "1 round", duree: "1 round",
@ -107,6 +97,6 @@ export class RdDItemSigneDraconique extends RdDItem {
static async randomSigneDescription() { static async randomSigneDescription() {
return await RdDRollTables.drawTextFromRollTable("Signes draconiques", false); return await RdDRollTables.drawTextFromRollTable("Signes draconiques", false);
} }
} }

View File

@ -7,25 +7,25 @@ export class RdDItemSort extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
static isDifficulteVariable(sort) { static isDifficulteVariable(sort) {
return sort && (sort.system.difficulte.toLowerCase() == "variable"); return sort && (sort.data.difficulte.toLowerCase() == "variable");
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static isCoutVariable(sort) { static isCoutVariable(sort) {
return sort && (sort.system.ptreve.toLowerCase() == "variable" || sort.system.ptreve.indexOf("+") >= 0); return sort && (sort.data.ptreve.toLowerCase() == "variable" || sort.data.ptreve.indexOf("+") >= 0);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static setCoutReveReel(sort){ static setCoutReveReel(sort){
if (sort) { if (sort) {
sort.system.ptreve_reel = this.isCoutVariable(sort) ? 1 : sort.system.ptreve; sort.data.ptreve_reel = this.isCoutVariable(sort) ? 1 : sort.data.ptreve;
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static getDifficulte(sort, variable) { static getDifficulte(sort, variable) {
if (sort && !RdDItemSort.isDifficulteVariable(sort)) { if (sort && !RdDItemSort.isDifficulteVariable(sort)) {
return Misc.toInt(sort.system.difficulte); return Misc.toInt(sort.data.difficulte);
} }
return variable; return variable;
} }
@ -54,35 +54,40 @@ export class RdDItemSort extends Item {
static getBonusCaseList( item, newCase = false ) { static getBonusCaseList( item, newCase = false ) {
// Gestion spéciale case bonus // Gestion spéciale case bonus
if ( item.type == 'sort') { if ( item.type == 'sort') {
return this.buildBonusCaseList(item.system.bonuscase, newCase ); return this.buildBonusCaseList(item.data.bonuscase, newCase );
} }
return undefined; return undefined;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/** Met à jour les données de formulaire /** Met à jour les données de formulaire
* si static des bonus de cases sont présents * si static des bonus de cases sont présents
* */ * */
static buildBonusCaseStringFromFormData( bonuses, cases ) { static buildBonusCaseStringFromFormData( formData ) {
if ( bonuses ) { if ( formData.bonusValue ) {
let list = []; let list = [];
let caseCheck = {}; let caseCheck = {};
for (let i=0; i<bonuses.length; i++) { for(let i=0; i<formData.bonusValue.length; i++) {
let coord = cases[i]?.toUpperCase() || 'A1'; let coord = formData.caseValue[i] || 'A1';
let bonus = bonuses[i] || 0; coord = coord.toUpperCase();
if ( TMRUtility.verifyTMRCoord( coord ) && bonus > 0 && caseCheck[coord] == undefined ) { if ( TMRUtility.verifyTMRCoord( coord ) ) { // Sanity check
caseCheck[coord] = bonus; let bonus = formData.bonusValue[i] || 0;
list.push( coord+":"+bonus ); if ( bonus > 0 && caseCheck[coord] == undefined ) {
caseCheck[coord] = bonus;
list.push( coord+":"+bonus );
}
}
} }
formData.bonusValue = undefined;
formData.caseValue = undefined;
formData['data.bonuscase'] = list.toString(); // Reset
} }
return list.toString(); return formData;
}
return undefined;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static incrementBonusCase( actor, sort, coord ) { static incrementBonusCase( actor, sort, coord ) {
let bonusCaseList = this.buildBonusCaseList(sort.system.bonuscase, false); let bonusCaseList = this.buildBonusCaseList(sort.data.bonuscase, false);
//console.log("ITEMSORT", sort, bonusCaseList); //console.log("ITEMSORT", sort, bonusCaseList);
let found = false; let found = false;
@ -101,12 +106,12 @@ export class RdDItemSort extends Item {
// Sauvegarde/update // Sauvegarde/update
let bonuscase = StringList.toString(); let bonuscase = StringList.toString();
//console.log("Bonus cae :", bonuscase); //console.log("Bonus cae :", bonuscase);
actor.updateEmbeddedDocuments('Item', [{ _id: sort._id, 'system.bonuscase': bonuscase }] ); actor.updateEmbeddedDocuments('Item', [{ _id: sort._id, 'data.bonuscase': bonuscase }] );
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static getCaseBonus( sort, coord) { static getCaseBonus( sort, coord) {
let bonusCaseList = this.buildBonusCaseList(sort.system.bonuscase, false); let bonusCaseList = this.buildBonusCaseList(sort.data.bonuscase, false);
for( let bc of bonusCaseList) { for( let bc of bonusCaseList) {
if (bc.case == coord) { // Case existante if (bc.case == coord) { // Case existante
return Number(bc.bonus); return Number(bc.bonus);

File diff suppressed because it is too large Load Diff

View File

@ -1,80 +0,0 @@
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 },
{ code: "passeur", resultat: "succes", description: "Déplacer le demi-rêve à (force) cases", method: EffetsRencontre.passeur},
{ code: "reve+f", resultat: "succes", description: "Gain de (force) points de rêve" , method: EffetsRencontre.reve_plus_force},
{ code: "teleport", resultat: "succes", description: "Déplacer le demi-rêve (même type)", method: EffetsRencontre.teleportation_typecase },
{ code: "part+tete", resultat: "succes", description: "Tête de dragon sur réussite particulière", method: EffetsRencontre.rdd_part_tete },
{ code: "part+xp", resultat: "succes", description: "Expérience sur réussite particulière", method: EffetsRencontre.experience_particuliere },
{ code: "seuil", resultat: "succes", description: "Récupération de seuil de rêve", method: EffetsRencontre.regain_seuil },
{ code: "reve-1", resultat: "echec", description: "Perte de 1 point de rêve", method: EffetsRencontre.reve_moins_1 },
{ code: "reve-f", resultat: "echec", description: "Perte de (force) points de rêve", method: EffetsRencontre.reve_moins_force },
{ code: "vie-1", resultat: "echec", description: "Perte de 1 point de vie", method: EffetsRencontre.vie_moins_1 },
{ code: "reinsere", resultat: "echec", description: "Réinsertion aléatoire", method: EffetsRencontre.reinsertion },
{ code: "persistant", resultat: "echec", description: "Bloque le demi-rêve", method: EffetsRencontre.rencontre_persistante },
{ code: "teleport-aleatoire", resultat: "echec", description: "Déplacement aléatoire (même type)", method: EffetsRencontre.teleportation_aleatoire_typecase },
{ code: "aleatoire", resultat: "echec", description: "Déplacement aléatoire", method: EffetsRencontre.deplacement_aleatoire },
{ code: "sort-aleatoire", resultat: "echec", description: "Déclenche un sort en réserve aléatoire", method: EffetsRencontre.sort_aleatoire },
{ code: "rompu", resultat: "echec", description: "Demi-rêve interrompu", method: EffetsRencontre.demireve_rompu },
{ code: "echec-queue", resultat: "echec", description: "Queue(s) de dragon sur échec", method: EffetsRencontre.rdd_echec_queue },
{ code: "reve+1", resultat: "succes", description: "Gain de 1 point de rêve", method: EffetsRencontre.reve_plus_1 },
{ code: "vie-f", resultat: "echec", description: "Perte de (force) points de vie", method: EffetsRencontre.vie_moins_force },
{ code: "moral+1", resultat: "succes", description: "Gain de 1 point de moral", method: EffetsRencontre.moral_plus_1 },
{ code: "moral-1", resultat: "echec", description: "Perte de 1 point de moral", method: EffetsRencontre.moral_moins_1 },
{ code: "xpsort+f", resultat: "succes", description: "Gain de (force) xp sort", method: EffetsRencontre.xp_sort_force },
{ code: "endurance-1", resultat: "echec", description: "Perte de 1 point d'endurance", method: EffetsRencontre.end_moins_1 },
{ code: "endurance-f", resultat: "echec", description: "Perte de (force) points d'endurance", method: EffetsRencontre.end_moins_force },
{ code: "fatigue+1", resultat: "echec", description: "Coup de fatigue de 1 point", method: EffetsRencontre.fatigue_plus_1},
{ code: "fatigue+f", resultat: "echec", description: "Coup de fatigue de 1 (force) points", method: EffetsRencontre.fatigue_plus_force },
{ code: "fatigue-1", resultat: "succes", description: "Récupération de 1 point de fatigue", method: EffetsRencontre.fatigue_moins_1},
{ code: "fatigue-f", resultat: "succes", description: "Récupération de 1 (force) points de fatigue", method: EffetsRencontre.fatigue_moins_force },
{ code: "perte-chance", resultat: "echec", description: "Perte de chance actuelle", method: EffetsRencontre.perte_chance },
{ code: "stress+1", resultat: "succes", description: "Gain de 1 point de stress", method: EffetsRencontre.stress_plus_1 },
// { code: "epart-souffle", resultat: "echec", description: "Souffle de dragon sur échec particulier" },
];
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"); }
static getEffets(resultat) {
return tableEffets.filter(e => resultat == e.resultat);
}
static mapEffets(liste) {
return liste.map(it => RdDRencontre.getEffet(it));
}
static getListeEffets(item, reussite) {
if (reussite == 'echec') {
return [...item.system.echec.effets];
}
if (reussite == 'succes') {
return [...item.system.succes.effets];
}
return [];
}
static getEffet(code) {
return tableEffets.find(it => code == it.code)
}
static async appliquer(codes, tmrDialog, rencData) {
for(const effet of RdDRencontre.mapEffets(codes)){
await effet.method(tmrDialog, rencData);
}
}
async calculerFinPeriodeTemporel(debut) {
return await debut.nouvelleHeure().addHeures(12);
}
}

View File

@ -1,17 +0,0 @@
import { RdDItem } from "../item.js";
export class RdDItemService extends RdDItem {
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/services/lit.webp";
}
isService() { return true; }
getProprietes() {
return [
RdDItem.propertyIfDefined('Qualité', this.system.qualite, this.system.qualite != 0),
RdDItem.propertyIfDefined('Moral', 'Situation heureuse', this.system.moral),
RdDItem.propertyIfDefined('Coût', `${this.calculerPrixCommercant()} sols`),
];
}
}

View File

@ -1,47 +0,0 @@
import { RdDItem } from "../item.js";
import { Misc } from "../misc.js";
import { RdDTimestamp } from "../rdd-timestamp.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);
}
async onFinPeriode(oldTimestamp, newTimestamp) {
await RdDItemMaladie.notifierMaladiePoison(this, oldTimestamp, newTimestamp)
}
static async notifierMaladiePoison(mal, oldTimestamp, newTimestamp) {
if (mal.actor) {
const souffrance = mal.system.identifie
? `de ${mal.name}`
: `d'un mal inconnu`
ChatMessage.create({ content: `${mal.actor.name} souffre ${souffrance} (${Misc.typeName('Item', mal.type)}): vérifiez que les effets ne se sont pas aggravés !` });
mal.postItemToChat('gmroll');
await RdDItemMaladie.prolongerPeriode(mal,oldTimestamp, newTimestamp);
}
}
static async prolongerPeriode(mal, oldTimestamp, newTimestamp) {
if (mal.actor) {
// TODO: déterminer le nombre de périodes écoulées
console.log(`${mal.actor.name}: le mal ${mal.name} a atteint la fin de sa période et été prolongé`);
const current = newTimestamp;
const finPeriode = new RdDTimestamp(mal.system.temporel.fin)
const periodeSuivante = (finPeriode.compare(current) > 0 ? finPeriode : current);
const timestampFin = await mal.calculerFinPeriodeTemporel(periodeSuivante);
await mal.actor.updateEmbeddedDocuments('Item', [{
_id: mal.id,
'system.temporel.fin': duplicate(timestampFin),
}])
}
}
}

View File

@ -1,11 +0,0 @@
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);
}
}

View File

@ -1,17 +0,0 @@
import { RdDItem } from "../item.js";
import { RdDItemMaladie } from "./maladie.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 onFinPeriode(oldTimestamp, newTimestamp) {
RdDItemMaladie.notifierMaladiePoison(this, oldTimestamp, newTimestamp)
}
}

View File

@ -1,13 +0,0 @@
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);
}
}

View File

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

@ -1,482 +0,0 @@
import { RdDBaseActor } from "./actor/base-actor.js";
import { LOG_HEAD, SYSTEM_RDD } from "./constants.js";
import { Environnement } from "./environnement.js";
import { Grammar } from "./grammar.js";
import { Monnaie } from "./item-monnaie.js";
import { RdDItem } from "./item.js";
import { RdDTimestamp } from "./rdd-timestamp.js";
class Migration {
get code() { return "sample"; }
get version() { return "0.0.0"; }
async migrate() { }
async applyItemsUpdates(computeUpdates) {
await game.actors.forEach(async (actor) => {
const actorItemUpdates = computeUpdates(actor.items);
if (actorItemUpdates.length > 0) {
console.log(
this.code,
`Applying updates on actor ${actor.name} items`,
actorItemUpdates
);
await actor.updateEmbeddedDocuments("Item", actorItemUpdates);
}
});
const itemUpdates = computeUpdates(game.items);
if (itemUpdates.length > 0) {
console.log(this.code, "Applying updates on items", itemUpdates);
await Item.updateDocuments(itemUpdates);
}
}
}
class _1_5_34_migrationPngWebp {
get code() { return "migrationPngWebp"; }
get version() { return "1.5.34"; }
async migrate() {
const regexOldPngJpg = /(systems\/foundryvtt-reve-de-dragon\/icons\/.*)\.(png|jpg)/;
const replaceWithWebp = '$1.webp';
function convertImgToWebp(img) {
return img.replace(regexOldPngJpg, replaceWithWebp);
}
function prepareDocumentsImgUpdate(documents) {
return documents.filter(it => it.img && it.img.match(regexOldPngJpg))
.map(it => {
return { _id: it.id, img: convertImgToWebp(it.img) }
});
}
const itemsUpdates = prepareDocumentsImgUpdate(game.items);
const actorsUpdates = prepareDocumentsImgUpdate(game.actors);
//Migrate system png to webp
await Item.updateDocuments(itemsUpdates);
await Actor.updateDocuments(actorsUpdates);
game.actors.forEach(actor => {
if (actor.token?.img && actor.token.img.match(regexOldPngJpg)) {
actor.update({ "token.img": convertImgToWebp(actor.token.img) });
}
const actorItemsToUpdate = prepareDocumentsImgUpdate(actor.items);
actor.updateEmbeddedDocuments('Item', actorItemsToUpdate);
});
}
}
class _10_0_16_MigrationSortsReserve extends Migration {
get code() { return "creation-item-sort-reserve"; }
get version() { return "10.0.16"; }
async migrate() {
await game.actors
.filter((actor) => actor.type == "personnage")
.filter((actor) => actor.system.reve?.reserve?.list?.length ?? 0 > 0)
.forEach(async (actor) => {
const sortsReserve = actor.system.reve.reserve.list.map(this.conversionSortReserve);
console.log(`${LOG_HEAD} Migration des sorts en réserve de ${actor.name}`, sortsReserve);
await actor.createEmbeddedDocuments("Item", sortsReserve, {
renderSheet: false,
});
await actor.update({ 'system.reve.reserve': undefined })
});
}
conversionSortReserve(it) {
return {
type: 'sortreserve',
name: it.sort.name,
img: it.sort.img,
system: {
// ATTENTION, utilisation de data / _id possibles, encore présents pour les anciens sorts en réserve
sortid: it.sort._id,
draconic: it.sort.draconic,
ptreve: (it.sort.system ?? it.sort.data).ptreve_reel,
coord: it.coord,
heurecible: 'Vaisseau',
},
};
}
}
class _10_0_17_MigrationCompetenceCreature extends Migration {
get code() { return "competences-creature-parade"; }
get version() { return "10.0.17"; }
async migrate() {
await this.applyItemsUpdates(items => items
.filter(it => it.type == "competencecreature" && it.system.isparade && it.system.categorie_parade == "")
.map(it => { return { _id: it.id, "system.categorie_parade": "armes-naturelles" } }));
await this.applyItemsUpdates(items => items
.filter(it => it.type == "competencecreature" && it.system.iscombat)
.map(it => { return { _id: it.id, "system.categorie": (Grammar.includesLowerCaseNoAccent(it.name, "lancee") ? "lancer" : "melee") } })
);
}
}
class _10_0_21_VehiculeStructureResistanceMax extends Migration {
get code() { return "vehicule-structure-resistance-max"; }
get version() { return "10.0.21"; }
async migrate() {
await game.actors
.filter((actor) => actor.type == "vehicule")
.forEach(async (actor) => {
await actor.update({
'system.etat.resistance.value': actor.system.resistance,
'system.etat.resistance.max': actor.system.resistance,
'system.etat.structure.value': actor.system.structure,
'system.etat.structure.max': actor.system.structure
})
});
}
}
class _10_0_33_MigrationNomsDraconic extends Migration {
get code() { return "competences-creature-parade"; }
get version() { return "10.0.33"; }
migrationNomDraconic(ancien) {
if (typeof ancien == 'string') {
switch (ancien) {
case 'oniros': case "Voie d'Oniros": return "Voie d'Oniros";
case 'hypnos': case "Voie d'Hypnos": return "Voie d'Hypnos";
case 'narcos': case "Voie de Narcos": return "Voie de Narcos";
case 'thanatos': case "Voie de Thanatos": return "Voie de Thanatos";
}
return ancien;
}
else if (typeof ancien.name == 'string') {
return this.migrationNomDraconic(ancien.name)
}
return ancien;
}
async migrate() {
await this.applyItemsUpdates(items => items
.filter(it => ["sort", "sortreserve"].includes(it.type)
&& (typeof it.system.draconic == 'string') || (typeof it.system.draconic?.name == 'string'))
.map(it => { return { _id: it.id, "system.draconic": this.migrationNomDraconic(it.system.draconic) } }));
}
}
class _10_2_5_ArmesTirLancer extends Migration {
constructor() {
super();
this.dagues = { "system.competence": 'Dague', "system.lancer": 'Dague de jet', "system.portee_courte": 3, "system.portee_moyenne": 8, "system.portee_extreme": 15 }
this.javelot = { "system.competence": 'Lance', "system.lancer": 'Javelot', "system.portee_courte": 6, "system.portee_moyenne": 12, "system.portee_extreme": 20 }
this.fouet = { "system.competence": '', "system.lancer": 'Fouet', "system.portee_courte": 2, "system.portee_moyenne": 2, "system.portee_extreme": 3, "system.penetration": -1 }
this.arc = { "system.competence": '', "system.tir": 'Arc' }
this.arbalete = { "system.competence": '', "system.tir": 'Arbalète' }
this.fronde = { "system.competence": '', "system.tir": 'Fronde' }
this.mappings = {
'dague': { filter: it => true, updates: this.dagues },
'dague de jet': { filter: it => true, updates: this.dagues },
'javelot': { filter: it => true, updates: this.javelot },
'lance': { filter: it => it.name == 'Javeline', updates: this.javelot },
'fouet': { filter: it => true, updates: this.fouet },
'arc': { filter: it => true, updates: this.arc },
'arbalete': { filter: it => true, updates: this.arbalete },
'fronde': { filter: it => true, updates: this.fronde },
}
}
get code() { return "separation-competences-tir-lancer"; }
get version() { return "10.2.5"; }
migrateArmeTirLancer(it) {
let updates = mergeObject({ _id: it.id }, this.getMapping(it).updates);
console.log(it.name, updates);
return updates;
}
async migrate() {
await this.applyItemsUpdates(items => items
.filter(it => "arme" == it.type)
.filter(it => this.isTirLancer(it))
.filter(it => this.getMapping(it).filter(it))
.map(it => this.migrateArmeTirLancer(it)));
}
isTirLancer(it) {
return Object.keys(this.mappings).includes(this.getCompKey(it));
}
getMapping(it) {
return this.mappings[this.getCompKey(it)];
}
getCompKey(it) {
return Grammar.toLowerCaseNoAccent(it.system.competence);
}
}
class _10_2_10_DesirLancinant_IdeeFixe extends Migration {
get code() { return "desir-lancinat-idee-fixe"; }
get version() { return "10.2.10"; }
migrateQueue(it) {
let categorie = undefined
let name = it.name
if (Grammar.toLowerCaseNoAccent(name).includes('desir')) {
categorie = 'lancinant';
name = it.name.replace('Désir lancinant : ', '');
}
if (Grammar.toLowerCaseNoAccent(name).includes('idee fixe')) {
categorie = 'ideefixe';
name = it.name.replace('Idée fixe : ', '')
}
return {
_id: it.id, name: name,
'system.ideefixe': undefined,
'system.lancinant': undefined,
'system.categorie': categorie
}
}
async migrate() {
await this.applyItemsUpdates(items => items
.filter(it => ['queue', 'ombre'].includes(it.type))
.map(it => this.migrateQueue(it))
);
}
}
class _10_3_0_Inventaire extends Migration {
get code() { return "migration-equipement-inventaire"; }
get version() { return "10.3.0"; }
async migrate() {
await this.applyItemsUpdates(items => {
return this._updatesMonnaies(items)
.concat(this._updatesNonEquipe(items))
.concat(this._updatesObjets(items))
});
}
_updatesNonEquipe(items) {
return items
.filter(it => ['munition'].includes(it.type))
.map(it => { return { _id: it.id, 'system.equipe': undefined } });
}
_updatesObjets(items) {
return items
.filter(it => ['objet'].includes(it.type))
.map(it => { return { _id: it.id, 'system.resistance': undefined, 'system.equipe': undefined } });
}
_updatesMonnaies(items) {
return items
.filter(it => ['monnaie'].includes(it.type) && it.system.valeur_deniers != undefined)
.map(it => { return { _id: it.id, 'system.cout': it.system.valeur_deniers / 100, 'system.valeur_deniers': undefined } });
}
}
class _10_3_0_FrequenceEnvironnement extends Migration {
get code() { return "migration-frequence-resources"; }
get version() { return "10.3.0"; }
async migrate() {
await this.applyItemsUpdates(items => items.filter(it => ['herbe', 'ingredient'].includes(it.type))
.map(it => this._updatesFrequences(it)));
}
_updatesFrequences(it) {
return {
_id: it.id,
'system.rarete': undefined,
'system.environnement': [{ milieu: it.system.milieu, rarete: it.system.rarete, frequence: Environnement.getFrequenceRarete(it.system.rarete, 'frequence') }]
}
}
}
class _10_3_17_Monnaies extends Migration {
constructor() {
super();
this.mapValeur = {
"Etain (1 denier)": { name: 'Denier (étain)', system: { cout: 0.01 } },
"Bronze (10 deniers)": { name: "Sou (bronze)", system: { cout: 0.1 } },
"Argent (1 sol)": { name: "Sol (argent)", system: { cout: 1 } },
"Or (10 sols)": { name: "Dragon (or)", system: { cout: 10 } }
};
}
get code() { return "migration-monnaies"; }
get version() { return "10.3.17"; }
async migrate() {
await this.applyItemsUpdates(items => this._updatesMonnaies(items));
}
_updatesMonnaies(items) {
return items
.filter(it => 'monnaie' == it.type)
.filter(it => this.mapValeur[it.name] != undefined)
.map(it => {
const correction = this.mapValeur[it.name];
return {
_id: it.id,
'name': correction.name,
'system.cout': correction.system.cout,
'system.valeur_deniers': undefined
}
});
}
}
class _10_4_6_ServicesEnCommerces extends Migration {
get code() { return "migration-service-acteurs"; }
get version() { return "10.4.6"; }
async migrate() {
const servicesToMigrate = game.items.filter(it => it.type == 'service');
servicesToMigrate.forEach(async service => {
const commerce = await this.convertServiceToCommerce(service);
await RdDBaseActor.create(commerce, { renderSheet: false });
await service.delete();
});
}
async convertServiceToCommerce(service) {
return {
name: service.name, img: service.img, type: 'commerce',
system: {
description: service.system.description,
notesmj: service.system.descriptionmj,
illimite: service.system.illimite
},
items: await this.transformInventaireCommerce(service)
}
}
async transformInventaireCommerce(service) {
const serviceItems = (service.system.items ?? []);
const commerceItems = await Promise.all(serviceItems.map(async (it) => { return await this.transformToItemBoutique(it); }));
return commerceItems.concat(Monnaie.monnaiesStandard());
}
async transformToItemBoutique(serviceRefItem) {
const item = await RdDItem.getCorrespondingItem(serviceRefItem);
const itemToCreate = {
name: item.name, img: item.img, type: item.type,
system: mergeObject({ cout: serviceRefItem.system.cout, quantite: serviceRefItem.system.quantite }, item.system, { overwrite: false })
};
return itemToCreate;
}
}
class _10_5_0_UpdatePeriodicite extends Migration {
get code() { return "migration-periodicite-poisons-maladies"; }
get version() { return "10.5.0"; }
async migrate() {
await this.applyItemsUpdates(items => this._updatePeriodicite(items));
}
_updatePeriodicite(items) {
return items.filter(it => ['poison', 'maladie'].includes(it.type))
.filter(it => it.system.periodicite != "")
.map(it => {
let [incubation, periodicite] = this.getPeriodicite(it);
const periode = periodicite.split(' ');
let unite = periode.length == 2
? RdDTimestamp.formulesPeriode().find(it => Grammar.includesLowerCaseNoAccent(periode[1], it.code))?.code
: undefined
if (unite && Number(periode[0])) {
return {
_id: it.id,
'system.periodicite': undefined,
'system.incubation': incubation,
'system.periode.nombre': Number.parseInt(periode[0]),
'system.periode.unite': unite
};
}
else {
return {
_id: it.id,
'system.periodicite': undefined,
'system.incubation': it.system.periodicite
};
}
}).filter(it => it != undefined);
}
getPeriodicite(it) {
let p = it.system.periodicite.split(/[\/\\]/);
switch (p.length) {
case 2: return [p[0].trim(), p[1].trim()];
case 1: return ["", it.system.periodicite.trim()];
default: return [it.system.periodicite.trim(), ""];
}
}
}
export class Migrations {
static getMigrations() {
return [
new _1_5_34_migrationPngWebp(),
new _10_0_16_MigrationSortsReserve(),
new _10_0_17_MigrationCompetenceCreature(),
new _10_0_21_VehiculeStructureResistanceMax(),
new _10_0_33_MigrationNomsDraconic(),
new _10_2_5_ArmesTirLancer(),
new _10_2_10_DesirLancinant_IdeeFixe(),
new _10_3_0_Inventaire(),
new _10_3_0_FrequenceEnvironnement(),
new _10_3_17_Monnaies(),
new _10_4_6_ServicesEnCommerces(),
new _10_5_0_UpdatePeriodicite(),
];
}
constructor() {
game.settings.register(SYSTEM_RDD, "systemMigrationVersion", {
name: "System Migration Version",
scope: "world",
config: false,
type: String,
default: "0.0.0",
});
}
migrate() {
const currentVersion = game.settings.get(SYSTEM_RDD, "systemMigrationVersion");
if (isNewerVersion(game.system.version, currentVersion)) {
//if (true) { /* comment previous and uncomment here to test before upgrade */
const migrations = Migrations.getMigrations().filter(m => isNewerVersion(m.version, currentVersion));
if (migrations.length > 0) {
migrations.sort((a, b) => this.compareVersions(a, b));
migrations.forEach(async (m) => {
ui.notifications.info(
`Executing migration ${m.code}: version ${currentVersion} is lower than ${m.version}`
);
await m.migrate();
});
ui.notifications.info(
`Migrations done, version will change to ${game.system.version}`
);
} else {
console.log(
LOG_HEAD +
`No migration needeed, version will change to ${game.system.version}`
);
}
game.settings.set(
SYSTEM_RDD,
"systemMigrationVersion",
game.system.version
);
} else {
console.log(LOG_HEAD + `No system version changed`);
}
}
compareVersions(a, b) {
return isNewerVersion(a.version, b.version) ? 1 : isNewerVersion(b.version, a.version) ? -1 : 0;
}
}

View File

@ -24,7 +24,7 @@ export class Misc {
} }
static sum() { static sum() {
return (a, b) => Number(a) + Number(b); return (a, b) => a + b;
} }
static ascending(orderFunction = x => x) { static ascending(orderFunction = x => x) {
@ -41,14 +41,6 @@ export class Misc {
return 0; return 0;
} }
static typeName(type, subType) {
return subType ? game.i18n.localize(`${type.toUpperCase()}.Type${Misc.upperFirst(subType)}`)
: '';
}
static arrayOrEmpty(items) {
return items?.length ? items : [];
}
/** /**
* Converts the value to an integer, or to 0 if undefined/null/not representing integer * Converts the value to an integer, or to 0 if undefined/null/not representing integer
* @param {*} value value to convert to an integer using parseInt * @param {*} value value to convert to an integer using parseInt
@ -76,23 +68,10 @@ export class Misc {
} }
} }
static indexLowercase(list) {
const obj = {};
const addToObj = (map, val) => {
const key = Grammar.toLowerCaseNoAccent(val);
if (key && !map[key]) map[key] = val
}
list.forEach(it => addToObj(obj, it))
return obj;
}
static concat(lists) {
return lists.reduce((a, b) => a.concat(b), []);
}
static classify(items, classifier = it => it.type) { static classify(items, classifier = it => it.type) {
let itemsBy = {} let itemsBy = {};
Misc.classifyInto(itemsBy, items, classifier) Misc.classifyInto(itemsBy, items, classifier);
return itemsBy return itemsBy;
} }
static classifyFirst(items, classifier) { static classifyFirst(items, classifier) {
@ -108,13 +87,13 @@ export class Misc {
static classifyInto(itemsBy, items, classifier = it => it.type) { static classifyInto(itemsBy, items, classifier = it => it.type) {
for (const item of items) { for (const item of items) {
const classification = classifier(item) const classification = classifier(item);
let list = itemsBy[classification]; let list = itemsBy[classification];
if (!list) { if (!list) {
list = [] list = [];
itemsBy[classification] = list itemsBy[classification] = list;
} }
list.push(item) list.push(item);
} }
} }
@ -123,11 +102,29 @@ export class Misc {
} }
static join(params, separator = '') { static join(params, separator = '') {
return params?.reduce(Misc.joining(separator)) ?? ''; return params.reduce((a, b) => a + separator + b);
} }
static joining(separator = '') {
return (a, b) => a + separator + b; static data(it) {
if (it instanceof Actor || it instanceof Item || it instanceof Combatant) {
return it.data;
}
return it;
}
static templateData(it) {
return Misc.data(it)?.data ?? {}
}
static getEntityTypeLabel(entity) {
const documentName = entity?.documentName;
const type = entity?.data.type;
if (documentName === 'Actor' || documentName === 'Item') {
const label = CONFIG[documentName]?.typeLabels?.[type] ?? type;
return game.i18n.has(label) ? game.i18n.localize(label) : t;
}
return type;
} }
static connectedGMOrUser(ownerId = undefined) { static connectedGMOrUser(ownerId = undefined) {
@ -137,27 +134,24 @@ export class Misc {
return Misc.firstConnectedGM()?.id ?? game.user.id; return Misc.firstConnectedGM()?.id ?? game.user.id;
} }
static isRollModeHiddenToPlayer() { static getUsers() {
switch (game.settings.get("core", "rollMode")) { return game.version ? game.users : game.users.entities;
case CONST.DICE_ROLL_MODES.BLIND:
case CONST.DICE_ROLL_MODES.SELF: return true;
}
return false
} }
static getActiveUser(id) { static getActiveUser(id) {
return game.users.find(u => u.id == id && u.active); return Misc.getUsers().find(u => u.id == id && u.active);
} }
static firstConnectedGM() { static firstConnectedGM() {
return game.users.filter(u => u.isGM && u.active).sort(Misc.ascending(u => u.id)).find(u => u.isGM && u.active); return Misc.getUsers().filter(u => u.isGM && u.active).sort(Misc.ascending(u => u.id)).find(u => u.isGM && u.active);
} }
static isOwnerPlayer(actor, user = undefined) { static isOwnerPlayer(actor, user=undefined) {
return actor.testUserPermission(user ?? game.user, CONST.DOCUMENT_PERMISSION_LEVELS.OWNER) return actor.testUserPermission(user ?? game.user, CONST.DOCUMENT_PERMISSION_LEVELS.OWNER)
} }
static isOwnerPlayerOrUniqueConnectedGM(actor, user = undefined) { static isOwnerPlayerOrUniqueConnectedGM(actor, user =undefined){
return Misc.isOwnerPlayer(actor, user) ?? Misc.isUniqueConnectedGM(); return Misc.isOwnerPlayer(actor, user) ?? Misc.isUniqueConnectedGM();
} }
@ -165,16 +159,12 @@ export class Misc {
* @returns true pour un seul utilisateur: le premier GM connecté par ordre d'id * @returns true pour un seul utilisateur: le premier GM connecté par ordre d'id
*/ */
static isUniqueConnectedGM() { static isUniqueConnectedGM() {
return game.user.id == Misc.firstConnectedGMId(); return game.user.id == Misc.firstConnectedGM()?.id;
}
static firstConnectedGMId() {
return Misc.firstConnectedGM()?.id;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static findPlayer(name) { static findPlayer(name) {
return Misc.findFirstLike(name, game.users, { description: 'joueur' }); return Misc.findFirstLike(name, Misc.getUsers(), { description: 'joueur' });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -227,4 +217,4 @@ export class Misc {
} }
return subset; return subset;
} }
} }

View File

@ -1,13 +1,72 @@
import { Misc } from "./misc.js"
import { RdDDice } from "./rdd-dice.js"; import { RdDDice } from "./rdd-dice.js";
import { SystemCompendiums } from "./settings/system-compendiums.js";
const poesieHautReve = [
{
reference: 'Le Ratier Bretonien',
extrait: `Le courant du Fleuve
<br>Te domine et te Porte
<br>Avant que tu te moeuves
<br>Combat le, ou il t'emporte`
},
{
reference: 'Incompatibilité, Charles Beaudelaire',
extrait: `Et lorsque par hasard une nuée errante
<br>Assombrit dans son vol le lac silencieux,
<br>On croirait voir la robe ou l'ombre transparente
<br>D'un esprit qui voyage et passe dans les cieux.`
},
{
reference: 'Au fleuve de Loire, Joachim du Bellay',
extrait: `Ô de qui la vive course
<br>Prend sa bienheureuse source,
<br>Dune argentine fontaine,
<br>Qui dune fuite lointaine,
<br>Te rends au sein fluctueux
<br>De lOcéan monstrueux`
},
{
reference: 'Denis Gerfaud',
extrait: `Et l'on peut savoir qui est le maître d'Oniros, c'est le Fleuve de l'Oubli.
Et l'on sait qui est le créateur du Fleuve de l'Oubli, c'est Hypnos et Narcos.
Mais l'on ne sait pas qui est le maître du Fleuve de l'Oubli,
sinon peut-être lui-même, ou peut-être Thanatos` },
{
reference: 'Denis Gerfaud',
extrait: `Narcos est la source du Fleuve de l'Oubli et Hypnos l'embouchure
Remonter le Fleuve est la Voie de la Nuit, la Voie du Souvenir.
Descendre le Fleuve est la Voie du Jour, la Voie de l'Oubli`
},
{
reference: 'Denis Gerfaud',
extrait: `Narcos engendre le fils dont il est la mère à l'heure du Vaisseau,
car Oniros s'embarque pour redescendre le Fleuve
vers son père Hypnos sur la Voie de l'Oubli`
},
{
reference: 'Denis Gerfaud',
extrait: `Hypnos engendre le fils dont il est la mère à l'heure du Serpent, car
tel les serpents, Oniros commence à remonter le Fleuve
sur le Voie du Souvenir vers son père Narcos`
},
{
reference: 'Denis Gerfaud',
extrait: `Ainsi se succèdent les Jours et les Ages.
<br>Les jours des Dragons sont les Ages des Hommes.`
},
{
reference: 'Denis Gerfaud',
extrait: `Ainsi parlent les sages:
&laquo;Les Dragons sont créateurs de leurs rêves, mais ils ne sont pas créateurs d'Oniros
Les Dragons ne sont pas les maîtres de leurs rêvezs, car ils ne sont pas maîtres d'Oniros.
Nul ne sait qui est le créateur des Dragons, ni qui est leur maître.
Mais l'on peut supposer qui est le maître du Rêve des Dragons, c'est Oniros&raquo;`
},
]
export class Poetique { export class Poetique {
static async getExtrait() { static async getExtrait(){
const items = await SystemCompendiums.getItems('extrait-poetique', 'extraitpoetique') return await RdDDice.rollOneOf(poesieHautReve);
const selected = await RdDDice.rollOneOf(items);
return {
reference: selected?.name,
extrait: selected?.system.extrait
}
} }
}
}

44
module/poetique.txt Normal file
View File

@ -0,0 +1,44 @@
Le courant du Fleuve
Te domine et te Porte
Avant que tu te moeuves
Combat le, ou il t'emporte
A vous qui faites ripaille
sourds aux damnés de la faim
à vous qui livrez
une inégale bataille
à ceux qui vous tendent la main
Ils sont tout près ! - Tenons fermée
<br>Cette salle, où nous les narguons.
<br>Quel bruit dehors ! Hideuse armée
<br>De vampires et de dragons !
<br>La poutre du toit descellée
<br>Ploie ainsi qu'une herbe mouillée,
<br>Et la vieille porte rouillée
<br>Tremble, à déraciner ses gonds !`),
https://www.poetica.fr/poeme-1423/guy-de-maupassant-le-sommeil-du-mandarin/
Le monde est un rêve de Dragons. Nous
ne savons pas qui sont les Dragons ni à quoi
ils ressemblent, en dépit de lantique iconographie qui les dépeint comme de gigantesques créatures ailées capables de cracher
feu et flammes.
Car parmi les humains, autre nom lui est donné,
Nom sinistre parmi tous, nom funèbre, c'est la mort!
Un ami disparu... Thanatos est passé...
Messieurs, ne crachez pas de jurons ni d'ordure
Au visage fardé de cette pauvre impure
Que déesse Famine a par un soir d'hiver,
Contrainte à relever ses jupons en plein air.

View File

@ -7,9 +7,9 @@ const matchOperationTerms = new RegExp(/@(\w*){([\w\-]+)}/i);
export class RdDAlchimie { export class RdDAlchimie {
/* -------------------------------------------- */ /* -------------------------------------------- */
static processManipulation(recette, actorId = undefined) { static processManipulation(recetteData, actorId = undefined) {
//console.log("CALLED", recette, recette.isOwned, actorId ); //console.log("CALLED", recette, recette.isOwned, actorId );
let manip = recette.system.manipulation; let manip = recetteData.data.manipulation;
let matchArray = manip.match(matchOperations); let matchArray = manip.match(matchOperations);
if (matchArray) { if (matchArray) {
for (let matchStr of matchArray) { for (let matchStr of matchArray) {
@ -17,12 +17,12 @@ export class RdDAlchimie {
//console.log("RESULT ", result); //console.log("RESULT ", result);
if (result[1] && result[2]) { if (result[1] && result[2]) {
let commande = Misc.upperFirst(result[1]); let commande = Misc.upperFirst(result[1]);
let replacement = this[`_alchimie${commande}`](recette, result[2], actorId); let replacement = this[`_alchimie${commande}`](recetteData, result[2], actorId);
manip = manip.replace(result[0], replacement); manip = manip.replace(result[0], replacement);
} }
} }
} }
recette.system.manipulation_update = manip; recetteData.data.manipulation_update = manip;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */

View File

@ -3,37 +3,26 @@
* Extend the base Dialog entity by defining a custom window to perform roll. * Extend the base Dialog entity by defining a custom window to perform roll.
* @extends {Dialog} * @extends {Dialog}
*/ */
export class RdDAstrologieEditeur extends Dialog { export class RdDAstrologieEditeur extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
constructor(html, calendrier, calendrierData) { constructor(html, calendrier, calendrierData) {
let myButtons = { let myButtons = {
resetButton: { label: "Re-tirer les nombres astraux", callback: html => this.resetNombreAstraux() }, resetButton: { label: "Re-tirer les nombres astraux", callback: html => this.resetNombreAstraux() },
saveButton: { label: "Fermer", callback: html => this.fillData() } saveButton: { label: "Fermer", callback: html => this.fillData() }
}; };
// Common conf // Common conf
let dialogConf = { content: html, title: "Editeur d'Astrologie", buttons: myButtons, default: "saveButton" }; let dialogConf = { content: html, title: "Editeur d'Astrologie", buttons: myButtons, default: "saveButton" };
let dialogOptions = { let dialogOptions = { classes: ["rdddialog"], width: 600, height: 300, 'z-index': 99999 }
classes: ["rdd-roll-dialog"], width: 600,
height: 'fit-content',
'max-height': 800,
'z-index': 99999
}
super(dialogConf, dialogOptions) super(dialogConf, dialogOptions)
this.calendrier = calendrier; this.calendrier = calendrier;
this.updateData(calendrierData); this.updateData( calendrierData );
} }
activateListeners(html) { /* -------------------------------------------- */
super.activateListeners(html);
this.html = html;
}
/* -------------------------------------------- */
async resetNombreAstraux() { async resetNombreAstraux() {
game.system.rdd.calendrier.resetNombreAstral(); game.system.rdd.calendrier.resetNombreAstral();
await game.system.rdd.calendrier.rebuildListeNombreAstral(); await game.system.rdd.calendrier.rebuildListeNombreAstral();
@ -41,13 +30,24 @@ export class RdDAstrologieEditeur extends Dialog {
game.system.rdd.calendrier.showAstrologieEditor(); game.system.rdd.calendrier.showAstrologieEditor();
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
fillData() { fillData( ) {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
updateData(calendrierData) { updateData( calendrierData ) {
this.calendrierData = duplicate(calendrierData); this.calendrierData = duplicate(calendrierData);
} }
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
let astrologieData = this.astrologieData;
$(function () {
});
}
} }

View File

@ -10,61 +10,51 @@ import { SYSTEM_SOCKET_ID } from "./constants.js";
export class RdDAstrologieJoueur extends Dialog { export class RdDAstrologieJoueur extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
static async create(actor) { static async create(actor, dialogConfig) {
let dialogData = { let data = {
nombres: this.organizeNombres(actor), nombres: this.organizeNombres(actor),
dates: game.system.rdd.calendrier.getJoursSuivants(10), dates: game.system.rdd.calendrier.getJoursSuivants(10),
etat: actor.getEtatGeneral(), etat: actor.getEtatGeneral(),
ajustementsConditions: CONFIG.RDD.ajustementsConditions, ajustementsConditions: CONFIG.RDD.ajustementsConditions,
astrologie: RdDItemCompetence.findCompetence(actor.items, 'Astrologie') astrologie: RdDItemCompetence.findCompetence(actor.data.items, 'Astrologie')
} }
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-astrologie-joueur.html', dialogData); const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-astrologie-joueur.html', data);
let options = { classes: ["rdddialog"], width: 600, height: 500, 'z-index': 99999 };
const options = { classes: ["rdd-roll-dialog"], width: 600, height: 'fit-content', 'z-index': 99999 }; if (dialogConfig.options) {
const dialog = new RdDAstrologieJoueur(html, actor, dialogData, options); mergeObject(options, dialogConfig.options, { overwrite: true });
dialog.render(true); }
return new RdDAstrologieJoueur(html, actor, data);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
constructor(html, actor, dialogData, dialogOptions) { constructor(html, actor, data) {
const dialogConf = {
title: "Nombres Astraux", let myButtons = {
content: html, saveButton: { label: "Fermer", callback: html => this.quitDialog() }
default: "saveButton",
buttons: {
saveButton: { label: "Fermer", callback: html => this.quitDialog() }
},
}; };
// Get all n
// Common conf
let dialogConf = { content: html, title: "Nombres Astraux", buttons: myButtons, default: "saveButton" };
let dialogOptions = { classes: ["rdddialog"], width: 600, height: 300, 'z-index': 99999 };
super(dialogConf, dialogOptions); super(dialogConf, dialogOptions);
this.actor = actor; this.actor = actor;
this.dataNombreAstral = duplicate(dialogData); this.dataNombreAstral = duplicate(data);
}
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
this.html = html;
this.html.find("[name='diffConditions']").val(0);
this.html.find('[name="jet-astrologie"]').click((event) => {
this.requestJetAstrologie();
});
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static organizeNombres(actor) { static organizeNombres(actor) {
let itemNombres = actor.listItems('nombreastral'); let itemNombres = actor.listItemsData('nombreastral');
let itemFiltered = {}; let itemFiltered = {};
for (let item of itemNombres) { for (let item of itemNombres) {
if (itemFiltered[item.system.jourindex]) { if (itemFiltered[item.data.jourindex]) {
itemFiltered[item.system.jourindex].listValues.push(item.system.value); itemFiltered[item.data.jourindex].listValues.push(item.data.value);
} else { } else {
itemFiltered[item.system.jourindex] = { itemFiltered[item.data.jourindex] = {
listValues: [item.system.value], listValues: [item.data.value],
jourlabel: item.system.jourlabel jourlabel: item.data.jourlabel
} }
} }
} }
@ -73,21 +63,21 @@ export class RdDAstrologieJoueur extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
requestJetAstrologie() { requestJetAstrologie() {
let socketData = { let data = {
id: this.actor.id, id: this.actor.data._id,
carac_vue: this.actor.system.carac['vue'].value, carac_vue: Misc.data(this.actor).data.carac['vue'].value,
etat: this.dataNombreAstral.etat, etat: this.dataNombreAstral.etat,
astrologie: this.dataNombreAstral.astrologie, astrologie: this.dataNombreAstral.astrologie,
conditions: this.html.find('[name="diffConditions"]').val(), conditions: $("#diffConditions").val(),
date: this.html.find('[name="joursAstrologie"]').val(), date: $("#joursAstrologie").val(),
userId: game.user.id userId: game.user.id
} }
if (Misc.isUniqueConnectedGM()) { if (Misc.isUniqueConnectedGM()) {
game.system.rdd.calendrier.requestNombreAstral(socketData); game.system.rdd.calendrier.requestNombreAstral(data);
} else { } else {
game.socket.emit(SYSTEM_SOCKET_ID, { game.socket.emit(SYSTEM_SOCKET_ID, {
msg: "msg_request_nombre_astral", msg: "msg_request_nombre_astral",
data: socketData data: data
}); });
} }
this.close(); this.close();
@ -97,4 +87,17 @@ export class RdDAstrologieJoueur extends Dialog {
quitDialog() { quitDialog() {
} }
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
$(function () {
$("#diffConditions").val(0);
});
html.find('#jet-astrologie').click((event) => {
this.requestJetAstrologie();
});
}
} }

View File

@ -20,7 +20,7 @@ export class RdDBonus {
static isAjustementAstrologique(rollData) { static isAjustementAstrologique(rollData) {
return RdDCarac.isChance(rollData.selectedCarac) || return RdDCarac.isChance(rollData.selectedCarac) ||
rollData.selectedSort?.system.isrituel; rollData.selectedSort?.data.isrituel;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static isDefenseAttaqueFinesse(rollData) { static isDefenseAttaqueFinesse(rollData) {
@ -68,23 +68,23 @@ export class RdDBonus {
} }
return isCauchemar ? "cauchemar" return isCauchemar ? "cauchemar"
: rollData.dmg?.mortalite : rollData.dmg?.mortalite
?? rollData.arme?.system.mortalite ?? rollData.arme?.data.mortalite
?? "mortel"; ?? "mortel";
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static _dmgArme(rollData) { static _dmgArme(rollData) {
if ( rollData.arme) { if ( rollData.arme) {
let dmgBase = rollData.arme.system.dommagesReels ?? Number(rollData.arme.system.dommages ?? 0); let dmgBase = rollData.arme.data.dommagesReels ?? Number(rollData.arme.data.dommages ?? 0);
//Le bonus dégats magiques ne peut pas faire dépasser le bonus de l'arme (cf p.278) //Le bonus dégats magiques ne peut pas faire dépasser le bonus de l'arme (cf p.278)
return dmgBase + Math.min(dmgBase, rollData.arme.system.magique ? rollData.arme.system.ecaille_efficacite : 0); return dmgBase + Math.min(dmgBase, rollData.arme.data.magique ? rollData.arme.data.ecaille_efficacite : 0);
} }
return 0; return 0;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static _peneration(rollData) { static _peneration(rollData) {
return parseInt(rollData.arme?.system.penetration ?? 0); return parseInt(rollData.arme?.data.penetration ?? 0);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */

View File

@ -1,4 +1,4 @@
import { RdDTimestamp } from "./rdd-timestamp.js"; import { Misc } from "./misc.js";
/** /**
* Extend the base Dialog entity by defining a custom window to perform roll. * Extend the base Dialog entity by defining a custom window to perform roll.
@ -8,60 +8,50 @@ export class RdDCalendrierEditeur extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
constructor(html, calendrier, calendrierData) { constructor(html, calendrier, calendrierData) {
let dialogConf = {
content: html,
title: "Editeur de date/heure",
buttons: {
save: { label: "Enregistrer", callback: html => this.saveCalendrier() }
},
default: "save"
};
let dialogOptions = { classes: ["rdd-dialog-calendar-editor"], width: 400, height: 'fit-content', 'z-index': 99999 }
super(dialogConf, dialogOptions)
let myButtons = {
saveButton: { label: "Enregistrer", callback: html => this.fillData() }
};
// Common conf
let dialogConf = { content: html, title: "Editeur de date/heure", buttons: myButtons, default: "saveButton" };
let dialogOptions = { classes: ["rdddialog"], width: 400, height: 300, 'z-index': 99999 }
super(dialogConf, dialogOptions)
this.calendrier = calendrier; this.calendrier = calendrier;
this.calendrierData = calendrierData; this.calendrierData = calendrierData; //duplicate(calendrierData);
} }
/* -------------------------------------------- */
fillData( ) {
this.calendrierData.moisKey = $("#nomMois").val();
this.calendrierData.heureKey = $("#nomHeure").val();
this.calendrierData.jourMois = $("#jourMois").val();
this.calendrierData.minutesRelative = $("#minutesRelative").val();
console.log("UPDATE ", this.calendrierData);
this.calendrier.saveEditeur( this.calendrierData )
}
/* -------------------------------------------- */
updateData( calendrierData ) {
this.calendrierData = duplicate(calendrierData);
}
/* -------------------------------------------- */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
this.html = html;
let calendrierData = this.calendrierData;
this.html.find("input[name='calendar.annee']").val(this.calendrierData.annee); $(function () {
this.html.find("select[name='calendar.mois']").val(this.calendrierData.mois.key); console.log(calendrierData);
this.html.find("select[name='calendar.heure']").val(this.calendrierData.heure.key); $("#nomMois").val(calendrierData.moisKey);
RdDCalendrierEditeur.setLimited(this.html.find("input[name='calendar.jourDuMois']"), this.calendrierData.jourDuMois, 1, 28); $("#nomHeure").val(calendrierData.heureKey);
RdDCalendrierEditeur.setLimited(this.html.find("input[name='calendar.minute']"), this.calendrierData.minute, 0, 119); $("#jourMois").val(calendrierData.jourMois);
} $("#minutesRelative").val(calendrierData.minutesRelative);
static setLimited(input, init, min, max) {
input.val(init);
input.change(event => {
const val = Number.parseInt(input.val());
if (val < min) {
input.val(min);
}
if (val > max) {
input.val(max);
}
}); });
} }
/* -------------------------------------------- */
saveCalendrier() {
const annee = Number.parseInt(this.html.find("input[name='calendar.annee']").val());
const mois = this.html.find("select[name='calendar.mois']").val();
const jour = Number.parseInt(this.html.find("input[name='calendar.jourDuMois']").val());
const heure = this.html.find("select[name='calendar.heure']").val();
const minute = Number.parseInt(this.html.find("input[name='calendar.minute']").val());
this.calendrier.setNewTimestamp(RdDTimestamp.timestamp(annee, mois, jour, heure, minute))
}
/* -------------------------------------------- */
updateData(calendrierData) {
this.calendrierData = duplicate(calendrierData);
}
} }

Some files were not shown because too many files have changed in this diff Show More