Appv2 + DataModel migration completed
This commit is contained in:
177
modules/applications/hawkmoon-roll-dialog.mjs
Normal file
177
modules/applications/hawkmoon-roll-dialog.mjs
Normal file
@@ -0,0 +1,177 @@
|
||||
import { HawkmoonUtility } from "../hawkmoon-utility.js"
|
||||
import { HAWKMOON_CONFIG } from "../hawkmoon-config.js"
|
||||
|
||||
/**
|
||||
* Dialogue de jet de dé pour Hawkmoon - Version DialogV2
|
||||
*/
|
||||
export class HawkmoonRollDialog {
|
||||
|
||||
/**
|
||||
* Create and display the roll dialog
|
||||
* @param {HawkmoonActor} actor - The actor making the roll
|
||||
* @param {Object} rollData - Data for the roll
|
||||
* @returns {Promise<HawkmoonRollDialog>}
|
||||
*/
|
||||
static async create(actor, rollData) {
|
||||
// Préparer le contexte pour le template
|
||||
const context = {
|
||||
...rollData,
|
||||
difficulte: String(rollData.difficulte || 0), // Convertir en string pour matcher les options du select
|
||||
img: actor.img,
|
||||
name: actor.name,
|
||||
config: HAWKMOON_CONFIG,
|
||||
}
|
||||
|
||||
// Si attrKey est "tochoose", préparer la liste des attributs sélectionnables
|
||||
if (rollData.attrKey === "tochoose") {
|
||||
context.selectableAttributes = actor.system.attributs
|
||||
// Ne pas changer attrKey ni attr - l'utilisateur doit choisir
|
||||
}
|
||||
|
||||
// Rendre le template en HTML
|
||||
const content = await foundry.applications.handlebars.renderTemplate(
|
||||
"systems/fvtt-hawkmoon-cyd/templates/roll-dialog-generic.hbs",
|
||||
context
|
||||
)
|
||||
|
||||
// Utiliser DialogV2.wait avec le HTML rendu
|
||||
return foundry.applications.api.DialogV2.wait({
|
||||
window: { title: "Test de Capacité", icon: "fa-solid fa-dice-d20" },
|
||||
classes: ["hawkmoon-roll-dialog"],
|
||||
position: { width: 480 },
|
||||
modal: false, // Permettre l'interaction avec le canvas pour garder la cible sélectionnée
|
||||
content,
|
||||
buttons: [
|
||||
{
|
||||
action: "rolld10",
|
||||
label: "Lancer 1d10",
|
||||
icon: "fa-solid fa-dice-d10",
|
||||
default: true,
|
||||
callback: (event, button, dialog) => {
|
||||
this._updateRollDataFromForm(rollData, button.form.elements, actor)
|
||||
rollData.mainDice = "d10"
|
||||
HawkmoonUtility.rollHawkmoon(rollData)
|
||||
}
|
||||
},
|
||||
{
|
||||
action: "rolld20",
|
||||
label: "Lancer 1d20",
|
||||
icon: "fa-solid fa-dice-d20",
|
||||
callback: (event, button, dialog) => {
|
||||
this._updateRollDataFromForm(rollData, button.form.elements, actor)
|
||||
rollData.mainDice = "d20"
|
||||
HawkmoonUtility.rollHawkmoon(rollData)
|
||||
}
|
||||
},
|
||||
],
|
||||
rejectClose: false,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Mettre à jour rollData avec les valeurs du formulaire
|
||||
* @param {Object} rollData - L'objet rollData à mettre à jour
|
||||
* @param {HTMLFormControlsCollection} formElements - Les éléments du formulaire
|
||||
* @param {HawkmoonActor} actor - L'acteur pour récupérer les attributs
|
||||
* @private
|
||||
*/
|
||||
static _updateRollDataFromForm(rollData, formElements, actor) {
|
||||
// Attributs
|
||||
if (formElements.attrKey) {
|
||||
rollData.attrKey = formElements.attrKey.value
|
||||
// Si l'attribut a changé, mettre à jour rollData.attr
|
||||
if (rollData.attrKey !== "tochoose" && rollData.attrKey !== "none" && actor) {
|
||||
rollData.attr = foundry.utils.duplicate(actor.system.attributs[rollData.attrKey])
|
||||
rollData.actionImg = "systems/fvtt-hawkmoon-cyd/assets/icons/" + actor.system.attributs[rollData.attrKey].labelnorm + ".webp"
|
||||
}
|
||||
}
|
||||
if (formElements.attrKey2) {
|
||||
rollData.attrKey2 = formElements.attrKey2.value
|
||||
}
|
||||
|
||||
// Modificateurs de base
|
||||
if (formElements.difficulte) {
|
||||
rollData.difficulte = Number(formElements.difficulte.value)
|
||||
}
|
||||
if (formElements.modificateur) {
|
||||
rollData.modificateur = Number(formElements.modificateur.value)
|
||||
}
|
||||
if (formElements.soutiens) {
|
||||
rollData.soutiens = Number(formElements.soutiens.value)
|
||||
}
|
||||
|
||||
// Compétence
|
||||
if (formElements.maitrise) {
|
||||
rollData.maitriseId = formElements.maitrise.value
|
||||
}
|
||||
if (formElements.talents) {
|
||||
// Récupérer toutes les options sélectionnées (select multiple)
|
||||
const selectedOptions = Array.from(formElements.talents.selectedOptions)
|
||||
rollData.selectedTalents = selectedOptions.map(opt => opt.value)
|
||||
}
|
||||
|
||||
// Modificateurs de tir
|
||||
if (formElements.tailleCible) {
|
||||
rollData.tailleCible = formElements.tailleCible.value
|
||||
}
|
||||
if (formElements.tireurDeplacement) {
|
||||
rollData.tireurDeplacement = formElements.tireurDeplacement.value
|
||||
}
|
||||
if (formElements.cibleCouvert) {
|
||||
rollData.cibleCouvert = formElements.cibleCouvert.value
|
||||
}
|
||||
if (formElements.distanceTir) {
|
||||
rollData.distanceTir = formElements.distanceTir.value
|
||||
}
|
||||
if (formElements.cibleDeplace) {
|
||||
rollData.cibleDeplace = formElements.cibleDeplace.checked
|
||||
}
|
||||
if (formElements.cibleCaC) {
|
||||
rollData.cibleCaC = formElements.cibleCaC.checked
|
||||
}
|
||||
|
||||
// Modificateurs de combat (checkboxes)
|
||||
if (formElements.defenseurAuSol) {
|
||||
rollData.defenseurAuSol = formElements.defenseurAuSol.checked
|
||||
}
|
||||
if (formElements.ambidextre1) {
|
||||
rollData.ambidextre1 = formElements.ambidextre1.checked
|
||||
}
|
||||
if (formElements.ambidextre2) {
|
||||
rollData.ambidextre2 = formElements.ambidextre2.checked
|
||||
}
|
||||
if (formElements.attaqueMonte) {
|
||||
rollData.attaqueMonte = formElements.attaqueMonte.checked
|
||||
}
|
||||
if (formElements.defenseurAveugle) {
|
||||
rollData.defenseurAveugle = formElements.defenseurAveugle.checked
|
||||
}
|
||||
if (formElements.defenseurDeDos) {
|
||||
rollData.defenseurDeDos = formElements.defenseurDeDos.checked
|
||||
}
|
||||
if (formElements.defenseurRestreint) {
|
||||
rollData.defenseurRestreint = formElements.defenseurRestreint.checked
|
||||
}
|
||||
if (formElements.defenseurImmobilise) {
|
||||
rollData.defenseurImmobilise = formElements.defenseurImmobilise.checked
|
||||
}
|
||||
if (formElements.attaqueCharge) {
|
||||
rollData.attaqueCharge = formElements.attaqueCharge.checked
|
||||
}
|
||||
if (formElements.chargeCavalerie) {
|
||||
rollData.chargeCavalerie = formElements.chargeCavalerie.checked
|
||||
}
|
||||
if (formElements.attaquantsMultiple) {
|
||||
rollData.attaquantsMultiple = formElements.attaquantsMultiple.checked
|
||||
}
|
||||
if (formElements.feinte) {
|
||||
rollData.feinte = formElements.feinte.checked
|
||||
}
|
||||
if (formElements.contenir) {
|
||||
rollData.contenir = formElements.contenir.checked
|
||||
}
|
||||
if (formElements.attaqueDesarme) {
|
||||
rollData.attaqueDesarme = formElements.attaqueDesarme.checked
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,3 +10,8 @@ export { default as HawkmoonArtefactSheet } from "./artefact-sheet.mjs"
|
||||
export { default as HawkmoonRessourceSheet } from "./ressource-sheet.mjs"
|
||||
export { default as HawkmoonContactSheet } from "./contact-sheet.mjs"
|
||||
export { default as HawkmoonMutationSheet } from "./mutation-sheet.mjs"
|
||||
|
||||
// Actor sheets
|
||||
export { default as HawkmoonPersonnageSheet } from "./personnage-sheet.mjs"
|
||||
export { default as HawkmoonCreatureSheet } from "./creature-sheet.mjs"
|
||||
export { default as HawkmoonCelluleSheet } from "./cellule-sheet.mjs"
|
||||
|
||||
547
modules/applications/sheets/base-actor-sheet.mjs
Normal file
547
modules/applications/sheets/base-actor-sheet.mjs
Normal file
@@ -0,0 +1,547 @@
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||
|
||||
import { HawkmoonUtility } from "../../hawkmoon-utility.js"
|
||||
import { HawkmoonAutomation } from "../../hawkmoon-automation.js"
|
||||
|
||||
export default class HawkmoonActorSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ActorSheetV2) {
|
||||
/**
|
||||
* Different sheet modes.
|
||||
* @enum {number}
|
||||
*/
|
||||
static SHEET_MODES = { EDIT: 0, PLAY: 1 }
|
||||
|
||||
constructor(options = {}) {
|
||||
super(options)
|
||||
this.#dragDrop = this.#createDragDropHandlers()
|
||||
this._sheetMode = this.constructor.SHEET_MODES.PLAY // Commencer en mode visualisation
|
||||
}
|
||||
|
||||
#dragDrop
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["fvtt-hawkmoon-cyd", "sheet", "actor"],
|
||||
position: {
|
||||
width: 640,
|
||||
height: 720,
|
||||
},
|
||||
window: {
|
||||
resizable: true,
|
||||
},
|
||||
form: {
|
||||
submitOnChange: true,
|
||||
closeOnSubmit: false,
|
||||
},
|
||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: "form" }],
|
||||
actions: {
|
||||
editImage: HawkmoonActorSheet.#onEditImage,
|
||||
toggleSheet: HawkmoonActorSheet.#onToggleSheet,
|
||||
editItem: HawkmoonActorSheet.#onEditItem,
|
||||
deleteItem: HawkmoonActorSheet.#onDeleteItem,
|
||||
createItem: HawkmoonActorSheet.#onCreateItem,
|
||||
equipItem: HawkmoonActorSheet.#onEquipItem,
|
||||
modifyQuantity: HawkmoonActorSheet.#onModifyQuantity,
|
||||
modifyAdversite: HawkmoonActorSheet.#onModifyAdversite,
|
||||
rollInitiative: HawkmoonActorSheet.#onRollInitiative,
|
||||
rollAttribut: HawkmoonActorSheet.#onRollAttribut,
|
||||
rollCompetence: HawkmoonActorSheet.#onRollCompetence,
|
||||
rollArmeOffensif: HawkmoonActorSheet.#onRollArmeOffensif,
|
||||
rollArmeDegats: HawkmoonActorSheet.#onRollArmeDegats,
|
||||
rollAssommer: HawkmoonActorSheet.#onRollAssommer,
|
||||
rollCoupBas: HawkmoonActorSheet.#onRollCoupBas,
|
||||
rollImmobiliser: HawkmoonActorSheet.#onRollImmobiliser,
|
||||
rollRepousser: HawkmoonActorSheet.#onRollRepousser,
|
||||
rollDesengager: HawkmoonActorSheet.#onRollDesengager,
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the sheet currently in 'Play' mode?
|
||||
* @type {boolean}
|
||||
*/
|
||||
get isPlayMode() {
|
||||
// Initialize if not set
|
||||
if (this._sheetMode === undefined) this._sheetMode = this.constructor.SHEET_MODES.PLAY
|
||||
return this._sheetMode === this.constructor.SHEET_MODES.PLAY
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the sheet currently in 'Edit' mode?
|
||||
* @type {boolean}
|
||||
*/
|
||||
get isEditMode() {
|
||||
// Initialize if not set
|
||||
if (this._sheetMode === undefined) this._sheetMode = this.constructor.SHEET_MODES.PLAY
|
||||
return this._sheetMode === this.constructor.SHEET_MODES.EDIT
|
||||
}
|
||||
|
||||
/**
|
||||
* Tab groups state
|
||||
* @type {object}
|
||||
*/
|
||||
tabGroups = { primary: "principal" }
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const actor = this.document
|
||||
|
||||
const context = {
|
||||
actor: actor,
|
||||
system: actor.system,
|
||||
source: actor.toObject(),
|
||||
fields: actor.schema.fields,
|
||||
systemFields: actor.system.schema.fields,
|
||||
isEditable: this.isEditable,
|
||||
isEditMode: this.isEditMode,
|
||||
isPlayMode: this.isPlayMode,
|
||||
isGM: game.user.isGM,
|
||||
config: CONFIG.HAWKMOON,
|
||||
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.description || "", { async: true }),
|
||||
enrichedHabitat: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.habitat || "", { async: true }),
|
||||
}
|
||||
|
||||
return context
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_onRender(context, options) {
|
||||
super._onRender(context, options)
|
||||
|
||||
// Activate drag & drop handlers
|
||||
this.#dragDrop.forEach(d => d.bind(this.element))
|
||||
|
||||
// Manual tab navigation
|
||||
const html = this.element
|
||||
const tabLinks = html.querySelectorAll('a.item[data-tab]')
|
||||
const tabContents = html.querySelectorAll('.tab[data-tab]')
|
||||
|
||||
// Hide all tabs initially
|
||||
tabContents.forEach(tab => {
|
||||
tab.classList.remove('active')
|
||||
tab.style.display = 'none'
|
||||
})
|
||||
|
||||
// Show active tab
|
||||
const activeTab = this.tabGroups.primary
|
||||
const activeTabContent = html.querySelector(`.tab[data-tab="${activeTab}"]`)
|
||||
if (activeTabContent) {
|
||||
activeTabContent.classList.add('active')
|
||||
activeTabContent.style.display = 'block'
|
||||
}
|
||||
|
||||
// Activate the corresponding nav link
|
||||
tabLinks.forEach(link => {
|
||||
if (link.dataset.tab === activeTab) {
|
||||
link.classList.add('active')
|
||||
} else {
|
||||
link.classList.remove('active')
|
||||
}
|
||||
})
|
||||
|
||||
// Tab click handler
|
||||
tabLinks.forEach(link => {
|
||||
link.addEventListener('click', (event) => {
|
||||
event.preventDefault()
|
||||
const tab = link.dataset.tab
|
||||
|
||||
// Update state
|
||||
this.tabGroups.primary = tab
|
||||
|
||||
// Hide all tabs
|
||||
tabContents.forEach(t => {
|
||||
t.classList.remove('active')
|
||||
t.style.display = 'none'
|
||||
})
|
||||
|
||||
// Show selected tab
|
||||
const selectedTab = html.querySelector(`.tab[data-tab="${tab}"]`)
|
||||
if (selectedTab) {
|
||||
selectedTab.classList.add('active')
|
||||
selectedTab.style.display = 'block'
|
||||
}
|
||||
|
||||
// Update nav links
|
||||
tabLinks.forEach(l => {
|
||||
if (l.dataset.tab === tab) {
|
||||
l.classList.add('active')
|
||||
} else {
|
||||
l.classList.remove('active')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// Inline item editing
|
||||
html.querySelectorAll('.edit-item-data').forEach(input => {
|
||||
input.addEventListener('change', (event) => {
|
||||
const li = event.target.closest('.item')
|
||||
const itemId = li.dataset.itemId
|
||||
const itemType = li.dataset.itemType
|
||||
const itemField = event.target.dataset.itemField
|
||||
const dataType = event.target.dataset.dtype
|
||||
const value = event.target.value
|
||||
this.actor.editItemField(itemId, itemType, itemField, dataType, value)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// #region Drag & Drop
|
||||
|
||||
/**
|
||||
* Create drag-and-drop workflow handlers for this Application
|
||||
* @returns {DragDrop[]} An array of DragDrop handlers
|
||||
* @private
|
||||
*/
|
||||
#createDragDropHandlers() {
|
||||
return this.options.dragDrop.map((d) => {
|
||||
d.permissions = {
|
||||
dragstart: this._canDragStart.bind(this),
|
||||
drop: this._canDragDrop.bind(this),
|
||||
}
|
||||
d.callbacks = {
|
||||
dragstart: this._onDragStart.bind(this),
|
||||
drop: this._onDrop.bind(this),
|
||||
}
|
||||
return new foundry.applications.ux.DragDrop(d)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Define whether a user is able to begin a dragstart workflow for a given drag selector
|
||||
* @param {string} selector The candidate HTML selector for dragging
|
||||
* @returns {boolean} Can the current user drag this selector?
|
||||
* @protected
|
||||
*/
|
||||
_canDragStart(selector) {
|
||||
return this.isEditable
|
||||
}
|
||||
|
||||
/**
|
||||
* Define whether a user is able to conclude a drag-and-drop workflow for a given drop selector
|
||||
* @param {string} selector The candidate HTML selector for the drop target
|
||||
* @returns {boolean} Can the current user drop on this selector?
|
||||
* @protected
|
||||
*/
|
||||
_canDragDrop(selector) {
|
||||
return this.isEditable
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback actions which occur at the beginning of a drag start workflow.
|
||||
* @param {DragEvent} event The originating DragEvent
|
||||
* @protected
|
||||
*/
|
||||
_onDragStart(event) {
|
||||
const li = event.currentTarget.closest(".item")
|
||||
if (!li?.dataset.itemId) return
|
||||
const item = this.actor.items.get(li.dataset.itemId)
|
||||
if (!item) return
|
||||
|
||||
const dragData = item.toDragData()
|
||||
event.dataTransfer.setData("text/plain", JSON.stringify(dragData))
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback actions which occur when a dragged element is dropped on a target.
|
||||
* @param {DragEvent} event The originating DragEvent
|
||||
* @protected
|
||||
*/
|
||||
async _onDrop(event) {
|
||||
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event)
|
||||
const actor = this.actor
|
||||
|
||||
// Handle different data types
|
||||
switch (data.type) {
|
||||
case "Item":
|
||||
return this._onDropItem(event, data)
|
||||
case "Actor":
|
||||
return this._onDropActor(event, data)
|
||||
case "ActiveEffect":
|
||||
return this._onDropActiveEffect(event, data)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle dropping an Item on the actor sheet
|
||||
* @param {DragEvent} event
|
||||
* @param {object} data
|
||||
* @private
|
||||
*/
|
||||
async _onDropItem(event, data) {
|
||||
if (!this.actor.isOwner) return false
|
||||
|
||||
let item = await fromUuid(data.uuid)
|
||||
if (item.pack) {
|
||||
item = await HawkmoonUtility.searchItem(item)
|
||||
}
|
||||
|
||||
const autoresult = HawkmoonAutomation.processAutomations("on-drop", item, this.actor)
|
||||
if (autoresult.isValid) {
|
||||
// In AppV2, we need to get the item data differently
|
||||
const itemData = item.toObject ? item.toObject() : item
|
||||
return this.actor.createEmbeddedDocuments("Item", [itemData])
|
||||
} else {
|
||||
ui.notifications.warn(autoresult.warningMessage)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle dropping an Actor on the sheet
|
||||
* @param {DragEvent} event
|
||||
* @param {object} data
|
||||
* @private
|
||||
*/
|
||||
async _onDropActor(event, data) {
|
||||
// To be implemented by subclasses if needed
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle dropping an ActiveEffect on the sheet
|
||||
* @param {DragEvent} event
|
||||
* @param {object} data
|
||||
* @private
|
||||
*/
|
||||
async _onDropActiveEffect(event, data) {
|
||||
// To be implemented by subclasses if needed
|
||||
return false
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region Action Handlers
|
||||
|
||||
/**
|
||||
* Toggle between edit and play mode
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static #onToggleSheet(event, target) {
|
||||
console.log("Toggle sheet clicked", this)
|
||||
const wasEditMode = this.isEditMode
|
||||
console.log("Current mode:", this._sheetMode, "isEditMode:", wasEditMode, "isPlayMode:", this.isPlayMode)
|
||||
this._sheetMode = wasEditMode ? this.constructor.SHEET_MODES.PLAY : this.constructor.SHEET_MODES.EDIT
|
||||
console.log("New mode set to:", this._sheetMode, "(", wasEditMode ? "PLAY" : "EDIT", ")")
|
||||
console.log("After change - isEditMode:", this.isEditMode, "isPlayMode:", this.isPlayMode)
|
||||
this.render({ force: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit the actor image
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onEditImage(event, target) {
|
||||
const fp = new FilePicker({
|
||||
type: "image",
|
||||
current: this.actor.img,
|
||||
callback: (path) => {
|
||||
this.actor.update({ img: path })
|
||||
},
|
||||
})
|
||||
return fp.browse()
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit an item
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onEditItem(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const itemId = li?.dataset.itemId
|
||||
if (!itemId) return
|
||||
const item = this.actor.items.get(itemId)
|
||||
if (item) item.sheet.render(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an item
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onDeleteItem(event, target) {
|
||||
const li = target.closest(".item")
|
||||
await HawkmoonUtility.confirmDelete(this, li)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new item
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onCreateItem(event, target) {
|
||||
const itemType = target.dataset.type
|
||||
await this.actor.createEmbeddedDocuments("Item", [{ name: `Nouveau ${itemType}`, type: itemType }], { renderSheet: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* Equip/unequip an item
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onEquipItem(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const itemId = li?.dataset.itemId
|
||||
if (itemId) {
|
||||
await this.actor.equipItem(itemId)
|
||||
this.render()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify item quantity
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onModifyQuantity(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const itemId = li?.dataset.itemId
|
||||
const value = Number(target.dataset.quantiteValue)
|
||||
if (itemId) {
|
||||
await this.actor.incDecQuantity(itemId, value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify adversité
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onModifyAdversite(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const adv = li?.dataset.adversite
|
||||
const value = Number(target.dataset.adversiteValue)
|
||||
if (adv) {
|
||||
await this.actor.incDecAdversite(adv, value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll initiative
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onRollInitiative(event, target) {
|
||||
await this.actor.rollAttribut("adr", true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll attribut
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onRollAttribut(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const attrKey = li?.dataset.attrKey
|
||||
if (attrKey) {
|
||||
await this.actor.rollAttribut(attrKey, false)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll competence
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onRollCompetence(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const attrKey = target.dataset.attrKey
|
||||
const compId = li?.dataset.itemId
|
||||
if (attrKey && compId) {
|
||||
await this.actor.rollCompetence(attrKey, compId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll arme offensif
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onRollArmeOffensif(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const armeId = li?.dataset.itemId
|
||||
if (armeId) {
|
||||
await this.actor.rollArmeOffensif(armeId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll arme degats
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onRollArmeDegats(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const armeId = li?.dataset.itemId
|
||||
if (armeId) {
|
||||
await this.actor.rollArmeDegats(armeId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll assommer
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onRollAssommer(event, target) {
|
||||
await this.actor.rollAssommer()
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll coup bas
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onRollCoupBas(event, target) {
|
||||
await this.actor.rollCoupBas()
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll immobiliser
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onRollImmobiliser(event, target) {
|
||||
await this.actor.rollImmobiliser()
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll repousser
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onRollRepousser(event, target) {
|
||||
await this.actor.rollRepousser()
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll désengager
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onRollDesengager(event, target) {
|
||||
await this.actor.rollDesengager()
|
||||
}
|
||||
|
||||
// #endregion
|
||||
}
|
||||
@@ -1,12 +1,6 @@
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||
|
||||
export default class HawkmoonItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) {
|
||||
/**
|
||||
* Different sheet modes.
|
||||
* @enum {number}
|
||||
*/
|
||||
static SHEET_MODES = { EDIT: 0, PLAY: 1 }
|
||||
|
||||
constructor(options = {}) {
|
||||
super(options)
|
||||
this.#dragDrop = this.#createDragDropHandlers()
|
||||
@@ -19,7 +13,7 @@ export default class HawkmoonItemSheet extends HandlebarsApplicationMixin(foundr
|
||||
classes: ["fvtt-hawkmoon-cyd", "item"],
|
||||
position: {
|
||||
width: 620,
|
||||
height: "auto",
|
||||
height: 600,
|
||||
},
|
||||
form: {
|
||||
submitOnChange: true,
|
||||
@@ -36,7 +30,6 @@ export default class HawkmoonItemSheet extends HandlebarsApplicationMixin(foundr
|
||||
],
|
||||
dragDrop: [{ dragSelector: "[data-drag]", dropSelector: null }],
|
||||
actions: {
|
||||
toggleSheet: HawkmoonItemSheet.#onToggleSheet,
|
||||
editImage: HawkmoonItemSheet.#onEditImage,
|
||||
postItem: HawkmoonItemSheet.#onPostItem,
|
||||
addPredilection: HawkmoonItemSheet.#onAddPredilection,
|
||||
@@ -46,12 +39,6 @@ export default class HawkmoonItemSheet extends HandlebarsApplicationMixin(foundr
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* The current sheet mode.
|
||||
* @type {number}
|
||||
*/
|
||||
_sheetMode = this.constructor.SHEET_MODES.PLAY
|
||||
|
||||
/**
|
||||
* Tab groups state
|
||||
* @type {object}
|
||||
@@ -62,18 +49,6 @@ export default class HawkmoonItemSheet extends HandlebarsApplicationMixin(foundr
|
||||
* Is the sheet currently in 'Play' mode?
|
||||
* @type {boolean}
|
||||
*/
|
||||
get isPlayMode() {
|
||||
return this._sheetMode === this.constructor.SHEET_MODES.PLAY
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the sheet currently in 'Edit' mode?
|
||||
* @type {boolean}
|
||||
*/
|
||||
get isEditMode() {
|
||||
return this._sheetMode === this.constructor.SHEET_MODES.EDIT
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = {
|
||||
@@ -83,8 +58,7 @@ export default class HawkmoonItemSheet extends HandlebarsApplicationMixin(foundr
|
||||
system: this.document.system,
|
||||
source: this.document.toObject(),
|
||||
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true }),
|
||||
isEditMode: this.isEditMode,
|
||||
isPlayMode: this.isPlayMode,
|
||||
isEditMode: true,
|
||||
isEditable: this.isEditable,
|
||||
isGM: game.user.isGM,
|
||||
config: CONFIG.HAWKMOON,
|
||||
@@ -198,17 +172,6 @@ export default class HawkmoonItemSheet extends HandlebarsApplicationMixin(foundr
|
||||
// #endregion
|
||||
|
||||
// #region Action Handlers
|
||||
/**
|
||||
* Toggle between Edit and Play mode
|
||||
* @param {Event} event The triggering event
|
||||
* @param {HTMLElement} target The target element
|
||||
* @private
|
||||
*/
|
||||
static #onToggleSheet(event, target) {
|
||||
this._sheetMode = this.isEditMode ? this.constructor.SHEET_MODES.PLAY : this.constructor.SHEET_MODES.EDIT
|
||||
this.render()
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit the item image
|
||||
* @param {Event} event The triggering event
|
||||
|
||||
142
modules/applications/sheets/cellule-sheet.mjs
Normal file
142
modules/applications/sheets/cellule-sheet.mjs
Normal file
@@ -0,0 +1,142 @@
|
||||
import HawkmoonActorSheet from "./base-actor-sheet.mjs"
|
||||
|
||||
const __ALLOWED_ITEM_CELLULE = { talent: 1, ressource: 1, contact: 1, equipement: 1, protection: 1, artefact: 1, arme: 1, monnaie: 1 }
|
||||
|
||||
export default class HawkmoonCelluleSheet extends HawkmoonActorSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes],
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "SHEETS.Actor.cellule",
|
||||
},
|
||||
actions: {
|
||||
...super.DEFAULT_OPTIONS.actions,
|
||||
editActor: HawkmoonCelluleSheet.#onEditActor,
|
||||
deleteActor: HawkmoonCelluleSheet.#onDeleteActor,
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-hawkmoon-cyd/templates/cellule-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = { primary: "talents" }
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
const actor = this.document
|
||||
|
||||
// Add cellule-specific data
|
||||
context.talents = foundry.utils.duplicate(actor.getTalents() || {})
|
||||
context.ressources = foundry.utils.duplicate(actor.getRessources ? actor.getRessources() : [])
|
||||
context.contacts = foundry.utils.duplicate(actor.getContacts ? actor.getContacts() : [])
|
||||
context.members = this.#getMembers()
|
||||
context.equipements = foundry.utils.duplicate(actor.getEquipments ? actor.getEquipments() : [])
|
||||
context.artefacts = foundry.utils.duplicate(actor.getArtefacts ? actor.getArtefacts() : [])
|
||||
context.armes = foundry.utils.duplicate(actor.getWeapons ? actor.getWeapons() : [])
|
||||
context.monnaies = foundry.utils.duplicate(actor.getMonnaies ? actor.getMonnaies() : [])
|
||||
context.protections = foundry.utils.duplicate(actor.getArmors ? actor.getArmors() : [])
|
||||
context.richesse = actor.computeRichesse ? actor.computeRichesse() : 0
|
||||
context.valeurEquipement = actor.computeValeurEquipement ? actor.computeValeurEquipement() : 0
|
||||
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.description || "", { async: true })
|
||||
|
||||
return context
|
||||
}
|
||||
|
||||
/**
|
||||
* Get members of the cellule with full actor data
|
||||
* @returns {Array}
|
||||
* @private
|
||||
*/
|
||||
#getMembers() {
|
||||
let membersFull = []
|
||||
for (let memberId of this.actor.system.members) {
|
||||
let actor = game.actors.get(memberId)
|
||||
if (actor) {
|
||||
membersFull.push({ name: actor.name, id: actor.id, img: actor.img })
|
||||
}
|
||||
}
|
||||
return membersFull
|
||||
}
|
||||
|
||||
/**
|
||||
* Override _onDropItem to filter allowed item types for cellule
|
||||
* @override
|
||||
*/
|
||||
async _onDropItem(event, data) {
|
||||
const item = await fromUuid(data.uuid)
|
||||
|
||||
// Check if item type is allowed for cellule
|
||||
if (!__ALLOWED_ITEM_CELLULE[item.type]) {
|
||||
ui.notifications.warn(`Le type d'item ${item.type} n'est pas autorisé pour une cellule`)
|
||||
return false
|
||||
}
|
||||
|
||||
return super._onDropItem(event, data)
|
||||
}
|
||||
|
||||
/**
|
||||
* Override _onDropActor to handle adding members
|
||||
* @override
|
||||
*/
|
||||
async _onDropActor(event, data) {
|
||||
const droppedActor = await fromUuid(data.uuid)
|
||||
|
||||
if (droppedActor.type !== "personnage") {
|
||||
ui.notifications.warn("Seuls les personnages peuvent être ajoutés à une cellule")
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if already a member
|
||||
const isMember = this.actor.system.members.includes(droppedActor.id)
|
||||
if (isMember) {
|
||||
ui.notifications.warn("Ce personnage est déjà membre de cette cellule")
|
||||
return false
|
||||
}
|
||||
|
||||
// Add member ID
|
||||
const members = [...this.actor.system.members, droppedActor.id]
|
||||
await this.actor.update({ "system.members": members })
|
||||
return true
|
||||
}
|
||||
|
||||
// #region Cellule-specific Actions
|
||||
|
||||
/**
|
||||
* Edit an actor (member)
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onEditActor(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const actorId = li?.dataset.actorId
|
||||
if (!actorId) return
|
||||
const actor = game.actors.get(actorId)
|
||||
if (actor) actor.sheet.render(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an actor (remove member)
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onDeleteActor(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const actorId = li?.dataset.actorId
|
||||
if (actorId) {
|
||||
const members = this.actor.system.members.filter(id => id !== actorId)
|
||||
await this.actor.update({ "system.members": members })
|
||||
}
|
||||
}
|
||||
|
||||
// #endregion
|
||||
}
|
||||
60
modules/applications/sheets/creature-sheet.mjs
Normal file
60
modules/applications/sheets/creature-sheet.mjs
Normal file
@@ -0,0 +1,60 @@
|
||||
import HawkmoonActorSheet from "./base-actor-sheet.mjs"
|
||||
import { HawkmoonUtility } from "../../hawkmoon-utility.js"
|
||||
|
||||
export default class HawkmoonCreatureSheet extends HawkmoonActorSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes],
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "SHEETS.Actor.creature",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-hawkmoon-cyd/templates/creature-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = { primary: "principal" }
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
const actor = this.document
|
||||
|
||||
// Add creature-specific data
|
||||
context.skills = actor.getSkills ? actor.getSkills() : []
|
||||
context.armes = foundry.utils.duplicate(actor.getWeapons ? actor.getWeapons() : [])
|
||||
context.protections = foundry.utils.duplicate(actor.getArmors ? actor.getArmors() : [])
|
||||
context.combat = actor.getCombatValues ? actor.getCombatValues() : {}
|
||||
context.equipements = foundry.utils.duplicate(actor.getEquipments ? actor.getEquipments() : [])
|
||||
context.talents = foundry.utils.duplicate(actor.getTalents ? actor.getTalents() : [])
|
||||
context.talentsCell = this.#getCelluleTalents()
|
||||
context.nbCombativite = actor.system.sante?.nbcombativite || 0
|
||||
context.combativiteList = HawkmoonUtility.getCombativiteList(actor.system.sante?.nbcombativite || 0)
|
||||
context.initiative = actor.getFlag("world", "last-initiative") || -1
|
||||
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.description || "", { async: true })
|
||||
context.enrichedHabitat = await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.habitat || "", { async: true })
|
||||
|
||||
return context
|
||||
}
|
||||
|
||||
/**
|
||||
* Get talents from attached cellule
|
||||
* @private
|
||||
*/
|
||||
#getCelluleTalents() {
|
||||
const celluleId = this.actor.system?.details?.celluleid
|
||||
if (!celluleId) return []
|
||||
|
||||
const cellule = game.actors.get(celluleId)
|
||||
if (!cellule) return []
|
||||
|
||||
return foundry.utils.duplicate(cellule.getTalents?.() || [])
|
||||
}
|
||||
}
|
||||
104
modules/applications/sheets/personnage-sheet.mjs
Normal file
104
modules/applications/sheets/personnage-sheet.mjs
Normal file
@@ -0,0 +1,104 @@
|
||||
import HawkmoonActorSheet from "./base-actor-sheet.mjs"
|
||||
import { HawkmoonUtility } from "../../hawkmoon-utility.js"
|
||||
|
||||
export default class HawkmoonPersonnageSheet extends HawkmoonActorSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes],
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "SHEETS.Actor.personnage",
|
||||
},
|
||||
actions: {
|
||||
...super.DEFAULT_OPTIONS.actions,
|
||||
openCellule: HawkmoonPersonnageSheet.#onOpenCellule,
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-hawkmoon-cyd/templates/actor-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = { primary: "principal" }
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
const actor = this.document
|
||||
|
||||
// Add personnage-specific data
|
||||
context.skills = actor.getSkills()
|
||||
context.armes = foundry.utils.duplicate(actor.getWeapons())
|
||||
context.monnaies = foundry.utils.duplicate(actor.getMonnaies())
|
||||
context.protections = foundry.utils.duplicate(actor.getArmors())
|
||||
context.historiques = foundry.utils.duplicate(actor.getHistoriques() || [])
|
||||
context.talents = foundry.utils.duplicate(actor.getTalents() || [])
|
||||
context.mutations = foundry.utils.duplicate(actor.getMutations() || [])
|
||||
context.talentsCell = this.#getCelluleTalents()
|
||||
context.celluleId = this.#getCelluleId()
|
||||
context.profils = foundry.utils.duplicate(actor.getProfils() || [])
|
||||
context.combat = actor.getCombatValues()
|
||||
context.equipements = foundry.utils.duplicate(actor.getEquipments())
|
||||
context.artefacts = foundry.utils.duplicate(actor.getArtefacts())
|
||||
context.richesse = actor.computeRichesse()
|
||||
context.coupDevastateur = actor.items.find(it => it.type == "talent" && it.name.toLowerCase() == "coup devastateur" && !it.system.used)
|
||||
context.valeurEquipement = actor.computeValeurEquipement()
|
||||
context.nbCombativite = actor.system.sante.nbcombativite
|
||||
context.combativiteList = HawkmoonUtility.getCombativiteList(actor.system.sante.nbcombativite)
|
||||
context.initiative = actor.getFlag("world", "last-initiative") || -1
|
||||
|
||||
return context
|
||||
}
|
||||
|
||||
/**
|
||||
* Get talents from cellules this actor is a member of
|
||||
* @returns {Array}
|
||||
* @private
|
||||
*/
|
||||
#getCelluleTalents() {
|
||||
let talents = []
|
||||
for (let cellule of game.actors) {
|
||||
if (cellule.type == "cellule") {
|
||||
let found = cellule.system.members.includes(this.actor.id)
|
||||
if (found) {
|
||||
talents = talents.concat(cellule.getTalents())
|
||||
}
|
||||
}
|
||||
}
|
||||
return talents
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ID of the cellule this actor is a member of
|
||||
* @returns {string|null}
|
||||
* @private
|
||||
*/
|
||||
#getCelluleId() {
|
||||
for (let cellule of game.actors) {
|
||||
if (cellule.type == "cellule") {
|
||||
if (cellule.system.members.includes(this.actor.id)) {
|
||||
return cellule.id
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Open cellule sheet
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onOpenCellule(event, target) {
|
||||
const celluleId = target.dataset.celluleId
|
||||
if (!celluleId) return
|
||||
const cellule = game.actors.get(celluleId)
|
||||
if (cellule) cellule.sheet.render(true)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user