Migration vers datamodels
This commit is contained in:
@@ -379,9 +379,9 @@ export class EcrymeActor extends Actor {
|
||||
rollData.img = this.img
|
||||
rollData.isReroll = false
|
||||
rollData.config = game.system.ecryme.config
|
||||
rollData.traits = foundry.utils.duplicate(this.getRollTraits())
|
||||
rollData.spleen = foundry.utils.duplicate(this.getSpleen() || {})
|
||||
rollData.ideal = foundry.utils.duplicate(this.getIdeal() || {})
|
||||
rollData.traits = this.getRollTraits().map(t => ({ _id: t.id, name: t.name, img: t.img, system: { level: t.system.level, traitype: t.system.traitype } }))
|
||||
rollData.spleen = this.getSpleen() ? foundry.utils.duplicate(this.getSpleen()) : null
|
||||
rollData.ideal = this.getIdeal() ? foundry.utils.duplicate(this.getIdeal()) : null
|
||||
rollData.confrontBonus = this.getBonusList()
|
||||
|
||||
return rollData
|
||||
|
||||
2
modules/actors/sheets/_module.js
Normal file
2
modules/actors/sheets/_module.js
Normal file
@@ -0,0 +1,2 @@
|
||||
export { default as EcrymeActorSheet } from "./pc-npc-sheet.js"
|
||||
export { default as EcrymeAnnencySheet } from "./annency-sheet.js"
|
||||
127
modules/actors/sheets/annency-sheet.js
Normal file
127
modules/actors/sheets/annency-sheet.js
Normal file
@@ -0,0 +1,127 @@
|
||||
import EcrymeBaseActorSheet from "./base-actor-sheet.js"
|
||||
import { EcrymeUtility } from "../../common/ecryme-utility.js"
|
||||
|
||||
/**
|
||||
* Actor sheet for the Annency type using Application V2.
|
||||
*/
|
||||
export default class EcrymeAnnencySheet extends EcrymeBaseActorSheet {
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["annency"],
|
||||
position: { width: 640, height: 600 },
|
||||
actions: {
|
||||
actorEdit: EcrymeAnnencySheet.#onActorEdit,
|
||||
actorDelete: EcrymeAnnencySheet.#onActorDelete,
|
||||
itemEdit: EcrymeAnnencySheet.#onItemEdit,
|
||||
itemDelete: EcrymeAnnencySheet.#onItemDelete,
|
||||
itemCreate: EcrymeAnnencySheet.#onItemCreate,
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
header: { template: "systems/fvtt-ecryme/templates/actors/partials/actor-header.hbs" },
|
||||
tabs: { template: "templates/generic/tab-navigation.hbs" },
|
||||
annency: { template: "systems/fvtt-ecryme/templates/actors/annency-annency.hbs" },
|
||||
boheme: { template: "systems/fvtt-ecryme/templates/actors/annency-boheme.hbs" },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = { primary: "annency" }
|
||||
|
||||
/** Build tabs conditionally based on active modules */
|
||||
_getTabs() {
|
||||
const tabs = {}
|
||||
if (EcrymeUtility.hasCephaly()) {
|
||||
tabs.annency = { id: "annency", group: "primary", label: "ECRY.ui.annency" }
|
||||
}
|
||||
if (EcrymeUtility.hasBoheme()) {
|
||||
tabs.boheme = { id: "boheme", group: "primary", label: "ECRY.ui.boheme" }
|
||||
}
|
||||
// Ensure initial tab is valid
|
||||
if (!tabs[this.tabGroups.primary]) {
|
||||
this.tabGroups.primary = Object.keys(tabs)[0] ?? "annency"
|
||||
}
|
||||
for (const tab of Object.values(tabs)) {
|
||||
tab.active = this.tabGroups[tab.group] === tab.id
|
||||
tab.cssClass = tab.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const actor = this.document
|
||||
return {
|
||||
actor,
|
||||
system: actor.system,
|
||||
source: actor.toObject(),
|
||||
fields: actor.schema.fields,
|
||||
systemFields: actor.system.schema.fields,
|
||||
type: actor.type,
|
||||
img: actor.img,
|
||||
name: actor.name,
|
||||
isEditable: this.isEditable,
|
||||
config: game.system.ecryme.config,
|
||||
hasCephaly: EcrymeUtility.hasCephaly(),
|
||||
hasBoheme: EcrymeUtility.hasBoheme(),
|
||||
characters: actor.buildAnnencyActorList(),
|
||||
owner: this.document.isOwner,
|
||||
isGM: game.user.isGM,
|
||||
tabs: this._getTabs(),
|
||||
}
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _preparePartContext(partId, context) {
|
||||
context = await super._preparePartContext(partId, context)
|
||||
if (partId === "annency" || partId === "boheme") {
|
||||
context.tab = context.tabs[partId]
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _onDrop(event) {
|
||||
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event)
|
||||
if (data.type === "Actor") {
|
||||
const actor = await fromUuid(data.uuid)
|
||||
if (actor) {
|
||||
this.actor.addAnnencyActor(actor.id)
|
||||
} else {
|
||||
ui.notifications.warn("Actor not found")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #region Static Action Handlers
|
||||
|
||||
static #onActorEdit(event, target) {
|
||||
const li = target.closest("[data-actor-id]")
|
||||
game.actors.get(li?.dataset.actorId)?.sheet.render(true)
|
||||
}
|
||||
|
||||
static async #onActorDelete(event, target) {
|
||||
const li = target.closest("[data-actor-id]")
|
||||
this.actor.removeAnnencyActor(li?.dataset.actorId)
|
||||
}
|
||||
|
||||
static #onItemEdit(event, target) {
|
||||
const li = target.closest("[data-item-id]")
|
||||
const itemId = li?.dataset.itemId ?? target.dataset.itemId
|
||||
this.document.items.get(itemId)?.sheet.render(true)
|
||||
}
|
||||
|
||||
static async #onItemDelete(event, target) {
|
||||
const li = target.closest("[data-item-id]")
|
||||
EcrymeUtility.confirmDelete(this, $(li)).catch(() => {})
|
||||
}
|
||||
|
||||
static #onItemCreate(event, target) {
|
||||
const dataType = target.dataset.type
|
||||
this.document.createEmbeddedDocuments("Item", [{ name: "NewItem", type: dataType }], { renderSheet: true })
|
||||
}
|
||||
|
||||
// #endregion
|
||||
}
|
||||
81
modules/actors/sheets/base-actor-sheet.js
Normal file
81
modules/actors/sheets/base-actor-sheet.js
Normal file
@@ -0,0 +1,81 @@
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||
|
||||
/**
|
||||
* Base actor sheet for Ecryme using Application V2.
|
||||
* Provides common drag-drop, image editing, and shared structure.
|
||||
*/
|
||||
export default class EcrymeBaseActorSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ActorSheetV2) {
|
||||
|
||||
constructor(options = {}) {
|
||||
super(options)
|
||||
this.#dragDrop = this.#createDragDropHandlers()
|
||||
}
|
||||
|
||||
#dragDrop
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["fvtt-ecryme", "sheet", "actor"],
|
||||
position: {
|
||||
width: 860,
|
||||
height: 680,
|
||||
},
|
||||
form: {
|
||||
submitOnChange: true,
|
||||
},
|
||||
window: {
|
||||
resizable: true,
|
||||
},
|
||||
dragDrop: [{ dragSelector: ".item-list .item[data-item-id]", dropSelector: null }],
|
||||
actions: {
|
||||
editImage: EcrymeBaseActorSheet.#onEditImage,
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_onRender(context, options) {
|
||||
this.#dragDrop.forEach((d) => d.bind(this.element))
|
||||
}
|
||||
|
||||
// #region Drag-and-Drop
|
||||
#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 foundry.applications.ux.DragDrop.implementation(d)
|
||||
})
|
||||
}
|
||||
|
||||
_canDragStart(selector) { return this.isEditable }
|
||||
_canDragDrop(selector) { return this.isEditable && this.document.isOwner }
|
||||
_onDragStart(event) {}
|
||||
_onDragOver(event) {}
|
||||
async _onDrop(event) {}
|
||||
// #endregion
|
||||
|
||||
// #region Actions
|
||||
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
|
||||
}
|
||||
255
modules/actors/sheets/pc-npc-sheet.js
Normal file
255
modules/actors/sheets/pc-npc-sheet.js
Normal file
@@ -0,0 +1,255 @@
|
||||
import EcrymeBaseActorSheet from "./base-actor-sheet.js"
|
||||
import { EcrymeUtility } from "../../common/ecryme-utility.js"
|
||||
|
||||
/**
|
||||
* Actor sheet for PC and NPC types using Application V2.
|
||||
*/
|
||||
export default class EcrymeActorSheet extends EcrymeBaseActorSheet {
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["pc-npc"],
|
||||
position: { width: 860, height: 680 },
|
||||
actions: {
|
||||
openAnnency: EcrymeActorSheet.#onOpenAnnency,
|
||||
itemEdit: EcrymeActorSheet.#onItemEdit,
|
||||
itemDelete: EcrymeActorSheet.#onItemDelete,
|
||||
itemCreate: EcrymeActorSheet.#onItemCreate,
|
||||
subactorEdit: EcrymeActorSheet.#onSubactorEdit,
|
||||
subactorDelete: EcrymeActorSheet.#onSubactorDelete,
|
||||
rollSkill: EcrymeActorSheet.#onRollSkill,
|
||||
rollSpec: EcrymeActorSheet.#onRollSpec,
|
||||
rollSkillConfront: EcrymeActorSheet.#onRollSkillConfront,
|
||||
rollCephaly: EcrymeActorSheet.#onRollCephaly,
|
||||
rollWeaponConfront:EcrymeActorSheet.#onRollWeaponConfront,
|
||||
impactModify: EcrymeActorSheet.#onImpactModify,
|
||||
rollWeapon: EcrymeActorSheet.#onRollWeapon,
|
||||
lockUnlock: EcrymeActorSheet.#onLockUnlock,
|
||||
equipItem: EcrymeActorSheet.#onEquipItem,
|
||||
quantityMinus: EcrymeActorSheet.#onQuantityMinus,
|
||||
quantityPlus: EcrymeActorSheet.#onQuantityPlus,
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
header: { template: "systems/fvtt-ecryme/templates/actors/partials/actor-header.hbs" },
|
||||
tabs: { template: "templates/generic/tab-navigation.hbs" },
|
||||
skills: { template: "systems/fvtt-ecryme/templates/actors/actor-skills.hbs" },
|
||||
traits: { template: "systems/fvtt-ecryme/templates/actors/actor-traits.hbs" },
|
||||
combat: { template: "systems/fvtt-ecryme/templates/actors/actor-combat.hbs" },
|
||||
cephaly: { template: "systems/fvtt-ecryme/templates/actors/actor-cephaly.hbs" },
|
||||
equipements:{ template: "systems/fvtt-ecryme/templates/actors/actor-equipements.hbs" },
|
||||
biodata: { template: "systems/fvtt-ecryme/templates/actors/actor-biodata.hbs" },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = { primary: "skills" }
|
||||
|
||||
/** Build tabs, conditionally adding cephaly if the module is active */
|
||||
_getTabs() {
|
||||
const hasCephaly = EcrymeUtility.hasCephaly()
|
||||
const tabs = {
|
||||
skills: { id: "skills", group: "primary", label: "ECRY.ui.skills" },
|
||||
traits: { id: "traits", group: "primary", label: "ECRY.ui.traits" },
|
||||
combat: { id: "combat", group: "primary", label: "ECRY.ui.healthcombat" },
|
||||
equipements:{ id: "equipements", group: "primary", label: "ECRY.ui.equipment" },
|
||||
biodata: { id: "biodata", group: "primary", label: "ECRY.ui.bionotes" },
|
||||
}
|
||||
if (hasCephaly) {
|
||||
// Insert cephaly after combat, rebuilding the object to preserve insertion order
|
||||
const ordered = {}
|
||||
for (const [k, v] of Object.entries(tabs)) {
|
||||
ordered[k] = v
|
||||
if (k === "combat") ordered.cephaly = { id: "cephaly", group: "primary", label: "ECRY.ui.cephaly" }
|
||||
}
|
||||
for (const tab of Object.values(ordered)) {
|
||||
tab.active = this.tabGroups[tab.group] === tab.id
|
||||
tab.cssClass = tab.active ? "active" : ""
|
||||
}
|
||||
return ordered
|
||||
}
|
||||
for (const tab of Object.values(tabs)) {
|
||||
tab.active = this.tabGroups[tab.group] === tab.id
|
||||
tab.cssClass = tab.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const actor = this.document
|
||||
return {
|
||||
actor,
|
||||
system: actor.system,
|
||||
source: actor.toObject(),
|
||||
fields: actor.schema.fields,
|
||||
systemFields: actor.system.schema.fields,
|
||||
type: actor.type,
|
||||
img: actor.img,
|
||||
name: actor.name,
|
||||
isEditable: this.isEditable,
|
||||
config: game.system.ecryme.config,
|
||||
hasCephaly: EcrymeUtility.hasCephaly(),
|
||||
hasBoheme: EcrymeUtility.hasBoheme(),
|
||||
hasAmertume: EcrymeUtility.hasAmertume(),
|
||||
skills: actor.prepareSkills(),
|
||||
traits: actor.getRollTraits(),
|
||||
ideal: actor.getIdeal(),
|
||||
spleen: actor.getSpleen(),
|
||||
weapons: actor.getWeapons(),
|
||||
maneuvers: actor.getManeuvers(),
|
||||
impactsMalus: actor.getImpactsMalus(),
|
||||
equipments: actor.getEquipments(),
|
||||
cephalySkills:actor.getCephalySkills(),
|
||||
confrontations: actor.getConfrontations(),
|
||||
subActors: actor.getSubActors(),
|
||||
annency: actor.getAnnency(),
|
||||
owner: this.document.isOwner,
|
||||
isGM: game.user.isGM,
|
||||
editScore: this.options.editScore ?? true,
|
||||
tabs: this._getTabs(),
|
||||
}
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _preparePartContext(partId, context) {
|
||||
context = await super._preparePartContext(partId, context)
|
||||
switch (partId) {
|
||||
case "skills":
|
||||
case "traits":
|
||||
case "combat":
|
||||
case "cephaly":
|
||||
case "equipements":
|
||||
context.tab = context.tabs[partId] ?? { cssClass: "" }
|
||||
break
|
||||
case "biodata":
|
||||
context.tab = context.tabs.biodata
|
||||
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||
this.document.system.biodata.description, { async: true }
|
||||
)
|
||||
context.enrichedGmnotes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||
this.document.system.biodata.gmnotes, { async: true }
|
||||
)
|
||||
break
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
// #region Drag and Drop
|
||||
|
||||
/** Handle incoming drops: Items from sidebar/compendium, Actors as subactors */
|
||||
async _onDrop(event) {
|
||||
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event)
|
||||
if (!data?.type) return
|
||||
|
||||
if (data.type === "Item") {
|
||||
const item = await fromUuid(data.uuid)
|
||||
if (!item) return
|
||||
await this.document.createEmbeddedDocuments("Item", [item.toObject()])
|
||||
} else if (data.type === "Actor") {
|
||||
const actor = fromUuidSync(data.uuid)
|
||||
if (actor) await this.actor.addSubActor(actor.id)
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle outgoing drag from embedded item rows */
|
||||
_onDragStart(event) {
|
||||
const li = event.currentTarget.closest("[data-item-id]")
|
||||
if (!li) return
|
||||
const item = this.document.items.get(li.dataset.itemId)
|
||||
if (!item) return
|
||||
event.dataTransfer.setData("text/plain", JSON.stringify(item.toDragData()))
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region Static Action Handlers
|
||||
|
||||
static #onOpenAnnency(event, target) {
|
||||
const actorId = target.dataset.annencyId
|
||||
game.actors.get(actorId)?.sheet.render(true)
|
||||
}
|
||||
|
||||
static #onItemEdit(event, target) {
|
||||
const li = target.closest("[data-item-id]")
|
||||
const itemId = li?.dataset.itemId ?? target.dataset.itemId
|
||||
this.document.items.get(itemId)?.sheet.render(true)
|
||||
}
|
||||
|
||||
static async #onItemDelete(event, target) {
|
||||
const li = target.closest("[data-item-id]")
|
||||
EcrymeUtility.confirmDelete(this, $(li)).catch(() => {})
|
||||
}
|
||||
|
||||
static #onItemCreate(event, target) {
|
||||
const dataType = target.dataset.type
|
||||
this.document.createEmbeddedDocuments("Item", [{ name: "NewItem", type: dataType }], { renderSheet: true })
|
||||
}
|
||||
|
||||
static #onSubactorEdit(event, target) {
|
||||
const li = target.closest("[data-actor-id]")
|
||||
game.actors.get(li?.dataset.actorId)?.sheet.render(true)
|
||||
}
|
||||
|
||||
static #onSubactorDelete(event, target) {
|
||||
const li = target.closest("[data-actor-id]")
|
||||
this.actor.delSubActor(li?.dataset.actorId)
|
||||
}
|
||||
|
||||
static #onRollSkill(event, target) {
|
||||
this.actor.rollSkill(target.dataset.categoryKey, target.dataset.skillKey)
|
||||
}
|
||||
|
||||
static #onRollSpec(event, target) {
|
||||
this.actor.rollSpec(target.dataset.categoryKey, target.dataset.skillKey, target.dataset.specId)
|
||||
}
|
||||
|
||||
static #onRollSkillConfront(event, target) {
|
||||
this.actor.rollSkillConfront(target.dataset.categoryKey, target.dataset.skillKey)
|
||||
}
|
||||
|
||||
static #onRollCephaly(event, target) {
|
||||
this.actor.rollCephalySkillConfront(target.dataset.skillKey)
|
||||
}
|
||||
|
||||
static #onRollWeaponConfront(event, target) {
|
||||
const li = target.closest("[data-item-id]")
|
||||
this.actor.rollWeaponConfront(li?.dataset.itemId)
|
||||
}
|
||||
|
||||
static #onImpactModify(event, target) {
|
||||
this.actor.modifyImpact(
|
||||
target.dataset.impactType,
|
||||
target.dataset.impactLevel,
|
||||
Number(target.dataset.impactModifier)
|
||||
)
|
||||
}
|
||||
|
||||
static #onRollWeapon(event, target) {
|
||||
this.actor.rollArme(target.dataset.armeId)
|
||||
}
|
||||
|
||||
static #onLockUnlock(event, target) {
|
||||
this.options.editScore = !this.options.editScore
|
||||
this.render(true)
|
||||
}
|
||||
|
||||
static #onEquipItem(event, target) {
|
||||
const li = target.closest("[data-item-id]")
|
||||
this.actor.equipItem(li?.dataset.itemId)
|
||||
this.render(true)
|
||||
}
|
||||
|
||||
static #onQuantityMinus(event, target) {
|
||||
const li = target.closest("[data-item-id]")
|
||||
this.actor.incDecQuantity(li?.dataset.itemId, -1)
|
||||
}
|
||||
|
||||
static #onQuantityPlus(event, target) {
|
||||
const li = target.closest("[data-item-id]")
|
||||
this.actor.incDecQuantity(li?.dataset.itemId, +1)
|
||||
}
|
||||
|
||||
// #endregion
|
||||
}
|
||||
@@ -211,6 +211,8 @@ export class EcrymeUtility {
|
||||
type: "confront-data",
|
||||
rollData1: this.confrontData1,
|
||||
rollData2: this.confrontData2,
|
||||
alias: this.confrontData1.alias,
|
||||
actorImg: this.confrontData1.actorImg,
|
||||
}
|
||||
// Compute margin
|
||||
confront.marginExecution = this.confrontData1.executionTotal - this.confrontData2.preservationTotal
|
||||
@@ -378,6 +380,9 @@ export class EcrymeUtility {
|
||||
'systems/fvtt-ecryme/templates/dialogs/partial-confront-dice-area.hbs',
|
||||
'systems/fvtt-ecryme/templates/dialogs/partial-confront-bonus-area.hbs',
|
||||
'systems/fvtt-ecryme/templates/actors/partial-impacts.hbs',
|
||||
'systems/fvtt-ecryme/templates/actors/partials/actor-header.hbs',
|
||||
'systems/fvtt-ecryme/templates/items/partials/item-header.hbs',
|
||||
'systems/fvtt-ecryme/templates/items/partials/item-description.hbs',
|
||||
]
|
||||
return foundry.applications.handlebars.loadTemplates(templatePaths);
|
||||
}
|
||||
|
||||
@@ -1,169 +1,192 @@
|
||||
import { EcrymeUtility } from "../common/ecryme-utility.js";
|
||||
import { EcrymeRollDialog } from "./ecryme-roll-dialog.js";
|
||||
|
||||
export class EcrymeConfrontDialog extends Dialog {
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||
|
||||
/**
|
||||
* Main confrontation dialog — Application V2 version.
|
||||
* Features drag-and-drop of dice from the pool to execution/preservation slots.
|
||||
* All event listeners (change + drag-drop) are bound once via _listenersAdded guard.
|
||||
*/
|
||||
export class EcrymeConfrontDialog extends HandlebarsApplicationMixin(foundry.applications.api.ApplicationV2) {
|
||||
|
||||
#dragDrop
|
||||
_listenersAdded = false
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(actor, rollData, options = {}) {
|
||||
super(options)
|
||||
this.actor = actor
|
||||
this.rollData = rollData
|
||||
this.buttonDisabled = true
|
||||
this.#dragDrop = this.#createDragDropHandlers()
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["fvtt-ecryme", "ecryme-confrontation-dialog"],
|
||||
position: { width: 640 },
|
||||
window: { title: "ECRY.ui.confront" },
|
||||
dragDrop: [{ dragSelector: ".confront-dice-container", dropSelector: null }],
|
||||
actions: {
|
||||
launchConfront: EcrymeConfrontDialog.#onLaunchConfront,
|
||||
cancel: EcrymeConfrontDialog.#onCancel,
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
content: { template: "systems/fvtt-ecryme/templates/dialogs/confront-dialog.hbs" },
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async create(actor, rollData) {
|
||||
|
||||
let options = foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["fvtt-ecryme ecryme-confrontation-dialog"],
|
||||
dragDrop: [{ dragSelector: ".confront-dice-container", dropSelector: null }],
|
||||
width: 620, height: 'fit-content', 'z-index': 99999
|
||||
});
|
||||
|
||||
let html = await foundry.applications.handlebars.renderTemplate('systems/fvtt-ecryme/templates/dialogs/confront-dialog.hbs', rollData);
|
||||
return new EcrymeConfrontDialog(actor, rollData, html, options);
|
||||
return new EcrymeConfrontDialog(actor, rollData)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(actor, rollData, html, options, close = undefined) {
|
||||
let conf = {
|
||||
title: game.i18n.localize("ECRY.ui.confront"),
|
||||
content: html,
|
||||
buttons: {
|
||||
launchConfront: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: game.i18n.localize("ECRY.ui.launchconfront"),
|
||||
callback: () => { this.launchConfront().catch("Error when launching Confrontation") }
|
||||
},
|
||||
cancel: {
|
||||
icon: '<i class="fas fa-times"></i>',
|
||||
label: game.i18n.localize("ECRY.ui.cancel"),
|
||||
callback: () => { this.close() }
|
||||
}
|
||||
},
|
||||
close: close
|
||||
async _prepareContext() {
|
||||
return {
|
||||
...this.rollData,
|
||||
config: game.system.ecryme.config,
|
||||
buttonDisabled: this.buttonDisabled,
|
||||
}
|
||||
|
||||
super(conf, options);
|
||||
|
||||
this.actor = actor;
|
||||
this.rollData = rollData;
|
||||
|
||||
// Ensure button is disabled
|
||||
setTimeout(function () { $(".launchConfront").attr("disabled", true) }, 180)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async launchConfront() {
|
||||
let msg = await EcrymeUtility.createChatMessage(this.rollData.alias, "blindroll", {
|
||||
content: await renderTemplate(`systems/fvtt-ecryme/templates/chat/chat-confrontation-pending.hbs`, this.rollData)
|
||||
/** Bind drag-drop and form-change listeners once; re-bind DragDrop on each render. */
|
||||
_onRender(context, options) {
|
||||
// DragDrop must be re-bound each render because the DOM is replaced
|
||||
this.#dragDrop.forEach(d => d.bind(this.element))
|
||||
|
||||
// Form-change listener is bound once (event delegation survives DOM re-renders)
|
||||
if (!this._listenersAdded) {
|
||||
this._listenersAdded = true
|
||||
this.element.addEventListener('change', this.#onFormChange.bind(this))
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
#onFormChange(event) {
|
||||
const target = event.target
|
||||
switch (target.id) {
|
||||
case 'bonusMalusPerso':
|
||||
this.rollData.bonusMalusPerso = Number(target.value)
|
||||
this.computeTotals()
|
||||
break
|
||||
case 'roll-specialization':
|
||||
this.rollData.selectedSpecs = Array.from(target.selectedOptions).map(o => o.value)
|
||||
this.computeTotals()
|
||||
break
|
||||
case 'roll-trait-bonus':
|
||||
this.rollData.traitsBonusSelected = Array.from(target.selectedOptions).map(o => o.value)
|
||||
this.computeTotals()
|
||||
break
|
||||
case 'roll-trait-malus':
|
||||
this.rollData.traitsMalusSelected = Array.from(target.selectedOptions).map(o => o.value)
|
||||
this.computeTotals()
|
||||
break
|
||||
case 'roll-select-transcendence':
|
||||
this.rollData.skillTranscendence = Number(target.value)
|
||||
this.computeTotals()
|
||||
break
|
||||
case 'roll-apply-transcendence':
|
||||
this.rollData.applyTranscendence = target.value
|
||||
this.computeTotals()
|
||||
break
|
||||
case 'annency-bonus':
|
||||
this.rollData.annencyBonus = Number(target.value)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// #region Drag-and-Drop
|
||||
|
||||
#createDragDropHandlers() {
|
||||
return this.options.dragDrop.map(d => {
|
||||
d.permissions = {
|
||||
dragstart: () => true,
|
||||
drop: () => true,
|
||||
}
|
||||
d.callbacks = {
|
||||
dragstart: this._onDragStart.bind(this),
|
||||
dragover: this._onDragOver.bind(this),
|
||||
drop: this._onDrop.bind(this),
|
||||
}
|
||||
return new foundry.applications.ux.DragDrop.implementation(d)
|
||||
})
|
||||
EcrymeUtility.blindMessageToGM( { rollData: this.rollData, template: "systems/fvtt-ecryme/templates/chat/chat-confrontation-pending.hbs" })
|
||||
console.log("MSG", this.rollData)
|
||||
msg.setFlag("world", "ecryme-rolldata", this.rollData)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async refreshDice() {
|
||||
this.rollData.filter = "execution"
|
||||
let content = await renderTemplate("systems/fvtt-ecryme/templates/dialogs/partial-confront-dice-area.hbs", this.rollData )
|
||||
content += await renderTemplate("systems/fvtt-ecryme/templates/dialogs/partial-confront-bonus-area.hbs", this.rollData )
|
||||
$("#confront-execution").html(content)
|
||||
|
||||
this.rollData.filter = "preservation"
|
||||
content = await renderTemplate("systems/fvtt-ecryme/templates/dialogs/partial-confront-dice-area.hbs", this.rollData )
|
||||
content += await renderTemplate("systems/fvtt-ecryme/templates/dialogs/partial-confront-bonus-area.hbs", this.rollData )
|
||||
$("#confront-preservation").html(content)
|
||||
|
||||
this.rollData.filter = "mainpool"
|
||||
content = await renderTemplate("systems/fvtt-ecryme/templates/dialogs/partial-confront-dice-area.hbs", this.rollData )
|
||||
$("#confront-dice-pool").html(content)
|
||||
content = await renderTemplate("systems/fvtt-ecryme/templates/dialogs/partial-confront-bonus-area.hbs", this.rollData )
|
||||
$("#confront-bonus-pool").html(content)
|
||||
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async refreshDialog() {
|
||||
const content = await renderTemplate("systems/fvtt-ecryme/templates/dialogs/confront-dialog.hbs", this.rollData)
|
||||
this.data.content = content
|
||||
this.render(true)
|
||||
|
||||
let button = this.buttonDisabled
|
||||
setTimeout(function () { $(".launchConfront").attr("disabled", button) }, 180)
|
||||
}
|
||||
|
||||
/* ------------------ -------------------------- */
|
||||
_canDragStart(selector) {
|
||||
console.log("CAN DRAG START", selector, super._canDragStart(selector) )
|
||||
return true
|
||||
}
|
||||
_canDragDrop(selector) {
|
||||
console.log("CAN DRAG DROP", selector, super._canDragDrop(selector) )
|
||||
return true
|
||||
}
|
||||
|
||||
/* ------------------ -------------------------- */
|
||||
_onDragStart(event) {
|
||||
console.log("DRAGSTART::::", event)
|
||||
super._onDragStart(event)
|
||||
let dragType = $(event.srcElement).data("drag-type")
|
||||
let diceData = {}
|
||||
console.log("DRAGTYPE", dragType)
|
||||
if (dragType == "dice") {
|
||||
const target = event.target
|
||||
const dragType = target.dataset.dragType
|
||||
let diceData
|
||||
|
||||
if (dragType === "dice") {
|
||||
diceData = {
|
||||
dragType: "dice",
|
||||
diceIndex: $(event.srcElement).data("dice-idx"),
|
||||
diceValue: $(event.srcElement).data("dice-value"),
|
||||
dragType: "dice",
|
||||
diceIndex: target.dataset.diceIdx,
|
||||
diceValue: target.dataset.diceValue,
|
||||
}
|
||||
} else {
|
||||
diceData = {
|
||||
dragType: "bonus",
|
||||
bonusIndex: $(event.srcElement).data("bonus-idx"),
|
||||
bonusValue: 1
|
||||
dragType: "bonus",
|
||||
bonusIndex: target.dataset.bonusIdx,
|
||||
bonusValue: 1,
|
||||
}
|
||||
}
|
||||
event.dataTransfer.setData("text/plain", JSON.stringify(diceData));
|
||||
event.dataTransfer.setData("text/plain", JSON.stringify(diceData))
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_onDragOver(event) {
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_onDrop(event) {
|
||||
let dataJSON = event.dataTransfer.getData('text/plain')
|
||||
let data = JSON.parse(dataJSON)
|
||||
if ( data.dragType == "dice") {
|
||||
let idx = Number(data.diceIndex)
|
||||
console.log("DATA", data, event, event.srcElement.className)
|
||||
if (event.srcElement.className.includes("execution") &&
|
||||
this.rollData.availableDices.filter(d => d.location == "execution").length < 2) {
|
||||
let data
|
||||
try { data = JSON.parse(event.dataTransfer.getData("text/plain")) }
|
||||
catch (e) { return }
|
||||
|
||||
// Walk up the DOM to find a meaningful drop area
|
||||
const executionArea = event.target.closest('.confront-execution-area')
|
||||
const preservationArea = event.target.closest('.confront-preservation-area')
|
||||
const diceList = event.target.closest('.confrontation-dice-list')
|
||||
const bonusList = event.target.closest('.confrontation-bonus-list')
|
||||
|
||||
if (data.dragType === "dice") {
|
||||
const idx = Number(data.diceIndex)
|
||||
if (executionArea && this.rollData.availableDices.filter(d => d.location === "execution").length < 2) {
|
||||
this.rollData.availableDices[idx].location = "execution"
|
||||
}
|
||||
if (event.srcElement.className.includes("preservation") &&
|
||||
this.rollData.availableDices.filter(d => d.location == "preservation").length < 2) {
|
||||
} else if (preservationArea && this.rollData.availableDices.filter(d => d.location === "preservation").length < 2) {
|
||||
this.rollData.availableDices[idx].location = "preservation"
|
||||
}
|
||||
if (event.srcElement.className.includes("dice-list")) {
|
||||
} else if (diceList) {
|
||||
this.rollData.availableDices[idx].location = "mainpool"
|
||||
}
|
||||
|
||||
if (this.rollData.availableDices.filter(d => d.location == "execution").length == 2 && this.rollData.availableDices.filter(d => d.location == "preservation").length == 2) {
|
||||
this.buttonDisabled = false
|
||||
} else {
|
||||
this.buttonDisabled = true
|
||||
}
|
||||
} else {
|
||||
let idx = Number(data.bonusIndex)
|
||||
if (event.srcElement.className.includes("execution")) {
|
||||
this.rollData.confrontBonus[idx].location = "execution"
|
||||
}
|
||||
if (event.srcElement.className.includes("preservation")) {
|
||||
this.rollData.confrontBonus[idx].location = "preservation"
|
||||
}
|
||||
if (event.srcElement.className.includes("bonus-list")) {
|
||||
this.rollData.confrontBonus[idx].location = "mainpool"
|
||||
}
|
||||
const execCount = this.rollData.availableDices.filter(d => d.location === "execution").length
|
||||
const presCount = this.rollData.availableDices.filter(d => d.location === "preservation").length
|
||||
this.buttonDisabled = !(execCount === 2 && presCount === 2)
|
||||
|
||||
} else if (data.dragType === "bonus") {
|
||||
const idx = Number(data.bonusIndex)
|
||||
if (executionArea) this.rollData.confrontBonus[idx].location = "execution"
|
||||
else if (preservationArea) this.rollData.confrontBonus[idx].location = "preservation"
|
||||
else if (bonusList) this.rollData.confrontBonus[idx].location = "mainpool"
|
||||
}
|
||||
|
||||
// Manage total values
|
||||
this.computeTotals()
|
||||
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
/* -------------------------------------------- */
|
||||
processTranscendence() {
|
||||
// Apply Transcend if needed
|
||||
if (this.rollData.skillTranscendence > 0) {
|
||||
if (this.rollData.applyTranscendence == "execution") {
|
||||
this.rollData.executionTotal += Number(this.rollData.skillTranscendence)
|
||||
if (this.rollData.applyTranscendence === "execution") {
|
||||
this.rollData.executionTotal += Number(this.rollData.skillTranscendence)
|
||||
} else {
|
||||
this.rollData.preservationTotal += Number(this.rollData.skillTranscendence)
|
||||
}
|
||||
@@ -172,94 +195,78 @@ export class EcrymeConfrontDialog extends Dialog {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
computeTotals() {
|
||||
let rollData = this.rollData
|
||||
let actor = game.actors.get(rollData.actorId)
|
||||
const rollData = this.rollData
|
||||
const actor = game.actors.get(rollData.actorId)
|
||||
|
||||
rollData.executionTotal = rollData.availableDices.filter(d => d.location == "execution").reduce((previous, current) => {
|
||||
return previous + current.result
|
||||
}, rollData.skill.value)
|
||||
rollData.executionTotal = rollData.confrontBonus.filter(d => d.location == "execution").reduce((previous, current) => {
|
||||
return previous + 1
|
||||
}, rollData.executionTotal)
|
||||
rollData.executionTotal = rollData.availableDices
|
||||
.filter(d => d.location === "execution")
|
||||
.reduce((acc, d) => acc + d.result, rollData.skill.value)
|
||||
rollData.executionTotal = rollData.confrontBonus
|
||||
.filter(d => d.location === "execution")
|
||||
.reduce((acc) => acc + 1, rollData.executionTotal)
|
||||
|
||||
rollData.preservationTotal = rollData.availableDices.filter(d => d.location == "preservation").reduce((previous, current) => {
|
||||
return previous + current.result
|
||||
}, rollData.skill.value)
|
||||
rollData.preservationTotal = rollData.confrontBonus.filter(d => d.location == "preservation").reduce((previous, current) => {
|
||||
return previous + 1
|
||||
}, rollData.preservationTotal)
|
||||
rollData.preservationTotal = rollData.availableDices
|
||||
.filter(d => d.location === "preservation")
|
||||
.reduce((acc, d) => acc + d.result, rollData.skill.value)
|
||||
rollData.preservationTotal = rollData.confrontBonus
|
||||
.filter(d => d.location === "preservation")
|
||||
.reduce((acc) => acc + 1, rollData.preservationTotal)
|
||||
|
||||
this.processTranscendence()
|
||||
|
||||
if (rollData.selectedSpecs && rollData.selectedSpecs.length > 0) {
|
||||
rollData.spec = foundry.utils.duplicate(actor.getSpecialization(rollData.selectedSpecs[0]))
|
||||
// Specialization
|
||||
if (rollData.selectedSpecs?.length > 0) {
|
||||
rollData.spec = foundry.utils.duplicate(actor.getSpecialization(rollData.selectedSpecs[0]))
|
||||
rollData.specApplied = true
|
||||
rollData.executionTotal += 2
|
||||
rollData.executionTotal += 2
|
||||
rollData.preservationTotal += 2
|
||||
}
|
||||
if ( rollData.specApplied && rollData.selectedSpecs.length == 0) {
|
||||
rollData.spec = undefined
|
||||
if (rollData.specApplied && rollData.selectedSpecs?.length === 0) {
|
||||
rollData.spec = undefined
|
||||
rollData.specApplied = false
|
||||
}
|
||||
|
||||
// Traits bonus/malus
|
||||
rollData.bonusMalusTraits = 0
|
||||
for (let t of rollData.traitsBonus) {
|
||||
t.activated = false
|
||||
for (const t of rollData.traitsBonus) t.activated = false
|
||||
for (const t of rollData.traitsMalus) t.activated = false
|
||||
|
||||
for (const id of (rollData.traitsBonusSelected ?? [])) {
|
||||
const trait = rollData.traitsBonus.find(t => t._id === id)
|
||||
if (trait) { trait.activated = true; rollData.bonusMalusTraits += Number(trait.system.level) }
|
||||
}
|
||||
for (let t of rollData.traitsMalus) {
|
||||
t.activated = false
|
||||
}
|
||||
if (rollData.traitsBonusSelected && rollData.traitsBonusSelected.length > 0) {
|
||||
for (let id of rollData.traitsBonusSelected) {
|
||||
let trait = rollData.traitsBonus.find(t => t._id == id)
|
||||
trait.activated = true
|
||||
rollData.bonusMalusTraits += Number(trait.system.level)
|
||||
}
|
||||
}
|
||||
if (rollData.traitsMalusSelected && rollData.traitsMalusSelected.length > 0) {
|
||||
for (let id of rollData.traitsMalusSelected) {
|
||||
let trait = rollData.traitsMalus.find(t => t._id == id)
|
||||
trait.activated = true
|
||||
rollData.bonusMalusTraits -= Number(trait.system.level)
|
||||
}
|
||||
for (const id of (rollData.traitsMalusSelected ?? [])) {
|
||||
const trait = rollData.traitsMalus.find(t => t._id === id)
|
||||
if (trait) { trait.activated = true; rollData.bonusMalusTraits -= Number(trait.system.level) }
|
||||
}
|
||||
|
||||
rollData.executionTotal += Number(rollData.bonusMalusTraits) + Number(rollData.bonusMalusPerso)
|
||||
rollData.executionTotal += Number(rollData.bonusMalusTraits) + Number(rollData.bonusMalusPerso)
|
||||
rollData.preservationTotal += Number(rollData.bonusMalusTraits) + Number(rollData.bonusMalusPerso)
|
||||
|
||||
this.refreshDialog()
|
||||
this.render()
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
html.find('#bonusMalusPerso').change((event) => {
|
||||
this.rollData.bonusMalusPerso = event.currentTarget.value
|
||||
this.computeTotals()
|
||||
async launchConfront() {
|
||||
const msg = await EcrymeUtility.createChatMessage(this.rollData.alias, "blindroll", {
|
||||
content: await foundry.applications.handlebars.renderTemplate(
|
||||
`systems/fvtt-ecryme/templates/chat/chat-confrontation-pending.hbs`, this.rollData
|
||||
),
|
||||
})
|
||||
html.find('#roll-specialization').change((event) => {
|
||||
this.rollData.selectedSpecs = $('#roll-specialization').val()
|
||||
this.computeTotals()
|
||||
EcrymeUtility.blindMessageToGM({
|
||||
rollData: this.rollData,
|
||||
template: "systems/fvtt-ecryme/templates/chat/chat-confrontation-pending.hbs",
|
||||
})
|
||||
html.find('#roll-trait-bonus').change((event) => {
|
||||
this.rollData.traitsBonusSelected = $('#roll-trait-bonus').val()
|
||||
this.computeTotals()
|
||||
})
|
||||
html.find('#roll-trait-malus').change((event) => {
|
||||
this.rollData.traitsMalusSelected = $('#roll-trait-malus').val()
|
||||
this.computeTotals()
|
||||
})
|
||||
html.find('#roll-select-transcendence').change((event) => {
|
||||
this.rollData.skillTranscendence = Number($('#roll-select-transcendence').val())
|
||||
this.computeTotals()
|
||||
})
|
||||
html.find('#roll-apply-transcendence').change((event) => {
|
||||
this.rollData.applyTranscendence = $('#roll-apply-transcendence').val()
|
||||
this.computeTotals()
|
||||
})
|
||||
html.find('#annency-bonus').change((event) => {
|
||||
this.rollData.annencyBonus = Number(event.currentTarget.value)
|
||||
})
|
||||
|
||||
msg.setFlag("world", "ecryme-rolldata", this.rollData)
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async #onLaunchConfront(event, target) {
|
||||
await this.launchConfront()
|
||||
this.close()
|
||||
}
|
||||
|
||||
static #onCancel(event, target) {
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,77 +1,80 @@
|
||||
import { EcrymeUtility } from "../common/ecryme-utility.js";
|
||||
import { EcrymeConfrontDialog } from "./ecryme-confront-dialog.js";
|
||||
|
||||
export class EcrymeConfrontStartDialog extends Dialog {
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||
|
||||
/**
|
||||
* Confrontation start dialog — Application V2 version.
|
||||
* Player picks which dice formula to roll (normal / spleen / ideal),
|
||||
* the dice are rolled and the main EcrymeConfrontDialog is opened.
|
||||
*/
|
||||
export class EcrymeConfrontStartDialog extends HandlebarsApplicationMixin(foundry.applications.api.ApplicationV2) {
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["fvtt-ecryme", "ecryme-confront-start-dialog"],
|
||||
position: { width: 540 },
|
||||
window: { title: "ECRY.ui.confront" },
|
||||
actions: {
|
||||
rollNormal: EcrymeConfrontStartDialog.#onRollNormal,
|
||||
rollSpleen: EcrymeConfrontStartDialog.#onRollSpleen,
|
||||
rollIdeal: EcrymeConfrontStartDialog.#onRollIdeal,
|
||||
cancel: EcrymeConfrontStartDialog.#onCancel,
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
content: { template: "systems/fvtt-ecryme/templates/dialogs/confront-start-dialog.hbs" },
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(actor, rollData, options = {}) {
|
||||
super(options)
|
||||
this.actor = actor?.token?.actor ?? actor
|
||||
this.rollData = rollData
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async create(actor, rollData) {
|
||||
if (!actor) throw new Error("Ecryme | No actor provided for confront dialog");
|
||||
if (!rollData) throw new Error("Ecryme | No roll data provided for confront dialog");
|
||||
|
||||
if (actor?.token) rollData.tokenId = actor.token.id;
|
||||
let options = { classes: ["fvtt-ecryme ecryme-confront-dialog"], width: 540, height: 'fit-content', 'z-index': 99999 }
|
||||
let html = await foundry.applications.handlebars.renderTemplate('systems/fvtt-ecryme/templates/dialogs/confront-start-dialog.hbs', rollData);
|
||||
return new EcrymeConfrontStartDialog(actor, rollData, html, options);
|
||||
if (!actor) throw new Error("Ecryme | No actor provided for confront dialog")
|
||||
if (!rollData) throw new Error("Ecryme | No roll data provided for confront dialog")
|
||||
if (actor?.token) rollData.tokenId = actor.token.id
|
||||
return new EcrymeConfrontStartDialog(actor, rollData)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(actor, rollData, html, options, close = undefined) {
|
||||
let conf = {
|
||||
title: game.i18n.localize("ECRY.ui.confront"),
|
||||
content: html,
|
||||
buttons: {
|
||||
rollNormal: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: game.i18n.localize("ECRY.ui.rollnormal"),
|
||||
callback: () => { this.rollConfront("4d6") }
|
||||
},
|
||||
rollSpleen: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: game.i18n.localize("ECRY.ui.rollspleen"),
|
||||
callback: () => { this.rollConfront("5d6kl4") }
|
||||
},
|
||||
rollIdeal: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: game.i18n.localize("ECRY.ui.rollideal"),
|
||||
callback: () => { this.rollConfront("5d6kh4") }
|
||||
},
|
||||
cancel: {
|
||||
icon: '<i class="fas fa-times"></i>',
|
||||
label: game.i18n.localize("ECRY.ui.cancel"),
|
||||
callback: () => { this.close() }
|
||||
}
|
||||
},
|
||||
close: close
|
||||
async _prepareContext() {
|
||||
return {
|
||||
...this.rollData,
|
||||
config: game.system.ecryme.config,
|
||||
}
|
||||
|
||||
super(conf, options);
|
||||
|
||||
this.actor = actor?.token?.actor || actor;
|
||||
this.rollData = rollData;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollConfront(diceFormula) {
|
||||
// Do the initial roll
|
||||
let myRoll = await new Roll(diceFormula).roll()
|
||||
async #rollConfront(diceFormula) {
|
||||
const myRoll = await new Roll(diceFormula).roll()
|
||||
await EcrymeUtility.showDiceSoNice(myRoll, game.settings.get("core", "rollMode"))
|
||||
// Fill the available dice table
|
||||
let rollData = this.rollData
|
||||
|
||||
const rollData = this.rollData
|
||||
rollData.roll = foundry.utils.duplicate(myRoll)
|
||||
rollData.availableDices = []
|
||||
for (let result of myRoll.terms[0].results) {
|
||||
for (const result of myRoll.terms[0].results) {
|
||||
if (!result.discarded) {
|
||||
let resultDup = foundry.utils.duplicate(result)
|
||||
resultDup.location = "mainpool"
|
||||
rollData.availableDices.push(resultDup)
|
||||
const dup = foundry.utils.duplicate(result)
|
||||
dup.location = "mainpool"
|
||||
rollData.availableDices.push(dup)
|
||||
}
|
||||
}
|
||||
let confrontDialog = await EcrymeConfrontDialog.create(this.actor, rollData)
|
||||
|
||||
const confrontDialog = await EcrymeConfrontDialog.create(this.actor, rollData)
|
||||
confrontDialog.render(true)
|
||||
this.close()
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
}
|
||||
}
|
||||
static async #onRollNormal(event, target) { await this.#rollConfront("4d6") }
|
||||
static async #onRollSpleen(event, target) { await this.#rollConfront("5d6kl4") }
|
||||
static async #onRollIdeal(event, target) { await this.#rollConfront("5d6kh4") }
|
||||
static #onCancel(event, target) { this.close() }
|
||||
}
|
||||
|
||||
@@ -1,86 +1,78 @@
|
||||
import { EcrymeUtility } from "../common/ecryme-utility.js";
|
||||
|
||||
export class EcrymeRollDialog extends Dialog {
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||
|
||||
/**
|
||||
* Roll dialog — Application V2 version.
|
||||
* Reads all form values at roll time (no live tracking needed).
|
||||
*/
|
||||
export class EcrymeRollDialog extends HandlebarsApplicationMixin(foundry.applications.api.ApplicationV2) {
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["fvtt-ecryme", "ecryme-roll-dialog"],
|
||||
position: { width: 540 },
|
||||
window: { title: "ECRY.ui.rolltitle" },
|
||||
actions: {
|
||||
roll: EcrymeRollDialog.#onRoll,
|
||||
cancel: EcrymeRollDialog.#onCancel,
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
content: { template: "systems/fvtt-ecryme/templates/dialogs/roll-dialog-generic.hbs" },
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(actor, rollData, options = {}) {
|
||||
super(options)
|
||||
this.actor = actor
|
||||
this.rollData = rollData
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async create(actor, rollData) {
|
||||
|
||||
let options = { classes: ["ecryme-roll-dialog"], width: 540, height: 'fit-content', 'z-index': 99999 }
|
||||
let html = await foundry.applications.handlebars.renderTemplate('systems/fvtt-ecryme/templates/dialogs/roll-dialog-generic.hbs', rollData);
|
||||
return new EcrymeRollDialog(actor, rollData, html, options);
|
||||
return new EcrymeRollDialog(actor, rollData)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(actor, rollData, html, options, close = undefined) {
|
||||
let conf = {
|
||||
title: game.i18n.localize("ECRY.ui.rolltitle"),
|
||||
content: html,
|
||||
buttons: {
|
||||
roll: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: game.i18n.localize("ECRY.ui.roll"),
|
||||
callback: () => { this.roll() }
|
||||
},
|
||||
cancel: {
|
||||
icon: '<i class="fas fa-times"></i>',
|
||||
label: game.i18n.localize("ECRY.ui.cancel"),
|
||||
callback: () => { this.close() }
|
||||
}
|
||||
},
|
||||
close: close
|
||||
async _prepareContext() {
|
||||
return {
|
||||
...this.rollData,
|
||||
config: game.system.ecryme.config,
|
||||
}
|
||||
|
||||
super(conf, options);
|
||||
|
||||
this.actor = actor;
|
||||
this.rollData = rollData;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
roll() {
|
||||
/** Read all form values at roll time, then execute. */
|
||||
static #onRoll(event, target) {
|
||||
const el = this.element
|
||||
|
||||
const bonusEl = el.querySelector('#bonusMalusPerso')
|
||||
const diffEl = el.querySelector('#roll-difficulty')
|
||||
const specEl = el.querySelector('#roll-specialization')
|
||||
const traitBonusEl = el.querySelector('#roll-trait-bonus')
|
||||
const traitMalusEl = el.querySelector('#roll-trait-malus')
|
||||
const transcEl = el.querySelector('#roll-select-transcendence')
|
||||
const spleenEl = el.querySelector('#roll-use-spleen')
|
||||
const idealEl = el.querySelector('#roll-use-ideal')
|
||||
|
||||
if (bonusEl) this.rollData.bonusMalusPerso = Number(bonusEl.value)
|
||||
if (diffEl) this.rollData.difficulty = Number(diffEl.value) || 0
|
||||
if (specEl) this.rollData.selectedSpecs = Array.from(specEl.selectedOptions).map(o => o.value)
|
||||
if (traitBonusEl) this.rollData.traitsBonus = Array.from(traitBonusEl.selectedOptions).map(o => o.value)
|
||||
if (traitMalusEl) this.rollData.traitsMalus = Array.from(traitMalusEl.selectedOptions).map(o => o.value)
|
||||
if (transcEl) this.rollData.skillTranscendence = Number(transcEl.value)
|
||||
if (spleenEl) this.rollData.useSpleen = spleenEl.checked
|
||||
if (idealEl) this.rollData.useIdeal = idealEl.checked
|
||||
|
||||
EcrymeUtility.rollEcryme(this.rollData)
|
||||
this.close()
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async refreshDialog() {
|
||||
const content = await renderTemplate("systems/fvtt-ecryme/templates/dialogs/roll-dialog-generic.hbs", this.rollData)
|
||||
this.data.content = content
|
||||
this.render(true)
|
||||
static #onCancel(event, target) {
|
||||
this.close()
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
function onLoad() {
|
||||
}
|
||||
$(function () { onLoad(); });
|
||||
|
||||
html.find('#bonusMalusPerso').change((event) => {
|
||||
console.log("DIFF", event.currentTarget.value)
|
||||
this.rollData.bonusMalusPerso = Number(event.currentTarget.value)
|
||||
})
|
||||
html.find('#roll-difficulty').change((event) => {
|
||||
this.rollData.difficulty = Number(event.currentTarget.value) || 0
|
||||
})
|
||||
html.find('#roll-specialization').change((event) => {
|
||||
this.rollData.selectedSpecs = $('#roll-specialization').val()
|
||||
})
|
||||
html.find('#roll-trait-bonus').change((event) => {
|
||||
this.rollData.traitsBonus = $('#roll-trait-bonus').val()
|
||||
})
|
||||
html.find('#roll-trait-malus').change((event) => {
|
||||
this.rollData.traitsMalus = $('#roll-trait-malus').val()
|
||||
})
|
||||
html.find('#roll-select-transcendence').change((event) => {
|
||||
this.rollData.skillTranscendence = Number($('#roll-select-transcendence').val())
|
||||
})
|
||||
html.find('#roll-use-spleen').change((event) => {
|
||||
this.rollData.useSpleen = event.currentTarget.checked
|
||||
})
|
||||
html.find('#roll-use-ideal').change((event) => {
|
||||
this.rollData.useIdeal = event.currentTarget.checked
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,17 @@ const ECRYME_WELCOME_MESSAGE_URL = "https://www.uberwald.me/gitea/public/fvtt-ec
|
||||
// Import Modules
|
||||
import { EcrymeActor } from "./actors/ecryme-actor.js";
|
||||
import { EcrymeItemSheet } from "./items/ecryme-item-sheet.js";
|
||||
import { EcrymeActorSheet } from "./actors/ecryme-actor-sheet.js";
|
||||
import { EcrymeAnnencySheet } from "./actors/ecryme-annency-sheet.js";
|
||||
import {
|
||||
EcrymeEquipmentSheet,
|
||||
EcrymeWeaponSheet,
|
||||
EcrymeTraitSheet,
|
||||
EcrymeSpecializationSheet,
|
||||
EcrymeManeuverSheet
|
||||
} from "./items/sheets/_module.js";
|
||||
import {
|
||||
EcrymeActorSheet,
|
||||
EcrymeAnnencySheet
|
||||
} from "./actors/sheets/_module.js";
|
||||
import { EcrymeUtility } from "./common/ecryme-utility.js";
|
||||
import { EcrymeCombat } from "./app/ecryme-combat.js";
|
||||
import { EcrymeItem } from "./items/ecryme-item.js";
|
||||
@@ -76,12 +85,16 @@ Hooks.once("init", async function () {
|
||||
/* -------------------------------------------- */
|
||||
// Register sheet application classes
|
||||
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet);
|
||||
foundry.documents.collections.Actors.registerSheet("fvtt-ecryme", EcrymeActorSheet, { types: ["pc"], makeDefault: true });
|
||||
foundry.documents.collections.Actors.registerSheet("fvtt-ecryme", EcrymeActorSheet, { types: ["pc"], makeDefault: true });
|
||||
foundry.documents.collections.Actors.registerSheet("fvtt-ecryme", EcrymeActorSheet, { types: ["npc"], makeDefault: true });
|
||||
foundry.documents.collections.Actors.registerSheet("fvtt-ecryme", EcrymeAnnencySheet, { types: ["annency"], makeDefault: false });
|
||||
foundry.documents.collections.Actors.registerSheet("fvtt-ecryme", EcrymeAnnencySheet, { types: ["annency"], makeDefault: true });
|
||||
|
||||
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet);
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-ecryme", EcrymeItemSheet, { makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-ecryme", EcrymeEquipmentSheet, { types: ["equipment"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-ecryme", EcrymeWeaponSheet, { types: ["weapon"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-ecryme", EcrymeTraitSheet, { types: ["trait"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-ecryme", EcrymeSpecializationSheet, { types: ["specialization"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-ecryme", EcrymeManeuverSheet, { types: ["maneuver"], makeDefault: true });
|
||||
|
||||
EcrymeUtility.init()
|
||||
|
||||
|
||||
6
modules/items/sheets/_module.js
Normal file
6
modules/items/sheets/_module.js
Normal file
@@ -0,0 +1,6 @@
|
||||
export { default as EcrymeBaseItemSheet } from "./base-item-sheet.js"
|
||||
export { default as EcrymeEquipmentSheet } from "./equipment-sheet.js"
|
||||
export { default as EcrymeWeaponSheet } from "./weapon-sheet.js"
|
||||
export { default as EcrymeTraitSheet } from "./trait-sheet.js"
|
||||
export { default as EcrymeSpecializationSheet } from "./specialization-sheet.js"
|
||||
export { default as EcrymeManeuverSheet } from "./maneuver-sheet.js"
|
||||
131
modules/items/sheets/base-item-sheet.js
Normal file
131
modules/items/sheets/base-item-sheet.js
Normal file
@@ -0,0 +1,131 @@
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||
|
||||
/**
|
||||
* Base item sheet for Ecryme using Application V2.
|
||||
* Subclasses must define static PARTS including header, tabs, description, and optionally details.
|
||||
*/
|
||||
export default class EcrymeBaseItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) {
|
||||
|
||||
constructor(options = {}) {
|
||||
super(options)
|
||||
this.#dragDrop = this.#createDragDropHandlers()
|
||||
}
|
||||
|
||||
#dragDrop
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["fvtt-ecryme", "item"],
|
||||
position: {
|
||||
width: 520,
|
||||
height: "auto",
|
||||
},
|
||||
form: {
|
||||
submitOnChange: true,
|
||||
},
|
||||
window: {
|
||||
resizable: true,
|
||||
},
|
||||
dragDrop: [{ dragSelector: "[data-drag]", dropSelector: null }],
|
||||
actions: {
|
||||
editImage: EcrymeBaseItemSheet.#onEditImage,
|
||||
},
|
||||
}
|
||||
|
||||
/** Active tab group tracking */
|
||||
tabGroups = {
|
||||
primary: "description",
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the tabs definition, adding a "details" tab only if the subclass has a "details" PART.
|
||||
* @returns {Record<string, object>}
|
||||
*/
|
||||
_getTabs() {
|
||||
const tabs = {
|
||||
description: { id: "description", group: "primary", label: "ECRY.ui.description" },
|
||||
}
|
||||
if (this.constructor.PARTS?.details) {
|
||||
tabs.details = { id: "details", group: "primary", label: "ECRY.ui.details" }
|
||||
}
|
||||
for (const tab of Object.values(tabs)) {
|
||||
tab.active = this.tabGroups[tab.group] === tab.id
|
||||
tab.cssClass = tab.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @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(),
|
||||
config: game.system.ecryme.config,
|
||||
isEditable: this.isEditable,
|
||||
tabs: this._getTabs(),
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _preparePartContext(partId, context) {
|
||||
context = await super._preparePartContext(partId, context)
|
||||
if (partId === "description") {
|
||||
context.tab = context.tabs.description
|
||||
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||
this.document.system.description, { async: true }
|
||||
)
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_onRender(context, options) {
|
||||
this.#dragDrop.forEach((d) => d.bind(this.element))
|
||||
}
|
||||
|
||||
// #region Drag-and-Drop
|
||||
#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 foundry.applications.ux.DragDrop.implementation(d)
|
||||
})
|
||||
}
|
||||
|
||||
_canDragStart(selector) { return this.isEditable }
|
||||
_canDragDrop(selector) { return this.isEditable && this.document.isOwner }
|
||||
_onDragStart(event) {}
|
||||
_onDragOver(event) {}
|
||||
async _onDrop(event) {}
|
||||
// #endregion
|
||||
|
||||
// #region Actions
|
||||
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
|
||||
}
|
||||
24
modules/items/sheets/equipment-sheet.js
Normal file
24
modules/items/sheets/equipment-sheet.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import EcrymeBaseItemSheet from "./base-item-sheet.js"
|
||||
|
||||
export default class EcrymeEquipmentSheet extends EcrymeBaseItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["equipment"],
|
||||
position: { width: 520 },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
header: { template: "systems/fvtt-ecryme/templates/items/partials/item-header.hbs" },
|
||||
tabs: { template: "templates/generic/tab-navigation.hbs" },
|
||||
description: { template: "systems/fvtt-ecryme/templates/items/partials/item-description.hbs" },
|
||||
details: { template: "systems/fvtt-ecryme/templates/items/item-equipment-details.hbs" },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _preparePartContext(partId, context) {
|
||||
context = await super._preparePartContext(partId, context)
|
||||
if (partId === "details") context.tab = context.tabs.details
|
||||
return context
|
||||
}
|
||||
}
|
||||
24
modules/items/sheets/maneuver-sheet.js
Normal file
24
modules/items/sheets/maneuver-sheet.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import EcrymeBaseItemSheet from "./base-item-sheet.js"
|
||||
|
||||
export default class EcrymeManeuverSheet extends EcrymeBaseItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["maneuver"],
|
||||
position: { width: 520 },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
header: { template: "systems/fvtt-ecryme/templates/items/partials/item-header.hbs" },
|
||||
tabs: { template: "templates/generic/tab-navigation.hbs" },
|
||||
description: { template: "systems/fvtt-ecryme/templates/items/partials/item-description.hbs" },
|
||||
details: { template: "systems/fvtt-ecryme/templates/items/item-maneuver-details.hbs" },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _preparePartContext(partId, context) {
|
||||
context = await super._preparePartContext(partId, context)
|
||||
if (partId === "details") context.tab = context.tabs.details
|
||||
return context
|
||||
}
|
||||
}
|
||||
24
modules/items/sheets/specialization-sheet.js
Normal file
24
modules/items/sheets/specialization-sheet.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import EcrymeBaseItemSheet from "./base-item-sheet.js"
|
||||
|
||||
export default class EcrymeSpecializationSheet extends EcrymeBaseItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["specialization"],
|
||||
position: { width: 520 },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
header: { template: "systems/fvtt-ecryme/templates/items/partials/item-header.hbs" },
|
||||
tabs: { template: "templates/generic/tab-navigation.hbs" },
|
||||
description: { template: "systems/fvtt-ecryme/templates/items/partials/item-description.hbs" },
|
||||
details: { template: "systems/fvtt-ecryme/templates/items/item-specialization-details.hbs" },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _preparePartContext(partId, context) {
|
||||
context = await super._preparePartContext(partId, context)
|
||||
if (partId === "details") context.tab = context.tabs.details
|
||||
return context
|
||||
}
|
||||
}
|
||||
24
modules/items/sheets/trait-sheet.js
Normal file
24
modules/items/sheets/trait-sheet.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import EcrymeBaseItemSheet from "./base-item-sheet.js"
|
||||
|
||||
export default class EcrymeTraitSheet extends EcrymeBaseItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["trait"],
|
||||
position: { width: 520 },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
header: { template: "systems/fvtt-ecryme/templates/items/partials/item-header.hbs" },
|
||||
tabs: { template: "templates/generic/tab-navigation.hbs" },
|
||||
description: { template: "systems/fvtt-ecryme/templates/items/partials/item-description.hbs" },
|
||||
details: { template: "systems/fvtt-ecryme/templates/items/item-trait-details.hbs" },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _preparePartContext(partId, context) {
|
||||
context = await super._preparePartContext(partId, context)
|
||||
if (partId === "details") context.tab = context.tabs.details
|
||||
return context
|
||||
}
|
||||
}
|
||||
24
modules/items/sheets/weapon-sheet.js
Normal file
24
modules/items/sheets/weapon-sheet.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import EcrymeBaseItemSheet from "./base-item-sheet.js"
|
||||
|
||||
export default class EcrymeWeaponSheet extends EcrymeBaseItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["weapon"],
|
||||
position: { width: 540 },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
header: { template: "systems/fvtt-ecryme/templates/items/partials/item-header.hbs" },
|
||||
tabs: { template: "templates/generic/tab-navigation.hbs" },
|
||||
description: { template: "systems/fvtt-ecryme/templates/items/partials/item-description.hbs" },
|
||||
details: { template: "systems/fvtt-ecryme/templates/items/item-weapon-details.hbs" },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _preparePartContext(partId, context) {
|
||||
context = await super._preparePartContext(partId, context)
|
||||
if (partId === "details") context.tab = context.tabs.details
|
||||
return context
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user