Make the system use Proxy and proper subclassing instead of the weird middle-ground polymorphism (closes #86)
This commit is contained in:
parent
745824f6cc
commit
cd98e66484
17 changed files with 322 additions and 351 deletions
|
|
@ -51,6 +51,9 @@
|
||||||
"skill-roll-locked": "@dotdungeon.trainingLevel.locked"
|
"skill-roll-locked": "@dotdungeon.trainingLevel.locked"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"name": "(Unnamed @TYPES.{document}.{type})"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"TYPES": {
|
"TYPES": {
|
||||||
|
|
@ -67,7 +70,7 @@
|
||||||
"pet": "Pet",
|
"pet": "Pet",
|
||||||
"structure": "Structure",
|
"structure": "Structure",
|
||||||
"service": "Service",
|
"service": "Service",
|
||||||
"materials": "Materials",
|
"material": "Materials",
|
||||||
"legendaryItem": "Legendary Item",
|
"legendaryItem": "Legendary Item",
|
||||||
"spell": "Spell",
|
"spell": "Spell",
|
||||||
"untyped": "Custom"
|
"untyped": "Custom"
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ export const localizerConfig = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const itemFilters = [
|
export const itemFilters = [
|
||||||
`materials`,
|
`material`,
|
||||||
`untyped`,
|
`untyped`,
|
||||||
`aspect`,
|
`aspect`,
|
||||||
`weapon`,
|
`weapon`,
|
||||||
|
|
|
||||||
102
module/documents/Actor/GenericActor.mjs
Normal file
102
module/documents/Actor/GenericActor.mjs
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
import { localizer } from "../../utils/localizer.mjs";
|
||||||
|
|
||||||
|
export class DotDungeonActor extends Actor {
|
||||||
|
/** @type {any} */
|
||||||
|
system;
|
||||||
|
|
||||||
|
async openEmbeddedSheet($event) {
|
||||||
|
const data = $event.target.dataset;
|
||||||
|
let item = await fromUuid(data.embeddedEdit);
|
||||||
|
item?.sheet.render(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
async createEmbeddedItem(defaults, opts = {}) {
|
||||||
|
let items = await this.createEmbeddedDocuments(`Item`, defaults);
|
||||||
|
if (items.length == 0) {
|
||||||
|
throw new Error(`Failed to create any items`);
|
||||||
|
};
|
||||||
|
this.sheet.render();
|
||||||
|
if (
|
||||||
|
game.settings.get(`dotdungeon`, `openEmbeddedOnCreate`)
|
||||||
|
&& !opts.overrideSheetOpen
|
||||||
|
) {
|
||||||
|
for (const item of items) {
|
||||||
|
item.sheet.render(true);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
async genericEmbeddedCreate($event) {
|
||||||
|
const data = $event.currentTarget.dataset;
|
||||||
|
if (!this[`createCustom${data.embeddedCreate}`]) {
|
||||||
|
this.createEmbeddedItem({
|
||||||
|
type: data.embeddedCreate,
|
||||||
|
name: localizer(
|
||||||
|
`dotdungeon.default.name`,
|
||||||
|
{ document: `Actor`, type: data.embeddedCreate }
|
||||||
|
),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this[`createCustom${data.embeddedCreate}`]($event);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
async genericEmbeddedUpdate($event) {
|
||||||
|
const target = $event.delegateTarget;
|
||||||
|
const data = target.dataset;
|
||||||
|
const item = await fromUuid(data.embeddedId);
|
||||||
|
|
||||||
|
let value = target.value;
|
||||||
|
switch (target.type) {
|
||||||
|
case "checkbox": value = target.checked; break;
|
||||||
|
};
|
||||||
|
|
||||||
|
await item?.update({ [data.embeddedUpdate]: value });
|
||||||
|
};
|
||||||
|
|
||||||
|
async genericEmbeddedDelete($event) {
|
||||||
|
let data = $event.currentTarget.dataset;
|
||||||
|
let item = await fromUuid(data.embeddedId);
|
||||||
|
|
||||||
|
if (!item) {
|
||||||
|
ui.notifications.error(
|
||||||
|
`dotdungeon.notification.error.item-not-found`,
|
||||||
|
{ console: false }
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
Dialog.confirm({
|
||||||
|
title: game.i18n.format(
|
||||||
|
`dotdungeon.dialogs.${item.type}.delete.title`,
|
||||||
|
item
|
||||||
|
),
|
||||||
|
content: game.i18n.format(
|
||||||
|
`dotdungeon.dialogs.${item.type}.delete.content`,
|
||||||
|
item
|
||||||
|
),
|
||||||
|
yes: () => {
|
||||||
|
item.delete();
|
||||||
|
},
|
||||||
|
defaultYes: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
async genericSendToChat($event) {
|
||||||
|
const data = $event.currentTarget.dataset;
|
||||||
|
const type = data.messageType;
|
||||||
|
if (this[`send${type}ToChat`]) {
|
||||||
|
return await this[`send${type}ToChat`]($event);
|
||||||
|
};
|
||||||
|
if (!data.messageContent) {
|
||||||
|
console.warn(`.dungeon | Tried to send a chat message with no content`);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let message = await ChatMessage.create({
|
||||||
|
content: data.messageContent,
|
||||||
|
flavor: data.messageFlavor,
|
||||||
|
speaker: { actor: this.actor },
|
||||||
|
});
|
||||||
|
message.render();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -1,104 +0,0 @@
|
||||||
import PlayerActor from "./Player.mjs";
|
|
||||||
import MobActor from "./Mob.mjs";
|
|
||||||
import SyncActor from "./Sync.mjs";
|
|
||||||
|
|
||||||
/** @extends {Actor} */
|
|
||||||
export class ActorHandler extends Actor {
|
|
||||||
proxyTargets = {
|
|
||||||
player: PlayerActor,
|
|
||||||
mob: MobActor,
|
|
||||||
sync: SyncActor,
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(data, ctx) {
|
|
||||||
super(data, ctx);
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @type {class|undefined} */
|
|
||||||
get fn() {
|
|
||||||
return this.proxyTargets[this.type];
|
|
||||||
};
|
|
||||||
|
|
||||||
async proxyFunction(funcName, ...args) {
|
|
||||||
if (!this.fn?.[funcName]) return;
|
|
||||||
return await this.fn?.[funcName].bind(this)(...args);
|
|
||||||
};
|
|
||||||
|
|
||||||
async openEmbeddedSheet($event) {
|
|
||||||
if (this.fn?.openEmbeddedSheet) {
|
|
||||||
this.fn.openEmbeddedSheet.bind(this)($event);
|
|
||||||
} else {
|
|
||||||
const data = $event.target.dataset;
|
|
||||||
let item = await fromUuid(data.embeddedEdit);
|
|
||||||
item?.sheet.render(true);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
async genericEmbeddedUpdate($event) {
|
|
||||||
if (this.fn?.genericEmbeddedUpdate) {
|
|
||||||
return this.fn.genericEmbeddedUpdate.bind(this)($event);
|
|
||||||
};
|
|
||||||
const target = $event.delegateTarget;
|
|
||||||
const data = target.dataset;
|
|
||||||
const item = await fromUuid(data.embeddedId);
|
|
||||||
|
|
||||||
let value = target.value;
|
|
||||||
switch (target.type) {
|
|
||||||
case "checkbox": value = target.checked; break;
|
|
||||||
};
|
|
||||||
|
|
||||||
await item?.update({ [data.embeddedUpdate]: value });
|
|
||||||
};
|
|
||||||
|
|
||||||
async genericEmbeddedDelete($event) {
|
|
||||||
if (!this.fn?.genericEmbeddedDelete) return;
|
|
||||||
this.fn.genericEmbeddedDelete.bind(this)($event);
|
|
||||||
};
|
|
||||||
|
|
||||||
async genericEmbeddedCreate($event) {
|
|
||||||
const data = $event.currentTarget.dataset;
|
|
||||||
if (!this.fn?.[`createCustom${data.embeddedCreate}`]) return;
|
|
||||||
this.fn?.[`createCustom${data.embeddedCreate}`].bind(this)($event);
|
|
||||||
};
|
|
||||||
|
|
||||||
async genericSendToChat($event) {
|
|
||||||
const data = $event.currentTarget.dataset;
|
|
||||||
const type = data.messageType;
|
|
||||||
if (this.fn?.[`send${type}ToChat`]) {
|
|
||||||
return await this.fn?.[`send${type}ToChat`].bind(this)($event);
|
|
||||||
};
|
|
||||||
if (!data.messageContent) {
|
|
||||||
console.warn(`.dungeon | Tried to send a chat message with no content`);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let message = await ChatMessage.create({
|
|
||||||
content: data.messageContent,
|
|
||||||
flavor: data.messageFlavor,
|
|
||||||
speaker: { actor: this.actor }
|
|
||||||
});
|
|
||||||
message.render();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {ItemHandler} item
|
|
||||||
* @returns {boolean} true to allow the document to be embedded
|
|
||||||
*/
|
|
||||||
async preItemEmbed(item) {
|
|
||||||
let type = item.type[0].toUpperCase() + item.type.slice(1);
|
|
||||||
if (this.fn?.[`pre${type}Embed`]) {
|
|
||||||
return await this.fn?.[`pre${type}Embed`].bind(this)(item);
|
|
||||||
};
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
_preUpdate(...args) {
|
|
||||||
return this.proxyFunction("_preUpdate", ...args);
|
|
||||||
};
|
|
||||||
|
|
||||||
getRollData() {
|
|
||||||
if (!this.fn?.getRollData) return {};
|
|
||||||
return this.fn?.getRollData.bind(this)();
|
|
||||||
};
|
|
||||||
|
|
||||||
useRestDie() {return this.proxyFunction("useRestDie")};
|
|
||||||
};
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
/** @this {Actor} */
|
import { DotDungeonActor } from "./GenericActor.mjs";
|
||||||
function getRollData() {
|
|
||||||
|
export class Mob extends DotDungeonActor {
|
||||||
|
getRollData() {
|
||||||
const data = {
|
const data = {
|
||||||
initiative: this.system.initiative ?? 0,
|
initiative: this.system.initiative ?? 0,
|
||||||
};
|
};
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
|
||||||
getRollData,
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,82 +1,14 @@
|
||||||
import { ItemHandler } from "../Item/Handler.mjs";
|
import { DotDungeonActor } from "./GenericActor.mjs";
|
||||||
|
import { DotDungeonItem } from "../Item/GenericItem.mjs";
|
||||||
|
|
||||||
/** @this {Actor} */
|
export class Player extends DotDungeonActor {
|
||||||
async function genericEmbeddedDelete($event) {
|
|
||||||
let data = $event.currentTarget.dataset;
|
|
||||||
let item = await fromUuid(data.embeddedId);
|
|
||||||
|
|
||||||
if (!item) {
|
async createCustomPet() {
|
||||||
ui.notifications.error(
|
|
||||||
`dotdungeon.notification.error.item-not-found`,
|
|
||||||
{ console: false }
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
Dialog.confirm({
|
|
||||||
title: game.i18n.format(
|
|
||||||
`dotdungeon.dialogs.${item.type}.delete.title`,
|
|
||||||
item
|
|
||||||
),
|
|
||||||
content: game.i18n.format(
|
|
||||||
`dotdungeon.dialogs.${item.type}.delete.content`,
|
|
||||||
item
|
|
||||||
),
|
|
||||||
yes: () => {
|
|
||||||
item.delete();
|
|
||||||
},
|
|
||||||
defaultYes: false,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @this {Actor} */
|
|
||||||
async function createCustomItem(defaults, opts = {}) {
|
|
||||||
let items = await this.createEmbeddedDocuments(`Item`, defaults);
|
|
||||||
if (items.length == 0) {
|
|
||||||
throw new Error();
|
|
||||||
};
|
|
||||||
this.sheet.render();
|
|
||||||
if (
|
|
||||||
game.settings.get(`dotdungeon`, `openEmbeddedOnCreate`)
|
|
||||||
&& !opts.overrideSheetOpen
|
|
||||||
) {
|
|
||||||
for (const item of items) {
|
|
||||||
item.sheet.render(true);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @this {Actor} */
|
|
||||||
async function createCustomUntyped() {
|
|
||||||
await createCustomItem.bind(this)([{
|
|
||||||
type: `untyped`,
|
|
||||||
name: game.i18n.format(`dotdungeon.defaults.untyped.name`),
|
|
||||||
}]);
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @this {Actor} */
|
|
||||||
async function createCustomAspect() {
|
|
||||||
await createCustomItem.bind(this)([{
|
|
||||||
type: `aspect`,
|
|
||||||
name: game.i18n.format(`dotdungeon.defaults.aspect.name`),
|
|
||||||
}]);
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @this {Actor} */
|
|
||||||
async function createCustomSpell() {
|
|
||||||
await createCustomItem.bind(this)([{
|
|
||||||
type: `spell`,
|
|
||||||
name: game.i18n.format(`dotdungeon.defaults.spell.name`),
|
|
||||||
}]);
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @this {Actor} */
|
|
||||||
async function createCustomPet() {
|
|
||||||
const body = new URLSearchParams({
|
const body = new URLSearchParams({
|
||||||
number: 1,
|
number: 1,
|
||||||
animal: `Cat`,
|
animal: `Cat`,
|
||||||
"X-Requested-With": "fetch"
|
"X-Requested-With": "fetch"
|
||||||
})
|
});
|
||||||
const r = await fetch(
|
const r = await fetch(
|
||||||
`https://randommer.io/pet-names`,
|
`https://randommer.io/pet-names`,
|
||||||
{
|
{
|
||||||
|
|
@ -84,24 +16,19 @@ async function createCustomPet() {
|
||||||
body
|
body
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
await createCustomItem.bind(this)([{
|
await this.createEmbeddedItem([{
|
||||||
type: `pet`,
|
type: `pet`,
|
||||||
name: (await r.json())[0] ?? game.i18n.localize(`dotdungeon.defaults.pet.name`),
|
name: (await r.json())[0] ?? game.i18n.localize(`dotdungeon.defaults.pet.name`),
|
||||||
}]);
|
}]);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @this {Actor} */
|
get atAspectLimit() {
|
||||||
async function atAspectLimit() {
|
|
||||||
let limit = game.settings.get(`dotdungeon`, `aspectLimit`);
|
let limit = game.settings.get(`dotdungeon`, `aspectLimit`);
|
||||||
return this.itemTypes.aspect.length >= limit;
|
return this.itemTypes.aspect.length >= limit;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
async preAspectEmbed(item) {
|
||||||
* @param {ItemHandler} item
|
if (this.atAspectLimit) {
|
||||||
* @this {Actor}
|
|
||||||
*/
|
|
||||||
async function preAspectEmbed(item) {
|
|
||||||
if (await atAspectLimit.bind(this)()) {
|
|
||||||
ui.notifications.error(
|
ui.notifications.error(
|
||||||
game.i18n.format(
|
game.i18n.format(
|
||||||
`dotdungeon.notification.error.aspect-limit-reached`,
|
`dotdungeon.notification.error.aspect-limit-reached`,
|
||||||
|
|
@ -114,10 +41,9 @@ async function preAspectEmbed(item) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ItemHandler} item
|
* @param {DotDungeonItem} item
|
||||||
* @this {Actor}
|
|
||||||
*/
|
*/
|
||||||
async function preUntypedEmbed(item) {
|
async preUntypedEmbed(item) {
|
||||||
let inventoryItem = this.itemTypes.untyped.find(i => i.name === item.name);
|
let inventoryItem = this.itemTypes.untyped.find(i => i.name === item.name);
|
||||||
if (inventoryItem) {
|
if (inventoryItem) {
|
||||||
inventoryItem.update({"system.quantity": inventoryItem.system.quantity + 1});
|
inventoryItem.update({"system.quantity": inventoryItem.system.quantity + 1});
|
||||||
|
|
@ -132,24 +58,11 @@ async function preUntypedEmbed(item) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @this {Actor} */
|
getRollData() {
|
||||||
function getRollData() {
|
|
||||||
const data = {
|
const data = {
|
||||||
initiative: this.system.stats.hands ?? 0,
|
initiative: this.system.stats.hands ?? 0,
|
||||||
stats: this.system.stats,
|
stats: this.system.stats,
|
||||||
};
|
};
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
|
||||||
atAspectLimit,
|
|
||||||
createCustomItem,
|
|
||||||
createCustomUntyped,
|
|
||||||
createCustomAspect,
|
|
||||||
createCustomSpell,
|
|
||||||
createCustomPet,
|
|
||||||
genericEmbeddedDelete,
|
|
||||||
preAspectEmbed,
|
|
||||||
preUntypedEmbed,
|
|
||||||
getRollData,
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { syncMilestones, syncDice } from "../../config.mjs";
|
import { DotDungeonActor } from "./GenericActor.mjs";
|
||||||
|
|
||||||
/** @this {Actor} */
|
export class Sync extends DotDungeonActor {
|
||||||
async function useRestDie() {
|
async useRestDie() {
|
||||||
let addToSync = await (new Roll(syncDice)).evaluate();
|
let addToSync = await (new Roll(syncDice)).evaluate();
|
||||||
await addToSync.toMessage({
|
await addToSync.toMessage({
|
||||||
speaker: ChatMessage.getSpeaker({ actor: this.actor }),
|
speaker: ChatMessage.getSpeaker({ actor: this.actor }),
|
||||||
|
|
@ -13,8 +13,7 @@ async function useRestDie() {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @this {Actor} */
|
async _preUpdate(data, options) {
|
||||||
async function _preUpdate(data, options) {
|
|
||||||
if (options.diff) {
|
if (options.diff) {
|
||||||
if (data.system?.value != null) {
|
if (data.system?.value != null) {
|
||||||
let currentSync = this.system.value;
|
let currentSync = this.system.value;
|
||||||
|
|
@ -53,8 +52,4 @@ async function _preUpdate(data, options) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
|
||||||
_preUpdate,
|
|
||||||
useRestDie,
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
46
module/documents/Actor/_proxy.mjs
Normal file
46
module/documents/Actor/_proxy.mjs
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { DotDungeonActor } from "./GenericActor.mjs";
|
||||||
|
import { Player } from "./Player.mjs";
|
||||||
|
import { Sync } from "./Sync.mjs";
|
||||||
|
import { Mob } from "./Mob.mjs";
|
||||||
|
|
||||||
|
const classes = {
|
||||||
|
player: Player,
|
||||||
|
mob: Mob,
|
||||||
|
sync: Sync,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ActorProxy = new Proxy(function () {}, {
|
||||||
|
construct(target, args) {
|
||||||
|
const [data] = args;
|
||||||
|
|
||||||
|
if (!classes.hasOwnProperty(data.type)) {
|
||||||
|
return new DotDungeonActor(...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new classes[data.type](...args);
|
||||||
|
},
|
||||||
|
get(target, prop, receiver) {
|
||||||
|
console.log(prop)
|
||||||
|
if (["create", "createDocuments"].includes(prop)) {
|
||||||
|
return function (data, options) {
|
||||||
|
if (data.constructor === Array) {
|
||||||
|
return data.map(i => ItemProxy.create(i, options))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!classes.hasOwnProperty(data.type)) {
|
||||||
|
return DotDungeonActor.create(data, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
return classes[data.type].create(data, options)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
if (prop == Symbol.hasInstance) {
|
||||||
|
return function (instance) {
|
||||||
|
return Object.values(classes).some(i => instance instanceof i)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return DotDungeonActor[prop];
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
/** @this {ItemHandler} */
|
import { DotDungeonItem } from "./GenericItem.mjs";
|
||||||
async function _preCreate(_data, _options, _user) {
|
|
||||||
|
export class Aspect extends DotDungeonItem {
|
||||||
|
async _preCreate() {
|
||||||
if (this.isEmbedded) {
|
if (this.isEmbedded) {
|
||||||
return await this.actor?.preItemEmbed(this);
|
return await this.actor?.preItemEmbed(this);
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
export default {
|
|
||||||
_preCreate,
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
1
module/documents/Item/GenericItem.mjs
Normal file
1
module/documents/Item/GenericItem.mjs
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export class DotDungeonItem extends Item {};
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
import AspectItem from "./Aspect.mjs";
|
|
||||||
import SpellItem from "./Spell.mjs";
|
|
||||||
|
|
||||||
/** @extends {Item} */
|
|
||||||
export class ItemHandler extends Item {
|
|
||||||
proxyTargets = {
|
|
||||||
aspect: AspectItem,
|
|
||||||
spell: SpellItem,
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(data, ctx) {
|
|
||||||
super(data, ctx);
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @type {class|undefined} */
|
|
||||||
get fn() {
|
|
||||||
return this.proxyTargets[this.type];
|
|
||||||
};
|
|
||||||
|
|
||||||
async proxyFunction(funcName, ...args) {
|
|
||||||
if (!this.fn?.[funcName]) return;
|
|
||||||
return await this.fn?.[funcName].bind(this)(...args);
|
|
||||||
};
|
|
||||||
|
|
||||||
async _preCreate(...args) {
|
|
||||||
if (this.fn?._preCreate) return this.fn?._preCreate.bind(this)(...args);
|
|
||||||
if (this.isEmbedded) return await this.actor?.preItemEmbed(this);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export default {};
|
|
||||||
42
module/documents/Item/_proxy.mjs
Normal file
42
module/documents/Item/_proxy.mjs
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
import { Aspect } from "./Aspect.mjs";
|
||||||
|
import { DotDungeonItem } from "./GenericItem.mjs";
|
||||||
|
|
||||||
|
const classes = {
|
||||||
|
aspect: Aspect,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ItemProxy = new Proxy(function () {}, {
|
||||||
|
construct(target, args) {
|
||||||
|
const [data] = args;
|
||||||
|
|
||||||
|
if (!classes.hasOwnProperty(data.type)) {
|
||||||
|
return new DotDungeonItem(...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new classes[data.type](...args);
|
||||||
|
},
|
||||||
|
get(target, prop, receiver) {
|
||||||
|
console.log(prop)
|
||||||
|
if (["create", "createDocuments"].includes(prop)) {
|
||||||
|
return function (data, options) {
|
||||||
|
if (data.constructor === Array) {
|
||||||
|
return data.map(i => ItemProxy.create(i, options))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!classes.hasOwnProperty(data.type)) {
|
||||||
|
return DotDungeonItem.create(data, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
return classes[data.type].create(data, options)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
if (prop == Symbol.hasInstance) {
|
||||||
|
return function (instance) {
|
||||||
|
return Object.values(classes).some(i => instance instanceof i)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return DotDungeonItem[prop];
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
@ -8,8 +8,8 @@ import { SyncData } from "./models/Actor/Sync.mjs";
|
||||||
import { MobData } from "./models/Actor/Mob.mjs";
|
import { MobData } from "./models/Actor/Mob.mjs";
|
||||||
|
|
||||||
// Main Documents
|
// Main Documents
|
||||||
import { ActorHandler } from "./documents/Actor/Handler.mjs";
|
import { ActorProxy } from "./documents/Actor/_proxy.mjs";
|
||||||
import { ItemHandler } from "./documents/Item/Handler.mjs";
|
import { ItemProxy } from "./documents/Item/_proxy.mjs";
|
||||||
|
|
||||||
// Item Sheets
|
// Item Sheets
|
||||||
import { UntypedItemSheet } from "./sheets/Items/UntypedItemSheet.mjs";
|
import { UntypedItemSheet } from "./sheets/Items/UntypedItemSheet.mjs";
|
||||||
|
|
@ -46,8 +46,8 @@ Hooks.once(`init`, async () => {
|
||||||
CONFIG.Item.dataModels.aspect = AspectItemData;
|
CONFIG.Item.dataModels.aspect = AspectItemData;
|
||||||
CONFIG.Item.dataModels.spell = SpellItemData;
|
CONFIG.Item.dataModels.spell = SpellItemData;
|
||||||
CONFIG.Item.dataModels.pet = PetItemData;
|
CONFIG.Item.dataModels.pet = PetItemData;
|
||||||
CONFIG.Actor.documentClass = ActorHandler;
|
CONFIG.Actor.documentClass = ActorProxy;
|
||||||
CONFIG.Item.documentClass = ItemHandler;
|
CONFIG.Item.documentClass = ItemProxy;
|
||||||
|
|
||||||
CONFIG.DOTDUNGEON = DOTDUNGEON;
|
CONFIG.DOTDUNGEON = DOTDUNGEON;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,13 @@ import { GenericActorSheet } from "../../GenericActorSheet.mjs";
|
||||||
import DOTDUNGEON from "../../../config.mjs";
|
import DOTDUNGEON from "../../../config.mjs";
|
||||||
import { localizer } from "../../../utils/localizer.mjs";
|
import { localizer } from "../../../utils/localizer.mjs";
|
||||||
import { modifierToString } from "../../../utils/modifierToString.mjs";
|
import { modifierToString } from "../../../utils/modifierToString.mjs";
|
||||||
|
import { Player } from "../../../documents/Actor2/Player.mjs";
|
||||||
|
|
||||||
export class PlayerSheetv2 extends GenericActorSheet {
|
export class PlayerSheetv2 extends GenericActorSheet {
|
||||||
|
|
||||||
|
/** @type {Player | null} */
|
||||||
|
actor;
|
||||||
|
|
||||||
static get defaultOptions() {
|
static get defaultOptions() {
|
||||||
let opts = mergeObject(
|
let opts = mergeObject(
|
||||||
super.defaultOptions,
|
super.defaultOptions,
|
||||||
|
|
@ -61,7 +66,7 @@ export class PlayerSheetv2 extends GenericActorSheet {
|
||||||
|
|
||||||
ctx.computed = {
|
ctx.computed = {
|
||||||
canChangeGroup: ctx.settings.playersCanChangeGroup || ctx.isGM,
|
canChangeGroup: ctx.settings.playersCanChangeGroup || ctx.isGM,
|
||||||
canAddAspect: !await actor.proxyFunction.bind(actor)(`atAspectLimit`),
|
canAddAspect: !this.actor.atAspectLimit,
|
||||||
stats: this.#statData,
|
stats: this.#statData,
|
||||||
itemFilters: this.#itemFilters,
|
itemFilters: this.#itemFilters,
|
||||||
noItemTypesVisible: this._itemTypesHidden.size === DOTDUNGEON.itemFilters.length,
|
noItemTypesVisible: this._itemTypesHidden.size === DOTDUNGEON.itemFilters.length,
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ export class MVPPCSheet extends GenericActorSheet {
|
||||||
|
|
||||||
ctx.computed = {
|
ctx.computed = {
|
||||||
canChangeGroup: ctx.settings.playersCanChangeGroup || ctx.isGM,
|
canChangeGroup: ctx.settings.playersCanChangeGroup || ctx.isGM,
|
||||||
canAddAspect: !await actor.proxyFunction.bind(actor)(`atAspectLimit`),
|
canAddAspect: !this.actor.atAspectLimit,
|
||||||
};
|
};
|
||||||
|
|
||||||
return ctx;
|
return ctx;
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
"Item": {
|
"Item": {
|
||||||
"types": [
|
"types": [
|
||||||
"untyped",
|
"untyped",
|
||||||
|
"material",
|
||||||
"aspect",
|
"aspect",
|
||||||
"weapon",
|
"weapon",
|
||||||
"armour",
|
"armour",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue