Cleanup - preparation Coeur

Simplification de code:
- des Méthodes simples sur une ligne
- utilisation de item.update au lieu de updateEmbeddedDocuments
  quand possibe
- renommage des templates SubActeur
- déplacement de logs quand compétence non trouvée
This commit is contained in:
Vincent Vandemeulebrouck 2023-11-21 16:03:26 +01:00
parent bfb7b9b6bf
commit b5db2a9ef3
27 changed files with 375 additions and 388 deletions

View File

@ -126,25 +126,20 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
this.actor.conjurerPossession(poss)
})
this.html.find('.subacteur-label a').click(async event => {
let actorId = RdDSheetUtility.getEventItemData(event, 'actor-id');
let actor = game.actors.get(actorId);
if (actor) {
actor.sheet.render(true);
}
});
this.html.find('.subacteur-coeur-toggle a').click(async event => {
const actorId = RdDSheetUtility.getEventItemData(event, 'actor-id')
const clickCoeurNombre = $(event.currentTarget).data("coeur-nombre")
this.toggleSubActeurCoeur(actorId, clickCoeurNombre)
})
this.html.find('.subacteur-open').click(async event => {
const subActorId = RdDSheetUtility.getEventItemData(event, 'subactor-id');
this.openSubActeur(subActorId);
})
this.html.find('.subacteur-delete').click(async event => {
const li = RdDSheetUtility.getEventElement(event);
const actorId = li.data("actor-id");
if (actorId) {
const subActor = game.actors.get(actorId);
RdDUtility.confirmerSuppressionSubacteur(this, subActor, li, () => {
console.log('Delete : ', subActor.id);
this.actor.removeSubacteur(subActor.id);
RdDUtility.slideOnDelete(this, li);
});
}
});
const subActorId = li.data("subactor-id");
this.deleteSubActeur(subActorId, li);
})
this.html.find('.experiencelog-delete').click(async event => {
const li = this.html.find(event.currentTarget)?.parents(".experiencelog");
const key = Number(li.data("key") ?? -1);
@ -286,9 +281,8 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
}
getBlessure(event) {
const itemId = this.html.find(event.currentTarget).parents(".item-blessure").data('item-id');
const blessure = this.actor.getItem(itemId, 'blessure');
return blessure;
const blessureId = this.html.find(event.currentTarget).parents(".item-blessure").data('item-id');
return this.actor.getItem(blessureId, 'blessure');
}
isCompetenceAffichable(competence) {
@ -302,6 +296,36 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
super._onDropActor(event, dragData);
}
openSubActeur(actorId) {
let actor = game.actors.get(actorId);
if (actor) {
actor.sheet.render(true);
}
}
deleteSubActeur(actorId, li) {
if (actorId) {
const subActor = game.actors.get(actorId);
RdDUtility.confirmSubActeurDelete(this, subActor, li, () => {
console.log('Delete : ', subActor.id);
this.actor.removeSubActeur(subActor.id);
RdDUtility.slideOnDelete(this, li);
});
}
}
toggleSubActeurCoeur(actorId, toggleCoeur) {
console.log(this.actor, 'toggleSubActeurCoeur', actorId, toggleCoeur)
const coeur = this.actor.getPointsCoeur(actorId)
if (toggleCoeur <= coeur) {
this.actor.jetDeMoral('malheureuse');
this.actor.setPointsCoeur(actorId, Math.max(0, coeur - 1))
}
else {
this.actor.setPointsCoeur(actorId, Math.min(4, toggleCoeur))
}
}
/* -------------------------------------------- */
async selectTypeOeuvreToCreate() {
let types = RdDItem.getTypesOeuvres();

View File

@ -83,29 +83,27 @@ export class RdDActor extends RdDBaseActorSang {
this.system.compteurs.chance.max = this.system.carac.chance.value;
}
$computeIsHautRevant() {
this.system.attributs.hautrevant.value = this.itemTypes['tete'].find(it => Grammar.equalsInsensitive(it.name, 'don de haut-reve'))
? "Haut rêvant"
: "";
}
/* -------------------------------------------- */
canReceive(item) {
return ![TYPES.competencecreature, TYPES.tarot, TYPES.service].includes(item.type)
}
/* -------------------------------------------- */
isPersonnage() { return true }
isHautRevant() { return this.system.attributs.hautrevant.value != "" }
getReveActuel() {
return Misc.toInt(this.system.reve?.reve?.value ?? this.carac.reve.value);
}
getChanceActuel() {
return Misc.toInt(this.system.compteurs.chance?.value ?? 10);
}
/* -------------------------------------------- */
getAgilite() { return Number(this.system.carac.agilite?.value ?? 0) }
getChance() { return Number(this.system.carac.chance?.value ?? 0) }
/* -------------------------------------------- */
getMoralTotal() {
return Number(this.system.compteurs.moral?.value ?? 0);
}
getReveActuel() { return Misc.toInt(this.system.reve?.reve?.value ?? this.carac.reve.value) }
getChanceActuel() { return Misc.toInt(this.system.compteurs.chance?.value ?? 10) }
getMoralTotal() { return Number(this.system.compteurs.moral?.value ?? 0) }
/* -------------------------------------------- */
getEtatGeneral(options = { ethylisme: false }) {
@ -130,41 +128,19 @@ export class RdDActor extends RdDBaseActorSang {
}
/* -------------------------------------------- */
getTache(id) {
return this.findItemLike(id, 'tache');
}
getMeditation(id) {
return this.findItemLike(id, 'meditation');
}
getChant(id) {
return this.findItemLike(id, 'chant');
}
getDanse(id) {
return this.findItemLike(id, 'danse');
}
getMusique(id) {
return this.findItemLike(id, 'musique');
}
getOeuvre(id, type = 'oeuvre') {
return this.findItemLike(id, type);
}
getJeu(id) {
return this.findItemLike(id, 'jeu');
}
getRecetteCuisine(id) {
return this.findItemLike(id, 'recettecuisine');
}
/* -------------------------------------------- */
getDraconicList() {
return this.itemTypes[TYPES.competence].filter(it => it.system.categorie == 'draconic')
}
/* -------------------------------------------- */
getBestDraconic() {
const list = this.getDraconicList()
.sort(Misc.descending(it => it.system.niveau))
return duplicate(list[0])
}
getTache(id) { return this.findItemLike(id, 'tache') }
getMeditation(id) { return this.findItemLike(id, 'meditation') }
getChant(id) { return this.findItemLike(id, 'chant') }
getDanse(id) { return this.findItemLike(id, 'danse') }
getMusique(id) { return this.findItemLike(id, 'musique') }
getOeuvre(id, type = 'oeuvre') { return this.findItemLike(id, type) }
getJeu(id) { return this.findItemLike(id, 'jeu') }
getRecetteCuisine(id) { return this.findItemLike(id, 'recettecuisine') }
/* -------------------------------------------- */
getDemiReve() { return this.system.reve.tmrpos.coord }
getDraconicList() { return this.itemTypes[TYPES.competence].filter(it => it.system.categorie == 'draconic') }
getBestDraconic() { return duplicate(this.getDraconicList().sort(Misc.descending(it => it.system.niveau)).find(it => true)) }
getDraconicOuPossession() {
return [...this.getDraconicList().filter(it => it.system.niveau >= 0),
super.getDraconicOuPossession()]
@ -172,36 +148,33 @@ export class RdDActor extends RdDBaseActorSang {
.find(it => true)
}
getDemiReve() {
return this.system.reve.tmrpos.coord;
}
/* -------------------------------------------- */
async verifierPotionsEnchantees() {
let potionsEnchantees = this.filterItems(it => it.type == 'potion' && it.system.categorie.toLowerCase().includes('enchant'));
for (let potion of potionsEnchantees) {
if (!potion.system.prpermanent) {
console.log(potion);
let newPr = (potion.system.pr > 0) ? potion.system.pr - 1 : 0;
let update = { _id: potion._id, 'system.pr': newPr };
const updated = await this.updateEmbeddedDocuments('Item', [update]); // Updates one EmbeddedEntity
async $perteRevePotionsEnchantees() {
let potions = this.itemTypes[TYPES.potion]
.filter(it => it.system.categorie.toLowerCase().includes('enchant') && !potion.system.prpermanent)
let messageData = {
pr: newPr,
const potionUpdates = Promise.all(potions.map(async potion => {
console.log(potion)
let nouveauReve = (potion.system.pr > 0) ? potion.system.pr - 1 : 0;
const message = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-potionenchantee-chateaudormant.html`, {
pr: nouveauReve,
alias: this.name,
potionName: potion.name,
potionImg: potion.img
}
})
ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-potionenchantee-chateaudormant.html`, messageData)
content: message
});
}
}
return { _id: potion._id, 'system.pr': nouveauReve };
}))
await this.updateEmbeddedDocuments('Item', potionUpdates);
}
/* -------------------------------------------- */
hasArmeeMeleeEquipee() { // Return true si l'acteur possède au moins 1 arme de mêlée équipée
/** --------------------------------------------
* @returns true si l'acteur possède au moins 1 arme de mêlée équipée
*/
hasArmeeMeleeEquipee() {
return this.itemTypes['arme'].find(it => it.system.equipe && it.system.competence != "")
}
@ -229,12 +202,12 @@ export class RdDActor extends RdDBaseActorSang {
}
/* -------------------------------------------- */
async grisReve(nGrisReve) {
async grisReve(nbJours) {
let message = {
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
content: `${nGrisReve} jours de gris rêve sont passés. `
content: `${nbJours} jours de gris rêve sont passés. `
};
for (let i = 0; i < nGrisReve; i++) {
for (let i = 0; i < nbJours; i++) {
await this.dormir(4, { grisReve: true });
await this._recuperationSante(message);
@ -252,7 +225,7 @@ export class RdDActor extends RdDBaseActorSang {
}
async _recuperationSante(message) {
const maladiesPoisons = this._maladiePoisons(message);
const maladiesPoisons = this.getMaladiePoisons();
const isMaladeEmpoisonne = maladiesPoisons.length > 0;
this._messageRecuperationMaladiePoisons(maladiesPoisons, message);
@ -260,9 +233,8 @@ export class RdDActor extends RdDBaseActorSang {
await this._recupererVie(message, isMaladeEmpoisonne);
}
_maladiePoisons(message) {
const actifs = this.items.filter(item => item.type == 'maladie' || (item.type == 'poison' && item.system.active));
return actifs;
getMaladiePoisons() {
return this.items.filter(item => item.type == 'maladie' || (item.type == 'poison' && item.system.active));
}
_messageRecuperationMaladiePoisons(maladiesPoisons, message) {
@ -275,15 +247,12 @@ export class RdDActor extends RdDBaseActorSang {
case 1: message.content += ` d'un mal inconnu`; break;
default: message.content += ` de ${nonIdentifies.length} maux inconnus`; break;
}
if (identifies.length > 0 && nonIdentifies.length > 0) { message.content += ' et' }
if (identifies.length > 0) {
if (nonIdentifies > 0) {
message.content += ' et';
} else {
message.content += ' de ' + identifies.map(it => it.name).reduce(Misc.joining(', '));
}
}
}
}
/* -------------------------------------------- */
async dormirChateauDormant() {
@ -300,7 +269,7 @@ export class RdDActor extends RdDBaseActorSang {
await this.retourSeuilDeReve(message);
await this.setBonusPotionSoin(0);
await this.retourSust(message);
await this.verifierPotionsEnchantees();
await this.$perteRevePotionsEnchantees();
if (message.content != "") {
message.content = `A la fin Chateau Dormant, ${message.content}<br>Un nouveau jour se lève`;
ChatMessage.create(message);
@ -794,10 +763,8 @@ export class RdDActor extends RdDBaseActorSang {
const toNiveau = compValue ?? RdDItemCompetence.getNiveauBase(competence.system.categorie, competence.getCategories());
this.notifyCompetencesTronc(competence, toNiveau);
const fromNiveau = competence.system.niveau;
await this.updateEmbeddedDocuments('Item', [{ _id: competence.id, 'system.niveau': toNiveau }]);
await competence.update({ 'system.niveau': toNiveau });
await ExperienceLog.add(this, XP_TOPIC.NIVEAU, fromNiveau, toNiveau, competence.name, true);
} else {
console.log("Competence not found", idOrName);
}
}
@ -821,13 +788,11 @@ export class RdDActor extends RdDBaseActorSang {
if (isNaN(toXp) || typeof (toXp) != 'number') toXp = 0;
const fromXp = competence.system.xp;
this.checkCompetenceXP(idOrName, toXp);
await this.updateEmbeddedDocuments('Item', [{ _id: competence.id, 'system.xp': toXp }]);
await competence.update({ 'system.xp': toXp });
await ExperienceLog.add(this, XP_TOPIC.XP, fromXp, toXp, competence.name, true);
if (toXp > fromXp) {
RdDUtility.checkThanatosXP(idOrName);
}
} else {
console.log("Competence not found", idOrName);
}
}
@ -837,23 +802,19 @@ export class RdDActor extends RdDBaseActorSang {
if (competence) {
if (isNaN(toXpSort) || typeof (toXpSort) != 'number') toXpSort = 0;
const fromXpSort = competence.system.xp_sort;
await this.updateEmbeddedDocuments('Item', [{ _id: competence.id, 'system.xp_sort': toXpSort }]);
await competence.update({ 'system.xp_sort': toXpSort });
await ExperienceLog.add(this, XP_TOPIC.XPSORT, fromXpSort, toXpSort, competence.name, true);
if (toXpSort > fromXpSort) {
RdDUtility.checkThanatosXP(idOrName);
}
} else {
console.log("Competence not found", idOrName);
}
}
/* -------------------------------------------- */
async updateCompetenceArchetype(idOrName, compValue) {
let competence = this.getCompetence(idOrName);
let competence = this.getCompetence(idOrName)
if (competence) {
await this.updateEmbeddedDocuments('Item', [{ _id: competence.id, 'system.niveau_archetype': Math.max(compValue ?? 0, 0) }]);
} else {
console.log("Competence not found", idOrName);
await competence.update({ 'system.niveau_archetype': Math.max(compValue ?? 0, 0) });
}
}
@ -909,12 +870,6 @@ export class RdDActor extends RdDBaseActorSang {
}
/* -------------------------------------------- */
$computeIsHautRevant() {
this.system.attributs.hautrevant.value = this.itemTypes['tete'].find(it => Grammar.equalsInsensitive(it.name, 'don de haut-reve'))
? "Haut rêvant"
: "";
}
malusEthylisme() {
return Math.min(0, (this.system.compteurs.ethylisme?.value ?? 0));
}
@ -2561,7 +2516,7 @@ export class RdDActor extends RdDBaseActorSang {
let item = this.getEmbeddedDocument('Item', itemID);
if (item?.isEquipable()) {
const isEquipe = !item.system.equipe;
await this.updateEmbeddedDocuments('Item', [{ _id: item.id, "system.equipe": isEquipe }]);
await item.update({ "system.equipe": isEquipe });
this.computeEncTotal();
if (isEquipe)
this.verifierForceMin(item);
@ -2677,85 +2632,106 @@ export class RdDActor extends RdDBaseActorSang {
}
/* -------------------------------------------- */
listeVehicules() {
const listeVehichules = this.system.subacteurs?.vehicules ?? [];
return this._buildActorLinksList(listeVehichules, vehicle => RdDActor._vehicleData(vehicle));
}
/* -------------------------------------------- */
listeSuivants() {
return this._buildActorLinksList(this.system.subacteurs?.suivants ?? []);
}
/* -------------------------------------------- */
listeMontures() {
return this._buildActorLinksList(this.system.subacteurs?.montures ?? []);
}
/* -------------------------------------------- */
_buildActorLinksList(links, actorTransformation = it => RdDActor._buildActorData(it)) {
return links.map(link => game.actors.get(link.id))
.filter(it => it != undefined)
.map(actorTransformation);
}
/* -------------------------------------------- */
static _vehicleData(vehicle) {
return {
id: vehicle.id,
name: vehicle.name,
img: vehicle.img,
system: {
categorie: vehicle.system.categorie,
etat: vehicle.system.etat
}
static $transformSubActeurSuivant = (suivant, link) => {
return mergeObject(RdDBaseActor.extractActorMin(suivant), {
coeur: link.coeur ?? 0
})
};
listeSuivants(filter = suivant => true) {
return RdDActor.$buildSubActorLinks(
this.system.subacteurs.suivants.filter(filter), RdDActor.$transformSubActeurSuivant
)
}
getSuivant(actorId) {
const suivant = this.system.subacteurs.suivants.find(it => it.id == actorId);
if (suivant) {
return RdDActor.$transformSubActeurSuivant(game.actors.get(actorId), suivant);
}
return undefined
}
/* -------------------------------------------- */
static _buildActorData(it) {
return { id: it.id, name: it.name, img: it.img };
static $transformSubActeurVehicule = (vehicle, link) => {
return mergeObject(RdDBaseActor.extractActorMin(vehicle), {
system: { categorie: vehicle.system.categorie, etat: vehicle.system.etat }
})
};
listeVehicules() {
return RdDActor.$buildSubActorLinks(this.system.subacteurs.vehicules, RdDActor.$transformSubActeurVehicule)
}
/* -------------------------------------------- */
async pushSubacteur(actor, dataArray, dataPath, dataName) {
let alreadyPresent = dataArray.find(attached => attached.id == actor._id);
if (!alreadyPresent) {
let newArray = duplicate(dataArray);
newArray.push({ id: actor._id });
await this.update({ [dataPath]: newArray });
} else {
ui.notifications.warn(dataName + " est déja attaché à ce Personnage.");
static $transformSubActeurCreature = (actor, link) => RdDBaseActor.extractActorMin(actor.id)
listeMontures() {
return RdDActor.$buildSubActorLinks(this.system.subacteurs.montures, RdDActor.$transformSubActeurCreature);
}
/* -------------------------------------------- */
static $buildSubActorLinks(subActors, actorTransformation = (actor, link) => undefined) {
if (!subActors) {
return []
}
return subActors.map(link => {
const actor = game.actors.get(link.id)
return actor ? actorTransformation(actor, link) : undefined
})
.filter(it => it != undefined)
.sort(Misc.ascending(it => it.name))
}
/* -------------------------------------------- */
addSubActeur(subActor) {
if (subActor?.id == this.id) {
ui.notifications.warn("Vous ne pouvez pas attacher un acteur à lui même")
if (!this.isAddSubActeurAllowed(subActor)) {
return
}
else if (!subActor?.isOwner) {
ui.notifications.warn("Vous n'avez pas les droits sur l'acteur que vous attachez.")
}
else {
const subActorOnlyId = { id: subActor._id };
if (subActor.type == 'vehicule') {
this.pushSubacteur(subActor, this.system.subacteurs.vehicules, 'system.subacteurs.vehicules', 'Ce Véhicule');
this.pushSubActeur(subActorOnlyId, this.system.subacteurs.vehicules, `system.subacteurs.vehicules`, `Le véhicule ${subActor.name}`)
} else if (subActor.type == 'creature') {
this.pushSubacteur(subActor, this.system.subacteurs.montures, 'system.subacteurs.montures', 'Cette Monture');
this.pushSubActeur(subActorOnlyId, this.system.subacteurs.montures, 'system.subacteurs.montures', `L'animal ${subActor.name}`)
} else if (subActor.type == 'personnage') {
this.pushSubacteur(subActor, this.system.subacteurs.suivants, 'system.subacteurs.suivants', 'Ce Suivant');
}
this.pushSubActeur(subActorOnlyId, this.system.subacteurs.suivants, 'system.subacteurs.suivants', `Le compagnon ${subActor.name}`)
}
}
/* -------------------------------------------- */
async removeSubacteur(actorId) {
let newVehicules = this.system.subacteurs.vehicules.filter(function (obj, index, arr) { return obj.id != actorId });
let newSuivants = this.system.subacteurs.suivants.filter(function (obj, index, arr) { return obj.id != actorId });
let newMontures = this.system.subacteurs.montures.filter(function (obj, index, arr) { return obj.id != actorId });
await this.update({ 'system.subacteurs.vehicules': newVehicules }, { renderSheet: false });
await this.update({ 'system.subacteurs.suivants': newSuivants }, { renderSheet: false });
await this.update({ 'system.subacteurs.montures': newMontures }, { renderSheet: false });
async pushSubActeur(subActor, dataArray, dataPath, dataName) {
let alreadyPresent = dataArray.find(attached => attached.id == subActor.id);
if (!alreadyPresent) {
let newArray = [...dataArray, subActor]
await this.update({ [dataPath]: newArray });
} else {
ui.notifications.warn(dataName + " est déja attaché à " + this.name);
}
}
isAddSubActeurAllowed(subActor) {
if (subActor?.id == undefined) {
ui.notifications.warn("Aucun acteur à ajouter")
return false
}
if (subActor?.id == this.id) {
ui.notifications.warn("Vous ne pouvez pas attacher un acteur à lui même")
return false
}
else if (!subActor?.isOwner) {
ui.notifications.warn("Vous n'avez pas les droits sur l'acteur que vous attachez.")
return false
}
return true
}
async deleteSubActeur(actorId) {
['vehicules', 'suivants', 'montures'].forEach(async type => {
const subList = this.system.subacteurs[type];
if (subList.find(it => it.id == actorId)) {
let newList = subList.filter(it => it.id != actorId)
await this.update({ [`system.subacteurs.${type}`]: newList }, { renderSheet: false });
}
})
}
/* -------------------------------------------- */

View File

@ -174,7 +174,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
}
const path = getFieldPath(fieldName);
if (path) {
await this.updateEmbeddedDocuments('Item', [{ _id: competence.id, [path]: value }]); // updates one EmbeddedEntity
await competence.update({ [path]: value });
}
}
}

View File

@ -15,7 +15,6 @@ export class RdDBaseActorSheet extends ActorSheet {
/** @override */
static get defaultOptions() {
RdDUtility.initAfficheContenu();
return mergeObject(ActorSheet.defaultOptions, {
classes: ["rdd", "sheet", "actor"],
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],

View File

@ -29,21 +29,10 @@ export class RdDBaseActor extends Actor {
return entry && entry.length > 0 ? carac[entry[0]] : undefined;
}
getCaracByName(name) {
switch (Grammar.toLowerCaseNoAccent(name)) {
case 'reve-actuel': case 'reve actuel':
return this.getCaracReveActuel();
case 'chance-actuelle': case 'chance-actuelle':
return this.getCaracChanceActuelle();
}
return RdDBaseActor._findCaracByName(this.system.carac, name);
}
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));
@ -98,12 +87,14 @@ export class RdDBaseActor extends Actor {
return game.actors.get(actorId)
}
static extractActorMin = (actor) => { return { id: actor?.id, type: actor?.type, name: actor?.name, img: actor?.img }; };
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:
* Cette 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.
@ -144,6 +135,17 @@ export class RdDBaseActor extends Actor {
super(docData, context);
}
getCaracByName(name) {
switch (Grammar.toLowerCaseNoAccent(name)) {
case 'reve-actuel': case 'reve actuel':
return this.getCaracReveActuel();
case 'chance-actuelle': case 'chance-actuelle':
return this.getCaracChanceActuelle();
}
return RdDBaseActor._findCaracByName(this.system.carac, name);
}
/* -------------------------------------------- */
/* -------------------------------------------- */
async _preCreate(data, options, user) {
await super._preCreate(data, options, user);
@ -184,7 +186,7 @@ export class RdDBaseActor extends Actor {
}
return undefined;
}
listeSuivants(filter = suivant => true) { return [] }
listItems(type = undefined) { return (type ? this.itemTypes[type] : this.items); }
filterItems(filter, type = undefined) { return (type ? this.itemTypes[type] : this.items)?.filter(filter) ?? []; }
findItemLike(idOrName, type) {
@ -242,7 +244,7 @@ export class RdDBaseActor extends Actor {
let item = this.getItem(id);
if (item && item.isInventaire()) {
const quantite = Math.max(0, item.system.quantite + value);
await this.updateEmbeddedDocuments('Item', [{ _id: item.id, 'system.quantite': quantite }]);
await item.update({ 'system.quantite': quantite });
}
}
@ -549,8 +551,7 @@ export class RdDBaseActor extends Actor {
}
/* -------------------------------------------- */
/** Ajoute un item dans un conteneur, sur la base
* de leurs ID */
/** Ajoute un item dans un conteneur, sur la base de leurs ID */
async ajouterDansConteneur(item, conteneur, onAjouterDansConteneur) {
if (!conteneur) {
// TODO: afficher
@ -558,10 +559,8 @@ export class RdDBaseActor extends Actor {
}
else if (conteneur.isConteneur()) {
item.estContenu = true;
await this.updateEmbeddedDocuments('Item', [{
_id: conteneur.id,
'system.contenu': [...conteneur.system.contenu, item.id]
}]);
const nouveauContenu = [...conteneur.system.contenu, item.id];
await conteneur.update({ 'system.contenu': nouveauContenu });
onAjouterDansConteneur(item.id, conteneur.id);
}
}
@ -621,10 +620,8 @@ export class RdDBaseActor extends Actor {
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)
}]);
const contenu = conteneur.system.contenu.filter(id => id != item.id);
await conteneur.update({ 'system.contenu': contenu });
onEnleverDeConteneur();
}
}
@ -645,20 +642,17 @@ export class RdDBaseActor extends Actor {
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
const newConteneurId = itemMap[item.conteneurId];
const newConteneur = this.getItem(newConteneurId);
const 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 }]);
const nouveauContenu = [...newConteneur.system.contenu, newItemId]
await newConteneur.update({ 'system.contenu': nouveauContenu })
}
}
for (let item of itemsList) {
await sourceActor.deleteEmbeddedDocuments('Item', [item.id]);
}
const deletedItemIds = itemsList.map(it => it.id)
await sourceActor.deleteEmbeddedDocuments('Item', deletedItemIds);
}
_buildMapOldNewId(itemsList, newItems) {

View File

@ -18,12 +18,11 @@ export class RdDCreature extends RdDBaseActorSang {
async remiseANeuf() {
await this.removeEffects(e => true);
await this.supprimerBlessures(it => true);
const updates = {
await this.update({
'system.sante.endurance.value': this.system.sante.endurance.max,
'system.sante.vie.value': this.system.sante.vie.max,
'system.sante.fatigue.value': 0
};
await this.update(updates);
});
}
async finDeRoundBlessures() {
@ -54,13 +53,11 @@ export class RdDCreature extends RdDBaseActorSang {
// déjà accordé
return;
}
resonnance.actors.push(attacker.id);
await this.update({ "system.sante.resonnance": resonnance });
await this.update({ "system.sante.resonnance": [...resonnance, attacker.id] });
}
else {
super.setEntiteReveAccordee(attacker)
}
}
}

View File

@ -45,18 +45,17 @@ export class RdDActorEntiteSheet extends RdDBaseActorReveSheet {
const actorId = li.data("actor-id");
if (actorId) {
const actorResonance = game.actors.get(actorId);
RdDUtility.confirmerSuppressionSubacteur(this, actorResonance, li, () => {
RdDUtility.confirmSubActeurDelete(this, actorResonance, li, () => {
console.log('Delete : ', actorId);
this.removeSubacteur(actorId);
this.deleteSubActeur(actorId);
RdDUtility.slideOnDelete(this, li);
});
}
});
}
async removeSubacteur(actorId) {
async deleteSubActeur(actorId) {
let newResonances = this.actor.system.sante.resonnance.actors.filter(id => id != actorId);
await this.actor.update({ 'system.sante.resonnance.actors': newResonances }, { renderSheet: false });
}
}

View File

@ -6,8 +6,6 @@ export class RdDActorVehiculeSheet extends RdDBaseActorSheet {
/** @override */
static get defaultOptions() {
RdDUtility.initAfficheContenu();
return mergeObject(RdDBaseActorSheet.defaultOptions, {
template: "systems/foundryvtt-reve-de-dragon/templates/actor-vehicule-sheet.html",
width: 640, height: 720,

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);
}
}
}

45
module/dialog-select.js Normal file
View File

@ -0,0 +1,45 @@
export class DialogSelect extends Dialog {
static extractIdNameImg(it) { return { id: it.id, name: it.name, img: it.img } }
static async select(selectData, onSelectChoice) {
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-select.html", selectData)
const dialogData = {
title: selectData.title ?? selectData.label,
content: html,
buttons: {}
}
const dialogOptions = {
classes: ["rdd-dialog-select"],
width: 'fit-content',
height: 'fit-content',
'max-height': 600,
'z-index': 99999
}
new DialogSelect(dialogData, dialogOptions, selectData, onSelectChoice).render(true)
}
constructor(dialogData, dialogOptions, selectionData, onSelectChoice) {
super(dialogData, dialogOptions)
this.selectionData = selectionData
this.onSelectChoice = onSelectChoice
}
activateListeners(html) {
super.activateListeners(html)
this.html = html
this.html.find("li.select-choice").click(event =>
this.choiceSelected(this.html.find(event.currentTarget)?.data("id"))
)
}
choiceSelected(selectedId) {
const selected = this.selectionData.find(it => it.id == selectedId)
this.close()
if (selected) {
this.onSelectChoice(selected)
}
}
}

View File

@ -205,6 +205,7 @@ export class Misc {
const subset = this.findAllLike(value, elements, options);
if (subset.length == 0) {
console.log(`Aucune ${options.description} pour ${value}`);
return undefined
}
if (subset.length == 1) {

View File

@ -36,20 +36,18 @@ export class RdDBonus {
/* -------------------------------------------- */
static dmg(rollData, dmgActor, isEntiteIncarnee = false) {
let dmg = { total: 0 };
if (rollData.arme && rollData.arme.name.toLowerCase() == "esquive") {
// Specific case management
ui.notifications.warn("Calcul de bonus dégats sur esquive !");
} else {
dmg.dmgArme = RdDBonus._dmgArme(rollData);
dmg.penetration = RdDBonus._peneration(rollData);
dmg.dmgTactique = RdDBonus.dmgBonus(rollData.tactique);
dmg.dmgParticuliere = RdDBonus._dmgParticuliere(rollData);
dmg.dmgSurprise = RdDBonus.dmgBonus(rollData.ajustements?.attaqueDefenseurSurpris.used);
dmg.dmgActor = rollData.selectedCarac ? RdDBonus._dmgPerso(dmgActor, rollData.selectedCarac.label, dmg.dmgArme) : 0;
dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere;
dmg.mortalite = RdDBonus._calculMortalite(rollData, isEntiteIncarnee)
const dmgArme = RdDBonus._dmgArme(rollData)
let dmg = {
total: 0,
dmgArme: dmgArme,
penetration: RdDBonus._peneration(rollData),
dmgTactique: RdDBonus.dmgBonus(rollData.tactique),
dmgParticuliere: RdDBonus._dmgParticuliere(rollData),
dmgSurprise: RdDBonus.dmgBonus(rollData.ajustements?.attaqueDefenseurSurpris.used),
mortalite: RdDBonus._calculMortalite(rollData, isEntiteIncarnee),
dmgActor: RdDBonus._dmgPerso(dmgActor, rollData.selectedCarac?.label, dmgArme)
}
dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere;
return dmg;
}
@ -93,6 +91,9 @@ export class RdDBonus {
/* -------------------------------------------- */
static _dmgPerso(dmgActor, categorie, dmgArme) {
if (categorie == undefined) {
return 0
}
switch (categorie) {
case "Tir": return 0;
case "Lancer": return Math.max(0, Math.min(dmgArme, dmgActor));

View File

@ -99,7 +99,8 @@ const definitionsEncaissement = {
/* -------------------------------------------- */
export class RdDUtility {
// persistent handling of conteneur show/hide
static afficheContenu = {}
/* -------------------------------------------- */
static async init() {
Hooks.on("renderChatMessage", async (app, html, msg) => RdDUtility.onRenderChatMessage(app, html, msg));
@ -165,9 +166,9 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/actor/inventaire.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/inventaire-item.html',
"systems/foundryvtt-reve-de-dragon/templates/actor/inventaire-monnaie.html",
'systems/foundryvtt-reve-de-dragon/templates/actor/liens-animaux.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/liens-suivants.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/liens-vehicules.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/liens-animaux.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/liens-suivants.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/liens-vehicules.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire-item.html',
//Items
@ -323,24 +324,16 @@ export class RdDUtility {
}
/* -------------------------------------------- */
static getNomEthylisme(niveauEthylisme) {
let index = -niveauEthylisme;
return index < 0 ? 'Aucun' : nomEthylisme[index];
}
static getNomEthylisme(niveauEthylisme) { return niveauEthylisme > 0 ? 'Aucun' : nomEthylisme[-niveauEthylisme] }
/* -------------------------------------------- */
static initAfficheContenu() { // persistent handling of conteneur show/hide
if (!this.afficheContenu)
this.afficheContenu = {};
}
/* -------------------------------------------- */
static toggleAfficheContenu(conteneurId) {
this.afficheContenu[conteneurId] = !this.afficheContenu[conteneurId];
RdDUtility.afficheContenu[conteneurId] = !RdDUtility.afficheContenu[conteneurId];
}
/* -------------------------------------------- */
static getAfficheContenu(conteneurId) {
if (conteneurId)
return this.afficheContenu[conteneurId];
return RdDUtility.afficheContenu[conteneurId];
return undefined;
}
@ -651,8 +644,8 @@ export class RdDUtility {
/* -------------------------------------------- */
static async chatListeners(html) {
RdDCombat.registerChatCallbacks(html);
RdDEmpoignade.registerChatCallbacks(html);
RdDCombat.registerChatCallbacks(html)
RdDEmpoignade.registerChatCallbacks(html)
// Gestion spécifique message passeurs
html.on("click", '.tmr-passeur-coord a', event => {
@ -811,7 +804,7 @@ export class RdDUtility {
}
/* -------------------------------------------- */
static confirmerSuppressionSubacteur(sheet, subActor, htmlToDelete, onSuppression = ()=>{}) {
static confirmSubActeurDelete(sheet, subActor, htmlToDelete, onSuppression = ()=>{}) {
RdDConfirm.confirmer({
settingConfirmer: "confirmation-supprimer-lien-acteur",
content: `<p>Etes vous certain de vouloir supprimer le lien vers ${subActor.name} ?</p>`,

View File

@ -301,11 +301,12 @@ export class CompendiumTableHelpers {
table,
isGM: game.user.isGM,
});
ChatMessage.create({
const messageData = {
user: game.user.id,
whisper: game.user.id,
content: flavorContent
}, { rollMode: "gmroll" });
};
ChatMessage.create(messageData, { rollMode: "gmroll" });
}
}

View File

@ -1,5 +1,5 @@
import { ENTITE_NONINCARNE } from "./constants.js";
import { DialogSelectTarget } from "./dialog-select-target.js";
import { DialogSelect } from "./dialog-select.js";
export class Targets {
static listTargets() {
@ -11,10 +11,7 @@ export class Targets {
}
static extractTokenData(target) {
if (!target) {
return undefined
}
return { id: target.id, name: target.document.name, img: target.document.texture.src ?? target.actor.img ?? 'icons/svg/mystery-man.svg' };
return { id: target?.id, name: target?.document.name, img: target?.document.texture.src ?? target?.actor.img ?? 'icons/svg/mystery-man.svg' };
}
static isTargetEntite(target) {
@ -30,11 +27,12 @@ export class Targets {
return;
default:
{
const tokens = targets.map(it => Targets.extractTokenData(it))
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-select-target.html", {
tokens: tokens
});
new DialogSelectTarget(html, onSelectTarget, targets).render(true);
const selectData = {
title: "Choisir une cible",
label: "Choisir une seule des cibles",
list: targets.map(it => Targets.extractTokenData(it))
};
DialogSelect.select(selectData, onSelectTarget);
}
}
}

View File

@ -4,10 +4,6 @@ import { PixiTMR } from "./pixi-tmr.js";
export class CarteTmr extends Draconique {
constructor() {
super();
}
type() { return '' }
match(item) { return false; }
manualMessage() { return false }

View File

@ -135,7 +135,7 @@ section.window-content div.dialog-buttons {
.strong-text {
font-weight: bold;
}
i:is(.fas, .far) {
i:is(.fas, .far, .fa-solid, .fa-regular, .fa-sharp ) {
font-size: smaller;
}
@ -199,6 +199,7 @@ i:is(.fas, .far) {
object-fit: scale-down;
object-position: 50% 0;
margin: 0.1rem;
object-fit: contain;
}
.system-foundryvtt-reve-de-dragon .rdd-item-sheet-tarot img.profile-img {
@ -210,6 +211,7 @@ i:is(.fas, .far) {
border: none;
margin-right: 5px;
object-position: 50% 0;
object-fit: contain;
}
.system-foundryvtt-reve-de-dragon img.equipement-inutilisable {
vertical-align: bottom ;
@ -526,7 +528,7 @@ input:is(.blessure-premiers_soins, .blessure-soins_complets) {
text-shadow: 1px 1px 4px rgba(60, 60, 60, 1);
}
.rdd-dialog-select-target img.select-token-img {
.rdd-dialog-select img.select-img {
-webkit-box-flex: 0;
-ms-flex: 0 0 48px;
flex: 0 0 48px;
@ -538,7 +540,7 @@ input:is(.blessure-premiers_soins, .blessure-soins_complets) {
vertical-align: baseline;
}
.rdd-dialog-select-target li.select-target {
.rdd-dialog-select li.select-choice {
vertical-align: baseline;
padding: 0.1rem;
}
@ -1528,6 +1530,8 @@ table.table-nombres-astraux tr:hover {
float: left;
max-width: 64px;
max-height: 64px;
height: 100%;
object-fit: contain;
}
#sidebar-tabs {

View File

@ -140,10 +140,8 @@
<div class="tab items" data-group="primary" data-tab="items">
{{> "systems/foundryvtt-reve-de-dragon/templates/actor/inventaire-monnaie.html"}}
{{> "systems/foundryvtt-reve-de-dragon/templates/actor/inventaire.html"}}
{{> "systems/foundryvtt-reve-de-dragon/templates/actor/liens-animaux.html"}}
{{> "systems/foundryvtt-reve-de-dragon/templates/actor/liens-suivants.html"}}
{{> "systems/foundryvtt-reve-de-dragon/templates/actor/liens-vehicules.html"}}
{{> "systems/foundryvtt-reve-de-dragon/templates/actor/liens-animaux.hbs"}}
{{> "systems/foundryvtt-reve-de-dragon/templates/actor/liens-vehicules.hbs"}}
</div>
{{!-- Biography Tab --}}
@ -202,6 +200,10 @@
</ul>
</article>
<article class="flexcol">
{{> "systems/foundryvtt-reve-de-dragon/templates/actor/liens-suivants.hbs"}}
</article>
<article class="flexcol">
<h3>Biographie : </h3>
<div class="form-group large-editor">

View File

@ -1,9 +1,9 @@
<span class="item-name"><h4>Compagnons animaux</h4></span>
<ul class="item-list alterne-list">
{{#each subacteurs.montures as |monture id|}}
<li class="item flexrow list-item" data-actor-id="{{monture.id}}">
<img class="sheet-competence-img" src="{{monture.img}}" title="{{monture.name}}"/>
<span class="subacteur-label"><a>{{monture.name}}</a></span>
<li class="item flexrow list-item" data-subactor-id="{{monture.id}}">
<img class="sheet-competence-img subacteur-open" src="{{monture.img}}" title="{{monture.name}}"/>
<span class="subacteur-label subacteur-open"><a>{{monture.name}}</a></span>
<div class="flex-shrink">
<a class="subacteur-delete" title="Supprimer"><i class="fas fa-trash"></i></a>
</div>

View File

@ -0,0 +1,14 @@
<h4>Suivants/Compagnons/Amoureux</h4>
<ul class="item-list alterne-list">
{{#each subacteurs.suivants as |suivant id|}}
<li class="item flexrow list-item" data-subactor-id="{{suivant.id}}">
<img class="sheet-competence-img subacteur-open" src="{{suivant.img}}" title="{{suivant.name}}"/>
<span class="competence-title subacteur-label subacteur-open">
<a>{{suivant.name}}</a>
</span>
<div class="item-controls flex-shrink">
<a class="subacteur-delete" title="Supprimer"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/each}}
</ul>

View File

@ -1,12 +0,0 @@
<span class="item-name"><h4>Suivants</h4></span>
<ul class="item-list alterne-list">
{{#each subacteurs.suivants as |suivant id|}}
<li class="item flexrow list-item" data-actor-id="{{suivant.id}}">
<img class="sheet-competence-img" src="{{suivant.img}}" title="{{suivant.name}}"/>
<span class="competence-title subacteur-label"><a>{{suivant.name}}</a></span>
<div class="item-controls flex-shrink">
<a class="subacteur-delete" title="Supprimer"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/each}}
</ul>

View File

@ -11,13 +11,9 @@
</li>
{{#each subacteurs.vehicules as |vehicule id|}}
<li class="item flexrow list-item" data-actor-id="{{vehicule.id}}">
<span class="subacteur-label">
<a>
<img class="sheet-competence-img" src="{{vehicule.img}}" title="{{vehicule.name}}"/>
{{vehicule.name}}
</a>
</span>
<li class="item flexrow list-item" data-subactor-id="{{vehicule.id}}">
<img class="sheet-competence-img subacteur-open" src="{{vehicule.img}}" title="{{vehicule.name}}"/>
<span class="subacteur-label subacteur-open"><a>{{vehicule.name}}</a></span>
<span>{{vehicule.system.categorie}}</span>
<span>{{vehicule.system.etat.resistance.max}}</span>
<span>{{vehicule.system.etat.structure.max}}</span>

View File

@ -2,8 +2,8 @@
<ul class="item-list alterne-list">
{{#each resonances as |actor|}}
<li class="item flexrow list-item" data-actor-id="{{actor.id}}">
<img class="sheet-competence-img" src="{{actor.img}}" title="{{actor.name}}"/>
<span class="subacteur-label"><a>{{actor.name}}</a></span>
<img class="sheet-competence-img subacteur-open" src="{{actor.img}}" title="{{actor.name}}"/>
<span class="subacteur-label subacteur-open"><a>{{actor.name}}</a></span>
<div class="flex-shrink">
<a class="resonance-delete" title="Supprimer"><i class="fas fa-trash"></i></a>
</div>

View File

@ -1,8 +1,8 @@
<span><a class="vue-detaillee">
{{#if options.vueDetaillee}}
<i class="fas fa-eye-slash"></i> Vue simplifiée
<i class="fa-solid fa-eye-slash"></i> Vue simplifiée
{{else}}
<i class="fas fa-eye"></i> Vue détaillée
<i class="fa-solid fa-eye"></i> Vue détaillée
{{/if}}
</a>
</span>

View File

@ -11,7 +11,7 @@
<div>
<ul class="flexcol item-list alterne-list">
{{#each table as |row|}}
<li class="select-target item list-item" >
<li class="item list-item" >
<span>{{row.min}}{{#unless (eq row.min row.max)}}-{{row.max}}{{/unless}} : &nbsp;</span>
<span>{{linkCompendium row.document.pack row.document.id row.document.name}}</span>
</li>

View File

@ -1,14 +0,0 @@
<form class="rdd-dialog-select-target">
<label>Choisir une seule des cibles</label>
<hr>
<ul class="flexcol item-list alterne-list">
{{#each tokens as |token key|}}
<li class="select-target item list-item flexrow" data-token-id="{{token.id}}">
<img class="select-token-img flex-shrink" src="{{token.img}}" title="{{token.name}}" />
<a>
<label>{{token.name}}</label>
</a>
</li>
{{/each}}
</ul>
</form>

View File

@ -0,0 +1,12 @@
<form class="rdd-dialog-select">
<label>{{label}}</label>
<hr>
<ul class="flexcol item-list alterne-list">
{{#each list as |choice key|}}
<li class="select-choice item list-item flexrow" data-id="{{choice.id}}">
<img class="select-img flex-shrink" src="{{choice.img}}" title="{{choice.name}}" />
<a><label>{{choice.name}}</label></a>
</li>
{{/each}}
</ul>
</form>