diff --git a/module/actor-sheet.js b/module/actor-sheet.js
index b735fda4..803ad71c 100644
--- a/module/actor-sheet.js
+++ b/module/actor-sheet.js
@@ -10,7 +10,6 @@ import { DialogSplitItem } from "./dialog-split-item.js";
import { ReglesOptionelles } from "./settings/regles-optionelles.js";
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
import { STATUSES } from "./settings/status-effects.js";
-import { Monnaie } from "./item-monnaie.js";
import { MAINS_DIRECTRICES } from "./actor.js";
import { RdDBaseActorSheet } from "./actor/base-actor-sheet.js";
import { RdDItem } from "./item.js";
@@ -46,10 +45,8 @@ export class RdDActorSheet extends RdDBaseActorSheet {
effects: this.actor.effects.map(e => foundry.utils.deepClone(e)),
limited: this.actor.limited,
owner: this.actor.isOwner,
- description: await TextEditor.enrichHTML(this.object.system.description, { async: true }),
- biographie: await TextEditor.enrichHTML(this.object.system.biographie, { async: true }),
- notes: await TextEditor.enrichHTML(this.object.system.notes, { async: true }),
- notesmj: await TextEditor.enrichHTML(this.object.system.notesmj, { async: true }),
+ 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(),
diff --git a/module/actor.js b/module/actor.js
index 8b85cdce..dca482fb 100644
--- a/module/actor.js
+++ b/module/actor.js
@@ -13,7 +13,6 @@ import { RdDItemSort } from "./item-sort.js";
import { Grammar } from "./grammar.js";
import { RdDEncaisser } from "./rdd-roll-encaisser.js";
import { RdDCombat } from "./rdd-combat.js";
-import { RdDAudio } from "./rdd-audio.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemArme } from "./item-arme.js";
import { RdDAlchimie } from "./rdd-alchimie.js";
@@ -24,13 +23,11 @@ import { ReglesOptionelles } from "./settings/regles-optionelles.js";
import { EffetsDraconiques } from "./tmr/effets-draconiques.js";
import { Draconique } from "./tmr/draconique.js";
import { RdDCarac } from "./rdd-carac.js";
-import { Monnaie } from "./item-monnaie.js";
import { DialogConsommer } from "./dialog-item-consommer.js";
import { DialogFabriquerPotion } from "./dialog-fabriquer-potion.js";
import { RollDataAjustements } from "./rolldata-ajustements.js";
-import { RdDItem } from "./item.js";
import { RdDPossession } from "./rdd-possession.js";
-import { ENTITE_BLURETTE, ENTITE_INCARNE, ENTITE_NONINCARNE, HIDE_DICE, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
+import { ENTITE_BLURETTE, ENTITE_INCARNE, ENTITE_NONINCARNE, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { RdDConfirm } from "./rdd-confirm.js";
import { DialogValidationEncaissement } from "./dialog-validation-encaissement.js";
import { RdDRencontre } from "./item-rencontre.js";
@@ -77,12 +74,12 @@ export class RdDActor extends RdDBaseActor {
/* -------------------------------------------- */
_prepareCreatureData(actorData) {
- this.computeEncombrementTotalEtMalusArmure();
+ this.computeEncTotal();
}
/* -------------------------------------------- */
_prepareVehiculeData(actorData) {
- this.computeEncombrementTotalEtMalusArmure();
+ this.computeEncTotal();
}
/* -------------------------------------------- */
@@ -94,7 +91,8 @@ export class RdDActor extends RdDBaseActor {
RdDCarac.computeCarac(actorData.system)
this.computeIsHautRevant();
await this.cleanupConteneurs();
- await this.computeEncombrementTotalEtMalusArmure();
+ await this.computeEncTotal();
+ await this.computeMalusArmure();
}
/* -------------------------------------------- */
@@ -234,10 +232,6 @@ export class RdDActor extends RdDBaseActor {
}
/* -------------------------------------------- */
- getMonnaie(id) {
- return this.findItemLike(id, 'monnaie');
- }
-
getTache(id) {
return this.findItemLike(id, 'tache');
}
@@ -993,237 +987,7 @@ export class RdDActor extends RdDBaseActor {
await this.update({ [`system.attributs.${fieldName}.value`]: fieldValue });
}
- /* -------------------------------------------- */
- _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...*/
- }
-
- /* -------------------------------------------- */
- 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();
- }
- }
-
- /* -------------------------------------------- */
- /** 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: `
Etes vous certain de vouloir vider tous les conteneurs ?
`,
- 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);
- }
- }
- });
- }
-
- 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() && 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}
${item.name} a été déplacé dans: ${cible.name}`
- : `${message}
${item.name} a été sorti du conteneur`);
- }
- }
- }
- }
- await this.computeEncombrementTotalEtMalusArmure();
- 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;
-
- }
-
- /* -------------------------------------------- */
- 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;
- }
isSurenc() {
return this.isPersonnage() ? (this.computeMalusSurEncombrement() < 0) : false
@@ -1268,16 +1032,6 @@ export class RdDActor extends RdDBaseActor {
return this.listItems(type).find(it => Grammar.toLowerCaseNoAccent(it.name) == name);
}
- /* -------------------------------------------- */
- async computeEncombrementTotalEtMalusArmure() {
- if (!this.pack) {
- await this.computeMalusArmure();
- this.encTotal = this.items.map(it => it.getEncTotal()).reduce(Misc.sum(), 0);
- return this.encTotal;
- }
- return 0;
- }
-
/* -------------------------------------------- */
async computeMalusArmure() {
if (this.isPersonnage()) {
@@ -1291,15 +1045,6 @@ export class RdDActor extends RdDBaseActor {
}
}
- /* -------------------------------------------- */
- computePrixTotalEquipement() {
- const valeur = this.items.filter(it => it.isInventaire())
- .filter(it => !it.isMonnaie())
- .map(it => it.valeurTotale())
- .reduce(Misc.sum(), 0);
- return valeur;
- }
-
/* -------------------------------------------- */
computeResumeBlessure(blessures = undefined) {
blessures = blessures ?? this.system.blessures;
@@ -1332,7 +1077,7 @@ export class RdDActor extends RdDBaseActor {
}
}
- recompute(){
+ recompute() {
this.computeEtatGeneral();
}
@@ -3282,7 +3027,7 @@ export class RdDActor extends RdDBaseActor {
if (item && ['arme', 'armure'].includes(item.type)) {
const isEquipe = !item.system.equipe;
await this.updateEmbeddedDocuments('Item', [{ _id: item.id, "system.equipe": isEquipe }]);
- this.computeEncombrementTotalEtMalusArmure(); // Mise à jour encombrement
+ this.computeEncTotal(); // Mise à jour encombrement
if (isEquipe)
this.verifierForceMin(item);
}
@@ -3575,186 +3320,6 @@ export class RdDActor extends RdDBaseActor {
return;
}
- /* -------------------------------------------- */
- async payerSols(depense) {
- depense = Number(depense);
- if (depense == 0) {
- return;
- }
- let fortune = super.getFortune();
- console.log("payer", game.user.character, depense, fortune);
- let msg = "";
- if (fortune >= depense) {
- await Monnaie.optimiserFortune(this, fortune - depense);
- msg = `Vous avez payé ${depense} Sols, 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 = super.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 ${sols} Sols ${fromActor ? " de " + fromActor.name : ''}, qui ont été ajoutés à votre argent.`
- });
- }
- }
-
- /* -------------------------------------------- */
- 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 }]);
- }
- }
-
- /* -------------------------------------------- */
- 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) ?? (await RdDItem.getCorrespondingItem(vente.item));
- if (!this.verifierQuantite(vendeur, itemVendu, quantite)) {
- ChatUtility.notifyUser(achat.userId, 'warn', `Le vendeur n'a pas assez de ${itemVendu.name} !`);
- return
- }
-
- if ((acheteur?.getFortune() ?? 0) < Number(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);
- let 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 {
- 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);
- }
- }
-
- verifierQuantite(vendeur, item, quantiteTotal) {
- const disponible = vendeur ? (item?.getQuantite() ?? 0) : quantiteTotal;
- return 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) {
- let resteQuantite = (item.system.quantite ?? 1) - quantite;
- if (resteQuantite <= 0) {
- await this.deleteEmbeddedDocuments("Item", [item.id]);
- 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) {
- const items = await this.createEmbeddedDocuments("Item", RdDActor.$prepareListeAchat(item, quantite));
- return items.length > 0 ? items[0].id : undefined;
- }
-
- static $prepareListeAchat(item, quantite) {
- const isItemEmpilable = "quantite" in item.system;
- const achatData = {
- type: item.type,
- img: item.img,
- name: item.name,
- system: mergeObject(item.system, { quantite: isItemEmpilable ? quantite : undefined }),
- };
- return isItemEmpilable ? [achatData] : Array.from({ length: quantite }, (_, i) => achatData);
- }
-
/* -------------------------------------------- */
async effectuerTacheAlchimie(recetteId, tacheAlchimie, texteTache) {
let recetteData = this.findItemLike(recetteId, 'recettealchimique');
diff --git a/module/actor/base-actor-sheet.js b/module/actor/base-actor-sheet.js
index 7ffa9259..328e2b72 100644
--- a/module/actor/base-actor-sheet.js
+++ b/module/actor/base-actor-sheet.js
@@ -40,6 +40,7 @@ export class RdDBaseActorSheet extends ActorSheet {
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 = {
@@ -49,13 +50,15 @@ export class RdDBaseActorSheet extends ActorSheet {
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.computeEncombrementTotalEtMalusArmure(),
+ encTotal: await this.actor.computeEncTotal(),
}
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
@@ -138,22 +141,22 @@ export class RdDBaseActorSheet extends ActorSheet {
this.html = html;
this.html.find('.conteneur-name a').click(async event => {
- RdDUtility.toggleAfficheContenu(RdDSheetUtility.getItemId(event));
+ RdDUtility.toggleAfficheContenu(this.getItemId(event));
this.render(true);
});
- this.html.find('.item-edit').click(async event => RdDSheetUtility.getItem(event, this.actor)?.sheet.render(true))
- this.html.find('.item-montrer').click(async event => RdDSheetUtility.getItem(event, this.actor)?.postItemToChat());
+ 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 = RdDSheetUtility.getItem(event, this.actor);
+ const item = this.getItem(event);
RdDSheetUtility.splitItem(item, this.actor);
});
- this.html.find('.item-delete').click(async event => RdDUtility.confirmActorItemDelete(this, RdDSheetUtility.getItem(event, this.actor)));
- this.html.find('.item-vendre').click(async event => RdDSheetUtility.getItem(event, this.actor)?.proposerVente(this.getQuantiteMax(item)));
+ 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();
@@ -162,16 +165,19 @@ export class RdDBaseActorSheet extends ActorSheet {
this.actor.nettoyerConteneurs();
});
this.html.find('.monnaie-plus').click(async event => {
- this.actor.monnaieIncDec(RdDSheetUtility.getItemId(event), 1);
+ this.actor.monnaieIncDec(this.getItemId(event), 1);
});
this.html.find('.monnaie-moins').click(async event => {
- this.actor.monnaieIncDec(RdDSheetUtility.getItemId(event), -1);
+ this.actor.monnaieIncDec(this.getItemId(event), -1);
});
-
}
- getQuantiteMax(item) {
- return item.system.quantite;
+ getItemId(event) {
+ return RdDSheetUtility.getItemId(event);
+ }
+
+ getItem(event) {
+ return RdDSheetUtility.getItem(event, this.actor);
}
/* -------------------------------------------- */
@@ -197,7 +203,6 @@ export class RdDBaseActorSheet extends ActorSheet {
}
}
-
/* -------------------------------------------- */
async selectObjetTypeToCreate() {
let typeObjets = RdDItem.getItemTypesInventaire();
@@ -256,4 +261,8 @@ export class RdDBaseActorSheet extends ActorSheet {
}
}
+ vendre(item) {
+ item?.proposerVente(this.actor.getQuantiteDisponible(item));
+ }
+
}
diff --git a/module/actor/base-actor.js b/module/actor/base-actor.js
index b95a7ff5..409cd793 100644
--- a/module/actor/base-actor.js
+++ b/module/actor/base-actor.js
@@ -1,6 +1,9 @@
+import { ChatUtility } from "../chat-utility.js";
import { SYSTEM_SOCKET_ID } from "../constants.js";
import { Monnaie } from "../item-monnaie.js";
+import { RdDItem } from "../item.js";
import { Misc } from "../misc.js";
+import { RdDAudio } from "../rdd-audio.js";
import { RdDUtility } from "../rdd-utility.js";
import { SystemCompendiums } from "../settings/system-compendiums.js";
@@ -73,14 +76,14 @@ export class RdDBaseActor extends Actor {
if (actorData.items) {
return await super.create(actorData, options);
}
-
+ actorData.items = [];
if (actorData.type == "personnage") {
const competences = await SystemCompendiums.getCompetences(actorData.type);
- actorData.items = competences.map(i => i.toObject())
+ actorData.items = actorData.items.concat(competences.map(i => i.toObject()))
.concat(Monnaie.monnaiesStandard());
}
- else {
- actorData.items = [];
+ else if (actorData.type == "commerce") {
+ actorData.items = actorData.items.concat(Monnaie.monnaiesStandard());
}
return super.create(actorData, options);
}
@@ -120,9 +123,11 @@ export class RdDBaseActor extends Actor {
?? 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) { }
@@ -132,11 +137,218 @@ export class RdDBaseActor extends Actor {
async onUpdateActor(update, options, actorId) { }
-
+ /* -------------------------------------------- */
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é ${depense} Sols, 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 ${sols} Sols ${fromActor ? " de " + fromActor.name : ''}, qui ont été ajoutés à votre argent.`
+ });
+ }
+ }
+
+ /* -------------------------------------------- */
+
+ getQuantiteDisponible(item) {
+ return 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);
+ let 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}) {
+ 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) {
+ 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);
@@ -148,6 +360,237 @@ export class RdDBaseActor extends Actor {
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() && 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}
${item.name} a été déplacé dans: ${cible.name}`
+ : `${message}
${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: `Etes vous certain de vouloir vider tous les conteneurs ?
`,
+ 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 = {
diff --git a/module/rdd-main.js b/module/rdd-main.js
index 7d68790f..13be7ddf 100644
--- a/module/rdd-main.js
+++ b/module/rdd-main.js
@@ -101,7 +101,7 @@ export class SystemReveDeDragon {
/* -------------------------------------------- */
// Define custom Entity classes
- CONFIG.Actor.documentClass = RdDActor;
+ CONFIG.Actor.documentClass = RdDBaseActor;
CONFIG.Item.documentClass = RdDItem;
CONFIG.RDD = {
resolutionTable: RdDResolutionTable.resolutionTable,
diff --git a/module/rdd-namegen.js b/module/rdd-namegen.js
index f054f435..b27ea5bc 100644
--- a/module/rdd-namegen.js
+++ b/module/rdd-namegen.js
@@ -1,4 +1,4 @@
-import { RdDActor } from "./actor.js";
+import { RdDBaseActor } from "./actor/base-actor.js";
import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js";
@@ -20,7 +20,7 @@ export class RdDNameGen {
static async onCreerActeur(event) {
const button = event.currentTarget;
- await RdDActor.create({
+ await RdDBaseActor.create({
name: button.attributes['data-nom'].value,
type: button.attributes['data-type'].value
},
diff --git a/templates/actor-sheet.html b/templates/actor-sheet.html
index 3a824616..772f0e72 100644
--- a/templates/actor-sheet.html
+++ b/templates/actor-sheet.html
@@ -189,7 +189,7 @@
Biographie :
- {{editor biographie target="system.biographie" button=true owner=owner editable=true engine="prosemirror"}}
+ {{editor biographie target="system.biographie" button=true owner=options.owner editable=true engine="prosemirror"}}
Notes :