Ecole de commerce
This commit is contained in:
parent
65a4e1ec69
commit
c4cb3bf60d
@ -239,6 +239,12 @@ export class RdDActorSheet extends ActorSheet {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
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 => {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
const itemId = li.data("item-id");
|
||||
|
106
module/actor.js
106
module/actor.js
@ -969,12 +969,11 @@ export class RdDActor extends Actor {
|
||||
this.moveItemsBetweenActors(droppedItemId, dragData.actorId);
|
||||
return false;
|
||||
}
|
||||
|
||||
let result = true;
|
||||
const destId = $(event.target).parents(".item").attr("data-item-id");
|
||||
const itemId = dragData.id || dragData.data._id;
|
||||
const item = this.getObjet(itemId);
|
||||
if (item.isEquipement()) {
|
||||
if (item?.isEquipement()) {
|
||||
if (dragData.actorId == this.id) {
|
||||
// rangement
|
||||
const srcId = objetVersConteneur[itemId];
|
||||
@ -1000,8 +999,8 @@ export class RdDActor extends Actor {
|
||||
}
|
||||
}
|
||||
}
|
||||
await this.computeEncombrementTotalEtMalusArmure();
|
||||
}
|
||||
await this.computeEncombrementTotalEtMalusArmure();
|
||||
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);
|
||||
let compteur = sante[name];
|
||||
@ -1667,7 +1666,7 @@ export class RdDActor extends Actor {
|
||||
|
||||
let enduranceLost = new Roll("1d6").roll().total;
|
||||
rollDataView.enduranceLost = enduranceLost;
|
||||
await this.santeIncDec("endurance", -enduranceLost, {ethylisme:true});
|
||||
await this.santeIncDec("endurance", -enduranceLost, { ethylisme: true });
|
||||
// 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);
|
||||
rollDataView.rollVolonteIsSuccess = rollVolonte.isSuccess;
|
||||
@ -1741,7 +1740,7 @@ export class RdDActor extends Actor {
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}
|
||||
const surmonteExotisme = await this.surmonterExotisme(item, choix);
|
||||
@ -2946,7 +2945,7 @@ export class RdDActor extends Actor {
|
||||
const perteVie = this.isEntiteCauchemar()
|
||||
? { newValue: 0 }
|
||||
: 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.sheet.render(false);
|
||||
@ -3210,9 +3209,7 @@ export class RdDActor extends Actor {
|
||||
if (fortune >= depense) {
|
||||
fortune -= depense;
|
||||
const toActor = game.actors.get(toActorId)
|
||||
if (toActor) {
|
||||
toActor.ajouterDeniers(depense, this.id);
|
||||
}
|
||||
await 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
|
||||
@ -3235,6 +3232,17 @@ export class RdDActor extends Actor {
|
||||
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) {
|
||||
if (fromActorId && !game.user.isGM) {
|
||||
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
|
||||
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.`
|
||||
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) {
|
||||
let recetteData = Misc.data(this.getItemOfType(recetteId, 'recettealchimique'));
|
||||
|
86
module/dialog-item-achat.js
Normal file
86
module/dialog-item-achat.js
Normal 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);
|
||||
}
|
||||
|
||||
}
|
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,
|
||||
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)
|
||||
}
|
||||
}
|
@ -43,4 +43,8 @@ export class Monnaie {
|
||||
static deValeur(monnaie, v) {
|
||||
return v != monnaie.data.valeur_deniers;
|
||||
}
|
||||
|
||||
static arrondiDeniers(sols) {
|
||||
return sols.toFixed(2);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { RdDItemSort } from "./item-sort.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
import { RdDItem } from "./item.js";
|
||||
import { RdDAlchimie } from "./rdd-alchimie.js";
|
||||
import { RdDItemCompetence } from "./item-competence.js";
|
||||
import { RdDHerbes } from "./rdd-herbes.js";
|
||||
@ -15,45 +14,54 @@ import { ReglesOptionelles } from "./regles-optionelles.js";
|
||||
export class RdDItemSheet extends ItemSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: ["foundryvtt-reve-de-dragon", "sheet", "item"],
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/item-sheet.html",
|
||||
width: 550,
|
||||
height: 550
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: ["foundryvtt-reve-de-dragon", "sheet", "item"],
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/item-sheet.html",
|
||||
width: 550,
|
||||
height: 550
|
||||
//tabs: [{navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description"}]
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_getHeaderButtons() {
|
||||
let buttons = super._getHeaderButtons();
|
||||
const videSiConteneur = this.object.isConteneur() ? this.object.isVide() : true;
|
||||
// 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!
|
||||
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",
|
||||
icon: "fas fa-comment",
|
||||
onclick: ev => this.item.postItem()
|
||||
})
|
||||
});
|
||||
}
|
||||
return buttons
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
setPosition(options={}) {
|
||||
setPosition(options = {}) {
|
||||
const position = super.setPosition(options);
|
||||
const sheetBody = this.element.find(".sheet-body");
|
||||
const bodyHeight = position.height - 192;
|
||||
sheetBody.css("height", bodyHeight);
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async getData() {
|
||||
const objectData = Misc.data(this.object);
|
||||
|
||||
let formData ={
|
||||
let formData = {
|
||||
title: objectData.name,
|
||||
id: objectData.id,
|
||||
type: objectData.type,
|
||||
@ -66,57 +74,57 @@ export class RdDItemSheet extends ItemSheet {
|
||||
cssClass: this.isEditable ? "editable" : "locked",
|
||||
isSoins: false
|
||||
}
|
||||
if ( this.actor ) {
|
||||
if (this.actor) {
|
||||
formData.isOwned = true;
|
||||
formData.actorId = this.actor.id;
|
||||
}
|
||||
|
||||
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.competences = await RdDUtility.loadCompendium( 'foundryvtt-reve-de-dragon.competences' );
|
||||
formData.competences = await RdDUtility.loadCompendium('foundryvtt-reve-de-dragon.competences');
|
||||
}
|
||||
if (formData.type == 'arme') {
|
||||
formData.competences = await RdDUtility.loadCompendium( 'foundryvtt-reve-de-dragon.competences', it => RdDItemCompetence.isCompetenceArme(it));
|
||||
if (formData.type == 'arme') {
|
||||
formData.competences = await RdDUtility.loadCompendium('foundryvtt-reve-de-dragon.competences', it => RdDItemCompetence.isCompetenceArme(it));
|
||||
console.log(formData.competences);
|
||||
}
|
||||
if ( formData.type == 'recettealchimique' ) {
|
||||
RdDAlchimie.processManipulation(objectData, this.actor && this.actor.id );
|
||||
if (formData.type == 'recettealchimique') {
|
||||
RdDAlchimie.processManipulation(objectData, this.actor && this.actor.id);
|
||||
}
|
||||
if ( formData.type == 'potion') {
|
||||
if (formData.type == 'potion') {
|
||||
if (this.dateUpdated) {
|
||||
formData.data.prdate = this.dateUpdated;
|
||||
this.dateUpdated = undefined;
|
||||
}
|
||||
RdDHerbes.updatePotionData(formData);
|
||||
}
|
||||
if ( formData.isOwned && formData.type == 'herbe' && (formData.data.categorie == 'Soin' || formData.data.categorie == 'Repos') ) {
|
||||
formData.isIngredientPotionBase = true;
|
||||
}
|
||||
if (formData.isOwned && formData.type == 'herbe' && (formData.data.categorie == 'Soin' || formData.data.categorie == 'Repos')) {
|
||||
formData.isIngredientPotionBase = true;
|
||||
}
|
||||
formData.bonusCaseList = RdDItemSort.getBonusCaseList(formData, true);
|
||||
|
||||
return formData;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
activateListeners(html) {
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
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
|
||||
if (!this.options.editable) return;
|
||||
|
||||
|
||||
// Select competence categorie
|
||||
html.find(".categorie").change(event => this._onSelectCategorie(event));
|
||||
|
||||
html.find('.sheet-competence-xp').change((event) => {
|
||||
if ( this.object.data.type == 'competence') {
|
||||
RdDUtility.checkThanatosXP( this.object.data.name );
|
||||
if (this.object.data.type == 'competence') {
|
||||
RdDUtility.checkThanatosXP(this.object.data.name);
|
||||
}
|
||||
} );
|
||||
});
|
||||
|
||||
html.find('.enchanteDate').change((event) => {
|
||||
let jour = Number($('#jourMois').val());
|
||||
@ -126,35 +134,35 @@ export class RdDItemSheet extends ItemSheet {
|
||||
|
||||
html.find('.creer-tache-livre').click((event) => {
|
||||
let actorId = event.currentTarget.attributes['data-actor-id'].value;
|
||||
let actor = game.actors.get( actorId );
|
||||
actor.creerTacheDepuisLivre( this.item );
|
||||
let actor = game.actors.get(actorId);
|
||||
actor.creerTacheDepuisLivre(this.item);
|
||||
});
|
||||
html.find('.consommer-potion').click((event) => {
|
||||
let actorId = event.currentTarget.attributes['data-actor-id'].value;
|
||||
let actor = game.actors.get( actorId );
|
||||
actor.consommerPotion( this.item );
|
||||
let actor = game.actors.get(actorId);
|
||||
actor.consommerPotion(this.item);
|
||||
});
|
||||
html.find('.creer-potion-base').click((event) => {
|
||||
let actorId = event.currentTarget.attributes['data-actor-id'].value;
|
||||
let actor = game.actors.get( actorId );
|
||||
actor.dialogFabriquerPotion( this.item );
|
||||
let actor = game.actors.get(actorId);
|
||||
actor.dialogFabriquerPotion(this.item);
|
||||
});
|
||||
|
||||
|
||||
html.find('.alchimie-tache a').click((event) => {
|
||||
let actorId = event.currentTarget.attributes['data-actor-id'].value;
|
||||
let recetteId = event.currentTarget.attributes['data-recette-id'].value;
|
||||
let tacheName = event.currentTarget.attributes['data-alchimie-tache'].value;
|
||||
let tacheData = event.currentTarget.attributes['data-alchimie-data'].value;
|
||||
let actor = game.actors.get( actorId );
|
||||
if ( actor ) {
|
||||
let actor = game.actors.get(actorId);
|
||||
if (actor) {
|
||||
actor.effectuerTacheAlchimie(recetteId, tacheName, tacheData);
|
||||
} else {
|
||||
ui.notifications.info("Impossible trouver un actur pour réaliser cette tache Alchimique.");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async _onSelectCategorie(event) {
|
||||
event.preventDefault();
|
||||
@ -167,8 +175,7 @@ export class RdDItemSheet extends ItemSheet {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
get template()
|
||||
{
|
||||
get template() {
|
||||
//console.log(this);
|
||||
let type = this.object.data.type;
|
||||
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
|
||||
//console.log("UPDATE !", formData);
|
||||
// Données de bonus de cases ?
|
||||
formData = RdDItemSort.buildBonusCaseStringFromFormData( formData );
|
||||
|
||||
formData = RdDItemSort.buildBonusCaseStringFromFormData(formData);
|
||||
|
||||
return this.object.update(formData);
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { DialogItemVente } from "./dialog-item-vente.js";
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { Misc } from "./misc.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
@ -24,6 +25,9 @@ export class RdDItem extends Item {
|
||||
isConteneur() {
|
||||
return Misc.data(this).type == 'conteneur';
|
||||
}
|
||||
isVide() {
|
||||
return this.isConteneur() && (Misc.templateData(this).contenu ?? []).length == 0;
|
||||
}
|
||||
|
||||
isAlcool() {
|
||||
const itemData = Misc.data(this);
|
||||
@ -37,13 +41,13 @@ export class RdDItem extends Item {
|
||||
isEquipement() {
|
||||
return RdDItem.getTypeObjetsEquipement().includes(Misc.data(this).type);
|
||||
}
|
||||
|
||||
|
||||
isCristalAlchimique() {
|
||||
const itemData = Misc.data(this);
|
||||
return itemData.type == 'objet' && Grammar.toLowerCaseNoAccent(itemData.name) == 'cristal alchimique' && itemData.data.quantite > 0;
|
||||
}
|
||||
|
||||
isMagique(){
|
||||
isMagique() {
|
||||
return Misc.templateData(this.object).magique;
|
||||
}
|
||||
|
||||
@ -118,12 +122,12 @@ export class RdDItem extends Item {
|
||||
|
||||
async quantiteIncDec(nombre, options = { diminuerQuantite: true, supprimerSiZero: false }) {
|
||||
const itemData = Misc.data(this);
|
||||
const quantite = Number(itemData.data.quantite ??-1);
|
||||
if (quantite >=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){
|
||||
if (options.supprimerSiZero) {
|
||||
ui.notifications.notify(`${itemData.name} supprimé de votre équipement`);
|
||||
await this.delete();
|
||||
}
|
||||
@ -157,6 +161,26 @@ export class RdDItem extends Item {
|
||||
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() {
|
||||
@ -164,8 +188,8 @@ 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 };
|
||||
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;
|
||||
@ -184,7 +208,7 @@ export class RdDItem extends Item {
|
||||
</div>
|
||||
<p>Modifier la prix?</p>
|
||||
<div class="form-group">
|
||||
<label> Prix en Sols</label>
|
||||
<label>Prix en Sols</label>
|
||||
<input name="price" type="text" value="${chatData.data.cout}"/>
|
||||
</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];
|
||||
if (quantiteEnvoi > 0) {
|
||||
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}`] : [];
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_objetChatData() {
|
||||
const tplData = Misc.templateData(this);
|
||||
let properties = [
|
||||
`<b>Encombrement</b>: ${tplData.encombrement}`
|
||||
]
|
||||
let properties = [].concat(
|
||||
RdDItem.propertyIfDefined('Résistance', tplData.resistance, tplData.resistance),
|
||||
RdDItem.propertyIfDefined('Qualité', tplData.qualite, tplData.qualite),
|
||||
RdDItem.propertyIfDefined('Encombrement', tplData.encombrement),
|
||||
);
|
||||
return properties;
|
||||
}
|
||||
|
||||
@ -268,8 +294,8 @@ export class RdDItem extends Item {
|
||||
RdDItem.propertyIfDefined('Désaltère', tplData.desaltere, tplData.boisson),
|
||||
RdDItem.propertyIfDefined('Force alcool', tplData.force, tplData.boisson && tplData.alcoolise),
|
||||
RdDItem.propertyIfDefined('Exotisme', tplData.exotisme, tplData.exotisme < 0),
|
||||
[`<b>Qualité</b>: ${tplData.qualité}`],
|
||||
[`<b>Encombrement</b>: ${tplData.encombrement}`],
|
||||
RdDItem.propertyIfDefined('Qualité', tplData.qualite, tplData.qualite),
|
||||
RdDItem.propertyIfDefined('Encombrement', tplData.encombrement),
|
||||
);
|
||||
return properties;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import { RdDCombat } from "./rdd-combat.js";
|
||||
import { Misc } from "./misc.js";
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { TMRUtility } from "./tmr-utility.js";
|
||||
import { DialogItemAchat } from "./dialog-item-achat.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
// This table starts at 0 -> niveau -10
|
||||
@ -546,6 +547,10 @@ export class RdDUtility {
|
||||
let actor = game.actors.get(actorId);
|
||||
actor.tmrApp.lancerSortEnReserve(coord, sortId);
|
||||
});
|
||||
|
||||
// gestion bouton tchat Acheter
|
||||
html.on("click", '.button-acheter', event => DialogItemAchat.onButtonAcheter(event));
|
||||
|
||||
// Gestion du bouton payer
|
||||
html.on("click", '.payer-button', event => {
|
||||
let sumdenier = event.currentTarget.attributes['data-somme-denier']?.value ?? 0;
|
||||
@ -571,8 +576,15 @@ export class RdDUtility {
|
||||
}
|
||||
|
||||
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;
|
||||
return RdDUtility.getChatMessageId(RdDUtility.findChatMessage(current));
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -585,22 +597,25 @@ export class RdDUtility {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
static getSelectedActor(msgPlayer = '') {
|
||||
static getSelectedActor(msgPlayer = undefined) {
|
||||
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 (msgPlayer != undefined){
|
||||
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] });
|
||||
if (msgPlayer != undefined){
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -14,10 +14,14 @@
|
||||
<span class="item-quantite">{{numberFormat item.data.encTotal decimals=2}}</span>
|
||||
<div class="item-controls flex-grow">
|
||||
{{#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}}
|
||||
<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>
|
||||
{{#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}}
|
||||
<a class="item-name item-action">{{item.data.actionPrincipale}}</a>
|
||||
{{/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>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>
|
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