Merge branch 'v1.4-commerce' into 'v1.4'
Payer donne l'argent à qui de droit See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!200
This commit is contained in:
commit
fde5096c59
143
module/actor.js
143
module/actor.js
@ -48,6 +48,39 @@ export class RdDActor extends Actor {
|
||||
Hooks.on("updateActor", (actor, change, options, actorId) => actor.onUpdateActor(change, options, actorId));
|
||||
}
|
||||
|
||||
static onSocketMessage(sockmsg) {
|
||||
switch (sockmsg.msg) {
|
||||
case "msg_remote_actor_call":
|
||||
return RdDActor.onRemoteActorCall(sockmsg.data);
|
||||
}
|
||||
}
|
||||
|
||||
static remoteActorCall(actorId, method, ...args) {
|
||||
game.socket.emit("system.foundryvtt-reve-de-dragon", {
|
||||
msg: "msg_remote_actor_call",
|
||||
data: {
|
||||
gmId: Misc.connectedGM(),
|
||||
toActorId: actorId,
|
||||
method: method,
|
||||
args: args
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static onRemoteActorCall(data) {
|
||||
if (game.user.id == data.gmId) { // Seul le GM connecté choisi effectue l'appel
|
||||
const actor = game.actors.get(data?.toActorId);
|
||||
if (!actor) {
|
||||
console.info("RdDActor.onRemoteActorCall: Pas d'Actor disponible ", data);
|
||||
}
|
||||
else {
|
||||
const args = data.args;
|
||||
console.info(`RdDActor.onRemoteActorCall: pour l'Actor ${data.toActorId}, appel de RdDActor.${data.method}(`, ...args, ')');
|
||||
actor[data.method](...args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static getParentActor(document) {
|
||||
return document?.parent instanceof Actor ? document.parent : undefined
|
||||
}
|
||||
@ -826,15 +859,15 @@ export class RdDActor extends Actor {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_isConteneurContenu(item, conteneurId) {
|
||||
if (Misc.data(item)?.type == 'conteneur') { // Si c'est un conteneur, il faut vérifier qu'on ne le déplace pas vers un sous-conteneur lui appartenant
|
||||
_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 Misc.templateData(item).contenu) {
|
||||
let subObjet = this.getObjet(id);
|
||||
if (subObjet?.id == conteneurId) {
|
||||
if (subObjet?.id == conteneur.id) {
|
||||
return true; // Loop detected !
|
||||
}
|
||||
if (subObjet?.type == 'conteneur') {
|
||||
return this._isConteneurContenu(subObjet, conteneurId);
|
||||
if (subObjet?.isConteneur()) {
|
||||
return this._isConteneurContenu(subObjet, conteneur);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -969,7 +1002,7 @@ export class RdDActor extends Actor {
|
||||
ui.notifications.warn(`Impossible de déplacer un objet (${item.name}) vers un ${destData.type} qui n'est pas un conteneur (${dest.name}) !`);
|
||||
return false;
|
||||
}
|
||||
if (this._isConteneurContenu(item, conteneurId)) {
|
||||
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 !
|
||||
}
|
||||
@ -3077,54 +3110,68 @@ export class RdDActor extends Actor {
|
||||
return;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async optimizeArgent(sumDenier, monnaies) {
|
||||
getFortune() {
|
||||
let monnaies = Monnaie.filtrerMonnaies(this.data.items);
|
||||
if (monnaies.length < 4) {
|
||||
ui.notifications.error("Problème de monnaies manquantes, impossible de payer correctement!")
|
||||
return 0;
|
||||
}
|
||||
return monnaies.map(m => Misc.templateData(m))
|
||||
.map(tpl => tpl.valeur_deniers * Number(tpl.quantite))
|
||||
.reduce(Misc.sum(), 0);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async optimizeArgent(fortuneTotale) {
|
||||
let monnaies = Monnaie.filtrerMonnaies(this.data.items);
|
||||
let parValeur = Misc.classifyFirst(monnaies, it => Misc.templateData(it).valeur_deniers);
|
||||
let fortune = {
|
||||
1000: Math.floor(sumDenier / 1000), // or
|
||||
100: Math.floor(sumDenier / 100) % 10, // argent
|
||||
10: Math.floor(sumDenier / 10) % 10, // bronze
|
||||
1: sumDenier % 10 // étain
|
||||
let nouvelleFortune = {
|
||||
1000: Math.floor(fortuneTotale / 1000), // or
|
||||
100: Math.floor(fortuneTotale / 100) % 10, // argent
|
||||
10: Math.floor(fortuneTotale / 10) % 10, // bronze
|
||||
1: fortuneTotale % 10 // étain
|
||||
}
|
||||
let updates = []
|
||||
for (const [valeur, nombre] of Object.entries(fortune)) {
|
||||
for (const [valeur, nombre] of Object.entries(nouvelleFortune)) {
|
||||
updates.push({ _id: parValeur[valeur]._id, 'data.quantite': nombre });
|
||||
}
|
||||
await this.updateEmbeddedDocuments('Item', updates);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async payerDenier(sumDenier, dataObj = undefined, quantite = 1) {
|
||||
let monnaies = Monnaie.filtrerMonnaies(this.data.items);
|
||||
if (monnaies.length < 4) {
|
||||
ui.notifications.warn("Problème de monnaies manquantes, impossible de payer correctement!")
|
||||
return;
|
||||
}
|
||||
|
||||
sumDenier = Number(sumDenier);
|
||||
let denierDisponible = 0;
|
||||
|
||||
for (let pieceData of monnaies.map(m => Misc.data(m))) {
|
||||
denierDisponible += pieceData.data.valeur_deniers * Number(pieceData.data.quantite);
|
||||
}
|
||||
console.log("DENIER", game.user.character, sumDenier, denierDisponible);
|
||||
|
||||
async depenserDeniers(depense, dataObj = undefined, quantite = 1, toActorId) {
|
||||
depense = Number(depense);
|
||||
let fortune = this.getFortune();
|
||||
console.log("depenserDeniers", game.user.character, depense, fortune);
|
||||
let msg = "";
|
||||
let isPayed = false;
|
||||
if (denierDisponible >= sumDenier) {
|
||||
denierDisponible -= sumDenier;
|
||||
this.optimizeArgent(denierDisponible, monnaies);
|
||||
msg = `Vous avez payé <strong>${sumDenier} Deniers</strong>, qui ont été soustraits de votre argent.`;
|
||||
RdDAudio.PlayContextAudio("argent"); // Petit son
|
||||
isPayed = true;
|
||||
if (depense == 0) {
|
||||
if (dataObj) {
|
||||
dataObj.payload.data.cout = sumDenier / 100; // Mise à jour du prix en sols , avec le prix acheté
|
||||
dataObj.payload.data.cout = depense / 100; // Mise à jour du prix en sols , avec le prix acheté
|
||||
dataObj.payload.data.quantite = quantite;
|
||||
await this.createEmbeddedDocuments('Item', [dataObj.payload]);
|
||||
msg += `<br>Et l'objet <strong>${dataObj.payload.name}</strong> a été ajouté à votre inventaire.`;
|
||||
msg += `<br>L'objet <strong>${dataObj.payload.name}</strong> a été ajouté gratuitement à votre inventaire.`;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (fortune >= depense) {
|
||||
fortune -= depense;
|
||||
const toActor = game.actors.get(toActorId)
|
||||
if (toActor) {
|
||||
toActor.ajouterDeniers(depense, this.id);
|
||||
}
|
||||
await this.optimizeArgent(fortune);
|
||||
msg = `Vous avez payé <strong>${depense} Deniers</strong>${toActor ? " à " + toActor.name : ''}, qui ont été soustraits de votre argent.`;
|
||||
RdDAudio.PlayContextAudio("argent"); // Petit son
|
||||
|
||||
if (dataObj) {
|
||||
dataObj.payload.data.cout = depense / 100; // Mise à jour du prix en sols , avec le prix acheté
|
||||
dataObj.payload.data.quantite = quantite;
|
||||
await this.createEmbeddedDocuments('Item', [dataObj.payload]);
|
||||
msg += `<br>Et l'objet <strong>${dataObj.payload.name}</strong> a été ajouté à votre inventaire.`;
|
||||
}
|
||||
} else {
|
||||
msg = "Vous n'avez pas assez d'argent pour payer cette somme !";
|
||||
}
|
||||
} else {
|
||||
msg = "Vous n'avez pas assez d'argent pour payer cette somme !";
|
||||
}
|
||||
|
||||
let message = {
|
||||
@ -3134,6 +3181,24 @@ export class RdDActor extends Actor {
|
||||
ChatMessage.create(message);
|
||||
}
|
||||
|
||||
async ajouterDeniers(gain, fromActorId = undefined) {
|
||||
if (fromActorId && !game.user.isGM) {
|
||||
RdDActor.remoteActorCall(this.id, 'ajouterDeniers', gain, fromActorId);
|
||||
}
|
||||
else {
|
||||
const fromActor = game.actors.get(fromActorId)
|
||||
let fortune = this.getFortune();
|
||||
fortune += Number(gain);
|
||||
await this.optimizeArgent(fortune);
|
||||
|
||||
RdDAudio.PlayContextAudio("argent"); // Petit son
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
content: `Vous avez reçu <strong>${gain} Deniers</strong> ${fromActor ? " de " + fromActor.name : ''}, qui ont été ajoutés de votre argent.`
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async monnaieIncDec(id, value) {
|
||||
let monnaie = this.getMonnaie(id);
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { Misc } from "./misc.js";
|
||||
|
||||
/**
|
||||
* Class providing helper methods to get the list of users, and
|
||||
@ -7,31 +8,45 @@ export class ChatUtility {
|
||||
/* -------------------------------------------- */
|
||||
static onSocketMessage(sockmsg) {
|
||||
switch (sockmsg.msg) {
|
||||
case "msg_delete_chat_message": return ChatUtility.onRemoveMessages(sockmsg.part, sockmsg.gmId);
|
||||
case "msg_delete_chat_message": return ChatUtility.onRemoveMessages(sockmsg.data);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static onRemoveMessages(part, gmId) {
|
||||
if (game.user.id == gmId) {
|
||||
const toDelete = game.messages.filter(it => it.data.content.includes(part));
|
||||
toDelete.forEach(it => it.delete());
|
||||
static onRemoveMessages(data) {
|
||||
if (game.user.isGM || game.user.id == data.gmId) {
|
||||
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 removeChatMessageContaining(part) {
|
||||
const gmId = game.user.isGM ? game.user.id : game.users.entities.find(u => u.isGM && u.active)?.id;
|
||||
const removeMessageData = {
|
||||
part: part,
|
||||
gmId: Misc.connectedGM()
|
||||
};
|
||||
|
||||
if (!gmId || game.user.isGM) {
|
||||
ChatUtility.onRemoveMessages(part, game.user.id);
|
||||
if (game.user.isGM) {
|
||||
ChatUtility.onRemoveMessages(removeMessageData);
|
||||
}
|
||||
else {
|
||||
game.socket.emit("system.foundryvtt-reve-de-dragon", {
|
||||
msg: "msg_delete_chat_message", data: {
|
||||
part:part,
|
||||
gmId: gmId,
|
||||
}});
|
||||
game.socket.emit("system.foundryvtt-reve-de-dragon", { msg: "msg_delete_chat_message", data: removeMessageData });
|
||||
}
|
||||
}
|
||||
|
||||
static removeChatMessageId(messageId) {
|
||||
const removeMessageData = { messageId: messageId, gmId: Misc.connectedGM() };
|
||||
if (game.user.isGM) {
|
||||
ChatUtility.onRemoveMessages(removeMessageData);
|
||||
}
|
||||
else {
|
||||
game.socket.emit("system.foundryvtt-reve-de-dragon", { msg: "msg_delete_chat_message", data: removeMessageData });
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,5 +123,5 @@ export class ChatUtility {
|
||||
ChatMessage.create(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -104,9 +104,9 @@ export class RdDItem extends Item {
|
||||
|
||||
async quantiteIncDec(nombre, options = { diminuerQuantite: true, supprimerSiZero: false }) {
|
||||
const itemData = Misc.data(this);
|
||||
const quantite = itemData.data.quantite;
|
||||
if (quantite != undefined) {
|
||||
const reste = Math.max(quantite + nombre, 0);
|
||||
const quantite = Number(itemData.data.quantite ??-1);
|
||||
if (quantite >=0 ) {
|
||||
const reste = Math.max(quantite + Number(nombre), 0);
|
||||
|
||||
if (reste == 0) {
|
||||
if (options.supprimerSiZero){
|
||||
@ -150,7 +150,9 @@ export class RdDItem extends Item {
|
||||
let chatData = duplicate(Misc.data(this));
|
||||
const properties = this[`_${chatData.type}ChatData`]();
|
||||
chatData["properties"] = properties
|
||||
|
||||
if (this.actor){
|
||||
chatData.actor = {id: this.actor.id };
|
||||
}
|
||||
//Check if the posted item should have availability/pay buttons
|
||||
chatData.hasPrice = "cout" in chatData.data;
|
||||
chatData.data.cout_deniers = 0;
|
||||
@ -205,7 +207,7 @@ export class RdDItem extends Item {
|
||||
if (chatData.hasPrice) {
|
||||
if (quantiteEnvoi > 0)
|
||||
chatData.postQuantity = Number(quantiteEnvoi);
|
||||
if (prixTotal > 0) {
|
||||
if (prixTotal >= 0) {
|
||||
chatData.postPrice = prixTotal;
|
||||
chatData.data.cout_deniers = Math.floor(prixTotal * 100); // Mise à jour cout en deniers
|
||||
}
|
||||
|
@ -47,11 +47,13 @@ export class Misc {
|
||||
const parsed = parseInt(value);
|
||||
return isNaN(parsed) ? 0 : parsed;
|
||||
}
|
||||
|
||||
static keepDecimals(num, decimals) {
|
||||
if (decimals<=0 || decimals>6) return num;
|
||||
const decimal = Math.pow(10, parseInt(decimals));
|
||||
return Math.round(num * decimal) / decimal;
|
||||
}
|
||||
|
||||
static getFractionHtml(diviseur) {
|
||||
if (!diviseur || diviseur <= 1) return undefined;
|
||||
switch (diviseur || 1) {
|
||||
@ -111,4 +113,8 @@ export class Misc {
|
||||
static templateData(it) {
|
||||
return Misc.data(it)?.data ?? {}
|
||||
}
|
||||
|
||||
static connectedGM() {
|
||||
return game.user.isGM ? game.user.id : game.users.entities.find(u => u.isGM && u.active)?.id;
|
||||
}
|
||||
}
|
@ -1211,7 +1211,7 @@ export class RdDCombat {
|
||||
attackerId: this.attackerId,
|
||||
defenderTokenId: defenderTokenId,
|
||||
attackerRoll: attackerRoll,
|
||||
gmId: game.users.entities.find(u => u.isGM)?.id,
|
||||
gmId: Misc.connectedGM(),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -140,10 +140,11 @@ Hooks.once("init", async function () {
|
||||
};
|
||||
|
||||
/* -------------------------------------------- */
|
||||
game.socket.on("system.foundryvtt-reve-de-dragon", data => {
|
||||
RdDUtility.onSocketMesssage(data);
|
||||
RdDCombat.onSocketMessage(data);
|
||||
ChatUtility.onSocketMessage(data);
|
||||
game.socket.on("system.foundryvtt-reve-de-dragon", sockmsg => {
|
||||
RdDUtility.onSocketMesssage(sockmsg);
|
||||
RdDCombat.onSocketMessage(sockmsg);
|
||||
ChatUtility.onSocketMessage(sockmsg);
|
||||
RdDActor.onSocketMessage(sockmsg);
|
||||
});
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
@ -204,9 +204,9 @@ export class RdDUtility {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static buildListOptions( min, max ) {
|
||||
static buildListOptions(min, max) {
|
||||
let options = ""
|
||||
for(let i=min; i<= max; i++) {
|
||||
for (let i = min; i <= max; i++) {
|
||||
options += `<option value="${i}">${i}</option>`
|
||||
}
|
||||
return options;
|
||||
@ -529,25 +529,62 @@ export class RdDUtility {
|
||||
});
|
||||
// Gestion du bouton payer
|
||||
html.on("click", '.payer-button', event => {
|
||||
let sumdenier = event.currentTarget.attributes['data-somme-denier'].value;
|
||||
let quantite = 1;
|
||||
if (event.currentTarget.attributes['data-quantite']) {
|
||||
quantite = event.currentTarget.attributes['data-quantite'].value;
|
||||
}
|
||||
let sumdenier = event.currentTarget.attributes['data-somme-denier']?.value ?? 0;
|
||||
let quantite = event.currentTarget.attributes['data-quantite']?.value ?? 1;
|
||||
let fromActorId = event.currentTarget.attributes['data-actor-id']?.value;
|
||||
let jsondata = event.currentTarget.attributes['data-jsondata']
|
||||
let objData
|
||||
if (jsondata) {
|
||||
objData = JSON.parse(jsondata.value)
|
||||
}
|
||||
if (game.user.character) {
|
||||
game.user.character.payerDenier(sumdenier, objData, quantite);
|
||||
} else {
|
||||
let msgPayer = "Vous devez avoir un acteur relié pour effectuer le paiement";
|
||||
ChatMessage.create({ content: msgPayer, whisper: [game.user] });
|
||||
let actor = RdDUtility.getSelectedActor("Pour effectuer le paiement:");
|
||||
if (actor) {
|
||||
actor.depenserDeniers(sumdenier, objData, quantite, fromActorId);
|
||||
// TODO: diminuer la quantité ou supprimer le message
|
||||
// message: => document.querySelector("#chat-log > li:nth-child(61) > div > div > span > a")
|
||||
// => ../../../..[@data-message-id]
|
||||
let chatMessageId = RdDUtility.findChatMessageId(event.currentTarget);
|
||||
if (chatMessageId) {
|
||||
ChatUtility.removeChatMessageId(chatMessageId);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static findChatMessageId(current) {
|
||||
const isChatMessageWithId = it => it.classList.contains('chat-message') && it.attributes.getNamedItem('data-message-id');
|
||||
return RdDUtility.findNodeMatching(current, isChatMessageWithId)?.attributes.getNamedItem('data-message-id').value;
|
||||
}
|
||||
|
||||
static findNodeMatching(current, predicate) {
|
||||
if (current) {
|
||||
if (predicate(current)) {
|
||||
return current;
|
||||
}
|
||||
return RdDUtility.findNodeMatching(current.parentElement, predicate);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
static getSelectedActor(msgPlayer = '') {
|
||||
if (canvas.tokens.controlled.length == 1) {
|
||||
let token = canvas.tokens.controlled[0];
|
||||
if (token.actor && token.data.actorLink) {
|
||||
return token.actor;
|
||||
}
|
||||
msgPlayer += "<br>le token sélectionné doit être lié à un personnage";
|
||||
}
|
||||
if (game.user.character) {
|
||||
return game.user.character;
|
||||
}
|
||||
msgPlayer += "<br>vous pouvez sélectionner un seul token lié à un personnage";
|
||||
msgPlayer += "<br>vous devez être connecté comme joueur avec un personnage sélectionné";
|
||||
|
||||
ui.notifications.warn(msgPlayer);
|
||||
ChatMessage.create({ content: msgPlayer, whisper: [game.user] });
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static createMonnaie(name, valeur_deniers, img = "", enc = 0.01) {
|
||||
let piece = {
|
||||
|
@ -15,21 +15,21 @@
|
||||
<b>Quantité: </b> <span class="postQuantity">{{postQuantity}}</span>
|
||||
{{/if}}
|
||||
{{#if postPrice}}
|
||||
<b>Prix: </b> <span class="postPrice">{{postPrice}} Sols</span><br>
|
||||
<b>Prix: </b> <span class="postPrice">{{postPrice}} Sols</span>
|
||||
{{/if}}
|
||||
</span>
|
||||
</span><br>
|
||||
{{/if}}
|
||||
{{#if finalPrice}}
|
||||
<span>
|
||||
<b>Prix Total: </b> <span class="postPrice">{{finalPrice}} Sols</span><br>
|
||||
</span>
|
||||
{{/if}}
|
||||
</p>
|
||||
|
||||
{{#if hasPrice}}
|
||||
<span class="chat-card-button-area">
|
||||
<a class='payer-button chat-card-button market-button' data-jsondata='{{jsondata}}'
|
||||
data-somme-denier="{{data.cout_deniers_total}}" data-quantite="{{data.quantite}}">Payer</a>
|
||||
<a class='payer-button chat-card-button market-button'
|
||||
data-jsondata='{{jsondata}}'
|
||||
{{#if actor.id}}data-actor-id='{{actor.id}}'{{/if}}
|
||||
data-somme-denier="{{data.cout_deniers_total}}" data-quantite="{{data.quantite}}">Payer</a>
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user