Initial import with skill sheet working
This commit is contained in:
11
module/applications/_module.mjs
Normal file
11
module/applications/_module.mjs
Normal file
@ -0,0 +1,11 @@
|
||||
export { default as CthulhuEternalProtagonistSheet } from "./sheets/protagonist-sheet.mjs";
|
||||
export { default as CthulhuEternalWeaponSheet } from "./sheets/weapon-sheet.mjs"
|
||||
export { default as CthulhuEternalSkillSheet } from "./sheets/skill-sheet.mjs"
|
||||
export { default as CthulhuEternalBondSheet } from "./sheets/bond-sheet.mjs"
|
||||
export { default as CthulhuEternalArcaneSheet } from "./sheets/arcane-sheet.mjs"
|
||||
export { default as CthulhuEternalInjurySheet } from "./sheets/injury-sheet.mjs"
|
||||
export { default as CthulhuEternalArmorSheet } from "./sheets/armor-sheet.mjs"
|
||||
export { default as CthulhuEternalMentalDisorderSheet } from "./sheets/mentaldisorder-sheet.mjs"
|
||||
export { default as CthulhuEternalGearSheet } from "./sheets/gear-sheet.mjs"
|
||||
export { default as CthulhuEternalMotivationSheet } from "./sheets/motivation-sheet.mjs"
|
||||
export { default as CthulhuEternalManager } from "./manager.mjs"
|
142
module/applications/manager.mjs
Normal file
142
module/applications/manager.mjs
Normal file
@ -0,0 +1,142 @@
|
||||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api
|
||||
import { SYSTEM } from "../config/system.mjs"
|
||||
|
||||
/**
|
||||
* An application for configuring the permissions which are available to each User role.
|
||||
* @extends ApplicationV2
|
||||
* @mixes HandlebarsApplication
|
||||
* @alias PermissionConfig
|
||||
*/
|
||||
export default class CthulhuEternalManager extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
static DEFAULT_OPTIONS = {
|
||||
id: "cthulhueternal-application-manager",
|
||||
tag: "form",
|
||||
window: {
|
||||
contentClasses: ["cthulhueternal-manager"],
|
||||
title: "CTHULHUETERNAL.Manager.title",
|
||||
resizable: true,
|
||||
},
|
||||
position: {
|
||||
width: "auto",
|
||||
height: "auto",
|
||||
top: 80,
|
||||
left: 400,
|
||||
},
|
||||
form: {
|
||||
closeOnSubmit: true,
|
||||
},
|
||||
actions: {
|
||||
resourceAll: CthulhuEternalManager.#onResourceAll,
|
||||
resourceOne: CthulhuEternalManager.#onResourceOne,
|
||||
saveAll: CthulhuEternalManager.#onSaveAll,
|
||||
saveOne: CthulhuEternalManager.#onSaveOne,
|
||||
openSheet: CthulhuEternalManager.#onOpenSheet,
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-cthulhu-eternal/templates/manager.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Rendering */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
async _prepareContext(_options = {}) {
|
||||
return {
|
||||
players: game.users.filter((u) => u.hasPlayerOwner && u.active),
|
||||
}
|
||||
}
|
||||
|
||||
static async #onResourceAll(event, target) {
|
||||
const value = event.target.dataset.resource
|
||||
CthulhuEternalManager.askRollForAll("resource", value)
|
||||
}
|
||||
|
||||
static async #onSaveAll(event, target) {
|
||||
const value = event.target.dataset.save
|
||||
CthulhuEternalManager.askRollForAll("save", value)
|
||||
}
|
||||
|
||||
static #onResourceOne(event, target) {
|
||||
const value = event.target.dataset.resource
|
||||
const recipient = event.target.parentElement.dataset.userId
|
||||
const name = event.target.parentElement.dataset.characterName
|
||||
CthulhuEternalManager.askRollForOne("resource", value, recipient, name)
|
||||
}
|
||||
|
||||
static async #onSaveOne(event, target) {
|
||||
const value = event.target.dataset.save
|
||||
const recipient = event.target.parentElement.dataset.userId
|
||||
const name = event.target.parentElement.dataset.characterName
|
||||
CthulhuEternalManager.askRollForOne("save", value, recipient, name)
|
||||
}
|
||||
|
||||
static #onOpenSheet(event, target) {
|
||||
const characterId = event.target.dataset.characterId
|
||||
game.actors.get(characterId).sheet.render(true)
|
||||
}
|
||||
|
||||
static async askRollForAll(type, value, title = null, avantage = null) {
|
||||
let label = game.i18n.localize(`CTHULHUETERNAL.Manager.${value}`)
|
||||
let text = game.i18n.format("CTHULHUETERNAL.Chat.askRollForAll", { value: label })
|
||||
|
||||
if (avantage) {
|
||||
switch (avantage) {
|
||||
case "++":
|
||||
text += ` ${game.i18n.localize("CTHULHUETERNAL.Roll.doubleAvantage")}`
|
||||
break
|
||||
case "+":
|
||||
text += ` ${game.i18n.localize("CTHULHUETERNAL.Roll.avantage")}`
|
||||
break
|
||||
case "-":
|
||||
text += ` ${game.i18n.localize("CTHULHUETERNAL.Roll.desavantage")}`
|
||||
break
|
||||
case "--":
|
||||
text += ` ${game.i18n.localize("CTHULHUETERNAL.Roll.doubleDesavantage")}`
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
ChatMessage.create({
|
||||
user: game.user.id,
|
||||
content: await renderTemplate(`systems/fvtt-cthulhu-eternal/templates/chat-ask-roll.hbs`, {
|
||||
title: title !== null ? title : "",
|
||||
text: text,
|
||||
rollType: type,
|
||||
value: value,
|
||||
avantage: avantage,
|
||||
}),
|
||||
flags: { tenebris: { typeMessage: "askRoll" } },
|
||||
})
|
||||
}
|
||||
|
||||
static async askRollForOne(type, value, recipient, name) {
|
||||
let label = game.i18n.localize(`CTHULHUETERNAL.Manager.${value}`)
|
||||
const text = game.i18n.format("CTHULHUETERNAL.Chat.askRollForOne", { value: label, name: name })
|
||||
|
||||
game.socket.emit(`system.${SYSTEM.id}`, {
|
||||
action: "askRoll",
|
||||
data: {
|
||||
userId: recipient,
|
||||
},
|
||||
})
|
||||
|
||||
ChatMessage.create({
|
||||
user: game.user.id,
|
||||
content: await renderTemplate(`systems/fvtt-cthulhu-eternal/templates/chat-ask-roll.hbs`, {
|
||||
text: text,
|
||||
rollType: type,
|
||||
value: value,
|
||||
}),
|
||||
whisper: [recipient],
|
||||
flags: { tenebris: { typeMessage: "askRoll" } },
|
||||
})
|
||||
}
|
||||
}
|
28
module/applications/sheets/arcane-sheet.mjs
Normal file
28
module/applications/sheets/arcane-sheet.mjs
Normal file
@ -0,0 +1,28 @@
|
||||
import CthulhuEternalItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class CthulhuEternalArcaneSheet extends CthulhuEternalItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["arcane"],
|
||||
position: {
|
||||
width: 600,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["arcane-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-cthulhu-eternal/templates/arcane.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
|
||||
return context
|
||||
}
|
||||
}
|
27
module/applications/sheets/armor-sheet.mjs
Normal file
27
module/applications/sheets/armor-sheet.mjs
Normal file
@ -0,0 +1,27 @@
|
||||
import CthulhuEternalItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class CthulhuEternalArmorSheet extends CthulhuEternalItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["armor"],
|
||||
position: {
|
||||
width: 400,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["armor-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-cthulhu-eternal/templates/armor.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
return context
|
||||
}
|
||||
}
|
292
module/applications/sheets/base-actor-sheet.mjs
Normal file
292
module/applications/sheets/base-actor-sheet.mjs
Normal file
@ -0,0 +1,292 @@
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||
|
||||
export default class CthulhuEternalActorSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ActorSheetV2) {
|
||||
/**
|
||||
* Different sheet modes.r
|
||||
* @enum {number}
|
||||
*/
|
||||
static SHEET_MODES = { EDIT: 0, PLAY: 1 }
|
||||
|
||||
constructor(options = {}) {
|
||||
super(options)
|
||||
this.#dragDrop = this.#createDragDropHandlers()
|
||||
}
|
||||
|
||||
#dragDrop
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["fvtt-cthulhu-eternal", "actor"],
|
||||
position: {
|
||||
width: 1400,
|
||||
height: "auto",
|
||||
},
|
||||
form: {
|
||||
submitOnChange: true,
|
||||
},
|
||||
window: {
|
||||
resizable: true,
|
||||
},
|
||||
dragDrop: [{ dragSelector: '[data-drag="true"], .rollable', dropSelector: null }],
|
||||
actions: {
|
||||
editImage: CthulhuEternalActorSheet.#onEditImage,
|
||||
toggleSheet: CthulhuEternalActorSheet.#onToggleSheet,
|
||||
edit: CthulhuEternalActorSheet.#onItemEdit,
|
||||
delete: CthulhuEternalActorSheet.#onItemDelete,
|
||||
createSpell: CthulhuEternalActorSheet.#onCreateSpell,
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* The current sheet mode.
|
||||
* @type {number}
|
||||
*/
|
||||
_sheetMode = this.constructor.SHEET_MODES.PLAY
|
||||
|
||||
/**
|
||||
* 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 = {
|
||||
fields: this.document.schema.fields,
|
||||
systemFields: this.document.system.schema.fields,
|
||||
actor: this.document,
|
||||
system: this.document.system,
|
||||
source: this.document.toObject(),
|
||||
enrichedDescription: await TextEditor.enrichHTML(this.document.system.description, { async: true }),
|
||||
isEditMode: this.isEditMode,
|
||||
isPlayMode: this.isPlayMode,
|
||||
isEditable: this.isEditable,
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_onRender(context, options) {
|
||||
this.#dragDrop.forEach((d) => d.bind(this.element))
|
||||
// Add listeners to rollable elements
|
||||
const rollables = this.element.querySelectorAll(".rollable")
|
||||
rollables.forEach((d) => d.addEventListener("click", this._onRoll.bind(this)))
|
||||
}
|
||||
|
||||
// #region Drag-and-Drop Workflow
|
||||
/**
|
||||
* 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),
|
||||
dragover: this._onDragOver.bind(this),
|
||||
drop: this._onDrop.bind(this),
|
||||
}
|
||||
return new DragDrop(d)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback actions which occur when a dragged element is dropped on a target.
|
||||
* @param {DragEvent} event The originating DragEvent
|
||||
* @protected
|
||||
*/
|
||||
async _onDrop(event) {}
|
||||
|
||||
/**
|
||||
* 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 && this.document.isOwner
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback actions which occur at the beginning of a drag start workflow.
|
||||
* @param {DragEvent} event The originating DragEvent
|
||||
* @protected
|
||||
*/
|
||||
_onDragStart(event) {
|
||||
if ("link" in event.target.dataset) return
|
||||
|
||||
const el = event.currentTarget.closest('[data-drag="true"]')
|
||||
const dragType = el.dataset.dragType
|
||||
|
||||
let dragData = {}
|
||||
|
||||
let target
|
||||
switch (dragType) {
|
||||
case "save":
|
||||
target = event.currentTarget.querySelector("input")
|
||||
dragData = {
|
||||
actorId: this.document.id,
|
||||
type: "roll",
|
||||
rollType: target.dataset.rollType,
|
||||
rollTarget: target.dataset.rollTarget,
|
||||
value: target.value,
|
||||
}
|
||||
break
|
||||
case "resource":
|
||||
target = event.currentTarget.querySelector("select")
|
||||
dragData = {
|
||||
actorId: this.document.id,
|
||||
type: "roll",
|
||||
rollType: target.dataset.rollType,
|
||||
rollTarget: target.dataset.rollTarget,
|
||||
value: target.value,
|
||||
}
|
||||
break
|
||||
case "damage":
|
||||
dragData = {
|
||||
actorId: this.document.id,
|
||||
type: "rollDamage",
|
||||
rollType: el.dataset.dragType,
|
||||
rollTarget: el.dataset.itemId,
|
||||
}
|
||||
break
|
||||
case "attack":
|
||||
dragData = {
|
||||
actorId: this.document.id,
|
||||
type: "rollAttack",
|
||||
rollValue: el.dataset.rollValue,
|
||||
rollTarget: el.dataset.rollTarget,
|
||||
}
|
||||
break
|
||||
default:
|
||||
// Handle other cases or do nothing
|
||||
break
|
||||
}
|
||||
|
||||
// Extract the data you need
|
||||
|
||||
if (!dragData) return
|
||||
|
||||
// Set data transfer
|
||||
event.dataTransfer.setData("text/plain", JSON.stringify(dragData))
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback actions which occur when a dragged element is over a drop target.
|
||||
* @param {DragEvent} event The originating DragEvent
|
||||
* @protected
|
||||
*/
|
||||
_onDragOver(event) {}
|
||||
|
||||
async _onDropItem(item) {
|
||||
let itemData = item.toObject()
|
||||
await this.document.createEmbeddedDocuments("Item", [itemData], { renderSheet: false })
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region Actions
|
||||
/**
|
||||
* Handle toggling between Edit and Play mode.
|
||||
* @param {Event} event The initiating click event.
|
||||
* @param {HTMLElement} target The current target of the event listener.
|
||||
*/
|
||||
static #onToggleSheet(event, target) {
|
||||
const modes = this.constructor.SHEET_MODES
|
||||
this._sheetMode = this.isEditMode ? modes.PLAY : modes.EDIT
|
||||
this.render()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle changing a Document's image.
|
||||
*
|
||||
* @this CthulhuEternalCharacterSheet
|
||||
* @param {PointerEvent} event The originating click event
|
||||
* @param {HTMLElement} target The capturing HTML element which defined a [data-action]
|
||||
* @returns {Promise}
|
||||
* @private
|
||||
*/
|
||||
static async #onEditImage(event, target) {
|
||||
const attr = target.dataset.edit
|
||||
const current = foundry.utils.getProperty(this.document, attr)
|
||||
const { img } = this.document.constructor.getDefaultArtwork?.(this.document.toObject()) ?? {}
|
||||
const fp = new FilePicker({
|
||||
current,
|
||||
type: "image",
|
||||
redirectToRoot: img ? [img] : [],
|
||||
callback: (path) => {
|
||||
this.document.update({ [attr]: path })
|
||||
},
|
||||
top: this.position.top + 40,
|
||||
left: this.position.left + 10,
|
||||
})
|
||||
return fp.browse()
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit an existing item within the Actor
|
||||
* Start with the uuid, if it's not found, fallback to the id (as Embedded item in the actor)
|
||||
* @this CthulhuEternalCharacterSheet
|
||||
* @param {PointerEvent} event The originating click event
|
||||
* @param {HTMLElement} target the capturing HTML element which defined a [data-action]
|
||||
*/
|
||||
static async #onItemEdit(event, target) {
|
||||
const id = target.getAttribute("data-item-id")
|
||||
const uuid = target.getAttribute("data-item-uuid")
|
||||
let item
|
||||
item = await fromUuid(uuid)
|
||||
if (!item) item = this.document.items.get(id)
|
||||
if (!item) return
|
||||
item.sheet.render(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an existing talent within the Actor
|
||||
* Use the uuid to display the talent sheet
|
||||
* @param {PointerEvent} event The originating click event
|
||||
* @param {HTMLElement} target the capturing HTML element which defined a [data-action]
|
||||
*/
|
||||
static async #onItemDelete(event, target) {
|
||||
const itemUuid = target.getAttribute("data-item-uuid")
|
||||
const talent = await fromUuid(itemUuid)
|
||||
await talent.deleteDialog()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the creation of a new attack item.
|
||||
*
|
||||
* @param {Event} event The event that triggered the creation of the attack.
|
||||
* @param {Object} target The target object where the attack will be created.
|
||||
* @private
|
||||
* @static
|
||||
*/
|
||||
static #onCreateSpell(event, target) {
|
||||
const item = this.document.createEmbeddedDocuments("Item", [{ name: "Nouveau sortilège", type: "spell" }])
|
||||
}
|
||||
|
||||
// #endregion
|
||||
}
|
193
module/applications/sheets/base-item-sheet.mjs
Normal file
193
module/applications/sheets/base-item-sheet.mjs
Normal file
@ -0,0 +1,193 @@
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||
|
||||
export default class CthulhuEternalItemSheet 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()
|
||||
}
|
||||
|
||||
#dragDrop
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["fvtt-cthulhu-eternal", "item"],
|
||||
position: {
|
||||
width: 600,
|
||||
height: "auto",
|
||||
},
|
||||
form: {
|
||||
submitOnChange: true,
|
||||
},
|
||||
window: {
|
||||
resizable: true,
|
||||
},
|
||||
dragDrop: [{ dragSelector: "[data-drag]", dropSelector: null }],
|
||||
actions: {
|
||||
toggleSheet: CthulhuEternalItemSheet.#onToggleSheet,
|
||||
editImage: CthulhuEternalItemSheet.#onEditImage,
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* The current sheet mode.
|
||||
* @type {number}
|
||||
*/
|
||||
_sheetMode = this.constructor.SHEET_MODES.PLAY
|
||||
|
||||
/**
|
||||
* 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 = {
|
||||
fields: this.document.schema.fields,
|
||||
systemFields: this.document.system.schema.fields,
|
||||
item: this.document,
|
||||
system: this.document.system,
|
||||
source: this.document.toObject(),
|
||||
enrichedDescription: await TextEditor.enrichHTML(this.document.system.description, { async: true }),
|
||||
isEditMode: this.isEditMode,
|
||||
isPlayMode: this.isPlayMode,
|
||||
isEditable: this.isEditable,
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_onRender(context, options) {
|
||||
this.#dragDrop.forEach((d) => d.bind(this.element))
|
||||
}
|
||||
|
||||
// #region Drag-and-Drop Workflow
|
||||
/**
|
||||
* 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),
|
||||
dragover: this._onDragOver.bind(this),
|
||||
drop: this._onDrop.bind(this),
|
||||
}
|
||||
return new 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 && this.document.isOwner
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback actions which occur at the beginning of a drag start workflow.
|
||||
* @param {DragEvent} event The originating DragEvent
|
||||
* @protected
|
||||
*/
|
||||
_onDragStart(event) {
|
||||
const el = event.currentTarget
|
||||
if ("link" in event.target.dataset) return
|
||||
|
||||
// Extract the data you need
|
||||
let dragData = null
|
||||
|
||||
if (!dragData) return
|
||||
|
||||
// Set data transfer
|
||||
event.dataTransfer.setData("text/plain", JSON.stringify(dragData))
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback actions which occur when a dragged element is over a drop target.
|
||||
* @param {DragEvent} event The originating DragEvent
|
||||
* @protected
|
||||
*/
|
||||
_onDragOver(event) {}
|
||||
|
||||
/**
|
||||
* Callback actions which occur when a dragged element is dropped on a target.
|
||||
* @param {DragEvent} event The originating DragEvent
|
||||
* @protected
|
||||
*/
|
||||
async _onDrop(event) {}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region Actions
|
||||
/**
|
||||
* Handle toggling between Edit and Play mode.
|
||||
* @param {Event} event The initiating click event.
|
||||
* @param {HTMLElement} target The current target of the event listener.
|
||||
*/
|
||||
static #onToggleSheet(event, target) {
|
||||
const modes = this.constructor.SHEET_MODES
|
||||
this._sheetMode = this.isEditMode ? modes.PLAY : modes.EDIT
|
||||
this.render()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle changing a Document's image.
|
||||
*
|
||||
* @this CthulhuEternalCharacterSheet
|
||||
* @param {PointerEvent} event The originating click event
|
||||
* @param {HTMLElement} target The capturing HTML element which defined a [data-action]
|
||||
* @returns {Promise}
|
||||
* @private
|
||||
*/
|
||||
static async #onEditImage(event, target) {
|
||||
const attr = target.dataset.edit
|
||||
const current = foundry.utils.getProperty(this.document, attr)
|
||||
const { img } = this.document.constructor.getDefaultArtwork?.(this.document.toObject()) ?? {}
|
||||
const fp = new FilePicker({
|
||||
current,
|
||||
type: "image",
|
||||
redirectToRoot: img ? [img] : [],
|
||||
callback: (path) => {
|
||||
this.document.update({ [attr]: path })
|
||||
},
|
||||
top: this.position.top + 40,
|
||||
left: this.position.left + 10,
|
||||
})
|
||||
return fp.browse()
|
||||
}
|
||||
// #endregion
|
||||
}
|
28
module/applications/sheets/bond-sheet.mjs
Normal file
28
module/applications/sheets/bond-sheet.mjs
Normal file
@ -0,0 +1,28 @@
|
||||
import CthulhuEternalItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class CthulhuEternalGiftSheet extends CthulhuEternalItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["bond"],
|
||||
position: {
|
||||
width: 600,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["bond-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-cthulhu-eternal/templates/bond.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
|
||||
return context
|
||||
}
|
||||
}
|
27
module/applications/sheets/gear-sheet.mjs
Normal file
27
module/applications/sheets/gear-sheet.mjs
Normal file
@ -0,0 +1,27 @@
|
||||
import CthulhuEternalItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class CthulhuEternalGearSheet extends CthulhuEternalItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["gear"],
|
||||
position: {
|
||||
width: 600,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["gear-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-cthulhu-eternal/templates/gear.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
return context
|
||||
}
|
||||
}
|
28
module/applications/sheets/injury-sheet.mjs
Normal file
28
module/applications/sheets/injury-sheet.mjs
Normal file
@ -0,0 +1,28 @@
|
||||
import CthulhuEternalItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class CthulhuEternalInjurySheet extends CthulhuEternalItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["injury"],
|
||||
position: {
|
||||
width: 600,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["injury-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-cthulhu-eternal/templates/injury.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
|
||||
return context
|
||||
}
|
||||
}
|
21
module/applications/sheets/mentaldisorder-sheet.mjs
Normal file
21
module/applications/sheets/mentaldisorder-sheet.mjs
Normal file
@ -0,0 +1,21 @@
|
||||
import CthulhuEternalItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class CthulhuEternalMentalDisorderSheet extends CthulhuEternalItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["mentaldisorder"],
|
||||
position: {
|
||||
width: 450,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["mentaldisorder-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-cthulhu-eternal/templates/mentaldisorder.hbs",
|
||||
},
|
||||
}
|
||||
}
|
27
module/applications/sheets/motivation-sheet.mjs
Normal file
27
module/applications/sheets/motivation-sheet.mjs
Normal file
@ -0,0 +1,27 @@
|
||||
import CthulhuEternalItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class CthulhuEternalMotivationSheet extends CthulhuEternalItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["motivation"],
|
||||
position: {
|
||||
width: 620,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["motivation-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-cthulhu-eternal/templates/motivation.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
return context
|
||||
}
|
||||
}
|
173
module/applications/sheets/protagonist-sheet.mjs
Normal file
173
module/applications/sheets/protagonist-sheet.mjs
Normal file
@ -0,0 +1,173 @@
|
||||
import CthulhuEternalActorSheet from "./base-actor-sheet.mjs"
|
||||
|
||||
export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["protagonist"],
|
||||
position: {
|
||||
width: 1150,
|
||||
height: 780,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["protagonist-content"],
|
||||
},
|
||||
actions: {
|
||||
createEquipment: CthulhuEternalProtagonistSheet.#onCreateEquipment,
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-cthulhu-eternal/templates/character-main.hbs",
|
||||
},
|
||||
tabs: {
|
||||
template: "systems/fvtt-cthulhu-eternal/templates/generic/tab-navigation.hbs",
|
||||
},
|
||||
items: {
|
||||
template: "systems/fvtt-cthulhu-eternal/templates/character-items.hbs",
|
||||
},
|
||||
biography: {
|
||||
template: "systems/fvtt-cthulhu-eternal/templates/character-biography.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
sheet: "items",
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an array of form header tabs.
|
||||
* @returns {Record<string, Partial<ApplicationTab>>}
|
||||
*/
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
items: { id: "items", group: "sheet", icon: "fa-solid fa-shapes", label: "CTHULHUETERNAL.Character.Label.details" },
|
||||
biography: { id: "biography", group: "sheet", icon: "fa-solid fa-book", label: "CTHULHUETERNAL.Character.Label.biography" },
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
|
||||
context.tooltipsCaracteristiques = {
|
||||
}
|
||||
|
||||
context.tooltipsRessources = {
|
||||
}
|
||||
|
||||
context.rollType = {
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
_generateTooltip(type, target) {
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _preparePartContext(partId, context) {
|
||||
const doc = this.document
|
||||
switch (partId) {
|
||||
case "main":
|
||||
context.enrichedBiens = await TextEditor.enrichHTML(doc.system.biens, { async: true })
|
||||
break
|
||||
case "items":
|
||||
context.tab = context.tabs.items
|
||||
context.weapons = doc.itemTypes.weapon
|
||||
context.armors = doc.itemTypes.armor
|
||||
context.spells = doc.itemTypes.spell
|
||||
context.hasSpells = context.spells.length > 0
|
||||
break
|
||||
case "biography":
|
||||
context.tab = context.tabs.biography
|
||||
context.enrichedDescription = await TextEditor.enrichHTML(doc.system.description, { async: true })
|
||||
context.enrichedNotes = await TextEditor.enrichHTML(doc.system.notes, { async: true })
|
||||
break
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
// #region Drag-and-Drop Workflow
|
||||
|
||||
/**
|
||||
* Callback actions which occur when a dragged element is dropped on a target.
|
||||
* @param {DragEvent} event The originating DragEvent
|
||||
* @protected
|
||||
*/
|
||||
async _onDrop(event) {
|
||||
if (!this.isEditable || !this.isEditMode) return
|
||||
const data = TextEditor.getDragEventData(event)
|
||||
|
||||
// Handle different data types
|
||||
switch (data.type) {
|
||||
case "Item":
|
||||
const item = await fromUuid(data.uuid)
|
||||
if (!["path", "weapon", "armor", "spell"].includes(item.type)) return
|
||||
if (item.type === "path") return this.#onDropPathItem(item)
|
||||
if (item.type === "weapon") return super._onDropItem(item)
|
||||
if (item.type === "armor") return this._onDropItem(item)
|
||||
if (item.type === "spell") return this._onDropItem(item)
|
||||
}
|
||||
}
|
||||
|
||||
async #onDropPathItem(item) {
|
||||
await this.document.addPath(item)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new attack item directly from the sheet and embeds it into the document.
|
||||
* @param {Event} event The initiating click event.
|
||||
* @param {HTMLElement} target The current target of the event listener.
|
||||
*/
|
||||
static #onCreateEquipment(event, target) {
|
||||
// Création d'une armure
|
||||
if (event.shiftKey) {
|
||||
this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("CTHULHUETERNAL.Label.newArmor"), type: "armor" }])
|
||||
}
|
||||
// Création d'une arme
|
||||
else {
|
||||
this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("CTHULHUETERNAL.Label.newWeapon"), type: "weapon" }])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the roll action triggered by user interaction.
|
||||
*
|
||||
* @param {PointerEvent} event The event object representing the user interaction.
|
||||
* @param {HTMLElement} target The target element that triggered the roll.
|
||||
*
|
||||
* @returns {Promise<void>} A promise that resolves when the roll action is complete.
|
||||
*
|
||||
* @throws {Error} Throws an error if the roll type is not recognized.
|
||||
*
|
||||
* @description This method checks the current mode (edit or not) and determines the type of roll
|
||||
* (save, resource, or damage) based on the target element's data attributes. It retrieves the
|
||||
* corresponding value from the document's system and performs the roll.
|
||||
*/
|
||||
async _onRoll(event, target) {
|
||||
if (this.isEditMode) return
|
||||
// Jet de sauvegarde
|
||||
let elt = event.currentTarget.querySelector("input")
|
||||
// Jet de ressource
|
||||
if (!elt) elt = event.currentTarget.querySelector("select")
|
||||
// Jet de dégâts
|
||||
if (!elt) elt = event.currentTarget
|
||||
const rollType = elt.dataset.rollType
|
||||
let rollTarget
|
||||
switch (rollType) {
|
||||
default:
|
||||
break
|
||||
}
|
||||
await this.document.system.roll(rollType, rollTarget)
|
||||
}
|
||||
// #endregion
|
||||
}
|
28
module/applications/sheets/skill-sheet.mjs
Normal file
28
module/applications/sheets/skill-sheet.mjs
Normal file
@ -0,0 +1,28 @@
|
||||
import CthulhuEternalItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class CthulhuEternalSkillSheet extends CthulhuEternalItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["skill"],
|
||||
position: {
|
||||
width: 600,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["skill-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-cthulhu-eternal/templates/skill.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
|
||||
return context
|
||||
}
|
||||
}
|
21
module/applications/sheets/weapon-sheet.mjs
Normal file
21
module/applications/sheets/weapon-sheet.mjs
Normal file
@ -0,0 +1,21 @@
|
||||
import LethalFantasyItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class LethalFantasyWeaponSheet extends LethalFantasyItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["weapon"],
|
||||
position: {
|
||||
width: 620,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["weapon-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-cthulhu-eternal/templates/weapon.hbs",
|
||||
},
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user