L'appréciation utilise: - un niveau de qualité (qui réutilise la qualité sur les items en ayant) - un bon moment (coeur/musique/...) - un niveau de jet de moral - une caractéristique (perception) - une compétence Les bon moments passés sont remis à zéro lors du passage de château dormant. Ajout des jets de moral très heureux. Ajout de jet d'appréciation sur les résultats des oeuvres et des jeux.
345 lines
13 KiB
JavaScript
345 lines
13 KiB
JavaScript
import { ACTOR_TYPES, ITEM_TYPES } from "./constants.js";
|
|
|
|
import { RdDItem } from "./item.js";
|
|
import { RdDItemCompetence } from "./item-competence.js";
|
|
import { RdDItemSort } from "./item-sort.js";
|
|
import { RdDUtility } from "./rdd-utility.js";
|
|
import { HtmlUtility } from "./html-utility.js";
|
|
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
|
|
import { SYSTEM_RDD } from "./constants.js";
|
|
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
|
|
import { SystemCompendiums } from "./settings/system-compendiums.js";
|
|
import { Misc } from "./misc.js";
|
|
import { RdDTimestamp } from "./time/rdd-timestamp.js";
|
|
import { FLEUVE_COORD, TMRUtility } from "./tmr-utility.js";
|
|
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
|
|
import { ItemAction } from "./item/item-actions.js";
|
|
import { SANS_COMPETENCE } from "./item/base-items.js";
|
|
import { Apprecier } from "./moral/apprecier.mjs";
|
|
|
|
/**
|
|
* Extend the basic ItemSheet for RdD specific items
|
|
*/
|
|
export class RdDItemSheetV1 extends foundry.appv1.sheets.ItemSheet {
|
|
|
|
static get ITEM_TYPE() {
|
|
return undefined
|
|
}
|
|
|
|
static defaultTemplate(type) {
|
|
return type ?
|
|
`systems/foundryvtt-reve-de-dragon/templates/item/${type}-sheet.hbs` :
|
|
"systems/foundryvtt-reve-de-dragon/templates/item/item-sheet.hbs";
|
|
}
|
|
|
|
static register(sheetClass) {
|
|
foundry.documents.collections.Items.registerSheet(SYSTEM_RDD, sheetClass, {
|
|
label: Misc.typeName('Item', sheetClass.ITEM_TYPE),
|
|
types: [sheetClass.ITEM_TYPE],
|
|
makeDefault: true
|
|
})
|
|
}
|
|
|
|
/** @override */
|
|
static get defaultOptions() {
|
|
return foundry.utils.mergeObject(super.defaultOptions, {
|
|
classes: [SYSTEM_RDD, "sheet", "item"],
|
|
template: RdDItemSheetV1.defaultTemplate(RdDItemSheetV1.ITEM_TYPE),
|
|
width: 550,
|
|
height: 550
|
|
}, { inplace: false });
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
get template() {
|
|
return RdDItemSheetV1.defaultTemplate(this.item.type);
|
|
}
|
|
|
|
get title() {
|
|
const owner = (this.item.parent instanceof Actor) ? `(${this.item.parent.name})` : '';
|
|
return `${Misc.typeName('Item', this.item.type)}: ${this.item.name} ${owner}`;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
_getHeaderButtons() {
|
|
let buttons = super._getHeaderButtons();
|
|
if (this.item.isInventaire() && this.item.isVideOuNonConteneur()) {
|
|
buttons.unshift({
|
|
class: "vendre",
|
|
icon: "fas fa-comments-dollar",
|
|
onclick: ev => this.item.proposerVente(1)
|
|
});
|
|
}
|
|
buttons.unshift({
|
|
class: "montrer",
|
|
icon: "fas fa-comment",
|
|
onclick: ev => this.item.postItemToChat()
|
|
});
|
|
return buttons
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
/** @override */
|
|
setPosition(options = {}) {
|
|
const position = super.setPosition(options);
|
|
const sheetHeader = this.element.find(".sheet-header");
|
|
const sheetBody = this.element.find(".sheet-body");
|
|
const bodyHeight = position.height - sheetHeader[0].clientHeight;
|
|
sheetBody.css("height", bodyHeight);
|
|
return position;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
async getData() {
|
|
const competences = (await SystemCompendiums.getCompetences(ACTOR_TYPES.personnage))
|
|
let formData = {
|
|
title: this.item.name,
|
|
id: this.item.id,
|
|
type: this.item.type,
|
|
img: this.item.img,
|
|
name: this.item.name,
|
|
system: this.item.system,
|
|
actorId: this.actor?.id,
|
|
description: await RdDTextEditor.enrichHTML(this.item.system.description, this.item),
|
|
descriptionmj: await RdDTextEditor.enrichHTML(this.item.system.descriptionmj, this.item),
|
|
isComestible: this.item.getUtilisationCuisine(),
|
|
options: RdDSheetUtility.mergeDocumentRights({}, this.item, this.isEditable),
|
|
competences: [SANS_COMPETENCE, ...competences],
|
|
categories: RdDItem.getCategories(this.item.type),
|
|
isAppreciable: Apprecier.isAppreciable(this.item)
|
|
}
|
|
|
|
if (this.item.type == ITEM_TYPES.competencecreature) {
|
|
formData.isparade = this.item.isParade()
|
|
formData.isdommages = this.item.isDommages()
|
|
}
|
|
if (this.item.type == ITEM_TYPES.tache ||
|
|
this.item.type == ITEM_TYPES.livre ||
|
|
this.item.type == ITEM_TYPES.meditation ||
|
|
this.item.type == ITEM_TYPES.oeuvre) {
|
|
formData.caracList = foundry.utils.duplicate(game.model.Actor.personnage.carac)
|
|
formData.caracList["reve-actuel"] = foundry.utils.duplicate(game.model.Actor.personnage.reve.reve)
|
|
}
|
|
if (this.item.type == ITEM_TYPES.arme) {
|
|
formData.competences = formData.competences.filter(it => it.isCompetenceArme())
|
|
}
|
|
if (this.item.type == ITEM_TYPES.recettecuisine) {
|
|
formData.ingredients = await RdDTextEditor.enrichHTML(this.item.system.ingredients, this.item)
|
|
}
|
|
if (this.item.type == ITEM_TYPES.extraitpoetique) {
|
|
formData.extrait = await RdDTextEditor.enrichHTML(this.item.system.extrait, this.item)
|
|
formData.texte = await RdDTextEditor.enrichHTML(this.item.system.texte, this.item)
|
|
}
|
|
if (this.item.type == ITEM_TYPES.recettealchimique) {
|
|
formData.manipulation = await RdDTextEditor.enrichHTML(this.item.system.manipulation, this.item)
|
|
formData.utilisation = await RdDTextEditor.enrichHTML(this.item.system.utilisation, this.item)
|
|
formData.enchantement = await RdDTextEditor.enrichHTML(this.item.system.enchantement, this.item)
|
|
formData.sureffet = await RdDTextEditor.enrichHTML(this.item.system.sureffet, this.item)
|
|
}
|
|
|
|
if (this.item.type == ITEM_TYPES.herbe) {
|
|
if (formData.options.isOwned && ['Soin', 'Repos'].includes(formData.system.categorie)) {
|
|
formData.isIngredientPotionBase = true;
|
|
}
|
|
}
|
|
if (this.item.type == ITEM_TYPES.sortreserve) {
|
|
const sortId = this.item.system.sortid;
|
|
formData.competences = formData.competences.filter(it => RdDItemCompetence.isDraconic(it));
|
|
formData.sort = formData.options.isOwned ? this.item.actor.items.get(sortId) : game.items.get(sortId);
|
|
}
|
|
if (this.item.type == ITEM_TYPES.sort) {
|
|
formData.competences = formData.competences.filter(it => RdDItemCompetence.isDraconic(it));
|
|
formData.bonusCaseList = RdDItemSort.getBonusCaseList(this.item);
|
|
}
|
|
return formData;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
/** @override */
|
|
activateListeners(html) {
|
|
super.activateListeners(html);
|
|
this.html = html;
|
|
|
|
HtmlUtility.showControlWhen(this.html.find(".item-cout"), ReglesOptionnelles.isUsing('afficher-prix-joueurs')
|
|
|| game.user.isGM
|
|
|| !this.item.isOwned)
|
|
HtmlUtility.showControlWhen(this.html.find(".item-magique"), this.item.isMagique)
|
|
|
|
// Everything below here is only needed if the sheet is editable
|
|
if (!this.options.editable) return
|
|
|
|
this.form.ondragstart = async event => await this._onDragStart(event)
|
|
this.form.ondrop = async event => await this._onDrop(event)
|
|
|
|
// Select competence categorie
|
|
this.html.find(".categorie").change(async event => await this._onSelectCategorie(event))
|
|
|
|
this.html.find('.sheet-competence-xp').change(event => RdDUtility.checkThanatosXP(this.item))
|
|
this.html.find(".item-cout input[name='system.cout']").change(event => {
|
|
if (this.item.isMonnaie()) {
|
|
const value = event.currentTarget.value;
|
|
if (Number(value) == 0) {
|
|
ui.notifications.error(`${this.actor?.name ?? 'Monnaie'}: La monnaie ${this.item.name} a maintenant une valeur de 0, et ne peut plus être utilisée pour payer!`)
|
|
}
|
|
}
|
|
})
|
|
this.html.find('.delete-bonus-case').click(async event => await this.supprimerBonusCase(event.currentTarget.attributes['data-deleteCoord'].value))
|
|
this.html.find('.creer-tache-livre').click(async event => await this._getEventActor(event).creerTacheDepuisLivre(this.item))
|
|
this.html.find('.creer-potion-base').click(async event => await this._getEventActor(event).fabriquerDecoctionHerbe(this.item))
|
|
this.html.find('input[name="system.cacher_points_de_tache"]').change(async event =>
|
|
await this.item.update({ 'system.cacher_points_de_tache': event.currentTarget.checked })
|
|
)
|
|
|
|
this.html.find('.roll-text').click(async event => await RdDTextEditor.rollText(event, this.actor))
|
|
this.html.find('.chat-roll-text').click(async event => await RdDTextEditor.chatRollText(event))
|
|
|
|
if (this.actor) {
|
|
this.html.find('.actionItem').click(async event => await ItemAction.onActionItem(event, this.actor, this.options))
|
|
|
|
// TODO: utiliser un itemAction?
|
|
this.html.find('.item-potion-consommer').click(async event => await this.itemActionConsommer(event))
|
|
|
|
this.html.find('.item-quantite-plus').click(async event => {
|
|
await this.actor.itemQuantiteIncDec(RdDSheetUtility.getItemId(event), 1)
|
|
//this.render()
|
|
})
|
|
this.html.find('.item-quantite-moins').click(async event => {
|
|
await this.actor.itemQuantiteIncDec(RdDSheetUtility.getItemId(event), -1)
|
|
//this.render()
|
|
})
|
|
}
|
|
|
|
const updateItemTimestamp = (path, timestamp) => this.item.update({ [path]: foundry.utils.duplicate(timestamp) })
|
|
|
|
RdDTimestamp.handleTimestampEditor(this.html, 'system.temporel.debut', updateItemTimestamp)
|
|
RdDTimestamp.handleTimestampEditor(this.html, 'system.temporel.fin', updateItemTimestamp)
|
|
}
|
|
|
|
async itemActionDelete(event) {
|
|
const item = RdDSheetUtility.getItem(event, this.actor)
|
|
return await RdDUtility.confirmActorItemDelete(item, this.actor)
|
|
}
|
|
|
|
async itemActionConsommer(event) {
|
|
const item = RdDSheetUtility.getItem(event, this.actor)
|
|
if (item) {
|
|
await actor.consommerPotion(item)
|
|
await RdDSheetUtility.renderItemBranch(this.actor, item)
|
|
}
|
|
}
|
|
|
|
async itemActionSplit(event) {
|
|
const item = RdDSheetUtility.getItem(event, this.actor)
|
|
if (item) {
|
|
await RdDSheetUtility.splitItem(item, this.actor)
|
|
await RdDSheetUtility.renderItemBranch(this.actor, item)
|
|
}
|
|
}
|
|
|
|
_getEventActor(event) { return game.actors.get(event.currentTarget.attributes['data-actor-id'].value) }
|
|
|
|
/* -------------------------------------------- */
|
|
async _onSelectCategorie(event) {
|
|
event.preventDefault();
|
|
|
|
if (this.item.isCompetence()) {
|
|
const categorie = event.currentTarget.value;
|
|
const level = RdDItemCompetence.getNiveauBase(categorie, this.item.type);
|
|
this.item.system.base = level;
|
|
this.html.find('[name="system.base"]').val(level);
|
|
}
|
|
}
|
|
|
|
async supprimerBonusCase(deleteCoord) {
|
|
if (this.item.type == ITEM_TYPES.sort) {
|
|
const oldList = RdDItemSort.getBonusCaseList(this.item)
|
|
const newList = oldList.filter(it => it.case != deleteCoord);
|
|
if (newList.length != oldList.length) {
|
|
await this.item.update({
|
|
'system.bonuscase': RdDItemSort.bonuscasesToString(newList)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
/** @override */
|
|
async _updateObject(event, formData) {
|
|
switch (this.item.type) {
|
|
case ITEM_TYPES.sort:
|
|
formData['system.bonuscase'] = RdDItemSort.bonuscasesToString(RdDItemSheetV1._listCaseTmr(
|
|
formData.caseTmrCoord,
|
|
formData.caseTmrBonus,
|
|
formData.caseTmrAdd
|
|
))
|
|
break
|
|
case ITEM_TYPES.competence:
|
|
formData['system.niveau'] = formData['system.niveau'] ?? formData['system.base']
|
|
break
|
|
}
|
|
return await super._updateObject(event, formData)
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
/**
|
|
* reconstruit les bonus de cases
|
|
* @param {*} caseTmrCoord tableau des coordonées
|
|
* @param {*} caseTmrBonus tableau des bonus
|
|
* @param {*} caseTmrAdd case à ajouter
|
|
* @returns list d'objets {coord, bonus}
|
|
*/
|
|
static _listCaseTmr(caseTmrCoord, caseTmrBonus, caseTmrAdd) {
|
|
const listCaseTmrCoord = caseTmrCoord == undefined ? [] : Array.isArray(caseTmrCoord) ? caseTmrCoord : [caseTmrCoord]
|
|
const listCaseTmrBonus = caseTmrBonus == undefined ? [] : Array.isArray(caseTmrBonus) ? caseTmrBonus : [caseTmrBonus]
|
|
if (caseTmrAdd != undefined && caseTmrAdd != '' && TMRUtility.verifyTMRCoord(caseTmrAdd) && !listCaseTmrCoord.includes(caseTmrAdd)) {
|
|
listCaseTmrCoord.push(TMRUtility.getTMR(caseTmrAdd).coord)
|
|
listCaseTmrBonus.push(1)
|
|
}
|
|
|
|
const list = [];
|
|
const caseChecked = {};
|
|
for (let i = 0; i < listCaseTmrBonus.length && i < listCaseTmrCoord.length; i++) {
|
|
const coord = listCaseTmrCoord[i] == FLEUVE_COORD ? FLEUVE_COORD : (listCaseTmrCoord[i]?.toUpperCase() ?? 'A1')
|
|
const bonus = listCaseTmrBonus[i] ?? 0
|
|
if (TMRUtility.verifyTMRCoord(coord) && bonus >= 0 && !caseChecked[coord]) {
|
|
caseChecked[coord] = coord
|
|
list.push({ case: coord, bonus: bonus })
|
|
}
|
|
}
|
|
return list
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
async _onDragStart(event) { }
|
|
async _onDropItem(event, dragData) { }
|
|
async _onDropActor(event, dragData) { }
|
|
|
|
async _onDrop(event) {
|
|
// Try to extract the dragData
|
|
let dragData = RdDItemSheetV1.$extractDragData(event);
|
|
if (!dragData) return false;
|
|
const allowed = Hooks.call("dropActorSheetData", this.actor, this, dragData);
|
|
if (allowed === false) return false;
|
|
|
|
// Handle different dragData types
|
|
switch (dragData.type) {
|
|
case "Item":
|
|
return this._onDropItem(event, dragData);
|
|
case "Actor":
|
|
return this._onDropActor(event, dragData);
|
|
}
|
|
return super._onDrop(event);
|
|
}
|
|
|
|
static $extractDragData(event) {
|
|
try {
|
|
const eventData = event?.dataTransfer?.getData('text/plain');
|
|
if (eventData) {
|
|
return JSON.parse(eventData);
|
|
}
|
|
} catch (err) { }
|
|
return undefined
|
|
}
|
|
|
|
}
|