Merge branch 'master' into 10-implement-money
This commit is contained in:
commit
e89c87f0c1
46 changed files with 1651 additions and 505 deletions
|
@ -1,39 +1,19 @@
|
|||
export interface DS4ActorDataType {
|
||||
import { ModifiableData, ResourceData, UsableResource } from "../common/common-data";
|
||||
|
||||
export type DS4ActorDataType = DS4ActorDataCharacter | DS4ActorDataCreature;
|
||||
|
||||
interface DS4ActorDataBase {
|
||||
attributes: DS4ActorDataAttributes;
|
||||
traits: DS4ActorDataTraits;
|
||||
combatValues: DS4ActorDataCombatValues;
|
||||
baseInfo: DS4ActorDataBaseInfo;
|
||||
progression: DS4ActorDataProgression;
|
||||
language: DS4ActorDataLanguage;
|
||||
profile: DS4ActorDataProfile;
|
||||
currency: DS4ActorDataCurrency;
|
||||
}
|
||||
|
||||
interface DS4ActorDataAttributes {
|
||||
body: BodyAttribute;
|
||||
body: ModifiableData<number>;
|
||||
mobility: ModifiableData<number>;
|
||||
mind: ModifiableData<number>;
|
||||
}
|
||||
|
||||
export interface ModifiableData<T> {
|
||||
base: T;
|
||||
mod: T;
|
||||
total?: T;
|
||||
}
|
||||
|
||||
interface UsableResource<T> {
|
||||
total: T;
|
||||
used: T;
|
||||
}
|
||||
|
||||
interface ResourceData<T> extends ModifiableData<T> {
|
||||
value: T;
|
||||
max?: T;
|
||||
}
|
||||
|
||||
// Blueprint in case we need more detailed differentiation
|
||||
type BodyAttribute = ModifiableData<number>;
|
||||
|
||||
interface DS4ActorDataTraits {
|
||||
strength: ModifiableData<number>;
|
||||
constitution: ModifiableData<number>;
|
||||
|
@ -54,26 +34,35 @@ interface DS4ActorDataCombatValues {
|
|||
targetedSpellcasting: ModifiableData<number>;
|
||||
}
|
||||
|
||||
interface DS4ActorDataBaseInfo {
|
||||
interface DS4ActorDataCharacter extends DS4ActorDataBase {
|
||||
baseInfo: DS4ActorDataCharacterBaseInfo;
|
||||
progression: DS4ActorDataCharacterProgression;
|
||||
language: DS4ActorDataCharacterLanguage;
|
||||
profile: DS4ActorDataCharacterProfile;
|
||||
currency: DS4ActorDataCharacterCurrency;
|
||||
}
|
||||
|
||||
interface DS4ActorDataCharacterBaseInfo {
|
||||
race: string;
|
||||
class: string;
|
||||
heroClass: string;
|
||||
culture: string;
|
||||
}
|
||||
|
||||
interface DS4ActorDataProgression {
|
||||
interface DS4ActorDataCharacterProgression {
|
||||
level: number;
|
||||
experiencePoints: number;
|
||||
talentPoints: UsableResource<number>;
|
||||
progressPoints: UsableResource<number>;
|
||||
}
|
||||
|
||||
interface DS4ActorDataLanguage {
|
||||
interface DS4ActorDataCharacterLanguage {
|
||||
languages: string;
|
||||
alphabets: string;
|
||||
}
|
||||
|
||||
interface DS4ActorDataProfile {
|
||||
interface DS4ActorDataCharacterProfile {
|
||||
biography: string;
|
||||
gender: string;
|
||||
birthday: string;
|
||||
birthplace: string;
|
||||
|
@ -85,8 +74,25 @@ interface DS4ActorDataProfile {
|
|||
specialCharacteristics: string;
|
||||
}
|
||||
|
||||
interface DS4ActorDataCurrency {
|
||||
interface DS4ActorDataCharacterCurrency {
|
||||
gold: number;
|
||||
silver: number;
|
||||
copper: number;
|
||||
}
|
||||
|
||||
interface DS4ActorDataCreature extends DS4ActorDataBase {
|
||||
baseInfo: DS4ActorDataCreatureBaseInfo;
|
||||
}
|
||||
|
||||
type CreatureType = "animal" | "construct" | "humanoid" | "magicalEntity" | "plantBeing" | "undead";
|
||||
|
||||
type SizeCategory = "tiny" | "small" | "normal" | "large" | "huge" | "colossal";
|
||||
|
||||
interface DS4ActorDataCreatureBaseInfo {
|
||||
loot: string;
|
||||
foeFactor: number;
|
||||
creatureType: CreatureType;
|
||||
sizeCategory: SizeCategory;
|
||||
experiencePoints: number;
|
||||
description: string;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { ModifiableData } from "../common/common-data";
|
||||
import { DS4Item } from "../item/item";
|
||||
import { DS4ItemDataType } from "../item/item-data";
|
||||
import { DS4ActorDataType, ModifiableData } from "./actor-data";
|
||||
import { DS4ItemDataType, ItemType } from "../item/item-data";
|
||||
import { DS4ActorDataType } from "./actor-data";
|
||||
|
||||
export class DS4Actor extends Actor<DS4ActorDataType, DS4ItemDataType, DS4Item> {
|
||||
/** @override */
|
||||
|
@ -21,4 +22,37 @@ export class DS4Actor extends Actor<DS4ActorDataType, DS4ItemDataType, DS4Item>
|
|||
|
||||
combatValues.hitPoints.max = combatValues.hitPoints.total;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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",
|
||||
"trinket",
|
||||
"equipment",
|
||||
"spell",
|
||||
"talent",
|
||||
"racialAbility",
|
||||
"language",
|
||||
"alphabet",
|
||||
];
|
||||
case "creature":
|
||||
return ["weapon", "armor", "shield", "trinket", "equipment", "spell", "specialCreatureAbility"];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not the given item type can be owned by the actor.
|
||||
* @param itemType the item type to check
|
||||
*/
|
||||
canOwnItemType(itemType: ItemType): boolean {
|
||||
return this.ownableItemTypes.includes(itemType);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,30 @@
|
|||
import { DS4ItemDataType } from "../item/item-data";
|
||||
import { DS4Actor } from "./actor";
|
||||
import { DS4ActorDataType } from "./actor-data";
|
||||
import { DS4Item } from "../../item/item";
|
||||
import { DS4ItemDataType, ItemType } from "../../item/item-data";
|
||||
import { DS4Actor } from "../actor";
|
||||
import { DS4ActorDataType } from "../actor-data";
|
||||
|
||||
/**
|
||||
* Extend the basic ActorSheet with some very simple modifications
|
||||
* @extends {ActorSheet}
|
||||
*/
|
||||
export class DS4ActorSheet extends ActorSheet<DS4ActorDataType, DS4Actor, DS4ItemDataType> {
|
||||
/** @override */
|
||||
static get defaultOptions(): FormApplicationOptions {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: ["ds4", "sheet", "actor"],
|
||||
width: 745,
|
||||
height: 600,
|
||||
});
|
||||
}
|
||||
|
||||
/** @override */
|
||||
get template(): string {
|
||||
const path = "systems/ds4/templates/actor";
|
||||
return `${path}/${this.actor.data.type}-sheet.hbs`;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* This method returns the data for the template of the actor sheet.
|
||||
* It explicitly adds the items of the object sorted by type in the
|
||||
|
@ -21,21 +39,9 @@ export class DS4ActorSheet extends ActorSheet<DS4ActorDataType, DS4Actor, DS4Ite
|
|||
// Add the items explicitly sorted by type to the data:
|
||||
itemsByType: this.actor.itemTypes,
|
||||
};
|
||||
console.log("Data:", data);
|
||||
return data;
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions(): FormApplicationOptions {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: ["ds4", "sheet", "actor"],
|
||||
template: "systems/ds4/templates/actor/actor-sheet.hbs",
|
||||
width: 745,
|
||||
height: 600,
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description" }],
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
|
@ -200,4 +206,26 @@ export class DS4ActorSheet extends ActorSheet<DS4ActorDataType, DS4Actor, DS4Ite
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
async _onDrop(event: DragEvent): Promise<boolean | unknown> {
|
||||
const data = JSON.parse(event.dataTransfer?.getData("text/plain")) as { type?: string };
|
||||
if (data.type === "Item") {
|
||||
const item = await Item.fromDropData(data as Parameters<typeof DS4Item.fromDropData>[0]);
|
||||
if (item && !this.actor.canOwnItemType(item.data.type as ItemType)) {
|
||||
ui.notifications.warn(
|
||||
game.i18n.format("DS4.WarningActorCannotOwnItem", {
|
||||
actorName: this.actor.name,
|
||||
actorType: this.actor.data.type,
|
||||
itemName: item.name,
|
||||
itemType: item.data.type,
|
||||
}),
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return super._onDrop(event);
|
||||
}
|
||||
}
|
11
src/module/actor/sheets/character-sheet.ts
Normal file
11
src/module/actor/sheets/character-sheet.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { DS4ActorSheet } from "./actor-sheet";
|
||||
|
||||
export class DS4CharacterActorSheet extends DS4ActorSheet {
|
||||
/** @override */
|
||||
static get defaultOptions(): FormApplicationOptions {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: ["ds4", "sheet", "actor", "character"],
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "inventory" }],
|
||||
});
|
||||
}
|
||||
}
|
11
src/module/actor/sheets/creature-sheet.ts
Normal file
11
src/module/actor/sheets/creature-sheet.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { DS4ActorSheet } from "./actor-sheet";
|
||||
|
||||
export class DS4CreatureActorSheet extends DS4ActorSheet {
|
||||
/** @override */
|
||||
static get defaultOptions(): FormApplicationOptions {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: ["ds4", "sheet", "actor", "creature"],
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "inventory" }],
|
||||
});
|
||||
}
|
||||
}
|
15
src/module/common/common-data.ts
Normal file
15
src/module/common/common-data.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
export interface ModifiableData<T> {
|
||||
base: T;
|
||||
mod: T;
|
||||
total?: T;
|
||||
}
|
||||
|
||||
export interface ResourceData<T> extends ModifiableData<T> {
|
||||
value: T;
|
||||
max?: T;
|
||||
}
|
||||
|
||||
export interface UsableResource<T> {
|
||||
total: T;
|
||||
used: T;
|
||||
}
|
|
@ -26,6 +26,14 @@ export const DS4 = {
|
|||
ranged: "systems/ds4/assets/official/DS4-RAT.png",
|
||||
},
|
||||
|
||||
/**
|
||||
* Define the file paths to icon images
|
||||
*/
|
||||
spellTypesIcons: {
|
||||
spellcasting: "systems/ds4/assets/official/DS4-SPC.png",
|
||||
targetedSpellcasting: "systems/ds4/assets/official/DS4-TSC.png",
|
||||
},
|
||||
|
||||
/**
|
||||
* Define the set of item availabilties
|
||||
*/
|
||||
|
@ -46,12 +54,14 @@ export const DS4 = {
|
|||
weapon: "DS4.ItemTypeWeapon",
|
||||
armor: "DS4.ItemTypeArmor",
|
||||
shield: "DS4.ItemTypeShield",
|
||||
spell: "DS4.ItemTypeSpell",
|
||||
trinket: "DS4.ItemTypeTrinket",
|
||||
equipment: "DS4.ItemTypeEquipment",
|
||||
talent: "DS4.ItemTypeTalent",
|
||||
racialAbility: "DS4.ItemTypeRacialAbility",
|
||||
language: "DS4.ItemTypeLanguage",
|
||||
alphabet: "DS4.ItemTypeAlphabet",
|
||||
specialCreatureAbility: "DS4.ItemTypeSpecialCreatureAbility",
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -96,8 +106,33 @@ export const DS4 = {
|
|||
plate: "DS4.ArmorMaterialTypePlateAbbr",
|
||||
},
|
||||
|
||||
spellTypes: {
|
||||
spellcasting: "DS4.SpellTypeSpellcasting",
|
||||
targetedSpellcasting: "DS4.SpellTypeTargetedSpellcasting",
|
||||
},
|
||||
|
||||
spellCategories: {
|
||||
healing: "DS4.SpellCategoryHealing",
|
||||
fire: "DS4.SpellCategoryFire",
|
||||
ice: "DS4.SpellCategoryIce",
|
||||
light: "DS4.SpellCategoryLight",
|
||||
darkness: "DS4.SpellCategoryDarkness",
|
||||
mindAffecting: "DS4.SpellCategoryMindAffecting",
|
||||
electricity: "DS4.SpellCategoryElectricity",
|
||||
none: "DS4.SpellCategoryNone",
|
||||
unset: "DS4.SpellCategoryUnset",
|
||||
},
|
||||
|
||||
/**
|
||||
* Define the set of attributes a character has
|
||||
* Define the set of actor types
|
||||
*/
|
||||
actorTypes: {
|
||||
character: "DS4.ActorTypeCharacter",
|
||||
creature: "DS4.ActorTypeCreature",
|
||||
},
|
||||
|
||||
/**
|
||||
* Define the set of attributes an actor has
|
||||
*/
|
||||
attributes: {
|
||||
body: "DS4.AttributeBody",
|
||||
|
@ -106,7 +141,7 @@ export const DS4 = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Define the set of traits a character has
|
||||
* Define the set of traits an actor has
|
||||
*/
|
||||
traits: {
|
||||
strength: "DS4.TraitStrength",
|
||||
|
@ -118,7 +153,7 @@ export const DS4 = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Define the set of combat values a character has
|
||||
* Define the set of combat values an actor has
|
||||
*/
|
||||
combatValues: {
|
||||
hitPoints: "DS4.CombatValuesHitPoints",
|
||||
|
@ -134,50 +169,52 @@ export const DS4 = {
|
|||
/**
|
||||
* Define the base info of a character
|
||||
*/
|
||||
baseInfo: {
|
||||
race: "DS4.BaseInfoRace",
|
||||
class: "DS4.BaseInfoClass",
|
||||
heroClass: "DS4.BaseInfoHeroClass",
|
||||
culture: "DS4.BaseInfoCulture",
|
||||
characterBaseInfo: {
|
||||
race: "DS4.CharacterBaseInfoRace",
|
||||
class: "DS4.CharacterBaseInfoClass",
|
||||
heroClass: "DS4.CharacterBaseInfoHeroClass",
|
||||
culture: "DS4.CharacterBaseInfoCulture",
|
||||
},
|
||||
|
||||
/**
|
||||
* Define the progression info of a character
|
||||
*/
|
||||
progression: {
|
||||
level: "DS4.ProgressionLevel",
|
||||
experiencePoints: "DS4.ProgressionExperiencePoints",
|
||||
talentPoints: "DS4.ProgressionTalentPoints",
|
||||
progressPoints: "DS4.ProgressionProgressPoints",
|
||||
characterProgression: {
|
||||
level: "DS4.CharacterProgressionLevel",
|
||||
experiencePoints: "DS4.CharacterProgressionExperiencePoints",
|
||||
talentPoints: "DS4.CharacterProgressionTalentPoints",
|
||||
progressPoints: "DS4.CharacterProgressionProgressPoints",
|
||||
},
|
||||
|
||||
/**
|
||||
* Define the language info of a character
|
||||
*/
|
||||
language: {
|
||||
languages: "DS4.LanguageLanguages",
|
||||
alphabets: "DS4.LanguageAlphabets",
|
||||
characterLanguage: {
|
||||
languages: "DS4.CharacterLanguageLanguages",
|
||||
alphabets: "DS4.CharacterLanguageAlphabets",
|
||||
},
|
||||
|
||||
/**
|
||||
* Define the profile info of a character
|
||||
*/
|
||||
profile: {
|
||||
gender: "DS4.ProfileGender",
|
||||
birthday: "DS4.ProfileBirthday",
|
||||
birthplace: "DS4.ProfileBirthplace",
|
||||
age: "DS4.ProfileAge",
|
||||
height: "DS4.ProfileHeight",
|
||||
hairColor: "DS4.ProfilHairColor",
|
||||
weight: "DS4.ProfileWeight",
|
||||
eyeColor: "DS4.ProfileEyeColor",
|
||||
specialCharacteristics: "DS4.ProfileSpecialCharacteristics",
|
||||
characterProfile: {
|
||||
biography: "DS4.CharacterProfileBiography",
|
||||
gender: "DS4.CharacterProfileGender",
|
||||
birthday: "DS4.CharacterProfileBirthday",
|
||||
birthplace: "DS4.CharacterProfileBirthplace",
|
||||
age: "DS4.CharacterProfileAge",
|
||||
height: "DS4.CharacterProfileHeight",
|
||||
hairColor: "DS4.CharacterProfileHairColor",
|
||||
weight: "DS4.CharacterProfileWeight",
|
||||
eyeColor: "DS4.CharacterProfileEyeColor",
|
||||
specialCharacteristics: "DS4.CharacterProfileSpecialCharacteristics",
|
||||
},
|
||||
|
||||
/**
|
||||
* Define the profile info types for hanndlebars of a character
|
||||
* Define the profile info types for handlebars of a character
|
||||
*/
|
||||
profileDTypes: {
|
||||
characterProfileDTypes: {
|
||||
biography: "String",
|
||||
gender: "String",
|
||||
birthday: "String",
|
||||
birthplace: "String",
|
||||
|
@ -192,9 +229,94 @@ export const DS4 = {
|
|||
/**
|
||||
* Define currency elements of a character
|
||||
*/
|
||||
currency: {
|
||||
gold: "DS4.CurrencyGold",
|
||||
silver: "DS4.CurrencySilver",
|
||||
copper: "DS4.CurrencyCopper",
|
||||
characterCurrency: {
|
||||
gold: "DS4.CharacterCurrencyGold",
|
||||
silver: "DS4.CharacterCurrencySilver",
|
||||
copper: "DS4.CharacterCurrencyCopper",
|
||||
},
|
||||
|
||||
/**
|
||||
* Define the different creature types a creature can be
|
||||
*/
|
||||
creatureTypes: {
|
||||
animal: "DS4.CreatureTypeAnimal",
|
||||
construct: "DS4.CreatureTypeConstruct",
|
||||
humanoid: "DS4.CreatureTypeHumanoid",
|
||||
magicalEntity: "DS4.CreatureTypeMagicalEntity",
|
||||
plantBeing: "DS4.CreatureTypePlantBeing",
|
||||
undead: "DS4.CreatureTypeUndead",
|
||||
},
|
||||
|
||||
/**
|
||||
* Define the different size categories creatures fall into
|
||||
*/
|
||||
creatureSizeCategories: {
|
||||
tiny: "DS4.CreatureSizeCategoryTiny",
|
||||
small: "DS4.CreatureSizeCategorySmall",
|
||||
normal: "DS4.CreatureSizeCategoryNormal",
|
||||
large: "DS4.CreatureSizeCategoryLarge",
|
||||
huge: "DS4.CreatureSizeCategoryHuge",
|
||||
colossal: "DS4.CreatureSizeCategoryColossal",
|
||||
},
|
||||
|
||||
/**
|
||||
* Define the base info of a creature
|
||||
*/
|
||||
creatureBaseInfo: {
|
||||
loot: "DS4.CreatureBaseInfoLoot",
|
||||
foeFactor: "DS4.CreatureBaseInfoFoeFactor",
|
||||
creatureType: "DS4.CreatureBaseInfoCreatureType",
|
||||
sizeCategory: "DS4.CreatureBaseInfoSizeCategory",
|
||||
experiencePoints: "DS4.CreatureBaseInfoExperiencePoints",
|
||||
description: "DS4.CreatureBaseInfoDescription",
|
||||
},
|
||||
|
||||
/**
|
||||
* Define translations for available distance units
|
||||
*/
|
||||
distanceUnits: {
|
||||
meter: "DS4.UnitMeters",
|
||||
kilometer: "DS4.UnitKilometers",
|
||||
custom: "DS4.UnitCustom",
|
||||
},
|
||||
/**
|
||||
* Define abbreviations for available distance units
|
||||
*/
|
||||
distanceUnitsAbbr: {
|
||||
meter: "DS4.UnitMetersAbbr",
|
||||
kilometer: "DS4.UnitKilometersAbbr",
|
||||
custom: "DS4.UnitCustomAbbr",
|
||||
},
|
||||
|
||||
/**
|
||||
* Define translations for available distance units
|
||||
*/
|
||||
temporalUnits: {
|
||||
rounds: "DS4.UnitRounds",
|
||||
minutes: "DS4.UnitMinutes",
|
||||
hours: "DS4.UnitHours",
|
||||
days: "DS4.UnitDays",
|
||||
custom: "DS4.UnitCustom",
|
||||
},
|
||||
|
||||
/**
|
||||
* Define abbreviations for available units
|
||||
*/
|
||||
temporalUnitsAbbr: {
|
||||
rounds: "DS4.UnitRoundsAbbr",
|
||||
minutes: "DS4.UnitMinutesAbbr",
|
||||
hours: "DS4.UnitHoursAbbr",
|
||||
days: "DS4.UnitDaysAbbr",
|
||||
custom: "DS4.UnitCustomAbbr",
|
||||
},
|
||||
|
||||
/**
|
||||
* Define localization strings for Chat Visibility
|
||||
*/
|
||||
chatVisibilities: {
|
||||
roll: "DS4.ChatVisibilityRoll",
|
||||
gmroll: "DS4.ChatVisibilityGmRoll",
|
||||
blindroll: "DS4.ChatVisibilityBlindRoll",
|
||||
selfroll: "DS4.ChatVisibilitySelfRoll",
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
// Import Modules
|
||||
import { DS4Actor } from "./actor/actor";
|
||||
import { DS4ActorSheet } from "./actor/actor-sheet";
|
||||
import { DS4Item } from "./item/item";
|
||||
import { DS4ItemSheet } from "./item/item-sheet";
|
||||
import { DS4 } from "./config";
|
||||
import { DS4Check } from "./rolls/check";
|
||||
import { DS4CharacterActorSheet } from "./actor/sheets/character-sheet";
|
||||
import { DS4CreatureActorSheet } from "./actor/sheets/creature-sheet";
|
||||
import { createCheckRoll } from "./rolls/check-factory";
|
||||
|
||||
Hooks.once("init", async function () {
|
||||
console.log(`DS4 | Initializing the DS4 Game System\n${DS4.ASCII}`);
|
||||
|
@ -13,6 +15,7 @@ Hooks.once("init", async function () {
|
|||
DS4Actor,
|
||||
DS4Item,
|
||||
DS4,
|
||||
createCheckRoll,
|
||||
};
|
||||
|
||||
// Record configuration
|
||||
|
@ -22,6 +25,10 @@ Hooks.once("init", async function () {
|
|||
CONFIG.Actor.entityClass = DS4Actor as typeof Actor;
|
||||
CONFIG.Item.entityClass = DS4Item as typeof Item;
|
||||
|
||||
// Define localized type labels
|
||||
CONFIG.Actor.typeLabels = DS4.actorTypes;
|
||||
CONFIG.Item.typeLabels = DS4.itemTypes;
|
||||
|
||||
// Configure Dice
|
||||
CONFIG.Dice.types = [Die, DS4Check];
|
||||
CONFIG.Dice.terms = {
|
||||
|
@ -32,7 +39,8 @@ Hooks.once("init", async function () {
|
|||
|
||||
// Register sheet application classes
|
||||
Actors.unregisterSheet("core", ActorSheet);
|
||||
Actors.registerSheet("ds4", DS4ActorSheet, { makeDefault: true });
|
||||
Actors.registerSheet("ds4", DS4CharacterActorSheet, { types: ["character"], makeDefault: true });
|
||||
Actors.registerSheet("ds4", DS4CreatureActorSheet, { types: ["creature"], makeDefault: true });
|
||||
Items.unregisterSheet("core", ItemSheet);
|
||||
Items.registerSheet("ds4", DS4ItemSheet, { makeDefault: true });
|
||||
|
||||
|
@ -47,13 +55,15 @@ async function registerHandlebarsPartials() {
|
|||
"systems/ds4/templates/item/partials/effects.hbs",
|
||||
"systems/ds4/templates/item/partials/body.hbs",
|
||||
"systems/ds4/templates/actor/partials/items-overview.hbs",
|
||||
"systems/ds4/templates/actor/partials/talents-overview.hbs",
|
||||
"systems/ds4/templates/actor/partials/talents-abilities-overview.hbs",
|
||||
"systems/ds4/templates/actor/partials/spells-overview.hbs",
|
||||
"systems/ds4/templates/actor/partials/overview-add-button.hbs",
|
||||
"systems/ds4/templates/actor/partials/overview-control-buttons.hbs",
|
||||
"systems/ds4/templates/actor/partials/attributes-traits.hbs",
|
||||
"systems/ds4/templates/actor/partials/combat-values.hbs",
|
||||
"systems/ds4/templates/actor/partials/profile.hbs",
|
||||
"systems/ds4/templates/actor/partials/character-progression.hbs",
|
||||
"systems/ds4/templates/actor/partials/special-creature-abilites-overview.hbs",
|
||||
];
|
||||
return loadTemplates(templatePaths);
|
||||
}
|
||||
|
@ -76,18 +86,28 @@ Hooks.once("setup", function () {
|
|||
"armorMaterialTypes",
|
||||
"armorMaterialTypesAbbr",
|
||||
"armorMaterialTypes",
|
||||
"spellTypes",
|
||||
"spellCategories",
|
||||
"attributes",
|
||||
"traits",
|
||||
"combatValues",
|
||||
"baseInfo",
|
||||
"progression",
|
||||
"language",
|
||||
"profile",
|
||||
"currency",
|
||||
"characterBaseInfo",
|
||||
"characterProgression",
|
||||
"characterLanguage",
|
||||
"characterProfile",
|
||||
"characterCurrency",
|
||||
"creatureTypes",
|
||||
"creatureSizeCategories",
|
||||
"creatureBaseInfo",
|
||||
"temporalUnits",
|
||||
"temporalUnitsAbbr",
|
||||
"distanceUnits",
|
||||
"distanceUnitsAbbr",
|
||||
"chatVisibilities",
|
||||
];
|
||||
|
||||
// Exclude some from sorting where the default order matters
|
||||
const noSort = ["attributes", "traits", "combatValues"];
|
||||
const noSort = ["attributes", "traits", "combatValues", "creatureSizeCategories"];
|
||||
|
||||
// Localize and sort CONFIG objects
|
||||
for (const o of toLocalize) {
|
||||
|
|
|
@ -1,15 +1,20 @@
|
|||
import { ModifiableData } from "../actor/actor-data";
|
||||
import { ModifiableData } from "../common/common-data";
|
||||
import { DS4 } from "../config";
|
||||
|
||||
export type ItemType = keyof typeof DS4.itemTypes;
|
||||
|
||||
export type DS4ItemDataType =
|
||||
| DS4Weapon
|
||||
| DS4Armor
|
||||
| DS4Shield
|
||||
| DS4Spell
|
||||
| DS4Trinket
|
||||
| DS4Equipment
|
||||
| DS4Talent
|
||||
| DS4RacialAbility
|
||||
| DS4Language
|
||||
| DS4Alphabet;
|
||||
| DS4Alphabet
|
||||
| DS4SpecialCreatureAbility;
|
||||
|
||||
// types
|
||||
|
||||
|
@ -32,12 +37,35 @@ interface DS4TalentRank extends ModifiableData<number> {
|
|||
max: number;
|
||||
}
|
||||
|
||||
interface DS4Spell extends DS4ItemBase, DS4ItemEquipable {
|
||||
spellType: "spellcasting" | "targetedSpellcasting";
|
||||
bonus: string;
|
||||
spellCategory:
|
||||
| "healing"
|
||||
| "fire"
|
||||
| "ice"
|
||||
| "light"
|
||||
| "darkness"
|
||||
| "mindAffecting"
|
||||
| "electricity"
|
||||
| "none"
|
||||
| "unset";
|
||||
maxDistance: UnitData<DistanceUnit>;
|
||||
effectRadius: UnitData<DistanceUnit>;
|
||||
duration: UnitData<TemporalUnit>;
|
||||
cooldownDuration: UnitData<TemporalUnit>;
|
||||
scrollPrice: number;
|
||||
}
|
||||
|
||||
interface DS4Shield extends DS4ItemBase, DS4ItemPhysical, DS4ItemEquipable, DS4ItemProtective {}
|
||||
interface DS4Trinket extends DS4ItemBase, DS4ItemPhysical, DS4ItemEquipable {}
|
||||
interface DS4Equipment extends DS4ItemBase, DS4ItemPhysical {}
|
||||
type DS4RacialAbility = DS4ItemBase;
|
||||
type DS4Language = DS4ItemBase;
|
||||
type DS4Alphabet = DS4ItemBase;
|
||||
interface DS4SpecialCreatureAbility extends DS4ItemBase {
|
||||
experiencePoints: number;
|
||||
}
|
||||
|
||||
// templates
|
||||
|
||||
|
@ -62,3 +90,10 @@ interface DS4ItemEquipable {
|
|||
interface DS4ItemProtective {
|
||||
armorValue: number;
|
||||
}
|
||||
|
||||
interface UnitData<UnitType> {
|
||||
value: string;
|
||||
unit: UnitType;
|
||||
}
|
||||
type TemporalUnit = "rounds" | "minutes" | "hours" | "days" | "custom";
|
||||
type DistanceUnit = "meter" | "kilometer" | "custom";
|
||||
|
|
237
src/module/rolls/check-factory.ts
Normal file
237
src/module/rolls/check-factory.ts
Normal file
|
@ -0,0 +1,237 @@
|
|||
import { DS4 } from "../config";
|
||||
|
||||
/**
|
||||
* Provides default values for all arguments the `CheckFactory` expects.
|
||||
*/
|
||||
class DefaultCheckOptions implements DS4CheckFactoryOptions {
|
||||
maxCritSuccess = 1;
|
||||
minCritFailure = 20;
|
||||
useSlayingDice = false;
|
||||
rollMode: DS4RollMode = "roll";
|
||||
|
||||
mergeWith(other: Partial<DS4CheckFactoryOptions>): DS4CheckFactoryOptions {
|
||||
return { ...this, ...other } as DS4CheckFactoryOptions;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Singleton reference for default value extraction.
|
||||
*/
|
||||
const defaultCheckOptions = new DefaultCheckOptions();
|
||||
|
||||
/**
|
||||
* Most basic class responsible for generating the chat formula and passing it to the chat as roll.
|
||||
*/
|
||||
class CheckFactory {
|
||||
constructor(
|
||||
private checkTargetValue: number,
|
||||
private gmModifier: number,
|
||||
passedOptions: Partial<DS4CheckFactoryOptions> = {},
|
||||
) {
|
||||
this.checkOptions = new DefaultCheckOptions().mergeWith(passedOptions);
|
||||
}
|
||||
|
||||
private checkOptions: DS4CheckFactoryOptions;
|
||||
|
||||
async execute(): Promise<ChatMessage | any> {
|
||||
const rollCls: typeof Roll = CONFIG.Dice.rolls[0];
|
||||
|
||||
const formula = [
|
||||
"ds",
|
||||
this.createTargetValueTerm(),
|
||||
this.createCritTerm(),
|
||||
this.createSlayingDiceTerm(),
|
||||
].filterJoin("");
|
||||
const roll = new rollCls(formula);
|
||||
|
||||
const rollModeTemplate = this.checkOptions.rollMode;
|
||||
console.log(rollModeTemplate);
|
||||
return roll.toMessage({}, { rollMode: rollModeTemplate, create: true });
|
||||
}
|
||||
|
||||
// Term generators
|
||||
createTargetValueTerm(): string | null {
|
||||
if (this.checkTargetValue !== null) {
|
||||
return "v" + (this.checkTargetValue + this.gmModifier);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
createCritTerm(): string | null {
|
||||
const minCritRequired = this.checkOptions.minCritFailure !== defaultCheckOptions.minCritFailure;
|
||||
const maxCritRequired = this.checkOptions.maxCritSuccess !== defaultCheckOptions.maxCritSuccess;
|
||||
|
||||
if (minCritRequired || maxCritRequired) {
|
||||
return "c" + (this.checkOptions.maxCritSuccess ?? "") + "," + (this.checkOptions.minCritFailure ?? "");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
createSlayingDiceTerm(): string | null {
|
||||
return this.checkOptions.useSlayingDice ? "x" : null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks the user for all unknown/necessary information and passes them on to perform a roll.
|
||||
* @param targetValue {number} The Check Target Number ("CTN")
|
||||
* @param options {Partial<DS4CheckFactoryOptions>} Options changing the behaviour of the roll and message.
|
||||
*/
|
||||
export async function createCheckRoll(
|
||||
targetValue: number,
|
||||
options: Partial<DS4CheckFactoryOptions> = {},
|
||||
): Promise<ChatMessage | any> {
|
||||
// Ask for additional required data;
|
||||
const gmModifierData = await askGmModifier(targetValue, options);
|
||||
|
||||
const newOptions: Partial<DS4CheckFactoryOptions> = {
|
||||
maxCritSuccess: gmModifierData.maxCritSuccess ?? options.maxCritSuccess ?? undefined,
|
||||
minCritFailure: gmModifierData.minCritFailure ?? options.minCritFailure ?? undefined,
|
||||
useSlayingDice: gmModifierData.useSlayingDice ?? options.useSlayingDice ?? undefined,
|
||||
rollMode: gmModifierData.rollMode ?? options.rollMode ?? undefined,
|
||||
};
|
||||
|
||||
// Create Factory
|
||||
const cf = new CheckFactory(gmModifierData.checkTargetValue, gmModifierData.gmModifier, newOptions);
|
||||
|
||||
// Possibly additional processing
|
||||
|
||||
// Execute roll
|
||||
await cf.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Responsible for rendering the modal interface asking for the modifier specified by GM and (currently) additional data.
|
||||
*
|
||||
* @notes
|
||||
* At the moment, this asks for more data than it will do after some iterations.
|
||||
*
|
||||
* @returns {Promise<IntermediateGmModifierData>} The data given by the user.
|
||||
*/
|
||||
async function askGmModifier(
|
||||
targetValue: number,
|
||||
options: Partial<DS4CheckFactoryOptions> = {},
|
||||
{ template, title }: { template?: string; title?: string } = {},
|
||||
): Promise<IntermediateGmModifierData> {
|
||||
// Render model interface and return value
|
||||
const usedTemplate = template ?? "systems/ds4/templates/roll/roll-options.hbs";
|
||||
const usedTitle = title ?? game.i18n.localize("DS4.RollDialogDefaultTitle");
|
||||
const templateData = {
|
||||
cssClass: "roll-option",
|
||||
title: usedTitle,
|
||||
checkTargetValue: targetValue,
|
||||
maxCritSuccess: options.maxCritSuccess ?? defaultCheckOptions.maxCritSuccess,
|
||||
minCritFailure: options.minCritFailure ?? defaultCheckOptions.minCritFailure,
|
||||
rollModes: rollModes,
|
||||
config: DS4,
|
||||
};
|
||||
const renderedHtml = await renderTemplate(usedTemplate, templateData);
|
||||
|
||||
const dialogPromise = new Promise<HTMLFormElement>((resolve) => {
|
||||
new Dialog(
|
||||
{
|
||||
title: usedTitle,
|
||||
close: () => {
|
||||
// Don't do anything
|
||||
},
|
||||
content: renderedHtml,
|
||||
buttons: {
|
||||
ok: {
|
||||
label: game.i18n.localize("DS4.RollDialogOkButton"),
|
||||
callback: (html: HTMLElement | JQuery) => {
|
||||
if (!("jquery" in html)) {
|
||||
throw new Error(
|
||||
game.i18n.format("DS4.ErrorUnexpectedHtmlType", {
|
||||
exType: "JQuery",
|
||||
realType: "HTMLElement",
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
const innerForm = html[0].querySelector("form");
|
||||
resolve(innerForm);
|
||||
}
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
label: game.i18n.localize("DS4.RollDialogCancelButton"),
|
||||
callback: () => {
|
||||
// Don't do anything
|
||||
},
|
||||
},
|
||||
},
|
||||
default: "ok",
|
||||
},
|
||||
{},
|
||||
).render(true);
|
||||
});
|
||||
const dialogForm = await dialogPromise;
|
||||
return parseDialogFormData(dialogForm, targetValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts Dialog data from the returned DOM element.
|
||||
* @param formData {HTMLFormElement} The filed dialog
|
||||
* @param targetValue {number} The previously known target value (slated for removal once data automation is available)
|
||||
*/
|
||||
function parseDialogFormData(formData: HTMLFormElement, targetValue: number): IntermediateGmModifierData {
|
||||
return {
|
||||
checkTargetValue: parseInt(formData["ctv"]?.value) ?? targetValue,
|
||||
gmModifier: parseInt(formData["gmmod"]?.value) ?? 0,
|
||||
maxCritSuccess: parseInt(formData["maxcoup"]?.value) ?? defaultCheckOptions.maxCritSuccess,
|
||||
minCritFailure: parseInt(formData["minfumble"]?.value) ?? defaultCheckOptions.minCritFailure,
|
||||
useSlayingDice: false,
|
||||
rollMode: formData["visibility"]?.value ?? defaultCheckOptions.rollMode,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains data that needs retrieval from an interactive Dialog.
|
||||
*/
|
||||
interface GmModifierData {
|
||||
gmModifier: number;
|
||||
rollMode: DS4RollMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains *CURRENTLY* necessary Data for drafting a roll.
|
||||
*
|
||||
* @deprecated
|
||||
* Quite a lot of this information is requested due to a lack of automation:
|
||||
* - maxCritSuccess
|
||||
* - minCritFailure
|
||||
* - useSlayingDice
|
||||
* - checkTargetValue
|
||||
*
|
||||
* They will and should be removed once effects and data retrieval is in place.
|
||||
* If a "raw" roll dialog is necessary, create another pre-porcessing Dialog
|
||||
* class asking for the required information.
|
||||
* This interface should then be replaced with the `GmModifierData`.
|
||||
*/
|
||||
interface IntermediateGmModifierData extends GmModifierData {
|
||||
checkTargetValue: number;
|
||||
gmModifier: number;
|
||||
maxCritSuccess: number;
|
||||
minCritFailure: number;
|
||||
// TODO: In final version from system settings
|
||||
useSlayingDice: boolean;
|
||||
rollMode: DS4RollMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* The minimum behavioural options that need to be passed to the factory.
|
||||
*/
|
||||
export interface DS4CheckFactoryOptions {
|
||||
maxCritSuccess: number;
|
||||
minCritFailure: number;
|
||||
useSlayingDice: boolean;
|
||||
rollMode: DS4RollMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines all possible roll modes, both for iterating and typing.
|
||||
*/
|
||||
const rollModes = ["roll", "gmroll", "blindroll", "selfroll"] as const;
|
||||
type DS4RollModeTuple = typeof rollModes;
|
||||
export type DS4RollMode = DS4RollModeTuple[number];
|
|
@ -86,7 +86,7 @@ export class DS4Check extends DiceTerm {
|
|||
} else {
|
||||
return ds4roll(targetValueToUse, {
|
||||
maxCritSuccess: this.maxCritSuccess,
|
||||
minCritFail: this.minCritFailure,
|
||||
minCritFailure: this.minCritFailure,
|
||||
slayingDiceRepetition: slayingDiceRepetition,
|
||||
useSlayingDice: slayingDiceRepetition,
|
||||
});
|
||||
|
@ -132,7 +132,6 @@ export class DS4Check extends DiceTerm {
|
|||
static readonly DEFAULT_TARGET_VALUE = 10;
|
||||
static readonly DEFAULT_MAX_CRIT_SUCCESS = 1;
|
||||
static readonly DEFAULT_MIN_CRIT_FAILURE = 20;
|
||||
// TODO: add to Type declarations
|
||||
static DENOMINATION = "s";
|
||||
static MODIFIERS = {
|
||||
x: "explode",
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
export interface RollOptions {
|
||||
maxCritSuccess: number;
|
||||
minCritFail: number;
|
||||
minCritFailure: number;
|
||||
useSlayingDice: boolean;
|
||||
slayingDiceRepetition: boolean;
|
||||
}
|
||||
|
||||
export class DefaultRollOptions implements RollOptions {
|
||||
public maxCritSuccess = 1;
|
||||
public minCritFail = 20;
|
||||
public minCritFailure = 20;
|
||||
public useSlayingDice = false;
|
||||
public slayingDiceRepetition = false;
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ export function rollCheckSingleDie(
|
|||
|
||||
if (rolledDie <= usedOptions.maxCritSuccess) {
|
||||
return new RollResult(checkTargetValue, RollResultStatus.CRITICAL_SUCCESS, usedDice, true);
|
||||
} else if (rolledDie >= usedOptions.minCritFail && !isSlayingDiceRepetition(usedOptions)) {
|
||||
} else if (rolledDie >= usedOptions.minCritFailure && !isSlayingDiceRepetition(usedOptions)) {
|
||||
return new RollResult(0, RollResultStatus.CRITICAL_FAILURE, usedDice, true);
|
||||
} else {
|
||||
if (rolledDie <= checkTargetValue) {
|
||||
|
@ -90,7 +90,7 @@ export function rollCheckMultipleDice(
|
|||
const slayingDiceRepetition = isSlayingDiceRepetition(usedOptions);
|
||||
|
||||
// Slaying Dice require a different handling.
|
||||
if (firstResult >= usedOptions.minCritFail && !slayingDiceRepetition) {
|
||||
if (firstResult >= usedOptions.minCritFailure && !slayingDiceRepetition) {
|
||||
return new RollResult(0, RollResultStatus.CRITICAL_FAILURE, usedDice, true);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue