refactor: use subclasses for different item types

This commit is contained in:
Johannes Loher 2022-02-17 00:17:59 +01:00
parent be616e3be8
commit 8d2cff77d7
47 changed files with 766 additions and 456 deletions

View file

@ -257,11 +257,11 @@
"DS4.ErrorSlayingDiceRecursionLimitExceeded": "Die maximale Rekursionstiefe für slayende Würfelwürfe wurde überschritten.", "DS4.ErrorSlayingDiceRecursionLimitExceeded": "Die maximale Rekursionstiefe für slayende Würfelwürfe wurde überschritten.",
"DS4.ErrorInvalidNumberOfDice": "Ungültige Anzahl an Würfeln.", "DS4.ErrorInvalidNumberOfDice": "Ungültige Anzahl an Würfeln.",
"DS4.ErrorInvalidActorType": "Ungültiger Aktortyp '{type}'.", "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.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.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.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.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.ErrorUnexpectedAttackType": "Unerwartete Angriffsart '{actualType}', erwartete Angriffsarten: {expectedTypes}",
"DS4.ErrorUnexpectedAttribute": "Unerwartetes Attribut '{actualAttribute}', erwartete Attribute: {expectedTypes}", "DS4.ErrorUnexpectedAttribute": "Unerwartetes Attribut '{actualAttribute}', erwartete Attribute: {expectedTypes}",
"DS4.ErrorUnexpectedTrait": "Unerwartete Eigenschaft '{actualTrait}', erwartete Eigenschaften: {expectedTypes}", "DS4.ErrorUnexpectedTrait": "Unerwartete Eigenschaft '{actualTrait}', erwartete Eigenschaften: {expectedTypes}",

View file

@ -257,11 +257,11 @@
"DS4.ErrorSlayingDiceRecursionLimitExceeded": "Maximum recursion depth for slaying dice roll exceeded.", "DS4.ErrorSlayingDiceRecursionLimitExceeded": "Maximum recursion depth for slaying dice roll exceeded.",
"DS4.ErrorInvalidNumberOfDice": "Invalid number of dice.", "DS4.ErrorInvalidNumberOfDice": "Invalid number of dice.",
"DS4.ErrorInvalidActorType": "Invalid actor type '{type}'.", "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.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.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.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.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.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.ErrorUnexpectedAttribute": "Unexpected attribute '{actualAttribute}', expected it to be one of: {expectedTypes}",
"DS4.ErrorUnexpectedTrait": "Unexpected trait '{actualTrait}', expected it to be one of: {expectedTypes}", "DS4.ErrorUnexpectedTrait": "Unexpected trait '{actualTrait}', expected it to be one of: {expectedTypes}",

View file

@ -2,8 +2,8 @@
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import { CooldownDuration, DS4SpellDataSourceData } from "../../../src/item/item-data-source"; import { CooldownDuration, DS4SpellDataSourceData } from "../../../src/item/spell/spell-data-source";
import { calculateSpellPrice } from "../../../src/item/type-specific-helpers/spell"; import { calculateSpellPrice } from "../../../src/item/spell/calculate-spell-price";
const defaultData: DS4SpellDataSourceData = { const defaultData: DS4SpellDataSourceData = {
description: "", description: "",

View file

@ -6,9 +6,10 @@
import { ModifiableDataBaseTotal } from "../common/common-data"; import { ModifiableDataBaseTotal } from "../common/common-data";
import { DS4 } from "../config"; import { DS4 } from "../config";
import { getGame } from "../helpers"; import { getGame } from "../helpers";
import { DS4ArmorDataProperties } from "../item/armor/armor-data-properties";
import { DS4Item } from "../item/item"; import { DS4Item } from "../item/item";
import { DS4ArmorDataProperties, DS4ShieldDataProperties } from "../item/item-data-properties";
import { ItemType } from "../item/item-data-source"; import { ItemType } from "../item/item-data-source";
import { DS4ShieldDataProperties } from "../item/shield/shield-data-properties";
import { createCheckRoll } from "../rolls/check-factory"; import { createCheckRoll } from "../rolls/check-factory";
import { Check } from "./actor-data-properties-base"; import { Check } from "./actor-data-properties-base";
import { isAttribute, isTrait } from "./actor-data-source-base"; import { isAttribute, isTrait } from "./actor-data-source-base";

View file

@ -26,6 +26,7 @@ import { DS4Roll } from "../rolls/roll";
import registerSlayingDiceModifier from "../rolls/slaying-dice-modifier"; import registerSlayingDiceModifier from "../rolls/slaying-dice-modifier";
import { registerSystemSettings } from "../settings"; import { registerSystemSettings } from "../settings";
import { DS4TokenDocument } from "../token-document"; import { DS4TokenDocument } from "../token-document";
import { DS4ItemProxy } from "../item/proxy";
export default function registerForInitHook(): void { export default function registerForInitHook(): void {
Hooks.once("init", init); Hooks.once("init", init);
@ -36,7 +37,7 @@ async function init() {
getGame().ds4 = { getGame().ds4 = {
DS4Actor: DS4ActorProxy, DS4Actor: DS4ActorProxy,
DS4Item, DS4Item: DS4ItemProxy,
DS4, DS4,
createCheckRoll, createCheckRoll,
migration, migration,
@ -46,7 +47,7 @@ async function init() {
CONFIG.DS4 = DS4; CONFIG.DS4 = DS4;
CONFIG.Actor.documentClass = DS4ActorProxy; CONFIG.Actor.documentClass = DS4ActorProxy;
CONFIG.Item.documentClass = DS4Item; CONFIG.Item.documentClass = DS4ItemProxy;
CONFIG.ActiveEffect.documentClass = DS4ActiveEffect; CONFIG.ActiveEffect.documentClass = DS4ActiveEffect;
CONFIG.ChatMessage.documentClass = DS4ChatMessage; CONFIG.ChatMessage.documentClass = DS4ChatMessage;
CONFIG.Token.documentClass = DS4TokenDocument; CONFIG.Token.documentClass = DS4TokenDocument;

View file

@ -0,0 +1,13 @@
// SPDX-FileCopyrightText: 2021 Johannes Loher
//
// SPDX-License-Identifier: MIT
import { DS4ItemDataPropertiesDataRollable } from "../item-data-properties-base";
import { DS4AlphabetDataSourceData } from "./alphabet-data-source";
export interface DS4AlphabetDataProperties {
type: "alphabet";
data: DS4AlphabetDataPropertiesData;
}
interface DS4AlphabetDataPropertiesData extends DS4AlphabetDataSourceData, DS4ItemDataPropertiesDataRollable {}

View file

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: 2022 Johannes Loher
//
// SPDX-License-Identifier: MIT
import { DS4ItemDataSourceDataBase } from "../item-data-source-base";
export interface DS4AlphabetDataSource {
type: "alphabet";
data: DS4AlphabetDataSourceData;
}
export type DS4AlphabetDataSourceData = DS4ItemDataSourceDataBase;

View file

@ -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" } };
}

View file

@ -0,0 +1,13 @@
// SPDX-FileCopyrightText: 2022 Johannes Loher
//
// SPDX-License-Identifier: MIT
import { DS4ItemDataPropertiesDataRollable } from "../item-data-properties-base";
import { DS4ArmorDataSourceData } from "./armor-data-source";
export interface DS4ArmorDataProperties {
type: "armor";
data: DS4ArmorDataPropertiesData;
}
interface DS4ArmorDataPropertiesData extends DS4ArmorDataSourceData, DS4ItemDataPropertiesDataRollable {}

View file

@ -0,0 +1,25 @@
// SPDX-FileCopyrightText: 2022 Johannes Loher
//
// SPDX-License-Identifier: MIT
import { DS4 } from "../../config";
import {
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;
}

11
src/item/armor/armor.ts Normal file
View file

@ -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" } };
}

View file

@ -0,0 +1,13 @@
// SPDX-FileCopyrightText: 2021 Johannes Loher
//
// SPDX-License-Identifier: MIT
import { DS4ItemDataPropertiesDataRollable } from "../item-data-properties-base";
import { DS4EquipmentDataSourceData } from "./equipment-data-source";
export interface DS4EquipmentDataProperties {
type: "equipment";
data: DS4EquipmentDataPropertiesData;
}
interface DS4EquipmentDataPropertiesData extends DS4EquipmentDataSourceData, DS4ItemDataPropertiesDataRollable {}

View file

@ -0,0 +1,19 @@
// SPDX-FileCopyrightText: 2022 Johannes Loher
//
// SPDX-License-Identifier: MIT
import {
DS4ItemDataSourceDataBase,
DS4ItemDataSourceDataEquipable,
DS4ItemDataSourceDataPhysical,
} from "../item-data-source-base";
export interface DS4EquipmentDataSource {
type: "equipment";
data: DS4EquipmentDataSourceData;
}
export interface DS4EquipmentDataSourceData
extends DS4ItemDataSourceDataBase,
DS4ItemDataSourceDataPhysical,
DS4ItemDataSourceDataEquipable {}

View file

@ -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" } };
}

View file

@ -0,0 +1,7 @@
// SPDX-FileCopyrightText: 2021 Johannes Loher
//
// SPDX-License-Identifier: MIT
export interface DS4ItemDataPropertiesDataRollable {
rollable: boolean;
}

View file

@ -1,21 +1,18 @@
// SPDX-FileCopyrightText: 2021 Johannes Loher // SPDX-FileCopyrightText: 2022 Johannes Loher
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import { ModifiableDataBaseTotalMax } from "../common/common-data"; import { DS4AlphabetDataProperties } from "./alphabet/alphabet-data-properties";
import { import { DS4ArmorDataProperties } from "./armor/armor-data-properties";
DS4AlphabetDataSourceData, import { DS4EquipmentDataProperties } from "./equipment/equipment-data-properties";
DS4ArmorDataSourceData, import { DS4LanguageDataProperties } from "./language/language-data-properties";
DS4EquipmentDataSourceData, import { DS4LootDataProperties } from "./loot/loot-data-properties";
DS4LanguageDataSourceData, import { DS4RacialAbilityDataProperties } from "./racial-ability/racial-ability-data-properties";
DS4LootDataSourceData, import { DS4ShieldDataProperties } from "./shield/shield-data-properties";
DS4RacialAbilityDataSourceData, import { DS4SpecialCreatureAbilityDataProperties } from "./special-creature-ability/special-creature-ability-data-properties";
DS4ShieldDataSourceData, import { DS4SpellDataProperties } from "./spell/spell-data-properties";
DS4SpecialCreatureAbilityDataSourceData, import { DS4TalentDataProperties } from "./talent/talent-data-properties";
DS4SpellDataSourceData, import { DS4WeaponDataProperties } from "./weapon/weapon-data-properties";
DS4TalentDataSourceData,
DS4WeaponDataSourceData,
} from "./item-data-source";
declare global { declare global {
interface DataConfig { interface DataConfig {
@ -24,107 +21,14 @@ declare global {
} }
export type DS4ItemDataProperties = export type DS4ItemDataProperties =
| DS4WeaponDataProperties
| DS4ArmorDataProperties
| DS4ShieldDataProperties
| DS4SpellDataProperties
| DS4EquipmentDataProperties
| DS4LootDataProperties
| DS4TalentDataProperties
| DS4RacialAbilityDataProperties
| DS4LanguageDataProperties
| DS4AlphabetDataProperties | DS4AlphabetDataProperties
| DS4SpecialCreatureAbilityDataProperties; | DS4ArmorDataProperties
| DS4EquipmentDataProperties
export interface DS4WeaponDataProperties { | DS4LanguageDataProperties
type: "weapon"; | DS4LootDataProperties
data: DS4WeaponDataPropertiesData; | DS4RacialAbilityDataProperties
} | DS4ShieldDataProperties
| DS4SpecialCreatureAbilityDataProperties
export interface DS4ArmorDataProperties { | DS4SpellDataProperties
type: "armor"; | DS4TalentDataProperties
data: DS4ArmorDataPropertiesData; | DS4WeaponDataProperties;
}
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,30 @@
// SPDX-FileCopyrightText: 2021 Johannes Loher
// SPDX-FileCopyrightText: 2021 Oliver Rümpelein
// SPDX-FileCopyrightText: 2021 Gesina Schwalbe
//
// SPDX-License-Identifier: MIT
import { 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;
}

View file

@ -1,11 +1,19 @@
// SPDX-FileCopyrightText: 2021 Johannes Loher // SPDX-FileCopyrightText: 2022 Johannes Loher
// SPDX-FileCopyrightText: 2021 Oliver Rümpelein
// SPDX-FileCopyrightText: 2021 Gesina Schwalbe
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import { ModifiableDataBaseMax } from "../common/common-data";
import { DS4 } from "../config"; import { DS4 } from "../config";
import { DS4AlphabetDataSource } from "./alphabet/alphabet-data-source";
import { DS4ArmorDataSource } from "./armor/armor-data-source";
import { DS4EquipmentDataSource } from "./equipment/equipment-data-source";
import { DS4LanguageDataSource } from "./language/language-data-source";
import { DS4LootDataSource } from "./loot/loot-data-source";
import { DS4RacialAbilityDataSource } from "./racial-ability/racial-ability-data-source";
import { DS4ShieldDataSource } from "./shield/shield-data-source";
import { DS4SpecialCreatureAbilityDataSource } from "./special-creature-ability/special-creature-ability-data-source";
import { DS4SpellDataSource } from "./spell/spell-data-source";
import { DS4TalentDataSource } from "./talent/talent-data-source";
import { DS4WeaponDataSource } from "./weapon/weapon-data-source";
declare global { declare global {
interface SourceConfig { interface SourceConfig {
@ -16,169 +24,14 @@ declare global {
export type ItemType = keyof typeof DS4.i18n.itemTypes; export type ItemType = keyof typeof DS4.i18n.itemTypes;
export type DS4ItemDataSource = export type DS4ItemDataSource =
| DS4WeaponDataSource
| DS4ArmorDataSource
| DS4ShieldDataSource
| DS4SpellDataSource
| DS4EquipmentDataSource
| DS4LootDataSource
| DS4TalentDataSource
| DS4RacialAbilityDataSource
| DS4LanguageDataSource
| DS4AlphabetDataSource | DS4AlphabetDataSource
| DS4SpecialCreatureAbilityDataSource; | DS4ArmorDataSource
| DS4EquipmentDataSource
interface DS4WeaponDataSource { | DS4LanguageDataSource
type: "weapon"; | DS4LootDataSource
data: DS4WeaponDataSourceData; | DS4RacialAbilityDataSource
} | DS4ShieldDataSource
| DS4SpecialCreatureAbilityDataSource
interface DS4ArmorDataSource { | DS4SpellDataSource
type: "armor"; | DS4TalentDataSource
data: DS4ArmorDataSourceData; | DS4WeaponDataSource;
}
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<DistanceUnit>;
effectRadius: UnitData<DistanceUnit>;
duration: UnitData<TemporalUnit>;
cooldownDuration: CooldownDuration;
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 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

@ -9,7 +9,7 @@ import { DS4 } from "../config";
import { getGame } from "../helpers"; import { getGame } from "../helpers";
import notifications from "../ui/notifications"; import notifications from "../ui/notifications";
import { enforce } from "../utils"; import { enforce } from "../utils";
import { isDS4ItemDataTypePhysical } from "./item-data-source"; import { isDS4ItemDataTypePhysical } from "./item-data-source-base";
/** /**
* The Sheet class for DS4 Items * The Sheet class for DS4 Items

View file

@ -3,12 +3,8 @@
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import { DS4 } from "../config";
import { getGame } from "../helpers"; import { getGame } from "../helpers";
import { createCheckRoll } from "../rolls/check-factory"; import { ItemType } from "./item-data-source";
import notifications from "../ui/notifications";
import { AttackType, ItemType } from "./item-data-source";
import { calculateSpellPrice } from "./type-specific-helpers/spell";
declare global { declare global {
interface DocumentClassConfig { interface DocumentClassConfig {
@ -27,18 +23,7 @@ export class DS4Item extends Item {
/** @override */ /** @override */
prepareDerivedData(): void { prepareDerivedData(): void {
if (this.data.type === "talent") { this.data.data.rollable = false;
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);
}
} }
isNonEquippedEuipable(): boolean { isNonEquippedEuipable(): boolean {
@ -49,9 +34,6 @@ export class DS4Item extends Item {
* The number of times that active effect changes originating from this item should be applied. * The number of times that active effect changes originating from this item should be applied.
*/ */
get activeEffectFactor(): number | undefined { get activeEffectFactor(): number | undefined {
if (this.data.type === "talent") {
return this.data.data.rank.total;
}
return 1; return 1;
} }
@ -66,142 +48,8 @@ export class DS4Item extends Item {
* Roll a check for an action with this item. * Roll a check for an action with this item.
* @param options - Additional options to customize the roll * @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<void> { async roll(options: { speaker?: { token?: TokenDocument; alias?: string } } = {}): Promise<void> {
switch (this.data.type) { throw new Error(getGame().i18n.format("DS4.ErrorRollingForItemTypeNotPossible", { type: 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<void> {
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<void> {
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;
}
} }
} }

View file

@ -0,0 +1,13 @@
// SPDX-FileCopyrightText: 2021 Johannes Loher
//
// SPDX-License-Identifier: MIT
import { DS4ItemDataPropertiesDataRollable } from "../item-data-properties-base";
import { DS4LanguageDataSourceData } from "./language-data-source";
export interface DS4LanguageDataProperties {
type: "language";
data: DS4LanguageDataPropertiesData;
}
interface DS4LanguageDataPropertiesData extends DS4LanguageDataSourceData, DS4ItemDataPropertiesDataRollable {}

View file

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: 2022 Johannes Loher
//
// SPDX-License-Identifier: MIT
import { DS4ItemDataSourceDataBase } from "../item-data-source-base";
export interface DS4LanguageDataSource {
type: "language";
data: DS4LanguageDataSourceData;
}
export type DS4LanguageDataSourceData = DS4ItemDataSourceDataBase;

View file

@ -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" } };
}

View file

@ -0,0 +1,13 @@
// SPDX-FileCopyrightText: 2021 Johannes Loher
//
// SPDX-License-Identifier: MIT
import { DS4ItemDataPropertiesDataRollable } from "../item-data-properties-base";
import { DS4LootDataSourceData } from "./loot-data-source";
export interface DS4LootDataProperties {
type: "loot";
data: DS4LootDataPropertiesData;
}
interface DS4LootDataPropertiesData extends DS4LootDataSourceData, DS4ItemDataPropertiesDataRollable {}

View file

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: 2022 Johannes Loher
//
// SPDX-License-Identifier: MIT
import { DS4ItemDataSourceDataBase, DS4ItemDataSourceDataPhysical } from "../item-data-source-base";
export interface DS4LootDataSource {
type: "loot";
data: DS4LootDataSourceData;
}
export interface DS4LootDataSourceData extends DS4ItemDataSourceDataBase, DS4ItemDataSourceDataPhysical {}

11
src/item/loot/loot.ts Normal file
View file

@ -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" } };
}

50
src/item/proxy.ts Normal file
View file

@ -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<typeof DS4Item>) {
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);

View file

@ -0,0 +1,15 @@
// SPDX-FileCopyrightText: 2021 Johannes Loher
//
// SPDX-License-Identifier: MIT
import { DS4ItemDataPropertiesDataRollable } from "../item-data-properties-base";
import { DS4RacialAbilityDataSourceData } from "./racial-ability-data-source";
export interface DS4RacialAbilityDataProperties {
type: "racialAbility";
data: DS4RacialAbilityDataPropertiesData;
}
interface DS4RacialAbilityDataPropertiesData
extends DS4RacialAbilityDataSourceData,
DS4ItemDataPropertiesDataRollable {}

View file

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: 2022 Johannes Loher
//
// SPDX-License-Identifier: MIT
import { DS4ItemDataSourceDataBase } from "../item-data-source-base";
export interface DS4RacialAbilityDataSource {
type: "racialAbility";
data: DS4RacialAbilityDataSourceData;
}
export type DS4RacialAbilityDataSourceData = DS4ItemDataSourceDataBase;

View file

@ -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" } };
}

View file

@ -0,0 +1,13 @@
// SPDX-FileCopyrightText: 2021 Johannes Loher
//
// SPDX-License-Identifier: MIT
import { DS4ItemDataPropertiesDataRollable } from "../item-data-properties-base";
import { DS4ShieldDataSourceData } from "./shield-data-source";
export interface DS4ShieldDataProperties {
type: "shield";
data: DS4ShieldDataPropertiesData;
}
interface DS4ShieldDataPropertiesData extends DS4ShieldDataSourceData, DS4ItemDataPropertiesDataRollable {}

View file

@ -0,0 +1,21 @@
// SPDX-FileCopyrightText: 2022 Johannes Loher
//
// SPDX-License-Identifier: MIT
import {
DS4ItemDataSourceDataBase,
DS4ItemDataSourceDataEquipable,
DS4ItemDataSourceDataPhysical,
DS4ItemDataSourceDataProtective,
} from "../item-data-source-base";
export interface DS4ShieldDataSource {
type: "shield";
data: DS4ShieldDataSourceData;
}
export interface DS4ShieldDataSourceData
extends DS4ItemDataSourceDataBase,
DS4ItemDataSourceDataPhysical,
DS4ItemDataSourceDataEquipable,
DS4ItemDataSourceDataProtective {}

11
src/item/shield/shield.ts Normal file
View file

@ -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" } };
}

View file

@ -0,0 +1,15 @@
// SPDX-FileCopyrightText: 2021 Johannes Loher
//
// SPDX-License-Identifier: MIT
import { DS4ItemDataPropertiesDataRollable } from "../item-data-properties-base";
import { DS4SpecialCreatureAbilityDataSourceData } from "./special-creature-ability-data-source";
export interface DS4SpecialCreatureAbilityDataProperties {
type: "specialCreatureAbility";
data: DS4SpecialCreatureAbilityDataPropertiesData;
}
interface DS4SpecialCreatureAbilityDataPropertiesData
extends DS4SpecialCreatureAbilityDataSourceData,
DS4ItemDataPropertiesDataRollable {}

View file

@ -0,0 +1,14 @@
// SPDX-FileCopyrightText: 2022 Johannes Loher
//
// SPDX-License-Identifier: MIT
import { DS4ItemDataSourceDataBase } from "../item-data-source-base";
export interface DS4SpecialCreatureAbilityDataSource {
type: "specialCreatureAbility";
data: DS4SpecialCreatureAbilityDataSourceData;
}
export interface DS4SpecialCreatureAbilityDataSourceData extends DS4ItemDataSourceDataBase {
experiencePoints: number;
}

View file

@ -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" } };
}

View file

@ -2,7 +2,7 @@
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import { CooldownDuration, DS4SpellDataSourceData } from "../item-data-source"; import { CooldownDuration, DS4SpellDataSourceData } from "./spell-data-source";
export function calculateSpellPrice(data: DS4SpellDataSourceData): number | null { export function calculateSpellPrice(data: DS4SpellDataSourceData): number | null {
const spellPriceFactor = calculateSpellPriceFactor(data.cooldownDuration); const spellPriceFactor = calculateSpellPriceFactor(data.cooldownDuration);

View file

@ -0,0 +1,15 @@
// SPDX-FileCopyrightText: 2021 Johannes Loher
//
// SPDX-License-Identifier: MIT
import { DS4ItemDataPropertiesDataRollable } from "../item-data-properties-base";
import { DS4SpellDataSourceData } from "./spell-data-source";
export interface DS4SpellDataProperties {
type: "spell";
data: DS4SpellDataPropertiesData;
}
interface DS4SpellDataPropertiesData extends DS4SpellDataSourceData, DS4ItemDataPropertiesDataRollable {
price: number | null;
}

View file

@ -0,0 +1,35 @@
// SPDX-FileCopyrightText: 2022 Johannes Loher
//
// SPDX-License-Identifier: MIT
import { DS4 } from "../../config";
import { 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<DistanceUnit>;
effectRadius: UnitData<DistanceUnit>;
duration: UnitData<TemporalUnit>;
cooldownDuration: CooldownDuration;
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 TemporalUnit = keyof typeof DS4.i18n.temporalUnits;
export type CooldownDuration = keyof typeof DS4.i18n.cooldownDurations;

63
src/item/spell/spell.ts Normal file
View file

@ -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<void> {
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" } };
}

View file

@ -0,0 +1,16 @@
// SPDX-FileCopyrightText: 2021 Johannes Loher
//
// SPDX-License-Identifier: MIT
import { ModifiableDataBaseTotalMax } from "../../common/common-data";
import { DS4ItemDataPropertiesDataRollable } from "../item-data-properties-base";
import { DS4TalentDataSourceData } from "./talent-data-source";
export interface DS4TalentDataProperties {
type: "talent";
data: DS4TalentDataPropertiesData;
}
interface DS4TalentDataPropertiesData extends DS4TalentDataSourceData, DS4ItemDataPropertiesDataRollable {
rank: ModifiableDataBaseTotalMax<number>;
}

View file

@ -0,0 +1,15 @@
// SPDX-FileCopyrightText: 2022 Johannes Loher
//
// SPDX-License-Identifier: MIT
import { ModifiableDataBaseMax } from "../../common/common-data";
import { DS4ItemDataSourceDataBase } from "../item-data-source-base";
export interface DS4TalentDataSource {
type: "talent";
data: DS4TalentDataSourceData;
}
export interface DS4TalentDataSourceData extends DS4ItemDataSourceDataBase {
rank: ModifiableDataBaseMax<number>;
}

23
src/item/talent/talent.ts Normal file
View file

@ -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" } };
}

View file

@ -0,0 +1,13 @@
// SPDX-FileCopyrightText: 2022 Johannes Loher
//
// SPDX-License-Identifier: MIT
import { DS4ItemDataPropertiesDataRollable } from "../item-data-properties-base";
import { DS4WeaponDataSourceData } from "./weapon-data-source";
interface DS4WeaponDataPropertiesData extends DS4WeaponDataSourceData, DS4ItemDataPropertiesDataRollable {}
export interface DS4WeaponDataProperties {
type: "weapon";
data: DS4WeaponDataPropertiesData;
}

View file

@ -0,0 +1,26 @@
// SPDX-FileCopyrightText: 2022 Johannes Loher
//
// SPDX-License-Identifier: MIT
import { DS4 } from "../../config";
import {
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;

88
src/item/weapon/weapon.ts Normal file
View file

@ -0,0 +1,88 @@
// 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 { 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<void> {
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" } };
}

View file

@ -2,7 +2,6 @@
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import { CooldownDuration } from "../item/item-data-source";
import { import {
getActorUpdateDataGetter, getActorUpdateDataGetter,
getCompendiumMigrator, getCompendiumMigrator,
@ -45,10 +44,10 @@ function getItemUpdateData(itemData: Partial<foundry.data.ItemData["_source"]>)
return updateData; return updateData;
} }
function migrateCooldownDuration(cooldownDurationValue?: string, cooldownDurationUnit?: string) { function migrateCooldownDuration(cooldownDurationValue = "", cooldownDurationUnit = "") {
if (Number.isNumeric(cooldownDurationValue)) { if (Number.isNumeric(cooldownDurationValue)) {
const value = Number.fromString(cooldownDurationValue!); const value = Number.fromString(cooldownDurationValue);
const rounds = getRounds(cooldownDurationUnit ?? "", value); const rounds = getRounds(cooldownDurationUnit, value);
if (rounds * secondsPerRound > secondsPerDay) { if (rounds * secondsPerRound > secondsPerDay) {
return "d20d"; return "d20d";