feat: wip on adding support for mana system
This commit is contained in:
parent
bdc454d7c0
commit
be0c401aa3
31 changed files with 286 additions and 24 deletions
BIN
assets/icons/official/combat-values/mana.png
Normal file
BIN
assets/icons/official/combat-values/mana.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
12
lang/de.json
12
lang/de.json
|
@ -149,6 +149,10 @@
|
|||
"DS4.CooldownDuration100R": "100 Kampfrunden",
|
||||
"DS4.CooldownDuration1D": "1 Tag",
|
||||
"DS4.CooldownDurationD20D": "W20 Tage",
|
||||
"DS4.ManaCost": "Manakosten",
|
||||
"DS4.ManaCostDescription": "The Anzahl an Manapunkten, die es kostet, den Zauber zu wirken.",
|
||||
"DS4.CalculateManaCost": "Manakosten Automatisch Berechnen",
|
||||
"DS4.CalculateManaCostConfirmationQuestion": "<p>Die Manakosten des Zaubers werden automatisch an Hand der Tabelle auf Seite 19 der <a href=\"http://dungeonslayers.net/download/Slay05.pdf\">5. Ausgabe der Slay!</a> berechnet.</p><p><strong>Achtung:</strong> Dieser Vorgang überschreibt die bestehenden Werte und kann nicht automatisch rückgängig gemacht werden.</p>",
|
||||
"DS4.SpellMinimumLevel": "Zugangsstufe",
|
||||
"DS4.SpellMinimumLevelDescription": "Die minimale Stufe, ab der ein Zauberwirker den Zauberspruch erlernen kann.",
|
||||
"DS4.SpellCasterClassHealer": "Heiler",
|
||||
|
@ -189,6 +193,9 @@
|
|||
"DS4.CombatValuesRangedAttack": "Schießen",
|
||||
"DS4.CombatValuesSpellcasting": "Zaubern",
|
||||
"DS4.CombatValuesTargetedSpellcasting": "Zielzaubern",
|
||||
"DS4.CombatValuesMana": "Mana",
|
||||
"DS4.CombatValuesManaCurrent": "Aktuelles Mana",
|
||||
"DS4.CombatValuesManaCurrentAbbr": "MP",
|
||||
"DS4.CombatValuesHitPointsSheet": "Lebenskraft",
|
||||
"DS4.CombatValuesDefenseSheet": "Abwehr",
|
||||
"DS4.CombatValuesInitiativeSheet": "Initiative",
|
||||
|
@ -197,6 +204,7 @@
|
|||
"DS4.CombatValuesRangedAttackSheet": "Schießen",
|
||||
"DS4.CombatValuesSpellcastingSheet": "Zaubern",
|
||||
"DS4.CombatValuesTargetedSpellcastingSheet": "Zielzaubern",
|
||||
"DS4.CombatValuesManaSheet": "Mana",
|
||||
"DS4.CharacterBaseInfoRace": "Volk",
|
||||
"DS4.CharacterBaseInfoClass": "Klasse",
|
||||
"DS4.CharacterBaseInfoHeroClass": "Heldenklasse",
|
||||
|
@ -311,9 +319,11 @@
|
|||
"DS4.TooltipModifier": "Modifikator",
|
||||
"DS4.TooltipEffects": "Effekte",
|
||||
"DS4.SettingUseSlayingDiceForAutomatedChecksName": "Slayende Würfel",
|
||||
"DS4.SettingUseSlayingDiceForAutomatedChecksHint": "Benutze Slayende Würfel bei automatisierten Proben.",
|
||||
"DS4.SettingUseSlayingDiceForAutomatedChecksHint": "Verwende Slayende Würfel bei automatisierten Proben.",
|
||||
"DS4.SettingShowSlayerPointsName": "Slayerpunkte",
|
||||
"DS4.SettingShowSlayerPointsHint": "Zeige Slayerpunkte im Charakterbogen an.",
|
||||
"DS4.SettingUseManaSystemName": "Manasystem",
|
||||
"DS4.SettingUseManaSystemHint": "Verwende das Manasystem für Zauber.",
|
||||
"DS4.Checks": "Proben",
|
||||
"DS4.ChecksAppraise": "Schätzen",
|
||||
"DS4.ChecksChangeSpell": "Zauber Wechseln",
|
||||
|
|
10
lang/en.json
10
lang/en.json
|
@ -149,6 +149,10 @@
|
|||
"DS4.CooldownDuration100R": "100 Rounds",
|
||||
"DS4.CooldownDuration1D": "1 Day",
|
||||
"DS4.CooldownDurationD20D": "D20 Days",
|
||||
"DS4.ManaCost": "Mana Cost",
|
||||
"DS4.ManaCostDescription": "The amount of mana points casting the spell costs.",
|
||||
"DS4.CalculateManaCost": "Automatically Calculate Mana Cost",
|
||||
"DS4.CalculateManaCostConfirmationQuestion": "<p>The mana cost of the spell is automatically calculated using the table on page 19 of the <a href=\"http://dungeonslayers.net/download/Slay05.pdf\">5th edition of the Slay!</a>.</p><p><strong>Warning:</strong> This process overwrites the existing values and connot be reverted automatically.</p>",
|
||||
"DS4.SpellMinimumLevel": "Minimum Level",
|
||||
"DS4.SpellMinimumLevelDescription": "The minimum level at which a spell caster may learn the spell.",
|
||||
"DS4.SpellCasterClassHealer": "Healer",
|
||||
|
@ -189,6 +193,9 @@
|
|||
"DS4.CombatValuesRangedAttack": "Ranged Attack",
|
||||
"DS4.CombatValuesSpellcasting": "Spellcasting",
|
||||
"DS4.CombatValuesTargetedSpellcasting": "Targeted Spellcasting",
|
||||
"DS4.CombatValuesMana": "Mana",
|
||||
"DS4.CombatValuesManaCurrent": "Current Mana",
|
||||
"DS4.CombatValuesManaCurrentAbbr": "MP",
|
||||
"DS4.CombatValuesHitPointsSheet": "Hit Points",
|
||||
"DS4.CombatValuesDefenseSheet": "Defense",
|
||||
"DS4.CombatValuesInitiativeSheet": "Initiative",
|
||||
|
@ -197,6 +204,7 @@
|
|||
"DS4.CombatValuesRangedAttackSheet": "RAT",
|
||||
"DS4.CombatValuesSpellcastingSheet": "Spellcasting",
|
||||
"DS4.CombatValuesTargetedSpellcastingSheet": "TSC",
|
||||
"DS4.CombatValuesManaSheet": "Mana",
|
||||
"DS4.CharacterBaseInfoRace": "Race",
|
||||
"DS4.CharacterBaseInfoClass": "Class",
|
||||
"DS4.CharacterBaseInfoHeroClass": "Hero Class",
|
||||
|
@ -314,6 +322,8 @@
|
|||
"DS4.SettingUseSlayingDiceForAutomatedChecksHint": "Use Slaying Dice for automated checks.",
|
||||
"DS4.SettingShowSlayerPointsName": "Slayer Points",
|
||||
"DS4.SettingShowSlayerPointsHint": "Show Slayer Points in the character sheet.",
|
||||
"DS4.SettingUseManaSystemName": "Mana System",
|
||||
"DS4.SettingUseManaSystemHint": "Use the Mana System for spells.",
|
||||
"DS4.Checks": "Checks",
|
||||
"DS4.ChecksAppraise": "Appraise",
|
||||
"DS4.ChecksChangeSpell": "Change Spell",
|
||||
|
|
|
@ -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.3",
|
||||
"@league-of-foundry-developers/foundry-vtt-types": "9.249.4",
|
||||
"@rollup/plugin-typescript": "8.3.0",
|
||||
"@seald-io/nedb": "2.2.1",
|
||||
"@types/fs-extra": "9.0.13",
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
place-items: center;
|
||||
row-gap: 0.125em;
|
||||
|
||||
&__value {
|
||||
&__total {
|
||||
$combat-values-icons-path: "#{variables.$official-icons-path}/combat-values";
|
||||
@include mixins.centered-content;
|
||||
|
||||
|
@ -49,6 +49,9 @@
|
|||
&--targetedSpellcasting {
|
||||
background-image: url("#{$combat-values-icons-path}/targeted-spellcasting.png");
|
||||
}
|
||||
&--mana {
|
||||
background-image: url("#{$combat-values-icons-path}/mana.png");
|
||||
}
|
||||
}
|
||||
|
||||
&__label {
|
||||
|
|
11
scss/components/shared/_form_field_icon_button.scss
Normal file
11
scss/components/shared/_form_field_icon_button.scss
Normal file
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 Johannes Loher
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
.ds4-form-field-icon-button {
|
||||
&__icon {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
13
scss/components/shared/_form_field_input_extra_slim.scss
Normal file
13
scss/components/shared/_form_field_input_extra_slim.scss
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 Johannes Loher
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
.ds4-form-field-input-extra-slim {
|
||||
&[type="number"],
|
||||
&[type="text"] {
|
||||
flex: 0 0 32px !important; // needs to be made more specific to override foundry's style
|
||||
text-align: center;
|
||||
}
|
||||
}
|
|
@ -15,6 +15,8 @@
|
|||
@use "components/shared/control_button_group";
|
||||
@use "components/shared/editor";
|
||||
@use "components/shared/embedded_document_list";
|
||||
@use "components/shared/form_field_icon_button";
|
||||
@use "components/shared/form_field_input_extra_slim";
|
||||
@use "components/shared/rollable_image";
|
||||
@use "components/shared/sheet_body";
|
||||
@use "components/shared/sheet_form";
|
||||
|
|
|
@ -25,6 +25,11 @@ const defaultData: DS4SpellDataSourceData = {
|
|||
unit: "custom",
|
||||
},
|
||||
cooldownDuration: "0r",
|
||||
manaCost: {
|
||||
healer: null,
|
||||
wizard: null,
|
||||
sorcerer: null,
|
||||
},
|
||||
minimumLevels: {
|
||||
healer: null,
|
||||
wizard: null,
|
||||
|
|
|
@ -24,7 +24,7 @@ type DS4ActorDataPropertiesDataAttributes = {
|
|||
type DS4ActorDataPropertiesDataTraits = { [Key in keyof typeof DS4.i18n.traits]: ModifiableDataBaseTotal<number> };
|
||||
|
||||
type DS4ActorDataPropertiesDataCombatValues = {
|
||||
[Key in keyof typeof DS4.i18n.combatValues]: Key extends "hitPoints"
|
||||
[Key in keyof typeof DS4.i18n.combatValues]: Key extends "hitPoints" | "mana"
|
||||
? ResourceDataBaseTotalMax<number>
|
||||
: ModifiableDataBaseTotal<number>;
|
||||
};
|
||||
|
|
|
@ -47,12 +47,12 @@ export class DS4Actor extends Actor {
|
|||
|
||||
const attributes = data.data.attributes;
|
||||
Object.values(attributes).forEach(
|
||||
(attribute: ModifiableDataBaseTotal<number>) => (attribute.total = attribute.base + attribute.mod),
|
||||
(attribute: ModifiableDataBaseTotal<number>) => (attribute.total = attribute.base + (attribute.mod ?? 0)),
|
||||
);
|
||||
|
||||
const traits = data.data.traits;
|
||||
Object.values(traits).forEach(
|
||||
(trait: ModifiableDataBaseTotal<number>) => (trait.total = trait.base + trait.mod),
|
||||
(trait: ModifiableDataBaseTotal<number>) => (trait.total = trait.base + (trait.mod ?? 0)),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -158,6 +158,8 @@ export class DS4Actor extends Actor {
|
|||
});
|
||||
|
||||
this.data.data.combatValues.hitPoints.max = this.data.data.combatValues.hitPoints.total;
|
||||
this.data.data.combatValues.mana.max = this.data.data.combatValues.mana.total;
|
||||
|
||||
this.data.data.checks.defend = this.data.data.combatValues.defense.total;
|
||||
}
|
||||
|
||||
|
@ -166,7 +168,7 @@ export class DS4Actor extends Actor {
|
|||
* given in dot notation.
|
||||
*/
|
||||
get finalDerivedDataProperties(): string[] {
|
||||
return ["data.combatValues.hitPoints.max", "data.checks.defend"];
|
||||
return ["data.combatValues.hitPoints.max", "data.combatValues.mana.max", "data.checks.defend"];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -203,9 +205,11 @@ export class DS4Actor extends Actor {
|
|||
data.attributes.mind.total + data.traits.aura.total - spellMalusOfEquippedItems;
|
||||
data.combatValues.targetedSpellcasting.base =
|
||||
data.attributes.mind.total + data.traits.dexterity.total - spellMalusOfEquippedItems;
|
||||
data.combatValues.mana.base = data.attributes.mind.total + data.traits.aura.total;
|
||||
|
||||
Object.values(data.combatValues).forEach(
|
||||
(combatValue: ModifiableDataBaseTotal<number>) => (combatValue.total = combatValue.base + combatValue.mod),
|
||||
(combatValue: ModifiableDataBaseTotal<number>) =>
|
||||
(combatValue.total = combatValue.base + (combatValue.mod ?? 0)),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,13 @@ export class DS4Character extends DS4Actor {
|
|||
get ownableItemTypes(): Array<ItemType> {
|
||||
return [...super.ownableItemTypes, "talent", "racialAbility", "language", "alphabet"];
|
||||
}
|
||||
|
||||
/** @override */
|
||||
protected prepareCombatValues(): void {
|
||||
super.prepareCombatValues();
|
||||
this.data.data.combatValues.mana.base += this.data.data.progression.level;
|
||||
this.data.data.combatValues.mana.total += this.data.data.progression.level;
|
||||
}
|
||||
}
|
||||
|
||||
export interface DS4Character {
|
||||
|
|
|
@ -11,6 +11,13 @@ export class DS4Creature extends DS4Actor {
|
|||
get ownableItemTypes(): Array<ItemType> {
|
||||
return [...super.ownableItemTypes, "specialCreatureAbility"];
|
||||
}
|
||||
|
||||
/** @override */
|
||||
protected prepareCombatValues(): void {
|
||||
super.prepareCombatValues();
|
||||
this.data.data.combatValues.mana.base += this.data.data.baseInfo.foeFactor;
|
||||
this.data.data.combatValues.mana.total += this.data.data.baseInfo.foeFactor;
|
||||
}
|
||||
}
|
||||
|
||||
export interface DS4Creature {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
export interface ModifiableData<T> {
|
||||
mod: T;
|
||||
mod?: T | null | undefined;
|
||||
}
|
||||
|
||||
export interface HasBase<T> {
|
||||
|
|
|
@ -158,10 +158,11 @@ const i18nKeys = {
|
|||
rangedAttack: "DS4.CombatValuesRangedAttack",
|
||||
spellcasting: "DS4.CombatValuesSpellcasting",
|
||||
targetedSpellcasting: "DS4.CombatValuesTargetedSpellcasting",
|
||||
mana: "DS4.CombatValuesMana",
|
||||
},
|
||||
|
||||
/**
|
||||
* The what do display in the actor sheets for the combat value text (in some languages, abbreviations are necessary)
|
||||
* The what to display in the actor sheets for the combat value text (in some languages, abbreviations are necessary)
|
||||
*/
|
||||
combatValuesSheet: {
|
||||
hitPoints: "DS4.CombatValuesHitPointsSheet",
|
||||
|
@ -172,6 +173,7 @@ const i18nKeys = {
|
|||
rangedAttack: "DS4.CombatValuesRangedAttackSheet",
|
||||
spellcasting: "DS4.CombatValuesSpellcastingSheet",
|
||||
targetedSpellcasting: "DS4.CombatValuesTargetedSpellcastingSheet",
|
||||
mana: "DS4.CombatValuesManaSheet",
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
1
src/global.d.ts
vendored
1
src/global.d.ts
vendored
|
@ -12,6 +12,7 @@ declare global {
|
|||
"ds4.showSlayerPoints": boolean;
|
||||
"ds4.classes": Classes;
|
||||
"ds4.heroClasses": HeroClasses;
|
||||
"ds4.useManaSystem": boolean;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@ export default async function registerHandlebarsPartials(): Promise<void> {
|
|||
"systems/ds4/templates/sheets/item/tabs/properties.hbs",
|
||||
"systems/ds4/templates/sheets/shared/components/add-button.hbs",
|
||||
"systems/ds4/templates/sheets/shared/components/control-button-group.hbs",
|
||||
"systems/ds4/templates/sheets/shared/components/form-field-icon-button.hbs",
|
||||
"systems/ds4/templates/sheets/shared/components/rollable-image.hbs",
|
||||
];
|
||||
await loadTemplates(templatePaths);
|
||||
|
|
|
@ -16,6 +16,7 @@ import registerHandlebarsPartials from "../handlebars/handlebars-partials";
|
|||
import { getGame } from "../helpers";
|
||||
import { DS4ItemSheet } from "../item/item-sheet";
|
||||
import { DS4ItemProxy } from "../item/proxy";
|
||||
import { DS4SpellSheet } from "../item/spell/spell-sheet";
|
||||
import logger from "../logger";
|
||||
import { macros } from "../macros/macros";
|
||||
import { migration } from "../migrations";
|
||||
|
@ -69,7 +70,25 @@ async function init() {
|
|||
Actors.registerSheet("ds4", DS4CharacterSheet, { types: ["character"], makeDefault: true });
|
||||
Actors.registerSheet("ds4", DS4CreatureSheet, { types: ["creature"], makeDefault: true });
|
||||
Items.unregisterSheet("core", ItemSheet);
|
||||
Items.registerSheet("ds4", DS4ItemSheet, { makeDefault: true });
|
||||
Items.registerSheet("ds4", DS4ItemSheet, {
|
||||
types: [
|
||||
"weapon",
|
||||
"armor",
|
||||
"shield",
|
||||
"equipment",
|
||||
"loot",
|
||||
"talent",
|
||||
"racialAbility",
|
||||
"language",
|
||||
"alphabet",
|
||||
"specialCreatureAbility",
|
||||
],
|
||||
makeDefault: true,
|
||||
});
|
||||
Items.registerSheet("ds4", DS4SpellSheet, {
|
||||
types: ["spell"],
|
||||
makeDefault: true,
|
||||
});
|
||||
|
||||
preloadFonts();
|
||||
await registerHandlebarsPartials();
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import { DS4ActiveEffect } from "../active-effect";
|
||||
import { DS4 } from "../config";
|
||||
import { getGame } from "../helpers";
|
||||
import { DS4Settings, getDS4Settings } from "../settings";
|
||||
import notifications from "../ui/notifications";
|
||||
import { enforce } from "../utils";
|
||||
import { isDS4ItemDataTypePhysical } from "./item-data-source-base";
|
||||
|
@ -40,6 +41,7 @@ export class DS4ItemSheet extends ItemSheet<ItemSheet.Options, DS4ItemSheetData>
|
|||
isOwned: this.item.isOwned,
|
||||
actor: this.item.actor,
|
||||
isPhysical: isDS4ItemDataTypePhysical(this.item.data.data),
|
||||
settings: getDS4Settings(),
|
||||
};
|
||||
return data;
|
||||
}
|
||||
|
@ -128,6 +130,7 @@ interface DS4ItemSheetData extends ItemSheet.Data<ItemSheet.Options> {
|
|||
isOwned: boolean;
|
||||
actor: DS4ItemSheet["item"]["actor"];
|
||||
isPhysical: boolean;
|
||||
settings: DS4Settings;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
49
src/item/spell/calculate-mana-const.ts
Normal file
49
src/item/spell/calculate-mana-const.ts
Normal file
|
@ -0,0 +1,49 @@
|
|||
// SPDX-FileCopyrightText: 2022 Johannes Loher
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import type { CooldownDuration, DS4SpellDataSourceData } from "./spell-data-source";
|
||||
|
||||
type Level = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20;
|
||||
|
||||
export function calculateManaCost({
|
||||
minimumLevels,
|
||||
cooldownDuration,
|
||||
}: DS4SpellDataSourceData): DS4SpellDataSourceData["manaCost"] {
|
||||
// prettier-ignore
|
||||
const magicalManaTable: Record<Level, Record<CooldownDuration, number>> = {
|
||||
1: { "0r": 1, "1r": 2, "2r": 2, "5r": 2, "10r": 2, "100r": 3, "1d": 4, "d20d": 5 },
|
||||
2: { "0r": 1, "1r": 2, "2r": 2, "5r": 2, "10r": 3, "100r": 3, "1d": 4, "d20d": 5 },
|
||||
3: { "0r": 2, "1r": 2, "2r": 2, "5r": 3, "10r": 3, "100r": 4, "1d": 5, "d20d": 6 },
|
||||
4: { "0r": 3, "1r": 3, "2r": 3, "5r": 4, "10r": 4, "100r": 5, "1d": 6, "d20d": 7 },
|
||||
5: { "0r": 4, "1r": 4, "2r": 4, "5r": 5, "10r": 5, "100r": 6, "1d": 7, "d20d": 8 },
|
||||
6: { "0r": 4, "1r": 5, "2r": 5, "5r": 6, "10r": 6, "100r": 7, "1d": 7, "d20d": 8 },
|
||||
7: { "0r": 5, "1r": 6, "2r": 6, "5r": 7, "10r": 7, "100r": 7, "1d": 8, "d20d": 9 },
|
||||
8: { "0r": 6, "1r": 6, "2r": 7, "5r": 7, "10r": 7, "100r": 8, "1d": 8, "d20d": 9 },
|
||||
9: { "0r": 7, "1r": 7, "2r": 7, "5r": 8, "10r": 8, "100r": 8, "1d": 9, "d20d": 10 },
|
||||
10: { "0r": 7, "1r": 8, "2r": 8, "5r": 8, "10r": 9, "100r": 8, "1d": 10, "d20d": 11 },
|
||||
11: { "0r": 8, "1r": 8, "2r": 9, "5r": 9, "10r": 9, "100r": 10, "1d": 10, "d20d": 11 },
|
||||
12: { "0r": 9, "1r": 9, "2r": 9, "5r": 9, "10r": 10, "100r": 11, "1d": 11, "d20d": 12 },
|
||||
13: { "0r": 10, "1r": 10, "2r": 10, "5r": 10, "10r": 11, "100r": 12, "1d": 12, "d20d": 13 },
|
||||
14: { "0r": 10, "1r": 11, "2r": 11, "5r": 12, "10r": 12, "100r": 13, "1d": 13, "d20d": 14 },
|
||||
15: { "0r": 11, "1r": 12, "2r": 12, "5r": 12, "10r": 12, "100r": 13, "1d": 14, "d20d": 15 },
|
||||
16: { "0r": 12, "1r": 12, "2r": 12, "5r": 12, "10r": 13, "100r": 14, "1d": 15, "d20d": 15 },
|
||||
17: { "0r": 12, "1r": 13, "2r": 13, "5r": 13, "10r": 14, "100r": 15, "1d": 16, "d20d": 16 },
|
||||
18: { "0r": 13, "1r": 14, "2r": 14, "5r": 14, "10r": 14, "100r": 15, "1d": 16, "d20d": 17 },
|
||||
19: { "0r": 14, "1r": 15, "2r": 15, "5r": 15, "10r": 15, "100r": 15, "1d": 16, "d20d": 17 },
|
||||
20: { "0r": 14, "1r": 15, "2r": 15, "5r": 16, "10r": 16, "100r": 16, "1d": 17, "d20d": 18 },
|
||||
};
|
||||
|
||||
const getManaCostForSpellcasterClass = (spellcasterClass: keyof DS4SpellDataSourceData["manaCost"]) => {
|
||||
const minimumLevel = minimumLevels[spellcasterClass];
|
||||
return minimumLevel !== null
|
||||
? magicalManaTable[Math.clamped(minimumLevel, 1, 20) as Level][cooldownDuration]
|
||||
: null;
|
||||
};
|
||||
|
||||
return {
|
||||
healer: getManaCostForSpellcasterClass("healer"),
|
||||
wizard: getManaCostForSpellcasterClass("wizard"),
|
||||
sorcerer: getManaCostForSpellcasterClass("sorcerer"),
|
||||
};
|
||||
}
|
|
@ -18,6 +18,11 @@ export interface DS4SpellDataSourceData extends DS4ItemDataSourceDataBase, DS4It
|
|||
effectRadius: UnitData<DistanceUnit>;
|
||||
duration: UnitData<TemporalUnit>;
|
||||
cooldownDuration: CooldownDuration;
|
||||
manaCost: {
|
||||
healer: number | null;
|
||||
wizard: number | null;
|
||||
sorcerer: number | null;
|
||||
};
|
||||
minimumLevels: {
|
||||
healer: number | null;
|
||||
wizard: number | null;
|
||||
|
|
35
src/item/spell/spell-sheet.ts
Normal file
35
src/item/spell/spell-sheet.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
// SPDX-FileCopyrightText: 2021 Johannes Loher
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import { getGame } from "../../helpers";
|
||||
import { DS4ItemSheet } from "../item-sheet";
|
||||
import { calculateManaCost } from "./calculate-mana-const";
|
||||
|
||||
import type { DS4Item } from "../item";
|
||||
|
||||
export class DS4SpellSheet extends DS4ItemSheet {
|
||||
/** @override */
|
||||
activateListeners(html: JQuery): void {
|
||||
super.activateListeners(html);
|
||||
|
||||
if (!this.options.editable) return;
|
||||
|
||||
html.find(".ds4-calculate-mana-cost").on("click", this.onCalculateManaCost.bind(this));
|
||||
}
|
||||
|
||||
/** Calculates the mana cost of the spell automatically. */
|
||||
protected onCalculateManaCost(): void {
|
||||
const game = getGame();
|
||||
const manaCost = calculateManaCost(this.item.data.data);
|
||||
Dialog.confirm({
|
||||
title: game.i18n.localize("DS4.CalculateManaCost"),
|
||||
content: game.i18n.localize("DS4.CalculateManaCostConfirmationQuestion"),
|
||||
yes: () => this.item.update({ data: { manaCost } }),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export interface DS4SpellSheet {
|
||||
object: DS4Item & { data: { type: "spell"; _source: { type: "spell" } } };
|
||||
}
|
|
@ -9,7 +9,7 @@ export class DS4Talent extends DS4Item {
|
|||
prepareDerivedData(): void {
|
||||
super.prepareDerivedData();
|
||||
const data = this.data.data;
|
||||
data.rank.total = data.rank.base + data.rank.mod;
|
||||
data.rank.total = data.rank.base + (data.rank.mod ?? 0);
|
||||
}
|
||||
|
||||
/** @override */
|
||||
|
|
|
@ -58,6 +58,16 @@ export function registerSystemSettings(): void {
|
|||
restricted: true,
|
||||
type: ClassConfig,
|
||||
});
|
||||
|
||||
game.settings.register("ds4", "useManaSystem", {
|
||||
name: "DS4.SettingUseManaSystemName",
|
||||
hint: "DS4.SettingUseManaSystemHint",
|
||||
scope: "world",
|
||||
config: true,
|
||||
type: Boolean,
|
||||
default: false,
|
||||
onChange: renderActorAndSpellSheets,
|
||||
});
|
||||
}
|
||||
|
||||
export interface DS4Settings {
|
||||
|
@ -66,6 +76,7 @@ export interface DS4Settings {
|
|||
showSlayerPoints: boolean;
|
||||
classes: Classes;
|
||||
heroClasses: HeroClasses;
|
||||
useManaSystem: boolean;
|
||||
}
|
||||
|
||||
export function getDS4Settings(): DS4Settings {
|
||||
|
@ -76,6 +87,7 @@ export function getDS4Settings(): DS4Settings {
|
|||
showSlayerPoints: game.settings.get("ds4", "showSlayerPoints"),
|
||||
classes: game.settings.get("ds4", "classes"),
|
||||
heroClasses: game.settings.get("ds4", "heroClasses"),
|
||||
useManaSystem: game.settings.get("ds4", "useManaSystem"),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,10 @@
|
|||
},
|
||||
"targetedSpellcasting": {
|
||||
"mod": 0
|
||||
},
|
||||
"mana": {
|
||||
"mod": 0,
|
||||
"value": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -188,6 +192,11 @@
|
|||
"unit": "custom"
|
||||
},
|
||||
"cooldownDuration": "0r",
|
||||
"manaCost": {
|
||||
"healer": null,
|
||||
"wizard": null,
|
||||
"sorcerer": null
|
||||
},
|
||||
"minimumLevels": {
|
||||
"healer": null,
|
||||
"wizard": null,
|
||||
|
|
|
@ -16,6 +16,18 @@ SPDX-License-Identifier: MIT
|
|||
id="data.combatValues.hitPoints.value-{{data._id}}" value="{{data.data.combatValues.hitPoints.value}}"
|
||||
data-dtype="Number" />
|
||||
</div>
|
||||
{{!-- TODO: Find a better place for this --}}
|
||||
{{#if settings.useManaSystem}}
|
||||
<div class="ds4-actor-progression__entry">
|
||||
<h2 class="ds4-actor-progression__label"><label for="data.mana.value-{{data._id}}"
|
||||
title="{{localize 'DS4.CombatValuesManaCurrent'}}">{{localize
|
||||
"DS4.CombatValuesManaCurrentAbbr"}}</label>
|
||||
</h2>
|
||||
<input class="ds4-actor-progression__input" type="number" name="data.combatValues.mana.value"
|
||||
id="data.combatValues.mana.value-{{data._id}}" value="{{data.data.combatValues.mana.value}}"
|
||||
data-dtype="Number" />
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if (eq data.type "character")}}
|
||||
{{#if settings.showSlayerPoints}}
|
||||
<div class="ds4-actor-progression__entry">
|
||||
|
|
|
@ -15,7 +15,7 @@ SPDX-License-Identifier: MIT
|
|||
--}}
|
||||
|
||||
<div class="ds4-combat-value">
|
||||
<div class="ds4-combat-value__value ds4-combat-value__value--{{combat-value-key}}"
|
||||
<div class="ds4-combat-value__total ds4-combat-value__total--{{combat-value-key}}"
|
||||
title="{{combat-value-title}}: {{combat-value-data.tooltip}}">
|
||||
{{combat-value-data.total}}
|
||||
</div>
|
||||
|
|
|
@ -7,9 +7,11 @@ SPDX-License-Identifier: MIT
|
|||
|
||||
<div class="ds4-combat-values">
|
||||
{{#each config.i18n.combatValues as |combat-value-title combat-value-key|}}
|
||||
{{#unless (and (eq combat-value-key "mana") (not ../settings.useManaSystem)) }}
|
||||
{{> systems/ds4/templates/sheets/actor/components/combat-value.hbs combat-value-key=combat-value-key
|
||||
combat-value-data=(lookup ../data.data.combatValues combat-value-key) combat-value-label=(lookup
|
||||
../config.i18n.combatValuesSheet combat-value-key) combat-value-title=combat-value-title
|
||||
actor-id=../data._id}}
|
||||
{{/unless}}
|
||||
{{/each}}
|
||||
</div>
|
||||
|
|
|
@ -94,18 +94,42 @@ SPDX-License-Identifier: MIT
|
|||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{{#if settings.useManaSystem}}
|
||||
<div class="form-group slim">
|
||||
<label title="{{localize 'DS4.ManaCostDescription'}}">{{localize "DS4.ManaCost"}}</label>
|
||||
<div class="form-fields">
|
||||
{{> systems/ds4/templates/sheets/shared/components/form-field-icon-button.hbs
|
||||
class="ds4-calculate-mana-cost" title="DS4.CalculateManaCost" faClasses="fas fa-magic"}}
|
||||
<label for="data.manaCost.healer-{{data._id}}">{{localize "DS4.SpellCasterClassHealer"}}</label>
|
||||
<input id="data.manaCost.healer-{{data._id}}" class="ds4-form-field-input-extra-slim" data-dtype="Number"
|
||||
type="number" min="0" step="1" name="data.manaCost.healer" placeholder="–"
|
||||
value="{{data.data.manaCost.healer}}" />
|
||||
<label for="data.manaCost.sorcerer-{{data._id}}">{{localize "DS4.SpellCasterClassSorcerer"}}</label>
|
||||
<input id="data.manaCost.sorcerer-{{data._id}}" class="ds4-form-field-input-extra-slim" data-dtype="Number"
|
||||
type="number" min="0" step="1" name="data.manaCost.sorcerer" placeholder="–"
|
||||
value="{{data.data.manaCost.sorcerer}}" />
|
||||
<label for="data.manaCost.wizard-{{data._id}}">{{localize "DS4.SpellCasterClassWizard"}}</label>
|
||||
<input id="data.manaCost.wizard-{{data._id}}" class="ds4-form-field-input-extra-slim" data-dtype="Number"
|
||||
type="number" min="0" step="1" name="data.manaCost.wizard" placeholder="–"
|
||||
value="{{data.data.manaCost.wizard}}" />
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="form-group slim">
|
||||
<label title="{{localize 'DS4.SpellMinimumLevelDescription'}}">{{localize "DS4.SpellMinimumLevel"}}</label>
|
||||
<div class="form-fields">
|
||||
<label for="data.minimumLevels.healer-{{data._id}}">{{localize "DS4.SpellCasterClassHealer"}}</label>
|
||||
<input id="data.minimumLevels.healer-{{data._id}}" data-dtype="Number" type="number" min="0" step="1"
|
||||
name="data.minimumLevels.healer" placeholder="–" value="{{data.data.minimumLevels.healer}}" />
|
||||
<input id="data.minimumLevels.healer-{{data._id}}" class="ds4-form-field-input-extra-slim"
|
||||
data-dtype="Number" type="number" min="0" step="1" name="data.minimumLevels.healer" placeholder="–"
|
||||
value="{{data.data.minimumLevels.healer}}" />
|
||||
<label for="data.minimumLevels.sorcerer-{{data._id}}">{{localize "DS4.SpellCasterClassSorcerer"}}</label>
|
||||
<input id="data.minimumLevels.sorcerer-{{data._id}}" data-dtype="Number" type="number" min="0" step="1"
|
||||
name="data.minimumLevels.sorcerer" placeholder="–" value="{{data.data.minimumLevels.sorcerer}}" />
|
||||
<input id="data.minimumLevels.sorcerer-{{data._id}}" class="ds4-form-field-input-extra-slim"
|
||||
data-dtype="Number" type="number" min="0" step="1" name="data.minimumLevels.sorcerer" placeholder="–"
|
||||
value="{{data.data.minimumLevels.sorcerer}}" />
|
||||
<label for="data.minimumLevels.wizard-{{data._id}}">{{localize "DS4.SpellCasterClassWizard"}}</label>
|
||||
<input id="data.minimumLevels.wizard-{{data._id}}" data-dtype="Number" type="number" min="0" step="1"
|
||||
name="data.minimumLevels.wizard" placeholder="–" value="{{data.data.minimumLevels.wizard}}" />
|
||||
<input id="data.minimumLevels.wizard-{{data._id}}" class="ds4-form-field-input-extra-slim"
|
||||
data-dtype="Number" type="number" min="0" step="1" name="data.minimumLevels.wizard" placeholder="–"
|
||||
value="{{data.data.minimumLevels.wizard}}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
{{!--
|
||||
SPDX-FileCopyrightText: 2021 Johannes Loher
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
--}}
|
||||
|
||||
{{!
|
||||
!-- Render a form-field icon button.
|
||||
!-- @param class: A class to identify the button by
|
||||
!-- @param title: The title to use for the button (will be localized)
|
||||
!-- @param faClasses: The Fontawesom classes to use for the icon
|
||||
}}
|
||||
|
||||
<button class="ds4-form-field-icon-button {{class}}" type="button" title="{{localize title}}">
|
||||
<i class="{{faClasses}} ds4-form-field-icon-button__icon"></i>
|
||||
</button>
|
10
yarn.lock
10
yarn.lock
|
@ -892,9 +892,9 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@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"
|
||||
"@league-of-foundry-developers/foundry-vtt-types@npm:9.249.4":
|
||||
version: 9.249.4
|
||||
resolution: "@league-of-foundry-developers/foundry-vtt-types@npm:9.249.4"
|
||||
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: 13bbcafd57637a59f44ee136e5edd78b1fedb3f0327027bd2bae8971f2eed6ad5ad84755cebc32e4b08f788e0bf5c08dd06cbe4709ae89746198658ebb511451
|
||||
checksum: 612721d98bb6e8496d8000e86619615b2ae968ecb643273545c1a73c7d2faeca611f6d3adbc84b99cdf47b706a604226582731e0be560701a801a6a23bb75cae
|
||||
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.3
|
||||
"@league-of-foundry-developers/foundry-vtt-types": 9.249.4
|
||||
"@rollup/plugin-typescript": 8.3.0
|
||||
"@seald-io/nedb": 2.2.1
|
||||
"@types/fs-extra": 9.0.13
|
||||
|
|
Loading…
Reference in a new issue