More WIP on 0.8.x migration

This commit is contained in:
Johannes Loher 2021-06-30 03:53:52 +02:00
parent ef01698178
commit 6b39284164
16 changed files with 427 additions and 321 deletions

View file

@ -5,12 +5,18 @@
import { ModifiableDataBaseTotal } from "../common/common-data";
import { DS4 } from "../config";
import { DS4Item } from "../item/item";
import { ItemType } from "../item/item-data";
import { DS4ArmorPreparedData, DS4ShieldPreparedData } from "../item/item-prepared-data";
import { ItemType } from "../item/item-data-source";
import { DS4ArmorDataProperties, DS4ShieldDataProperties } from "../item/item-data-properties";
import { createCheckRoll } from "../rolls/check-factory";
import { isAttribute, isTrait } from "./actor-data-source";
import { Check } from "./actor-data-properties";
import { DS4Item } from "../item/item";
declare global {
interface DocumentClassConfig {
Actor: typeof DS4Actor;
}
}
/**
* The Actor class for DS4
@ -84,9 +90,9 @@ export class DS4Actor extends Actor {
(changes: (foundry.data.ActiveEffectData["changes"][number] & { effect: ActiveEffect })[], e) => {
if (e.data.disabled) return changes;
const item = this.getOriginatingItemOfActiveEffect(e);
if (item?.isNonEquippedEuipable()) return changes; // TODO: DS4Item
if (item?.isNonEquippedEuipable()) return changes;
const factor = item?.activeEffectFactor ?? 1; // TODO: DS4Item
const factor = item?.activeEffectFactor ?? 1;
const newChanges = e.data.changes.filter(predicate).flatMap((c) => {
const changeSource = c.toObject();
@ -110,8 +116,7 @@ export class DS4Actor extends Actor {
this.overrides = expandObject({ ...flattenObject(this.overrides), ...overrides });
}
// TODO: returns DS4Item | undefined
protected getOriginatingItemOfActiveEffect(effect: ActiveEffect): Item | undefined {
protected getOriginatingItemOfActiveEffect(effect: ActiveEffect): DS4Item | undefined {
return this.items.find((item) => item.uuid === effect.data.origin);
}
@ -272,7 +277,6 @@ export class DS4Actor extends Actor {
* Handle how changes to a Token attribute bar are applied to the Actor.
* This only differs from the base implementation by also allowing negative values.
* @override
* TODO: Adjust return type
*/
async modifyTokenAttribute(
attribute: string,

View file

@ -9,7 +9,7 @@ import { ModifiableDataBaseTotal } from "../../common/common-data";
import { DS4 } from "../../config";
import { getCanvas } from "../../helpers";
import { DS4Item } from "../../item/item";
import { DS4ItemData } from "../../item/item-data";
import { DS4ItemData } from "../../item/item-data-source";
import { getDS4Settings } from "../../settings";
import notifications from "../../ui/notifications";
import { DS4Actor } from "../actor";
@ -18,13 +18,13 @@ import { isCheck } from "../actor-data-properties";
/**
* The base Sheet class for all DS4 Actors
*/
export class DS4ActorSheet extends ActorSheet<ActorSheet.Data<DS4Actor>> {
// TODO(types): Improve mergeObject in upstream so that it isn't necessary to provide all parameters (see https://github.com/League-of-Foundry-Developers/foundry-vtt-types/issues/272)
export class DS4ActorSheet extends ActorSheet<ActorSheet.Options> {
/** @override */
static get defaultOptions(): BaseEntitySheet.Options {
const superDefaultOptions = super.defaultOptions;
return mergeObject(superDefaultOptions, {
...superDefaultOptions,
static get defaultOptions(): ActorSheet.Options {
// TODO: Improve
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["ds4", "sheet", "actor"],
height: 620,
scrollY: [
@ -105,7 +105,7 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Data<DS4Actor>> {
html.find(".item-edit").on("click", (ev) => {
const li = $(ev.currentTarget).parents(".item");
const id = li.data("itemId");
const item = this.actor.getOwnedItem(id);
const item = this.actor.getEmbeddedDocument("Item", id) as DS4Item; // TODO: Improve in upstream
if (!item) {
throw new Error(game.i18n.format("DS4.ErrorActorDoesNotHaveItem", { id, actor: this.actor.name }));
}
@ -118,7 +118,7 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Data<DS4Actor>> {
// Delete Inventory Item
html.find(".item-delete").on("click", (ev) => {
const li = $(ev.currentTarget).parents(".item");
this.actor.deleteOwnedItem(li.data("itemId"));
this.actor.deleteEmbeddedDocuments("Item", [li.data("itemId")]);
li.slideUp(200, () => this.render(false));
});
@ -133,23 +133,21 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Data<DS4Actor>> {
* Handle creating a new Owned Item for the actor using initial data defined in the HTML dataset
* @param event - The originating click event
*/
protected _onItemCreate(event: JQuery.ClickEvent): Promise<DS4ItemData> {
protected _onItemCreate(event: JQuery.ClickEvent): void {
event.preventDefault();
const header = event.currentTarget;
// Get the type of item to create.
// Grab any data associated with this control.
const { type, ...data } = duplicate(header.dataset);
// Initialize a default name.
const name = `New ${type.capitalize()}`;
// Prepare the item object.
const itemData = {
name: name,
type: type,
data: data,
};
// Finally, create the item!
return this.actor.createOwnedItem(itemData);
DS4Item.create(itemData, { parent: this.actor });
}
/**
@ -162,7 +160,8 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Data<DS4Actor>> {
ev.preventDefault();
const el: HTMLFormElement = $(ev.currentTarget).get(0);
const id = $(ev.currentTarget).parents(".item").data("itemId");
const item = duplicate(this.actor.getOwnedItem(id));
const item = this.actor.getEmbeddedDocument("Item", id) as DS4Item; // TODO: Improve in upstream
const itemObject = item.toObject();
const property: string | undefined = $(ev.currentTarget).data("property");
// Early return:
@ -175,8 +174,8 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Data<DS4Actor>> {
// Set new value
const newValue = this.getValue(el);
setProperty(item, property, newValue);
this.actor.updateOwnedItem(item);
setProperty(itemObject, property, newValue);
this.actor.updateEmbeddedDocuments("Item", [{ ...itemObject }]); // TODO: Improve in upstream
}
/**
@ -241,7 +240,7 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Data<DS4Actor>> {
protected _onRollItem(event: JQuery.ClickEvent): void {
event.preventDefault();
const id = $(event.currentTarget).parents(".item").data("itemId");
const item = this.actor.getOwnedItem(id);
const item = this.actor.getEmbeddedDocument("Item", id, { strict: true }) as DS4Item; // TODO: improve in upstream types
item.roll().catch((e) => notifications.error(e, { log: true }));
}
@ -277,14 +276,7 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Data<DS4Actor>> {
}
/** @override */
protected async _onDropItem(
event: DragEvent,
data: { type: "Item" } & (
| { data: DeepPartial<ActorSheet.OwnedItemData<DS4Actor>> }
| { pack: string }
| { id: string }
),
): Promise<boolean | undefined | ActorSheet.OwnedItemData<DS4Actor>> {
protected async _onDropItem(event: DragEvent, data: ActorSheet.DropData.Item): Promise<unknown> {
const item = await DS4Item.fromDropData(data);
if (item && !this.actor.canOwnItemType(item.data.type)) {
notifications.warn(

View file

@ -27,6 +27,10 @@ export interface HasMax<T> {
max: T;
}
export interface ModifiableDataBaseMax<T> extends ModifiableDataBase<T>, HasMax<T> {}
export interface ModifiableDataBaseTotalMax<T> extends ModifiableDataBaseMax<T>, HasTotal<T> {}
export interface ResourceDataBaseTotalMax<T> extends ResourceData<T>, HasBase<T>, HasTotal<T>, HasMax<T> {}
export interface UsableResource<T> {

View file

@ -4,19 +4,18 @@
import { isCheck } from "../actor/actor-data-properties";
import { DS4Item } from "../item/item";
import { DS4ItemData } from "../item/item-data";
import { createRollCheckMacro } from "../macros/roll-check";
import { createRollItemMacro } from "../macros/roll-item";
import notifications from "../ui/notifications";
export default function registerForHotbarDropHook(): void {
Hooks.on("hotbarDrop", async (hotbar: Hotbar, data: { type: string } & Record<string, unknown>, slot: string) => {
Hooks.on("hotbarDrop", async (hotbar: Hotbar, data: HotbarDropData, slot: string) => {
switch (data.type) {
case "Item": {
if (!("data" in data)) {
if (!isItemDropData(data) || !("data" in data)) {
return notifications.warn(game.i18n.localize("DS4.WarningMacrosCanOnlyBeCreatedForOwnedItems"));
}
const itemData = data.data as DS4ItemData;
const itemData = data.data;
if (!DS4Item.rollableItemTypes.includes(itemData.type)) {
return notifications.warn(
@ -38,3 +37,9 @@ export default function registerForHotbarDropHook(): void {
}
});
}
type HotbarDropData = ActorSheet.DropData.Item | ({ type: string } & Partial<Record<string, unknown>>);
function isItemDropData(dropData: HotbarDropData): dropData is ActorSheet.DropData.Item {
return dropData.type === "Item";
}

View file

@ -39,8 +39,8 @@ async function init() {
CONFIG.DS4 = DS4;
// CONFIG.Actor.documentClass = DS4Actor;
// CONFIG.Item.documentClass = DS4Item;
CONFIG.Actor.documentClass = DS4Actor;
CONFIG.Item.documentClass = DS4Item;
CONFIG.Actor.typeLabels = DS4.i18n.actorTypes;
CONFIG.Item.typeLabels = DS4.i18n.itemTypes;
@ -54,10 +54,10 @@ async function init() {
registerSystemSettings();
// Actors.unregisterSheet("core", ActorSheet);
Actors.unregisterSheet("core", ActorSheet);
// Actors.registerSheet("ds4", DS4CharacterActorSheet, { types: ["character"], makeDefault: true });
// Actors.registerSheet("ds4", DS4CreatureActorSheet, { types: ["creature"], makeDefault: true });
// Items.unregisterSheet("core", ItemSheet);
Items.unregisterSheet("core", ItemSheet);
// Items.registerSheet("ds4", DS4ItemSheet, { makeDefault: true });
await registerHandlebarsPartials();

View file

@ -0,0 +1,130 @@
// SPDX-FileCopyrightText: 2021 Johannes Loher
//
// SPDX-License-Identifier: MIT
import { ModifiableDataBaseTotalMax } from "../common/common-data";
import {
DS4AlphabetDataSourceData,
DS4ArmorDataSourceData,
DS4EquipmentDataSourceData,
DS4LanguageDataSourceData,
DS4LootDataSourceData,
DS4RacialAbilityDataSourceData,
DS4ShieldDataSourceData,
DS4SpecialCreatureAbilityDataSourceData,
DS4SpellDataSourceData,
DS4TalentDataSourceData,
DS4WeaponDataSourceData,
} from "./item-data-source";
declare global {
interface DataConfig {
Item: DS4ItemDataProperties;
}
}
export type DS4ItemDataProperties =
| DS4WeaponDataProperties
| DS4ArmorDataProperties
| DS4ShieldDataProperties
| DS4SpellDataProperties
| DS4EquipmentDataProperties
| DS4LootDataProperties
| DS4TalentDataProperties
| DS4RacialAbilityDataProperties
| DS4LanguageDataProperties
| DS4AlphabetDataProperties
| DS4SpecialCreatureAbilityDataProperties;
export interface DS4WeaponDataProperties {
type: "weapon";
data: DS4WeaponDataPropertiesData;
}
export interface DS4ArmorDataProperties {
type: "armor";
data: DS4ArmorDataPropertiesData;
}
export interface DS4ShieldDataProperties {
type: "shield";
data: DS4ShieldDataPropertiesData;
}
export interface DS4SpellDataProperties {
type: "spell";
data: DS4SpellDataPropertiesData;
}
export interface DS4EquipmentDataProperties {
type: "equipment";
data: DS4EquipmentDataPropertiesData;
}
export interface DS4LootDataProperties {
type: "loot";
data: DS4LootDataPropertiesData;
}
export interface DS4TalentDataProperties {
type: "talent";
data: DS4TalentDataPropertiesData;
}
export interface DS4RacialAbilityDataProperties {
type: "racialAbility";
data: DS4RacialAbilityDataPropertiesData;
}
export interface DS4LanguageDataProperties {
type: "language";
data: DS4LanguageDataPropertiesData;
}
export interface DS4AlphabetDataProperties {
type: "alphabet";
data: DS4AlphabetDataPropertiesData;
}
export interface DS4SpecialCreatureAbilityDataProperties {
type: "specialCreatureAbility";
data: DS4SpecialCreatureAbilityDataPropertiesData;
}
// templates
interface DS4ItemDataPropertiesDataRollable {
rollable: boolean;
}
//types
interface DS4WeaponDataPropertiesData extends DS4WeaponDataSourceData, DS4ItemDataPropertiesDataRollable {}
interface DS4ArmorDataPropertiesData extends DS4ArmorDataSourceData, DS4ItemDataPropertiesDataRollable {}
interface DS4ShieldDataPropertiesData extends DS4ShieldDataSourceData, DS4ItemDataPropertiesDataRollable {}
interface DS4SpellDataPropertiesData extends DS4SpellDataSourceData, DS4ItemDataPropertiesDataRollable {
price: number | null;
}
interface DS4EquipmentDataPropertiesData extends DS4EquipmentDataSourceData, DS4ItemDataPropertiesDataRollable {}
interface DS4LootDataPropertiesData extends DS4LootDataSourceData, DS4ItemDataPropertiesDataRollable {}
interface DS4TalentDataPropertiesData extends DS4TalentDataSourceData, DS4ItemDataPropertiesDataRollable {
rank: ModifiableDataBaseTotalMax<number>;
}
interface DS4RacialAbilityDataPropertiesData
extends DS4RacialAbilityDataSourceData,
DS4ItemDataPropertiesDataRollable {}
interface DS4LanguageDataPropertiesData extends DS4LanguageDataSourceData, DS4ItemDataPropertiesDataRollable {}
interface DS4AlphabetDataPropertiesData extends DS4AlphabetDataSourceData, DS4ItemDataPropertiesDataRollable {}
interface DS4SpecialCreatureAbilityDataPropertiesData
extends DS4SpecialCreatureAbilityDataSourceData,
DS4ItemDataPropertiesDataRollable {}

View file

@ -0,0 +1,184 @@
// SPDX-FileCopyrightText: 2021 Johannes Loher
// SPDX-FileCopyrightText: 2021 Oliver Rümpelein
// SPDX-FileCopyrightText: 2021 Gesina Schwalbe
//
// SPDX-License-Identifier: MIT
import { ModifiableDataBaseMax } from "../common/common-data";
import { DS4 } from "../config";
declare global {
interface SourceConfig {
Item: DS4ItemDataSource;
}
}
export type ItemType = keyof typeof DS4.i18n.itemTypes;
export type DS4ItemDataSource =
| DS4WeaponDataSource
| DS4ArmorDataSource
| DS4ShieldDataSource
| DS4SpellDataSource
| DS4EquipmentDataSource
| DS4LootDataSource
| DS4TalentDataSource
| DS4RacialAbilityDataSource
| DS4LanguageDataSource
| DS4AlphabetDataSource
| DS4SpecialCreatureAbilityDataSource;
interface DS4WeaponDataSource {
type: "weapon";
data: DS4WeaponDataSourceData;
}
interface DS4ArmorDataSource {
type: "armor";
data: DS4ArmorDataSourceData;
}
interface DS4ShieldDataSource {
type: "shield";
data: DS4ShieldDataSourceData;
}
interface DS4SpellDataSource {
type: "spell";
data: DS4SpellDataSourceData;
}
interface DS4EquipmentDataSource {
type: "equipment";
data: DS4EquipmentDataSourceData;
}
interface DS4LootDataSource {
type: "loot";
data: DS4LootDataSourceData;
}
interface DS4TalentDataSource {
type: "talent";
data: DS4TalentDataSourceData;
}
interface DS4RacialAbilityDataSource {
type: "racialAbility";
data: DS4RacialAbilityDataSourceData;
}
interface DS4LanguageDataSource {
type: "language";
data: DS4LanguageDataSourceData;
}
interface DS4AlphabetDataSource {
type: "alphabet";
data: DS4AlphabetDataSourceData;
}
interface DS4SpecialCreatureAbilityDataSource {
type: "specialCreatureAbility";
data: DS4SpecialCreatureAbilityDataSourceData;
}
// templates
interface DS4ItemDataSourceDataBase {
description: string;
}
interface DS4ItemDataSourceDataPhysical {
quantity: number;
price: number;
availability: keyof typeof DS4.i18n.itemAvailabilities;
storageLocation: string;
}
export function isDS4ItemDataTypePhysical(input: foundry.data.ItemData["data"]): boolean {
return "quantity" in input && "price" in input && "availability" in input && "storageLocation" in input;
}
interface DS4ItemDataSourceDataEquipable {
equipped: boolean;
}
interface DS4ItemDataSourceDataProtective {
armorValue: number;
}
// types
export interface DS4WeaponDataSourceData
extends DS4ItemDataSourceDataBase,
DS4ItemDataSourceDataPhysical,
DS4ItemDataSourceDataEquipable {
attackType: AttackType;
weaponBonus: number;
opponentDefense: number;
}
export type AttackType = keyof typeof DS4.i18n.attackTypes;
export interface DS4ArmorDataSourceData
extends DS4ItemDataSourceDataBase,
DS4ItemDataSourceDataPhysical,
DS4ItemDataSourceDataEquipable,
DS4ItemDataSourceDataProtective {
armorMaterialType: keyof typeof DS4.i18n.armorMaterialTypes;
armorType: keyof typeof DS4.i18n.armorTypes;
}
export interface DS4ShieldDataSourceData
extends DS4ItemDataSourceDataBase,
DS4ItemDataSourceDataPhysical,
DS4ItemDataSourceDataEquipable,
DS4ItemDataSourceDataProtective {}
export interface DS4SpellDataSourceData extends DS4ItemDataSourceDataBase, DS4ItemDataSourceDataEquipable {
spellType: keyof typeof DS4.i18n.spellTypes;
bonus: string;
spellCategory: keyof typeof DS4.i18n.spellCategories;
maxDistance: UnitData<DistanceUnit>;
effectRadius: UnitData<DistanceUnit>;
duration: UnitData<CustomTemporalUnit>;
cooldownDuration: UnitData<TemporalUnit>;
minimumLevels: {
healer: number | null;
wizard: number | null;
sorcerer: number | null;
};
}
export interface UnitData<UnitType> {
value: string;
unit: UnitType;
}
type DistanceUnit = keyof typeof DS4.i18n.distanceUnits;
type CustomTemporalUnit = keyof typeof DS4.i18n.customTemporalUnits;
export type TemporalUnit = keyof typeof DS4.i18n.temporalUnits;
export interface DS4EquipmentDataSourceData
extends DS4ItemDataSourceDataBase,
DS4ItemDataSourceDataPhysical,
DS4ItemDataSourceDataEquipable {}
export interface DS4LootDataSourceData extends DS4ItemDataSourceDataBase, DS4ItemDataSourceDataPhysical {}
export interface DS4TalentDataSourceData extends DS4ItemDataSourceDataBase {
rank: ModifiableDataBaseMax<number>;
}
export type DS4RacialAbilityDataSourceData = DS4ItemDataSourceDataBase;
export type DS4LanguageDataSourceData = DS4ItemDataSourceDataBase;
export type DS4AlphabetDataSourceData = DS4ItemDataSourceDataBase;
export interface DS4SpecialCreatureAbilityDataSourceData extends DS4ItemDataSourceDataBase {
experiencePoints: number;
}

View file

@ -1,133 +0,0 @@
// SPDX-FileCopyrightText: 2021 Johannes Loher
// SPDX-FileCopyrightText: 2021 Oliver Rümpelein
// SPDX-FileCopyrightText: 2021 Gesina Schwalbe
//
// SPDX-License-Identifier: MIT
import { ModifiableDataBase } from "../common/common-data";
import { DS4 } from "../config";
export type ItemType = keyof typeof DS4.i18n.itemTypes;
export type DS4ItemData =
| DS4WeaponData
| DS4ArmorData
| DS4ShieldData
| DS4SpellData
| DS4EquipmentData
| DS4LootData
| DS4TalentData
| DS4RacialAbilityData
| DS4LanguageData
| DS4AlphabetData
| DS4SpecialCreatureAbilityData;
export interface DS4ItemDataHelper<T, U extends ItemType> extends Item.Data<T> {
type: U;
}
type DS4WeaponData = DS4ItemDataHelper<DS4WeaponDataData, "weapon">;
type DS4ArmorData = DS4ItemDataHelper<DS4ArmorDataData, "armor">;
type DS4ShieldData = DS4ItemDataHelper<DS4ShieldDataData, "shield">;
type DS4SpellData = DS4ItemDataHelper<DS4SpellDataData, "spell">;
type DS4EquipmentData = DS4ItemDataHelper<DS4EquipmentDataData, "equipment">;
type DS4LootData = DS4ItemDataHelper<DS4LootDataData, "loot">;
type DS4TalentData = DS4ItemDataHelper<DS4TalentDataData, "talent">;
type DS4RacialAbilityData = DS4ItemDataHelper<DS4RacialAbilityDataData, "racialAbility">;
type DS4LanguageData = DS4ItemDataHelper<DS4LanguageDataData, "language">;
type DS4AlphabetData = DS4ItemDataHelper<DS4AlphabetDataData, "alphabet">;
type DS4SpecialCreatureAbilityData = DS4ItemDataHelper<DS4SpecialCreatureAbilityDataData, "specialCreatureAbility">;
// templates
interface DS4ItemDataDataBase {
description: string;
}
interface DS4ItemDataDataPhysical {
quantity: number;
price: number;
availability: keyof typeof DS4.i18n.itemAvailabilities;
storageLocation: string;
}
export function isDS4ItemDataTypePhysical(input: DS4ItemData["data"]): boolean {
return "quantity" in input && "price" in input && "availability" in input && "storageLocation" in input;
}
interface DS4ItemDataDataEquipable {
equipped: boolean;
}
interface DS4ItemDataDataProtective {
armorValue: number;
}
export interface UnitData<UnitType> {
value: string;
unit: UnitType;
}
export type TemporalUnit = keyof typeof DS4.i18n.temporalUnits;
type CustomTemporalUnit = keyof typeof DS4.i18n.customTemporalUnits;
type DistanceUnit = keyof typeof DS4.i18n.distanceUnits;
// types
export interface DS4WeaponDataData extends DS4ItemDataDataBase, DS4ItemDataDataPhysical, DS4ItemDataDataEquipable {
attackType: AttackType;
weaponBonus: number;
opponentDefense: number;
}
export type AttackType = keyof typeof DS4.i18n.attackTypes;
export interface DS4ArmorDataData
extends DS4ItemDataDataBase,
DS4ItemDataDataPhysical,
DS4ItemDataDataEquipable,
DS4ItemDataDataProtective {
armorMaterialType: keyof typeof DS4.i18n.armorMaterialTypes;
armorType: keyof typeof DS4.i18n.armorTypes;
}
export interface DS4TalentDataData extends DS4ItemDataDataBase {
rank: DS4TalentRank;
}
export interface DS4TalentRank extends ModifiableDataBase<number> {
max: number;
}
export interface DS4SpellDataData extends DS4ItemDataDataBase, DS4ItemDataDataEquipable {
spellType: keyof typeof DS4.i18n.spellTypes;
bonus: string;
spellCategory: keyof typeof DS4.i18n.spellCategories;
maxDistance: UnitData<DistanceUnit>;
effectRadius: UnitData<DistanceUnit>;
duration: UnitData<CustomTemporalUnit>;
cooldownDuration: UnitData<TemporalUnit>;
minimumLevels: {
healer: number | null;
wizard: number | null;
sorcerer: number | null;
};
}
export interface DS4ShieldDataData
extends DS4ItemDataDataBase,
DS4ItemDataDataPhysical,
DS4ItemDataDataEquipable,
DS4ItemDataDataProtective {}
export interface DS4EquipmentDataData extends DS4ItemDataDataBase, DS4ItemDataDataPhysical, DS4ItemDataDataEquipable {}
export interface DS4LootDataData extends DS4ItemDataDataBase, DS4ItemDataDataPhysical {}
export type DS4RacialAbilityDataData = DS4ItemDataDataBase;
export type DS4LanguageDataData = DS4ItemDataDataBase;
export type DS4AlphabetDataData = DS4ItemDataDataBase;
export interface DS4SpecialCreatureAbilityDataData extends DS4ItemDataDataBase {
experiencePoints: number;
}

View file

@ -1,86 +0,0 @@
// SPDX-FileCopyrightText: 2021 Johannes Loher
//
// SPDX-License-Identifier: MIT
import { HasTotal } from "../common/common-data";
import {
DS4AlphabetDataData,
DS4ArmorDataData,
DS4EquipmentDataData,
DS4ItemDataHelper,
DS4LanguageDataData,
DS4LootDataData,
DS4RacialAbilityDataData,
DS4ShieldDataData,
DS4SpecialCreatureAbilityDataData,
DS4SpellDataData,
DS4TalentDataData,
DS4TalentRank,
DS4WeaponDataData,
} from "./item-data";
export type DS4ItemPreparedData =
| DS4WeaponPreparedData
| DS4ArmorPreparedData
| DS4ShieldPreparedData
| DS4SpellPreparedData
| DS4EquipmentPreparedData
| DS4LootPreparedData
| DS4TalentPreparedData
| DS4RacialAbilityPreparedData
| DS4LanguagePreparedData
| DS4AlphabetPreparedData
| DS4SpecialCreatureAbilityPreparedData;
export type DS4WeaponPreparedData = DS4ItemDataHelper<DS4WeaponPreparedDataData, "weapon">;
export type DS4ArmorPreparedData = DS4ItemDataHelper<DS4ArmorPreparedDataData, "armor">;
export type DS4ShieldPreparedData = DS4ItemDataHelper<DS4ShieldPreparedDataData, "shield">;
export type DS4SpellPreparedData = DS4ItemDataHelper<DS4SpellPreparedDataData, "spell">;
export type DS4EquipmentPreparedData = DS4ItemDataHelper<DS4EquipmentPreparedDataData, "equipment">;
export type DS4LootPreparedData = DS4ItemDataHelper<DS4LootPreparedDataData, "loot">;
export type DS4TalentPreparedData = DS4ItemDataHelper<DS4TalentPreparedDataData, "talent">;
export type DS4RacialAbilityPreparedData = DS4ItemDataHelper<DS4RacialAbilityPreparedDataData, "racialAbility">;
export type DS4LanguagePreparedData = DS4ItemDataHelper<DS4LanguagePreparedDataData, "language">;
export type DS4AlphabetPreparedData = DS4ItemDataHelper<DS4AlphabetPreparedDataData, "alphabet">;
export type DS4SpecialCreatureAbilityPreparedData = DS4ItemDataHelper<
DS4SpecialCreatureAbilityPreparedDataData,
"specialCreatureAbility"
>;
// templates
interface DS4ItemPreparedDataDataRollable {
rollable: boolean;
}
//types
interface DS4WeaponPreparedDataData extends DS4WeaponDataData, DS4ItemPreparedDataDataRollable {}
interface DS4ArmorPreparedDataData extends DS4ArmorDataData, DS4ItemPreparedDataDataRollable {}
interface DS4ShieldPreparedDataData extends DS4ShieldDataData, DS4ItemPreparedDataDataRollable {}
interface DS4SpellPreparedDataData extends DS4SpellDataData, DS4ItemPreparedDataDataRollable {
price: number | null;
}
interface DS4EquipmentPreparedDataData extends DS4EquipmentDataData, DS4ItemPreparedDataDataRollable {}
interface DS4LootPreparedDataData extends DS4LootDataData, DS4ItemPreparedDataDataRollable {}
interface DS4TalentPreparedDataData extends DS4TalentDataData, DS4ItemPreparedDataDataRollable {
rank: DS4TalentPreparedRank;
}
interface DS4TalentPreparedRank extends DS4TalentRank, HasTotal<number> {}
interface DS4RacialAbilityPreparedDataData extends DS4RacialAbilityDataData, DS4ItemPreparedDataDataRollable {}
interface DS4LanguagePreparedDataData extends DS4LanguageDataData, DS4ItemPreparedDataDataRollable {}
interface DS4AlphabetPreparedDataData extends DS4AlphabetDataData, DS4ItemPreparedDataDataRollable {}
interface DS4SpecialCreatureAbilityPreparedDataData
extends DS4SpecialCreatureAbilityDataData,
DS4ItemPreparedDataDataRollable {}

View file

@ -7,17 +7,16 @@
import { DS4 } from "../config";
import notifications from "../ui/notifications";
import { DS4Item } from "./item";
import { isDS4ItemDataTypePhysical } from "./item-data";
import { isDS4ItemDataTypePhysical } from "./item-data-source";
/**
* The Sheet class for DS4 Items
*/
export class DS4ItemSheet extends ItemSheet<ItemSheet.Data<DS4Item>> {
export class DS4ItemSheet extends ItemSheet {
/** @override */
static get defaultOptions(): BaseEntitySheet.Options {
static get defaultOptions(): ItemSheet.Options {
const superDefaultOptions = super.defaultOptions;
return mergeObject(superDefaultOptions, {
...superDefaultOptions,
width: 540,
height: 400,
classes: ["ds4", "sheet", "item"],
@ -45,11 +44,14 @@ export class DS4ItemSheet extends ItemSheet<ItemSheet.Data<DS4Item>> {
}
/** @override */
setPosition(options: Partial<Application.Position> = {}): Application.Position & { height: number } {
setPosition(options: Partial<Application.Position> = {}): (Application.Position & { height: number }) | undefined {
const position = super.setPosition(options);
const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - 192;
sheetBody.css("height", bodyHeight);
if (position) {
const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - 192;
sheetBody.css("height", bodyHeight);
}
return position;
}
@ -86,7 +88,7 @@ export class DS4ItemSheet extends ItemSheet<ItemSheet.Data<DS4Item>> {
}
return effect.sheet.render(true);
case "delete": {
return this.item.deleteEmbeddedEntity("ActiveEffect", li.data("effectId"));
return this.item.deleteEmbeddedDocuments("ActiveEffect", [li.data("effectId")]);
}
}
}
@ -94,7 +96,7 @@ export class DS4ItemSheet extends ItemSheet<ItemSheet.Data<DS4Item>> {
/**
* Create a new ActiveEffect for the item using default data.
*/
protected async _createActiveEffect(): Promise<ActiveEffect.Data> {
protected async _createActiveEffect(): Promise<ActiveEffect | undefined> {
const label = `New Effect`;
const createData = {
@ -104,7 +106,6 @@ export class DS4ItemSheet extends ItemSheet<ItemSheet.Data<DS4Item>> {
transfer: true,
};
const effect = ActiveEffect.create(createData, this.item);
return effect.create({});
return ActiveEffect.create(createData, { parent: this.item });
}
}

View file

@ -7,14 +7,19 @@ import { DS4Actor } from "../actor/actor";
import { DS4 } from "../config";
import { createCheckRoll } from "../rolls/check-factory";
import notifications from "../ui/notifications";
import { AttackType, DS4ItemData, ItemType } from "./item-data";
import { DS4ItemPreparedData } from "./item-prepared-data";
import { AttackType, ItemType } from "./item-data-source";
import { calculateSpellPrice } from "./type-specific-helpers/spell";
declare global {
interface DocumentClassConfig {
Item: typeof DS4Item;
}
}
/**
* The Item class for DS4
*/
export class DS4Item extends Item<DS4ItemData, DS4ItemPreparedData> {
export class DS4Item extends Item {
/**
* @override
*/
@ -77,7 +82,7 @@ export class DS4Item extends Item<DS4ItemData, DS4ItemPreparedData> {
}
}
protected async rollWeapon(this: this & { readonly isOwned: true }): Promise<void> {
protected async rollWeapon(this: this & { readonly actor: DS4Actor }): Promise<void> {
if (!(this.data.type === "weapon")) {
throw new Error(
game.i18n.format("DS4.ErrorWrongItemType", {
@ -99,21 +104,21 @@ export class DS4Item extends Item<DS4ItemData, DS4ItemPreparedData> {
);
}
const actor = this.actor as unknown as DS4Actor; // TODO(types): Improve so that the concrete Actor type is known here
const actor = this.actor;
const ownerDataData = actor.data.data;
const weaponBonus = this.data.data.weaponBonus;
const combatValue = await this.getCombatValueKeyForAttackType(this.data.data.attackType);
const checkTargetNumber = ownerDataData.combatValues[combatValue].total + weaponBonus;
await createCheckRoll(checkTargetNumber, {
rollMode: game.settings.get("core", "rollMode") as Const.DiceRollMode, // TODO(types): Type this setting in upstream
rollMode: game.settings.get("core", "rollMode"),
maximumCoupResult: ownerDataData.rolling.maximumCoupResult,
minimumFumbleResult: ownerDataData.rolling.minimumFumbleResult,
flavor: game.i18n.format("DS4.ItemWeaponCheckFlavor", { actor: actor.name, weapon: this.name }),
});
}
protected async rollSpell(): Promise<void> {
protected async rollSpell(this: this & { readonly actor: DS4Actor }): Promise<void> {
if (!(this.data.type === "spell")) {
throw new Error(
game.i18n.format("DS4.ErrorWrongItemType", {
@ -135,7 +140,7 @@ export class DS4Item extends Item<DS4ItemData, DS4ItemPreparedData> {
);
}
const actor = this.actor as unknown as DS4Actor; // TODO(types): Improve so that the concrete Actor type is known here
const actor = this.actor;
const ownerDataData = actor.data.data;
const spellBonus = Number.isNumeric(this.data.data.bonus) ? parseInt(this.data.data.bonus) : undefined;
if (spellBonus === undefined) {
@ -150,7 +155,7 @@ export class DS4Item extends Item<DS4ItemData, DS4ItemPreparedData> {
const checkTargetNumber = ownerDataData.combatValues[spellType].total + (spellBonus ?? 0);
await createCheckRoll(checkTargetNumber, {
rollMode: game.settings.get("core", "rollMode") as Const.DiceRollMode, // TODO(types): Type this setting in upstream
rollMode: game.settings.get("core", "rollMode"),
maximumCoupResult: ownerDataData.rolling.maximumCoupResult,
minimumFumbleResult: ownerDataData.rolling.minimumFumbleResult,
flavor: game.i18n.format("DS4.ItemSpellCheckFlavor", { actor: actor.name, spell: this.name }),
@ -194,7 +199,7 @@ export class DS4Item extends Item<DS4ItemData, DS4ItemPreparedData> {
/**
* Type-guarding variant to check if the item is owned.
*/
isOwnedItem(): this is this & { readonly isOwned: true } {
isOwnedItem(): this is this & { readonly isOwned: true; readonly actor: DS4Actor; readonly parent: DS4Actor } {
return this.isOwned;
}
}

View file

@ -3,9 +3,9 @@
// SPDX-License-Identifier: MIT
import { hoursPerDay, minutesPerHour, secondsPerMinute, secondsPerRound } from "../../common/time-helpers";
import { DS4SpellDataData, TemporalUnit, UnitData } from "../item-data";
import { DS4SpellDataSourceData, TemporalUnit, UnitData } from "../item-data-source";
export function calculateSpellPrice(data: DS4SpellDataData): number | null {
export function calculateSpellPrice(data: DS4SpellDataSourceData): number | null {
const spellPriceFactor = calculateSpellPriceFactor(data.cooldownDuration);
const baseSpellPrices = [
data.minimumLevels.healer !== null ? 10 + (data.minimumLevels.healer - 1) * 35 : null,

View file

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: MIT
import { DS4ItemData } from "../item/item-data";
import { DS4ItemData } from "../item/item-data-source";
import notifications from "../ui/notifications";
import { getActiveActor } from "./helpers";

View file

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: MIT
import { DS4SpellDataData } from "../item/item-data";
import { DS4SpellDataSourceData } from "../item/item-data-source";
import logger from "../logger";
export async function migrate(): Promise<void> {
@ -33,7 +33,7 @@ function getItemUpdateData(itemData: DeepPartial<Item.Data>) {
"-=data.scrollPrice": null,
"data.minimumLevels": { healer: null, wizard: null, sorcerer: null },
};
if (((itemData.data as DS4SpellDataData).cooldownDuration.unit as string) === "custom") {
if (((itemData.data as DS4SpellDataSourceData).cooldownDuration.unit as string) === "custom") {
updateData["data.cooldownDuration.unit"] = "rounds";
}
return updateData;

View file

@ -170,29 +170,6 @@
"shield": {
"templates": ["base", "physical", "equipable", "protective"]
},
"equipment": {
"templates": ["base", "physical", "equipable"]
},
"loot": {
"templates": ["base", "physical"]
},
"talent": {
"templates": ["base"],
"rank": {
"base": 0,
"max": 0,
"mod": 0
}
},
"racialAbility": {
"templates": ["base"]
},
"language": {
"templates": ["base"]
},
"alphabet": {
"templates": ["base"]
},
"spell": {
"templates": ["base", "equipable"],
"spellType": "spellcasting",
@ -220,6 +197,29 @@
"sorcerer": null
}
},
"equipment": {
"templates": ["base", "physical", "equipable"]
},
"loot": {
"templates": ["base", "physical"]
},
"talent": {
"templates": ["base"],
"rank": {
"base": 0,
"max": 0,
"mod": 0
}
},
"racialAbility": {
"templates": ["base"]
},
"language": {
"templates": ["base"]
},
"alphabet": {
"templates": ["base"]
},
"specialCreatureAbility": {
"templates": ["base"],
"experiencePoints": 0

View file

@ -841,7 +841,7 @@ __metadata:
"@league-of-foundry-developers/foundry-vtt-types@https://github.com/League-of-Foundry-Developers/foundry-vtt-types.git#foundry-0.8.x":
version: 0.7.9-6
resolution: "@league-of-foundry-developers/foundry-vtt-types@https://github.com/League-of-Foundry-Developers/foundry-vtt-types.git#commit=62c138c4ff2f6c3b19301db2b31e14e7c825f1e6"
resolution: "@league-of-foundry-developers/foundry-vtt-types@https://github.com/League-of-Foundry-Developers/foundry-vtt-types.git#commit=f242ac76237f2099f946b10d642f0b3272ead043"
dependencies:
"@types/jquery": ~3.5.5
"@types/simple-peer": ~9.11.0
@ -851,7 +851,7 @@ __metadata:
socket.io-client: 4.1.2
tinymce: 5.8.1
typescript: ^4.1.6
checksum: af1f4d3cfae69a5a0fab2ca3a301c9f755d7f5584bf1eaee37031b19fe805581b7588e6a2452553f874a68cb5475a5a8fce287ed8436cf0af24fa0527ea5c014
checksum: ae81444ddf4b36bff67a2483cc559ff64dd1fdaaada277439e2ed14a8ec8233f06723b9421be70033b38383d9c275de18b216307bb14b17feafc5866156b0ac3
languageName: node
linkType: hard
@ -1505,9 +1505,9 @@ __metadata:
linkType: hard
"@types/sizzle@npm:*":
version: 2.3.2
resolution: "@types/sizzle@npm:2.3.2"
checksum: 447a1c3f39f0e47ffdbccd1df58d63e8b67dc001f44f26f43ac8243db7834a3d956cebc8abe9272ecbdccfc8f4ec0ae74b811ccdad5b6cddaf8f0968513d618a
version: 2.3.3
resolution: "@types/sizzle@npm:2.3.3"
checksum: 8f019f9e1b110b4fdfc08f8a3a8b8b87118a11f3ba11e159541b17f17498c0ef95e8efa0b818c9fed6911041f6b71ef8d44cf8c1c83b4cbb7bd14e4248892f4c
languageName: node
linkType: hard
@ -8516,11 +8516,11 @@ fsevents@^1.2.7:
linkType: hard
"uglify-js@npm:^3.1.4":
version: 3.13.0
resolution: "uglify-js@npm:3.13.0"
version: 3.13.10
resolution: "uglify-js@npm:3.13.10"
bin:
uglifyjs: bin/uglifyjs
checksum: bb35cfe5ce9735a9707b33628dbbef02ab4b62bdd3650a02e14dfe42f4ac3fe5e9d616352476605706ab651561abc66ef2877c3dcabf4bde5bf66cecec94f3e8
checksum: 2c8467faf68a0ba4da7a9539026dc996804f0e89f184ce0a6ceaa9a9c7e4e2ab78399caee8ebbebcd3df64a45b049585c4125e144f1c5992f9b61e81864d9535
languageName: node
linkType: hard