diff --git a/.vscode/settings.json b/.vscode/settings.json index 62787842..f8012687 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,5 +6,11 @@ "eslint.nodePath": ".yarn/sdks", "prettier.prettierPath": ".yarn/sdks/prettier/index.js", "typescript.tsdk": ".yarn/sdks/typescript/lib", - "typescript.enablePromptUseWorkspaceTsdk": true + "typescript.enablePromptUseWorkspaceTsdk": true, + "importSorter.generalConfiguration.sortOnBeforeSave": true, + "importSorter.importStringConfiguration.maximumNumberOfImportExpressionsPerLine.type": "newLineEachExpressionAfterCountLimitExceptIfOnlyOne", + "importSorter.importStringConfiguration.maximumNumberOfImportExpressionsPerLine.count": 120, + "importSorter.importStringConfiguration.tabSize": 4, + "importSorter.importStringConfiguration.quoteMark": "double", + "importSorter.importStringConfiguration.trailingComma": "multiLine" } diff --git a/lang/de.json b/lang/de.json index d1a9e186..2c0dfd5f 100644 --- a/lang/de.json +++ b/lang/de.json @@ -256,11 +256,12 @@ "DS4.ErrorDiceCoupFumbleOverlap": "Es gibt eine Überlappung zwischen Patzern und Immersiegen.", "DS4.ErrorSlayingDiceRecursionLimitExceeded": "Die maximale Rekursionstiefe für slayende Würfelwürfe wurde überschritten.", "DS4.ErrorInvalidNumberOfDice": "Ungültige Anzahl an Würfeln.", + "DS4.ErrorInvalidActorType": "Ungültiger Aktortyp '{type}'.", + "DS4.ErrorInvalidItemType": "Ungültiger Itemtyp '{type}'.", "DS4.ErrorDuringMigration": "Fehler während der Aktualisierung des DS4 Systems von Migrationsversion {currentVersion} auf {targetVersion}. Der Fehler trat während der Ausführung des Migrationsskripts mit der Version {migrationVersion} auf. Spätere Migrationsskripte wurden nicht ausgeführt. Mehr Details finden Sie in der Entwicklerkonsole (F12).", "DS4.ErrorDuringCompendiumMigration": "Fehler während der Aktualisierung Kompendiums '{pack}' für DS4 von Migrationsversion {currentVersion} auf {targetVersion}. Der Fehler trat während der Ausführung des Migrationsskripts mit der Version {migrationVersion} auf. Spätere Migrationsskripte wurden nicht ausgeführt. Mehr Details finden Sie in der Entwicklerkonsole (F12).", "DS4.ErrorCannotRollUnownedItem": "Für das Item '{name}' ({id}) kann nicht gewürfelt werden, da es keinem Aktor gehört.", "DS4.ErrorRollingForItemTypeNotPossible": "Würfeln ist für Items vom Typ '{type}' nicht möglich.", - "DS4.ErrorWrongItemType": "Ein Item vom Type '{expectedType}' wurde erwartet aber das Item '{name}' ({id}) ist vom Typ '{actualType}'.", "DS4.ErrorUnexpectedAttackType": "Unerwartete Angriffsart '{actualType}', erwartete Angriffsarten: {expectedTypes}", "DS4.ErrorUnexpectedAttribute": "Unerwartetes Attribut '{actualAttribute}', erwartete Attribute: {expectedTypes}", "DS4.ErrorUnexpectedTrait": "Unerwartete Eigenschaft '{actualTrait}', erwartete Eigenschaften: {expectedTypes}", diff --git a/lang/en.json b/lang/en.json index 38640607..19973936 100644 --- a/lang/en.json +++ b/lang/en.json @@ -256,11 +256,12 @@ "DS4.ErrorDiceCoupFumbleOverlap": "There is an overlap between Fumbles and Coups.", "DS4.ErrorSlayingDiceRecursionLimitExceeded": "Maximum recursion depth for slaying dice roll exceeded.", "DS4.ErrorInvalidNumberOfDice": "Invalid number of dice.", + "DS4.ErrorInvalidActorType": "Invalid actor type '{type}'.", + "DS4.ErrorInvalidItemType": "Invalid item type '{type}'.", "DS4.ErrorDuringMigration": "Error while migrating DS4 system from migration version {currentVersion} to {targetVersion}. The error occurred during execution of migration script with version {migrationVersion}. Later migrations have not been executed. For more details, please look at the development console (F12).", "DS4.ErrorDuringCompendiumMigration": "Error while migrating compendium '{pack}' for DS4 from migration version {currentVersion} to {targetVersion}. The error occurred during execution of migration script with version {migrationVersion}. Later migrations have not been executed. For more details, please look at the development console (F12).", "DS4.ErrorCannotRollUnownedItem": "Rolling for item '{name}' ({id})is not possible because it is not owned.", "DS4.ErrorRollingForItemTypeNotPossible": "Rolling is not possible for items of type '{type}'.", - "DS4.ErrorWrongItemType": "Expected an item of type '{expectedType}' but item '{name}' ({id}) is of type '{actualType}'.", "DS4.ErrorUnexpectedAttackType": "Unexpected attack type '{actualType}', expected it to be one of: {expectedTypes}", "DS4.ErrorUnexpectedAttribute": "Unexpected attribute '{actualAttribute}', expected it to be one of: {expectedTypes}", "DS4.ErrorUnexpectedTrait": "Unexpected trait '{actualTrait}', expected it to be one of: {expectedTypes}", diff --git a/package.json b/package.json index 156626e8..76898f6f 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "@commitlint/cli": "16.2.1", "@commitlint/config-conventional": "16.2.1", "@guanghechen/rollup-plugin-copy": "1.8.6", - "@league-of-foundry-developers/foundry-vtt-types": "9.249.2", + "@league-of-foundry-developers/foundry-vtt-types": "9.249.3", "@rollup/plugin-typescript": "8.3.0", "@seald-io/nedb": "2.2.1", "@types/fs-extra": "9.0.13", diff --git a/spec/item/type-specific-helpers/spell.spec.ts b/spec/item/spell/calculate-spell-price.spec.ts similarity index 97% rename from spec/item/type-specific-helpers/spell.spec.ts rename to spec/item/spell/calculate-spell-price.spec.ts index e454c959..56d49f6d 100644 --- a/spec/item/type-specific-helpers/spell.spec.ts +++ b/spec/item/spell/calculate-spell-price.spec.ts @@ -2,8 +2,9 @@ // // SPDX-License-Identifier: MIT -import { CooldownDuration, DS4SpellDataSourceData } from "../../../src/item/item-data-source"; -import { calculateSpellPrice } from "../../../src/item/type-specific-helpers/spell"; +import { calculateSpellPrice } from "../../../src/item/spell/calculate-spell-price"; + +import type { CooldownDuration, DS4SpellDataSourceData } from "../../../src/item/spell/spell-data-source"; const defaultData: DS4SpellDataSourceData = { description: "", diff --git a/src/active-effect.ts b/src/active-effect.ts index 81689bfb..d810e6b0 100644 --- a/src/active-effect.ts +++ b/src/active-effect.ts @@ -4,7 +4,8 @@ import { DS4Actor } from "./actor/actor"; import { getGame } from "./helpers"; -import { DS4Item } from "./item/item"; + +import type { DS4Item } from "./item/item"; declare global { interface DocumentClassConfig { diff --git a/src/actor/actor-data-properties-base.ts b/src/actor/actor-data-properties-base.ts new file mode 100644 index 00000000..9aa9e335 --- /dev/null +++ b/src/actor/actor-data-properties-base.ts @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2021 Johannes Loher +// SPDX-FileCopyrightText: 2021 Oliver Rümpelein +// SPDX-FileCopyrightText: 2021 Gesina Schwalbe +// SPDX-FileCopyrightText: 2021 Siegfried Krug +// +// SPDX-License-Identifier: MIT + +import { DS4 } from "../config"; + +import type { ModifiableDataBaseTotal, ResourceDataBaseTotalMax } from "../common/common-data"; + +export interface DS4ActorDataPropertiesDataBase { + attributes: DS4ActorDataPropertiesDataAttributes; + traits: DS4ActorDataPropertiesDataTraits; + combatValues: DS4ActorDataPropertiesDataCombatValues; + rolling: DS4ActorDataPropertiesDataRolling; + checks: DS4ActorDataPropertiesDataChecks; +} + +type DS4ActorDataPropertiesDataAttributes = { + [Key in keyof typeof DS4.i18n.attributes]: ModifiableDataBaseTotal; +}; + +type DS4ActorDataPropertiesDataTraits = { [Key in keyof typeof DS4.i18n.traits]: ModifiableDataBaseTotal }; + +type DS4ActorDataPropertiesDataCombatValues = { + [Key in keyof typeof DS4.i18n.combatValues]: Key extends "hitPoints" + ? ResourceDataBaseTotalMax + : ModifiableDataBaseTotal; +}; + +interface DS4ActorDataPropertiesDataRolling { + maximumCoupResult: number; + minimumFumbleResult: number; +} + +type DS4ActorDataPropertiesDataChecks = { + [key in Check]: number; +}; + +export type Check = keyof typeof DS4.i18n.checks; + +export function isCheck(value: string): value is Check { + return Object.keys(DS4.i18n.checks).includes(value); +} diff --git a/src/actor/actor-data-properties.ts b/src/actor/actor-data-properties.ts index 828fad18..9360e728 100644 --- a/src/actor/actor-data-properties.ts +++ b/src/actor/actor-data-properties.ts @@ -1,17 +1,9 @@ -// SPDX-FileCopyrightText: 2021 Johannes Loher +// SPDX-FileCopyrightText: 2022 Johannes Loher // // SPDX-License-Identifier: MIT -import { ModifiableDataBaseTotal, ResourceDataBaseTotalMax } from "../common/common-data"; -import { DS4 } from "../config"; -import { - DS4CharacterDataSourceDataBaseInfo, - DS4CharacterDataSourceDataCurrency, - DS4CharacterDataSourceDataProfile, - DS4CharacterDataSourceDataProgression, - DS4CharacterDataSourceDataSlayerPoints, - DS4CreatureDataSourceDataBaseInfo, -} from "./actor-data-source"; +import type { DS4CharacterDataProperties } from "./character/character-data-properties"; +import type { DS4CreatureDataProperties } from "./creature/creature-data-properties"; declare global { interface DataConfig { @@ -20,68 +12,3 @@ declare global { } export type DS4ActorDataProperties = DS4CharacterDataProperties | DS4CreatureDataProperties; - -interface DS4CharacterDataProperties { - type: "character"; - data: DS4CharacterDataPropertiesData; -} - -interface DS4CreatureDataProperties { - type: "creature"; - data: DS4CreatureDataPropertiesData; -} - -// templates - -interface DS4ActorDataPropertiesDataBase { - attributes: DS4ActorDataPropertiesDataAttributes; - traits: DS4ActorDataPropertiesDataTraits; - combatValues: DS4ActorDataPropertiesDataCombatValues; - rolling: DS4ActorDataPropertiesDataRolling; - checks: DS4ActorDataPropertiesDataChecks; -} - -type DS4ActorDataPropertiesDataAttributes = { - [Key in keyof typeof DS4.i18n.attributes]: ModifiableDataBaseTotal; -}; - -type DS4ActorDataPropertiesDataTraits = { [Key in keyof typeof DS4.i18n.traits]: ModifiableDataBaseTotal }; - -type DS4ActorDataPropertiesDataCombatValues = { - [Key in keyof typeof DS4.i18n.combatValues]: Key extends "hitPoints" - ? ResourceDataBaseTotalMax - : ModifiableDataBaseTotal; -}; - -interface DS4ActorDataPropertiesDataRolling { - maximumCoupResult: number; - minimumFumbleResult: number; -} - -type DS4ActorDataPropertiesDataChecks = { - [key in Check]: number; -}; - -export type Check = keyof typeof DS4.i18n.checks; - -export function isCheck(value: string): value is Check { - return Object.keys(DS4.i18n.checks).includes(value); -} - -// types - -interface DS4CreatureDataPropertiesData extends DS4ActorDataPropertiesDataBase { - baseInfo: DS4CreatureDataSourceDataBaseInfo; -} - -interface DS4CharacterDataPropertiesData extends DS4ActorDataPropertiesDataBase { - baseInfo: DS4CharacterDataSourceDataBaseInfo; - progression: DS4CharacterDataSourceDataProgression; - profile: DS4CharacterDataSourceDataProfile; - currency: DS4CharacterDataSourceDataCurrency; - slayerPoints: DS4CharacterDataPropertiesDataSlayerPoints; -} - -export interface DS4CharacterDataPropertiesDataSlayerPoints extends DS4CharacterDataSourceDataSlayerPoints { - max: number; -} diff --git a/src/actor/actor-data-source-base.ts b/src/actor/actor-data-source-base.ts new file mode 100644 index 00000000..e57ad17d --- /dev/null +++ b/src/actor/actor-data-source-base.ts @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: 2021 Johannes Loher +// SPDX-FileCopyrightText: 2021 Oliver Rümpelein +// SPDX-FileCopyrightText: 2021 Gesina Schwalbe +// SPDX-FileCopyrightText: 2021 Siegfried Krug +// +// SPDX-License-Identifier: MIT + +import { DS4 } from "../config"; + +import type { ModifiableData, ModifiableDataBase, ResourceData } from "../common/common-data"; + +export interface DS4ActorDataSourceDataBase { + attributes: DS4ActorDataSourceDataAttributes; + traits: DS4ActorDataSourceDataTraits; + combatValues: DS4ActorDataSourceDataCombatValues; +} + +type DS4ActorDataSourceDataAttributes = { [Key in keyof typeof DS4.i18n.attributes]: ModifiableDataBase }; + +type Attribute = keyof DS4ActorDataSourceDataAttributes; + +export function isAttribute(value: unknown): value is Attribute { + return (Object.keys(DS4.i18n.attributes) as Array).includes(value); +} + +type DS4ActorDataSourceDataTraits = { [Key in keyof typeof DS4.i18n.traits]: ModifiableDataBase }; + +type Trait = keyof DS4ActorDataSourceDataTraits; + +export function isTrait(value: unknown): value is Trait { + return (Object.keys(DS4.i18n.traits) as Array).includes(value); +} + +type DS4ActorDataSourceDataCombatValues = { + [Key in keyof typeof DS4.i18n.combatValues]: Key extends "hitPoints" + ? ResourceData + : ModifiableData; +}; + +type CombatValue = keyof DS4ActorDataSourceDataCombatValues; + +export function isCombatValue(value: string): value is CombatValue { + return (Object.keys(DS4.i18n.combatValues) as Array).includes(value); +} diff --git a/src/actor/actor-data-source.ts b/src/actor/actor-data-source.ts index 6fd6cabd..f0fd61fe 100644 --- a/src/actor/actor-data-source.ts +++ b/src/actor/actor-data-source.ts @@ -1,12 +1,9 @@ -// SPDX-FileCopyrightText: 2021 Johannes Loher -// SPDX-FileCopyrightText: 2021 Oliver Rümpelein -// SPDX-FileCopyrightText: 2021 Gesina Schwalbe -// SPDX-FileCopyrightText: 2021 Siegfried Krug +// SPDX-FileCopyrightText: 2022 Johannes Loher // // SPDX-License-Identifier: MIT -import { ModifiableData, ModifiableDataBase, ResourceData, UsableResource } from "../common/common-data"; -import { DS4 } from "../config"; +import type { DS4CharacterDataSource } from "./character/character-data-source"; +import type { DS4CreatureDataSource } from "./creature/creature-data-source"; declare global { interface SourceConfig { @@ -15,111 +12,3 @@ declare global { } export type DS4ActorDataSource = DS4CharacterDataSource | DS4CreatureDataSource; - -interface DS4CharacterDataSource { - type: "character"; - data: DS4CharacterDataSourceData; -} - -interface DS4CreatureDataSource { - type: "creature"; - data: DS4CreatureDataSourceData; -} - -// templates - -interface DS4ActorDataSourceDataBase { - attributes: DS4ActorDataSourceDataAttributes; - traits: DS4ActorDataSourceDataTraits; - combatValues: DS4ActorDataSourceDataCombatValues; -} - -type DS4ActorDataSourceDataAttributes = { [Key in keyof typeof DS4.i18n.attributes]: ModifiableDataBase }; - -type Attribute = keyof DS4ActorDataSourceDataAttributes; - -export function isAttribute(value: unknown): value is Attribute { - return (Object.keys(DS4.i18n.attributes) as Array).includes(value); -} - -type DS4ActorDataSourceDataTraits = { [Key in keyof typeof DS4.i18n.traits]: ModifiableDataBase }; - -type Trait = keyof DS4ActorDataSourceDataTraits; - -export function isTrait(value: unknown): value is Trait { - return (Object.keys(DS4.i18n.traits) as Array).includes(value); -} - -type DS4ActorDataSourceDataCombatValues = { - [Key in keyof typeof DS4.i18n.combatValues]: Key extends "hitPoints" - ? ResourceData - : ModifiableData; -}; - -type CombatValue = keyof DS4ActorDataSourceDataCombatValues; - -export function isCombatValue(value: string): value is CombatValue { - return (Object.keys(DS4.i18n.combatValues) as Array).includes(value); -} - -// types - -interface DS4CreatureDataSourceData extends DS4ActorDataSourceDataBase { - baseInfo: DS4CreatureDataSourceDataBaseInfo; -} - -export interface DS4CreatureDataSourceDataBaseInfo { - loot: string; - foeFactor: number; - creatureType: CreatureType; - sizeCategory: SizeCategory; - experiencePoints: number; - description: string; -} - -type CreatureType = keyof typeof DS4.i18n.creatureTypes; - -type SizeCategory = keyof typeof DS4.i18n.creatureSizeCategories; - -interface DS4CharacterDataSourceData extends DS4ActorDataSourceDataBase { - baseInfo: DS4CharacterDataSourceDataBaseInfo; - progression: DS4CharacterDataSourceDataProgression; - profile: DS4CharacterDataSourceDataProfile; - currency: DS4CharacterDataSourceDataCurrency; - slayerPoints: DS4CharacterDataSourceDataSlayerPoints; -} -export interface DS4CharacterDataSourceDataBaseInfo { - race: string; - class: string; - heroClass: string; - culture: string; -} -export interface DS4CharacterDataSourceDataProgression { - level: number; - experiencePoints: number; - talentPoints: UsableResource; - progressPoints: UsableResource; -} - -export interface DS4CharacterDataSourceDataProfile { - biography: string; - gender: string; - birthday: string; - birthplace: string; - age: number; - height: number; - hairColor: string; - weight: number; - eyeColor: string; - specialCharacteristics: string; -} - -export interface DS4CharacterDataSourceDataCurrency { - gold: number; - silver: number; - copper: number; -} - -export interface DS4CharacterDataSourceDataSlayerPoints { - value: number; -} diff --git a/src/actor/sheets/actor-sheet.ts b/src/actor/actor-sheet.ts similarity index 97% rename from src/actor/sheets/actor-sheet.ts rename to src/actor/actor-sheet.ts index f4a56713..517af2ee 100644 --- a/src/actor/sheets/actor-sheet.ts +++ b/src/actor/actor-sheet.ts @@ -5,15 +5,17 @@ // // SPDX-License-Identifier: MIT -import { DS4ActiveEffect } from "../../active-effect"; -import { ModifiableDataBaseTotal } from "../../common/common-data"; -import { DS4 } from "../../config"; -import { getCanvas, getGame } from "../../helpers"; -import type { DS4Item } from "../../item/item"; -import { DS4Settings, getDS4Settings } from "../../settings"; -import notifications from "../../ui/notifications"; -import { enforce } from "../../utils"; -import { isCheck } from "../actor-data-properties"; +import { DS4ActiveEffect } from "../active-effect"; +import { DS4 } from "../config"; +import { getCanvas, getGame } from "../helpers"; +import { getDS4Settings } from "../settings"; +import notifications from "../ui/notifications"; +import { enforce } from "../utils"; +import { isCheck } from "./actor-data-properties-base"; + +import type { ModifiableDataBaseTotal } from "../common/common-data"; +import type { DS4Settings } from "../settings"; +import type { DS4Item } from "../item/item"; /** * The base sheet class for all {@link DS4Actor}s. diff --git a/src/actor/actor.ts b/src/actor/actor.ts index 9ed12857..ecad7f40 100644 --- a/src/actor/actor.ts +++ b/src/actor/actor.ts @@ -3,15 +3,17 @@ // // SPDX-License-Identifier: MIT -import { ModifiableDataBaseTotal } from "../common/common-data"; import { DS4 } from "../config"; import { getGame } from "../helpers"; -import { DS4Item } from "../item/item"; -import { DS4ArmorDataProperties, DS4ShieldDataProperties } from "../item/item-data-properties"; -import { ItemType } from "../item/item-data-source"; import { createCheckRoll } from "../rolls/check-factory"; -import { Check } from "./actor-data-properties"; -import { isAttribute, isTrait } from "./actor-data-source"; +import { isAttribute, isTrait } from "./actor-data-source-base"; + +import type { ModifiableDataBaseTotal } from "../common/common-data"; +import type { DS4ArmorDataProperties } from "../item/armor/armor-data-properties"; +import type { DS4Item } from "../item/item"; +import type { ItemType } from "../item/item-data-source"; +import type { DS4ShieldDataProperties } from "../item/shield/shield-data-properties"; +import type { Check } from "./actor-data-properties-base"; declare global { interface DocumentClassConfig { @@ -157,9 +159,6 @@ export class DS4Actor extends Actor { this.data.data.combatValues.hitPoints.max = this.data.data.combatValues.hitPoints.total; this.data.data.checks.defend = this.data.data.combatValues.defense.total; - if (this.data.type === "character") { - this.data.data.slayerPoints.max = 3; - } } /** @@ -167,32 +166,14 @@ export class DS4Actor extends Actor { * given in dot notation. */ get finalDerivedDataProperties(): string[] { - return ["data.combatValues.hitPoints.max", "data.checks.defend"].concat( - this.data.type === "character" ? ["data.slayerPoints.max"] : [], - ); + return ["data.combatValues.hitPoints.max", "data.checks.defend"]; } /** * The list of item types that can be owned by this actor. */ get ownableItemTypes(): Array { - switch (this.data.type) { - case "character": - return [ - "weapon", - "armor", - "shield", - "equipment", - "loot", - "spell", - "talent", - "racialAbility", - "language", - "alphabet", - ]; - case "creature": - return ["weapon", "armor", "shield", "equipment", "loot", "spell", "specialCreatureAbility"]; - } + return ["weapon", "armor", "shield", "equipment", "loot", "spell"]; } /** diff --git a/src/actor/character/character-data-properties.ts b/src/actor/character/character-data-properties.ts new file mode 100644 index 00000000..515d0319 --- /dev/null +++ b/src/actor/character/character-data-properties.ts @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { DS4ActorDataPropertiesDataBase } from "../actor-data-properties-base"; +import type { + DS4CharacterDataSourceDataBaseInfo, + DS4CharacterDataSourceDataCurrency, + DS4CharacterDataSourceDataProfile, + DS4CharacterDataSourceDataProgression, + DS4CharacterDataSourceDataSlayerPoints, +} from "./character-data-source"; + +export interface DS4CharacterDataProperties { + type: "character"; + data: DS4CharacterDataPropertiesData; +} + +interface DS4CharacterDataPropertiesData extends DS4ActorDataPropertiesDataBase { + baseInfo: DS4CharacterDataSourceDataBaseInfo; + progression: DS4CharacterDataSourceDataProgression; + profile: DS4CharacterDataSourceDataProfile; + currency: DS4CharacterDataSourceDataCurrency; + slayerPoints: DS4CharacterDataPropertiesDataSlayerPoints; +} + +export interface DS4CharacterDataPropertiesDataSlayerPoints extends DS4CharacterDataSourceDataSlayerPoints { + max: number; +} diff --git a/src/actor/character/character-data-source.ts b/src/actor/character/character-data-source.ts new file mode 100644 index 00000000..69192285 --- /dev/null +++ b/src/actor/character/character-data-source.ts @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { UsableResource } from "../../common/common-data"; +import type { DS4ActorDataSourceDataBase } from "../actor-data-source-base"; + +export interface DS4CharacterDataSource { + type: "character"; + data: DS4CharacterDataSourceData; +} + +interface DS4CharacterDataSourceData extends DS4ActorDataSourceDataBase { + baseInfo: DS4CharacterDataSourceDataBaseInfo; + progression: DS4CharacterDataSourceDataProgression; + profile: DS4CharacterDataSourceDataProfile; + currency: DS4CharacterDataSourceDataCurrency; + slayerPoints: DS4CharacterDataSourceDataSlayerPoints; +} + +export interface DS4CharacterDataSourceDataBaseInfo { + race: string; + class: string; + heroClass: string; + culture: string; +} + +export interface DS4CharacterDataSourceDataProgression { + level: number; + experiencePoints: number; + talentPoints: UsableResource; + progressPoints: UsableResource; +} + +export interface DS4CharacterDataSourceDataProfile { + biography: string; + gender: string; + birthday: string; + birthplace: string; + age: number; + height: number; + hairColor: string; + weight: number; + eyeColor: string; + specialCharacteristics: string; +} + +export interface DS4CharacterDataSourceDataCurrency { + gold: number; + silver: number; + copper: number; +} + +export interface DS4CharacterDataSourceDataSlayerPoints { + value: number; +} diff --git a/src/actor/sheets/character-sheet.ts b/src/actor/character/character-sheet.ts similarity index 89% rename from src/actor/sheets/character-sheet.ts rename to src/actor/character/character-sheet.ts index fe7f6bba..04f19ab8 100644 --- a/src/actor/sheets/character-sheet.ts +++ b/src/actor/character/character-sheet.ts @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: MIT -import { DS4ActorSheet } from "./actor-sheet"; +import { DS4ActorSheet } from "../actor-sheet"; /** * The Sheet class for DS4 Character Actors diff --git a/src/actor/character/character.ts b/src/actor/character/character.ts new file mode 100644 index 00000000..b8dd87a6 --- /dev/null +++ b/src/actor/character/character.ts @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import { DS4Actor } from "../actor"; + +import type { ItemType } from "../../item/item-data-source"; + +export class DS4Character extends DS4Actor { + /** @override */ + prepareFinalDerivedData(): void { + super.prepareFinalDerivedData(); + this.data.data.slayerPoints.max = 3; + } + + /** @override */ + get finalDerivedDataProperties(): string[] { + return [...super.finalDerivedDataProperties, "data.slayerPoints.max"]; + } + + /** @override */ + get ownableItemTypes(): Array { + return [...super.ownableItemTypes, "talent", "racialAbility", "language", "alphabet"]; + } +} + +export interface DS4Character { + data: foundry.data.ActorData & { type: "character"; _source: { type: "character" } }; +} diff --git a/src/actor/creature/creature-data-properties.ts b/src/actor/creature/creature-data-properties.ts new file mode 100644 index 00000000..63ac946b --- /dev/null +++ b/src/actor/creature/creature-data-properties.ts @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { DS4ActorDataPropertiesDataBase } from "../actor-data-properties-base"; +import type { DS4CreatureDataSourceDataBaseInfo } from "./creature-data-source"; + +export interface DS4CreatureDataProperties { + type: "creature"; + data: DS4CreatureDataPropertiesData; +} + +interface DS4CreatureDataPropertiesData extends DS4ActorDataPropertiesDataBase { + baseInfo: DS4CreatureDataSourceDataBaseInfo; +} diff --git a/src/actor/creature/creature-data-source.ts b/src/actor/creature/creature-data-source.ts new file mode 100644 index 00000000..6d01ccbe --- /dev/null +++ b/src/actor/creature/creature-data-source.ts @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { DS4 } from "../../config"; +import type { DS4ActorDataSourceDataBase } from "../actor-data-source-base"; + +export interface DS4CreatureDataSource { + type: "creature"; + data: DS4CreatureDataSourceData; +} + +interface DS4CreatureDataSourceData extends DS4ActorDataSourceDataBase { + baseInfo: DS4CreatureDataSourceDataBaseInfo; +} + +export interface DS4CreatureDataSourceDataBaseInfo { + loot: string; + foeFactor: number; + creatureType: CreatureType; + sizeCategory: SizeCategory; + experiencePoints: number; + description: string; +} + +type CreatureType = keyof typeof DS4.i18n.creatureTypes; + +type SizeCategory = keyof typeof DS4.i18n.creatureSizeCategories; diff --git a/src/actor/sheets/creature-sheet.ts b/src/actor/creature/creature-sheet.ts similarity index 89% rename from src/actor/sheets/creature-sheet.ts rename to src/actor/creature/creature-sheet.ts index 323d8377..94aa940d 100644 --- a/src/actor/sheets/creature-sheet.ts +++ b/src/actor/creature/creature-sheet.ts @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: MIT -import { DS4ActorSheet } from "./actor-sheet"; +import { DS4ActorSheet } from "../actor-sheet"; /** * The Sheet class for DS4 Creature Actors diff --git a/src/actor/creature/creature.ts b/src/actor/creature/creature.ts new file mode 100644 index 00000000..f6ae06a7 --- /dev/null +++ b/src/actor/creature/creature.ts @@ -0,0 +1,18 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import { DS4Actor } from "../actor"; + +import type { ItemType } from "../../item/item-data-source"; + +export class DS4Creature extends DS4Actor { + /** @override */ + get ownableItemTypes(): Array { + return [...super.ownableItemTypes, "specialCreatureAbility"]; + } +} + +export interface DS4Creature { + data: foundry.data.ActorData & { type: "creature"; _source: { type: "creature" } }; +} diff --git a/src/actor/proxy.ts b/src/actor/proxy.ts new file mode 100644 index 00000000..51ca02f2 --- /dev/null +++ b/src/actor/proxy.ts @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import { getGame } from "../helpers"; +import { DS4Actor } from "./actor"; +import { DS4Character } from "./character/character"; +import { DS4Creature } from "./creature/creature"; + +const handler = { + construct(_: typeof DS4Actor, args: ConstructorParameters) { + switch (args[0]?.type) { + case "character": + return new DS4Character(...args); + case "creature": + return new DS4Creature(...args); + default: + throw new Error(getGame().i18n.format("DS4.ErrorInvalidActorType", { type: args[0]?.type })); + } + }, +}; + +export const DS4ActorProxy: typeof DS4Actor = new Proxy(DS4Actor, handler); diff --git a/src/ds4.ts b/src/ds4.ts index 285b2bfd..57f61604 100644 --- a/src/ds4.ts +++ b/src/ds4.ts @@ -3,6 +3,7 @@ // SPDX-License-Identifier: MIT import "../scss/ds4.scss"; + import registerForHooks from "./hooks/hooks"; registerForHooks(); diff --git a/src/hooks/hotbar-drop.ts b/src/hooks/hotbar-drop.ts index ac4e621a..efc8d719 100644 --- a/src/hooks/hotbar-drop.ts +++ b/src/hooks/hotbar-drop.ts @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: MIT -import { isCheck } from "../actor/actor-data-properties"; +import { isCheck } from "../actor/actor-data-properties-base"; import { getGame } from "../helpers"; import { DS4Item } from "../item/item"; import { createRollCheckMacro } from "../macros/roll-check"; diff --git a/src/hooks/init.ts b/src/hooks/init.ts index 45264fe4..ee2f8870 100644 --- a/src/hooks/init.ts +++ b/src/hooks/init.ts @@ -5,17 +5,17 @@ // SPDX-License-Identifier: MIT import { DS4ActiveEffect } from "../active-effect"; -import { DS4Actor } from "../actor/actor"; -import { DS4CharacterActorSheet } from "../actor/sheets/character-sheet"; -import { DS4CreatureActorSheet } from "../actor/sheets/creature-sheet"; +import { DS4CharacterActorSheet } from "../actor/character/character-sheet"; +import { DS4CreatureActorSheet } from "../actor/creature/creature-sheet"; +import { DS4ActorProxy } from "../actor/proxy"; import { DS4ChatMessage } from "../chat-message"; import { DS4 } from "../config"; -import { preloadFonts as preloadFonts } from "../fonts"; +import { preloadFonts } from "../fonts"; import registerHandlebarsHelpers from "../handlebars/handlebars-helpers"; import registerHandlebarsPartials from "../handlebars/handlebars-partials"; import { getGame } from "../helpers"; -import { DS4Item } from "../item/item"; import { DS4ItemSheet } from "../item/item-sheet"; +import { DS4ItemProxy } from "../item/proxy"; import logger from "../logger"; import { macros } from "../macros/macros"; import { migration } from "../migrations"; @@ -26,6 +26,9 @@ import registerSlayingDiceModifier from "../rolls/slaying-dice-modifier"; import { registerSystemSettings } from "../settings"; import { DS4TokenDocument } from "../token-document"; +import type { DS4Actor } from "../actor/actor"; +import type { DS4Item } from "../item/item"; + export default function registerForInitHook(): void { Hooks.once("init", init); } @@ -34,8 +37,8 @@ async function init() { logger.info(`Initializing the DS4 Game System\n${DS4.ASCII}`); getGame().ds4 = { - DS4Actor, - DS4Item, + DS4Actor: DS4ActorProxy, + DS4Item: DS4ItemProxy, DS4, createCheckRoll, migration, @@ -44,8 +47,8 @@ async function init() { CONFIG.DS4 = DS4; - CONFIG.Actor.documentClass = DS4Actor; - CONFIG.Item.documentClass = DS4Item; + CONFIG.Actor.documentClass = DS4ActorProxy; + CONFIG.Item.documentClass = DS4ItemProxy; CONFIG.ActiveEffect.documentClass = DS4ActiveEffect; CONFIG.ChatMessage.documentClass = DS4ChatMessage; CONFIG.Token.documentClass = DS4TokenDocument; diff --git a/src/hooks/render.ts b/src/hooks/render.ts index 547f80e2..14a7f689 100644 --- a/src/hooks/render.ts +++ b/src/hooks/render.ts @@ -20,9 +20,7 @@ export default function registerForRenderHooks(): void { * @param html - The {@link JQuery} representing the HTML of the application. */ function selectTargetInputOnFocus(app: Application, html: JQuery) { - $(html) - .find("input") - .on("focus", (ev: JQuery.FocusEvent) => { - ev.currentTarget.select(); - }); + html.find("input").on("focus", (ev: JQuery.FocusEvent) => { + ev.currentTarget.select(); + }); } diff --git a/src/item/alphabet/alphabet-data-properties.ts b/src/item/alphabet/alphabet-data-properties.ts new file mode 100644 index 00000000..b66becb8 --- /dev/null +++ b/src/item/alphabet/alphabet-data-properties.ts @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2021 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { DS4ItemDataPropertiesDataRollable } from "../item-data-properties-base"; +import type { DS4AlphabetDataSourceData } from "./alphabet-data-source"; + +export interface DS4AlphabetDataProperties { + type: "alphabet"; + data: DS4AlphabetDataPropertiesData; +} + +interface DS4AlphabetDataPropertiesData extends DS4AlphabetDataSourceData, DS4ItemDataPropertiesDataRollable {} diff --git a/src/item/alphabet/alphabet-data-source.ts b/src/item/alphabet/alphabet-data-source.ts new file mode 100644 index 00000000..291e1504 --- /dev/null +++ b/src/item/alphabet/alphabet-data-source.ts @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { DS4ItemDataSourceDataBase } from "../item-data-source-base"; + +export interface DS4AlphabetDataSource { + type: "alphabet"; + data: DS4AlphabetDataSourceData; +} + +export type DS4AlphabetDataSourceData = DS4ItemDataSourceDataBase; diff --git a/src/item/alphabet/alphabet.ts b/src/item/alphabet/alphabet.ts new file mode 100644 index 00000000..d710b896 --- /dev/null +++ b/src/item/alphabet/alphabet.ts @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import { DS4Item } from "../item"; + +export class DS4Alphabet extends DS4Item {} + +export interface DS4Alphabet { + data: foundry.data.ItemData & { type: "alphabet"; _source: { type: "alphabet" } }; +} diff --git a/src/item/armor/armor-data-properties.ts b/src/item/armor/armor-data-properties.ts new file mode 100644 index 00000000..0166f01e --- /dev/null +++ b/src/item/armor/armor-data-properties.ts @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { DS4ItemDataPropertiesDataRollable } from "../item-data-properties-base"; +import type { DS4ArmorDataSourceData } from "./armor-data-source"; + +export interface DS4ArmorDataProperties { + type: "armor"; + data: DS4ArmorDataPropertiesData; +} + +interface DS4ArmorDataPropertiesData extends DS4ArmorDataSourceData, DS4ItemDataPropertiesDataRollable {} diff --git a/src/item/armor/armor-data-source.ts b/src/item/armor/armor-data-source.ts new file mode 100644 index 00000000..e19f8a06 --- /dev/null +++ b/src/item/armor/armor-data-source.ts @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { DS4 } from "../../config"; +import type { + DS4ItemDataSourceDataBase, + DS4ItemDataSourceDataEquipable, + DS4ItemDataSourceDataPhysical, + DS4ItemDataSourceDataProtective, +} from "../item-data-source-base"; + +export interface DS4ArmorDataSource { + type: "armor"; + data: DS4ArmorDataSourceData; +} + +export interface DS4ArmorDataSourceData + extends DS4ItemDataSourceDataBase, + DS4ItemDataSourceDataPhysical, + DS4ItemDataSourceDataEquipable, + DS4ItemDataSourceDataProtective { + armorMaterialType: keyof typeof DS4.i18n.armorMaterialTypes; + armorType: keyof typeof DS4.i18n.armorTypes; +} diff --git a/src/item/armor/armor.ts b/src/item/armor/armor.ts new file mode 100644 index 00000000..9c18fb6e --- /dev/null +++ b/src/item/armor/armor.ts @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import { DS4Item } from "../item"; + +export class DS4Armor extends DS4Item {} + +export interface DS4Armor { + data: foundry.data.ItemData & { type: "armor"; _source: { type: "armor" } }; +} diff --git a/src/item/equipment/equipment-data-properties.ts b/src/item/equipment/equipment-data-properties.ts new file mode 100644 index 00000000..5852842f --- /dev/null +++ b/src/item/equipment/equipment-data-properties.ts @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2021 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { DS4ItemDataPropertiesDataRollable } from "../item-data-properties-base"; +import type { DS4EquipmentDataSourceData } from "./equipment-data-source"; + +export interface DS4EquipmentDataProperties { + type: "equipment"; + data: DS4EquipmentDataPropertiesData; +} + +interface DS4EquipmentDataPropertiesData extends DS4EquipmentDataSourceData, DS4ItemDataPropertiesDataRollable {} diff --git a/src/item/equipment/equipment-data-source.ts b/src/item/equipment/equipment-data-source.ts new file mode 100644 index 00000000..6db28e7f --- /dev/null +++ b/src/item/equipment/equipment-data-source.ts @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { + DS4ItemDataSourceDataBase, + DS4ItemDataSourceDataEquipable, + DS4ItemDataSourceDataPhysical, +} from "../item-data-source-base"; + +export interface DS4EquipmentDataSource { + type: "equipment"; + data: DS4EquipmentDataSourceData; +} + +export interface DS4EquipmentDataSourceData + extends DS4ItemDataSourceDataBase, + DS4ItemDataSourceDataPhysical, + DS4ItemDataSourceDataEquipable {} diff --git a/src/item/equipment/equipment.ts b/src/item/equipment/equipment.ts new file mode 100644 index 00000000..f5e7d455 --- /dev/null +++ b/src/item/equipment/equipment.ts @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import { DS4Item } from "../item"; + +export class DS4Equipment extends DS4Item {} + +export interface DS4Equipment { + data: foundry.data.ItemData & { type: "equipment"; _source: { type: "equipment" } }; +} diff --git a/src/item/item-data-properties-base.ts b/src/item/item-data-properties-base.ts new file mode 100644 index 00000000..a8a38380 --- /dev/null +++ b/src/item/item-data-properties-base.ts @@ -0,0 +1,7 @@ +// SPDX-FileCopyrightText: 2021 Johannes Loher +// +// SPDX-License-Identifier: MIT + +export interface DS4ItemDataPropertiesDataRollable { + rollable: boolean; +} diff --git a/src/item/item-data-properties.ts b/src/item/item-data-properties.ts index 3dcda46f..6e7125e7 100644 --- a/src/item/item-data-properties.ts +++ b/src/item/item-data-properties.ts @@ -1,21 +1,18 @@ -// SPDX-FileCopyrightText: 2021 Johannes Loher +// SPDX-FileCopyrightText: 2022 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"; +import type { DS4AlphabetDataProperties } from "./alphabet/alphabet-data-properties"; +import type { DS4ArmorDataProperties } from "./armor/armor-data-properties"; +import type { DS4EquipmentDataProperties } from "./equipment/equipment-data-properties"; +import type { DS4LanguageDataProperties } from "./language/language-data-properties"; +import type { DS4LootDataProperties } from "./loot/loot-data-properties"; +import type { DS4RacialAbilityDataProperties } from "./racial-ability/racial-ability-data-properties"; +import type { DS4ShieldDataProperties } from "./shield/shield-data-properties"; +import type { DS4SpecialCreatureAbilityDataProperties } from "./special-creature-ability/special-creature-ability-data-properties"; +import type { DS4SpellDataProperties } from "./spell/spell-data-properties"; +import type { DS4TalentDataProperties } from "./talent/talent-data-properties"; +import type { DS4WeaponDataProperties } from "./weapon/weapon-data-properties"; declare global { interface DataConfig { @@ -24,107 +21,14 @@ declare global { } 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; -} - -interface DS4RacialAbilityDataPropertiesData - extends DS4RacialAbilityDataSourceData, - DS4ItemDataPropertiesDataRollable {} - -interface DS4LanguageDataPropertiesData extends DS4LanguageDataSourceData, DS4ItemDataPropertiesDataRollable {} - -interface DS4AlphabetDataPropertiesData extends DS4AlphabetDataSourceData, DS4ItemDataPropertiesDataRollable {} - -interface DS4SpecialCreatureAbilityDataPropertiesData - extends DS4SpecialCreatureAbilityDataSourceData, - DS4ItemDataPropertiesDataRollable {} + | DS4ArmorDataProperties + | DS4EquipmentDataProperties + | DS4LanguageDataProperties + | DS4LootDataProperties + | DS4RacialAbilityDataProperties + | DS4ShieldDataProperties + | DS4SpecialCreatureAbilityDataProperties + | DS4SpellDataProperties + | DS4TalentDataProperties + | DS4WeaponDataProperties; diff --git a/src/item/item-data-source-base.ts b/src/item/item-data-source-base.ts new file mode 100644 index 00000000..ce801d31 --- /dev/null +++ b/src/item/item-data-source-base.ts @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: 2021 Johannes Loher +// SPDX-FileCopyrightText: 2021 Oliver Rümpelein +// SPDX-FileCopyrightText: 2021 Gesina Schwalbe +// +// SPDX-License-Identifier: MIT + +import type { DS4 } from "../config"; + +export interface DS4ItemDataSourceDataBase { + description: string; +} + +export 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; +} + +export interface DS4ItemDataSourceDataEquipable { + equipped: boolean; +} + +export interface DS4ItemDataSourceDataProtective { + armorValue: number; +} diff --git a/src/item/item-data-source.ts b/src/item/item-data-source.ts index f75dafa5..ab4cf950 100644 --- a/src/item/item-data-source.ts +++ b/src/item/item-data-source.ts @@ -1,11 +1,19 @@ -// SPDX-FileCopyrightText: 2021 Johannes Loher -// SPDX-FileCopyrightText: 2021 Oliver Rümpelein -// SPDX-FileCopyrightText: 2021 Gesina Schwalbe +// SPDX-FileCopyrightText: 2022 Johannes Loher // // SPDX-License-Identifier: MIT -import { ModifiableDataBaseMax } from "../common/common-data"; -import { DS4 } from "../config"; +import type { DS4 } from "../config"; +import type { DS4AlphabetDataSource } from "./alphabet/alphabet-data-source"; +import type { DS4ArmorDataSource } from "./armor/armor-data-source"; +import type { DS4EquipmentDataSource } from "./equipment/equipment-data-source"; +import type { DS4LanguageDataSource } from "./language/language-data-source"; +import type { DS4LootDataSource } from "./loot/loot-data-source"; +import type { DS4RacialAbilityDataSource } from "./racial-ability/racial-ability-data-source"; +import type { DS4ShieldDataSource } from "./shield/shield-data-source"; +import type { DS4SpecialCreatureAbilityDataSource } from "./special-creature-ability/special-creature-ability-data-source"; +import type { DS4SpellDataSource } from "./spell/spell-data-source"; +import type { DS4TalentDataSource } from "./talent/talent-data-source"; +import type { DS4WeaponDataSource } from "./weapon/weapon-data-source"; declare global { interface SourceConfig { @@ -16,169 +24,14 @@ declare global { 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 type CooldownDuration = keyof typeof DS4.i18n.cooldownDurations; - -export interface DS4SpellDataSourceData extends DS4ItemDataSourceDataBase, DS4ItemDataSourceDataEquipable { - spellType: keyof typeof DS4.i18n.spellTypes; - bonus: string; - spellCategory: keyof typeof DS4.i18n.spellCategories; - maxDistance: UnitData; - effectRadius: UnitData; - duration: UnitData; - cooldownDuration: CooldownDuration; - minimumLevels: { - healer: number | null; - wizard: number | null; - sorcerer: number | null; - }; -} - -export interface UnitData { - value: string; - unit: UnitType; -} - -type DistanceUnit = keyof typeof DS4.i18n.distanceUnits; - -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; -} - -export type DS4RacialAbilityDataSourceData = DS4ItemDataSourceDataBase; - -export type DS4LanguageDataSourceData = DS4ItemDataSourceDataBase; - -export type DS4AlphabetDataSourceData = DS4ItemDataSourceDataBase; - -export interface DS4SpecialCreatureAbilityDataSourceData extends DS4ItemDataSourceDataBase { - experiencePoints: number; -} + | DS4ArmorDataSource + | DS4EquipmentDataSource + | DS4LanguageDataSource + | DS4LootDataSource + | DS4RacialAbilityDataSource + | DS4ShieldDataSource + | DS4SpecialCreatureAbilityDataSource + | DS4SpellDataSource + | DS4TalentDataSource + | DS4WeaponDataSource; diff --git a/src/item/item-sheet.ts b/src/item/item-sheet.ts index 77fac4af..245b1cfe 100644 --- a/src/item/item-sheet.ts +++ b/src/item/item-sheet.ts @@ -9,7 +9,7 @@ import { DS4 } from "../config"; import { getGame } from "../helpers"; import notifications from "../ui/notifications"; import { enforce } from "../utils"; -import { isDS4ItemDataTypePhysical } from "./item-data-source"; +import { isDS4ItemDataTypePhysical } from "./item-data-source-base"; /** * The Sheet class for DS4 Items diff --git a/src/item/item.ts b/src/item/item.ts index ed875897..d3041604 100644 --- a/src/item/item.ts +++ b/src/item/item.ts @@ -3,12 +3,9 @@ // // SPDX-License-Identifier: MIT -import { DS4 } from "../config"; import { getGame } from "../helpers"; -import { createCheckRoll } from "../rolls/check-factory"; -import notifications from "../ui/notifications"; -import { AttackType, ItemType } from "./item-data-source"; -import { calculateSpellPrice } from "./type-specific-helpers/spell"; + +import type { ItemType } from "./item-data-source"; declare global { interface DocumentClassConfig { @@ -27,18 +24,7 @@ export class DS4Item extends Item { /** @override */ prepareDerivedData(): void { - if (this.data.type === "talent") { - const data = this.data.data; - data.rank.total = data.rank.base + data.rank.mod; - } - if (this.data.type === "weapon" || this.data.type === "spell") { - this.data.data.rollable = this.data.data.equipped; - } else { - this.data.data.rollable = false; - } - if (this.data.type === "spell") { - this.data.data.price = calculateSpellPrice(this.data.data); - } + this.data.data.rollable = false; } isNonEquippedEuipable(): boolean { @@ -49,9 +35,6 @@ export class DS4Item extends Item { * The number of times that active effect changes originating from this item should be applied. */ get activeEffectFactor(): number | undefined { - if (this.data.type === "talent") { - return this.data.data.rank.total; - } return 1; } @@ -66,142 +49,8 @@ export class DS4Item extends Item { * Roll a check for an action with this item. * @param options - Additional options to customize the roll */ + // eslint-disable-next-line @typescript-eslint/no-unused-vars async roll(options: { speaker?: { token?: TokenDocument; alias?: string } } = {}): Promise { - switch (this.data.type) { - case "weapon": - return this.rollWeapon(options); - case "spell": - return this.rollSpell(options); - default: - throw new Error( - getGame().i18n.format("DS4.ErrorRollingForItemTypeNotPossible", { type: this.data.type }), - ); - } - } - - protected async rollWeapon(options: { speaker?: { token?: TokenDocument; alias?: string } } = {}): Promise { - if (!(this.data.type === "weapon")) { - throw new Error( - getGame().i18n.format("DS4.ErrorWrongItemType", { - actualType: this.data.type, - expectedType: "weapon", - id: this.id, - name: this.name, - }), - ); - } - - if (!this.data.data.equipped) { - return notifications.warn( - getGame().i18n.format("DS4.WarningItemMustBeEquippedToBeRolled", { - name: this.name, - id: this.id, - type: this.data.type, - }), - ); - } - - if (!this.actor) { - throw new Error(getGame().i18n.format("DS4.ErrorCannotRollUnownedItem", { name: this.name, id: this.id })); - } - - const ownerDataData = this.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; - - const speaker = ChatMessage.getSpeaker({ actor: this.actor, ...options.speaker }); - await createCheckRoll(checkTargetNumber, { - rollMode: getGame().settings.get("core", "rollMode"), - maximumCoupResult: ownerDataData.rolling.maximumCoupResult, - minimumFumbleResult: ownerDataData.rolling.minimumFumbleResult, - flavor: "DS4.ItemWeaponCheckFlavor", - flavorData: { actor: speaker.alias ?? this.actor.name, weapon: this.name }, - speaker, - }); - } - - protected async rollSpell(options: { speaker?: { token?: TokenDocument; alias?: string } } = {}): Promise { - if (!(this.data.type === "spell")) { - throw new Error( - getGame().i18n.format("DS4.ErrorWrongItemType", { - actualType: this.data.type, - expectedType: "spell", - id: this.id, - name: this.name, - }), - ); - } - - if (!this.data.data.equipped) { - return notifications.warn( - getGame().i18n.format("DS4.WarningItemMustBeEquippedToBeRolled", { - name: this.name, - id: this.id, - type: this.data.type, - }), - ); - } - - if (!this.actor) { - throw new Error(getGame().i18n.format("DS4.ErrorCannotRollUnownedItem", { name: this.name, id: this.id })); - } - - const ownerDataData = this.actor.data.data; - const spellModifier = Number.isNumeric(this.data.data.bonus) ? parseInt(this.data.data.bonus) : undefined; - if (spellModifier === undefined) { - notifications.info( - getGame().i18n.format("DS4.InfoManuallyEnterSpellModifier", { - name: this.name, - spellModifier: this.data.data.bonus, - }), - ); - } - const spellType = this.data.data.spellType; - const checkTargetNumber = ownerDataData.combatValues[spellType].total + (spellModifier ?? 0); - - const speaker = ChatMessage.getSpeaker({ actor: this.actor, ...options.speaker }); - await createCheckRoll(checkTargetNumber, { - rollMode: getGame().settings.get("core", "rollMode"), - maximumCoupResult: ownerDataData.rolling.maximumCoupResult, - minimumFumbleResult: ownerDataData.rolling.minimumFumbleResult, - flavor: "DS4.ItemSpellCheckFlavor", - flavorData: { actor: speaker.alias ?? this.actor.name, spell: this.name }, - speaker, - }); - } - - protected async getCombatValueKeyForAttackType(attackType: AttackType): Promise<"meleeAttack" | "rangedAttack"> { - if (attackType === "meleeRanged") { - const { melee, ranged } = { ...DS4.i18n.attackTypes }; - const identifier = "attack-type-selection"; - return Dialog.prompt({ - title: getGame().i18n.localize("DS4.DialogAttackTypeSelection"), - content: await renderTemplate("systems/ds4/templates/dialogs/simple-select-form.hbs", { - selects: [ - { - label: getGame().i18n.localize("DS4.AttackType"), - identifier, - options: { melee, ranged }, - }, - ], - }), - label: getGame().i18n.localize("DS4.GenericOkButton"), - callback: (html) => { - const selectedAttackType = html.find(`#${identifier}`).val(); - if (selectedAttackType !== "melee" && selectedAttackType !== "ranged") { - throw new Error( - getGame().i18n.format("DS4.ErrorUnexpectedAttackType", { - actualType: selectedAttackType, - expectedTypes: "'melee', 'ranged'", - }), - ); - } - return `${selectedAttackType}Attack` as const; - }, - }); - } else { - return `${attackType}Attack` as const; - } + throw new Error(getGame().i18n.format("DS4.ErrorRollingForItemTypeNotPossible", { type: this.data.type })); } } diff --git a/src/item/language/language-data-properties.ts b/src/item/language/language-data-properties.ts new file mode 100644 index 00000000..963f3f66 --- /dev/null +++ b/src/item/language/language-data-properties.ts @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2021 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { DS4ItemDataPropertiesDataRollable } from "../item-data-properties-base"; +import type { DS4LanguageDataSourceData } from "./language-data-source"; + +export interface DS4LanguageDataProperties { + type: "language"; + data: DS4LanguageDataPropertiesData; +} + +interface DS4LanguageDataPropertiesData extends DS4LanguageDataSourceData, DS4ItemDataPropertiesDataRollable {} diff --git a/src/item/language/language-data-source.ts b/src/item/language/language-data-source.ts new file mode 100644 index 00000000..15b3d33d --- /dev/null +++ b/src/item/language/language-data-source.ts @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { DS4ItemDataSourceDataBase } from "../item-data-source-base"; + +export interface DS4LanguageDataSource { + type: "language"; + data: DS4LanguageDataSourceData; +} + +export type DS4LanguageDataSourceData = DS4ItemDataSourceDataBase; diff --git a/src/item/language/language.ts b/src/item/language/language.ts new file mode 100644 index 00000000..0faf53da --- /dev/null +++ b/src/item/language/language.ts @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import { DS4Item } from "../item"; + +export class DS4Language extends DS4Item {} + +export interface DS4Language { + data: foundry.data.ItemData & { type: "language"; _source: { type: "language" } }; +} diff --git a/src/item/loot/loot-data-properties.ts b/src/item/loot/loot-data-properties.ts new file mode 100644 index 00000000..71fd948f --- /dev/null +++ b/src/item/loot/loot-data-properties.ts @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2021 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { DS4ItemDataPropertiesDataRollable } from "../item-data-properties-base"; +import type { DS4LootDataSourceData } from "./loot-data-source"; + +export interface DS4LootDataProperties { + type: "loot"; + data: DS4LootDataPropertiesData; +} + +interface DS4LootDataPropertiesData extends DS4LootDataSourceData, DS4ItemDataPropertiesDataRollable {} diff --git a/src/item/loot/loot-data-source.ts b/src/item/loot/loot-data-source.ts new file mode 100644 index 00000000..9ebef459 --- /dev/null +++ b/src/item/loot/loot-data-source.ts @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { DS4ItemDataSourceDataBase, DS4ItemDataSourceDataPhysical } from "../item-data-source-base"; + +export interface DS4LootDataSource { + type: "loot"; + data: DS4LootDataSourceData; +} + +export interface DS4LootDataSourceData extends DS4ItemDataSourceDataBase, DS4ItemDataSourceDataPhysical {} diff --git a/src/item/loot/loot.ts b/src/item/loot/loot.ts new file mode 100644 index 00000000..34528207 --- /dev/null +++ b/src/item/loot/loot.ts @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import { DS4Item } from "../item"; + +export class DS4Loot extends DS4Item {} + +export interface DS4Loot { + data: foundry.data.ItemData & { type: "loot"; _source: { type: "loot" } }; +} diff --git a/src/item/proxy.ts b/src/item/proxy.ts new file mode 100644 index 00000000..58d4997f --- /dev/null +++ b/src/item/proxy.ts @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import { getGame } from "../helpers"; +import { DS4Alphabet } from "./alphabet/alphabet"; +import { DS4Armor } from "./armor/armor"; +import { DS4Equipment } from "./equipment/equipment"; +import { DS4Item } from "./item"; +import { DS4Language } from "./language/language"; +import { DS4Loot } from "./loot/loot"; +import { DS4RacialAbility } from "./racial-ability/racial-ability"; +import { DS4Shield } from "./shield/shield"; +import { DS4SpecialCreatureAbility } from "./special-creature-ability/special-creature-ability"; +import { DS4Spell } from "./spell/spell"; +import { DS4Talent } from "./talent/talent"; +import { DS4Weapon } from "./weapon/weapon"; + +const handler = { + construct(_: typeof DS4Item, args: ConstructorParameters) { + switch (args[0]?.type) { + case "alphabet": + return new DS4Alphabet(...args); + case "armor": + return new DS4Armor(...args); + case "equipment": + return new DS4Equipment(...args); + case "language": + return new DS4Language(...args); + case "loot": + return new DS4Loot(...args); + case "racialAbility": + return new DS4RacialAbility(...args); + case "shield": + return new DS4Shield(...args); + case "specialCreatureAbility": + return new DS4SpecialCreatureAbility(...args); + case "spell": + return new DS4Spell(...args); + case "talent": + return new DS4Talent(...args); + case "weapon": + return new DS4Weapon(...args); + default: + throw new Error(getGame().i18n.format("DS4.ErrorInvalidItemType", { type: args[0]?.type })); + } + }, +}; + +export const DS4ItemProxy: typeof DS4Item = new Proxy(DS4Item, handler); diff --git a/src/item/racial-ability/racial-ability-data-properties.ts b/src/item/racial-ability/racial-ability-data-properties.ts new file mode 100644 index 00000000..5592fe69 --- /dev/null +++ b/src/item/racial-ability/racial-ability-data-properties.ts @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: 2021 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { DS4ItemDataPropertiesDataRollable } from "../item-data-properties-base"; +import type { DS4RacialAbilityDataSourceData } from "./racial-ability-data-source"; + +export interface DS4RacialAbilityDataProperties { + type: "racialAbility"; + data: DS4RacialAbilityDataPropertiesData; +} + +interface DS4RacialAbilityDataPropertiesData + extends DS4RacialAbilityDataSourceData, + DS4ItemDataPropertiesDataRollable {} diff --git a/src/item/racial-ability/racial-ability-data-source.ts b/src/item/racial-ability/racial-ability-data-source.ts new file mode 100644 index 00000000..589775f5 --- /dev/null +++ b/src/item/racial-ability/racial-ability-data-source.ts @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { DS4ItemDataSourceDataBase } from "../item-data-source-base"; + +export interface DS4RacialAbilityDataSource { + type: "racialAbility"; + data: DS4RacialAbilityDataSourceData; +} + +export type DS4RacialAbilityDataSourceData = DS4ItemDataSourceDataBase; diff --git a/src/item/racial-ability/racial-ability.ts b/src/item/racial-ability/racial-ability.ts new file mode 100644 index 00000000..526f2533 --- /dev/null +++ b/src/item/racial-ability/racial-ability.ts @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import { DS4Item } from "../item"; + +export class DS4RacialAbility extends DS4Item {} + +export interface DS4RacialAbility { + data: foundry.data.ItemData & { type: "racialAbility"; _source: { type: "racialAbility" } }; +} diff --git a/src/item/shield/shield-data-properties.ts b/src/item/shield/shield-data-properties.ts new file mode 100644 index 00000000..a51b0512 --- /dev/null +++ b/src/item/shield/shield-data-properties.ts @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2021 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { DS4ItemDataPropertiesDataRollable } from "../item-data-properties-base"; +import type { DS4ShieldDataSourceData } from "./shield-data-source"; + +export interface DS4ShieldDataProperties { + type: "shield"; + data: DS4ShieldDataPropertiesData; +} + +interface DS4ShieldDataPropertiesData extends DS4ShieldDataSourceData, DS4ItemDataPropertiesDataRollable {} diff --git a/src/item/shield/shield-data-source.ts b/src/item/shield/shield-data-source.ts new file mode 100644 index 00000000..74cdda26 --- /dev/null +++ b/src/item/shield/shield-data-source.ts @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { + DS4ItemDataSourceDataBase, + DS4ItemDataSourceDataEquipable, + DS4ItemDataSourceDataPhysical, + DS4ItemDataSourceDataProtective, +} from "../item-data-source-base"; + +export interface DS4ShieldDataSource { + type: "shield"; + data: DS4ShieldDataSourceData; +} + +export interface DS4ShieldDataSourceData + extends DS4ItemDataSourceDataBase, + DS4ItemDataSourceDataPhysical, + DS4ItemDataSourceDataEquipable, + DS4ItemDataSourceDataProtective {} diff --git a/src/item/shield/shield.ts b/src/item/shield/shield.ts new file mode 100644 index 00000000..16a6e683 --- /dev/null +++ b/src/item/shield/shield.ts @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import { DS4Item } from "../item"; + +export class DS4Shield extends DS4Item {} + +export interface DS4Shield { + data: foundry.data.ItemData & { type: "shield"; _source: { type: "shield" } }; +} diff --git a/src/item/special-creature-ability/special-creature-ability-data-properties.ts b/src/item/special-creature-ability/special-creature-ability-data-properties.ts new file mode 100644 index 00000000..06f96d4a --- /dev/null +++ b/src/item/special-creature-ability/special-creature-ability-data-properties.ts @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: 2021 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { DS4ItemDataPropertiesDataRollable } from "../item-data-properties-base"; +import type { DS4SpecialCreatureAbilityDataSourceData } from "./special-creature-ability-data-source"; + +export interface DS4SpecialCreatureAbilityDataProperties { + type: "specialCreatureAbility"; + data: DS4SpecialCreatureAbilityDataPropertiesData; +} + +interface DS4SpecialCreatureAbilityDataPropertiesData + extends DS4SpecialCreatureAbilityDataSourceData, + DS4ItemDataPropertiesDataRollable {} diff --git a/src/item/special-creature-ability/special-creature-ability-data-source.ts b/src/item/special-creature-ability/special-creature-ability-data-source.ts new file mode 100644 index 00000000..1017a6f2 --- /dev/null +++ b/src/item/special-creature-ability/special-creature-ability-data-source.ts @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { DS4ItemDataSourceDataBase } from "../item-data-source-base"; + +export interface DS4SpecialCreatureAbilityDataSource { + type: "specialCreatureAbility"; + data: DS4SpecialCreatureAbilityDataSourceData; +} + +export interface DS4SpecialCreatureAbilityDataSourceData extends DS4ItemDataSourceDataBase { + experiencePoints: number; +} diff --git a/src/item/special-creature-ability/special-creature-ability.ts b/src/item/special-creature-ability/special-creature-ability.ts new file mode 100644 index 00000000..1919ae88 --- /dev/null +++ b/src/item/special-creature-ability/special-creature-ability.ts @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import { DS4Item } from "../item"; + +export class DS4SpecialCreatureAbility extends DS4Item {} + +export interface DS4SpecialCreatureAbility { + data: foundry.data.ItemData & { type: "specialCreatureAbility"; _source: { type: "specialCreatureAbility" } }; +} diff --git a/src/item/type-specific-helpers/spell.ts b/src/item/spell/calculate-spell-price.ts similarity index 93% rename from src/item/type-specific-helpers/spell.ts rename to src/item/spell/calculate-spell-price.ts index c9949996..caf3bc6c 100644 --- a/src/item/type-specific-helpers/spell.ts +++ b/src/item/spell/calculate-spell-price.ts @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: MIT -import { CooldownDuration, DS4SpellDataSourceData } from "../item-data-source"; +import type { CooldownDuration, DS4SpellDataSourceData } from "./spell-data-source"; export function calculateSpellPrice(data: DS4SpellDataSourceData): number | null { const spellPriceFactor = calculateSpellPriceFactor(data.cooldownDuration); diff --git a/src/item/spell/spell-data-properties.ts b/src/item/spell/spell-data-properties.ts new file mode 100644 index 00000000..874f0544 --- /dev/null +++ b/src/item/spell/spell-data-properties.ts @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: 2021 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { DS4ItemDataPropertiesDataRollable } from "../item-data-properties-base"; +import type { DS4SpellDataSourceData } from "./spell-data-source"; + +export interface DS4SpellDataProperties { + type: "spell"; + data: DS4SpellDataPropertiesData; +} + +interface DS4SpellDataPropertiesData extends DS4SpellDataSourceData, DS4ItemDataPropertiesDataRollable { + price: number | null; +} diff --git a/src/item/spell/spell-data-source.ts b/src/item/spell/spell-data-source.ts new file mode 100644 index 00000000..7c578dc9 --- /dev/null +++ b/src/item/spell/spell-data-source.ts @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { DS4 } from "../../config"; +import type { DS4ItemDataSourceDataBase, DS4ItemDataSourceDataEquipable } from "../item-data-source-base"; + +export interface DS4SpellDataSource { + type: "spell"; + data: DS4SpellDataSourceData; +} + +export interface DS4SpellDataSourceData extends DS4ItemDataSourceDataBase, DS4ItemDataSourceDataEquipable { + spellType: keyof typeof DS4.i18n.spellTypes; + bonus: string; + spellCategory: keyof typeof DS4.i18n.spellCategories; + maxDistance: UnitData; + effectRadius: UnitData; + duration: UnitData; + cooldownDuration: CooldownDuration; + minimumLevels: { + healer: number | null; + wizard: number | null; + sorcerer: number | null; + }; +} + +export interface UnitData { + value: string; + unit: UnitType; +} + +type DistanceUnit = keyof typeof DS4.i18n.distanceUnits; +type TemporalUnit = keyof typeof DS4.i18n.temporalUnits; +export type CooldownDuration = keyof typeof DS4.i18n.cooldownDurations; diff --git a/src/item/spell/spell.ts b/src/item/spell/spell.ts new file mode 100644 index 00000000..efcf8f1a --- /dev/null +++ b/src/item/spell/spell.ts @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import { getGame } from "../../helpers"; +import { createCheckRoll } from "../../rolls/check-factory"; +import notifications from "../../ui/notifications"; +import { DS4Item } from "../item"; +import { calculateSpellPrice } from "./calculate-spell-price"; + +export class DS4Spell extends DS4Item { + /** @override */ + prepareDerivedData(): void { + this.data.data.rollable = this.data.data.equipped; + this.data.data.price = calculateSpellPrice(this.data.data); + } + + /** @override */ + async roll(options: { speaker?: { token?: TokenDocument; alias?: string } } = {}): Promise { + const game = getGame(); + + if (!this.data.data.equipped) { + return notifications.warn( + game.i18n.format("DS4.WarningItemMustBeEquippedToBeRolled", { + name: this.name, + id: this.id, + type: this.data.type, + }), + ); + } + + if (!this.actor) { + throw new Error(game.i18n.format("DS4.ErrorCannotRollUnownedItem", { name: this.name, id: this.id })); + } + + const ownerDataData = this.actor.data.data; + const spellModifier = Number.isNumeric(this.data.data.bonus) ? parseInt(this.data.data.bonus) : undefined; + if (spellModifier === undefined) { + notifications.info( + game.i18n.format("DS4.InfoManuallyEnterSpellModifier", { + name: this.name, + spellModifier: this.data.data.bonus, + }), + ); + } + const spellType = this.data.data.spellType; + const checkTargetNumber = ownerDataData.combatValues[spellType].total + (spellModifier ?? 0); + + const speaker = ChatMessage.getSpeaker({ actor: this.actor, ...options.speaker }); + await createCheckRoll(checkTargetNumber, { + rollMode: game.settings.get("core", "rollMode"), + maximumCoupResult: ownerDataData.rolling.maximumCoupResult, + minimumFumbleResult: ownerDataData.rolling.minimumFumbleResult, + flavor: "DS4.ItemSpellCheckFlavor", + flavorData: { actor: speaker.alias ?? this.actor.name, spell: this.name }, + speaker, + }); + } +} + +export interface DS4Spell { + data: foundry.data.ItemData & { type: "spell"; _source: { type: "spell" } }; +} diff --git a/src/item/talent/talent-data-properties.ts b/src/item/talent/talent-data-properties.ts new file mode 100644 index 00000000..fe679226 --- /dev/null +++ b/src/item/talent/talent-data-properties.ts @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: 2021 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { ModifiableDataBaseTotalMax } from "../../common/common-data"; +import type { DS4ItemDataPropertiesDataRollable } from "../item-data-properties-base"; +import type { DS4TalentDataSourceData } from "./talent-data-source"; + +export interface DS4TalentDataProperties { + type: "talent"; + data: DS4TalentDataPropertiesData; +} + +interface DS4TalentDataPropertiesData extends DS4TalentDataSourceData, DS4ItemDataPropertiesDataRollable { + rank: ModifiableDataBaseTotalMax; +} diff --git a/src/item/talent/talent-data-source.ts b/src/item/talent/talent-data-source.ts new file mode 100644 index 00000000..f5cb46b8 --- /dev/null +++ b/src/item/talent/talent-data-source.ts @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { ModifiableDataBaseMax } from "../../common/common-data"; +import type { DS4ItemDataSourceDataBase } from "../item-data-source-base"; + +export interface DS4TalentDataSource { + type: "talent"; + data: DS4TalentDataSourceData; +} + +export interface DS4TalentDataSourceData extends DS4ItemDataSourceDataBase { + rank: ModifiableDataBaseMax; +} diff --git a/src/item/talent/talent.ts b/src/item/talent/talent.ts new file mode 100644 index 00000000..dea5782f --- /dev/null +++ b/src/item/talent/talent.ts @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import { DS4Item } from "../item"; + +export class DS4Talent extends DS4Item { + /** @override */ + prepareDerivedData(): void { + super.prepareDerivedData(); + const data = this.data.data; + data.rank.total = data.rank.base + data.rank.mod; + } + + /** @override */ + get activeEffectFactor(): number | undefined { + return this.data.data.rank.total; + } +} + +export interface DS4Talent { + data: foundry.data.ItemData & { type: "talent"; _source: { type: "talent" } }; +} diff --git a/src/item/weapon/weapon-data-properties.ts b/src/item/weapon/weapon-data-properties.ts new file mode 100644 index 00000000..446037b3 --- /dev/null +++ b/src/item/weapon/weapon-data-properties.ts @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { DS4ItemDataPropertiesDataRollable } from "../item-data-properties-base"; +import type { DS4WeaponDataSourceData } from "./weapon-data-source"; + +interface DS4WeaponDataPropertiesData extends DS4WeaponDataSourceData, DS4ItemDataPropertiesDataRollable {} + +export interface DS4WeaponDataProperties { + type: "weapon"; + data: DS4WeaponDataPropertiesData; +} diff --git a/src/item/weapon/weapon-data-source.ts b/src/item/weapon/weapon-data-source.ts new file mode 100644 index 00000000..3dbe5410 --- /dev/null +++ b/src/item/weapon/weapon-data-source.ts @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import type { DS4 } from "../../config"; +import type { + DS4ItemDataSourceDataBase, + DS4ItemDataSourceDataEquipable, + DS4ItemDataSourceDataPhysical, +} from "../item-data-source-base"; + +export interface DS4WeaponDataSource { + type: "weapon"; + data: DS4WeaponDataSourceData; +} + +export interface DS4WeaponDataSourceData + extends DS4ItemDataSourceDataBase, + DS4ItemDataSourceDataPhysical, + DS4ItemDataSourceDataEquipable { + attackType: AttackType; + weaponBonus: number; + opponentDefense: number; +} + +export type AttackType = keyof typeof DS4.i18n.attackTypes; diff --git a/src/item/weapon/weapon.ts b/src/item/weapon/weapon.ts new file mode 100644 index 00000000..dabea48f --- /dev/null +++ b/src/item/weapon/weapon.ts @@ -0,0 +1,89 @@ +// SPDX-FileCopyrightText: 2022 Johannes Loher +// +// SPDX-License-Identifier: MIT + +import { DS4 } from "../../config"; +import { getGame } from "../../helpers"; +import { createCheckRoll } from "../../rolls/check-factory"; +import notifications from "../../ui/notifications"; +import { DS4Item } from "../item"; + +import type { AttackType } from "./weapon-data-source"; + +export class DS4Weapon extends DS4Item { + /** @override */ + prepareDerivedData(): void { + this.data.data.rollable = this.data.data.equipped; + } + + /** @override */ + async roll(options: { speaker?: { token?: TokenDocument; alias?: string } } = {}): Promise { + const game = getGame(); + if (!this.data.data.equipped) { + return notifications.warn( + game.i18n.format("DS4.WarningItemMustBeEquippedToBeRolled", { + name: this.name, + id: this.id, + type: this.data.type, + }), + ); + } + + if (!this.actor) { + throw new Error(game.i18n.format("DS4.ErrorCannotRollUnownedItem", { name: this.name, id: this.id })); + } + + const ownerDataData = this.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; + + const speaker = ChatMessage.getSpeaker({ actor: this.actor, ...options.speaker }); + await createCheckRoll(checkTargetNumber, { + rollMode: getGame().settings.get("core", "rollMode"), + maximumCoupResult: ownerDataData.rolling.maximumCoupResult, + minimumFumbleResult: ownerDataData.rolling.minimumFumbleResult, + flavor: "DS4.ItemWeaponCheckFlavor", + flavorData: { actor: speaker.alias ?? this.actor.name, weapon: this.name }, + speaker, + }); + } + + private async getCombatValueKeyForAttackType(attackType: AttackType): Promise<"meleeAttack" | "rangedAttack"> { + if (attackType === "meleeRanged") { + const { melee, ranged } = { ...DS4.i18n.attackTypes }; + const identifier = "attack-type-selection"; + return Dialog.prompt({ + title: getGame().i18n.localize("DS4.DialogAttackTypeSelection"), + content: await renderTemplate("systems/ds4/templates/dialogs/simple-select-form.hbs", { + selects: [ + { + label: getGame().i18n.localize("DS4.AttackType"), + identifier, + options: { melee, ranged }, + }, + ], + }), + label: getGame().i18n.localize("DS4.GenericOkButton"), + callback: (html) => { + const selectedAttackType = html.find(`#${identifier}`).val(); + if (selectedAttackType !== "melee" && selectedAttackType !== "ranged") { + throw new Error( + getGame().i18n.format("DS4.ErrorUnexpectedAttackType", { + actualType: selectedAttackType, + expectedTypes: "'melee', 'ranged'", + }), + ); + } + return `${selectedAttackType}Attack` as const; + }, + }); + } else { + return `${attackType}Attack` as const; + } + } +} + +export interface DS4Weapon { + data: foundry.data.ItemData & { type: "weapon"; _source: { type: "weapon" } }; +} diff --git a/src/macros/helpers.ts b/src/macros/helpers.ts index 941ee947..5471a2e4 100644 --- a/src/macros/helpers.ts +++ b/src/macros/helpers.ts @@ -2,9 +2,10 @@ // // SPDX-License-Identifier: MIT -import { DS4Actor } from "../actor/actor"; import { getCanvas, getGame } from "../helpers"; +import type { DS4Actor } from "../actor/actor"; + /** * Gets the currently active actor and token based on how {@link ChatMessage} * determines the current speaker. diff --git a/src/macros/roll-check.ts b/src/macros/roll-check.ts index 327541af..ae93a039 100644 --- a/src/macros/roll-check.ts +++ b/src/macros/roll-check.ts @@ -2,12 +2,12 @@ // // SPDX-License-Identifier: MIT -import { Check } from "../actor/actor-data-properties"; import { DS4 } from "../config"; import { getGame } from "../helpers"; import notifications from "../ui/notifications"; import { getActiveActorAndToken } from "./helpers"; +import type { Check } from "../actor/actor-data-properties-base"; /** * Creates a macro from a check drop. * Get an existing roll check macro if one exists, otherwise create a new one. diff --git a/src/migrations/005.ts b/src/migrations/005.ts index 80d0fc8f..16919ce6 100644 --- a/src/migrations/005.ts +++ b/src/migrations/005.ts @@ -2,7 +2,6 @@ // // SPDX-License-Identifier: MIT -import { CooldownDuration } from "../item/item-data-source"; import { getActorUpdateDataGetter, getCompendiumMigrator, @@ -45,10 +44,10 @@ function getItemUpdateData(itemData: Partial) return updateData; } -function migrateCooldownDuration(cooldownDurationValue?: string, cooldownDurationUnit?: string) { +function migrateCooldownDuration(cooldownDurationValue = "", cooldownDurationUnit = "") { if (Number.isNumeric(cooldownDurationValue)) { - const value = Number.fromString(cooldownDurationValue!); - const rounds = getRounds(cooldownDurationUnit ?? "", value); + const value = Number.fromString(cooldownDurationValue); + const rounds = getRounds(cooldownDurationUnit, value); if (rounds * secondsPerRound > secondsPerDay) { return "d20d"; diff --git a/src/token-document.ts b/src/token-document.ts index 0491f13e..cf829f0b 100644 --- a/src/token-document.ts +++ b/src/token-document.ts @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: MIT -import { DS4Actor } from "./actor/actor"; +import { DS4ActorProxy } from "./actor/proxy"; import { getGame } from "./helpers"; let fallbackData: foundry.data.ActorData["data"] | undefined = undefined; @@ -13,7 +13,7 @@ function getFallbackData() { for (const type of getGame().system.template.Actor?.types ?? []) { foundry.utils.mergeObject( fallbackData, - new DS4Actor({ type: type as foundry.data.ActorData["type"], name: "temporary" }).data.data, + new DS4ActorProxy({ type: type as foundry.data.ActorData["type"], name: "temporary" }).data.data, ); } } diff --git a/tsconfig.json b/tsconfig.json index 7a7a51ce..9062a9a8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,7 +8,8 @@ "forceConsistentCasingInFileNames": true, "strict": true, "noUncheckedIndexedAccess": true, - "resolveJsonModule": true + "resolveJsonModule": true, + "importsNotUsedAsValues": "error" }, "include": ["src"] } diff --git a/yarn.lock b/yarn.lock index 6b946a6d..2dda5023 100644 --- a/yarn.lock +++ b/yarn.lock @@ -892,9 +892,9 @@ __metadata: languageName: node linkType: hard -"@league-of-foundry-developers/foundry-vtt-types@npm:9.249.2": - version: 9.249.2 - resolution: "@league-of-foundry-developers/foundry-vtt-types@npm:9.249.2" +"@league-of-foundry-developers/foundry-vtt-types@npm:9.249.3": + version: 9.249.3 + resolution: "@league-of-foundry-developers/foundry-vtt-types@npm:9.249.3" dependencies: "@types/jquery": ~3.5.9 "@types/simple-peer": ~9.11.1 @@ -903,7 +903,7 @@ __metadata: pixi.js: 5.3.11 socket.io-client: 4.3.2 tinymce: 5.10.1 - checksum: 31e5a7909a9928d34f60c9bd01a615502647331cea1b8f4af2c6f3ed461a1e90efd27a0801527a3eb0d6080f0bc51f62cc38e3658c85afad43522d99e8fd39a6 + checksum: 13bbcafd57637a59f44ee136e5edd78b1fedb3f0327027bd2bae8971f2eed6ad5ad84755cebc32e4b08f788e0bf5c08dd06cbe4709ae89746198658ebb511451 languageName: node linkType: hard @@ -3262,7 +3262,7 @@ __metadata: "@commitlint/cli": 16.2.1 "@commitlint/config-conventional": 16.2.1 "@guanghechen/rollup-plugin-copy": 1.8.6 - "@league-of-foundry-developers/foundry-vtt-types": 9.249.2 + "@league-of-foundry-developers/foundry-vtt-types": 9.249.3 "@rollup/plugin-typescript": 8.3.0 "@seald-io/nedb": 2.2.1 "@types/fs-extra": 9.0.13