From be616e3be86c697ff36ce3ddce8ac3e55d300a43 Mon Sep 17 00:00:00 2001
From: Johannes Loher <johannes.loher@fg4f.de>
Date: Wed, 16 Feb 2022 13:32:04 +0100
Subject: [PATCH] refactor: use subclasses for different actor types

---
 lang/de.json                                  |   1 +
 lang/en.json                                  |   1 +
 package.json                                  |   2 +-
 src/actor/actor-data-properties-base.ts       |  44 +++++++
 src/actor/actor-data-properties.ts            |  79 +-----------
 src/actor/actor-data-source-base.ts           |  43 +++++++
 src/actor/actor-data-source.ts                | 117 +-----------------
 src/actor/{sheets => }/actor-sheet.ts         |  18 +--
 src/actor/actor.ts                            |  29 +----
 .../character/character-data-properties.ts    |  29 +++++
 src/actor/character/character-data-source.ts  |  56 +++++++++
 .../{sheets => character}/character-sheet.ts  |   2 +-
 src/actor/character/character.ts              |  28 +++++
 .../creature/creature-data-properties.ts      |  15 +++
 src/actor/creature/creature-data-source.ts    |  28 +++++
 .../{sheets => creature}/creature-sheet.ts    |   2 +-
 src/actor/creature/creature.ts                |  17 +++
 src/actor/proxy.ts                            |  23 ++++
 src/hooks/hotbar-drop.ts                      |   2 +-
 src/hooks/init.ts                             |   9 +-
 src/macros/roll-check.ts                      |   2 +-
 src/token-document.ts                         |   4 +-
 yarn.lock                                     |  10 +-
 23 files changed, 321 insertions(+), 240 deletions(-)
 create mode 100644 src/actor/actor-data-properties-base.ts
 create mode 100644 src/actor/actor-data-source-base.ts
 rename src/actor/{sheets => }/actor-sheet.ts (97%)
 create mode 100644 src/actor/character/character-data-properties.ts
 create mode 100644 src/actor/character/character-data-source.ts
 rename src/actor/{sheets => character}/character-sheet.ts (89%)
 create mode 100644 src/actor/character/character.ts
 create mode 100644 src/actor/creature/creature-data-properties.ts
 create mode 100644 src/actor/creature/creature-data-source.ts
 rename src/actor/{sheets => creature}/creature-sheet.ts (89%)
 create mode 100644 src/actor/creature/creature.ts
 create mode 100644 src/actor/proxy.ts

diff --git a/lang/de.json b/lang/de.json
index d1a9e186..8e6fbd7a 100644
--- a/lang/de.json
+++ b/lang/de.json
@@ -256,6 +256,7 @@
     "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.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.",
diff --git a/lang/en.json b/lang/en.json
index 38640607..cd8632c0 100644
--- a/lang/en.json
+++ b/lang/en.json
@@ -256,6 +256,7 @@
     "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.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.",
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/src/actor/actor-data-properties-base.ts b/src/actor/actor-data-properties-base.ts
new file mode 100644
index 00000000..2360ecb6
--- /dev/null
+++ b/src/actor/actor-data-properties-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 { ModifiableDataBaseTotal, ResourceDataBaseTotalMax } from "../common/common-data";
+import { DS4 } from "../config";
+
+export interface DS4ActorDataPropertiesDataBase {
+    attributes: DS4ActorDataPropertiesDataAttributes;
+    traits: DS4ActorDataPropertiesDataTraits;
+    combatValues: DS4ActorDataPropertiesDataCombatValues;
+    rolling: DS4ActorDataPropertiesDataRolling;
+    checks: DS4ActorDataPropertiesDataChecks;
+}
+
+type DS4ActorDataPropertiesDataAttributes = {
+    [Key in keyof typeof DS4.i18n.attributes]: ModifiableDataBaseTotal<number>;
+};
+
+type DS4ActorDataPropertiesDataTraits = { [Key in keyof typeof DS4.i18n.traits]: ModifiableDataBaseTotal<number> };
+
+type DS4ActorDataPropertiesDataCombatValues = {
+    [Key in keyof typeof DS4.i18n.combatValues]: Key extends "hitPoints"
+        ? ResourceDataBaseTotalMax<number>
+        : ModifiableDataBaseTotal<number>;
+};
+
+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..28275571 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 { DS4CharacterDataProperties } from "./character/character-data-properties";
+import { 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<number>;
-};
-
-type DS4ActorDataPropertiesDataTraits = { [Key in keyof typeof DS4.i18n.traits]: ModifiableDataBaseTotal<number> };
-
-type DS4ActorDataPropertiesDataCombatValues = {
-    [Key in keyof typeof DS4.i18n.combatValues]: Key extends "hitPoints"
-        ? ResourceDataBaseTotalMax<number>
-        : ModifiableDataBaseTotal<number>;
-};
-
-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..c740dcd4
--- /dev/null
+++ b/src/actor/actor-data-source-base.ts
@@ -0,0 +1,43 @@
+// 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 { ModifiableData, ModifiableDataBase, ResourceData } from "../common/common-data";
+import { DS4 } from "../config";
+
+export interface DS4ActorDataSourceDataBase {
+    attributes: DS4ActorDataSourceDataAttributes;
+    traits: DS4ActorDataSourceDataTraits;
+    combatValues: DS4ActorDataSourceDataCombatValues;
+}
+
+type DS4ActorDataSourceDataAttributes = { [Key in keyof typeof DS4.i18n.attributes]: ModifiableDataBase<number> };
+
+type Attribute = keyof DS4ActorDataSourceDataAttributes;
+
+export function isAttribute(value: unknown): value is Attribute {
+    return (Object.keys(DS4.i18n.attributes) as Array<unknown>).includes(value);
+}
+
+type DS4ActorDataSourceDataTraits = { [Key in keyof typeof DS4.i18n.traits]: ModifiableDataBase<number> };
+
+type Trait = keyof DS4ActorDataSourceDataTraits;
+
+export function isTrait(value: unknown): value is Trait {
+    return (Object.keys(DS4.i18n.traits) as Array<unknown>).includes(value);
+}
+
+type DS4ActorDataSourceDataCombatValues = {
+    [Key in keyof typeof DS4.i18n.combatValues]: Key extends "hitPoints"
+        ? ResourceData<number>
+        : ModifiableData<number>;
+};
+
+type CombatValue = keyof DS4ActorDataSourceDataCombatValues;
+
+export function isCombatValue(value: string): value is CombatValue {
+    return (Object.keys(DS4.i18n.combatValues) as Array<unknown>).includes(value);
+}
diff --git a/src/actor/actor-data-source.ts b/src/actor/actor-data-source.ts
index 6fd6cabd..ca74631b 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 { DS4CharacterDataSource } from "./character/character-data-source";
+import { 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<number> };
-
-type Attribute = keyof DS4ActorDataSourceDataAttributes;
-
-export function isAttribute(value: unknown): value is Attribute {
-    return (Object.keys(DS4.i18n.attributes) as Array<unknown>).includes(value);
-}
-
-type DS4ActorDataSourceDataTraits = { [Key in keyof typeof DS4.i18n.traits]: ModifiableDataBase<number> };
-
-type Trait = keyof DS4ActorDataSourceDataTraits;
-
-export function isTrait(value: unknown): value is Trait {
-    return (Object.keys(DS4.i18n.traits) as Array<unknown>).includes(value);
-}
-
-type DS4ActorDataSourceDataCombatValues = {
-    [Key in keyof typeof DS4.i18n.combatValues]: Key extends "hitPoints"
-        ? ResourceData<number>
-        : ModifiableData<number>;
-};
-
-type CombatValue = keyof DS4ActorDataSourceDataCombatValues;
-
-export function isCombatValue(value: string): value is CombatValue {
-    return (Object.keys(DS4.i18n.combatValues) as Array<unknown>).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<number>;
-    progressPoints: UsableResource<number>;
-}
-
-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..21a97b65 100644
--- a/src/actor/sheets/actor-sheet.ts
+++ b/src/actor/actor-sheet.ts
@@ -5,16 +5,16 @@
 //
 // 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 { ModifiableDataBaseTotal } from "../common/common-data";
+import { DS4 } from "../config";
+import { getCanvas, getGame } from "../helpers";
+import { DS4Settings, getDS4Settings } from "../settings";
+import notifications from "../ui/notifications";
+import { enforce } from "../utils";
+import { isCheck } from "./actor-data-properties-base";
 
+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..8f46b81a 100644
--- a/src/actor/actor.ts
+++ b/src/actor/actor.ts
@@ -10,8 +10,8 @@ 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 { Check } from "./actor-data-properties-base";
+import { isAttribute, isTrait } from "./actor-data-source-base";
 
 declare global {
     interface DocumentClassConfig {
@@ -157,9 +157,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 +164,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<ItemType> {
-        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..db511a38
--- /dev/null
+++ b/src/actor/character/character-data-properties.ts
@@ -0,0 +1,29 @@
+// SPDX-FileCopyrightText: 2022 Johannes Loher
+//
+// SPDX-License-Identifier: MIT
+
+import { DS4ActorDataPropertiesDataBase } from "../actor-data-properties-base";
+import {
+    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..6dcba132
--- /dev/null
+++ b/src/actor/character/character-data-source.ts
@@ -0,0 +1,56 @@
+// SPDX-FileCopyrightText: 2022 Johannes Loher
+//
+// SPDX-License-Identifier: MIT
+
+import { UsableResource } from "../../common/common-data";
+import { 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<number>;
+    progressPoints: UsableResource<number>;
+}
+
+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..8a425aed
--- /dev/null
+++ b/src/actor/character/character.ts
@@ -0,0 +1,28 @@
+// SPDX-FileCopyrightText: 2022 Johannes Loher
+//
+// SPDX-License-Identifier: MIT
+
+import { ItemType } from "../../item/item-data-source";
+import { DS4Actor } from "../actor";
+
+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<ItemType> {
+        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..c5d5a4c3
--- /dev/null
+++ b/src/actor/creature/creature-data-properties.ts
@@ -0,0 +1,15 @@
+// SPDX-FileCopyrightText: 2022 Johannes Loher
+//
+// SPDX-License-Identifier: MIT
+
+import { DS4ActorDataPropertiesDataBase } from "../actor-data-properties-base";
+import { 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..7bd2368b
--- /dev/null
+++ b/src/actor/creature/creature-data-source.ts
@@ -0,0 +1,28 @@
+// SPDX-FileCopyrightText: 2022 Johannes Loher
+//
+// SPDX-License-Identifier: MIT
+
+import { DS4 } from "../../config";
+import { 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..f9829015
--- /dev/null
+++ b/src/actor/creature/creature.ts
@@ -0,0 +1,17 @@
+// SPDX-FileCopyrightText: 2022 Johannes Loher
+//
+// SPDX-License-Identifier: MIT
+
+import { ItemType } from "../../item/item-data-source";
+import { DS4Actor } from "../actor";
+
+export class DS4Creature extends DS4Actor {
+    /** @override */
+    get ownableItemTypes(): Array<ItemType> {
+        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<typeof DS4Actor>) {
+        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/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..ce0eca18 100644
--- a/src/hooks/init.ts
+++ b/src/hooks/init.ts
@@ -6,8 +6,9 @@
 
 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 { DS4ActorProxy } from "../actor/proxy";
+import { DS4CharacterActorSheet } from "../actor/character/character-sheet";
+import { DS4CreatureActorSheet } from "../actor/creature/creature-sheet";
 import { DS4ChatMessage } from "../chat-message";
 import { DS4 } from "../config";
 import { preloadFonts as preloadFonts } from "../fonts";
@@ -34,7 +35,7 @@ async function init() {
     logger.info(`Initializing the DS4 Game System\n${DS4.ASCII}`);
 
     getGame().ds4 = {
-        DS4Actor,
+        DS4Actor: DS4ActorProxy,
         DS4Item,
         DS4,
         createCheckRoll,
@@ -44,7 +45,7 @@ async function init() {
 
     CONFIG.DS4 = DS4;
 
-    CONFIG.Actor.documentClass = DS4Actor;
+    CONFIG.Actor.documentClass = DS4ActorProxy;
     CONFIG.Item.documentClass = DS4Item;
     CONFIG.ActiveEffect.documentClass = DS4ActiveEffect;
     CONFIG.ChatMessage.documentClass = DS4ChatMessage;
diff --git a/src/macros/roll-check.ts b/src/macros/roll-check.ts
index 327541af..1e37b7d4 100644
--- a/src/macros/roll-check.ts
+++ b/src/macros/roll-check.ts
@@ -2,7 +2,7 @@
 //
 // SPDX-License-Identifier: MIT
 
-import { Check } from "../actor/actor-data-properties";
+import { Check } from "../actor/actor-data-properties-base";
 import { DS4 } from "../config";
 import { getGame } from "../helpers";
 import notifications from "../ui/notifications";
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/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