Merge branch 'v1.4' of https://gitlab.com/LeRatierBretonnien/foundryvtt-reve-de-dragon into v1.4
This commit is contained in:
commit
bf9df5d68e
@ -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");
|
||||||
|
113
module/actor.js
113
module/actor.js
@ -649,7 +649,8 @@ export class RdDActor extends Actor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let deRecuperation = new Roll("1dr + 7").evaluate().total;
|
const roll = new Roll("1dr").evaluate();
|
||||||
|
let deRecuperation = roll.total;
|
||||||
console.log("recuperationReve", deRecuperation);
|
console.log("recuperationReve", deRecuperation);
|
||||||
if (deRecuperation >= 7) {
|
if (deRecuperation >= 7) {
|
||||||
// Rêve de Dragon !
|
// Rêve de Dragon !
|
||||||
@ -973,18 +974,16 @@ export class RdDActor extends Actor {
|
|||||||
|
|
||||||
async processDropItem(event, dragData, objetVersConteneur) {
|
async processDropItem(event, dragData, objetVersConteneur) {
|
||||||
console.log("DRAG", this.id, dragData);
|
console.log("DRAG", this.id, dragData);
|
||||||
const droppedItemId = dragData.id || dragData.data._id;
|
const itemId = dragData.id || dragData.data._id;
|
||||||
if (dragData.actorId && dragData.actorId != this.id) {
|
if (dragData.actorId && dragData.actorId != this.id) {
|
||||||
console.log("Moving objects", dragData);
|
console.log("Moving objects", dragData);
|
||||||
this.moveItemsBetweenActors(droppedItemId, dragData.actorId);
|
this.moveItemsBetweenActors(itemId, 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 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];
|
||||||
@ -1010,8 +1009,8 @@ export class RdDActor extends Actor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await this.computeEncombrementTotalEtMalusArmure();
|
|
||||||
}
|
}
|
||||||
|
await this.computeEncombrementTotalEtMalusArmure();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@ -1072,7 +1071,7 @@ export class RdDActor extends Actor {
|
|||||||
|
|
||||||
async regrouperEquipementsSimilaires(item, dest) {
|
async regrouperEquipementsSimilaires(item, dest) {
|
||||||
await dest.quantiteIncDec(Misc.templateData(item).quantite);
|
await dest.quantiteIncDec(Misc.templateData(item).quantite);
|
||||||
await this.deleteEmbeddedDocuments('Item', [item.id]);
|
await item.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@ -1751,7 +1750,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);
|
||||||
@ -3226,9 +3225,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
|
||||||
@ -3251,6 +3248,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] });
|
||||||
@ -3264,7 +3272,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.`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3278,6 +3286,85 @@ export class RdDActor extends Actor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
async achatVente(vendeurId, acheteurId, venteData, chatMessageIdVente) {
|
||||||
|
if (vendeurId == acheteurId){
|
||||||
|
ui.notifications.info("Inutile de se vendre à soi-même");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
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.quantiteTotal : 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.quantiteTotal;
|
||||||
|
if (qtReste == 0) {
|
||||||
|
vendeur.deleteEmbeddedDocuments("Item", itemId);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vendeur.updateEmbeddedDocuments("Item", [{ _id: itemId, 'data.quantite': qtReste }]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (acheteur) {
|
||||||
|
// TODO: achat depuis un compendium
|
||||||
|
const achat = duplicate(Misc.data(vendeur?.getObjet(itemId) ?? game.items.get(itemId)));
|
||||||
|
achat.data.quantite = venteData.quantiteTotal;
|
||||||
|
achat._id = undefined;
|
||||||
|
// TODO: investigate bug - création marche mal...
|
||||||
|
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)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (venteData.quantiteNbLots <= venteData.nombreLots) {
|
||||||
|
ChatUtility.removeChatMessageId(chatMessageIdVente);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
venteData.quantiteNbLots -= venteData.nombreLots;
|
||||||
|
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'));
|
||||||
|
87
module/dialog-item-achat.js
Normal file
87
module/dialog-item-achat.js
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
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-vendeurId']?.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,
|
||||||
|
vendeurId: vendeurId,
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
90
module/dialog-item-vente.js
Normal file
90
module/dialog-item-vente.js
Normal 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,
|
||||||
|
vendeurId: 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)
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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";
|
||||||
@ -28,14 +27,23 @@ export class RdDItemSheet extends ItemSheet {
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
_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
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,11 +112,11 @@ export class RdDItemSheet extends ItemSheet {
|
|||||||
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));
|
||||||
|
|
||||||
@ -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`;
|
||||||
|
@ -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);
|
||||||
@ -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() {
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
if (msgPlayer != undefined){
|
||||||
msgPlayer += "<br>le token sélectionné doit être lié à un personnage";
|
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;
|
||||||
}
|
}
|
||||||
|
if (msgPlayer != undefined){
|
||||||
msgPlayer += "<br>vous pouvez sélectionner un seul token lié à un personnage";
|
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é";
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)}}
|
||||||
|
|
||||||
|
<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}}
|
||||||
|
8
templates/chat-achat-item.html
Normal file
8
templates/chat-achat-item.html
Normal 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>
|
36
templates/chat-vente-item.html
Normal file
36
templates/chat-vente-item.html
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<div class="post-item" data-transfer="{{transfer}}">
|
||||||
|
<h3>{{#if alias}}{{alias}} propose:{{else}}Acheter {{/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 vendeurId}}data-vendeurId='{{vendeurId}}'{{/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>
|
49
templates/dialog-item-achat.html
Normal file
49
templates/dialog-item-achat.html
Normal 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>
|
41
templates/dialog-item-vente.html
Normal file
41
templates/dialog-item-vente.html
Normal 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>
|
Loading…
Reference in New Issue
Block a user