Ecole de commerce

This commit is contained in:
Vincent Vandemeulebrouck 2021-05-07 17:27:02 +02:00
parent 65a4e1ec69
commit c4cb3bf60d
13 changed files with 539 additions and 83 deletions

View File

@ -239,6 +239,12 @@ export class RdDActorSheet extends ActorSheet {
const li = $(ev.currentTarget).parents(".item"); const li = $(ev.currentTarget).parents(".item");
RdDUtility.confirmerSuppression(this, li); RdDUtility.confirmerSuppression(this, li);
}); });
html.find('.item-vendre').click(ev => {
const li = $(ev.currentTarget).parents(".item");
const itemId = li.data("item-id");
const item = this.actor.getObjet(itemId);
item?.proposerVente();
});
html.find('.item-action').click(ev => { html.find('.item-action').click(ev => {
const li = $(ev.currentTarget).parents(".item"); const li = $(ev.currentTarget).parents(".item");
const itemId = li.data("item-id"); const itemId = li.data("item-id");

View File

@ -969,12 +969,11 @@ export class RdDActor extends Actor {
this.moveItemsBetweenActors(droppedItemId, dragData.actorId); this.moveItemsBetweenActors(droppedItemId, dragData.actorId);
return false; return false;
} }
let result = true; let result = true;
const destId = $(event.target).parents(".item").attr("data-item-id"); const destId = $(event.target).parents(".item").attr("data-item-id");
const itemId = dragData.id || dragData.data._id; const itemId = dragData.id || dragData.data._id;
const item = this.getObjet(itemId); const item = this.getObjet(itemId);
if (item.isEquipement()) { if (item?.isEquipement()) {
if (dragData.actorId == this.id) { if (dragData.actorId == this.id) {
// rangement // rangement
const srcId = objetVersConteneur[itemId]; const srcId = objetVersConteneur[itemId];
@ -1000,8 +999,8 @@ export class RdDActor extends Actor {
} }
} }
} }
await this.computeEncombrementTotalEtMalusArmure();
} }
await this.computeEncombrementTotalEtMalusArmure();
return result; return result;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -1472,7 +1471,7 @@ export class RdDActor extends Actor {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async santeIncDec(name, inc, options = {isCritique: false, ethylisme: false}) { async santeIncDec(name, inc, options = { isCritique: false, ethylisme: false }) {
const sante = duplicate(Misc.templateData(this).sante); const sante = duplicate(Misc.templateData(this).sante);
let compteur = sante[name]; let compteur = sante[name];
@ -1667,7 +1666,7 @@ export class RdDActor extends Actor {
let enduranceLost = new Roll("1d6").roll().total; let enduranceLost = new Roll("1d6").roll().total;
rollDataView.enduranceLost = enduranceLost; rollDataView.enduranceLost = enduranceLost;
await this.santeIncDec("endurance", -enduranceLost, {ethylisme:true}); await this.santeIncDec("endurance", -enduranceLost, { ethylisme: true });
// Qui a bu boira (p 164) // Qui a bu boira (p 164)
let rollVolonte = await RdDResolutionTable.roll(actorData.data.carac.volonte.value, Math.min(ethylisme.value, 0) + actorData.data.compteurs.moral.value); let rollVolonte = await RdDResolutionTable.roll(actorData.data.carac.volonte.value, Math.min(ethylisme.value, 0) + actorData.data.compteurs.moral.value);
rollDataView.rollVolonteIsSuccess = rollVolonte.isSuccess; rollDataView.rollVolonteIsSuccess = rollVolonte.isSuccess;
@ -1741,7 +1740,7 @@ export class RdDActor extends Actor {
return; return;
} }
if (choix.doses > itemData.data.quantite) { if (choix.doses > itemData.data.quantite) {
ui.notifications.warn(`Il n'y a pas assez de ${itemData.name} poour manger ${choix.doses}`) ui.notifications.warn(`Il n'y a pas assez de ${itemData.name} pour manger ${choix.doses}`)
return; return;
} }
const surmonteExotisme = await this.surmonterExotisme(item, choix); const surmonteExotisme = await this.surmonterExotisme(item, choix);
@ -2946,7 +2945,7 @@ export class RdDActor extends Actor {
const perteVie = this.isEntiteCauchemar() const perteVie = this.isEntiteCauchemar()
? { newValue: 0 } ? { newValue: 0 }
: await this.santeIncDec("vie", - encaissement.vie); : await this.santeIncDec("vie", - encaissement.vie);
const perteEndurance = await this.santeIncDec("endurance", -encaissement.endurance, {critiques: encaissement.critiques > 0}); const perteEndurance = await this.santeIncDec("endurance", -encaissement.endurance, { critiques: encaissement.critiques > 0 });
this.computeEtatGeneral(); this.computeEtatGeneral();
this.sheet.render(false); this.sheet.render(false);
@ -3210,9 +3209,7 @@ export class RdDActor extends Actor {
if (fortune >= depense) { if (fortune >= depense) {
fortune -= depense; fortune -= depense;
const toActor = game.actors.get(toActorId) const toActor = game.actors.get(toActorId)
if (toActor) { await toActor?.ajouterDeniers(depense, this.id);
toActor.ajouterDeniers(depense, this.id);
}
await this.optimizeArgent(fortune); await this.optimizeArgent(fortune);
msg = `Vous avez payé <strong>${depense} Deniers</strong>${toActor ? " à " + toActor.name : ''}, qui ont été soustraits de votre argent.`; msg = `Vous avez payé <strong>${depense} Deniers</strong>${toActor ? " à " + toActor.name : ''}, qui ont été soustraits de votre argent.`;
RdDAudio.PlayContextAudio("argent"); // Petit son RdDAudio.PlayContextAudio("argent"); // Petit son
@ -3235,6 +3232,17 @@ export class RdDActor extends Actor {
ChatMessage.create(message); ChatMessage.create(message);
} }
async depenser(depense) {
depense = Number(depense);
let fortune = this.getFortune();
let reste = fortune - depense;
if (reste >= 0) {
fortune -= depense;
await this.optimizeArgent(fortune);
}
return reste;
}
async ajouterDeniers(gain, fromActorId = undefined) { async ajouterDeniers(gain, fromActorId = undefined) {
if (fromActorId && !game.user.isGM) { if (fromActorId && !game.user.isGM) {
RdDActor.remoteActorCall({ userId: Misc.connectedGMOrUser(), actorId: this.id, method: 'ajouterDeniers', args: [gain, fromActorId] }); RdDActor.remoteActorCall({ userId: Misc.connectedGMOrUser(), actorId: this.id, method: 'ajouterDeniers', args: [gain, fromActorId] });
@ -3248,7 +3256,7 @@ export class RdDActor extends Actor {
RdDAudio.PlayContextAudio("argent"); // Petit son RdDAudio.PlayContextAudio("argent"); // Petit son
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), 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.` content: `Vous avez reçu <strong>${gain} Deniers</strong> ${fromActor ? " de " + fromActor.name : ''}, qui ont été ajoutés à votre argent.`
}); });
} }
} }
@ -3262,6 +3270,82 @@ export class RdDActor extends Actor {
} }
} }
/* -------------------------------------------- */
async achatVente(vendeurId, acheteurId, venteData, chatMessageIdVente) {
if (!game.user.isGM) {
RdDActor.remoteActorCall({
userId: Misc.connectedGMOrUser(),
actorId: this.vendeur?.id ?? this.acheteur?.id,
method: 'achatVente', args: [vendeurId, acheteurId, venteData, chatMessageIdVente]
});
return;
}
const acheteur = acheteurId ? game.actors.get(acheteurId) : undefined;
const vendeur = vendeurId ? game.actors.get(vendeurId) : undefined;
const itemId = venteData.item._id;
const coutDeniers = Math.floor((venteData.prixTotal ?? 0) * 100);
const achat = duplicate(venteData.item);
venteData.quantiteTotal = (venteData.nombreLots ?? 1) * (venteData.tailleLot);
if (acheteur) {
let resteAcheteur = await acheteur.depenser(coutDeniers);
if (resteAcheteur < 0) {
ui.notifications.warn(`Vous n'avez pas assez d'argent pour payer ${venteData.prixTotal} sols !`);
return;
}
}
if (vendeur) {
let itemData = Misc.data(vendeur.getObjet(itemId));
// diminuer QuantiteVendeur
if (("quantite" in itemData.data && itemData.data.quantite < venteData.nombreLots)
|| (!("quantite" in itemData.data) && venteData.nombreLots != 1)) {
// pas assez de quantite
await acheteur?.ajouterDeniers(coutDeniers);
ui.notifications.warn(`Le vendeur n'a plus assez de ${venteData.item.name} !`);
return;
}
vendeur.ajouterDeniers(coutDeniers);
let qtReste = (itemData.data.quantite ?? 1) - venteData.nombreLots;
if (qtReste == 0) {
vendeur.deleteEmbeddedDocuments("Item", itemId);
}
else {
vendeur.updateEmbeddedDocuments("Item", [{ _id: itemId, 'data.quantite': qtReste }]);
}
}
if (acheteur) {
// ajouter l'objet à l'acheteur
achat._id = undefined;
if ("quantite" in achat.data) {
achat.data.quantite = venteData.quantiteTotal;
}
await acheteur.createEmbeddedDocuments("Item", [achat]);
}
if (coutDeniers > 0) {
RdDAudio.PlayContextAudio("argent");
}
ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-achat-item.html', venteData)
});
venteData.quantiteNbLots -= venteData.nombreLots;
if (venteData.quantiteNbLots <= 0) {
ChatUtility.removeChatMessageId(chatMessageIdVente);
}
else {
venteData.jsondata = JSON.stringify(venteData.item);
let newMessageVente = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', venteData);
const messageVente = game.messages.get(chatMessageIdVente);
messageVente.update({ content: newMessageVente });
messageVente.render(true);
}
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async effectuerTacheAlchimie(recetteId, tacheAlchimie, texteTache) { async effectuerTacheAlchimie(recetteId, tacheAlchimie, texteTache) {
let recetteData = Misc.data(this.getItemOfType(recetteId, 'recettealchimique')); let recetteData = Misc.data(this.getItemOfType(recetteId, 'recettealchimique'));

View File

@ -0,0 +1,86 @@
import { RdDActor } from "./actor.js";
import { HtmlUtility } from "./html-utility.js";
import { Misc } from "./misc.js";
import { RdDUtility } from "./rdd-utility.js";
export class DialogItemAchat extends Dialog {
static async onButtonAcheter(event) {
let jsondata = event.currentTarget.attributes['data-jsondata']?.value;
if (!jsondata) {
ui.notifications.warn("Impossible d'acheter: informations sur l'objet manquantes")
return;
}
const vendeurId = event.currentTarget.attributes['data-actorId']?.value;
const vendeur = vendeurId ? game.actors.get(vendeurId) : undefined;
const acheteur = RdDUtility.getSelectedActor();
if (!acheteur && !vendeur) {
ui.notifications.info("Pas d'acheteur ni de vendeur, aucun changement");
return;
}
const chatMessageIdVente = RdDUtility.findChatMessageId(event.currentTarget);
const itemData = JSON.parse(jsondata);
const prixLot = event.currentTarget.attributes['data-prixLot']?.value ?? 0;
let venteData = {
item: itemData,
vendeur: Misc.data(vendeur),
acheteur: Misc.data(acheteur),
tailleLot: event.currentTarget.attributes['data-tailleLot']?.value ?? 1,
quantiteNbLots: event.currentTarget.attributes['data-quantiteNbLots']?.value,
nombreLots: 1,
prixLot: prixLot,
prixTotal: prixLot,
isVente: prixLot > 0
};
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-achat.html`, venteData);
const dialog = new DialogItemAchat(html, vendeur, acheteur, venteData, chatMessageIdVente);
dialog.render(true);
}
constructor(html, vendeur, acheteur, venteData, chatMessageIdVente) {
let options = { classes: ["dialogachat"], width: 400, height: 300, 'z-index': 99999 };
const actionAchat = venteData.prixLot > 0 ? "Acheter" : "Prendre";
let conf = {
title: actionAchat,
content: html,
default: actionAchat,
buttons: {
[actionAchat]: { label: actionAchat, callback: it => { this.onAchat(); } },
"decliner": { label: "Décliner", callback: it => { } }
}
};
super(conf, options);
this.vendeur = vendeur;
this.acheteur = acheteur;
this.chatMessageIdVente = chatMessageIdVente;
this.venteData = venteData;
}
async onAchat() {
(this.vendeur ?? this.acheteur).achatVente(
this.vendeur?.id,
this.acheteur?.id,
this.venteData,
this.chatMessageIdVente
);
}
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
html.find(".nombreLots").change(event => this.setnombreLots(Number(event.currentTarget.value)));
}
setnombreLots(nombreLots) {
this.venteData.nombreLots = nombreLots;
this.venteData.prixTotal = (nombreLots * this.venteData.prixLot).toFixed(2);
$(".prixTotal").text(this.venteData.prixTotal);
}
}

View File

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

View File

@ -43,4 +43,8 @@ export class Monnaie {
static deValeur(monnaie, v) { static deValeur(monnaie, v) {
return v != monnaie.data.valeur_deniers; return v != monnaie.data.valeur_deniers;
} }
static arrondiDeniers(sols) {
return sols.toFixed(2);
}
} }

View File

@ -1,6 +1,5 @@
import { RdDItemSort } from "./item-sort.js"; import { RdDItemSort } from "./item-sort.js";
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";
import { RdDItem } from "./item.js";
import { RdDAlchimie } from "./rdd-alchimie.js"; import { RdDAlchimie } from "./rdd-alchimie.js";
import { RdDItemCompetence } from "./item-competence.js"; import { RdDItemCompetence } from "./item-competence.js";
import { RdDHerbes } from "./rdd-herbes.js"; import { RdDHerbes } from "./rdd-herbes.js";
@ -15,45 +14,54 @@ import { ReglesOptionelles } from "./regles-optionelles.js";
export class RdDItemSheet extends ItemSheet { export class RdDItemSheet extends ItemSheet {
/** @override */ /** @override */
static get defaultOptions() { static get defaultOptions() {
return mergeObject(super.defaultOptions, { return mergeObject(super.defaultOptions, {
classes: ["foundryvtt-reve-de-dragon", "sheet", "item"], classes: ["foundryvtt-reve-de-dragon", "sheet", "item"],
template: "systems/foundryvtt-reve-de-dragon/templates/item-sheet.html", template: "systems/foundryvtt-reve-de-dragon/templates/item-sheet.html",
width: 550, width: 550,
height: 550 height: 550
//tabs: [{navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description"}] //tabs: [{navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description"}]
}); });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_getHeaderButtons() { _getHeaderButtons() {
let buttons = super._getHeaderButtons(); let buttons = super._getHeaderButtons();
const videSiConteneur = this.object.isConteneur() ? this.object.isVide() : true;
// Add "Post to chat" button // Add "Post to chat" button
// We previously restricted this to GM and editable items only. If you ever find this comment because it broke something: eh, sorry! // We previously restricted this to GM and editable items only. If you ever find this comment because it broke something: eh, sorry!
buttons.unshift( if ("cout" in Misc.templateData(this.object) && videSiConteneur) {
{ buttons.unshift({
class: "post",
icon: "fas fa-comments-dollar",
onclick: ev => this.item.proposerVente()
});
}
else {
buttons.unshift({
class: "post", class: "post",
icon: "fas fa-comment", icon: "fas fa-comment",
onclick: ev => this.item.postItem() onclick: ev => this.item.postItem()
}) });
}
return buttons return buttons
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @override */
setPosition(options={}) { setPosition(options = {}) {
const position = super.setPosition(options); const position = super.setPosition(options);
const sheetBody = this.element.find(".sheet-body"); const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - 192; const bodyHeight = position.height - 192;
sheetBody.css("height", bodyHeight); sheetBody.css("height", bodyHeight);
return position; return position;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async getData() { async getData() {
const objectData = Misc.data(this.object); const objectData = Misc.data(this.object);
let formData ={ let formData = {
title: objectData.name, title: objectData.name,
id: objectData.id, id: objectData.id,
type: objectData.type, type: objectData.type,
@ -66,57 +74,57 @@ export class RdDItemSheet extends ItemSheet {
cssClass: this.isEditable ? "editable" : "locked", cssClass: this.isEditable ? "editable" : "locked",
isSoins: false isSoins: false
} }
if ( this.actor ) { if (this.actor) {
formData.isOwned = true; formData.isOwned = true;
formData.actorId = this.actor.id; formData.actorId = this.actor.id;
} }
formData.categorieCompetences = RdDItemCompetence.getCategorieCompetences(); formData.categorieCompetences = RdDItemCompetence.getCategorieCompetences();
if ( formData.type == 'tache' || formData.type == 'livre' || formData.type == 'meditation' || formData.type == 'oeuvre') { if (formData.type == 'tache' || formData.type == 'livre' || formData.type == 'meditation' || formData.type == 'oeuvre') {
formData.caracList = duplicate(game.system.model.Actor.personnage.carac); formData.caracList = duplicate(game.system.model.Actor.personnage.carac);
formData.competences = await RdDUtility.loadCompendium( 'foundryvtt-reve-de-dragon.competences' ); formData.competences = await RdDUtility.loadCompendium('foundryvtt-reve-de-dragon.competences');
} }
if (formData.type == 'arme') { if (formData.type == 'arme') {
formData.competences = await RdDUtility.loadCompendium( 'foundryvtt-reve-de-dragon.competences', it => RdDItemCompetence.isCompetenceArme(it)); formData.competences = await RdDUtility.loadCompendium('foundryvtt-reve-de-dragon.competences', it => RdDItemCompetence.isCompetenceArme(it));
console.log(formData.competences); console.log(formData.competences);
} }
if ( formData.type == 'recettealchimique' ) { if (formData.type == 'recettealchimique') {
RdDAlchimie.processManipulation(objectData, this.actor && this.actor.id ); RdDAlchimie.processManipulation(objectData, this.actor && this.actor.id);
} }
if ( formData.type == 'potion') { if (formData.type == 'potion') {
if (this.dateUpdated) { if (this.dateUpdated) {
formData.data.prdate = this.dateUpdated; formData.data.prdate = this.dateUpdated;
this.dateUpdated = undefined; this.dateUpdated = undefined;
} }
RdDHerbes.updatePotionData(formData); RdDHerbes.updatePotionData(formData);
} }
if ( formData.isOwned && formData.type == 'herbe' && (formData.data.categorie == 'Soin' || formData.data.categorie == 'Repos') ) { if (formData.isOwned && formData.type == 'herbe' && (formData.data.categorie == 'Soin' || formData.data.categorie == 'Repos')) {
formData.isIngredientPotionBase = true; formData.isIngredientPotionBase = true;
} }
formData.bonusCaseList = RdDItemSort.getBonusCaseList(formData, true); formData.bonusCaseList = RdDItemSort.getBonusCaseList(formData, true);
return formData; return formData;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @override */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
HtmlUtility._showControlWhen($(".item-cout"), ReglesOptionelles.isUsing('afficher-prix-joueurs') || game.user.isGM || !this.object.isOwned); HtmlUtility._showControlWhen($(".item-cout"), ReglesOptionelles.isUsing('afficher-prix-joueurs') || game.user.isGM || !this.object.isOwned);
HtmlUtility._showControlWhen($(".item-magique"), this.object.isMagique());
// Everything below here is only needed if the sheet is editable // Everything below here is only needed if the sheet is editable
if (!this.options.editable) return; if (!this.options.editable) return;
// Select competence categorie // Select competence categorie
html.find(".categorie").change(event => this._onSelectCategorie(event)); html.find(".categorie").change(event => this._onSelectCategorie(event));
html.find('.sheet-competence-xp').change((event) => { html.find('.sheet-competence-xp').change((event) => {
if ( this.object.data.type == 'competence') { if (this.object.data.type == 'competence') {
RdDUtility.checkThanatosXP( this.object.data.name ); RdDUtility.checkThanatosXP(this.object.data.name);
} }
} ); });
html.find('.enchanteDate').change((event) => { html.find('.enchanteDate').change((event) => {
let jour = Number($('#jourMois').val()); let jour = Number($('#jourMois').val());
@ -126,35 +134,35 @@ export class RdDItemSheet extends ItemSheet {
html.find('.creer-tache-livre').click((event) => { html.find('.creer-tache-livre').click((event) => {
let actorId = event.currentTarget.attributes['data-actor-id'].value; let actorId = event.currentTarget.attributes['data-actor-id'].value;
let actor = game.actors.get( actorId ); let actor = game.actors.get(actorId);
actor.creerTacheDepuisLivre( this.item ); actor.creerTacheDepuisLivre(this.item);
}); });
html.find('.consommer-potion').click((event) => { html.find('.consommer-potion').click((event) => {
let actorId = event.currentTarget.attributes['data-actor-id'].value; let actorId = event.currentTarget.attributes['data-actor-id'].value;
let actor = game.actors.get( actorId ); let actor = game.actors.get(actorId);
actor.consommerPotion( this.item ); actor.consommerPotion(this.item);
}); });
html.find('.creer-potion-base').click((event) => { html.find('.creer-potion-base').click((event) => {
let actorId = event.currentTarget.attributes['data-actor-id'].value; let actorId = event.currentTarget.attributes['data-actor-id'].value;
let actor = game.actors.get( actorId ); let actor = game.actors.get(actorId);
actor.dialogFabriquerPotion( this.item ); actor.dialogFabriquerPotion(this.item);
}); });
html.find('.alchimie-tache a').click((event) => { html.find('.alchimie-tache a').click((event) => {
let actorId = event.currentTarget.attributes['data-actor-id'].value; let actorId = event.currentTarget.attributes['data-actor-id'].value;
let recetteId = event.currentTarget.attributes['data-recette-id'].value; let recetteId = event.currentTarget.attributes['data-recette-id'].value;
let tacheName = event.currentTarget.attributes['data-alchimie-tache'].value; let tacheName = event.currentTarget.attributes['data-alchimie-tache'].value;
let tacheData = event.currentTarget.attributes['data-alchimie-data'].value; let tacheData = event.currentTarget.attributes['data-alchimie-data'].value;
let actor = game.actors.get( actorId ); let actor = game.actors.get(actorId);
if ( actor ) { if (actor) {
actor.effectuerTacheAlchimie(recetteId, tacheName, tacheData); actor.effectuerTacheAlchimie(recetteId, tacheName, tacheData);
} else { } else {
ui.notifications.info("Impossible trouver un actur pour réaliser cette tache Alchimique."); ui.notifications.info("Impossible trouver un actur pour réaliser cette tache Alchimique.");
} }
}); });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async _onSelectCategorie(event) { async _onSelectCategorie(event) {
event.preventDefault(); event.preventDefault();
@ -167,8 +175,7 @@ export class RdDItemSheet extends ItemSheet {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
get template() get template() {
{
//console.log(this); //console.log(this);
let type = this.object.data.type; let type = this.object.data.type;
return `systems/foundryvtt-reve-de-dragon/templates/item-${type}-sheet.html`; return `systems/foundryvtt-reve-de-dragon/templates/item-${type}-sheet.html`;
@ -180,8 +187,8 @@ export class RdDItemSheet extends ItemSheet {
_updateObject(event, formData) { // Deprecated en v0.8 à clarifier _updateObject(event, formData) { // Deprecated en v0.8 à clarifier
//console.log("UPDATE !", formData); //console.log("UPDATE !", formData);
// Données de bonus de cases ? // Données de bonus de cases ?
formData = RdDItemSort.buildBonusCaseStringFromFormData( formData ); formData = RdDItemSort.buildBonusCaseStringFromFormData(formData);
return this.object.update(formData); return this.object.update(formData);
} }
} }

View File

@ -1,3 +1,4 @@
import { DialogItemVente } from "./dialog-item-vente.js";
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";
@ -24,6 +25,9 @@ export class RdDItem extends Item {
isConteneur() { isConteneur() {
return Misc.data(this).type == 'conteneur'; return Misc.data(this).type == 'conteneur';
} }
isVide() {
return this.isConteneur() && (Misc.templateData(this).contenu ?? []).length == 0;
}
isAlcool() { isAlcool() {
const itemData = Misc.data(this); const itemData = Misc.data(this);
@ -37,13 +41,13 @@ export class RdDItem extends Item {
isEquipement() { isEquipement() {
return RdDItem.getTypeObjetsEquipement().includes(Misc.data(this).type); return RdDItem.getTypeObjetsEquipement().includes(Misc.data(this).type);
} }
isCristalAlchimique() { isCristalAlchimique() {
const itemData = Misc.data(this); const itemData = Misc.data(this);
return itemData.type == 'objet' && Grammar.toLowerCaseNoAccent(itemData.name) == 'cristal alchimique' && itemData.data.quantite > 0; return itemData.type == 'objet' && Grammar.toLowerCaseNoAccent(itemData.name) == 'cristal alchimique' && itemData.data.quantite > 0;
} }
isMagique(){ isMagique() {
return Misc.templateData(this.object).magique; return Misc.templateData(this.object).magique;
} }
@ -118,12 +122,12 @@ export class RdDItem extends Item {
async quantiteIncDec(nombre, options = { diminuerQuantite: true, supprimerSiZero: false }) { async quantiteIncDec(nombre, options = { diminuerQuantite: true, supprimerSiZero: false }) {
const itemData = Misc.data(this); const itemData = Misc.data(this);
const quantite = Number(itemData.data.quantite ??-1); const quantite = Number(itemData.data.quantite ?? -1);
if (quantite >=0 ) { if (quantite >= 0) {
const reste = Math.max(quantite + Number(nombre), 0); const reste = Math.max(quantite + Number(nombre), 0);
if (reste == 0) { if (reste == 0) {
if (options.supprimerSiZero){ if (options.supprimerSiZero) {
ui.notifications.notify(`${itemData.name} supprimé de votre équipement`); ui.notifications.notify(`${itemData.name} supprimé de votre équipement`);
await this.delete(); await this.delete();
} }
@ -157,6 +161,26 @@ export class RdDItem extends Item {
return true; return true;
} }
async proposerVente() {
console.log(this);
const dialog = await DialogItemVente.create(this, (vente) => this._onProposerVente(vente))
dialog.render(true);
}
async _onProposerVente(venteData) {
venteData["properties"] = this[`_${venteData.item.type}ChatData`]();
if (venteData.isOwned) {
if (venteData.quantiteNbLots * venteData.tailleLot > venteData.quantiteMax) {
ui.notifications.warn(`Vous avez ${venteData.quantiteMax} ${venteData.item.name}, ce n'est pas suffisant pour vendre ${venteData.quantiteNbLots} de ${venteData.tailleLot}`)
return;
}
}
venteData.jsondata = JSON.stringify(venteData.item);
console.log(venteData);
let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', venteData);
ChatMessage.create( RdDUtility.chatDataSetup(html));
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async postItem() { async postItem() {
@ -164,8 +188,8 @@ export class RdDItem extends Item {
let chatData = duplicate(Misc.data(this)); let chatData = duplicate(Misc.data(this));
const properties = this[`_${chatData.type}ChatData`](); const properties = this[`_${chatData.type}ChatData`]();
chatData["properties"] = properties chatData["properties"] = properties
if (this.actor){ if (this.actor) {
chatData.actor = {id: this.actor.id }; chatData.actor = { id: this.actor.id };
} }
//Check if the posted item should have availability/pay buttons //Check if the posted item should have availability/pay buttons
chatData.hasPrice = "cout" in chatData.data; chatData.hasPrice = "cout" in chatData.data;
@ -184,7 +208,7 @@ export class RdDItem extends Item {
</div> </div>
<p>Modifier la prix?</p> <p>Modifier la prix?</p>
<div class="form-group"> <div class="form-group">
<label> Prix en Sols</label> <label>Prix en Sols</label>
<input name="price" type="text" value="${chatData.data.cout}"/> <input name="price" type="text" value="${chatData.data.cout}"/>
</div> </div>
`, `,
@ -201,7 +225,7 @@ export class RdDItem extends Item {
}) })
} }
let quantiteEnvoi = Math.min(dialogResult[0], chatData.data.quantite); let quantiteEnvoi = this.isOwned ? Math.min(dialogResult[0], chatData.data.quantite) : dialogResult[0];
const prixTotal = dialogResult[1]; const prixTotal = dialogResult[1];
if (quantiteEnvoi > 0) { if (quantiteEnvoi > 0) {
if (this.isOwned) { if (this.isOwned) {
@ -247,16 +271,18 @@ export class RdDItem extends Item {
}); });
} }
static propertyIfDefined(name, val, condition) { static propertyIfDefined(name, val, condition = (it) => true) {
return condition ? [`<b>${name}</b>: ${val}`] : []; return condition ? [`<b>${name}</b>: ${val}`] : [];
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_objetChatData() { _objetChatData() {
const tplData = Misc.templateData(this); const tplData = Misc.templateData(this);
let properties = [ let properties = [].concat(
`<b>Encombrement</b>: ${tplData.encombrement}` RdDItem.propertyIfDefined('Résistance', tplData.resistance, tplData.resistance),
] RdDItem.propertyIfDefined('Qualité', tplData.qualite, tplData.qualite),
RdDItem.propertyIfDefined('Encombrement', tplData.encombrement),
);
return properties; return properties;
} }
@ -268,8 +294,8 @@ export class RdDItem extends Item {
RdDItem.propertyIfDefined('Désaltère', tplData.desaltere, tplData.boisson), RdDItem.propertyIfDefined('Désaltère', tplData.desaltere, tplData.boisson),
RdDItem.propertyIfDefined('Force alcool', tplData.force, tplData.boisson && tplData.alcoolise), RdDItem.propertyIfDefined('Force alcool', tplData.force, tplData.boisson && tplData.alcoolise),
RdDItem.propertyIfDefined('Exotisme', tplData.exotisme, tplData.exotisme < 0), RdDItem.propertyIfDefined('Exotisme', tplData.exotisme, tplData.exotisme < 0),
[`<b>Qualité</b>: ${tplData.qualité}`], RdDItem.propertyIfDefined('Qualité', tplData.qualite, tplData.qualite),
[`<b>Encombrement</b>: ${tplData.encombrement}`], RdDItem.propertyIfDefined('Encombrement', tplData.encombrement),
); );
return properties; return properties;
} }

View File

@ -5,6 +5,7 @@ import { RdDCombat } from "./rdd-combat.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { TMRUtility } from "./tmr-utility.js"; import { TMRUtility } from "./tmr-utility.js";
import { DialogItemAchat } from "./dialog-item-achat.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
// This table starts at 0 -> niveau -10 // This table starts at 0 -> niveau -10
@ -546,6 +547,10 @@ export class RdDUtility {
let actor = game.actors.get(actorId); let actor = game.actors.get(actorId);
actor.tmrApp.lancerSortEnReserve(coord, sortId); actor.tmrApp.lancerSortEnReserve(coord, sortId);
}); });
// gestion bouton tchat Acheter
html.on("click", '.button-acheter', event => DialogItemAchat.onButtonAcheter(event));
// Gestion du bouton payer // Gestion du bouton payer
html.on("click", '.payer-button', event => { html.on("click", '.payer-button', event => {
let sumdenier = event.currentTarget.attributes['data-somme-denier']?.value ?? 0; let sumdenier = event.currentTarget.attributes['data-somme-denier']?.value ?? 0;
@ -571,8 +576,15 @@ export class RdDUtility {
} }
static findChatMessageId(current) { static findChatMessageId(current) {
const isChatMessageWithId = it => it.classList.contains('chat-message') && it.attributes.getNamedItem('data-message-id'); return RdDUtility.getChatMessageId(RdDUtility.findChatMessage(current));
return RdDUtility.findNodeMatching(current, isChatMessageWithId)?.attributes.getNamedItem('data-message-id').value; }
static getChatMessageId(node) {
return node?.attributes.getNamedItem('data-message-id')?.value;
}
static findChatMessage(current) {
return RdDUtility.findNodeMatching(current, it => it.classList.contains('chat-message') && it.attributes.getNamedItem('data-message-id'));
} }
static findNodeMatching(current, predicate) { static findNodeMatching(current, predicate) {
@ -585,22 +597,25 @@ export class RdDUtility {
return undefined; return undefined;
} }
static getSelectedActor(msgPlayer = '') { static getSelectedActor(msgPlayer = undefined) {
if (canvas.tokens.controlled.length == 1) { if (canvas.tokens.controlled.length == 1) {
let token = canvas.tokens.controlled[0]; let token = canvas.tokens.controlled[0];
if (token.actor && token.data.actorLink) { if (token.actor && token.data.actorLink) {
return token.actor; return token.actor;
} }
msgPlayer += "<br>le token sélectionné doit être lié à un personnage"; if (msgPlayer != undefined){
msgPlayer += "<br>le token sélectionné doit être lié à un personnage";
}
} }
if (game.user.character) { if (game.user.character) {
return game.user.character; return game.user.character;
} }
msgPlayer += "<br>vous pouvez sélectionner un seul token lié à un personnage"; if (msgPlayer != undefined){
msgPlayer += "<br>vous devez être connecté comme joueur avec un personnage sélectionné"; 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); ui.notifications.warn(msgPlayer);
ChatMessage.create({ content: msgPlayer, whisper: [game.user] }); ChatMessage.create({ content: msgPlayer, whisper: [game.user] });
}
return undefined; return undefined;
} }

View File

@ -14,10 +14,14 @@
<span class="item-quantite">{{numberFormat item.data.encTotal decimals=2}}</span> <span class="item-quantite">{{numberFormat item.data.encTotal decimals=2}}</span>
<div class="item-controls flex-grow"> <div class="item-controls flex-grow">
{{#unless item.estContenu}} {{#unless item.estContenu}}
<a class="item-control item-equip" title="Equiper">{{#if item.data.equipe}}<i class="fas fa-circle"></i>{{else}}<i class="fas fa-genderless"></i>{{/if}}</a> <a class="item-control item-equip" title="Equiper">{{#if item.data.equipe}}<i class="fas fa-hand-rock"></i>{{else}}<i class="fas fa-genderless"></i>{{/if}}</a>
{{/unless}} {{/unless}}
<a class="item-control item-edit" title="Editer"><i class="fas fa-edit"></i></a> <a class="item-control item-edit" title="Editer"><i class="fas fa-edit"></i></a>
<a class="item-control item-delete" title="Supprimer"><i class="fas fa-trash"></i></a> <a class="item-control item-delete" title="Supprimer"><i class="fas fa-trash"></i></a>
{{#if (or (eq item.type 'arme') (eq item.type 'conteneur') item.data.quantite)}}
&nbsp;
<a class="item-control item-vendre" title="Vendre ou donner"><i class="fas fa-comments-dollar"></i></a>
{{/if}}
{{#if item.data.actionPrincipale}} {{#if item.data.actionPrincipale}}
<a class="item-name item-action">{{item.data.actionPrincipale}}</a> <a class="item-name item-action">{{item.data.actionPrincipale}}</a>
{{/if}} {{/if}}

View File

@ -0,0 +1,8 @@
<img class="chat-icon" src="{{item.img}}" alt="{{item.name}}" />
<h4>{{#if isVente}}Achat{{else}}Don{{/if}}</h4>
<p>
{{#if acheteur}}{{acheteur.name}}{{else}}L'acheteur{{/if}} a
{{#if isVente}}acheté{{else}}pris{{/if}}
{{#if vendeur}}à {{vendeur.name}}{{/if}}
{{quantiteTotal}} {{item.name}} pour {{prixTotal}} sols.
</p>

View File

@ -0,0 +1,36 @@
<div class="post-item" data-transfer="{{transfer}}">
<h3>Acheter {{#if alias}}{{alias}} propose: {{/if}}{{item.name}}</h3>
{{#if item.img}}
<img src="{{item.img}}" title="{{item.name}}" />
{{/if}}
<p class="card-content">{{{item.data.description}}}</p>
<p>
{{#each properties as |property p|}}
<span>{{{property}}}</span><br>
{{/each}}
</p>
<hr>
<p>
{{#unless quantiteIllimite}}
<span>Lots disponibles: <span class="quantiteNbLots">{{quantiteNbLots}}</span></span><br>
{{/unless}}
{{#if (gt tailleLot 1)}}
<span>Lots de: <span class="tailleLot">{{tailleLot}}</span></span><br>
{{/if}}
{{#if prixLot}}
<span><strong>Prix {{#if (gt tailleLot 1)}}du lot {{else}}unitaire{{/if}}:
<span class="prixLot">{{prixLot}}</span> Sols</strong></span><br>
{{/if}}
</p>
<span class="chat-card-button-area">
<a class="button-acheter chat-card-button"
data-jsondata='{{jsondata}}'
{{#if actorId}}data-actorId='{{actorId}}'{{/if}}
data-tailleLot="{{tailleLot}}"
data-quantiteNbLots="{{quantiteNbLots}}"
data-quantiteIllimite="{{#if quantiteIllimite}}true{{else}}false{{/if}}"
data-prixLot="{{prixLot}}">
{{#if prixLot}}Acheter{{else}}Prendre{{/if}}</a>
</span>
</div>

View File

@ -0,0 +1,49 @@
<form class="rdddialog">
<div>
{{#if vendeur}}
<img class="chat-icon" src="{{vendeur.img}}" title="{{vendeur.name}}" alt="{{vendeur.name}}" />
{{/if}}
<img class="chat-icon" src="{{item.img}}" title="{{item.name}}" alt="{{item.name}}" />
{{!--
{{#if acheteur}}
<img class="chat-icon" src="{{acheteur.img}}" title="{{acheteur.name}}" alt="{{acheteur.name}}" />
{{/if}}
--}}
<h4>
{{#if isVente}}Acheter{{else}}Prendre{{/if}}
{{#if vendeur}}à {{vendeur.name}} {{/if}}:
{{item.name}}</h4>
</div>
{{#unless quantiteIllimite}}
<div class="flexrow flex-group-left">
<label>{{#if (gt tailleLot 1)}}Lots disponibles
{{else}}Quantité disponible{{/if}}</label>
<label>{{quantiteNbLots}}</label>
</div>
{{/unless}}
<div class="flexrow flex-group-left">
<label>
{{#if (gt tailleLot 1)}}Nombre de lots de {{tailleLot}}
{{else}}Quantité{{/if}}
</label>
<div class="flexrow">
<input name="nombreLots" class="nombreLots flex-shrink" type="number" min="1" max="{{quantiteNbLots}}"
value="{{nombreLots}}" data-dtype="Number" />
</div>
</div>
{{#if isVente}}
<div class="flexrow flex-group-left">
<label>Prix {{#if (gt tailleLot 1)}}du lot{{else}}unitaire{{/if}}</label>
<label>{{prixLot}} Sols</label>
</div>
<div class="flexrow flex-group-left">
<label>Prix total</label>
<span class="flexrow">
<span class="prixTotal">{{prixTotal}}</span>
<span>Sols</span>
</span>
</div>
{{/if}}
</div>
</form>

View File

@ -0,0 +1,41 @@
<form class="rdddialog">
<img class="chat-icon" src="{{item.img}}" title="{{item.name}}" alt="{{item.name}}" />
<h4>{{item.name}}</h4>
<div class="flexcol">
{{#if isOwned}}
<div class="flexrow flex-group-left">
<label>Quantité disponible</label>
<label>{{quantiteMax}}</label>
</div>
{{/if}}
<div class="flexrow flex-group-left">
<label>Nombre de lots</label>
<div class="flexrow">
{{#unless isOwned}}
<input name="quantiteIllimite" class="quantiteIllimite flex-shrink" type="checkbox" {{#if
quantiteIllimite}}checked{{/if}} />
<label class="label-quantiteIllimite flex-shrink">Illimités</label>
{{/unless}}
<input name="quantiteNbLots" class="quantiteNbLots flex-shrink" type="number" min="1"
max="{{quantiteMaxLots}}" value="{{quantiteNbLots}}" data-dtype="Number" />
</div>
</div>
<div class="flexrow flex-group-left">
<label for="tailleLot">Taille d'un lot</label>
<input name="tailleLot" class="tailleLot flex-shrink" type="number" min="1"
max="{{quantiteMax}}" value="{{tailleLot}}" data-dtype="Number" />
</div>
<div class="flexrow flex-group-left">
<label>Valeur unitaire</label>
<label>{{prixOrigine}} Sols</label>
</div>
<div class="flexrow flex-group-left">
<label for="prixLot">Prix du lot</label>
<span class="flexrow">
<input name="prixLot" class="prixLot flex-shrink" type="number" value="{{prixLot}}"
data-dtype="Number" />
<label>Sols</label>
</span>
</div>
</div>
</form>