Adding Prettier

* Added prettier with automatic useage on pre-commit to avoid style breakage
* Ran Prettier on the project
This commit is contained in:
WBHarry 2025-05-23 18:57:50 +02:00 committed by GitHub
parent 820c2df1f4
commit b24cdcc9ed
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
136 changed files with 13929 additions and 12206 deletions

1
.husky/pre-commit Normal file
View file

@ -0,0 +1 @@
npx lint-staged

5
.prettierignore Normal file
View file

@ -0,0 +1,5 @@
node_modules
package-lock.json
package.json
.github
*.hbs

13
.prettierrc Normal file
View file

@ -0,0 +1,13 @@
{
"trailingComma": "none",
"tabWidth": 4,
"useTabs": false,
"semi": true,
"singleQuote": true,
"quoteProps": "consistent",
"bracketSpacing": true,
"arrowParens": "avoid",
"printWidth": 120,
"endOfLine": "lf",
"bracketSameLine": true
}

View file

@ -1,27 +1,47 @@
# Daggerheart # Daggerheart
#### For Foundry VTT #### For Foundry VTT
This is a repo for a Foundry VTT implementation of daggerheart. It is not associated with critical role This is a repo for a Foundry VTT implementation of daggerheart. It is not associated with critical role
or darrington press. or darrington press.
# Table Of Contents # Table Of Contents
- [Overview](#overview) - [Overview](#overview)
- [Developer Guide](#developer-guide) - [Developer Guide](#developer-guide)
# Overview # Overview
# Developer Guide # Developer Guide
#### Coding Practises
##### Branches And Pull Requests
During pre-release development, we are making use of `main` as the development branch. Once release is getting closer we will instead be making a `dev` branch to base development from to make `main` more stable.
When you work on an issue or feature, start from `main` and make a new branch. Branches should be topically named and with the associated Issue number if it relates to an Issue. EX: `#6/Level-Up-Bugginess`.
---
Once you're finished with an issue or feature, open a Pull Request on Github for that branch.
The Reviewers Team will be approving submissions. This is mainly since we have a wide spread of experience with system building and the system itself, and we do want the system to become something great. As time goes on, more collaborators are likely to be added as reviewers.
#### Setup #### Setup
- Open a terminal in the directory with the repo `cd <path>/<to>/<repo>` - Open a terminal in the directory with the repo `cd <path>/<to>/<repo>`
- NOTE: The repo should be placed in the system files are or somewhere else and a link (if on linux) is placed in the system directory - NOTE: The repo should be placed in the system files are or somewhere else and a link (if on linux) is placed in the system directory
- NOTE: Linux link can be made using `ln -snf <path to development folder> daggerheart` inside the system folder - NOTE: Linux link can be made using `ln -snf <path to development folder> daggerheart` inside the system folder
- Install npm `npm install` - Install npm `npm install`
- Update package.json to match your profile - Update package.json to match your profile
``` ```
"start": "concurrently \"rollup -c --watch\" \"node C:/FoundryDev/resources/app/main.js --dataPath=C:/FoundryDevFiles --noupnp\" \"gulp\"", "start": "concurrently \"rollup -c --watch\" \"node C:/FoundryDev/resources/app/main.js --dataPath=C:/FoundryDevFiles --noupnp\" \"gulp\"",
"start-test": "node C:/FoundryDev/resources/app/main.js --dataPath=C:/FoundryDevFiles && rollup -c --watch && gulp", "start-test": "node C:/FoundryDev/resources/app/main.js --dataPath=C:/FoundryDevFiles && rollup -c --watch && gulp",
``` ```
- Replace `C:/FoundryDev/resources/app/main.js` with `<your>/<path>/<to>/<foundry>/<main.js>` - Replace `C:/FoundryDev/resources/app/main.js` with `<your>/<path>/<to>/<foundry>/<main.js>`
- The main is likely in `<Foundry Install Location>/resouces/app/main.js` - The main is likely in `<Foundry Install Location>/resouces/app/main.js`
- Replace `--dataPath=C:/FoundryDevFiles` with `<your>/<path>/<to>/<foundry>/<data>` - Replace `--dataPath=C:/FoundryDevFiles` with `<your>/<path>/<to>/<foundry>/<data>`
@ -29,5 +49,4 @@ or darrington press.
Now you should be able to build the app using `npm start` Now you should be able to build the app using `npm start`
[Foundry VTT Website][1] [Foundry VTT Website][1]
[1]: https://foundryvtt.com/ [1]: https://foundryvtt.com/

View file

@ -17,11 +17,14 @@ Hooks.once('init', () => {
game.system.api = { game.system.api = {
applications, applications,
models, models,
documents, documents
} };
CONFIG.statusEffects = Object.values(SYSTEM.GENERAL.conditions).map(x => ({ ...x, name: game.i18n.localize(x.name) })); CONFIG.statusEffects = Object.values(SYSTEM.GENERAL.conditions).map(x => ({
...x,
name: game.i18n.localize(x.name)
}));
CONFIG.Item.documentClass = documents.DhpItem; CONFIG.Item.documentClass = documents.DhpItem;
CONFIG.Item.dataModels = { CONFIG.Item.dataModels = {
ancestry: models.DhpAncestry, ancestry: models.DhpAncestry,
@ -29,49 +32,49 @@ Hooks.once('init', () => {
class: models.DhpClass, class: models.DhpClass,
subclass: models.DhpSubclass, subclass: models.DhpSubclass,
feature: models.DhpFeature, feature: models.DhpFeature,
domainCard: models.DhpDomainCard, domainCard: models.DhpDomainCard,
miscellaneous: models.DhpMiscellaneous, miscellaneous: models.DhpMiscellaneous,
consumable: models.DhpConsumable, consumable: models.DhpConsumable,
weapon: models.DhpWeapon, weapon: models.DhpWeapon,
armor: models.DhpArmor, armor: models.DhpArmor
}; };
const { Items, Actors } = foundry.documents.collections; const { Items, Actors } = foundry.documents.collections;
Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet); Items.unregisterSheet('core', foundry.appv1.sheets.ItemSheet);
Items.registerSheet(SYSTEM.id, applications.DhpAncestry, {types: ["ancestry"], makeDefault: true}); Items.registerSheet(SYSTEM.id, applications.DhpAncestry, { types: ['ancestry'], makeDefault: true });
Items.registerSheet(SYSTEM.id, applications.DhpCommunity, {types: ["community"], makeDefault: true}); Items.registerSheet(SYSTEM.id, applications.DhpCommunity, { types: ['community'], makeDefault: true });
Items.registerSheet(SYSTEM.id, applications.DhpClassSheet, {types: ["class"], makeDefault: true}); Items.registerSheet(SYSTEM.id, applications.DhpClassSheet, { types: ['class'], makeDefault: true });
Items.registerSheet(SYSTEM.id, applications.DhpSubclass, {types: ["subclass"], makeDefault: true}); Items.registerSheet(SYSTEM.id, applications.DhpSubclass, { types: ['subclass'], makeDefault: true });
Items.registerSheet(SYSTEM.id, applications.DhpFeatureSheet, {types: ["feature"], makeDefault: true}); Items.registerSheet(SYSTEM.id, applications.DhpFeatureSheet, { types: ['feature'], makeDefault: true });
Items.registerSheet(SYSTEM.id, applications.DhpDomainCardSheet, {types: ["domainCard"], makeDefault: true}); Items.registerSheet(SYSTEM.id, applications.DhpDomainCardSheet, { types: ['domainCard'], makeDefault: true });
Items.registerSheet(SYSTEM.id, applications.DhpMiscellaneous, {types: ["miscellaneous"], makeDefault: true}); Items.registerSheet(SYSTEM.id, applications.DhpMiscellaneous, { types: ['miscellaneous'], makeDefault: true });
Items.registerSheet(SYSTEM.id, applications.DhpConsumable, {types: ["consumable"], makeDefault: true}); Items.registerSheet(SYSTEM.id, applications.DhpConsumable, { types: ['consumable'], makeDefault: true });
Items.registerSheet(SYSTEM.id, applications.DhpWeapon, {types: ["weapon"], makeDefault: true}); Items.registerSheet(SYSTEM.id, applications.DhpWeapon, { types: ['weapon'], makeDefault: true });
Items.registerSheet(SYSTEM.id, applications.DhpArmor, {types: ["armor"], makeDefault: true}); Items.registerSheet(SYSTEM.id, applications.DhpArmor, { types: ['armor'], makeDefault: true });
CONFIG.Actor.documentClass = documents.DhpActor; CONFIG.Actor.documentClass = documents.DhpActor;
CONFIG.Actor.dataModels = { CONFIG.Actor.dataModels = {
pc: models.DhpPC, pc: models.DhpPC,
adversary: models.DhpAdversary, adversary: models.DhpAdversary,
environment: models.DhpEnvironment, environment: models.DhpEnvironment
}; };
Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet); Actors.unregisterSheet('core', foundry.appv1.sheets.ActorSheet);
Actors.registerSheet(SYSTEM.id, applications.DhpPCSheet, {types: ["pc"], makeDefault: true}); Actors.registerSheet(SYSTEM.id, applications.DhpPCSheet, { types: ['pc'], makeDefault: true });
Actors.registerSheet(SYSTEM.id, applications.DhpAdversarySheet, {types: ["adversary"], makeDefault: true}); Actors.registerSheet(SYSTEM.id, applications.DhpAdversarySheet, { types: ['adversary'], makeDefault: true });
Actors.registerSheet(SYSTEM.id, applications.DhpEnvironment, {types: ["environment"], makeDefault: true}); Actors.registerSheet(SYSTEM.id, applications.DhpEnvironment, { types: ['environment'], makeDefault: true });
CONFIG.Combat.dataModels = { CONFIG.Combat.dataModels = {
base: models.DhpCombat, base: models.DhpCombat
}; };
CONFIG.Combatant.dataModels = { CONFIG.Combatant.dataModels = {
base: models.DhpCombatant, base: models.DhpCombatant
}; };
CONFIG.ChatMessage.dataModels ={ CONFIG.ChatMessage.dataModels = {
dualityRoll: models.DhpDualityRoll, dualityRoll: models.DhpDualityRoll,
adversaryRoll: models.DhpAdversaryRoll, adversaryRoll: models.DhpAdversaryRoll,
abilityUse: models.DhpAbilityUse, abilityUse: models.DhpAbilityUse
}; };
CONFIG.ChatMessage.documentClass = applications.DhpChatMessage; CONFIG.ChatMessage.documentClass = applications.DhpChatMessage;
@ -90,22 +93,24 @@ Hooks.once('init', () => {
return preloadHandlebarsTemplates(); return preloadHandlebarsTemplates();
}); });
Hooks.once('dicesoniceready', () => { Hooks.once('dicesoniceready', () => {});
});
Hooks.on(socketEvent.GMUpdate, async (action, uuid, update) => { Hooks.on(socketEvent.GMUpdate, async (action, uuid, update) => {
if(game.user.isGM){ if (game.user.isGM) {
const document = uuid ? await fromUuid(uuid) : null; const document = uuid ? await fromUuid(uuid) : null;
switch(action){ switch (action) {
case GMUpdateEvent.UpdateDocument: case GMUpdateEvent.UpdateDocument:
if(document && update){ if (document && update) {
await document.update(update); await document.update(update);
} }
break; break;
case GMUpdateEvent.UpdateFear: case GMUpdateEvent.UpdateFear:
if(game.user.isGM){ if (game.user.isGM) {
await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear, Math.max(Math.min(update, 6), 0)); await game.settings.set(
SYSTEM.id,
SYSTEM.SETTINGS.gameSettings.Resources.Fear,
Math.max(Math.min(update, 6), 0)
);
Hooks.callAll(socketEvent.DhpFearUpdate); Hooks.callAll(socketEvent.DhpFearUpdate);
await game.socket.emit(`system.${SYSTEM.id}`, { action: socketEvent.DhpFearUpdate }); await game.socket.emit(`system.${SYSTEM.id}`, { action: socketEvent.DhpFearUpdate });
} }
@ -114,27 +119,27 @@ Hooks.on(socketEvent.GMUpdate, async (action, uuid, update) => {
} }
}); });
const preloadHandlebarsTemplates = async function() { const preloadHandlebarsTemplates = async function () {
return foundry.applications.handlebars.loadTemplates([ return foundry.applications.handlebars.loadTemplates([
"systems/daggerheart/templates/sheets/parts/attributes.hbs", 'systems/daggerheart/templates/sheets/parts/attributes.hbs',
"systems/daggerheart/templates/sheets/parts/defense.hbs", 'systems/daggerheart/templates/sheets/parts/defense.hbs',
"systems/daggerheart/templates/sheets/parts/armor.hbs", 'systems/daggerheart/templates/sheets/parts/armor.hbs',
"systems/daggerheart/templates/sheets/parts/experience.hbs", 'systems/daggerheart/templates/sheets/parts/experience.hbs',
"systems/daggerheart/templates/sheets/parts/features.hbs", 'systems/daggerheart/templates/sheets/parts/features.hbs',
"systems/daggerheart/templates/sheets/parts/gold.hbs", 'systems/daggerheart/templates/sheets/parts/gold.hbs',
"systems/daggerheart/templates/sheets/parts/health.hbs", 'systems/daggerheart/templates/sheets/parts/health.hbs',
"systems/daggerheart/templates/sheets/parts/hope.hbs", 'systems/daggerheart/templates/sheets/parts/hope.hbs',
"systems/daggerheart/templates/sheets/parts/inventory.hbs", 'systems/daggerheart/templates/sheets/parts/inventory.hbs',
"systems/daggerheart/templates/sheets/parts/weapons.hbs", 'systems/daggerheart/templates/sheets/parts/weapons.hbs',
"systems/daggerheart/templates/sheets/parts/domainCard.hbs", 'systems/daggerheart/templates/sheets/parts/domainCard.hbs',
"systems/daggerheart/templates/sheets/parts/heritage.hbs", 'systems/daggerheart/templates/sheets/parts/heritage.hbs',
"systems/daggerheart/templates/sheets/parts/subclassFeature.hbs", 'systems/daggerheart/templates/sheets/parts/subclassFeature.hbs',
"systems/daggerheart/templates/sheets/parts/effects.hbs", 'systems/daggerheart/templates/sheets/parts/effects.hbs',
"systems/daggerheart/templates/sheets/pc/sections/inventory.hbs", 'systems/daggerheart/templates/sheets/pc/sections/inventory.hbs',
"systems/daggerheart/templates/sheets/pc/sections/loadout.hbs", 'systems/daggerheart/templates/sheets/pc/sections/loadout.hbs',
"systems/daggerheart/templates/sheets/pc/parts/heritageCard.hbs", 'systems/daggerheart/templates/sheets/pc/parts/heritageCard.hbs',
"systems/daggerheart/templates/sheets/pc/parts/advancementCard.hbs", 'systems/daggerheart/templates/sheets/pc/parts/advancementCard.hbs',
"systems/daggerheart/templates/views/parts/level.hbs", 'systems/daggerheart/templates/views/parts/level.hbs',
"systems/daggerheart/templates/components/slider.hbs", 'systems/daggerheart/templates/components/slider.hbs'
]); ]);
}; };

View file

@ -2,20 +2,15 @@
var gulp = require('gulp'); var gulp = require('gulp');
var less = require('gulp-less'); var less = require('gulp-less');
gulp.task('less', function(cb) { gulp.task('less', function (cb) {
gulp gulp.src('styles/daggerheart.less').pipe(less()).pipe(gulp.dest('styles'));
.src('styles/daggerheart.less') cb();
.pipe(less())
.pipe(
gulp.dest("styles")
);
cb();
}); });
gulp.task( gulp.task(
'default', 'default',
gulp.series('less', function(cb) { gulp.series('less', function (cb) {
gulp.watch('styles/**/*.less', gulp.series('less')); gulp.watch('styles/**/*.less', gulp.series('less'));
cb(); cb();
}) })
); );

View file

@ -102,7 +102,7 @@
"Fear": "Fear", "Fear": "Fear",
"CriticalSuccess": "Critical Success", "CriticalSuccess": "Critical Success",
"Advantage": "Advantage", "Advantage": "Advantage",
"Disadvantage": "Disadvantage", "Disadvantage": "Disadvantage",
"OK": "OK", "OK": "OK",
"Cancel": "Cancel", "Cancel": "Cancel",
"Or": "Or", "Or": "Or",
@ -472,7 +472,7 @@
}, },
"Timeslowing": { "Timeslowing": {
"Name": "Timeslowing", "Name": "Timeslowing",
"Description": "On any incoming attacks, roll 1d4 and add its value to your Evasion score." "Description": "On any incoming attacks, roll 1d4 and add its value to your Evasion score."
}, },
"Truthseeking": { "Truthseeking": {
"Name": "Truthseeking", "Name": "Truthseeking",
@ -819,7 +819,7 @@
"Bags": "Bags", "Bags": "Bags",
"Chests": "Chests" "Chests": "Chests"
}, },
"Health":{ "Health": {
"Title": "HIT POINTS & STRESS", "Title": "HIT POINTS & STRESS",
"Minor": "Minor", "Minor": "Minor",
"Major": "Major", "Major": "Major",
@ -1064,4 +1064,4 @@
} }
} }
} }
} }

View file

@ -11,4 +11,4 @@ export { default as DhpConsumable } from './sheets/consumable.mjs';
export { default as DhpWeapon } from './sheets/weapon.mjs'; export { default as DhpWeapon } from './sheets/weapon.mjs';
export { default as DhpArmor } from './sheets/armor.mjs'; export { default as DhpArmor } from './sheets/armor.mjs';
export { default as DhpChatMessage } from './chatMessage.mjs'; export { default as DhpChatMessage } from './chatMessage.mjs';
export { default as DhpEnvironment } from './sheets/environment.mjs'; export { default as DhpEnvironment } from './sheets/environment.mjs';

View file

@ -1,10 +1,9 @@
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
export default class AncestrySelectionDialog extends HandlebarsApplicationMixin(ApplicationV2) { export default class AncestrySelectionDialog extends HandlebarsApplicationMixin(ApplicationV2) {
constructor(resolve) {
constructor(resolve){
super({}); super({});
this.resolve = resolve; this.resolve = resolve;
this.data = { this.data = {
ancestries: [], ancestries: [],
@ -13,17 +12,17 @@ export default class AncestrySelectionDialog extends HandlebarsApplicationMixin(
name: '', name: '',
img: null, img: null,
customImg: 'icons/svg/mystery-man.svg', customImg: 'icons/svg/mystery-man.svg',
description: '', description: ''
}, }
}; };
} }
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
tag: 'form', tag: 'form',
classes: ["daggerheart", "views", "ancestry-selection"], classes: ['daggerheart', 'views', 'ancestry-selection'],
position: { position: {
width: 800, width: 800,
height: "auto" height: 'auto'
}, },
actions: { actions: {
selectAncestry: this.selectAncestry, selectAncestry: this.selectAncestry,
@ -31,21 +30,21 @@ export default class AncestrySelectionDialog extends HandlebarsApplicationMixin(
viewItem: this.viewItem, viewItem: this.viewItem,
selectImage: this.selectImage, selectImage: this.selectImage,
editImage: this._onEditImage, editImage: this._onEditImage,
saveAncestry: this.saveAncestry, saveAncestry: this.saveAncestry
}, },
form: { form: {
submitOnChange: true, submitOnChange: true,
closeOnSubmit: false, closeOnSubmit: false
} }
}; };
/** @override */ /** @override */
static PARTS = { static PARTS = {
damageSelection: { damageSelection: {
id: "ancestrySelection", id: 'ancestrySelection',
template: "systems/daggerheart/templates/views/ancestrySelection.hbs" template: 'systems/daggerheart/templates/views/ancestrySelection.hbs'
} }
} };
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -57,10 +56,10 @@ export default class AncestrySelectionDialog extends HandlebarsApplicationMixin(
_attachPartListeners(partId, htmlElement, options) { _attachPartListeners(partId, htmlElement, options) {
super._attachPartListeners(partId, htmlElement, options); super._attachPartListeners(partId, htmlElement, options);
const ancestryNameInput = $(htmlElement).find(".ancestry-name"); const ancestryNameInput = $(htmlElement).find('.ancestry-name');
if(ancestryNameInput.length > 0){ if (ancestryNameInput.length > 0) {
ancestryNameInput.on("change", this.setName.bind(this)); ancestryNameInput.on('change', this.setName.bind(this));
$(htmlElement).find(".ancestry-description").on("change", this.setDescription.bind(this)); $(htmlElement).find('.ancestry-description').on('change', this.setDescription.bind(this));
} }
// $(htmlElement).find(".ancestry-image").on("change", this.selectImage.bind(this)); // $(htmlElement).find(".ancestry-image").on("change", this.selectImage.bind(this));
} }
@ -68,19 +67,26 @@ export default class AncestrySelectionDialog extends HandlebarsApplicationMixin(
async _prepareContext(_options) { async _prepareContext(_options) {
const systemAncestries = Array.from((await game.packs.get('daggerheart.playtest-ancestries')).index).map(x => ({ const systemAncestries = Array.from((await game.packs.get('daggerheart.playtest-ancestries')).index).map(x => ({
...x, ...x,
selected: this.data.ancestries.some(selected => selected.uuid === x.uuid), selected: this.data.ancestries.some(selected => selected.uuid === x.uuid)
})); }));
const customAncestries = game.items.reduce((acc, x) => { const customAncestries = game.items.reduce((acc, x) => {
if(x.type === 'ancestry'){ if (x.type === 'ancestry') {
acc.push({ ...x, uuid: x.uuid, selected: this.data.ancestries.some(selected => selected.uuid === x.uuid) }); acc.push({
...x,
uuid: x.uuid,
selected: this.data.ancestries.some(selected => selected.uuid === x.uuid)
});
} }
return acc; return acc;
}, []); }, []);
const ancestryFeatures = this.data.ancestries.flatMap(x => const ancestryFeatures = this.data.ancestries.flatMap(x =>
x.system.abilities.map(x => ({ ...x, selected: this.data.features.some(selected => selected.uuid === x.uuid) })) x.system.abilities.map(x => ({
...x,
selected: this.data.features.some(selected => selected.uuid === x.uuid)
}))
); );
return { return {
@ -89,13 +95,13 @@ export default class AncestrySelectionDialog extends HandlebarsApplicationMixin(
ancestryFeatures, ancestryFeatures,
selectedAncestries: this.data.ancestries, selectedAncestries: this.data.ancestries,
selectedFeatures: this.data.features, selectedFeatures: this.data.features,
ancestryInfo: this.data.ancestryInfo, ancestryInfo: this.data.ancestryInfo
}; };
} }
static async selectAncestry(_, button) { static async selectAncestry(_, button) {
const newAncestries = [...this.data.ancestries]; const newAncestries = [...this.data.ancestries];
if(!newAncestries.findSplice(x => x.uuid === button.dataset.uuid) && this.data.ancestries.length < 2){ if (!newAncestries.findSplice(x => x.uuid === button.dataset.uuid) && this.data.ancestries.length < 2) {
const ancestry = await fromUuid(button.dataset.uuid); const ancestry = await fromUuid(button.dataset.uuid);
newAncestries.push(ancestry); newAncestries.push(ancestry);
} }
@ -108,7 +114,7 @@ export default class AncestrySelectionDialog extends HandlebarsApplicationMixin(
static async selectFeature(_, button) { static async selectFeature(_, button) {
const newFeatures = [...this.data.features]; const newFeatures = [...this.data.features];
if(!newFeatures.findSplice(x => x.uuid === button.dataset.uuid) && this.data.features.length < 2){ if (!newFeatures.findSplice(x => x.uuid === button.dataset.uuid) && this.data.features.length < 2) {
const feature = await fromUuid(button.dataset.uuid); const feature = await fromUuid(button.dataset.uuid);
newFeatures.push(feature); newFeatures.push(feature);
} }
@ -125,7 +131,7 @@ export default class AncestrySelectionDialog extends HandlebarsApplicationMixin(
this.data.ancestryInfo.name = event.currentTarget.value; this.data.ancestryInfo.name = event.currentTarget.value;
this.render(true); this.render(true);
} }
setDescription(event) { setDescription(event) {
this.data.ancestryInfo.description = event.currentTarget.value; this.data.ancestryInfo.description = event.currentTarget.value;
this.render(true); this.render(true);
@ -139,7 +145,7 @@ export default class AncestrySelectionDialog extends HandlebarsApplicationMixin(
static _onEditImage() { static _onEditImage() {
const fp = new FilePicker({ const fp = new FilePicker({
current: this.data.ancestryInfo.img, current: this.data.ancestryInfo.img,
type: "image", type: 'image',
redirectToRoot: ['icons/svg/mystery-man.svg'], redirectToRoot: ['icons/svg/mystery-man.svg'],
callback: async path => this._updateImage.bind(this)(path), callback: async path => this._updateImage.bind(this)(path),
top: this.position.top + 40, top: this.position.top + 40,
@ -148,17 +154,32 @@ export default class AncestrySelectionDialog extends HandlebarsApplicationMixin(
return fp.browse(); return fp.browse();
} }
_updateImage(path){ _updateImage(path) {
this.data.ancestryInfo.customImg = path; this.data.ancestryInfo.customImg = path;
this.data.ancestryInfo.img = path; this.data.ancestryInfo.img = path;
this.render(true); this.render(true);
} }
static async saveAncestry(_, button) { static async saveAncestry(_, button) {
if(this.data.ancestries.length === 2){ if (this.data.ancestries.length === 2) {
const { name, img, description } = this.data.ancestryInfo; const { name, img, description } = this.data.ancestryInfo;
this.resolve({ data: { name: name, img: img, type: "ancestry", system: { description: description, abilities: this.data.features.map(x => ({ name: x.name, img: x.img, uuid: x.uuid, subclassLevel: '' })) }}}); this.resolve({
data: {
name: name,
img: img,
type: 'ancestry',
system: {
description: description,
abilities: this.data.features.map(x => ({
name: x.name,
img: x.img,
uuid: x.uuid,
subclassLevel: ''
}))
}
}
});
} else { } else {
this.resolve({ data: this.data.ancestries[0].toObject() }); this.resolve({ data: this.data.ancestries[0].toObject() });
} }
@ -170,7 +191,7 @@ export default class AncestrySelectionDialog extends HandlebarsApplicationMixin(
// export default class DamageSelectionDialog extends FormApplication { // export default class DamageSelectionDialog extends FormApplication {
// constructor(rollString, bonusDamage, resolve){ // constructor(rollString, bonusDamage, resolve){
// super({}, {}); // super({}, {});
// this.data = { // this.data = {
// rollString, // rollString,
// bonusDamage: bonusDamage.map(x => ({ // bonusDamage: bonusDamage.map(x => ({
@ -180,11 +201,11 @@ export default class AncestrySelectionDialog extends HandlebarsApplicationMixin(
// } // }
// this.resolve = resolve; // this.resolve = resolve;
// } // }
// get title (){ // get title (){
// return 'Damage Options'; // return 'Damage Options';
// } // }
// static get defaultOptions() { // static get defaultOptions() {
// const defaults = super.defaultOptions; // const defaults = super.defaultOptions;
// const overrides = { // const overrides = {
@ -195,35 +216,35 @@ export default class AncestrySelectionDialog extends HandlebarsApplicationMixin(
// closeOnSubmit: false, // closeOnSubmit: false,
// classes: ["daggerheart", "views", "damage-selection"], // classes: ["daggerheart", "views", "damage-selection"],
// }; // };
// const mergedOptions = foundry.utils.mergeObject(defaults, overrides); // const mergedOptions = foundry.utils.mergeObject(defaults, overrides);
// return mergedOptions; // return mergedOptions;
// } // }
// async getData(){ // async getData(){
// const context = super.getData(); // const context = super.getData();
// context.rollString = this.data.rollString; // context.rollString = this.data.rollString;
// context.bonusDamage = this.data.bonusDamage; // context.bonusDamage = this.data.bonusDamage;
// return context; // return context;
// } // }
// activateListeners(html) { // activateListeners(html) {
// super.activateListeners(html); // super.activateListeners(html);
// html.find('.roll-button').click(this.finish.bind(this)); // html.find('.roll-button').click(this.finish.bind(this));
// html.find('.').change(); // html.find('.').change();
// } // }
// // async _updateObject(_, formData) { // // async _updateObject(_, formData) {
// // const data = foundry.utils.expandObject(formData); // // const data = foundry.utils.expandObject(formData);
// // this.data = foundry.utils.mergeObject(this.data, data); // // this.data = foundry.utils.mergeObject(this.data, data);
// // this.render(true); // // this.render(true);
// // } // // }
// finish(){ // finish(){
// this.resolve(this.data); // this.resolve(this.data);
// this.close(); // this.close();
// } // }
// } // }

View file

@ -1,9 +1,9 @@
export default class DhpChatMesssage extends ChatMessage { export default class DhpChatMesssage extends ChatMessage {
async renderHTML() { async renderHTML() {
if(this.type === 'dualityRoll' || this.type === 'adversaryRoll' || this.type === 'abilityUse'){ if (this.type === 'dualityRoll' || this.type === 'adversaryRoll' || this.type === 'abilityUse') {
this.content = await foundry.applications.handlebars.renderTemplate(this.content, this.system); this.content = await foundry.applications.handlebars.renderTemplate(this.content, this.system);
} }
return super.renderHTML(); return super.renderHTML();
} }
} }

View file

@ -1,8 +1,8 @@
import DaggerheartSheet from '../sheets/daggerheart-sheet.mjs'; import DaggerheartSheet from '../sheets/daggerheart-sheet.mjs';
const {ApplicationV2} = foundry.applications.api; const { ApplicationV2 } = foundry.applications.api;
export default class DaggerheartActionConfig extends DaggerheartSheet(ApplicationV2) { export default class DaggerheartActionConfig extends DaggerheartSheet(ApplicationV2) {
constructor(action){ constructor(action) {
super({}); super({});
this.action = action; this.action = action;
@ -10,40 +10,47 @@ export default class DaggerheartActionConfig extends DaggerheartSheet(Applicatio
} }
// get title(){ // get title(){
// return `Action - ${this.action.name}`; // return `Action - ${this.action.name}`;
// } // }
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
tag: 'form', tag: 'form',
id: "daggerheart-action", id: 'daggerheart-action',
classes: ["daggerheart", "views", "action"], classes: ['daggerheart', 'views', 'action'],
position: { width: 600, height: 'auto' }, position: { width: 600, height: 'auto' },
actions: { actions: {
toggleSection: this.toggleSection, toggleSection: this.toggleSection
}, },
form: { form: {
handler: this.updateForm, handler: this.updateForm,
closeOnSubmit: true, closeOnSubmit: true
}, }
}; };
static PARTS = { static PARTS = {
form: { form: {
id: "action", id: 'action',
template: "systems/daggerheart/templates/views/action.hbs" template: 'systems/daggerheart/templates/views/action.hbs'
} }
} };
_getTabs() { _getTabs() {
const tabs = { const tabs = {
effects: { active: true, cssClass: '', group: 'primary', id: 'effects', icon: null, label: 'Effects' }, effects: { active: true, cssClass: '', group: 'primary', id: 'effects', icon: null, label: 'Effects' },
useage: { active: false, cssClass: '', group: 'primary', id: 'useage', icon: null, label: 'Useage' }, useage: { active: false, cssClass: '', group: 'primary', id: 'useage', icon: null, label: 'Useage' },
conditions: { active: false, cssClass: '', group: 'primary', id: 'conditions', icon: null, label: 'Conditions' }, conditions: {
} active: false,
cssClass: '',
group: 'primary',
id: 'conditions',
icon: null,
label: 'Conditions'
}
};
for ( const v of Object.values(tabs) ) { for (const v of Object.values(tabs)) {
v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active; v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active;
v.cssClass = v.active ? "active" : ""; v.cssClass = v.active ? 'active' : '';
} }
return tabs; return tabs;
@ -61,14 +68,14 @@ export default class DaggerheartActionConfig extends DaggerheartSheet(Applicatio
this.openSection = button.dataset.section === this.openSection ? null : button.dataset.section; this.openSection = button.dataset.section === this.openSection ? null : button.dataset.section;
this.render(true); this.render(true);
} }
static async updateForm(event, _, formData) { static async updateForm(event, _, formData) {
const data = foundry.utils.expandObject(foundry.utils.mergeObject(this.action.toObject(), formData.object)); const data = foundry.utils.expandObject(foundry.utils.mergeObject(this.action.toObject(), formData.object));
const newActions = this.action.parent.actions.map(x => x.toObject()); const newActions = this.action.parent.actions.map(x => x.toObject());
if(!newActions.findSplice(x => x.id === data.id, data)){ if (!newActions.findSplice(x => x.id === data.id, data)) {
newActions.push(data); newActions.push(data);
} }
await this.action.parent.parent.update({ "system.actions": newActions }); await this.action.parent.parent.update({ 'system.actions': newActions });
} }
} }

View file

@ -1,22 +1,22 @@
export default function DhpApplicationMixin(Base) { export default function DhpApplicationMixin(Base) {
return class DhpSheet extends Base { return class DhpSheet extends Base {
static applicationType = "sheets"; static applicationType = 'sheets';
static documentType = ""; static documentType = '';
static get defaultOptions() { static get defaultOptions() {
return Object.assign(super.defaultOptions, { return Object.assign(super.defaultOptions, {
classes: ["daggerheart", "sheet", this.documentType], classes: ['daggerheart', 'sheet', this.documentType],
template: `systems/${SYSTEM.id}/templates/${this.applicationType}/${this.documentType}.hbs`, template: `systems/${SYSTEM.id}/templates/${this.applicationType}/${this.documentType}.hbs`,
height: "auto", height: 'auto',
submitOnChange: true, submitOnChange: true,
submitOnClose: false, submitOnClose: false,
width: 450 width: 450
}); });
} }
/** @override */ /** @override */
get title() { get title() {
const {documentName, type, name} = this.object; const { documentName, type, name } = this.object;
// const typeLabel = game.i18n.localize(CONFIG[documentName].typeLabels[type]); // const typeLabel = game.i18n.localize(CONFIG[documentName].typeLabels[type]);
const typeLabel = documentName; const typeLabel = documentName;
return `[${typeLabel}] ${name}`; return `[${typeLabel}] ${name}`;
@ -32,17 +32,17 @@ export default function DhpApplicationMixin(Base) {
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
html.on("click", "[data-action]", this.#onClickAction.bind(this)); html.on('click', '[data-action]', this.#onClickAction.bind(this));
} }
async #onClickAction(event) { async #onClickAction(event) {
event.preventDefault(); event.preventDefault();
const button = event.currentTarget; const button = event.currentTarget;
const action = button.dataset.action; const action = button.dataset.action;
return this._handleAction(action, event, button); return this._handleAction(action, event, button);
} }
async _handleAction(action, event, button) {} async _handleAction(action, event, button) {}
} };
} }

View file

@ -1,53 +1,52 @@
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
export default class DamageSelectionDialog extends HandlebarsApplicationMixin(ApplicationV2) { export default class DamageSelectionDialog extends HandlebarsApplicationMixin(ApplicationV2) {
constructor(rollString, bonusDamage, hope, resolve) {
constructor(rollString, bonusDamage, hope, resolve){
super({}); super({});
this.data = { this.data = {
rollString, rollString,
bonusDamage: bonusDamage.reduce((acc, x) => { bonusDamage: bonusDamage.reduce((acc, x) => {
if(x.appliesOn === SYSTEM.EFFECTS.applyLocations.damageRoll.id){ if (x.appliesOn === SYSTEM.EFFECTS.applyLocations.damageRoll.id) {
acc.push(({ acc.push({
...x, ...x,
hopeUses: 0 hopeUses: 0
})); });
} }
return acc; return acc;
}, []), }, []),
hope, hope
} };
this.resolve = resolve; this.resolve = resolve;
} }
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
tag: 'form', tag: 'form',
classes: ["daggerheart", "views", "damage-selection"], classes: ['daggerheart', 'views', 'damage-selection'],
position: { position: {
width: 400, width: 400,
height: "auto" height: 'auto'
}, },
actions: { actions: {
decreaseHopeUse: this.decreaseHopeUse, decreaseHopeUse: this.decreaseHopeUse,
increaseHopeUse: this.increaseHopeUse, increaseHopeUse: this.increaseHopeUse,
rollDamage: this.rollDamage, rollDamage: this.rollDamage
}, },
form: { form: {
handler: this.updateSelection, handler: this.updateSelection,
submitOnChange: true, submitOnChange: true,
closeOnSubmit: false, closeOnSubmit: false
} }
}; };
/** @override */ /** @override */
static PARTS = { static PARTS = {
damageSelection: { damageSelection: {
id: "damageSelection", id: 'damageSelection',
template: "systems/daggerheart/templates/views/damageSelection.hbs" template: 'systems/daggerheart/templates/views/damageSelection.hbs'
} }
} };
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -60,19 +59,19 @@ export default class DamageSelectionDialog extends HandlebarsApplicationMixin(Ap
return { return {
rollString: this.getRollString(), rollString: this.getRollString(),
bonusDamage: this.data.bonusDamage, bonusDamage: this.data.bonusDamage,
hope: this.data.hope+1, hope: this.data.hope + 1,
hopeUsed: this.getHopeUsed(), hopeUsed: this.getHopeUsed()
} };
} }
static updateSelection(event, _, formData){ static updateSelection(event, _, formData) {
const { bonusDamage, ...rest } = foundry.utils.expandObject(formData.object); const { bonusDamage, ...rest } = foundry.utils.expandObject(formData.object);
for(var index in bonusDamage){ for (var index in bonusDamage) {
this.data.bonusDamage[index].initiallySelected = bonusDamage[index].initiallySelected; this.data.bonusDamage[index].initiallySelected = bonusDamage[index].initiallySelected;
if(bonusDamage[index].hopeUses){ if (bonusDamage[index].hopeUses) {
const value = Number.parseInt(bonusDamage[index].hopeUses); const value = Number.parseInt(bonusDamage[index].hopeUses);
if(!Number.isNaN(value)) this.data.bonusDamage[index].hopeUses = value; if (!Number.isNaN(value)) this.data.bonusDamage[index].hopeUses = value;
} }
} }
@ -80,40 +79,46 @@ export default class DamageSelectionDialog extends HandlebarsApplicationMixin(Ap
this.render(true); this.render(true);
} }
getRollString(){ getRollString() {
return this.data.rollString.concat(this.data.bonusDamage.reduce((acc, x) => { return this.data.rollString.concat(
if(x.initiallySelected){ this.data.bonusDamage.reduce((acc, x) => {
const nr = 1+x.hopeUses; if (x.initiallySelected) {
const baseDamage = x.value; const nr = 1 + x.hopeUses;
return acc.concat(` + ${nr}${baseDamage}`); const baseDamage = x.value;
} return acc.concat(` + ${nr}${baseDamage}`);
}
return acc; return acc;
}, "")); }, '')
);
} }
getHopeUsed(){ getHopeUsed() {
return this.data.bonusDamage.reduce((acc, x) => acc+x.hopeUses, 0); return this.data.bonusDamage.reduce((acc, x) => acc + x.hopeUses, 0);
} }
static decreaseHopeUse(_, button){ static decreaseHopeUse(_, button) {
const index = Number.parseInt(button.dataset.index); const index = Number.parseInt(button.dataset.index);
if(this.data.bonusDamage[index].hopeUses - 1 >= 0) { if (this.data.bonusDamage[index].hopeUses - 1 >= 0) {
this.data.bonusDamage[index].hopeUses -= 1; this.data.bonusDamage[index].hopeUses -= 1;
this.render(true); this.render(true);
} }
} }
static increaseHopeUse(_, button){ static increaseHopeUse(_, button) {
const index = Number.parseInt(button.dataset.index); const index = Number.parseInt(button.dataset.index);
if(this.data.bonusDamage[index].hopeUses <= this.data.hope+1) { if (this.data.bonusDamage[index].hopeUses <= this.data.hope + 1) {
this.data.bonusDamage[index].hopeUses += 1; this.data.bonusDamage[index].hopeUses += 1;
this.render(true); this.render(true);
} }
} }
static rollDamage(){ static rollDamage() {
this.resolve({ rollString: this.getRollString(), bonusDamage: this.data.bonusDamage, hopeUsed: this.getHopeUsed() }); this.resolve({
rollString: this.getRollString(),
bonusDamage: this.data.bonusDamage,
hopeUsed: this.getHopeUsed()
});
this.close(); this.close();
} }
} }
@ -121,7 +126,7 @@ export default class DamageSelectionDialog extends HandlebarsApplicationMixin(Ap
// export default class DamageSelectionDialog extends FormApplication { // export default class DamageSelectionDialog extends FormApplication {
// constructor(rollString, bonusDamage, resolve){ // constructor(rollString, bonusDamage, resolve){
// super({}, {}); // super({}, {});
// this.data = { // this.data = {
// rollString, // rollString,
// bonusDamage: bonusDamage.map(x => ({ // bonusDamage: bonusDamage.map(x => ({
@ -131,11 +136,11 @@ export default class DamageSelectionDialog extends HandlebarsApplicationMixin(Ap
// } // }
// this.resolve = resolve; // this.resolve = resolve;
// } // }
// get title (){ // get title (){
// return 'Damage Options'; // return 'Damage Options';
// } // }
// static get defaultOptions() { // static get defaultOptions() {
// const defaults = super.defaultOptions; // const defaults = super.defaultOptions;
// const overrides = { // const overrides = {
@ -146,35 +151,35 @@ export default class DamageSelectionDialog extends HandlebarsApplicationMixin(Ap
// closeOnSubmit: false, // closeOnSubmit: false,
// classes: ["daggerheart", "views", "damage-selection"], // classes: ["daggerheart", "views", "damage-selection"],
// }; // };
// const mergedOptions = foundry.utils.mergeObject(defaults, overrides); // const mergedOptions = foundry.utils.mergeObject(defaults, overrides);
// return mergedOptions; // return mergedOptions;
// } // }
// async getData(){ // async getData(){
// const context = super.getData(); // const context = super.getData();
// context.rollString = this.data.rollString; // context.rollString = this.data.rollString;
// context.bonusDamage = this.data.bonusDamage; // context.bonusDamage = this.data.bonusDamage;
// return context; // return context;
// } // }
// activateListeners(html) { // activateListeners(html) {
// super.activateListeners(html); // super.activateListeners(html);
// html.find('.roll-button').click(this.finish.bind(this)); // html.find('.roll-button').click(this.finish.bind(this));
// html.find('.').change(); // html.find('.').change();
// } // }
// // async _updateObject(_, formData) { // // async _updateObject(_, formData) {
// // const data = foundry.utils.expandObject(formData); // // const data = foundry.utils.expandObject(formData);
// // this.data = foundry.utils.mergeObject(this.data, data); // // this.data = foundry.utils.mergeObject(this.data, data);
// // this.render(true); // // this.render(true);
// // } // // }
// finish(){ // finish(){
// this.resolve(this.data); // this.resolve(this.data);
// this.close(); // this.close();
// } // }
// } // }

View file

@ -1,32 +1,32 @@
const {HandlebarsApplicationMixin, ApplicationV2} = foundry.applications.api; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
export default class DhpDeathMove extends HandlebarsApplicationMixin(ApplicationV2) { export default class DhpDeathMove extends HandlebarsApplicationMixin(ApplicationV2) {
constructor(actor){ constructor(actor) {
super({}); super({});
this.actor = actor; this.actor = actor;
this.selectedMove = null; this.selectedMove = null;
} }
get title(){ get title() {
return game.i18n.format("DAGGERHEART.Application.DeathMove.Title", { actor: this.actor.name }); return game.i18n.format('DAGGERHEART.Application.DeathMove.Title', { actor: this.actor.name });
} }
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
classes: ["daggerheart", "views", "death-move"], classes: ['daggerheart', 'views', 'death-move'],
position: { width: 800, height: 'auto' }, position: { width: 800, height: 'auto' },
actions: { actions: {
selectMove: this.selectMove, selectMove: this.selectMove,
takeMove: this.takeMove, takeMove: this.takeMove
}, }
}; };
static PARTS = { static PARTS = {
application: { application: {
id: "death-move", id: 'death-move',
template: "systems/daggerheart/templates/views/deathMove.hbs" template: 'systems/daggerheart/templates/views/deathMove.hbs'
} }
} };
async _prepareContext(_options) { async _prepareContext(_options) {
const context = await super._prepareContext(_options); const context = await super._prepareContext(_options);
@ -36,28 +36,27 @@ export default class DhpDeathMove extends HandlebarsApplicationMixin(Application
return context; return context;
} }
static selectMove(_, button) {
static selectMove(_, button){
const move = button.dataset.move; const move = button.dataset.move;
this.selectedMove = SYSTEM.GENERAL.deathMoves[move]; this.selectedMove = SYSTEM.GENERAL.deathMoves[move];
this.render(); this.render();
} }
static async takeMove(){ static async takeMove() {
const cls = getDocumentClass("ChatMessage"); const cls = getDocumentClass('ChatMessage');
const msg = new cls({ const msg = new cls({
user: game.user.id, user: game.user.id,
content: await renderTemplate("systems/daggerheart/templates/chat/deathMove.hbs", { content: await renderTemplate('systems/daggerheart/templates/chat/deathMove.hbs', {
player: game.user.character.name, player: game.user.character.name,
title: game.i18n.localize(this.selectedMove.name), title: game.i18n.localize(this.selectedMove.name),
img: this.selectedMove.img, img: this.selectedMove.img,
description: game.i18n.localize(this.selectedMove.description), description: game.i18n.localize(this.selectedMove.description)
}), })
}); });
cls.create(msg.toObject()); cls.create(msg.toObject());
this.close(); this.close();
} }
} }

View file

@ -1,7 +1,7 @@
const {HandlebarsApplicationMixin, ApplicationV2} = foundry.applications.api; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV2) { export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV2) {
constructor(actor, shortrest){ constructor(actor, shortrest) {
super({}); super({});
this.actor = actor; this.actor = actor;
@ -11,27 +11,27 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
this.customActivity = SYSTEM.GENERAL.downtime.custom; this.customActivity = SYSTEM.GENERAL.downtime.custom;
} }
get title(){ get title() {
return `${this.actor.name} - ${this.shortrest ? 'Short Rest': 'Long Rest'}`; return `${this.actor.name} - ${this.shortrest ? 'Short Rest' : 'Long Rest'}`;
} }
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
tag: 'form', tag: 'form',
classes: ["daggerheart", "views", "downtime"], classes: ['daggerheart', 'views', 'downtime'],
position: { width: 800, height: 'auto' }, position: { width: 800, height: 'auto' },
actions: { actions: {
selectActivity: this.selectActivity, selectActivity: this.selectActivity,
takeDowntime: this.takeDowntime, takeDowntime: this.takeDowntime
}, },
form: { handler: this.updateData, submitOnChange: true } form: { handler: this.updateData, submitOnChange: true }
}; };
static PARTS = { static PARTS = {
application: { application: {
id: "downtime", id: 'downtime',
template: "systems/daggerheart/templates/views/downtime.hbs" template: 'systems/daggerheart/templates/views/downtime.hbs'
} }
} };
async _prepareContext(_options) { async _prepareContext(_options) {
const context = await super._prepareContext(_options); const context = await super._prepareContext(_options);
@ -39,44 +39,53 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
context.options = this.shortrest ? SYSTEM.GENERAL.downtime.shortRest : SYSTEM.GENERAL.downtime.longRest; context.options = this.shortrest ? SYSTEM.GENERAL.downtime.shortRest : SYSTEM.GENERAL.downtime.longRest;
context.customActivity = this.customActivity; context.customActivity = this.customActivity;
context.disabledDowntime = !this.selectedActivity || (this.selectedActivity.id === this.customActivity.id && (!this.customActivity.name || !this.customActivity.description)); context.disabledDowntime =
!this.selectedActivity ||
(this.selectedActivity.id === this.customActivity.id &&
(!this.customActivity.name || !this.customActivity.description));
return context; return context;
} }
static selectActivity(_, button) {
static selectActivity(_, button){
const activity = button.dataset.activity; const activity = button.dataset.activity;
this.selectedActivity = activity === this.customActivity.id ? this.customActivity : this.shortrest ? SYSTEM.GENERAL.downtime.shortRest[activity] : SYSTEM.GENERAL.downtime.longRest[activity]; this.selectedActivity =
activity === this.customActivity.id
? this.customActivity
: this.shortrest
? SYSTEM.GENERAL.downtime.shortRest[activity]
: SYSTEM.GENERAL.downtime.longRest[activity];
this.render(); this.render();
} }
static async takeDowntime(){ static async takeDowntime() {
const refreshedFeatures = this.shortrest ? this.actor.system.refreshableFeatures.shortRest : [...this.actor.system.refreshableFeatures.shortRest, ...this.actor.system.refreshableFeatures.longRest]; const refreshedFeatures = this.shortrest
for(var feature of refreshedFeatures){ ? this.actor.system.refreshableFeatures.shortRest
: [...this.actor.system.refreshableFeatures.shortRest, ...this.actor.system.refreshableFeatures.longRest];
for (var feature of refreshedFeatures) {
await feature.system.refresh(); await feature.system.refresh();
} }
const cls = getDocumentClass("ChatMessage"); const cls = getDocumentClass('ChatMessage');
const msg = new cls({ const msg = new cls({
user: game.user.id, user: game.user.id,
content: await renderTemplate("systems/daggerheart/templates/chat/downtime.hbs", { content: await renderTemplate('systems/daggerheart/templates/chat/downtime.hbs', {
player: game.user.character.name, player: game.user.character.name,
title: game.i18n.localize(this.selectedActivity.name), title: game.i18n.localize(this.selectedActivity.name),
img: this.selectedActivity.img, img: this.selectedActivity.img,
description: game.i18n.localize(this.selectedActivity.description), description: game.i18n.localize(this.selectedActivity.description),
refreshedFeatures: refreshedFeatures, refreshedFeatures: refreshedFeatures
}), })
}); });
cls.create(msg.toObject()); cls.create(msg.toObject());
this.close(); this.close();
} }
static async updateData(event, element, formData){ static async updateData(event, element, formData) {
this.customActivity = foundry.utils.mergeObject(this.customActivity, formData.object); this.customActivity = foundry.utils.mergeObject(this.customActivity, formData.object);
this.render(); this.render();
} }
} }

View file

@ -1,77 +1,82 @@
import SelectDialog from "../dialogs/selectDialog.mjs"; import SelectDialog from '../dialogs/selectDialog.mjs';
import { getTier } from "../helpers/utils.mjs"; import { getTier } from '../helpers/utils.mjs';
import DhpMulticlassDialog from "./multiclassDialog.mjs"; import DhpMulticlassDialog from './multiclassDialog.mjs';
const {HandlebarsApplicationMixin, ApplicationV2} = foundry.applications.api; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
export default class DhpLevelup extends HandlebarsApplicationMixin(ApplicationV2) { export default class DhpLevelup extends HandlebarsApplicationMixin(ApplicationV2) {
constructor(actor){ constructor(actor) {
super({}); super({});
this.actor = actor; this.actor = actor;
this.data = foundry.utils.deepClone(actor.system.levelData); this.data = foundry.utils.deepClone(actor.system.levelData);
this.activeLevel = actor.system.levelData.currentLevel+1; this.activeLevel = actor.system.levelData.currentLevel + 1;
} }
get title(){ get title() {
return `${this.actor.name} - Level Up`; return `${this.actor.name} - Level Up`;
} }
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
id: "daggerheart-levelup", id: 'daggerheart-levelup',
classes: ["daggerheart", "views", "levelup"], classes: ['daggerheart', 'views', 'levelup'],
position: { width: 1200, height: 'auto' }, position: { width: 1200, height: 'auto' },
window: { window: {
resizable: true, resizable: true
}, },
actions: { actions: {
toggleBox: this.toggleBox, toggleBox: this.toggleBox,
advanceLevel: this.advanceLevel, advanceLevel: this.advanceLevel,
finishLevelup: this.finishLevelup, finishLevelup: this.finishLevelup
}, }
}; };
static PARTS = { static PARTS = {
form: { form: {
id: "levelup", id: 'levelup',
template: "systems/daggerheart/templates/views/levelup.hbs" template: 'systems/daggerheart/templates/views/levelup.hbs'
} }
} };
async _prepareContext(_options) { async _prepareContext(_options) {
let selectedChoices = 0, multiclassing = {}, subclassing = {}; let selectedChoices = 0,
const leveledTiers = Object.keys(this.data.levelups).reduce((acc, levelKey) => { multiclassing = {},
const levelData = this.data.levelups[levelKey]; subclassing = {};
['tier1','tier2','tier3'].forEach(tierKey => { const leveledTiers = Object.keys(this.data.levelups).reduce(
let tierUpdate = {}; (acc, levelKey) => {
const tierData = levelData[tierKey]; const levelData = this.data.levelups[levelKey];
if(tierData){ ['tier1', 'tier2', 'tier3'].forEach(tierKey => {
tierUpdate = Object.keys(tierData).reduce((acc, propertyKey) => { let tierUpdate = {};
const values = tierData[propertyKey]; const tierData = levelData[tierKey];
const level = Number.parseInt(levelKey); if (tierData) {
tierUpdate = Object.keys(tierData).reduce((acc, propertyKey) => {
const values = tierData[propertyKey];
const level = Number.parseInt(levelKey);
acc[propertyKey] = Object.values(values).map(value => { acc[propertyKey] = Object.values(values).map(value => {
if(value && level === this.activeLevel) selectedChoices++; if (value && level === this.activeLevel) selectedChoices++;
if(propertyKey === 'multiclass') multiclassing[levelKey] = true; if (propertyKey === 'multiclass') multiclassing[levelKey] = true;
if(propertyKey === 'subclass') subclassing[tierKey] = true; if (propertyKey === 'subclass') subclassing[tierKey] = true;
return { level: level, value: value };
});
return acc; return { level: level, value: value };
}, {}); });
}
return acc;
Object.keys(tierUpdate).forEach(propertyKey => { }, {});
const property = tierUpdate[propertyKey]; }
const propertyValues = foundry.utils.getProperty(acc, `${tierKey}.${propertyKey}`)??[];
foundry.utils.setProperty(acc, `${tierKey}.${propertyKey}`, [...propertyValues, ...property]); Object.keys(tierUpdate).forEach(propertyKey => {
const property = tierUpdate[propertyKey];
const propertyValues = foundry.utils.getProperty(acc, `${tierKey}.${propertyKey}`) ?? [];
foundry.utils.setProperty(acc, `${tierKey}.${propertyKey}`, [...propertyValues, ...property]);
});
}); });
});
return acc; return acc;
}, { tier1: {}, tier2: {}, tier3: {} }); },
{ tier1: {}, tier2: {}, tier3: {} }
);
const activeTier = getTier(this.activeLevel); const activeTier = getTier(this.activeLevel);
const data = Object.keys(SYSTEM.ACTOR.levelupData).reduce((acc, tierKey) => { const data = Object.keys(SYSTEM.ACTOR.levelupData).reduce((acc, tierKey) => {
@ -85,21 +90,35 @@ export default class DhpLevelup extends HandlebarsApplicationMixin(ApplicationV2
choices: Object.keys(tier.choices).reduce((acc, propertyKey) => { choices: Object.keys(tier.choices).reduce((acc, propertyKey) => {
const property = tier.choices[propertyKey]; const property = tier.choices[propertyKey];
acc[propertyKey] = { description: property.description, cost: property.cost ?? 1, values: [] }; acc[propertyKey] = { description: property.description, cost: property.cost ?? 1, values: [] };
for(var i = 0; i < property.maxChoices; i++){ for (var i = 0; i < property.maxChoices; i++) {
const leveledValue = leveledTiers[tierKey][propertyKey]?.[i]; const leveledValue = leveledTiers[tierKey][propertyKey]?.[i];
const subclassLock = propertyKey === 'subclass' && Object.keys(multiclassing).find(x => getTier(Number.parseInt(x)) === tierKey); const subclassLock =
propertyKey === 'subclass' &&
Object.keys(multiclassing).find(x => getTier(Number.parseInt(x)) === tierKey);
const subclassMulticlassLock = propertyKey === 'multiclass' && subclassing[tierKey]; const subclassMulticlassLock = propertyKey === 'multiclass' && subclassing[tierKey];
const multiclassLock = propertyKey === 'multiclass' && Object.keys(multiclassing).length > 0 && !(leveledValue && Object.keys(multiclassing).find(x => Number.parseInt(x) === leveledValue.level)); const multiclassLock =
const locked = leveledValue && leveledValue.level !== this.activeLevel || subclassLock || subclassMulticlassLock || multiclassLock; propertyKey === 'multiclass' &&
const disabled = tierKey > activeTier || (selectedChoices === 2 && !(leveledValue && leveledValue.level === this.activeLevel)) || locked; Object.keys(multiclassing).length > 0 &&
!(
leveledValue &&
Object.keys(multiclassing).find(x => Number.parseInt(x) === leveledValue.level)
);
const locked =
(leveledValue && leveledValue.level !== this.activeLevel) ||
subclassLock ||
subclassMulticlassLock ||
multiclassLock;
const disabled =
tierKey > activeTier ||
(selectedChoices === 2 && !(leveledValue && leveledValue.level === this.activeLevel)) ||
locked;
acc[propertyKey].values.push({ acc[propertyKey].values.push({
selected: leveledValue?.value !== undefined, selected: leveledValue?.value !== undefined,
path: `levelups.${this.activeLevel}.${tierKey}.${propertyKey}.${i}`, path: `levelups.${this.activeLevel}.${tierKey}.${propertyKey}.${i}`,
description: game.i18n.localize(property.description), description: game.i18n.localize(property.description),
disabled: disabled, disabled: disabled,
locked: locked, locked: locked
}); });
} }
@ -114,70 +133,122 @@ export default class DhpLevelup extends HandlebarsApplicationMixin(ApplicationV2
data: data, data: data,
activeLevel: this.activeLevel, activeLevel: this.activeLevel,
changedLevel: this.actor.system.levelData.changedLevel, changedLevel: this.actor.system.levelData.changedLevel,
completedSelection: selectedChoices === 2, completedSelection: selectedChoices === 2
} };
} }
static async toggleBox(_, button){ static async toggleBox(_, button) {
const path = button.dataset.path; const path = button.dataset.path;
if(foundry.utils.getProperty(this.data, path)){ if (foundry.utils.getProperty(this.data, path)) {
const pathParts = path.split('.'); const pathParts = path.split('.');
const arrayPart = pathParts.slice(0, pathParts.length-1).join('.'); const arrayPart = pathParts.slice(0, pathParts.length - 1).join('.');
let array = foundry.utils.getProperty(this.data, arrayPart); let array = foundry.utils.getProperty(this.data, arrayPart);
if(button.dataset.levelAttribute === 'multiclass'){ if (button.dataset.levelAttribute === 'multiclass') {
array = []; array = [];
} } else {
else { delete array[Number.parseInt(pathParts[pathParts.length - 1])];
delete array[Number.parseInt(pathParts[pathParts.length-1])];
} }
foundry.utils.setProperty(this.data, arrayPart, array); foundry.utils.setProperty(this.data, arrayPart, array);
} else { } else {
const updates = [{ path: path, value: { level: this.activeLevel } }]; const updates = [{ path: path, value: { level: this.activeLevel } }];
const levelChoices = SYSTEM.ACTOR.levelChoices[button.dataset.levelAttribute]; const levelChoices = SYSTEM.ACTOR.levelChoices[button.dataset.levelAttribute];
if(button.dataset.levelAttribute === 'subclass'){ if (button.dataset.levelAttribute === 'subclass') {
if(!this.actor.system.multiclassSubclass){ if (!this.actor.system.multiclassSubclass) {
updates[0].value.value = { multiclass: false, feature: this.actor.system.subclass.system.specializationFeature.unlocked ? 'mastery' : 'specialization' }; updates[0].value.value = {
} multiclass: false,
else { feature: this.actor.system.subclass.system.specializationFeature.unlocked
const choices = [{name: this.actor.system.subclass.name, value: this.actor.system.subclass.uuid}, {name: this.actor.system.multiclassSubclass.name, value: this.actor.system.multiclassSubclass.uuid}]; ? 'mastery'
const indexes = await SelectDialog.selectItem({ actor: this.actor, choices: choices, title: levelChoices.title, nrChoices: 1 }); : 'specialization'
if(indexes.length === 0) { };
} else {
const choices = [
{ name: this.actor.system.subclass.name, value: this.actor.system.subclass.uuid },
{
name: this.actor.system.multiclassSubclass.name,
value: this.actor.system.multiclassSubclass.uuid
}
];
const indexes = await SelectDialog.selectItem({
actor: this.actor,
choices: choices,
title: levelChoices.title,
nrChoices: 1
});
if (indexes.length === 0) {
this.render(); this.render();
return; return;
} }
const multiclassSubclass = choices[indexes[0]].name === this.actor.system.multiclassSubclass.name; const multiclassSubclass = choices[indexes[0]].name === this.actor.system.multiclassSubclass.name;
updates[0].value.value = { multiclass: multiclassSubclass, feature: this.actor.system.multiclassSubclass.system.specializationFeature.unlocked ? 'mastery' : 'specialization' }; updates[0].value.value = {
multiclass: multiclassSubclass,
feature: this.actor.system.multiclassSubclass.system.specializationFeature.unlocked
? 'mastery'
: 'specialization'
};
} }
} } else if (button.dataset.levelAttribute === 'multiclass') {
else if (button.dataset.levelAttribute === 'multiclass'){ const multiclassAwait = new Promise(resolve => {
const multiclassAwait = new Promise((resolve) => {
new DhpMulticlassDialog(this.actor.name, this.actor.system.class, resolve).render(true); new DhpMulticlassDialog(this.actor.name, this.actor.system.class, resolve).render(true);
}); });
const multiclassData = await multiclassAwait; const multiclassData = await multiclassAwait;
if(!multiclassData) { if (!multiclassData) {
this.render(); this.render();
return; return;
} }
const pathParts = path.split('.'); const pathParts = path.split('.');
const arrayPart = pathParts.slice(0, pathParts.length-1).join('.'); const arrayPart = pathParts.slice(0, pathParts.length - 1).join('.');
updates[0] = { path: [arrayPart, '0'].join('.'), value: { level: this.activeLevel, value: { class: multiclassData.class, subclass: multiclassData.subclass, domain: multiclassData.domain, level: this.activeLevel } } }; updates[0] = {
updates[1] = { path: [arrayPart, '1'].join('.'), value: { level: this.activeLevel, value: { class: multiclassData.class, subclass: multiclassData.subclass, domain: multiclassData.domain, level: this.activeLevel } } }; path: [arrayPart, '0'].join('.'),
} value: {
else { level: this.activeLevel,
if(levelChoices.choices.length > 0){ value: {
if(typeof levelChoices.choices === 'string'){ class: multiclassData.class,
const choices = foundry.utils.getProperty(this.actor, levelChoices.choices).map(x => ({ name: x.description, value: x.id })); subclass: multiclassData.subclass,
const indexes = await SelectDialog.selectItem({ actor: this.actor, choices: choices, title: levelChoices.title, nrChoices: levelChoices.nrChoices }); domain: multiclassData.domain,
if(indexes.length === 0) { level: this.activeLevel
}
}
};
updates[1] = {
path: [arrayPart, '1'].join('.'),
value: {
level: this.activeLevel,
value: {
class: multiclassData.class,
subclass: multiclassData.subclass,
domain: multiclassData.domain,
level: this.activeLevel
}
}
};
} else {
if (levelChoices.choices.length > 0) {
if (typeof levelChoices.choices === 'string') {
const choices = foundry.utils
.getProperty(this.actor, levelChoices.choices)
.map(x => ({ name: x.description, value: x.id }));
const indexes = await SelectDialog.selectItem({
actor: this.actor,
choices: choices,
title: levelChoices.title,
nrChoices: levelChoices.nrChoices
});
if (indexes.length === 0) {
this.render(); this.render();
return; return;
} }
updates[0].value.value = choices.filter((_, index) => indexes.includes(index)).map(x => x.value); updates[0].value.value = choices
} .filter((_, index) => indexes.includes(index))
else { .map(x => x.value);
const indexes = await SelectDialog.selectItem({ actor: this.actor, choices: levelChoices.choices, title: levelChoices.title, nrChoices: levelChoices.nrChoices }); } else {
if(indexes.length === 0) { const indexes = await SelectDialog.selectItem({
actor: this.actor,
choices: levelChoices.choices,
title: levelChoices.title,
nrChoices: levelChoices.nrChoices
});
if (indexes.length === 0) {
this.render(); this.render();
return; return;
} }
@ -198,44 +269,57 @@ export default class DhpLevelup extends HandlebarsApplicationMixin(ApplicationV2
this.render(); this.render();
} }
static advanceLevel(){ static advanceLevel() {
this.activeLevel += 1; this.activeLevel += 1;
this.render(); this.render();
} }
static async finishLevelup(){ static async finishLevelup() {
this.data.currentLevel = this.data.changedLevel; this.data.currentLevel = this.data.changedLevel;
let multiclass = null; let multiclass = null;
for(var level in this.data.levelups){ for (var level in this.data.levelups) {
for(var tier in this.data.levelups[level]){ for (var tier in this.data.levelups[level]) {
for(var category in this.data.levelups[level][tier]) { for (var category in this.data.levelups[level][tier]) {
for (var value in this.data.levelups[level][tier][category]){ for (var value in this.data.levelups[level][tier][category]) {
if(category === 'multiclass'){ if (category === 'multiclass') {
multiclass = this.data.levelups[level][tier][category][value].value; multiclass = this.data.levelups[level][tier][category][value].value;
this.data.levelups[level][tier][category][value] = true; this.data.levelups[level][tier][category][value] = true;
} else { } else {
this.data.levelups[level][tier][category][value] = this.data.levelups[level][tier][category][value].value ?? true; this.data.levelups[level][tier][category][value] =
this.data.levelups[level][tier][category][value].value ?? true;
} }
} }
} }
} }
} }
const tiersMoved = getTier(this.actor.system.levelData.changedLevel, true) - getTier(this.actor.system.levelData.currentLevel, true); const tiersMoved =
const experiences = Array.from(Array(tiersMoved), (_,index) => ({ id: foundry.utils.randomID(), level: this.actor.system.experiences.length+index*3, description: '', value: 1 })); getTier(this.actor.system.levelData.changedLevel, true) -
getTier(this.actor.system.levelData.currentLevel, true);
const experiences = Array.from(Array(tiersMoved), (_, index) => ({
id: foundry.utils.randomID(),
level: this.actor.system.experiences.length + index * 3,
description: '',
value: 1
}));
await this.actor.update({ system: { await this.actor.update(
levelData: this.data, {
experiences: [...this.actor.system.experiences, ...experiences], system: {
}}, { diff: false }); levelData: this.data,
experiences: [...this.actor.system.experiences, ...experiences]
}
},
{ diff: false }
);
if(!this.actor.multiclass && multiclass){ if (!this.actor.multiclass && multiclass) {
const multiclassClass = (await fromUuid(multiclass.class.uuid)).toObject(); const multiclassClass = (await fromUuid(multiclass.class.uuid)).toObject();
multiclassClass.system.domains = [multiclass.domain.id]; multiclassClass.system.domains = [multiclass.domain.id];
multiclassClass.system.multiclass = multiclass.level; multiclassClass.system.multiclass = multiclass.level;
const multiclassFeatures = []; const multiclassFeatures = [];
for(var i = 0; i < multiclassClass.system.features.length; i++){ for (var i = 0; i < multiclassClass.system.features.length; i++) {
const feature = (await fromUuid(multiclassClass.system.features[i].uuid)).toObject(); const feature = (await fromUuid(multiclassClass.system.features[i].uuid)).toObject();
feature.system.multiclass = multiclass.level; feature.system.multiclass = multiclass.level;
multiclassFeatures.push(feature); multiclassFeatures.push(feature);
@ -243,17 +327,21 @@ export default class DhpLevelup extends HandlebarsApplicationMixin(ApplicationV2
const multiclassSubclass = (await fromUuid(multiclass.subclass.uuid)).toObject(); const multiclassSubclass = (await fromUuid(multiclass.subclass.uuid)).toObject();
multiclassSubclass.system.multiclass = multiclass.level; multiclassSubclass.system.multiclass = multiclass.level;
const multiclassSubclassFeatures = {}; const multiclassSubclassFeatures = {};
const features = [multiclassSubclass.system.foundationFeature, multiclassSubclass.system.specializationFeature, multiclassSubclass.system.masteryFeature]; const features = [
for(var i = 0; i < features.length; i++){ multiclassSubclass.system.foundationFeature,
multiclassSubclass.system.specializationFeature,
multiclassSubclass.system.masteryFeature
];
for (var i = 0; i < features.length; i++) {
const path = i === 0 ? 'foundationFeature' : i === 1 ? 'specializationFeature' : 'masteryFeature'; const path = i === 0 ? 'foundationFeature' : i === 1 ? 'specializationFeature' : 'masteryFeature';
const feature = features[i]; const feature = features[i];
for(var ability of feature.abilities){ for (var ability of feature.abilities) {
const data = (await fromUuid(ability.uuid)).toObject(); const data = (await fromUuid(ability.uuid)).toObject();
if(i > 0 ) data.system.disabled = true; if (i > 0) data.system.disabled = true;
data.system.multiclass = multiclass.level; data.system.multiclass = multiclass.level;
if(!multiclassSubclassFeatures[path]) multiclassSubclassFeatures[path] = [data]; if (!multiclassSubclassFeatures[path]) multiclassSubclassFeatures[path] = [data];
else multiclassSubclassFeatures[path].push(data); else multiclassSubclassFeatures[path].push(data);
// data.uuid = feature.uuid; // data.uuid = feature.uuid;
@ -264,18 +352,21 @@ export default class DhpLevelup extends HandlebarsApplicationMixin(ApplicationV2
} }
} }
for(let subclassFeaturesKey in multiclassSubclassFeatures){ for (let subclassFeaturesKey in multiclassSubclassFeatures) {
const values = multiclassSubclassFeatures[subclassFeaturesKey]; const values = multiclassSubclassFeatures[subclassFeaturesKey];
const abilityResults = await this.actor.createEmbeddedDocuments('Item', values); const abilityResults = await this.actor.createEmbeddedDocuments('Item', values);
for(var i = 0; i < abilityResults.length; i++){ for (var i = 0; i < abilityResults.length; i++) {
multiclassSubclass.system[subclassFeaturesKey].abilities[i].uuid = abilityResults[i].uuid; multiclassSubclass.system[subclassFeaturesKey].abilities[i].uuid = abilityResults[i].uuid;
} }
} }
await this.actor.createEmbeddedDocuments('Item', [multiclassClass, ...multiclassFeatures, multiclassSubclass]); await this.actor.createEmbeddedDocuments('Item', [
} multiclassClass,
...multiclassFeatures,
multiclassSubclass
]);
}
this.close(); this.close();
} }
} }

View file

@ -1,58 +1,60 @@
const {HandlebarsApplicationMixin, ApplicationV2} = foundry.applications.api; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
export default class DhpMulticlassDialog extends HandlebarsApplicationMixin(ApplicationV2) { export default class DhpMulticlassDialog extends HandlebarsApplicationMixin(ApplicationV2) {
constructor(actorName, actorClass, resolve){ constructor(actorName, actorClass, resolve) {
super({}); super({});
this.actorName = actorName; this.actorName = actorName;
this.actorClass = actorClass; this.actorClass = actorClass;
this.resolve = resolve; this.resolve = resolve;
this.classChoices = Array.from(game.items.reduce((acc, x) => { this.classChoices = Array.from(
if(x.type === 'class' && x.name !== actorClass.name){ game.items.reduce((acc, x) => {
acc.add(x); if (x.type === 'class' && x.name !== actorClass.name) {
} acc.add(x);
}
return acc;
}, new Set())); return acc;
}, new Set())
);
this.subclassChoices = []; this.subclassChoices = [];
this.domainChoices = []; this.domainChoices = [];
this.data = { this.data = {
class: null, class: null,
subclass: null, subclass: null,
domain: null, domain: null
}; };
} }
get title(){ get title() {
return `${this.actorName} - Multiclass`; return `${this.actorName} - Multiclass`;
} }
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
classes: ["daggerheart", "views", "multiclass"], classes: ['daggerheart', 'views', 'multiclass'],
position: { width: 600, height: 'auto' }, position: { width: 600, height: 'auto' },
actions: { actions: {
selectClass: this.selectClass, selectClass: this.selectClass,
selectSubclass: this.selectSubclass, selectSubclass: this.selectSubclass,
selectDomain: this.selectDomain, selectDomain: this.selectDomain,
finish: this.finish, finish: this.finish
}, }
}; };
static PARTS = { static PARTS = {
form: { form: {
id: "levelup", id: 'levelup',
template: "systems/daggerheart/templates/views/multiclass.hbs" template: 'systems/daggerheart/templates/views/multiclass.hbs'
} }
} };
async _prepareContext(_options) { async _prepareContext(_options) {
const context = await super._prepareContext(_options); const context = await super._prepareContext(_options);
context.classChoices = this.classChoices; context.classChoices = this.classChoices;
context.subclassChoices = this.subclassChoices; context.subclassChoices = this.subclassChoices;
context.domainChoices = this.domainChoices; context.domainChoices = this.domainChoices;
context.disabledFinish = !this.data.class || !this.data.subclass || !this.data.domain; context.disabledFinish = !this.data.class || !this.data.subclass || !this.data.domain;
context.data = this.data; context.data = this.data;
return context; return context;
@ -61,38 +63,51 @@ export default class DhpMulticlassDialog extends HandlebarsApplicationMixin(Appl
static async selectClass(_, button) { static async selectClass(_, button) {
const oldClass = this.data.class; const oldClass = this.data.class;
this.data.class = this.data.class?.uuid === button.dataset.class ? null : await fromUuid(button.dataset.class); this.data.class = this.data.class?.uuid === button.dataset.class ? null : await fromUuid(button.dataset.class);
if(oldClass !== button.dataset.class){ if (oldClass !== button.dataset.class) {
this.data.subclass = null; this.data.subclass = null;
this.data.domain = null; this.data.domain = null;
this.subclassChoices = this.data.class ? this.data.class.system.subclasses : []; this.subclassChoices = this.data.class ? this.data.class.system.subclasses : [];
this.domainChoices = this.data.class ? this.data.class.system.domains.map(x => { this.domainChoices = this.data.class
const config = SYSTEM.DOMAIN.domains[x]; ? this.data.class.system.domains.map(x => {
return { name: game.i18n.localize(config.name), id: config.id, img: config.src, disabled: this.actorClass.system.domains.includes(config.id) }; const config = SYSTEM.DOMAIN.domains[x];
}) : []; return {
name: game.i18n.localize(config.name),
id: config.id,
img: config.src,
disabled: this.actorClass.system.domains.includes(config.id)
};
})
: [];
} }
this.render(true); this.render(true);
} }
static async selectSubclass(_, button) { static async selectSubclass(_, button) {
this.data.subclass = this.data.subclass?.uuid === button.dataset.subclass ? null : this.subclassChoices.find(x => x.uuid === button.dataset.subclass); this.data.subclass =
this.data.subclass?.uuid === button.dataset.subclass
? null
: this.subclassChoices.find(x => x.uuid === button.dataset.subclass);
this.render(true); this.render(true);
} }
static async selectDomain(_, button) { static async selectDomain(_, button) {
const domain = this.data.domain?.id === button.dataset.domain ? null : this.domainChoices.find(x => x.id === button.dataset.domain);; const domain =
if(domain?.disabled) return; this.data.domain?.id === button.dataset.domain
? null
: this.domainChoices.find(x => x.id === button.dataset.domain);
if (domain?.disabled) return;
this.data.domain = domain; this.data.domain = domain;
this.render(true); this.render(true);
} }
static finish(){ static finish() {
this.close({}, this.data); this.close({}, this.data);
} }
async close(options={}, data=null) { async close(options = {}, data = null) {
this.resolve(data); this.resolve(data);
super.close(options); super.close(options);
} }
} }

View file

@ -1,76 +1,81 @@
export default class NpcRollSelectionDialog extends FormApplication { export default class NpcRollSelectionDialog extends FormApplication {
constructor(experiences, resolve, isNpc){ constructor(experiences, resolve, isNpc) {
super({}, {}); super({}, {});
this.experiences = experiences; this.experiences = experiences;
this.resolve = resolve; this.resolve = resolve;
this.selectedExperiences = []; this.selectedExperiences = [];
this.data = { this.data = {
nrDice: 1, nrDice: 1,
advantage: null, advantage: null
}; };
} }
get title (){ get title() {
return 'Roll Options'; return 'Roll Options';
} }
static get defaultOptions() { static get defaultOptions() {
const defaults = super.defaultOptions; const defaults = super.defaultOptions;
const overrides = { const overrides = {
height: 'auto', height: 'auto',
width: 400, width: 400,
id: 'roll-selection', id: 'roll-selection',
template: 'systems/daggerheart/templates/views/npcRollSelection.hbs', template: 'systems/daggerheart/templates/views/npcRollSelection.hbs',
closeOnSubmit: false, closeOnSubmit: false,
submitOnChange: true, submitOnChange: true,
classes: ["daggerheart", "views", "npc-roll-selection"], classes: ['daggerheart', 'views', 'npc-roll-selection']
}; };
const mergedOptions = foundry.utils.mergeObject(defaults, overrides);
return mergedOptions;
}
async getData(){
const context = super.getData();
context.nrDice = this.data.nrDice;
context.advantage = this.data.advantage;
context.experiences = this.experiences.map(x => ({ ...x, selected: this.selectedExperiences.find(selected => selected.id === x.id) }));
return context; const mergedOptions = foundry.utils.mergeObject(defaults, overrides);
}
activateListeners(html) { return mergedOptions;
super.activateListeners(html); }
html.find('.increase').click(_ => this.updateNrDice(1)); async getData() {
html.find('.decrease').click(_ => this.updateNrDice(-1)); const context = super.getData();
html.find('.advantage').click(_ => this.updateIsAdvantage(true)); context.nrDice = this.data.nrDice;
html.find('.disadvantage').click(_ => this.updateIsAdvantage(false)); context.advantage = this.data.advantage;
html.find('.roll-button').click(this.finish.bind(this)); context.experiences = this.experiences.map(x => ({
html.find('.roll-dialog-chip').click(this.selectExperience.bind(this)); ...x,
} selected: this.selectedExperiences.find(selected => selected.id === x.id)
}));
updateNrDice(value){ return context;
this.data.nrDice += value; }
this.render();
}
updateIsAdvantage(advantage) { activateListeners(html) {
this.data.advantage = this.data.advantage === advantage ? null : advantage; super.activateListeners(html);
this.render();
}
selectExperience(event){ html.find('.increase').click(_ => this.updateNrDice(1));
const experience = this.experiences[event.currentTarget.dataset.key]; html.find('.decrease').click(_ => this.updateNrDice(-1));
this.selectedExperiences = this.selectedExperiences.find(x => x.name === experience.name) ? this.selectedExperiences.filter(x => x.name !== experience.name) : [...this.selectedExperiences, experience]; html.find('.advantage').click(_ => this.updateIsAdvantage(true));
html.find('.disadvantage').click(_ => this.updateIsAdvantage(false));
html.find('.roll-button').click(this.finish.bind(this));
html.find('.roll-dialog-chip').click(this.selectExperience.bind(this));
}
this.render(); updateNrDice(value) {
} this.data.nrDice += value;
this.render();
}
finish(){ updateIsAdvantage(advantage) {
this.resolve({ ...this.data, experiences: this.selectedExperiences }); this.data.advantage = this.data.advantage === advantage ? null : advantage;
this.close(); this.render();
} }
}
selectExperience(event) {
const experience = this.experiences[event.currentTarget.dataset.key];
this.selectedExperiences = this.selectedExperiences.find(x => x.name === experience.name)
? this.selectedExperiences.filter(x => x.name !== experience.name)
: [...this.selectedExperiences, experience];
this.render();
}
finish() {
this.resolve({ ...this.data, experiences: this.selectedExperiences });
this.close();
}
}

View file

@ -1,147 +1,161 @@
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
export default class RollSelectionDialog extends HandlebarsApplicationMixin(ApplicationV2) { export default class RollSelectionDialog extends HandlebarsApplicationMixin(ApplicationV2) {
constructor(experiences, bonusDamage, hopeResource, resolve, isNpc){ constructor(experiences, bonusDamage, hopeResource, resolve, isNpc) {
super({}, {}); super({}, {});
this.experiences = experiences; this.experiences = experiences;
this.resolve = resolve; this.resolve = resolve;
this.isNpc; this.isNpc;
this.selectedExperiences = []; this.selectedExperiences = [];
this.data = { this.data = {
diceOptions: [{ name: 'd12', value: 'd12' }, { name: 'd20', value: 'd20' }], diceOptions: [
hope: ['d12'], { name: 'd12', value: 'd12' },
fear: ['d12'], { name: 'd20', value: 'd20' }
advantage: null, ],
disadvantage: null, hope: ['d12'],
bonusDamage: bonusDamage.reduce((acc, x) => { fear: ['d12'],
if(x.appliesOn === SYSTEM.EFFECTS.applyLocations.attackRoll.id){ advantage: null,
acc.push(({ disadvantage: null,
...x, bonusDamage: bonusDamage.reduce((acc, x) => {
hopeUses: 0 if (x.appliesOn === SYSTEM.EFFECTS.applyLocations.attackRoll.id) {
})); acc.push({
...x,
hopeUses: 0
});
}
return acc;
}, []),
hopeResource: hopeResource
};
}
static DEFAULT_OPTIONS = {
tag: 'form',
classes: ['daggerheart', 'views', 'roll-selection'],
position: {
width: 400,
height: 'auto'
},
actions: {
selectExperience: this.selectExperience,
decreaseHopeUse: this.decreaseHopeUse,
increaseHopeUse: this.increaseHopeUse,
setAdvantage: this.setAdvantage,
setDisadvantage: this.setDisadvantage,
finish: this.finish
},
form: {
handler: this.updateSelection,
submitOnChange: true,
submitOnClose: false
} }
return acc;
}, []),
hopeResource: hopeResource,
}; };
}
static DEFAULT_OPTIONS = { /** @override */
tag: 'form', static PARTS = {
classes: ["daggerheart", "views", "roll-selection"], damageSelection: {
position: { id: 'damageSelection',
width: 400, template: 'systems/daggerheart/templates/views/rollSelection.hbs'
height: "auto" }
}, };
actions: {
selectExperience: this.selectExperience,
decreaseHopeUse: this.decreaseHopeUse,
increaseHopeUse: this.increaseHopeUse,
setAdvantage: this.setAdvantage,
setDisadvantage: this.setDisadvantage,
finish: this.finish,
},
form: {
handler: this.updateSelection,
submitOnChange: true,
submitOnClose: false,
}
};
/** @override */
static PARTS = {
damageSelection: {
id: "damageSelection",
template: "systems/daggerheart/templates/views/rollSelection.hbs"
}
}
get title() { get title() {
return `Roll Options`; return `Roll Options`;
} }
async _prepareContext(_options) { async _prepareContext(_options) {
const context = await super._prepareContext(_options); const context = await super._prepareContext(_options);
context.isNpc = this.isNpc; context.isNpc = this.isNpc;
context.diceOptions = this.data.diceOptions; context.diceOptions = this.data.diceOptions;
context.hope = this.data.hope; context.hope = this.data.hope;
context.fear = this.data.fear; context.fear = this.data.fear;
context.advantage = this.data.advantage; context.advantage = this.data.advantage;
context.disadvantage = this.data.disadvantage; context.disadvantage = this.data.disadvantage;
context.experiences = this.experiences.map(x => ({ ...x, selected: this.selectedExperiences.find(selected => selected.id === x.id) })); context.experiences = this.experiences.map(x => ({
context.bonusDamage = this.data.bonusDamage; ...x,
context.hopeResource = this.data.hopeResource+1; selected: this.selectedExperiences.find(selected => selected.id === x.id)
context.hopeUsed = this.getHopeUsed(); }));
context.bonusDamage = this.data.bonusDamage;
context.hopeResource = this.data.hopeResource + 1;
context.hopeUsed = this.getHopeUsed();
return context; return context;
} }
static updateSelection(event, _, formData){ static updateSelection(event, _, formData) {
const { bonusDamage, ...rest } = foundry.utils.expandObject(formData.object); const { bonusDamage, ...rest } = foundry.utils.expandObject(formData.object);
for(var index in bonusDamage){ for (var index in bonusDamage) {
this.data.bonusDamage[index].initiallySelected = bonusDamage[index].initiallySelected; this.data.bonusDamage[index].initiallySelected = bonusDamage[index].initiallySelected;
if(bonusDamage[index].hopeUses){ if (bonusDamage[index].hopeUses) {
const value = Number.parseInt(bonusDamage[index].hopeUses); const value = Number.parseInt(bonusDamage[index].hopeUses);
if(!Number.isNaN(value)) this.data.bonusDamage[index].hopeUses = value; if (!Number.isNaN(value)) this.data.bonusDamage[index].hopeUses = value;
}
}
this.data = foundry.utils.mergeObject(this.data, rest);
this.render();
}
static selectExperience(_, button) {
if (this.selectedExperiences.find(x => x.id === button.dataset.key)) {
this.selectedExperiences = this.selectedExperiences.filter(x => x.id !== button.dataset.key);
} else {
this.selectedExperiences = [
...this.selectedExperiences,
this.experiences.find(x => x.id === button.dataset.key)
];
}
this.render();
}
getHopeUsed() {
return this.data.bonusDamage.reduce((acc, x) => acc + x.hopeUses, 0);
}
static decreaseHopeUse(_, button) {
const index = Number.parseInt(button.dataset.index);
if (this.data.bonusDamage[index].hopeUses - 1 >= 0) {
this.data.bonusDamage[index].hopeUses -= 1;
this.render(true);
} }
} }
this.data = foundry.utils.mergeObject(this.data, rest); static increaseHopeUse(_, button) {
this.render(); const index = Number.parseInt(button.dataset.index);
} if (this.data.bonusDamage[index].hopeUses <= this.data.hopeResource + 1) {
this.data.bonusDamage[index].hopeUses += 1;
static selectExperience(_, button){ this.render(true);
if(this.selectedExperiences.find(x => x.id === button.dataset.key)){ }
this.selectedExperiences = this.selectedExperiences.filter(x => x.id !== button.dataset.key);
} else {
this.selectedExperiences = [...this.selectedExperiences, this.experiences.find(x => x.id === button.dataset.key)];
} }
this.render(); static setAdvantage() {
} this.data.advantage = this.data.advantage ? null : 'd6';
this.data.disadvantage = null;
getHopeUsed(){ this.render(true);
return this.data.bonusDamage.reduce((acc, x) => acc+x.hopeUses, 0); }
}
static decreaseHopeUse(_, button){ static setDisadvantage() {
const index = Number.parseInt(button.dataset.index); this.data.advantage = null;
if(this.data.bonusDamage[index].hopeUses - 1 >= 0) { this.data.disadvantage = this.data.disadvantage ? null : 'd6';
this.data.bonusDamage[index].hopeUses -= 1;
this.render(true);
}
}
static increaseHopeUse(_, button){ this.render(true);
const index = Number.parseInt(button.dataset.index); }
if(this.data.bonusDamage[index].hopeUses <= this.data.hopeResource+1) {
this.data.bonusDamage[index].hopeUses += 1;
this.render(true);
}
}
static setAdvantage(){ static async finish() {
this.data.advantage = this.data.advantage ? null : 'd6'; const { diceOptions, ...rest } = this.data;
this.data.disadvantage = null; this.resolve({
...rest,
this.render(true); experiences: this.selectedExperiences,
} hopeUsed: this.getHopeUsed(),
bonusDamage: this.data.bonusDamage.reduce((acc, x) => acc.concat(` + ${1 + x.hopeUses}${x.value}`), '')
static setDisadvantage(){ });
this.data.advantage = null; this.close();
this.data.disadvantage = this.data.disadvantage ? null : 'd6'; }
this.render(true);
}
static async finish(){
const { diceOptions, ...rest } = this.data;
this.resolve({ ...rest, experiences: this.selectedExperiences, hopeUsed: this.getHopeUsed(), bonusDamage: this.data.bonusDamage.reduce((acc, x) => acc.concat(` + ${1+x.hopeUses}${x.value}`), "") });
this.close();
}
} }
// V1.3 // V1.3
@ -194,7 +208,7 @@ export default class RollSelectionDialog extends HandlebarsApplicationMixin(Appl
// closeOnSubmit: false, // closeOnSubmit: false,
// } // }
// }; // };
// /** @override */ // /** @override */
// static PARTS = { // static PARTS = {
// damageSelection: { // damageSelection: {
@ -225,7 +239,7 @@ export default class RollSelectionDialog extends HandlebarsApplicationMixin(Appl
// static updateSelection(event, _, formData){ // static updateSelection(event, _, formData){
// const { bonusDamage, ...rest } = foundry.utils.expandObject(formData.object); // const { bonusDamage, ...rest } = foundry.utils.expandObject(formData.object);
// for(var index in bonusDamage){ // for(var index in bonusDamage){
// this.data.bonusDamage[index].initiallySelected = bonusDamage[index].initiallySelected; // this.data.bonusDamage[index].initiallySelected = bonusDamage[index].initiallySelected;
// if(bonusDamage[index].hopeUses){ // if(bonusDamage[index].hopeUses){
@ -273,4 +287,4 @@ export default class RollSelectionDialog extends HandlebarsApplicationMixin(Appl
// this.resolve({ ...rest, experiences: this.selectedExperiences, hopeUsed: this.getHopeUsed(), bonusDamage: this.data.bonusDamage.reduce((acc, x) => acc.concat(` + ${1+x.hopeUses}${x.value}`), "") }); // this.resolve({ ...rest, experiences: this.selectedExperiences, hopeUsed: this.getHopeUsed(), bonusDamage: this.data.bonusDamage.reduce((acc, x) => acc.concat(` + ${1+x.hopeUses}${x.value}`), "") });
// this.close(); // this.close();
// } // }
// } // }

View file

@ -1,26 +1,26 @@
class DhpAutomationSettings extends FormApplication { class DhpAutomationSettings extends FormApplication {
constructor(object={}, options={}){ constructor(object = {}, options = {}) {
super(object, options); super(object, options);
} }
static get defaultOptions() { static get defaultOptions() {
const defaults = super.defaultOptions; const defaults = super.defaultOptions;
const overrides = { const overrides = {
height: 'auto', height: 'auto',
width: 400, width: 400,
id: 'daggerheart-automation-settings', id: 'daggerheart-automation-settings',
template: 'systems/daggerheart/templates/views/automation-settings.hbs', template: 'systems/daggerheart/templates/views/automation-settings.hbs',
closeOnSubmit: true, closeOnSubmit: true,
submitOnChange: false, submitOnChange: false,
classes: ["daggerheart", "views", "settings"], classes: ['daggerheart', 'views', 'settings']
}; };
const mergedOptions = foundry.utils.mergeObject(defaults, overrides); const mergedOptions = foundry.utils.mergeObject(defaults, overrides);
return mergedOptions; return mergedOptions;
} }
async getData(){ async getData() {
const context = super.getData(); const context = super.getData();
context.settings = SYSTEM.SETTINGS.gameSettings.Automation; context.settings = SYSTEM.SETTINGS.gameSettings.Automation;
context.hope = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.Hope); context.hope = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.Hope);
@ -36,35 +36,35 @@ class DhpAutomationSettings extends FormApplication {
async _updateObject(_, formData) { async _updateObject(_, formData) {
const data = foundry.utils.expandObject(formData); const data = foundry.utils.expandObject(formData);
const updateSettingsKeys = Object.keys(data); const updateSettingsKeys = Object.keys(data);
for(var i = 0; i < updateSettingsKeys.length; i++){ for (var i = 0; i < updateSettingsKeys.length; i++) {
await game.settings.set(SYSTEM.id, updateSettingsKeys[i], data[updateSettingsKeys[i]]); await game.settings.set(SYSTEM.id, updateSettingsKeys[i], data[updateSettingsKeys[i]]);
} }
} }
} }
class DhpHomebrewSettings extends FormApplication { class DhpHomebrewSettings extends FormApplication {
constructor(object={}, options={}){ constructor(object = {}, options = {}) {
super(object, options); super(object, options);
} }
static get defaultOptions() { static get defaultOptions() {
const defaults = super.defaultOptions; const defaults = super.defaultOptions;
const overrides = { const overrides = {
height: 'auto', height: 'auto',
width: 400, width: 400,
id: 'daggerheart-homebrew-settings', id: 'daggerheart-homebrew-settings',
template: 'systems/daggerheart/templates/views/homebrew-settings.hbs', template: 'systems/daggerheart/templates/views/homebrew-settings.hbs',
closeOnSubmit: true, closeOnSubmit: true,
submitOnChange: false, submitOnChange: false,
classes: ["daggerheart", "views", "settings"], classes: ['daggerheart', 'views', 'settings']
}; };
const mergedOptions = foundry.utils.mergeObject(defaults, overrides); const mergedOptions = foundry.utils.mergeObject(defaults, overrides);
return mergedOptions; return mergedOptions;
} }
async getData(){ async getData() {
const context = super.getData(); const context = super.getData();
context.settings = SYSTEM.SETTINGS.gameSettings.General; context.settings = SYSTEM.SETTINGS.gameSettings.General;
context.abilityArray = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.General.AbilityArray); context.abilityArray = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.General.AbilityArray);
@ -79,14 +79,14 @@ class DhpHomebrewSettings extends FormApplication {
async _updateObject(_, formData) { async _updateObject(_, formData) {
const data = foundry.utils.expandObject(formData); const data = foundry.utils.expandObject(formData);
const updateSettingsKeys = Object.keys(data); const updateSettingsKeys = Object.keys(data);
for(var i = 0; i < updateSettingsKeys.length; i++){ for (var i = 0; i < updateSettingsKeys.length; i++) {
await game.settings.set(SYSTEM.id, updateSettingsKeys[i], data[updateSettingsKeys[i]]); await game.settings.set(SYSTEM.id, updateSettingsKeys[i], data[updateSettingsKeys[i]]);
} }
} }
} }
class DhpRangeSettings extends FormApplication { class DhpRangeSettings extends FormApplication {
constructor(object={}, options={}){ constructor(object = {}, options = {}) {
super(object, options); super(object, options);
this.range = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.General.RangeMeasurement); this.range = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.General.RangeMeasurement);
@ -95,25 +95,33 @@ class DhpRangeSettings extends FormApplication {
static get defaultOptions() { static get defaultOptions() {
const defaults = super.defaultOptions; const defaults = super.defaultOptions;
const overrides = { const overrides = {
height: 'auto', height: 'auto',
width: 400, width: 400,
id: 'daggerheart-range-settings', id: 'daggerheart-range-settings',
template: 'systems/daggerheart/templates/views/range-settings.hbs', template: 'systems/daggerheart/templates/views/range-settings.hbs',
closeOnSubmit: false, closeOnSubmit: false,
submitOnChange: true, submitOnChange: true,
classes: ["daggerheart", "views", "settings"], classes: ['daggerheart', 'views', 'settings']
}; };
const mergedOptions = foundry.utils.mergeObject(defaults, overrides); const mergedOptions = foundry.utils.mergeObject(defaults, overrides);
return mergedOptions; return mergedOptions;
} }
async getData(){ async getData() {
const context = super.getData(); const context = super.getData();
context.settings = SYSTEM.SETTINGS.gameSettings.General; context.settings = SYSTEM.SETTINGS.gameSettings.General;
context.range = this.range; context.range = this.range;
context.disabled = context.range.enabled && [context.range.melee, context.range.veryClose, context.range.close, context.range.far, context.range.veryFar].some(x => x === null || x === false); context.disabled =
context.range.enabled &&
[
context.range.melee,
context.range.veryClose,
context.range.close,
context.range.far,
context.range.veryFar
].some(x => x === null || x === false);
return context; return context;
} }
@ -121,9 +129,9 @@ class DhpRangeSettings extends FormApplication {
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
html.find(".range-reset").click(this.reset.bind(this)); html.find('.range-reset').click(this.reset.bind(this));
html.find(".save").click(this.save.bind(this)); html.find('.save').click(this.save.bind(this));
html.find(".close").click(this.close.bind(this)); html.find('.close').click(this.close.bind(this));
} }
async _updateObject(_, formData) { async _updateObject(_, formData) {
@ -132,7 +140,7 @@ class DhpRangeSettings extends FormApplication {
this.render(true); this.render(true);
} }
reset(){ reset() {
this.range = { this.range = {
enabled: false, enabled: false,
melee: 5, melee: 5,
@ -144,7 +152,7 @@ class DhpRangeSettings extends FormApplication {
this.render(true); this.render(true);
} }
async save(){ async save() {
await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.General.RangeMeasurement, this.range); await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.General.RangeMeasurement, this.range);
this.close(); this.close();
} }
@ -154,44 +162,44 @@ export const registerDHPSettings = () => {
// const debouncedReload = foundry.utils.debounce(() => window.location.reload(), 100); // const debouncedReload = foundry.utils.debounce(() => window.location.reload(), 100);
game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.General.AbilityArray, { game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.General.AbilityArray, {
name: game.i18n.localize("DAGGERHEART.Settings.General.AbilityArray.Name"), name: game.i18n.localize('DAGGERHEART.Settings.General.AbilityArray.Name'),
hint: game.i18n.localize("DAGGERHEART.Settings.General.AbilityArray.Hint"), hint: game.i18n.localize('DAGGERHEART.Settings.General.AbilityArray.Hint'),
scope: 'world', scope: 'world',
config: false, config: false,
type: String, type: String,
default: '[2,1,1,0,0,-1]', default: '[2,1,1,0,0,-1]'
}); });
game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear, { game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear, {
name: game.i18n.localize("DAGGERHEART.Settings.Resources.Fear.Name"), name: game.i18n.localize('DAGGERHEART.Settings.Resources.Fear.Name'),
hint: game.i18n.localize("DAGGERHEART.Settings.Resources.Fear.Hint"), hint: game.i18n.localize('DAGGERHEART.Settings.Resources.Fear.Hint'),
scope: 'world', scope: 'world',
config: false, config: false,
type: Number, type: Number,
default: 0, default: 0
}); });
game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.Hope, { game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.Hope, {
name: game.i18n.localize("DAGGERHEART.Settings.Automation.Hope.Name"), name: game.i18n.localize('DAGGERHEART.Settings.Automation.Hope.Name'),
hint: game.i18n.localize("DAGGERHEART.Settings.Automation.Hope.Hint"), hint: game.i18n.localize('DAGGERHEART.Settings.Automation.Hope.Hint'),
scope: 'world', scope: 'world',
config: false, config: false,
type: Boolean, type: Boolean,
default: false, default: false
}); });
game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.ActionPoints, { game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.ActionPoints, {
name: game.i18n.localize("DAGGERHEART.Settings.Automation.ActionPoints.Name"), name: game.i18n.localize('DAGGERHEART.Settings.Automation.ActionPoints.Name'),
hint: game.i18n.localize("DAGGERHEART.Settings.Automation.ActionPoints.Hint"), hint: game.i18n.localize('DAGGERHEART.Settings.Automation.ActionPoints.Hint'),
scope: 'world', scope: 'world',
config: false, config: false,
type: Boolean, type: Boolean,
default: true, default: true
}); });
game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.General.RangeMeasurement, { game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.General.RangeMeasurement, {
name: game.i18n.localize("DAGGERHEART.Settings.General.RangeMeasurement.Name"), name: game.i18n.localize('DAGGERHEART.Settings.General.RangeMeasurement.Name'),
hint: game.i18n.localize("DAGGERHEART.Settings.General.RangeMeasurement.Hint"), hint: game.i18n.localize('DAGGERHEART.Settings.General.RangeMeasurement.Hint'),
scope: 'world', scope: 'world',
config: false, config: false,
type: Object, type: Object,
@ -202,35 +210,34 @@ export const registerDHPSettings = () => {
close: 30, close: 30,
far: 60, far: 60,
veryFar: 120 veryFar: 120
}, }
}); });
game.settings.registerMenu(SYSTEM.id, SYSTEM.SETTINGS.menu.Automation.Name, { game.settings.registerMenu(SYSTEM.id, SYSTEM.SETTINGS.menu.Automation.Name, {
name: game.i18n.localize("DAGGERHEART.Settings.Menu.Automation.Name"), name: game.i18n.localize('DAGGERHEART.Settings.Menu.Automation.Name'),
label: game.i18n.localize("DAGGERHEART.Settings.Menu.Automation.Label"), label: game.i18n.localize('DAGGERHEART.Settings.Menu.Automation.Label'),
hint: game.i18n.localize("DAGGERHEART.Settings.Menu.Automation.Hint"), hint: game.i18n.localize('DAGGERHEART.Settings.Menu.Automation.Hint'),
icon: SYSTEM.SETTINGS.menu.Automation.Icon, icon: SYSTEM.SETTINGS.menu.Automation.Icon,
type: DhpAutomationSettings, type: DhpAutomationSettings,
restricted: true restricted: true
}); });
game.settings.registerMenu(SYSTEM.id, SYSTEM.SETTINGS.menu.Homebrew.Name, { game.settings.registerMenu(SYSTEM.id, SYSTEM.SETTINGS.menu.Homebrew.Name, {
name: game.i18n.localize("DAGGERHEART.Settings.Menu.Homebrew.Name"), name: game.i18n.localize('DAGGERHEART.Settings.Menu.Homebrew.Name'),
label: game.i18n.localize("DAGGERHEART.Settings.Menu.Homebrew.Label"), label: game.i18n.localize('DAGGERHEART.Settings.Menu.Homebrew.Label'),
hint: game.i18n.localize("DAGGERHEART.Settings.Menu.Homebrew.Hint"), hint: game.i18n.localize('DAGGERHEART.Settings.Menu.Homebrew.Hint'),
icon: SYSTEM.SETTINGS.menu.Homebrew.Icon, icon: SYSTEM.SETTINGS.menu.Homebrew.Icon,
type: DhpHomebrewSettings, type: DhpHomebrewSettings,
restricted: true restricted: true
}); });
game.settings.registerMenu(SYSTEM.id, SYSTEM.SETTINGS.menu.Range.Name, { game.settings.registerMenu(SYSTEM.id, SYSTEM.SETTINGS.menu.Range.Name, {
name: game.i18n.localize("DAGGERHEART.Settings.Menu.Range.Name"), name: game.i18n.localize('DAGGERHEART.Settings.Menu.Range.Name'),
label: game.i18n.localize("DAGGERHEART.Settings.Menu.Range.Label"), label: game.i18n.localize('DAGGERHEART.Settings.Menu.Range.Label'),
hint: game.i18n.localize("DAGGERHEART.Settings.Menu.Range.Hint"), hint: game.i18n.localize('DAGGERHEART.Settings.Menu.Range.Hint'),
icon: SYSTEM.SETTINGS.menu.Range.Icon, icon: SYSTEM.SETTINGS.menu.Range.Icon,
type: DhpRangeSettings, type: DhpRangeSettings,
restricted: true restricted: true
}); });
} };
// const {HandlebarsApplicationMixin, ApplicationV2} = foundry.applications.api; // const {HandlebarsApplicationMixin, ApplicationV2} = foundry.applications.api;
@ -246,7 +253,7 @@ export const registerDHPSettings = () => {
// } // }
// get title(){ // get title(){
// return game.i18n.localize("DAGGERHEART.Application.Settings.Title"); // return game.i18n.localize("DAGGERHEART.Application.Settings.Title");
// } // }
// static DEFAULT_OPTIONS = { // static DEFAULT_OPTIONS = {
@ -258,7 +265,7 @@ export const registerDHPSettings = () => {
// }, // },
// form: { handler: this.updateData } // form: { handler: this.updateData }
// }; // };
// static PARTS = { // static PARTS = {
// application: { // application: {
// id: "settings", // id: "settings",
@ -279,4 +286,4 @@ export const registerDHPSettings = () => {
// static close(){ // static close(){
// super.close(); // super.close();
// } // }
// } // }

View file

@ -1,4 +1,3 @@
// import DhpApplicationMixin from '../daggerheart-sheet.mjs'; // import DhpApplicationMixin from '../daggerheart-sheet.mjs';
// export class Teest extends DhpApplicationMixin(ActorSheet) { // export class Teest extends DhpApplicationMixin(ActorSheet) {
@ -33,10 +32,10 @@
// type: game.i18n.localize(SYSTEM.ACTOR.adversaryTypes[this.object.system.type].name), // type: game.i18n.localize(SYSTEM.ACTOR.adversaryTypes[this.object.system.type].name),
// attack: { // attack: {
// name: this.object.system.attack.name, // name: this.object.system.attack.name,
// attackModifier: this.object.system.attackModifier, // attackModifier: this.object.system.attackModifier,
// range: this.object.system.attack.range ? game.i18n.localize(SYSTEM.GENERAL.range[this.object.system.attack.range].name) : null, // range: this.object.system.attack.range ? game.i18n.localize(SYSTEM.GENERAL.range[this.object.system.attack.range].name) : null,
// damage: { // damage: {
// value: this.object.system.attack.damage.value, // value: this.object.system.attack.damage.value,
// type: this.object.system.attack.damage.type, // type: this.object.system.attack.damage.type,
// typeName: this.object.system.attack.damage.type ? game.i18n.localize(SYSTEM.GENERAL.damageTypes[this.object.system.attack.damage.type].abbreviation).toLowerCase() : null, // typeName: this.object.system.attack.damage.type ? game.i18n.localize(SYSTEM.GENERAL.damageTypes[this.object.system.attack.damage.type].abbreviation).toLowerCase() : null,
// }, // },
@ -68,7 +67,7 @@
// case 'addMotive': // case 'addMotive':
// await this.addMotive(); // await this.addMotive();
// break; // break;
// case 'removeMotive': // case 'removeMotive':
// await this.removeMotive(button); // await this.removeMotive(button);
// break; // break;
// case 'reactionRoll': // case 'reactionRoll':
@ -138,7 +137,7 @@
// content: "systems/daggerheart/templates/chat/adversary-roll.hbs", // content: "systems/daggerheart/templates/chat/adversary-roll.hbs",
// rolls: [roll] // rolls: [roll]
// }); // });
// cls.create(msg.toObject()); // cls.create(msg.toObject());
// } // }
@ -169,7 +168,7 @@
// content: "systems/daggerheart/templates/chat/adversary-attack-roll.hbs", // content: "systems/daggerheart/templates/chat/adversary-attack-roll.hbs",
// rolls: [roll] // rolls: [roll]
// }); // });
// cls.create(msg.toObject()); // cls.create(msg.toObject());
// } // }
@ -198,16 +197,16 @@ import DaggerheartSheet from './daggerheart-sheet.mjs';
const { ActorSheetV2 } = foundry.applications.sheets; const { ActorSheetV2 } = foundry.applications.sheets;
export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) { export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) {
constructor(options={}){ constructor(options = {}) {
super(options); super(options);
this.editMode = false; this.editMode = false;
} }
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
tag: 'form', tag: 'form',
id: "daggerheart-adversary", id: 'daggerheart-adversary',
classes: ["daggerheart", "sheet", "adversary"], classes: ['daggerheart', 'sheet', 'adversary'],
position: { width: 600 }, position: { width: 600 },
actions: { actions: {
viewMove: this.viewMove, viewMove: this.viewMove,
@ -221,21 +220,21 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) {
addExperience: this.addExperience, addExperience: this.addExperience,
removeExperience: this.removeExperience, removeExperience: this.removeExperience,
toggleHP: this.toggleHP, toggleHP: this.toggleHP,
toggleStress: this.toggleStress, toggleStress: this.toggleStress
}, },
form: { form: {
handler: this.updateForm, handler: this.updateForm,
submitOnChange: true, submitOnChange: true,
closeOnSubmit: false, closeOnSubmit: false
}, }
}; };
static PARTS = { static PARTS = {
form: { form: {
id: "feature", id: 'feature',
template: "systems/daggerheart/templates/sheets/adversary.hbs" template: 'systems/daggerheart/templates/sheets/adversary.hbs'
} }
} };
async _prepareContext(_options) { async _prepareContext(_options) {
const context = await super._prepareContext(_options); const context = await super._prepareContext(_options);
@ -251,93 +250,119 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) {
type: game.i18n.localize(SYSTEM.ACTOR.adversaryTypes[this.document.system.type].name), type: game.i18n.localize(SYSTEM.ACTOR.adversaryTypes[this.document.system.type].name),
attack: { attack: {
name: this.document.system.attack.name, name: this.document.system.attack.name,
attackModifier: this.document.system.attackModifier, attackModifier: this.document.system.attackModifier,
range: this.document.system.attack.range ? game.i18n.localize(SYSTEM.GENERAL.range[this.document.system.attack.range].name) : null, range: this.document.system.attack.range
? game.i18n.localize(SYSTEM.GENERAL.range[this.document.system.attack.range].name)
: null,
damage: { damage: {
value: this.document.system.attack.damage.value, value: this.document.system.attack.damage.value,
type: this.document.system.attack.damage.type, type: this.document.system.attack.damage.type,
typeName: this.document.system.attack.damage.type ? game.i18n.localize(SYSTEM.GENERAL.damageTypes[this.document.system.attack.damage.type].abbreviation).toLowerCase() : null, typeName: this.document.system.attack.damage.type
}, ? game.i18n
.localize(
SYSTEM.GENERAL.damageTypes[this.document.system.attack.damage.type].abbreviation
)
.toLowerCase()
: null
}
}, },
damageThresholds: this.document.system.damageThresholds, damageThresholds: this.document.system.damageThresholds,
difficulty: this.document.system.difficulty, difficulty: this.document.system.difficulty,
hp: { ...this.document.system.resources.health, lastRowIndex: Math.floor(this.document.system.resources.health.max/5)*5 }, hp: {
stress: { ...this.document.system.resources.stress, lastRowIndex: Math.floor(this.document.system.resources.stress.max/5)*5 }, ...this.document.system.resources.health,
moves: this.document.system.moves, lastRowIndex: Math.floor(this.document.system.resources.health.max / 5) * 5
},
stress: {
...this.document.system.resources.stress,
lastRowIndex: Math.floor(this.document.system.resources.stress.max / 5) * 5
},
moves: this.document.system.moves
}; };
return context; return context;
} }
static async updateForm(event, _, formData) { static async updateForm(event, _, formData) {
await this.document.update(formData.object) await this.document.update(formData.object);
this.render(); this.render();
} }
static async viewMove(_, button){ static async viewMove(_, button) {
const move = await fromUuid(button.dataset.move); const move = await fromUuid(button.dataset.move);
move.sheet.render(true); move.sheet.render(true);
} }
static async addMove(){ static async addMove() {
const result = await this.document.createEmbeddedDocuments("Item", [{ const result = await this.document.createEmbeddedDocuments('Item', [
name: game.i18n.localize('DAGGERHEART.Sheets.Adversary.NewMove'), {
type: 'feature', name: game.i18n.localize('DAGGERHEART.Sheets.Adversary.NewMove'),
}]); type: 'feature'
}
]);
await result[0].sheet.render(true); await result[0].sheet.render(true);
} }
static async removeMove(_, button){ static async removeMove(_, button) {
await this.document.items.find(x => x.uuid === button.dataset.move).delete(); await this.document.items.find(x => x.uuid === button.dataset.move).delete();
} }
static toggleEditMode(){ static toggleEditMode() {
this.editMode = !this.editMode; this.editMode = !this.editMode;
this.render(); this.render();
} }
static async addMotive(){ static async addMotive() {
await this.document.update({ "system.motivesAndTactics": [...this.document.system.motivesAndTactics, ''] }); await this.document.update({ 'system.motivesAndTactics': [...this.document.system.motivesAndTactics, ''] });
} }
static async removeMotive(button){ static async removeMotive(button) {
await this.document.update({ "system.motivesAndTactics": this.document.system.motivesAndTactics.filter((_, index) => index !== Number.parseInt(button.dataset.motive) )}); await this.document.update({
'system.motivesAndTactics': this.document.system.motivesAndTactics.filter(
(_, index) => index !== Number.parseInt(button.dataset.motive)
)
});
} }
static async reactionRoll(event){ static async reactionRoll(event) {
const { roll, diceResults, modifiers } = await this.actor.diceRoll({ title: `${this.actor.name} - Reaction Roll`, value: 0 }, event.shiftKey); const { roll, diceResults, modifiers } = await this.actor.diceRoll(
{ title: `${this.actor.name} - Reaction Roll`, value: 0 },
event.shiftKey
);
const cls = getDocumentClass("ChatMessage"); const cls = getDocumentClass('ChatMessage');
const msg = new cls({ const msg = new cls({
type: 'adversaryRoll', type: 'adversaryRoll',
system: { system: {
roll: roll._formula, roll: roll._formula,
total: roll._total, total: roll._total,
modifiers: modifiers, modifiers: modifiers,
diceResults: diceResults, diceResults: diceResults
}, },
content: "systems/daggerheart/templates/chat/adversary-roll.hbs", content: 'systems/daggerheart/templates/chat/adversary-roll.hbs',
rolls: [roll] rolls: [roll]
}); });
cls.create(msg.toObject()); cls.create(msg.toObject());
} }
static async attackRoll(event, button){ static async attackRoll(event, button) {
const modifier = Number.parseInt(button.dataset.value); const modifier = Number.parseInt(button.dataset.value);
const { roll, diceResults, modifiers } = await this.actor.diceRoll({ title: `${this.actor.name} - Attack Roll`, value: modifier }, event.shiftKey); const { roll, diceResults, modifiers } = await this.actor.diceRoll(
{ title: `${this.actor.name} - Attack Roll`, value: modifier },
event.shiftKey
);
const targets = Array.from(game.user.targets).map(x => ({ const targets = Array.from(game.user.targets).map(x => ({
id: x.id, id: x.id,
name: x.actor.name, name: x.actor.name,
img: x.actor.img, img: x.actor.img,
difficulty: x.actor.system.difficulty, difficulty: x.actor.system.difficulty,
evasion: x.actor.system.evasion, evasion: x.actor.system.evasion
})); }));
const cls = getDocumentClass("ChatMessage"); const cls = getDocumentClass('ChatMessage');
const msg = new cls({ const msg = new cls({
type: 'adversaryRoll', type: 'adversaryRoll',
system: { system: {
@ -346,32 +371,38 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) {
modifiers: modifiers, modifiers: modifiers,
diceResults: diceResults, diceResults: diceResults,
targets: targets, targets: targets,
damage: { value: button.dataset.damage, type: button.dataset.damageType }, damage: { value: button.dataset.damage, type: button.dataset.damageType }
}, },
content: "systems/daggerheart/templates/chat/adversary-attack-roll.hbs", content: 'systems/daggerheart/templates/chat/adversary-attack-roll.hbs',
rolls: [roll] rolls: [roll]
}); });
cls.create(msg.toObject()); cls.create(msg.toObject());
} }
static async addExperience(){ static async addExperience() {
await this.document.update({ "system.experiences": [...this.document.system.experiences, { name: 'Experience', value: 1 }] }); await this.document.update({
'system.experiences': [...this.document.system.experiences, { name: 'Experience', value: 1 }]
});
} }
static async removeExperience(_, button){ static async removeExperience(_, button) {
await this.document.update({ "system.experiences": this.document.system.experiences.filter((_, index) => index !== Number.parseInt(button.dataset.experience) )}); await this.document.update({
'system.experiences': this.document.system.experiences.filter(
(_, index) => index !== Number.parseInt(button.dataset.experience)
)
});
} }
static async toggleHP(_, button){ static async toggleHP(_, button) {
const index = Number.parseInt(button.dataset.index); const index = Number.parseInt(button.dataset.index);
const newHP = index < this.document.system.resources.health.value ? index : index+1; const newHP = index < this.document.system.resources.health.value ? index : index + 1;
await this.document.update({ "system.resources.health.value": newHP }); await this.document.update({ 'system.resources.health.value': newHP });
} }
static async toggleStress(_, button){ static async toggleStress(_, button) {
const index = Number.parseInt(button.dataset.index); const index = Number.parseInt(button.dataset.index);
const newStress = index < this.document.system.resources.stress.value ? index : index+1; const newStress = index < this.document.system.resources.stress.value ? index : index + 1;
await this.document.update({ "system.resources.stress.value": newStress }); await this.document.update({ 'system.resources.stress.value': newStress });
} }
} }

View file

@ -24,13 +24,12 @@
// return context; // return context;
// } // }
// async _handleAction(action, event, button) { // async _handleAction(action, event, button) {
// switch(action){ // switch(action){
// case 'editAbility': // case 'editAbility':
// this.editAbility(button); // this.editAbility(button);
// break; // break;
// case 'deleteAbility': // case 'deleteAbility':
// this.deleteAbility(event); // this.deleteAbility(event);
// break; // break;
// } // }
@ -59,30 +58,30 @@
import DaggerheartSheet from './daggerheart-sheet.mjs'; import DaggerheartSheet from './daggerheart-sheet.mjs';
const { ItemSheetV2 } = foundry.applications.sheets; const { ItemSheetV2 } = foundry.applications.sheets;
export default class AncestrySheet extends DaggerheartSheet(ItemSheetV2) { export default class AncestrySheet extends DaggerheartSheet(ItemSheetV2) {
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
tag: 'form', tag: 'form',
id: "daggerheart-ancestry", id: 'daggerheart-ancestry',
classes: ["daggerheart", "sheet", "heritage"], classes: ['daggerheart', 'sheet', 'heritage'],
position: { width: 600 }, position: { width: 600 },
actions: { actions: {
editAbility: this.editAbility, editAbility: this.editAbility,
deleteAbility: this.deleteAbility, deleteAbility: this.deleteAbility
}, },
form: { form: {
handler: this.updateForm, handler: this.updateForm,
submitOnChange: true, submitOnChange: true,
closeOnSubmit: false, closeOnSubmit: false
}, },
dragDrop: [{ dragSelector: null, dropSelector: null }], dragDrop: [{ dragSelector: null, dropSelector: null }]
}; };
static PARTS = { static PARTS = {
form: { form: {
id: "feature", id: 'feature',
template: "systems/daggerheart/templates/sheets/ancestry.hbs" template: 'systems/daggerheart/templates/sheets/ancestry.hbs'
} }
} };
async _prepareContext(_options) { async _prepareContext(_options) {
const context = await super._prepareContext(_options); const context = await super._prepareContext(_options);
@ -92,26 +91,33 @@ export default class AncestrySheet extends DaggerheartSheet(ItemSheetV2) {
} }
static async updateForm(event, _, formData) { static async updateForm(event, _, formData) {
await this.document.update(formData.object) await this.document.update(formData.object);
this.render(); this.render();
} }
static async editAbility(_, button){ static async editAbility(_, button) {
const feature = await fromUuid(button.dataset.ability); const feature = await fromUuid(button.dataset.ability);
feature.sheet.render(true); feature.sheet.render(true);
} }
static async deleteAbility(event, button){ static async deleteAbility(event, button) {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
await this.item.update({ "system.abilities": this.item.system.abilities.filter(x => x.uuid !== button.dataset.ability) }) await this.item.update({
'system.abilities': this.item.system.abilities.filter(x => x.uuid !== button.dataset.ability)
});
} }
async _onDrop(event) { async _onDrop(event) {
const data = TextEditor.getDragEventData(event); const data = TextEditor.getDragEventData(event);
const item = await fromUuid(data.uuid); const item = await fromUuid(data.uuid);
if(item.type === 'feature' && item.system.type === SYSTEM.ITEM.featureTypes.ancestry.id) { if (item.type === 'feature' && item.system.type === SYSTEM.ITEM.featureTypes.ancestry.id) {
await this.document.update({ "system.abilities": [...this.document.system.abilities, { img: item.img, name: item.name, uuid: item.uuid }] }); await this.document.update({
'system.abilities': [
...this.document.system.abilities,
{ img: item.img, name: item.name, uuid: item.uuid }
]
});
} }
} }
} }

View file

@ -20,7 +20,6 @@
// return context; // return context;
// } // }
// async _handleAction(action, event, button) { // async _handleAction(action, event, button) {
// switch(action){ // switch(action){
// } // }
@ -29,26 +28,26 @@
import DaggerheartSheet from './daggerheart-sheet.mjs'; import DaggerheartSheet from './daggerheart-sheet.mjs';
const { ItemSheetV2 } = foundry.applications.sheets; const { ItemSheetV2 } = foundry.applications.sheets;
export default class ArmorSheet extends DaggerheartSheet(ItemSheetV2) { export default class ArmorSheet extends DaggerheartSheet(ItemSheetV2) {
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
tag: 'form', tag: 'form',
id: "daggerheart-armor", id: 'daggerheart-armor',
classes: ["daggerheart", "sheet", "armor"], classes: ['daggerheart', 'sheet', 'armor'],
position: { width: 400 }, position: { width: 400 },
form: { form: {
handler: this.updateForm, handler: this.updateForm,
submitOnChange: true, submitOnChange: true,
closeOnSubmit: false, closeOnSubmit: false
}, },
dragDrop: [{ dragSelector: null, dropSelector: null }], dragDrop: [{ dragSelector: null, dropSelector: null }]
}; };
static PARTS = { static PARTS = {
form: { form: {
id: "feature", id: 'feature',
template: "systems/daggerheart/templates/sheets/armor.hbs" template: 'systems/daggerheart/templates/sheets/armor.hbs'
} }
} };
async _prepareContext(_options) { async _prepareContext(_options) {
const context = await super._prepareContext(_options); const context = await super._prepareContext(_options);
@ -59,7 +58,7 @@ export default class ArmorSheet extends DaggerheartSheet(ItemSheetV2) {
} }
static async updateForm(event, _, formData) { static async updateForm(event, _, formData) {
await this.document.update(formData.object) await this.document.update(formData.object);
this.render(); this.render();
} }
} }

View file

@ -40,17 +40,17 @@
// const domainTagify = new Tagify(domainInput, { // const domainTagify = new Tagify(domainInput, {
// tagTextProp: "name", // tagTextProp: "name",
// enforceWhitelist: true, // enforceWhitelist: true,
// whitelist : Object.keys(SYSTEM.DOMAIN.domains).map(key => { // whitelist : Object.keys(SYSTEM.DOMAIN.domains).map(key => {
// const domain = SYSTEM.DOMAIN.domains[key]; // const domain = SYSTEM.DOMAIN.domains[key];
// return { value: key, name: game.i18n.localize(domain.name), src: domain.src, background: domain.background }; // return { value: key, name: game.i18n.localize(domain.name), src: domain.src, background: domain.background };
// }), // }),
// maxTags: 2, // maxTags: 2,
// callbacks : { invalid: this.onAddTag }, // callbacks : { invalid: this.onAddTag },
// dropdown : { // dropdown : {
// mapValueTo: 'name', // mapValueTo: 'name',
// searchKeys: ['name'], // searchKeys: ['name'],
// enabled: 0, // enabled: 0,
// maxItems: 20, // maxItems: 20,
// closeOnSelect : true, // closeOnSelect : true,
// highlightFirst: false, // highlightFirst: false,
// }, // },
@ -61,7 +61,7 @@
// spellcheck='false' // spellcheck='false'
// tabIndex="${this.settings.a11y.focusableTags ? 0 : -1}" // tabIndex="${this.settings.a11y.focusableTags ? 0 : -1}"
// class="${this.settings.classNames.tag} ${tagData.class ? tagData.class : ""}" // class="${this.settings.classNames.tag} ${tagData.class ? tagData.class : ""}"
// ${this.getAttributes(tagData)}> // ${this.getAttributes(tagData)}>
// <x class="${this.settings.classNames.tagX}" role='button' aria-label='remove tag'></x> // <x class="${this.settings.classNames.tagX}" role='button' aria-label='remove tag'></x>
// <div> // <div>
// <span class="${this.settings.classNames.tagText}">${tagData[this.settings.tagTextProp] || tagData.value}</span> // <span class="${this.settings.classNames.tagText}">${tagData[this.settings.tagTextProp] || tagData.value}</span>
@ -70,16 +70,16 @@
// </tag>`; // </tag>`;
// }} // }}
// }); // });
// domainTagify.on('change', this.onDomainSelect.bind(this)); // domainTagify.on('change', this.onDomainSelect.bind(this));
// } // }
// onAddTag(e){ // onAddTag(e){
// if( e.detail.index ===2 ){ // if( e.detail.index ===2 ){
// ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.ClassCanOnlyHaveTwoDomains")); // ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.ClassCanOnlyHaveTwoDomains"));
// } // }
// } // }
// async onDomainSelect(event) { // async onDomainSelect(event) {
// const domains = event.detail?.value ? JSON.parse(event.detail.value) : []; // const domains = event.detail?.value ? JSON.parse(event.detail.value) : [];
// await this.object.update({ "system.domains": domains.map(x => x.value) }); // await this.object.update({ "system.domains": domains.map(x => x.value) });
@ -170,7 +170,7 @@
// super._onDragStart(event); // super._onDragStart(event);
// } // }
// async _onDrop(event) { // async _onDrop(event) {
// const data = TextEditor.getDragEventData(event); // const data = TextEditor.getDragEventData(event);
// const item = await fromUuid(data.uuid); // const item = await fromUuid(data.uuid);
@ -210,14 +210,14 @@
// } // }
import DaggerheartSheet from './daggerheart-sheet.mjs'; import DaggerheartSheet from './daggerheart-sheet.mjs';
import Tagify from "@yaireo/tagify"; import Tagify from '@yaireo/tagify';
const { ItemSheetV2 } = foundry.applications.sheets; const { ItemSheetV2 } = foundry.applications.sheets;
export default class ClassSheet extends DaggerheartSheet(ItemSheetV2) { export default class ClassSheet extends DaggerheartSheet(ItemSheetV2) {
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
tag: 'form', tag: 'form',
id: "daggerheart-class", id: 'daggerheart-class',
classes: ["daggerheart", "sheet", "class"], classes: ['daggerheart', 'sheet', 'class'],
position: { width: 600 }, position: { width: 600 },
actions: { actions: {
removeSubclass: this.removeSubclass, removeSubclass: this.removeSubclass,
@ -228,13 +228,12 @@ export default class ClassSheet extends DaggerheartSheet(ItemSheetV2) {
viewItem: this.viewItem, viewItem: this.viewItem,
removePrimaryWeapon: this.removePrimaryWeapon, removePrimaryWeapon: this.removePrimaryWeapon,
removeSecondaryWeapon: this.removeSecondaryWeapon, removeSecondaryWeapon: this.removeSecondaryWeapon,
removeArmor: this.removeArmor, removeArmor: this.removeArmor
}, },
form: { form: {
handler: this.updateForm, handler: this.updateForm,
submitOnChange: true, submitOnChange: true,
closeOnSubmit: false, closeOnSubmit: false
}, },
dragDrop: [ dragDrop: [
{ dragSelector: '.suggested-item', dropSelector: null }, { dragSelector: '.suggested-item', dropSelector: null },
@ -244,25 +243,39 @@ export default class ClassSheet extends DaggerheartSheet(ItemSheetV2) {
{ dragSelector: null, dropSelector: '.primary-weapon-section' }, { dragSelector: null, dropSelector: '.primary-weapon-section' },
{ dragSelector: null, dropSelector: '.secondary-weapon-section' }, { dragSelector: null, dropSelector: '.secondary-weapon-section' },
{ dragSelector: null, dropSelector: '.armor-section' }, { dragSelector: null, dropSelector: '.armor-section' },
{ dragSelector: null, dropSelector: null }, { dragSelector: null, dropSelector: null }
] ]
}; };
static PARTS = { static PARTS = {
form: { form: {
id: "feature", id: 'feature',
template: "systems/daggerheart/templates/sheets/class.hbs" template: 'systems/daggerheart/templates/sheets/class.hbs'
} }
} };
_getTabs() { _getTabs() {
const tabs = { const tabs = {
features: { active: true, cssClass: '', group: 'primary', id: 'features', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.Class.Tabs.Features') }, features: {
guide: { active: false, cssClass: '', group: 'primary', id: 'guide', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.Class.Tabs.Guide') }, active: true,
} cssClass: '',
for ( const v of Object.values(tabs) ) { group: 'primary',
id: 'features',
icon: null,
label: game.i18n.localize('DAGGERHEART.Sheets.Class.Tabs.Features')
},
guide: {
active: false,
cssClass: '',
group: 'primary',
id: 'guide',
icon: null,
label: game.i18n.localize('DAGGERHEART.Sheets.Class.Tabs.Guide')
}
};
for (const v of Object.values(tabs)) {
v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active; v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active;
v.cssClass = v.active ? "active" : ""; v.cssClass = v.active ? 'active' : '';
} }
return tabs; return tabs;
@ -270,32 +283,38 @@ export default class ClassSheet extends DaggerheartSheet(ItemSheetV2) {
_attachPartListeners(partId, htmlElement, options) { _attachPartListeners(partId, htmlElement, options) {
super._attachPartListeners(partId, htmlElement, options); super._attachPartListeners(partId, htmlElement, options);
const domainInput = htmlElement.querySelector('.domain-input'); const domainInput = htmlElement.querySelector('.domain-input');
const domainTagify = new Tagify(domainInput, { const domainTagify = new Tagify(domainInput, {
tagTextProp: "name", tagTextProp: 'name',
enforceWhitelist: true, enforceWhitelist: true,
whitelist : Object.keys(SYSTEM.DOMAIN.domains).map(key => { whitelist: Object.keys(SYSTEM.DOMAIN.domains).map(key => {
const domain = SYSTEM.DOMAIN.domains[key]; const domain = SYSTEM.DOMAIN.domains[key];
return { value: key, name: game.i18n.localize(domain.label), src: domain.src, background: domain.background }; return {
}), value: key,
maxTags: 2, name: game.i18n.localize(domain.label),
callbacks : { invalid: this.onAddTag }, src: domain.src,
dropdown : { background: domain.background
mapValueTo: 'name', };
searchKeys: ['name'], }),
enabled: 0, maxTags: 2,
maxItems: 20, callbacks: { invalid: this.onAddTag },
closeOnSelect : true, dropdown: {
highlightFirst: false, mapValueTo: 'name',
}, searchKeys: ['name'],
templates: { enabled: 0,
tag(tagData){ //z-index: unset; background-image: ${tagData.background}; Maybe a domain specific background for the chips? maxItems: 20,
return `<tag title="${(tagData.title || tagData.value)}" closeOnSelect: true,
highlightFirst: false
},
templates: {
tag(tagData) {
//z-index: unset; background-image: ${tagData.background}; Maybe a domain specific background for the chips?
return `<tag title="${tagData.title || tagData.value}"
contenteditable='false' contenteditable='false'
spellcheck='false' spellcheck='false'
tabIndex="${this.settings.a11y.focusableTags ? 0 : -1}" tabIndex="${this.settings.a11y.focusableTags ? 0 : -1}"
class="${this.settings.classNames.tag} ${tagData.class ? tagData.class : ""}" class="${this.settings.classNames.tag} ${tagData.class ? tagData.class : ''}"
${this.getAttributes(tagData)}> ${this.getAttributes(tagData)}>
<x class="${this.settings.classNames.tagX}" role='button' aria-label='remove tag'></x> <x class="${this.settings.classNames.tagX}" role='button' aria-label='remove tag'></x>
<div> <div>
@ -303,11 +322,12 @@ export default class ClassSheet extends DaggerheartSheet(ItemSheetV2) {
<img src="${tagData.src}"></i> <img src="${tagData.src}"></i>
</div> </div>
</tag>`; </tag>`;
}} }
}
}); });
domainTagify.on('change', this.onDomainSelect.bind(this)); domainTagify.on('change', this.onDomainSelect.bind(this));
} }
async _prepareContext(_options) { async _prepareContext(_options) {
const context = await super._prepareContext(_options); const context = await super._prepareContext(_options);
@ -319,101 +339,145 @@ export default class ClassSheet extends DaggerheartSheet(ItemSheetV2) {
} }
static async updateForm(event, _, formData) { static async updateForm(event, _, formData) {
await this.document.update(formData.object) await this.document.update(formData.object);
this.render(); this.render();
} }
onAddTag(e){ onAddTag(e) {
if( e.detail.index ===2 ){ if (e.detail.index === 2) {
ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.ClassCanOnlyHaveTwoDomains")); ui.notifications.info(game.i18n.localize('DAGGERHEART.Notification.Info.ClassCanOnlyHaveTwoDomains'));
} }
} }
async onDomainSelect(event) { async onDomainSelect(event) {
const domains = event.detail?.value ? JSON.parse(event.detail.value) : []; const domains = event.detail?.value ? JSON.parse(event.detail.value) : [];
await this.document.update({ "system.domains": domains.map(x => x.value) }); await this.document.update({ 'system.domains': domains.map(x => x.value) });
this.render(true); this.render(true);
} }
static async removeSubclass(_, button){ static async removeSubclass(_, button) {
await this.document.update({ "system.subclasses": this.document.system.subclasses.filter(x => x.uuid !== button.dataset.subclass)}); await this.document.update({
'system.subclasses': this.document.system.subclasses.filter(x => x.uuid !== button.dataset.subclass)
});
} }
static async viewSubclass(_, button){ static async viewSubclass(_, button) {
const subclass = await fromUuid(button.dataset.subclass); const subclass = await fromUuid(button.dataset.subclass);
subclass.sheet.render(true); subclass.sheet.render(true);
} }
static async removeFeature(_, button){ static async removeFeature(_, button) {
await this.document.update({ "system.features": this.document.system.features.filter(x => x.uuid !== button.dataset.feature)}); await this.document.update({
'system.features': this.document.system.features.filter(x => x.uuid !== button.dataset.feature)
});
} }
static async viewFeature(_, button){ static async viewFeature(_, button) {
const feature = await fromUuid(button.dataset.feature); const feature = await fromUuid(button.dataset.feature);
feature.sheet.render(true); feature.sheet.render(true);
} }
static async removeItem(event, button){ static async removeItem(event, button) {
event.stopPropagation(); event.stopPropagation();
const type = button.dataset.type; const type = button.dataset.type;
const path = `system.inventory.${type}`; const path = `system.inventory.${type}`;
await this.document.update({ [path]: this.document.system.inventory[type].filter(x => x.uuid !== button.dataset.item)}); await this.document.update({
[path]: this.document.system.inventory[type].filter(x => x.uuid !== button.dataset.item)
});
} }
static async viewItem(_, button){ static async viewItem(_, button) {
const item = await fromUuid(button.dataset.item); const item = await fromUuid(button.dataset.item);
item.sheet.render(true); item.sheet.render(true);
} }
static async removePrimaryWeapon(event){ static async removePrimaryWeapon(event) {
event.stopPropagation(); event.stopPropagation();
await this.document.update({ "system.characterGuide.suggestedPrimaryWeapon": null }, { diff: false }); await this.document.update({ 'system.characterGuide.suggestedPrimaryWeapon': null }, { diff: false });
} }
static async removeSecondaryWeapon(event){ static async removeSecondaryWeapon(event) {
event.stopPropagation(); event.stopPropagation();
await this.document.update({ "system.characterGuide.suggestedSecondaryWeapon": null }, { diff: false }); await this.document.update({ 'system.characterGuide.suggestedSecondaryWeapon': null }, { diff: false });
} }
static async removeArmor(event){ static async removeArmor(event) {
event.stopPropagation(); event.stopPropagation();
await this.document.update({ "system.characterGuide.suggestedArmor": null }, { diff: false }); await this.document.update({ 'system.characterGuide.suggestedArmor': null }, { diff: false });
} }
async _onDrop(event) { async _onDrop(event) {
const data = TextEditor.getDragEventData(event); const data = TextEditor.getDragEventData(event);
const item = await fromUuid(data.uuid); const item = await fromUuid(data.uuid);
if(item.type === 'subclass') { if (item.type === 'subclass') {
await this.document.update({ "system.subclasses": [...this.document.system.subclasses, { img: item.img, name: item.name, uuid: item.uuid }] }); await this.document.update({
} 'system.subclasses': [
else if(item.type === 'feature') { ...this.document.system.subclasses,
{ img: item.img, name: item.name, uuid: item.uuid }
await this.document.update({ "system.features": [...this.document.system.features, { img: item.img, name: item.name, uuid: item.uuid }] }); ]
} });
else if(item.type === 'weapon'){ } else if (item.type === 'feature') {
if(event.currentTarget.classList.contains('primary-weapon-section')){ await this.document.update({
if(!this.document.system.characterGuide.suggestedPrimaryWeapon && !item.system.secondary) await this.document.update({ "system.characterGuide.suggestedPrimaryWeapon": { img: item.img, name: item.name, uuid: item.uuid } }); 'system.features': [
} else if(event.currentTarget.classList.contains('secondary-weapon-section')){ ...this.document.system.features,
if(!this.document.system.characterGuide.suggestedSecondaryWeapon && item.system.secondary) await this.document.update({ "system.characterGuide.suggestedSecondaryWeapon": { img: item.img, name: item.name, uuid: item.uuid } }); { img: item.img, name: item.name, uuid: item.uuid }
]
});
} else if (item.type === 'weapon') {
if (event.currentTarget.classList.contains('primary-weapon-section')) {
if (!this.document.system.characterGuide.suggestedPrimaryWeapon && !item.system.secondary)
await this.document.update({
'system.characterGuide.suggestedPrimaryWeapon': {
img: item.img,
name: item.name,
uuid: item.uuid
}
});
} else if (event.currentTarget.classList.contains('secondary-weapon-section')) {
if (!this.document.system.characterGuide.suggestedSecondaryWeapon && item.system.secondary)
await this.document.update({
'system.characterGuide.suggestedSecondaryWeapon': {
img: item.img,
name: item.name,
uuid: item.uuid
}
});
} }
} } else if (item.type === 'armor') {
else if(item.type === 'armor'){ if (event.currentTarget.classList.contains('armor-section')) {
if(event.currentTarget.classList.contains('armor-section')){ if (!this.document.system.characterGuide.suggestedArmor)
if(!this.document.system.characterGuide.suggestedArmor) await this.document.update({ "system.characterGuide.suggestedArmor": { img: item.img, name: item.name, uuid: item.uuid } }); await this.document.update({
'system.characterGuide.suggestedArmor': { img: item.img, name: item.name, uuid: item.uuid }
});
} }
} } else if (event.currentTarget.classList.contains('choice-a-section')) {
else if(event.currentTarget.classList.contains('choice-a-section')){ if (item.type === 'miscellaneous' || item.type === 'consumable') {
if(item.type === 'miscellaneous' || item.type === 'consumable'){ if (this.document.system.inventory.choiceA.length < 2)
if(this.document.system.inventory.choiceA.length < 2) await this.document.update({ "system.inventory.choiceA": [...this.document.system.inventory.choiceA, { img: item.img, name: item.name, uuid: item.uuid }] }); await this.document.update({
'system.inventory.choiceA': [
...this.document.system.inventory.choiceA,
{ img: item.img, name: item.name, uuid: item.uuid }
]
});
} }
} } else if (item.type === 'miscellaneous') {
else if(item.type === 'miscellaneous'){ if (event.currentTarget.classList.contains('take-section')) {
if(event.currentTarget.classList.contains('take-section')){ if (this.document.system.inventory.take.length < 3)
if(this.document.system.inventory.take.length < 3) await this.document.update({ "system.inventory.take": [...this.document.system.inventory.take, { img: item.img, name: item.name, uuid: item.uuid }] }); await this.document.update({
} 'system.inventory.take': [
else if(event.currentTarget.classList.contains('choice-b-section')){ ...this.document.system.inventory.take,
if(this.document.system.inventory.choiceB.length < 2) await this.document.update({ "system.inventory.choiceB": [...this.document.system.inventory.choiceB, { img: item.img, name: item.name, uuid: item.uuid }] }); { img: item.img, name: item.name, uuid: item.uuid }
]
});
} else if (event.currentTarget.classList.contains('choice-b-section')) {
if (this.document.system.inventory.choiceB.length < 2)
await this.document.update({
'system.inventory.choiceB': [
...this.document.system.inventory.choiceB,
{ img: item.img, name: item.name, uuid: item.uuid }
]
});
} }
} }
} }
} }

View file

@ -24,13 +24,12 @@
// return context; // return context;
// } // }
// async _handleAction(action, event, button) { // async _handleAction(action, event, button) {
// switch(action){ // switch(action){
// case 'editAbility': // case 'editAbility':
// this.editAbility(button); // this.editAbility(button);
// break; // break;
// case 'deleteAbility': // case 'deleteAbility':
// this.deleteAbility(event); // this.deleteAbility(event);
// break; // break;
// } // }
@ -59,30 +58,30 @@
import DaggerheartSheet from './daggerheart-sheet.mjs'; import DaggerheartSheet from './daggerheart-sheet.mjs';
const { ItemSheetV2 } = foundry.applications.sheets; const { ItemSheetV2 } = foundry.applications.sheets;
export default class CommunitySheet extends DaggerheartSheet(ItemSheetV2) { export default class CommunitySheet extends DaggerheartSheet(ItemSheetV2) {
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
tag: 'form', tag: 'form',
id: "daggerheart-community", id: 'daggerheart-community',
classes: ["daggerheart", "sheet", "heritage"], classes: ['daggerheart', 'sheet', 'heritage'],
position: { width: 600 }, position: { width: 600 },
actions: { actions: {
editAbility: this.editAbility, editAbility: this.editAbility,
deleteAbility: this.deleteAbility, deleteAbility: this.deleteAbility
}, },
form: { form: {
handler: this.updateForm, handler: this.updateForm,
submitOnChange: true, submitOnChange: true,
closeOnSubmit: false, closeOnSubmit: false
}, },
dragDrop: [{ dragSelector: null, dropSelector: null }], dragDrop: [{ dragSelector: null, dropSelector: null }]
}; };
static PARTS = { static PARTS = {
form: { form: {
id: "feature", id: 'feature',
template: "systems/daggerheart/templates/sheets/community.hbs" template: 'systems/daggerheart/templates/sheets/community.hbs'
} }
} };
async _prepareContext(_options) { async _prepareContext(_options) {
const context = await super._prepareContext(_options); const context = await super._prepareContext(_options);
@ -92,26 +91,33 @@ export default class CommunitySheet extends DaggerheartSheet(ItemSheetV2) {
} }
static async updateForm(event, _, formData) { static async updateForm(event, _, formData) {
await this.document.update(formData.object) await this.document.update(formData.object);
this.render(); this.render();
} }
static async editAbility(_, button){ static async editAbility(_, button) {
const feature = await fromUuid(button.dataset.ability); const feature = await fromUuid(button.dataset.ability);
feature.sheet.render(true); feature.sheet.render(true);
} }
static async deleteAbility(event, button){ static async deleteAbility(event, button) {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
await this.item.update({ "system.abilities": this.item.system.abilities.filter(x => x.uuid !== button.dataset.ability) }) await this.item.update({
'system.abilities': this.item.system.abilities.filter(x => x.uuid !== button.dataset.ability)
});
} }
async _onDrop(event) { async _onDrop(event) {
const data = TextEditor.getDragEventData(event); const data = TextEditor.getDragEventData(event);
const item = await fromUuid(data.uuid); const item = await fromUuid(data.uuid);
if(item.type === 'feature' && item.system.type === SYSTEM.ITEM.featureTypes.community.id) { if (item.type === 'feature' && item.system.type === SYSTEM.ITEM.featureTypes.community.id) {
await this.document.update({ "system.abilities": [...this.document.system.abilities, { img: item.img, name: item.name, uuid: item.uuid }] }); await this.document.update({
'system.abilities': [
...this.document.system.abilities,
{ img: item.img, name: item.name, uuid: item.uuid }
]
});
} }
} }
} }

View file

@ -23,25 +23,25 @@
import DaggerheartSheet from './daggerheart-sheet.mjs'; import DaggerheartSheet from './daggerheart-sheet.mjs';
const { ItemSheetV2 } = foundry.applications.sheets; const { ItemSheetV2 } = foundry.applications.sheets;
export default class ConsumableSheet extends DaggerheartSheet(ItemSheetV2) { export default class ConsumableSheet extends DaggerheartSheet(ItemSheetV2) {
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
tag: 'form', tag: 'form',
id: "daggerheart-consumable", id: 'daggerheart-consumable',
classes: ["daggerheart", "sheet", "consumable"], classes: ['daggerheart', 'sheet', 'consumable'],
position: { width: 480 }, position: { width: 480 },
form: { form: {
handler: this.updateForm, handler: this.updateForm,
submitOnChange: true, submitOnChange: true,
closeOnSubmit: false, closeOnSubmit: false
}, }
}; };
static PARTS = { static PARTS = {
form: { form: {
id: "feature", id: 'feature',
template: "systems/daggerheart/templates/sheets/consumable.hbs" template: 'systems/daggerheart/templates/sheets/consumable.hbs'
} }
} };
async _prepareContext(_options) { async _prepareContext(_options) {
const context = await super._prepareContext(_options); const context = await super._prepareContext(_options);
@ -51,7 +51,7 @@ export default class ConsumableSheet extends DaggerheartSheet(ItemSheetV2) {
} }
static async updateForm(event, _, formData) { static async updateForm(event, _, formData) {
await this.document.update(formData.object) await this.document.update(formData.object);
this.render(); this.render();
} }
} }

View file

@ -1,73 +1,73 @@
const { HandlebarsApplicationMixin } = foundry.applications.api; const { HandlebarsApplicationMixin } = foundry.applications.api;
export default function DhpApplicationMixin(Base) { export default function DhpApplicationMixin(Base) {
return class DhpSheetV2 extends HandlebarsApplicationMixin(Base) { return class DhpSheetV2 extends HandlebarsApplicationMixin(Base) {
constructor(options={}){ constructor(options = {}) {
super(options); super(options);
this._dragDrop = this._createDragDropHandlers(); this._dragDrop = this._createDragDropHandlers();
} }
_attachPartListeners(partId, htmlElement, options) { _attachPartListeners(partId, htmlElement, options) {
super._attachPartListeners(partId, htmlElement, options); super._attachPartListeners(partId, htmlElement, options);
this._dragDrop.forEach(d => d.bind(htmlElement)); this._dragDrop.forEach(d => d.bind(htmlElement));
} }
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
position: { position: {
width: 480, width: 480,
height: "auto" height: 'auto'
}, },
actions: { actions: {
onEditImage: this._onEditImage onEditImage: this._onEditImage
}, },
dragDrop: [], dragDrop: []
};
async _prepareContext(_options, objectPath='document') {
const context = await super._prepareContext(_options);
context.source = this[objectPath].toObject();
context.fields = this[objectPath].schema.fields;
context.systemFields = this[objectPath].system ? this[objectPath].system.schema.fields : {};
return context;
}
static _onEditImage(event, target) {
const attr = target.dataset.edit;
const current = foundry.utils.getProperty(this.document, attr);
const { img } = this.document.constructor.getDefaultArtwork?.(this.document.toObject()) ?? {};
const fp = new FilePicker({
current,
type: "image",
redirectToRoot: img ? [img] : [],
callback: async path => this._updateImage.bind(this)(path),
top: this.position.top + 40,
left: this.position.left + 10
});
return fp.browse();
}
async _updateImage(path){
await this.document.update({ "img": path });
}
_createDragDropHandlers() {
return this.options.dragDrop.map(d => {
// d.permissions = {
// dragstart: this._canDragStart.bind(this),
// drop: this._canDragDrop.bind(this)
// };
d.callbacks = {
// dragstart: this._onDragStart.bind(this),
// dragover: this._onDragOver.bind(this),
drop: this._onDrop.bind(this)
}; };
return new foundry.applications.ux.DragDrop.implementation(d);
});
}
_onDrop(event) {} async _prepareContext(_options, objectPath = 'document') {
} const context = await super._prepareContext(_options);
} context.source = this[objectPath].toObject();
context.fields = this[objectPath].schema.fields;
context.systemFields = this[objectPath].system ? this[objectPath].system.schema.fields : {};
return context;
}
static _onEditImage(event, target) {
const attr = target.dataset.edit;
const current = foundry.utils.getProperty(this.document, attr);
const { img } = this.document.constructor.getDefaultArtwork?.(this.document.toObject()) ?? {};
const fp = new FilePicker({
current,
type: 'image',
redirectToRoot: img ? [img] : [],
callback: async path => this._updateImage.bind(this)(path),
top: this.position.top + 40,
left: this.position.left + 10
});
return fp.browse();
}
async _updateImage(path) {
await this.document.update({ img: path });
}
_createDragDropHandlers() {
return this.options.dragDrop.map(d => {
// d.permissions = {
// dragstart: this._canDragStart.bind(this),
// drop: this._canDragDrop.bind(this)
// };
d.callbacks = {
// dragstart: this._onDragStart.bind(this),
// dragover: this._onDragOver.bind(this),
drop: this._onDrop.bind(this)
};
return new foundry.applications.ux.DragDrop.implementation(d);
});
}
_onDrop(event) {}
};
}

View file

@ -21,7 +21,6 @@
// return context; // return context;
// } // }
// async _handleAction(action, event, button) { // async _handleAction(action, event, button) {
// switch(action){ // switch(action){
// case 'attributeRoll': // case 'attributeRoll':
@ -39,36 +38,36 @@ const { ItemSheetV2 } = foundry.applications.sheets;
export default class DomainCardSheet extends DaggerheartSheet(ItemSheetV2) { export default class DomainCardSheet extends DaggerheartSheet(ItemSheetV2) {
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
tag: 'form', tag: 'form',
id: "daggerheart-domainCard", id: 'daggerheart-domainCard',
classes: ["daggerheart", "sheet", "domain-card"], classes: ['daggerheart', 'sheet', 'domain-card'],
position: { width: 600, height: 600 }, position: { width: 600, height: 600 },
actions: { actions: {
addAction: this.addAction, addAction: this.addAction,
editAction: this.editAction, editAction: this.editAction,
removeAction: this.removeAction, removeAction: this.removeAction
}, },
form: { form: {
handler: this.updateForm, handler: this.updateForm,
submitOnChange: true, submitOnChange: true,
closeOnSubmit: false, closeOnSubmit: false
}, }
}; };
static PARTS = { static PARTS = {
form: { form: {
id: "feature", id: 'feature',
template: "systems/daggerheart/templates/sheets/domainCard.hbs" template: 'systems/daggerheart/templates/sheets/domainCard.hbs'
} }
} };
_getTabs() { _getTabs() {
const tabs = { const tabs = {
general: { active: true, cssClass: '', group: 'primary', id: 'general', icon: null, label: 'General' }, general: { active: true, cssClass: '', group: 'primary', id: 'general', icon: null, label: 'General' },
actions: { active: false, cssClass: '', group: 'primary', id: 'actions', icon: null, label: 'Actions' }, actions: { active: false, cssClass: '', group: 'primary', id: 'actions', icon: null, label: 'Actions' }
} };
for ( const v of Object.values(tabs) ) { for (const v of Object.values(tabs)) {
v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active; v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active;
v.cssClass = v.active ? "active" : ""; v.cssClass = v.active ? 'active' : '';
} }
return tabs; return tabs;
@ -83,28 +82,37 @@ export default class DomainCardSheet extends DaggerheartSheet(ItemSheetV2) {
} }
static async updateForm(event, _, formData) { static async updateForm(event, _, formData) {
await this.document.update(formData.object) await this.document.update(formData.object);
this.render(); this.render();
} }
static async addAction(){ static async addAction() {
const actionIndexes = this.document.system.actions.map(x => x.id.split('-')[2]).sort((a, b) => a-b); const actionIndexes = this.document.system.actions.map(x => x.id.split('-')[2]).sort((a, b) => a - b);
const action = await new DaggerheartAction({ const action = await new DaggerheartAction(
id: `${this.document.id}-Action-${actionIndexes.length > 0 ? actionIndexes[0]+1 : 1}`, {
}, { id: `${this.document.id}-Action-${actionIndexes.length > 0 ? actionIndexes[0] + 1 : 1}`
parent: this.document, },
}); {
await this.document.update({ "system.actions": [...this.document.system.actions, action] }); parent: this.document
await (new DaggerheartActionConfig(this.document.system.actions[this.document.system.actions.length-1])).render(true); }
);
await this.document.update({ 'system.actions': [...this.document.system.actions, action] });
await new DaggerheartActionConfig(this.document.system.actions[this.document.system.actions.length - 1]).render(
true
);
} }
static async editAction(_, button){ static async editAction(_, button) {
const action = this.document.system.actions[button.dataset.index]; const action = this.document.system.actions[button.dataset.index];
await (new DaggerheartActionConfig(action)).render(true); await new DaggerheartActionConfig(action).render(true);
} }
static async removeAction(event, button){ static async removeAction(event, button) {
event.stopPropagation(); event.stopPropagation();
await this.document.update({ "system.actions": this.document.system.actions.filter((_, index) => index !== Number.parseInt(button.dataset.index)) }); await this.document.update({
'system.actions': this.document.system.actions.filter(
(_, index) => index !== Number.parseInt(button.dataset.index)
)
});
} }
} }

View file

@ -1,9 +1,8 @@
import DaggerheartSheet from "./daggerheart-sheet.mjs"; import DaggerheartSheet from './daggerheart-sheet.mjs';
const { DocumentSheetV2 } = foundry.applications.api; const { DocumentSheetV2 } = foundry.applications.api;
export default class DhpEnvironment extends DaggerheartSheet(DocumentSheetV2) { export default class DhpEnvironment extends DaggerheartSheet(DocumentSheetV2) {
constructor(options) {
constructor(options){
super(options); super(options);
this.editMode = false; this.editMode = false;
@ -11,10 +10,10 @@ export default class DhpEnvironment extends DaggerheartSheet(DocumentSheetV2) {
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
tag: 'form', tag: 'form',
classes: ["daggerheart", "sheet", "adversary", "environment"], classes: ['daggerheart', 'sheet', 'adversary', 'environment'],
position: { position: {
width: 600, width: 600,
height: "auto" height: 'auto'
}, },
actions: { actions: {
toggleSlider: this.toggleSlider, toggleSlider: this.toggleSlider,
@ -23,22 +22,22 @@ export default class DhpEnvironment extends DaggerheartSheet(DocumentSheetV2) {
removeFeature: this.removeFeature, removeFeature: this.removeFeature,
addTone: this.addTone, addTone: this.addTone,
removeTone: this.removeTone, removeTone: this.removeTone,
useFeature: this.useFeature, useFeature: this.useFeature
}, },
form: { form: {
handler: this._updateForm, handler: this._updateForm,
closeOnSubmit: false, closeOnSubmit: false,
submitOnChange: true, submitOnChange: true
} }
}; };
/** @override */ /** @override */
static PARTS = { static PARTS = {
form: { form: {
id: "form", id: 'form',
template: "systems/daggerheart/templates/sheets/environment.hbs" template: 'systems/daggerheart/templates/sheets/environment.hbs'
} }
} };
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -49,81 +48,87 @@ export default class DhpEnvironment extends DaggerheartSheet(DocumentSheetV2) {
async _prepareContext(_options) { async _prepareContext(_options) {
return { return {
title: `${this.document.name} - ${game.i18n.localize(SYSTEM.ACTOR.adversaryTypes[this.document.system.type].name)}`, title: `${this.document.name} - ${game.i18n.localize(SYSTEM.ACTOR.adversaryTypes[this.document.system.type].name)}`,
user: this.document, user: this.document,
source: this.document.toObject(), source: this.document.toObject(),
fields: this.document.schema.fields, fields: this.document.schema.fields,
data: { data: {
type: game.i18n.localize(SYSTEM.ACTOR.adversaryTypes[this.document.system.type].name), type: game.i18n.localize(SYSTEM.ACTOR.adversaryTypes[this.document.system.type].name),
features: this.document.items.reduce((acc, x) => { features: this.document.items.reduce((acc, x) => {
if(x.type === 'feature'){ if (x.type === 'feature') {
const feature = x.toObject(); const feature = x.toObject();
acc.push({ acc.push({
...feature, ...feature,
system: { system: {
...feature.system, ...feature.system,
actionType: game.i18n.localize(SYSTEM.ITEM.actionTypes[feature.system.actionType].name) actionType: game.i18n.localize(SYSTEM.ITEM.actionTypes[feature.system.actionType].name)
}, },
uuid: x.uuid uuid: x.uuid
}); });
} }
return acc; return acc;
}, []), }, [])
}, },
editMode: this.editMode, editMode: this.editMode,
config: SYSTEM, config: SYSTEM
} };
} }
static async _updateForm(event, _, formData) { static async _updateForm(event, _, formData) {
await this.document.update(formData.object) await this.document.update(formData.object);
this.render(); this.render();
} }
static toggleSlider(){ static toggleSlider() {
this.editMode = !this.editMode; this.editMode = !this.editMode;
this.render(); this.render();
} }
static async viewFeature(_, button){ static async viewFeature(_, button) {
const move = await fromUuid(button.dataset.feature); const move = await fromUuid(button.dataset.feature);
move.sheet.render(true); move.sheet.render(true);
} }
static async addFeature(){ static async addFeature() {
const result = await this.document.createEmbeddedDocuments("Item", [{ const result = await this.document.createEmbeddedDocuments('Item', [
name: game.i18n.localize('DAGGERHEART.Sheets.Environment.NewFeature'), {
type: 'feature', name: game.i18n.localize('DAGGERHEART.Sheets.Environment.NewFeature'),
}]); type: 'feature'
}
]);
await result[0].sheet.render(true); await result[0].sheet.render(true);
} }
static async removeFeature(_, button){ static async removeFeature(_, button) {
await this.document.items.find(x => x.uuid === button.dataset.feature).delete(); await this.document.items.find(x => x.uuid === button.dataset.feature).delete();
} }
static async addTone(){ static async addTone() {
await this.document.update({ "system.toneAndFeel": [...this.document.system.toneAndFeel, ''] }); await this.document.update({ 'system.toneAndFeel': [...this.document.system.toneAndFeel, ''] });
} }
static async removeTone(button){ static async removeTone(button) {
await this.document.update({ "system.toneAndFeel": this.document.system.toneAndFeel.filter((_, index) => index !== Number.parseInt(button.dataset.tone) )}); await this.document.update({
'system.toneAndFeel': this.document.system.toneAndFeel.filter(
(_, index) => index !== Number.parseInt(button.dataset.tone)
)
});
} }
static async useFeature(_, button){ static async useFeature(_, button) {
const item = this.document.items.find(x => x.uuid === button.dataset.feature); const item = this.document.items.find(x => x.uuid === button.dataset.feature);
const cls = getDocumentClass("ChatMessage"); const cls = getDocumentClass('ChatMessage');
const msg = new cls({ const msg = new cls({
user: game.user.id, user: game.user.id,
content: await renderTemplate("systems/daggerheart/templates/chat/ability-use.hbs", { content: await renderTemplate('systems/daggerheart/templates/chat/ability-use.hbs', {
title: game.i18n.format("DAGGERHEART.Chat.EnvironmentTitle", { actionType: button.dataset.actionType }), title: game.i18n.format('DAGGERHEART.Chat.EnvironmentTitle', { actionType: button.dataset.actionType }),
card: { name: item.name, img: item.img, description: item.system.description }, card: { name: item.name, img: item.img, description: item.system.description }
}), })
}); });
cls.create(msg.toObject()); cls.create(msg.toObject());
} }
} }

View file

@ -4,47 +4,47 @@ import DaggerheartSheet from './daggerheart-sheet.mjs';
const { ItemSheetV2 } = foundry.applications.sheets; const { ItemSheetV2 } = foundry.applications.sheets;
export default class FeatureSheet extends DaggerheartSheet(ItemSheetV2) { export default class FeatureSheet extends DaggerheartSheet(ItemSheetV2) {
constructor(options={}){ constructor(options = {}) {
super(options); super(options);
this.selectedEffectType = null; this.selectedEffectType = null;
} }
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
tag: 'form', tag: 'form',
id: "daggerheart-feature", id: 'daggerheart-feature',
classes: ["daggerheart", "sheet", "feature"], classes: ['daggerheart', 'sheet', 'feature'],
position: { width: 600, height: 600 }, position: { width: 600, height: 600 },
actions: { actions: {
addEffect: this.addEffect, addEffect: this.addEffect,
removeEffect: this.removeEffect, removeEffect: this.removeEffect,
addAction: this.addAction, addAction: this.addAction,
editAction: this.editAction, editAction: this.editAction,
removeAction: this.removeAction, removeAction: this.removeAction
}, },
form: { form: {
handler: this.updateForm, handler: this.updateForm,
submitOnChange: true, submitOnChange: true,
closeOnSubmit: false, closeOnSubmit: false
}, }
}; };
static PARTS = { static PARTS = {
form: { form: {
id: "feature", id: 'feature',
template: "systems/daggerheart/templates/sheets/feature.hbs" template: 'systems/daggerheart/templates/sheets/feature.hbs'
} }
} };
_getTabs() { _getTabs() {
const tabs = { const tabs = {
features: { active: true, cssClass: '', group: 'primary', id: 'features', icon: null, label: 'Features' }, features: { active: true, cssClass: '', group: 'primary', id: 'features', icon: null, label: 'Features' },
effects: { active: false, cssClass: '', group: 'primary', id: 'effects', icon: null, label: 'Effects' }, effects: { active: false, cssClass: '', group: 'primary', id: 'effects', icon: null, label: 'Effects' },
actions: { active: false, cssClass: '', group: 'primary', id: 'actions', icon: null, label: 'Actions' }, actions: { active: false, cssClass: '', group: 'primary', id: 'actions', icon: null, label: 'Actions' }
} };
for ( const v of Object.values(tabs) ) { for (const v of Object.values(tabs)) {
v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active; v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active;
v.cssClass = v.active ? "active" : ""; v.cssClass = v.active ? 'active' : '';
} }
return tabs; return tabs;
@ -52,14 +52,13 @@ export default class FeatureSheet extends DaggerheartSheet(ItemSheetV2) {
_attachPartListeners(partId, htmlElement, options) { _attachPartListeners(partId, htmlElement, options) {
super._attachPartListeners(partId, htmlElement, options); super._attachPartListeners(partId, htmlElement, options);
$(htmlElement).find(".effect-select").on("change", this.effectSelect.bind(this)); $(htmlElement).find('.effect-select').on('change', this.effectSelect.bind(this));
} }
async _prepareContext(_options) { async _prepareContext(_options) {
const context = await super._prepareContext(_options); const context = await super._prepareContext(_options);
context.document = this.document; context.document = this.document;
context.tabs = this._getTabs(), (context.tabs = this._getTabs()), (context.generalConfig = SYSTEM.GENERAL);
context.generalConfig = SYSTEM.GENERAL;
context.itemConfig = SYSTEM.ITEM; context.itemConfig = SYSTEM.ITEM;
context.properties = SYSTEM.ACTOR.featureProperties; context.properties = SYSTEM.ACTOR.featureProperties;
context.dice = SYSTEM.GENERAL.diceTypes; context.dice = SYSTEM.GENERAL.diceTypes;
@ -70,47 +69,53 @@ export default class FeatureSheet extends DaggerheartSheet(ItemSheetV2) {
} }
static async updateForm(event, _, formData) { static async updateForm(event, _, formData) {
await this.document.update(formData.object) await this.document.update(formData.object);
this.render(); this.render();
} }
effectSelect(event){ effectSelect(event) {
this.selectedEffectType = event.currentTarget.value; this.selectedEffectType = event.currentTarget.value;
this.render(true); this.render(true);
} }
static async addEffect(){ static async addEffect() {
if(!this.selectedEffectType) return; if (!this.selectedEffectType) return;
const { id, name, ...rest } = SYSTEM.EFFECTS.effectTypes[this.selectedEffectType]; const { id, name, ...rest } = SYSTEM.EFFECTS.effectTypes[this.selectedEffectType];
const update = { const update = {
[foundry.utils.randomID()]: { [foundry.utils.randomID()]: {
type: this.selectedEffectType, type: this.selectedEffectType,
value: '', value: '',
...rest ...rest
} }
}; };
await this.item.update({ "system.effects": update }); await this.item.update({ 'system.effects': update });
} }
static async removeEffect(_, button){ static async removeEffect(_, button) {
const path = `system.effects.-=${button.dataset.effect}`; const path = `system.effects.-=${button.dataset.effect}`;
await this.item.update({ [path]: null }); await this.item.update({ [path]: null });
} }
static async addAction(){ static async addAction() {
const action = await new DaggerheartAction({}, {parent: this.document}); const action = await new DaggerheartAction({}, { parent: this.document });
await this.document.update({ "system.actions": [...this.document.system.actions, action] }); await this.document.update({ 'system.actions': [...this.document.system.actions, action] });
await (new DaggerheartActionConfig(this.document.system.actions[this.document.system.actions.length-1])).render(true); await new DaggerheartActionConfig(this.document.system.actions[this.document.system.actions.length - 1]).render(
true
);
} }
static async editAction(_, button){ static async editAction(_, button) {
const action = this.document.system.actions[button.dataset.index]; const action = this.document.system.actions[button.dataset.index];
await (new DaggerheartActionConfig(action)).render(true); await new DaggerheartActionConfig(action).render(true);
} }
static async removeAction(event, button){ static async removeAction(event, button) {
event.stopPropagation(); event.stopPropagation();
await this.document.update({ "system.actions": this.document.system.actions.filter((_, index) => index !== Number.parseInt(button.dataset.index)) }); await this.document.update({
'system.actions': this.document.system.actions.filter(
(_, index) => index !== Number.parseInt(button.dataset.index)
)
});
} }
} }

View file

@ -26,22 +26,22 @@ const { ItemSheetV2 } = foundry.applications.sheets;
export default class MiscellaneousSheet extends DaggerheartSheet(ItemSheetV2) { export default class MiscellaneousSheet extends DaggerheartSheet(ItemSheetV2) {
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
tag: 'form', tag: 'form',
id: "daggerheart-miscellaneous", id: 'daggerheart-miscellaneous',
classes: ["daggerheart", "sheet", "miscellaneous"], classes: ['daggerheart', 'sheet', 'miscellaneous'],
position: { width: 400 }, position: { width: 400 },
form: { form: {
handler: this.updateForm, handler: this.updateForm,
submitOnChange: true, submitOnChange: true,
closeOnSubmit: false, closeOnSubmit: false
}, }
}; };
static PARTS = { static PARTS = {
form: { form: {
id: "feature", id: 'feature',
template: "systems/daggerheart/templates/sheets/miscellaneous.hbs" template: 'systems/daggerheart/templates/sheets/miscellaneous.hbs'
} }
} };
async _prepareContext(_options) { async _prepareContext(_options) {
const context = await super._prepareContext(_options); const context = await super._prepareContext(_options);
@ -51,7 +51,7 @@ export default class MiscellaneousSheet extends DaggerheartSheet(ItemSheetV2) {
} }
static async updateForm(event, _, formData) { static async updateForm(event, _, formData) {
await this.document.update(formData.object) await this.document.update(formData.object);
this.render(); this.render();
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -51,7 +51,7 @@
// const feature = event.currentTarget.dataset.feature; // const feature = event.currentTarget.dataset.feature;
// const newAbilities = this.item.system[`${feature}Feature`].abilities.filter(x => x.uuid !== event.currentTarget.dataset.ability); // const newAbilities = this.item.system[`${feature}Feature`].abilities.filter(x => x.uuid !== event.currentTarget.dataset.ability);
// const path = `system.${feature}Feature.abilities`; // const path = `system.${feature}Feature.abilities`;
// await this.item.update({ [path]: newAbilities }); // await this.item.update({ [path]: newAbilities });
// } // }
@ -79,46 +79,74 @@ const { ItemSheetV2 } = foundry.applications.sheets;
export default class SubclassSheet extends DaggerheartSheet(ItemSheetV2) { export default class SubclassSheet extends DaggerheartSheet(ItemSheetV2) {
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
tag: 'form', tag: 'form',
id: "daggerheart-subclass", id: 'daggerheart-subclass',
classes: ["daggerheart", "sheet", "subclass"], classes: ['daggerheart', 'sheet', 'subclass'],
position: { width: 600 }, position: { width: 600 },
actions: { actions: {
editAbility: this.editAbility, editAbility: this.editAbility,
deleteFeatureAbility: this.deleteFeatureAbility, deleteFeatureAbility: this.deleteFeatureAbility
}, },
form: { form: {
handler: this.updateForm, handler: this.updateForm,
submitOnChange: true, submitOnChange: true,
closeOnSubmit: false, closeOnSubmit: false
}, },
dragDrop: [ dragDrop: [
{ dragSelector: null, dropSelector: '.foundation-tab' }, { dragSelector: null, dropSelector: '.foundation-tab' },
{ dragSelector: null, dropSelector: '.specialization-tab' }, { dragSelector: null, dropSelector: '.specialization-tab' },
{ dragSelector: null, dropSelector: '.mastery-tab' } { dragSelector: null, dropSelector: '.mastery-tab' }
], ]
}; };
_getTabs() { _getTabs() {
const tabs = { const tabs = {
general: { active: true, cssClass: '', group: 'primary', id: 'general', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.Subclass.Tabs.General') }, general: {
foundation: { active: false, cssClass: '', group: 'primary', id: 'foundation', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.Subclass.Tabs.Foundation') }, active: true,
specialization: { active: false, cssClass: '', group: 'primary', id: 'specialization', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.Subclass.Tabs.Specialization') }, cssClass: '',
mastery: { active: false, cssClass: '', group: 'primary', id: 'mastery', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.Subclass.Tabs.Mastery') }, group: 'primary',
} id: 'general',
for ( const v of Object.values(tabs) ) { icon: null,
label: game.i18n.localize('DAGGERHEART.Sheets.Subclass.Tabs.General')
},
foundation: {
active: false,
cssClass: '',
group: 'primary',
id: 'foundation',
icon: null,
label: game.i18n.localize('DAGGERHEART.Sheets.Subclass.Tabs.Foundation')
},
specialization: {
active: false,
cssClass: '',
group: 'primary',
id: 'specialization',
icon: null,
label: game.i18n.localize('DAGGERHEART.Sheets.Subclass.Tabs.Specialization')
},
mastery: {
active: false,
cssClass: '',
group: 'primary',
id: 'mastery',
icon: null,
label: game.i18n.localize('DAGGERHEART.Sheets.Subclass.Tabs.Mastery')
}
};
for (const v of Object.values(tabs)) {
v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active; v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active;
v.cssClass = v.active ? "active" : ""; v.cssClass = v.active ? 'active' : '';
} }
return tabs; return tabs;
} }
static PARTS = { static PARTS = {
form: { form: {
id: "feature", id: 'feature',
template: "systems/daggerheart/templates/sheets/subclass.hbs" template: 'systems/daggerheart/templates/sheets/subclass.hbs'
} }
} };
async _prepareContext(_options) { async _prepareContext(_options) {
const context = await super._prepareContext(_options); const context = await super._prepareContext(_options);
@ -130,39 +158,51 @@ export default class SubclassSheet extends DaggerheartSheet(ItemSheetV2) {
} }
static async updateForm(event, _, formData) { static async updateForm(event, _, formData) {
await this.document.update(formData.object) await this.document.update(formData.object);
this.render(); this.render();
} }
static async editAbility(_, button){ static async editAbility(_, button) {
const feature = await fromUuid(button.dataset.ability); const feature = await fromUuid(button.dataset.ability);
feature.sheet.render(true); feature.sheet.render(true);
} }
static async deleteFeatureAbility(event, button){ static async deleteFeatureAbility(event, button) {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
const feature = button.dataset.feature; const feature = button.dataset.feature;
const newAbilities = this.document.system[`${feature}Feature`].abilities.filter(x => x.uuid !== button.dataset.ability); const newAbilities = this.document.system[`${feature}Feature`].abilities.filter(
x => x.uuid !== button.dataset.ability
);
const path = `system.${feature}Feature.abilities`; const path = `system.${feature}Feature.abilities`;
await this.document.update({ [path]: newAbilities }); await this.document.update({ [path]: newAbilities });
} }
async _onDrop(event) { async _onDrop(event) {
const data = TextEditor.getDragEventData(event); const data = TextEditor.getDragEventData(event);
const item = await fromUuid(data.uuid); const item = await fromUuid(data.uuid);
if(item.type === 'feature' && item.system.type === SYSTEM.ITEM.featureTypes.subclass.id) { if (item.type === 'feature' && item.system.type === SYSTEM.ITEM.featureTypes.subclass.id) {
if(event.currentTarget.classList.contains('foundation-tab')){ if (event.currentTarget.classList.contains('foundation-tab')) {
await this.document.update({ "system.foundationFeature.abilities": [...this.document.system.foundationFeature.abilities, item.system] }); await this.document.update({
} 'system.foundationFeature.abilities': [
else if(event.currentTarget.classList.contains('specialization-tab')){ ...this.document.system.foundationFeature.abilities,
await this.document.update({ "system.specializationFeature.abilities": [...this.document.system.specializationFeature.abilities, data.system] }); item.system
} ]
else if(event.currentTarget.classList.contains('mastery-tab')){ });
await this.document.update({ "system.masteryFeature.abilities": [...this.document.system.masteryFeature.abilities, data.system] }); } else if (event.currentTarget.classList.contains('specialization-tab')) {
await this.document.update({
'system.specializationFeature.abilities': [
...this.document.system.specializationFeature.abilities,
data.system
]
});
} else if (event.currentTarget.classList.contains('mastery-tab')) {
await this.document.update({
'system.masteryFeature.abilities': [...this.document.system.masteryFeature.abilities, data.system]
});
} }
} }
} }
} }

View file

@ -20,7 +20,6 @@
// return context; // return context;
// } // }
// async _handleAction(action, event, button) { // async _handleAction(action, event, button) {
// switch(action){ // switch(action){
// } // }
@ -30,25 +29,25 @@
import DaggerheartSheet from './daggerheart-sheet.mjs'; import DaggerheartSheet from './daggerheart-sheet.mjs';
const { ItemSheetV2 } = foundry.applications.sheets; const { ItemSheetV2 } = foundry.applications.sheets;
export default class WeaponSheet extends DaggerheartSheet(ItemSheetV2) { export default class WeaponSheet extends DaggerheartSheet(ItemSheetV2) {
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
tag: 'form', tag: 'form',
id: "daggerheart-weapon", id: 'daggerheart-weapon',
classes: ["daggerheart", "sheet", "weapon"], classes: ['daggerheart', 'sheet', 'weapon'],
position: { width: 400 }, position: { width: 400 },
form: { form: {
handler: this.updateForm, handler: this.updateForm,
submitOnChange: true, submitOnChange: true,
closeOnSubmit: false, closeOnSubmit: false
}, }
}; };
static PARTS = { static PARTS = {
form: { form: {
id: "feature", id: 'feature',
template: "systems/daggerheart/templates/sheets/weapon.hbs" template: 'systems/daggerheart/templates/sheets/weapon.hbs'
} }
} };
async _prepareContext(_options) { async _prepareContext(_options) {
const context = await super._prepareContext(_options); const context = await super._prepareContext(_options);
@ -59,7 +58,7 @@ export default class WeaponSheet extends DaggerheartSheet(ItemSheetV2) {
} }
static async updateForm(event, _, formData) { static async updateForm(event, _, formData) {
await this.document.update(formData.object) await this.document.update(formData.object);
this.render(); this.render();
} }
} }

View file

@ -1,17 +1,17 @@
export const actionTypes = { export const actionTypes = {
damage: { damage: {
id: "damage", id: 'damage',
name: "DAGGERHEART.Effects.Types.Health.Name" name: 'DAGGERHEART.Effects.Types.Health.Name'
}, }
} };
export const targetTypes = { export const targetTypes = {
self: { self: {
id: 'self', id: 'self',
label: 'Self', label: 'Self'
}, },
other: { other: {
id: 'other', id: 'other',
label: 'Other', label: 'Other'
}, }
} };

View file

@ -1,164 +1,191 @@
export const abilities = { export const abilities = {
agility: { agility: {
label: "DAGGERHEART.Abilities.Agility.Name", label: 'DAGGERHEART.Abilities.Agility.Name',
verbs: ["DAGGERHEART.Abilities.Agility.Verb.Sprint", "DAGGERHEART.Abilities.Agility.Verb.Leap", "DAGGERHEART.Abilities.Agility.Verb.Maneuver"], verbs: [
'DAGGERHEART.Abilities.Agility.Verb.Sprint',
'DAGGERHEART.Abilities.Agility.Verb.Leap',
'DAGGERHEART.Abilities.Agility.Verb.Maneuver'
]
}, },
strength: { strength: {
label: "DAGGERHEART.Abilities.Strength.Name", label: 'DAGGERHEART.Abilities.Strength.Name',
verbs: ["DAGGERHEART.Abilities.Strength.Verb.Lift", "DAGGERHEART.Abilities.Strength.Verb.Smash", "DAGGERHEART.Abilities.Strength.Verb.Grapple"], verbs: [
'DAGGERHEART.Abilities.Strength.Verb.Lift',
'DAGGERHEART.Abilities.Strength.Verb.Smash',
'DAGGERHEART.Abilities.Strength.Verb.Grapple'
]
}, },
finesse: { finesse: {
label: "DAGGERHEART.Abilities.Finesse.Name", label: 'DAGGERHEART.Abilities.Finesse.Name',
verbs: ["DAGGERHEART.Abilities.Finesse.Verb.Control", "DAGGERHEART.Abilities.Finesse.Verb.Hide", "DAGGERHEART.Abilities.Finesse.Verb.Tinker"], verbs: [
'DAGGERHEART.Abilities.Finesse.Verb.Control',
'DAGGERHEART.Abilities.Finesse.Verb.Hide',
'DAGGERHEART.Abilities.Finesse.Verb.Tinker'
]
}, },
instinct: { instinct: {
label: "DAGGERHEART.Abilities.Instinct.Name", label: 'DAGGERHEART.Abilities.Instinct.Name',
verbs: ["DAGGERHEART.Abilities.Instinct.Verb.Perceive", "DAGGERHEART.Abilities.Instinct.Verb.Sense", "DAGGERHEART.Abilities.Instinct.Verb.Navigate"], verbs: [
'DAGGERHEART.Abilities.Instinct.Verb.Perceive',
'DAGGERHEART.Abilities.Instinct.Verb.Sense',
'DAGGERHEART.Abilities.Instinct.Verb.Navigate'
]
}, },
presence: { presence: {
label: "DAGGERHEART.Abilities.Presence.Name", label: 'DAGGERHEART.Abilities.Presence.Name',
verbs: ["DAGGERHEART.Abilities.Presence.Verb.Charm", "DAGGERHEART.Abilities.Presence.Verb.Perform", "DAGGERHEART.Abilities.Presence.Verb.Deceive"], verbs: [
'DAGGERHEART.Abilities.Presence.Verb.Charm',
'DAGGERHEART.Abilities.Presence.Verb.Perform',
'DAGGERHEART.Abilities.Presence.Verb.Deceive'
]
}, },
knowledge: { knowledge: {
label: "DAGGERHEART.Abilities.Knowledge.Name", label: 'DAGGERHEART.Abilities.Knowledge.Name',
verbs: ["DAGGERHEART.Abilities.Knowledge.Verb.Recall", "DAGGERHEART.Abilities.Knowledge.Verb.Analyze", "DAGGERHEART.Abilities.Knowledge.Verb.Comprehend"], verbs: [
}, 'DAGGERHEART.Abilities.Knowledge.Verb.Recall',
'DAGGERHEART.Abilities.Knowledge.Verb.Analyze',
'DAGGERHEART.Abilities.Knowledge.Verb.Comprehend'
]
}
}; };
export const featureProperties = { export const featureProperties = {
agility: { agility: {
name: "DAGGERHEART.Abilities.Agility.Name", name: 'DAGGERHEART.Abilities.Agility.Name',
path: actor => actor.system.attributes.agility.data.value, path: actor => actor.system.attributes.agility.data.value
}, },
strength: { strength: {
name: "DAGGERHEART.Abilities.Strength.Name", name: 'DAGGERHEART.Abilities.Strength.Name',
path: actor => actor.system.attributes.strength.data.value, path: actor => actor.system.attributes.strength.data.value
}, },
finesse: { finesse: {
name: "DAGGERHEART.Abilities.Finesse.Name", name: 'DAGGERHEART.Abilities.Finesse.Name',
path: actor => actor.system.attributes.finesse.data.value, path: actor => actor.system.attributes.finesse.data.value
}, },
instinct: { instinct: {
name: "DAGGERHEART.Abilities.Instinct.Name", name: 'DAGGERHEART.Abilities.Instinct.Name',
path: actor => actor.system.attributes.instinct.data.value, path: actor => actor.system.attributes.instinct.data.value
}, },
presence: { presence: {
name: "DAGGERHEART.Abilities.Presence.Name", name: 'DAGGERHEART.Abilities.Presence.Name',
path: actor => actor.system.attributes.presence.data.value, path: actor => actor.system.attributes.presence.data.value
}, },
knowledge: { knowledge: {
name: "DAGGERHEART.Abilities.Knowledge.Name", name: 'DAGGERHEART.Abilities.Knowledge.Name',
path: actor => actor.system.attributes.knowledge.data.value, path: actor => actor.system.attributes.knowledge.data.value
}, },
spellcastingTrait: { spellcastingTrait: {
name: "DAGGERHEART.FeatureProperty.SpellcastingTrait", name: 'DAGGERHEART.FeatureProperty.SpellcastingTrait',
path: actor => actor.system.attributes[actor.system.subclass.system.spellcastingTrait].data.value, path: actor => actor.system.attributes[actor.system.subclass.system.spellcastingTrait].data.value
}, }
} };
export const adversaryTypes = { export const adversaryTypes = {
bruiser: { bruiser: {
name: "DAGGERHEART.Adversary.Bruiser.Name", name: 'DAGGERHEART.Adversary.Bruiser.Name',
description: "DAGGERHEART.Adversary.Bruiser.Description" description: 'DAGGERHEART.Adversary.Bruiser.Description'
}, },
horde: { horde: {
name: "DAGGERHEART.Adversary.Horde.Name", name: 'DAGGERHEART.Adversary.Horde.Name',
description: "DAGGERHEART.Adversary.Horde.Description" description: 'DAGGERHEART.Adversary.Horde.Description'
}, },
leader: { leader: {
name: "DAGGERHEART.Adversary.Leader.Name", name: 'DAGGERHEART.Adversary.Leader.Name',
description: "DAGGERHEART.Adversary.Leader.Description" description: 'DAGGERHEART.Adversary.Leader.Description'
}, },
minion: { minion: {
name: "DAGGERHEART.Adversary.Minion.Name", name: 'DAGGERHEART.Adversary.Minion.Name',
description: "DAGGERHEART.Adversary.Minion.Description" description: 'DAGGERHEART.Adversary.Minion.Description'
}, },
ranged: { ranged: {
name: "DAGGERHEART.Adversary.Ranged.Name", name: 'DAGGERHEART.Adversary.Ranged.Name',
description: "DAGGERHEART.Adversary.Ranged.Description" description: 'DAGGERHEART.Adversary.Ranged.Description'
}, },
skulker: { skulker: {
name: "DAGGERHEART.Adversary.Skulker.Name", name: 'DAGGERHEART.Adversary.Skulker.Name',
description: "DAGGERHEART.Adversary.Skulker.Description" description: 'DAGGERHEART.Adversary.Skulker.Description'
}, },
social: { social: {
name: "DAGGERHEART.Adversary.Social.Name", name: 'DAGGERHEART.Adversary.Social.Name',
description: "DAGGERHEART.Adversary.Social.Description" description: 'DAGGERHEART.Adversary.Social.Description'
}, },
solo: { solo: {
name: "DAGGERHEART.Adversary.Solo.Name", name: 'DAGGERHEART.Adversary.Solo.Name',
description: "DAGGERHEART.Adversary.Solo.Description" description: 'DAGGERHEART.Adversary.Solo.Description'
}, },
standard: { standard: {
name: "DAGGERHEART.Adversary.Standard.Name", name: 'DAGGERHEART.Adversary.Standard.Name',
description: "DAGGERHEART.Adversary.Standard.Description" description: 'DAGGERHEART.Adversary.Standard.Description'
}, },
support: { support: {
name: "DAGGERHEART.Adversary.Support.Name", name: 'DAGGERHEART.Adversary.Support.Name',
description: "DAGGERHEART.Adversary.Support.Description" description: 'DAGGERHEART.Adversary.Support.Description'
}, }
}; };
export const adversaryTraits = { export const adversaryTraits = {
relentless: { relentless: {
name: "DAGGERHEART.Adversary.Trait..Name", name: 'DAGGERHEART.Adversary.Trait..Name',
description: "DAGGERHEART.Adversary.Trait..Description", description: 'DAGGERHEART.Adversary.Trait..Description',
tip: "DAGGERHEART.Adversary.Trait..Tip", tip: 'DAGGERHEART.Adversary.Trait..Tip'
}, },
slow: { slow: {
name: "DAGGERHEART.Adversary.Trait..Name", name: 'DAGGERHEART.Adversary.Trait..Name',
description: "DAGGERHEART.Adversary.Trait..Description", description: 'DAGGERHEART.Adversary.Trait..Description',
tip: "DAGGERHEART.Adversary.Trait..Tip", tip: 'DAGGERHEART.Adversary.Trait..Tip'
}, },
minion: { minion: {
name: "DAGGERHEART.Adversary.Trait..Name", name: 'DAGGERHEART.Adversary.Trait..Name',
description: "DAGGERHEART.Adversary.Trait..Description", description: 'DAGGERHEART.Adversary.Trait..Description',
tip: "DAGGERHEART.Adversary.Trait..Tip", tip: 'DAGGERHEART.Adversary.Trait..Tip'
}, }
}; };
export const levelChoices = { export const levelChoices = {
attributes: { attributes: {
name: 'attributes', name: 'attributes',
title: '', title: '',
choices: [], choices: []
}, },
hitPointSlots: { hitPointSlots: {
name: 'hitPointSlots', name: 'hitPointSlots',
title: '', title: '',
choices: [], choices: []
}, },
stressSlots: { stressSlots: {
name: 'stressSlots', name: 'stressSlots',
title: '', title: '',
choices: [], choices: []
}, },
experiences: { experiences: {
name: 'experiences', name: 'experiences',
title: '', title: '',
choices: 'system.experiences', choices: 'system.experiences',
nrChoices: 2, nrChoices: 2
}, },
proficiency: { proficiency: {
name: 'proficiency', name: 'proficiency',
title: '', title: '',
choices: [], choices: []
}, },
armorOrEvasionSlot: { armorOrEvasionSlot: {
name: 'armorOrEvasionSlot', name: 'armorOrEvasionSlot',
title: 'Permanently add one Armor Slot or take +1 to your Evasion', title: 'Permanently add one Armor Slot or take +1 to your Evasion',
choices: [{ name: 'Armor Marks +1', path: 'armor' }, { name: 'Evasion +1', path: 'evasion' }], choices: [
nrChoices: 1, { name: 'Armor Marks +1', path: 'armor' },
{ name: 'Evasion +1', path: 'evasion' }
],
nrChoices: 1
}, },
majorDamageThreshold2: { majorDamageThreshold2: {
name: 'majorDamageThreshold2', name: 'majorDamageThreshold2',
title: '', title: '',
choices: [], choices: []
}, },
severeDamageThreshold2: { severeDamageThreshold2: {
name: 'severeDamageThreshold2', name: 'severeDamageThreshold2',
title: '', title: '',
choices: [], choices: []
}, },
// minorDamageThreshold2: { // minorDamageThreshold2: {
// name: 'minorDamageThreshold2', // name: 'minorDamageThreshold2',
@ -168,7 +195,7 @@ export const levelChoices = {
severeDamageThreshold3: { severeDamageThreshold3: {
name: 'severeDamageThreshold3', name: 'severeDamageThreshold3',
title: '', title: '',
choices: [], choices: []
}, },
// major2OrSevere4DamageThreshold: { // major2OrSevere4DamageThreshold: {
// name: 'major2OrSevere4DamageThreshold', // name: 'major2OrSevere4DamageThreshold',
@ -185,7 +212,7 @@ export const levelChoices = {
severeDamageThreshold4: { severeDamageThreshold4: {
name: 'severeDamageThreshold4', name: 'severeDamageThreshold4',
title: '', title: '',
choices: [], choices: []
}, },
// majorDamageThreshold1: { // majorDamageThreshold1: {
// name: 'majorDamageThreshold2', // name: 'majorDamageThreshold2',
@ -195,161 +222,161 @@ export const levelChoices = {
subclass: { subclass: {
name: 'subclass', name: 'subclass',
title: 'Select subclass to upgrade', title: 'Select subclass to upgrade',
choices: [], choices: []
}, },
multiclass: { multiclass: {
name: 'multiclass', name: 'multiclass',
title: '', title: '',
choices: [{}], choices: [{}]
} }
}; };
export const levelupData = { export const levelupData = {
tier1: { tier1: {
id: "2_4", id: '2_4',
tier: 1, tier: 1,
levels: [2,3,4], levels: [2, 3, 4],
label: 'DAGGERHEART.LevelUp.Tier1.Label', label: 'DAGGERHEART.LevelUp.Tier1.Label',
info: "DAGGERHEART.LevelUp.Tier1.InfoLabel", info: 'DAGGERHEART.LevelUp.Tier1.InfoLabel',
pretext: "DAGGERHEART.LevelUp.Tier1.Pretext", pretext: 'DAGGERHEART.LevelUp.Tier1.Pretext',
posttext: "DAGGERHEART.LevelUp.Tier1.Posttext", posttext: 'DAGGERHEART.LevelUp.Tier1.Posttext',
choices: { choices: {
[levelChoices.attributes.name]: { [levelChoices.attributes.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Attributes", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.Attributes',
maxChoices: 3, maxChoices: 3
}, },
[levelChoices.hitPointSlots.name]: { [levelChoices.hitPointSlots.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.HitPointSlots", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.HitPointSlots',
maxChoices: 1, maxChoices: 1
}, },
[levelChoices.stressSlots.name]: { [levelChoices.stressSlots.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.StressSlots", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.StressSlots',
maxChoices: 1, maxChoices: 1
}, },
[levelChoices.experiences.name]: { [levelChoices.experiences.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Experiences", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.Experiences',
maxChoices: 1, maxChoices: 1
}, },
[levelChoices.proficiency.name]: { [levelChoices.proficiency.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Proficiency", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.Proficiency',
maxChoices: 1, maxChoices: 1
}, },
[levelChoices.armorOrEvasionSlot.name]: { [levelChoices.armorOrEvasionSlot.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.ArmorOrEvasionSlot", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.ArmorOrEvasionSlot',
maxChoices: 1, maxChoices: 1
}, },
[levelChoices.majorDamageThreshold2.name]: { [levelChoices.majorDamageThreshold2.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.MajorDamageThreshold2", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.MajorDamageThreshold2',
maxChoices: 1, maxChoices: 1
}, },
[levelChoices.severeDamageThreshold2.name]: { [levelChoices.severeDamageThreshold2.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.SevereDamageThreshold2", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.SevereDamageThreshold2',
maxChoices: 1, maxChoices: 1
} }
} }
}, },
tier2: { tier2: {
id: "5_7", id: '5_7',
tier: 2, tier: 2,
levels: [5,6,7], levels: [5, 6, 7],
label: 'DAGGERHEART.LevelUp.Tier2.Label', label: 'DAGGERHEART.LevelUp.Tier2.Label',
info: "DAGGERHEART.LevelUp.Tier2.InfoLabel", info: 'DAGGERHEART.LevelUp.Tier2.InfoLabel',
pretext: "DAGGERHEART.LevelUp.Tier2.Pretext", pretext: 'DAGGERHEART.LevelUp.Tier2.Pretext',
posttext: "DAGGERHEART.LevelUp.Tier2.Posttext", posttext: 'DAGGERHEART.LevelUp.Tier2.Posttext',
choices: { choices: {
[levelChoices.attributes.name]: { [levelChoices.attributes.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Attributes", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.Attributes',
maxChoices: 3, maxChoices: 3
}, },
[levelChoices.hitPointSlots.name]: { [levelChoices.hitPointSlots.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.HitPointSlots", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.HitPointSlots',
maxChoices: 2, maxChoices: 2
}, },
[levelChoices.stressSlots.name]: { [levelChoices.stressSlots.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.StressSlots", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.StressSlots',
maxChoices: 2, maxChoices: 2
}, },
[levelChoices.experiences.name]: { [levelChoices.experiences.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Experiences", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.Experiences',
maxChoices: 1, maxChoices: 1
}, },
[levelChoices.proficiency.name]: { [levelChoices.proficiency.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Proficiency", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.Proficiency',
maxChoices: 2, maxChoices: 2
}, },
[levelChoices.armorOrEvasionSlot.name]: { [levelChoices.armorOrEvasionSlot.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.ArmorOrEvasionSlot", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.ArmorOrEvasionSlot',
maxChoices: 2, maxChoices: 2
}, },
[levelChoices.majorDamageThreshold2.name]: { [levelChoices.majorDamageThreshold2.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.MajorDamageThreshold2", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.MajorDamageThreshold2',
maxChoices: 1, maxChoices: 1
}, },
[levelChoices.severeDamageThreshold3.name]: { [levelChoices.severeDamageThreshold3.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.SevereDamageThreshold3", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.SevereDamageThreshold3',
maxChoices: 1, maxChoices: 1
}, },
[levelChoices.subclass.name]: { [levelChoices.subclass.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Subclass", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.Subclass',
maxChoices: 1, maxChoices: 1
}, },
[levelChoices.multiclass.name]: { [levelChoices.multiclass.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Multiclass", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.Multiclass',
maxChoices: 1, maxChoices: 1,
cost: 2, cost: 2
}, }
}, }
}, },
tier3: { tier3: {
id: "8_10", id: '8_10',
tier: 3, tier: 3,
levels: [8,9,10], levels: [8, 9, 10],
label: 'DAGGERHEART.LevelUp.Tier3.Label', label: 'DAGGERHEART.LevelUp.Tier3.Label',
info: "DAGGERHEART.LevelUp.Tier3.InfoLabel", info: 'DAGGERHEART.LevelUp.Tier3.InfoLabel',
pretext: "DAGGERHEART.LevelUp.Tier3.Pretext", pretext: 'DAGGERHEART.LevelUp.Tier3.Pretext',
posttext: "DAGGERHEART.LevelUp.Tier3.Posttext", posttext: 'DAGGERHEART.LevelUp.Tier3.Posttext',
choices: { choices: {
[levelChoices.attributes.name]: { [levelChoices.attributes.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Attributes", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.Attributes',
maxChoices: 3, maxChoices: 3
}, },
[levelChoices.hitPointSlots.name]: { [levelChoices.hitPointSlots.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.HitPointSlots", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.HitPointSlots',
maxChoices: 2, maxChoices: 2
}, },
[levelChoices.stressSlots.name]: { [levelChoices.stressSlots.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.StressSlots", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.StressSlots',
maxChoices: 2, maxChoices: 2
}, },
[levelChoices.experiences.name]: { [levelChoices.experiences.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Experiences", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.Experiences',
maxChoices: 1, maxChoices: 1
}, },
[levelChoices.proficiency.name]: { [levelChoices.proficiency.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Proficiency", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.Proficiency',
maxChoices: 2, maxChoices: 2
}, },
[levelChoices.armorOrEvasionSlot.name]: { [levelChoices.armorOrEvasionSlot.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.ArmorOrEvasionSlot", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.ArmorOrEvasionSlot',
maxChoices: 2, maxChoices: 2
}, },
[levelChoices.majorDamageThreshold2.name]: { [levelChoices.majorDamageThreshold2.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.MajorDamageThreshold2", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.MajorDamageThreshold2',
maxChoices: 1, maxChoices: 1
}, },
[levelChoices.severeDamageThreshold4.name]: { [levelChoices.severeDamageThreshold4.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.SevereDamageThreshold4", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.SevereDamageThreshold4',
maxChoices: 1, maxChoices: 1
}, },
[levelChoices.subclass.name]: { [levelChoices.subclass.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Subclass", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.Subclass',
maxChoices: 1, maxChoices: 1
}, },
[levelChoices.multiclass.name]: { [levelChoices.multiclass.name]: {
description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Multiclass", description: 'DAGGERHEART.LevelUp.ChoiceDescriptions.Multiclass',
maxChoices: 1, maxChoices: 1,
cost: 2, cost: 2
}, }
}, }
} }
}; };

View file

@ -3,99 +3,99 @@ export const domains = {
id: 'arcana', id: 'arcana',
label: 'Arcana', label: 'Arcana',
src: 'icons/magic/symbols/circled-gem-pink.webp', src: 'icons/magic/symbols/circled-gem-pink.webp',
description: 'DAGGERHEART.Domains.Arcana', description: 'DAGGERHEART.Domains.Arcana'
}, },
blade: { blade: {
id: 'blade', id: 'blade',
label: 'Blade', label: 'Blade',
src: 'icons/weapons/swords/sword-broad-crystal-paired.webp', src: 'icons/weapons/swords/sword-broad-crystal-paired.webp',
description: 'DAGGERHEART.Domains.Blade', description: 'DAGGERHEART.Domains.Blade'
}, },
bone: { bone: {
id: 'bone', id: 'bone',
label: 'Bone', label: 'Bone',
src: 'icons/skills/wounds/bone-broken-marrow-red.webp', src: 'icons/skills/wounds/bone-broken-marrow-red.webp',
description: 'DAGGERHEART.Domains.Bone', description: 'DAGGERHEART.Domains.Bone'
}, },
codex: { codex: {
id: 'codex', id: 'codex',
label: 'Codex', label: 'Codex',
src: 'icons/sundries/books/book-embossed-jewel-gold-purple.webp', src: 'icons/sundries/books/book-embossed-jewel-gold-purple.webp',
description: 'DAGGERHEART.Domains.Codex', description: 'DAGGERHEART.Domains.Codex'
}, },
grace: { grace: {
id: 'grace', id: 'grace',
label: 'Grace', label: 'Grace',
src: 'icons/skills/movement/feet-winged-boots-glowing-yellow.webp', src: 'icons/skills/movement/feet-winged-boots-glowing-yellow.webp',
description: 'DAGGERHEART.Domains.Grace', description: 'DAGGERHEART.Domains.Grace'
}, },
midnight: { midnight: {
id: 'midnight', id: 'midnight',
label: 'Midnight', label: 'Midnight',
src: 'icons/environment/settlement/watchtower-castle-night.webp', src: 'icons/environment/settlement/watchtower-castle-night.webp',
background: 'systems/daggerheart/assets/backgrounds/MidnightBackground.webp', background: 'systems/daggerheart/assets/backgrounds/MidnightBackground.webp',
description: 'DAGGERHEART.Domains.Midnight', description: 'DAGGERHEART.Domains.Midnight'
}, },
sage: { sage: {
id: 'sage', id: 'sage',
label: 'Sage', label: 'Sage',
src: 'icons/sundries/misc/pipe-wooden-straight-brown.webp', src: 'icons/sundries/misc/pipe-wooden-straight-brown.webp',
description: 'DAGGERHEART.Domains.Sage', description: 'DAGGERHEART.Domains.Sage'
}, },
splendor: { splendor: {
id: 'splendor', id: 'splendor',
label: 'Splendor', label: 'Splendor',
src: 'icons/magic/control/control-influence-crown-gold.webp', src: 'icons/magic/control/control-influence-crown-gold.webp',
description: 'DAGGERHEART.Domains.Splendor', description: 'DAGGERHEART.Domains.Splendor'
}, },
valor: { valor: {
id: 'valor', id: 'valor',
label: 'Valor', label: 'Valor',
src: 'icons/magic/control/control-influence-rally-purple.webp', src: 'icons/magic/control/control-influence-rally-purple.webp',
description: 'DAGGERHEART.Domains.Valor', description: 'DAGGERHEART.Domains.Valor'
}, }
}; };
export const classDomainMap = { export const classDomainMap = {
rogue: [domains.midnight, domains.grace], rogue: [domains.midnight, domains.grace]
}; };
export const subclassMap = { export const subclassMap = {
syndicate: { syndicate: {
id: 'syndicate', id: 'syndicate',
label: 'Syndicate', label: 'Syndicate'
}, },
nightwalker: { nightwalker: {
id: 'nightwalker', id: 'nightwalker',
label: 'Nightwalker', label: 'Nightwalker'
}, }
}; };
export const classMap = { export const classMap = {
rogue: { rogue: {
label: "Rogue", label: 'Rogue',
subclasses: [subclassMap.syndicate.id, subclassMap.nightwalker.id], subclasses: [subclassMap.syndicate.id, subclassMap.nightwalker.id]
}, },
seraph: { seraph: {
label: "Seraph", label: 'Seraph',
subclasses: [] subclasses: []
}, }
}; };
export const cardTypes = { export const cardTypes = {
ability: { ability: {
id: 'ability', id: 'ability',
label: "DAGGERHEART.Domain.CardTypes.Ability", label: 'DAGGERHEART.Domain.CardTypes.Ability',
img: "", img: ''
}, },
spell: { spell: {
id: 'spell', id: 'spell',
label: "DAGGERHEART.Domain.CardTypes.Spell", label: 'DAGGERHEART.Domain.CardTypes.Spell',
img: "" img: ''
}, },
grimoire: { grimoire: {
id: 'grimoire', id: 'grimoire',
label: "DAGGERHEART.Domain.CardTypes.Grimoire", label: 'DAGGERHEART.Domain.CardTypes.Grimoire',
img: "" img: ''
} }
}; };

View file

@ -1,64 +1,64 @@
import { range } from "./generalConfig.mjs"; import { range } from './generalConfig.mjs';
export const valueTypes = { export const valueTypes = {
numberString: { numberString: {
id: 'numberString', id: 'numberString'
}, },
select: { select: {
id: 'select', id: 'select'
} }
} };
export const parseTypes = { export const parseTypes = {
string: { string: {
id: 'string', id: 'string'
}, },
number: { number: {
id: 'number', id: 'number'
}, }
} };
export const applyLocations = { export const applyLocations = {
attackRoll: { attackRoll: {
id: 'attackRoll', id: 'attackRoll',
name: "DAGGERHEART.Effects.ApplyLocations.AttackRoll.Name", name: 'DAGGERHEART.Effects.ApplyLocations.AttackRoll.Name'
}, },
damageRoll: { damageRoll: {
id: 'damageRoll', id: 'damageRoll',
name: "DAGGERHEART.Effects.ApplyLocations.DamageRoll.Name", name: 'DAGGERHEART.Effects.ApplyLocations.DamageRoll.Name'
} }
}; };
export const effectTypes = { export const effectTypes = {
health: { health: {
id: "health", id: 'health',
name: "DAGGERHEART.Effects.Types.Health.Name", name: 'DAGGERHEART.Effects.Types.Health.Name',
values: [], values: [],
valueType: valueTypes.numberString.id, valueType: valueTypes.numberString.id,
parseType: parseTypes.number.id, parseType: parseTypes.number.id
}, },
stress: { stress: {
id: "stress", id: 'stress',
name: "DAGGERHEART.Effects.Types.Stress.Name", name: 'DAGGERHEART.Effects.Types.Stress.Name',
valueType: valueTypes.numberString.id, valueType: valueTypes.numberString.id,
parseType: parseTypes.number.id, parseType: parseTypes.number.id
}, },
reach: { reach: {
id: "reach", id: 'reach',
name: "DAGGERHEART.Effects.Types.Reach.Name", name: 'DAGGERHEART.Effects.Types.Reach.Name',
valueType: valueTypes.select.id, valueType: valueTypes.select.id,
parseType: parseTypes.string.id, parseType: parseTypes.string.id,
options: Object.keys(range).map(x => ({ name: range[x].name, value: x })) options: Object.keys(range).map(x => ({ name: range[x].name, value: x }))
}, },
damage: { damage: {
id: "damage", id: 'damage',
name: "DAGGERHEART.Effects.Types.Damage.Name", name: 'DAGGERHEART.Effects.Types.Damage.Name',
valueType: valueTypes.numberString.id, valueType: valueTypes.numberString.id,
parseType: parseTypes.string.id, parseType: parseTypes.string.id,
appliesOn: applyLocations.damageRoll.id, appliesOn: applyLocations.damageRoll.id,
applyLocationChoices: { applyLocationChoices: {
[applyLocations.damageRoll.id]: applyLocations.damageRoll.name, [applyLocations.damageRoll.id]: applyLocations.damageRoll.name,
[applyLocations.attackRoll.id]: applyLocations.attackRoll.name, [applyLocations.attackRoll.id]: applyLocations.attackRoll.name
}, }
} }
}; };

View file

@ -1,170 +1,170 @@
export const range = { export const range = {
melee: { melee: {
label: "DAGGERHEART.Range.Melee.Name", label: 'DAGGERHEART.Range.Melee.Name',
description: "DAGGERHEART.Range.Melee.Description", description: 'DAGGERHEART.Range.Melee.Description',
distance: 1 distance: 1
}, },
veryClose: { veryClose: {
label: "DAGGERHEART.Range.VeryClose.Name", label: 'DAGGERHEART.Range.VeryClose.Name',
description: "DAGGERHEART.Range.VeryClose.Description", description: 'DAGGERHEART.Range.VeryClose.Description',
distance: 3 distance: 3
}, },
close: { close: {
label: "DAGGERHEART.Range.Close.Name", label: 'DAGGERHEART.Range.Close.Name',
description: "DAGGERHEART.Range.Close.Description", description: 'DAGGERHEART.Range.Close.Description',
distance: 10 distance: 10
}, },
far: { far: {
label: "DAGGERHEART.Range.Far.Name", label: 'DAGGERHEART.Range.Far.Name',
description: "DAGGERHEART.Range.Far.Description", description: 'DAGGERHEART.Range.Far.Description',
distance: 20 distance: 20
}, },
veryFar: { veryFar: {
label: "DAGGERHEART.Range.VeryFar.Name", label: 'DAGGERHEART.Range.VeryFar.Name',
description: "DAGGERHEART.Range.VeryFar.Description", description: 'DAGGERHEART.Range.VeryFar.Description',
distance: 30 distance: 30
} }
} };
export const burden = { export const burden = {
oneHanded: "DAGGERHEART.Burden.OneHanded", oneHanded: 'DAGGERHEART.Burden.OneHanded',
twoHanded: "DAGGERHEART.Burden.TwoHanded" twoHanded: 'DAGGERHEART.Burden.TwoHanded'
} };
export const damageTypes = { export const damageTypes = {
physical: { physical: {
id: 'physical', id: 'physical',
label: "DAGGERHEART.DamageType.Physical.Name", label: 'DAGGERHEART.DamageType.Physical.Name',
abbreviation: "DAGGERHEART.DamageType.Physical.Abbreviation", abbreviation: 'DAGGERHEART.DamageType.Physical.Abbreviation'
}, },
magical: { magical: {
id: 'magical', id: 'magical',
label: "DAGGERHEART.DamageType.Magical.Name", label: 'DAGGERHEART.DamageType.Magical.Name',
abbreviation: "DAGGERHEART.DamageType.Magical.Abbreviation", abbreviation: 'DAGGERHEART.DamageType.Magical.Abbreviation'
}, }
} };
export const healingTypes = { export const healingTypes = {
health: { health: {
id: 'health', id: 'health',
label: "DAGGERHEART.HealingType.HitPoints.Name", label: 'DAGGERHEART.HealingType.HitPoints.Name',
abbreviation: "DAGGERHEART.HealingType.HitPoints.Abbreviation" abbreviation: 'DAGGERHEART.HealingType.HitPoints.Abbreviation'
}, },
stress: { stress: {
id: 'stress', id: 'stress',
label: "DAGGERHEART.HealingType.Stress.Name", label: 'DAGGERHEART.HealingType.Stress.Name',
abbreviation: "DAGGERHEART.HealingType.Stress.Abbreviation" abbreviation: 'DAGGERHEART.HealingType.Stress.Abbreviation'
}, }
}; };
export const conditions = { export const conditions = {
vulnerable: { vulnerable: {
id: 'vulnerable', id: 'vulnerable',
name: "DAGGERHEART.Condition.Vulnerable.Name", name: 'DAGGERHEART.Condition.Vulnerable.Name',
icon: "icons/magic/control/silhouette-fall-slip-prone.webp", icon: 'icons/magic/control/silhouette-fall-slip-prone.webp',
description: "DAGGERHEART.Condition.Vulnerable.Description" description: 'DAGGERHEART.Condition.Vulnerable.Description'
}, },
hidden: { hidden: {
id: 'hidden', id: 'hidden',
name: "DAGGERHEART.Condition.Hidden.Name", name: 'DAGGERHEART.Condition.Hidden.Name',
icon: "icons/magic/perception/silhouette-stealth-shadow.webp", icon: 'icons/magic/perception/silhouette-stealth-shadow.webp',
description: "DAGGERHEART.Condition.Hidden.Description" description: 'DAGGERHEART.Condition.Hidden.Description'
}, },
restrained: { restrained: {
id: 'restrained', id: 'restrained',
name: "DAGGERHEART.Condition.Restrained.Name", name: 'DAGGERHEART.Condition.Restrained.Name',
icon: "icons/magic/control/debuff-chains-shackle-movement-red.webp", icon: 'icons/magic/control/debuff-chains-shackle-movement-red.webp',
description: "DAGGERHEART.Condition.Restrained.Description" description: 'DAGGERHEART.Condition.Restrained.Description'
}, }
} };
export const downtime = { export const downtime = {
shortRest: { shortRest: {
tendToWounds: { tendToWounds: {
id: "tendToWounds", id: 'tendToWounds',
name: "DAGGERHEART.Downtime.TendToWounds.Name", name: 'DAGGERHEART.Downtime.TendToWounds.Name',
img: "icons/magic/life/cross-worn-green.webp", img: 'icons/magic/life/cross-worn-green.webp',
description: "DAGGERHEART.Downtime.TendToWounds.Description", description: 'DAGGERHEART.Downtime.TendToWounds.Description'
}, },
clearStress: { clearStress: {
id: "clearStress", id: 'clearStress',
name: "DAGGERHEART.Downtime.ClearStress.Name", name: 'DAGGERHEART.Downtime.ClearStress.Name',
img: "icons/magic/perception/eye-ringed-green.webp", img: 'icons/magic/perception/eye-ringed-green.webp',
description: "DAGGERHEART.Downtime.ClearStress.Description", description: 'DAGGERHEART.Downtime.ClearStress.Description'
}, },
repairArmor: { repairArmor: {
id: "repairArmor", id: 'repairArmor',
name: "DAGGERHEART.Downtime.RepairArmor.Name", name: 'DAGGERHEART.Downtime.RepairArmor.Name',
img: "icons/skills/trades/smithing-anvil-silver-red.webp", img: 'icons/skills/trades/smithing-anvil-silver-red.webp',
description: "DAGGERHEART.Downtime.RepairArmor.Description", description: 'DAGGERHEART.Downtime.RepairArmor.Description'
}, },
prepare: { prepare: {
id: "prepare", id: 'prepare',
name: "DAGGERHEART.Downtime.Prepare.Name", name: 'DAGGERHEART.Downtime.Prepare.Name',
img: "icons/skills/trades/academics-merchant-scribe.webp", img: 'icons/skills/trades/academics-merchant-scribe.webp',
description: "DAGGERHEART.Downtime.Prepare.Description", description: 'DAGGERHEART.Downtime.Prepare.Description'
}, }
}, },
longRest: { longRest: {
tendToWounds: { tendToWounds: {
id: "tendToWounds", id: 'tendToWounds',
name: "DAGGERHEART.Downtime.TendToWounds.Name", name: 'DAGGERHEART.Downtime.TendToWounds.Name',
img: "icons/magic/life/cross-worn-green.webp", img: 'icons/magic/life/cross-worn-green.webp',
description: "DAGGERHEART.Downtime.TendToWounds.Description", description: 'DAGGERHEART.Downtime.TendToWounds.Description'
}, },
clearStress: { clearStress: {
id: "clearStress", id: 'clearStress',
name: "DAGGERHEART.Downtime.ClearStress.Name", name: 'DAGGERHEART.Downtime.ClearStress.Name',
img: "icons/magic/perception/eye-ringed-green.webp", img: 'icons/magic/perception/eye-ringed-green.webp',
description: "DAGGERHEART.Downtime.ClearStress.Description", description: 'DAGGERHEART.Downtime.ClearStress.Description'
}, },
repairArmor: { repairArmor: {
id: "repairArmor", id: 'repairArmor',
name: "DAGGERHEART.Downtime.RepairArmor.Name", name: 'DAGGERHEART.Downtime.RepairArmor.Name',
img: "icons/skills/trades/smithing-anvil-silver-red.webp", img: 'icons/skills/trades/smithing-anvil-silver-red.webp',
description: "DAGGERHEART.Downtime.RepairArmor.Description", description: 'DAGGERHEART.Downtime.RepairArmor.Description'
}, },
prepare: { prepare: {
id: "prepare", id: 'prepare',
name: "DAGGERHEART.Downtime.Prepare.Name", name: 'DAGGERHEART.Downtime.Prepare.Name',
img: "icons/skills/trades/academics-merchant-scribe.webp", img: 'icons/skills/trades/academics-merchant-scribe.webp',
description: "DAGGERHEART.Downtime.Prepare.Description", description: 'DAGGERHEART.Downtime.Prepare.Description'
}, },
workOnAProject: { workOnAProject: {
id: "workOnAProject", id: 'workOnAProject',
name: "DAGGERHEART.Downtime.WorkOnAProject.Name", name: 'DAGGERHEART.Downtime.WorkOnAProject.Name',
img: "icons/skills/social/thumbsup-approval-like.webp", img: 'icons/skills/social/thumbsup-approval-like.webp',
description: "DAGGERHEART.Downtime.WorkOnAProject.Description", description: 'DAGGERHEART.Downtime.WorkOnAProject.Description'
} }
}, },
custom: { custom: {
id: 'customActivity', id: 'customActivity',
name: "", name: '',
img: "icons/skills/trades/academics-investigation-puzzles.webp", img: 'icons/skills/trades/academics-investigation-puzzles.webp',
description: "", description: '',
namePlaceholder: "DAGGERHEART.Downtime.Custom.NamePlaceholder", namePlaceholder: 'DAGGERHEART.Downtime.Custom.NamePlaceholder',
placeholder: "DAGGERHEART.Downtime.Custom.Placeholder", placeholder: 'DAGGERHEART.Downtime.Custom.Placeholder'
} }
} };
export const deathMoves = { export const deathMoves = {
avoidDeath: { avoidDeath: {
id: "avoidDeath", id: 'avoidDeath',
name: "DAGGERHEART.DeathMoves.AvoidDeath.Name", name: 'DAGGERHEART.DeathMoves.AvoidDeath.Name',
img: "icons/magic/time/hourglass-yellow-green.webp", img: 'icons/magic/time/hourglass-yellow-green.webp',
description: "DAGGERHEART.DeathMoves.AvoidDeath.Description", description: 'DAGGERHEART.DeathMoves.AvoidDeath.Description'
}, },
riskItAll: { riskItAll: {
id: 'riskItAll', id: 'riskItAll',
name: "DAGGERHEART.DeathMoves.RiskItAll.Name", name: 'DAGGERHEART.DeathMoves.RiskItAll.Name',
img: "icons/sundries/gaming/dice-pair-white-green.webp", img: 'icons/sundries/gaming/dice-pair-white-green.webp',
description: "DAGGERHEART.DeathMoves.RiskItAll.Description", description: 'DAGGERHEART.DeathMoves.RiskItAll.Description'
}, },
blazeOfGlory: { blazeOfGlory: {
id: "blazeOfGlory", id: 'blazeOfGlory',
name: "DAGGERHEART.DeathMoves.BlazeOfGlory.Name", name: 'DAGGERHEART.DeathMoves.BlazeOfGlory.Name',
img: "icons/magic/life/heart-cross-strong-flame-purple-orange.webp", img: 'icons/magic/life/heart-cross-strong-flame-purple-orange.webp',
description: "DAGGERHEART.DeathMoves.BlazeOfGlory.Description", description: 'DAGGERHEART.DeathMoves.BlazeOfGlory.Description'
} }
}; };
@ -172,97 +172,97 @@ export const tiers = {
0: { 0: {
key: 0, key: 0,
id: 'tier0', id: 'tier0',
name: 'DAGGERHEART.General.Tier.0', name: 'DAGGERHEART.General.Tier.0'
}, },
1: { 1: {
key: 1, key: 1,
id: 'tier1', id: 'tier1',
name: 'DAGGERHEART.General.Tier.1', name: 'DAGGERHEART.General.Tier.1'
}, },
2: { 2: {
key: 2, key: 2,
id: 'tier2', id: 'tier2',
name: 'DAGGERHEART.General.Tier.2', name: 'DAGGERHEART.General.Tier.2'
}, },
3: { 3: {
key: 3, key: 3,
id: 'tier3', id: 'tier3',
name: 'DAGGERHEART.General.Tier.3', name: 'DAGGERHEART.General.Tier.3'
} }
}; };
export const objectTypes = { export const objectTypes = {
pc: { pc: {
name: "TYPES.Actor.pc", name: 'TYPES.Actor.pc'
}, },
npc: { npc: {
name: "TYPES.Actor.npc", name: 'TYPES.Actor.npc'
}, },
adversary: { adversary: {
name: "TYPES.Actor.adversary", name: 'TYPES.Actor.adversary'
}, },
ancestry: { ancestry: {
name: "TYPES.Item.ancestry", name: 'TYPES.Item.ancestry'
}, },
community: { community: {
name: "TYPES.Item.community", name: 'TYPES.Item.community'
}, },
class: { class: {
name: "TYPES.Item.class", name: 'TYPES.Item.class'
}, },
subclass: { subclass: {
name: "TYPES.Item.subclass", name: 'TYPES.Item.subclass'
}, },
feature: { feature: {
name: "TYPES.Item.feature", name: 'TYPES.Item.feature'
}, },
domainCard: { domainCard: {
name: "TYPES.Item.domainCard", name: 'TYPES.Item.domainCard'
}, },
consumable: { consumable: {
name: "TYPES.Item.consumable", name: 'TYPES.Item.consumable'
}, },
miscellaneous: { miscellaneous: {
name: "TYPES.Item.miscellaneous", name: 'TYPES.Item.miscellaneous'
}, },
weapon: { weapon: {
name: "TYPES.Item.weapon", name: 'TYPES.Item.weapon'
}, },
armor: { armor: {
name: "TYPES.Item.armor", name: 'TYPES.Item.armor'
} }
}; };
export const diceTypes = { export const diceTypes = {
d4: "d4", d4: 'd4',
d6: "d6", d6: 'd6',
d8: "d8", d8: 'd8',
d12: "d12", d12: 'd12',
d20: "d20" d20: 'd20'
}; };
export const refreshTypes = { export const refreshTypes = {
session: { session: {
id: 'session', id: 'session',
label: "DAGGERHEART.General.RefreshType.Session" label: 'DAGGERHEART.General.RefreshType.Session'
}, },
shortRest: { shortRest: {
id: 'shortRest', id: 'shortRest',
label: "DAGGERHEART.General.RefreshType.Shortrest", label: 'DAGGERHEART.General.RefreshType.Shortrest'
}, },
longRest: { longRest: {
id: 'longRest', id: 'longRest',
label: "DAGGERHEART.General.RefreshType.Longrest" label: 'DAGGERHEART.General.RefreshType.Longrest'
} }
} };
export const abilityCosts = { export const abilityCosts = {
hope: { hope: {
id: 'hope', id: 'hope',
label: 'Hope', label: 'Hope'
}, },
stress: { stress: {
id: 'stress', id: 'stress',
label: 'Stress', label: 'Stress'
} }
} };

View file

@ -1,351 +1,351 @@
export const armorFeatures = { export const armorFeatures = {
light: { light: {
label: "DAGGERHEART.ArmorFeature.Light.Name", label: 'DAGGERHEART.ArmorFeature.Light.Name',
description: "DAGGERHEART.ArmorFeature.Light.Description", description: 'DAGGERHEART.ArmorFeature.Light.Description'
}, },
heavy: { heavy: {
label: "DAGGERHEART.ArmorFeature.Heavy.Name", label: 'DAGGERHEART.ArmorFeature.Heavy.Name',
description: "DAGGERHEART.ArmorFeature.Heavy.Description", description: 'DAGGERHEART.ArmorFeature.Heavy.Description'
}, },
veryHeavy: { veryHeavy: {
label: "DAGGERHEART.ArmorFeature.VeryHeavy.Name", label: 'DAGGERHEART.ArmorFeature.VeryHeavy.Name',
description: "DAGGERHEART.ArmorFeature.VeryHeavy.Description", description: 'DAGGERHEART.ArmorFeature.VeryHeavy.Description'
}, },
reinforced: { reinforced: {
label: "DAGGERHEART.ArmorFeature.Reinforced.Name", label: 'DAGGERHEART.ArmorFeature.Reinforced.Name',
description: "DAGGERHEART.ArmorFeature.Reinforced.Description", description: 'DAGGERHEART.ArmorFeature.Reinforced.Description'
}, },
sturdy: { sturdy: {
label: "DAGGERHEART.ArmorFeature.Sturdy.Name", label: 'DAGGERHEART.ArmorFeature.Sturdy.Name',
description: "DAGGERHEART.ArmorFeature.Sturdy.Description", description: 'DAGGERHEART.ArmorFeature.Sturdy.Description'
}, },
warded: { warded: {
label: "DAGGERHEART.ArmorFeature.Warded.Name", label: 'DAGGERHEART.ArmorFeature.Warded.Name',
description: "DAGGERHEART.ArmorFeature.Warded.Description", description: 'DAGGERHEART.ArmorFeature.Warded.Description'
}, },
resistant: { resistant: {
label: "DAGGERHEART.ArmorFeature.Resistant.Name", label: 'DAGGERHEART.ArmorFeature.Resistant.Name',
description: "DAGGERHEART.ArmorFeature.Resistant.Description", description: 'DAGGERHEART.ArmorFeature.Resistant.Description'
}, },
quiet: { quiet: {
label: "DAGGERHEART.ArmorFeature.Quiet.Name", label: 'DAGGERHEART.ArmorFeature.Quiet.Name',
description: "DAGGERHEART.ArmorFeature.Quiet.Description", description: 'DAGGERHEART.ArmorFeature.Quiet.Description'
}, },
hopeful: { hopeful: {
label: "DAGGERHEART.ArmorFeature.Hopeful.Name", label: 'DAGGERHEART.ArmorFeature.Hopeful.Name',
description: "DAGGERHEART.ArmorFeature.Hopeful.Description", description: 'DAGGERHEART.ArmorFeature.Hopeful.Description'
}, },
impenetrable: { impenetrable: {
label: "DAGGERHEART.ArmorFeature.Impenetrable.Name", label: 'DAGGERHEART.ArmorFeature.Impenetrable.Name',
description: "DAGGERHEART.ArmorFeature.Impenetrable.Description", description: 'DAGGERHEART.ArmorFeature.Impenetrable.Description'
}, },
painful: { painful: {
label: "DAGGERHEART.ArmorFeature.Painful.Name", label: 'DAGGERHEART.ArmorFeature.Painful.Name',
description: "DAGGERHEART.ArmorFeature.Painful.Description", description: 'DAGGERHEART.ArmorFeature.Painful.Description'
}, },
gilded: { gilded: {
label: "DAGGERHEART.ArmorFeature.Gilded.Name", label: 'DAGGERHEART.ArmorFeature.Gilded.Name',
description: "DAGGERHEART.ArmorFeature.Gilded.Description", description: 'DAGGERHEART.ArmorFeature.Gilded.Description'
}, },
physical: { physical: {
label: "DAGGERHEART.ArmorFeature.Physical.Name", label: 'DAGGERHEART.ArmorFeature.Physical.Name',
description: "DAGGERHEART.ArmorFeature.Physical.Description", description: 'DAGGERHEART.ArmorFeature.Physical.Description'
}, },
magic: { magic: {
label: "DAGGERHEART.ArmorFeature.Magic.Name", label: 'DAGGERHEART.ArmorFeature.Magic.Name',
description: "DAGGERHEART.ArmorFeature.Magic.Description", description: 'DAGGERHEART.ArmorFeature.Magic.Description'
}, },
sharp: { sharp: {
label: "DAGGERHEART.ArmorFeature.Sharp.Name", label: 'DAGGERHEART.ArmorFeature.Sharp.Name',
description: "DAGGERHEART.ArmorFeature.Sharp.Description", description: 'DAGGERHEART.ArmorFeature.Sharp.Description'
}, },
burning: { burning: {
label: "DAGGERHEART.ArmorFeature.Burning.Name", label: 'DAGGERHEART.ArmorFeature.Burning.Name',
description: "DAGGERHEART.ArmorFeature.Burning.Description", description: 'DAGGERHEART.ArmorFeature.Burning.Description'
}, },
timeslowing: { timeslowing: {
label: "DAGGERHEART.ArmorFeature.Timeslowing.Name", label: 'DAGGERHEART.ArmorFeature.Timeslowing.Name',
description: "DAGGERHEART.ArmorFeature.Timeslowing.Description", description: 'DAGGERHEART.ArmorFeature.Timeslowing.Description'
}, },
truthseeking: { truthseeking: {
label: "DAGGERHEART.ArmorFeature.Truthseeking.Name", label: 'DAGGERHEART.ArmorFeature.Truthseeking.Name',
description: "DAGGERHEART.ArmorFeature.Truthseeking.Description", description: 'DAGGERHEART.ArmorFeature.Truthseeking.Description'
}, },
channeling: { channeling: {
label: "DAGGERHEART.ArmorFeature.Channeling.Name", label: 'DAGGERHEART.ArmorFeature.Channeling.Name',
description: "DAGGERHEART.ArmorFeature.Channeling.Description", description: 'DAGGERHEART.ArmorFeature.Channeling.Description'
}, },
difficult: { difficult: {
label: "DAGGERHEART.ArmorFeature.Difficult.Name", label: 'DAGGERHEART.ArmorFeature.Difficult.Name',
description: "DAGGERHEART.ArmorFeature.Difficult.Description", description: 'DAGGERHEART.ArmorFeature.Difficult.Description'
}, },
variable: { variable: {
label: "DAGGERHEART.ArmorFeature.Variable.Name", label: 'DAGGERHEART.ArmorFeature.Variable.Name',
description: "DAGGERHEART.ArmorFeature.Variable.Description", description: 'DAGGERHEART.ArmorFeature.Variable.Description'
}, }
}; };
export const weaponFeatures = { export const weaponFeatures = {
light: { light: {
label: "DAGGERHEART.WeaponFeature.Light.Name", label: 'DAGGERHEART.WeaponFeature.Light.Name',
description: "DAGGERHEART.WeaponFeature.Light.Description", description: 'DAGGERHEART.WeaponFeature.Light.Description'
}, },
heavy: { heavy: {
label: "DAGGERHEART.WeaponFeature.Heavy.Name", label: 'DAGGERHEART.WeaponFeature.Heavy.Name',
description: "DAGGERHEART.WeaponFeature.Heavy.Description", description: 'DAGGERHEART.WeaponFeature.Heavy.Description'
}, },
massive: { massive: {
label: "DAGGERHEART.WeaponFeature.Massive.Name", label: 'DAGGERHEART.WeaponFeature.Massive.Name',
description: "DAGGERHEART.WeaponFeature.Massive.Description", description: 'DAGGERHEART.WeaponFeature.Massive.Description'
}, },
reliable: { reliable: {
label: "DAGGERHEART.WeaponFeature.Reliable.Name", label: 'DAGGERHEART.WeaponFeature.Reliable.Name',
description: "DAGGERHEART.WeaponFeature.Reliable.Description", description: 'DAGGERHEART.WeaponFeature.Reliable.Description'
}, },
quick: { quick: {
label: "DAGGERHEART.WeaponFeature.Quick.Name", label: 'DAGGERHEART.WeaponFeature.Quick.Name',
description: "DAGGERHEART.WeaponFeature.Quick.Description", description: 'DAGGERHEART.WeaponFeature.Quick.Description'
}, },
cumbersome: { cumbersome: {
label: "DAGGERHEART.WeaponFeature.Cumbersome.Name", label: 'DAGGERHEART.WeaponFeature.Cumbersome.Name',
description: "DAGGERHEART.WeaponFeature.Cumbersome.Description", description: 'DAGGERHEART.WeaponFeature.Cumbersome.Description'
}, },
versatile: { versatile: {
label: "DAGGERHEART.WeaponFeature.Versatile.Name", label: 'DAGGERHEART.WeaponFeature.Versatile.Name',
description: "DAGGERHEART.WeaponFeature.Versatile.Description", description: 'DAGGERHEART.WeaponFeature.Versatile.Description',
override: { override: {
damage: "", damage: ''
} }
}, },
powerful: { powerful: {
label: "DAGGERHEART.WeaponFeature.Powerful.Name", label: 'DAGGERHEART.WeaponFeature.Powerful.Name',
description: "DAGGERHEART.WeaponFeature.Powerful.Description", description: 'DAGGERHEART.WeaponFeature.Powerful.Description'
}, },
scary: { scary: {
label: "DAGGERHEART.WeaponFeature.Scary.Name", label: 'DAGGERHEART.WeaponFeature.Scary.Name',
description: "DAGGERHEART.WeaponFeature.Scary.Description", description: 'DAGGERHEART.WeaponFeature.Scary.Description'
}, },
brutal: { brutal: {
label: "DAGGERHEART.WeaponFeature.Brutal.Name", label: 'DAGGERHEART.WeaponFeature.Brutal.Name',
description: "DAGGERHEART.WeaponFeature.Brutal.Description", description: 'DAGGERHEART.WeaponFeature.Brutal.Description'
}, },
reloading: { reloading: {
label: "DAGGERHEART.WeaponFeature.Reloading.Name", label: 'DAGGERHEART.WeaponFeature.Reloading.Name',
description: "DAGGERHEART.WeaponFeature.Reloading.Description", description: 'DAGGERHEART.WeaponFeature.Reloading.Description'
}, },
eruptive: { eruptive: {
label: "DAGGERHEART.WeaponFeature.Eruptive.Name", label: 'DAGGERHEART.WeaponFeature.Eruptive.Name',
description: "DAGGERHEART.WeaponFeature.Eruptive.Description", description: 'DAGGERHEART.WeaponFeature.Eruptive.Description'
}, },
persuasive: { persuasive: {
label: "DAGGERHEART.WeaponFeature.Persuasive.Name", label: 'DAGGERHEART.WeaponFeature.Persuasive.Name',
description: "DAGGERHEART.WeaponFeature.Persuasive.Description", description: 'DAGGERHEART.WeaponFeature.Persuasive.Description'
}, },
pompous: { pompous: {
label: "DAGGERHEART.WeaponFeature.Pompous.Name", label: 'DAGGERHEART.WeaponFeature.Pompous.Name',
description: "DAGGERHEART.WeaponFeature.Pompous.Description", description: 'DAGGERHEART.WeaponFeature.Pompous.Description'
}, },
invigorating: { invigorating: {
label: "DAGGERHEART.WeaponFeature.Invigorating.Name", label: 'DAGGERHEART.WeaponFeature.Invigorating.Name',
description: "DAGGERHEART.WeaponFeature.Invigorating.Description", description: 'DAGGERHEART.WeaponFeature.Invigorating.Description'
}, },
dense: { dense: {
label: "DAGGERHEART.WeaponFeature.Dense.Name", label: 'DAGGERHEART.WeaponFeature.Dense.Name',
description: "DAGGERHEART.WeaponFeature.Dense.Description", description: 'DAGGERHEART.WeaponFeature.Dense.Description'
}, },
soulswift: { soulswift: {
label: "DAGGERHEART.WeaponFeature.Soulswift.Name", label: 'DAGGERHEART.WeaponFeature.Soulswift.Name',
description: "DAGGERHEART.WeaponFeature.Soulswift.Description", description: 'DAGGERHEART.WeaponFeature.Soulswift.Description'
}, },
protective: { protective: {
label: "DAGGERHEART.WeaponFeature.Protective.Name", label: 'DAGGERHEART.WeaponFeature.Protective.Name',
description: "DAGGERHEART.WeaponFeature.Protective.Description", description: 'DAGGERHEART.WeaponFeature.Protective.Description'
}, },
devastating: { devastating: {
label: "DAGGERHEART.WeaponFeature.Devastating.Name", label: 'DAGGERHEART.WeaponFeature.Devastating.Name',
description: "DAGGERHEART.WeaponFeature.Devastating.Description", description: 'DAGGERHEART.WeaponFeature.Devastating.Description'
}, },
retractable: { retractable: {
label: "DAGGERHEART.WeaponFeature.Retractable.Name", label: 'DAGGERHEART.WeaponFeature.Retractable.Name',
description: "DAGGERHEART.WeaponFeature.Retractable.Description", description: 'DAGGERHEART.WeaponFeature.Retractable.Description'
}, },
burn: { burn: {
label: "DAGGERHEART.WeaponFeature.Burn.Name", label: 'DAGGERHEART.WeaponFeature.Burn.Name',
description: "DAGGERHEART.WeaponFeature.Burn.Description", description: 'DAGGERHEART.WeaponFeature.Burn.Description'
}, },
painful: { painful: {
label: "DAGGERHEART.WeaponFeature.Painful.Name", label: 'DAGGERHEART.WeaponFeature.Painful.Name',
description: "DAGGERHEART.WeaponFeature.Painful.Description", description: 'DAGGERHEART.WeaponFeature.Painful.Description'
}, },
otherwordly: { otherwordly: {
label: "DAGGERHEART.WeaponFeature.Otherwordly.Name", label: 'DAGGERHEART.WeaponFeature.Otherwordly.Name',
description: "DAGGERHEART.WeaponFeature.Otherwordly.Description", description: 'DAGGERHEART.WeaponFeature.Otherwordly.Description'
}, },
lucky: { lucky: {
label: "DAGGERHEART.WeaponFeature.Lucky.Name", label: 'DAGGERHEART.WeaponFeature.Lucky.Name',
description: "DAGGERHEART.WeaponFeature.Lucky.Description", description: 'DAGGERHEART.WeaponFeature.Lucky.Description'
}, },
selfCorrecting: { selfCorrecting: {
label: "DAGGERHEART.WeaponFeature.SelfCorrecting.Name", label: 'DAGGERHEART.WeaponFeature.SelfCorrecting.Name',
description: "DAGGERHEART.WeaponFeature.SelfCorrecting.Description", description: 'DAGGERHEART.WeaponFeature.SelfCorrecting.Description'
}, },
healing: { healing: {
label: "DAGGERHEART.WeaponFeature.Healing.Name", label: 'DAGGERHEART.WeaponFeature.Healing.Name',
description: "DAGGERHEART.WeaponFeature.Healing.Description", description: 'DAGGERHEART.WeaponFeature.Healing.Description'
}, },
timebender: { timebender: {
label: "DAGGERHEART.WeaponFeature.Timebender.Name", label: 'DAGGERHEART.WeaponFeature.Timebender.Name',
description: "DAGGERHEART.WeaponFeature.Timebender.Description", description: 'DAGGERHEART.WeaponFeature.Timebender.Description'
}, },
enchanted: { enchanted: {
label: "DAGGERHEART.WeaponFeature.Enchanted.Name", label: 'DAGGERHEART.WeaponFeature.Enchanted.Name',
description: "DAGGERHEART.WeaponFeature.Enchanted.Description", description: 'DAGGERHEART.WeaponFeature.Enchanted.Description'
}, },
serrated: { serrated: {
label: "DAGGERHEART.WeaponFeature.Serrated.Name", label: 'DAGGERHEART.WeaponFeature.Serrated.Name',
description: "DAGGERHEART.WeaponFeature.Serrated.Description", description: 'DAGGERHEART.WeaponFeature.Serrated.Description'
}, },
grappling: { grappling: {
label: "DAGGERHEART.WeaponFeature.Grappling.Name", label: 'DAGGERHEART.WeaponFeature.Grappling.Name',
description: "DAGGERHEART.WeaponFeature.Grappling.Description", description: 'DAGGERHEART.WeaponFeature.Grappling.Description'
}, },
long: { long: {
label: "DAGGERHEART.WeaponFeature.Long.Name", label: 'DAGGERHEART.WeaponFeature.Long.Name',
description: "DAGGERHEART.WeaponFeature.Long.Description", description: 'DAGGERHEART.WeaponFeature.Long.Description'
}, },
destructive: { destructive: {
label: "DAGGERHEART.WeaponFeature.Destructive.Name", label: 'DAGGERHEART.WeaponFeature.Destructive.Name',
description: "DAGGERHEART.WeaponFeature.Destructive.Description", description: 'DAGGERHEART.WeaponFeature.Destructive.Description'
}, },
concussive: { concussive: {
label: "DAGGERHEART.WeaponFeature.Concussive.Name", label: 'DAGGERHEART.WeaponFeature.Concussive.Name',
description: "DAGGERHEART.WeaponFeature.Concussive.Description", description: 'DAGGERHEART.WeaponFeature.Concussive.Description'
}, },
bouncing: { bouncing: {
label: "DAGGERHEART.WeaponFeature.Bouncing.Name", label: 'DAGGERHEART.WeaponFeature.Bouncing.Name',
description: "DAGGERHEART.WeaponFeature.Bouncing.Description", description: 'DAGGERHEART.WeaponFeature.Bouncing.Description'
}, },
penetrating: { penetrating: {
label: "DAGGERHEART.WeaponFeature.Penetrating.Name", label: 'DAGGERHEART.WeaponFeature.Penetrating.Name',
description: "DAGGERHEART.WeaponFeature.Penetrating.Description", description: 'DAGGERHEART.WeaponFeature.Penetrating.Description'
}, },
lifestealing: { lifestealing: {
label: "DAGGERHEART.WeaponFeature.Lifestealing.Name", label: 'DAGGERHEART.WeaponFeature.Lifestealing.Name',
description: "DAGGERHEART.WeaponFeature.Lifestealing.Description", description: 'DAGGERHEART.WeaponFeature.Lifestealing.Description'
}, },
greedy: { greedy: {
label: "DAGGERHEART.WeaponFeature.Greedy.Name", label: 'DAGGERHEART.WeaponFeature.Greedy.Name',
description: "DAGGERHEART.WeaponFeature.Greedy.Description", description: 'DAGGERHEART.WeaponFeature.Greedy.Description'
}, },
bonded: { bonded: {
label: "DAGGERHEART.WeaponFeature.Bonded.Name", label: 'DAGGERHEART.WeaponFeature.Bonded.Name',
description: "DAGGERHEART.WeaponFeature.Bonded.Description", description: 'DAGGERHEART.WeaponFeature.Bonded.Description'
}, },
barrier: { barrier: {
label: "DAGGERHEART.WeaponFeature.Barrier.Name", label: 'DAGGERHEART.WeaponFeature.Barrier.Name',
description: "DAGGERHEART.WeaponFeature.Barrier.Description", description: 'DAGGERHEART.WeaponFeature.Barrier.Description'
}, },
paired: { paired: {
label: "DAGGERHEART.WeaponFeature.Paired.Name", label: 'DAGGERHEART.WeaponFeature.Paired.Name',
description: "DAGGERHEART.WeaponFeature.Paired.Description", description: 'DAGGERHEART.WeaponFeature.Paired.Description'
}, },
whipcrack: { whipcrack: {
label: "DAGGERHEART.WeaponFeature.Whipcrack.Name", label: 'DAGGERHEART.WeaponFeature.Whipcrack.Name',
description: "DAGGERHEART.WeaponFeature.Whipcrack.Description", description: 'DAGGERHEART.WeaponFeature.Whipcrack.Description'
}, },
hook: { hook: {
label: "DAGGERHEART.WeaponFeature.Hook.Name", label: 'DAGGERHEART.WeaponFeature.Hook.Name',
description: "DAGGERHEART.WeaponFeature.Hook.Description", description: 'DAGGERHEART.WeaponFeature.Hook.Description'
}, },
doubleDuty: { doubleDuty: {
label: "DAGGERHEART.WeaponFeature.DoubleDuty.Name", label: 'DAGGERHEART.WeaponFeature.DoubleDuty.Name',
description: "DAGGERHEART.WeaponFeature.DoubleDuty.Description", description: 'DAGGERHEART.WeaponFeature.DoubleDuty.Description'
}, },
parry: { parry: {
label: "DAGGERHEART.WeaponFeature.Parry.Name", label: 'DAGGERHEART.WeaponFeature.Parry.Name',
description: "DAGGERHEART.WeaponFeature.Parry.Description", description: 'DAGGERHEART.WeaponFeature.Parry.Description'
}, },
retrieve: { retrieve: {
label: "DAGGERHEART.WeaponFeature.Retrieve.Name", label: 'DAGGERHEART.WeaponFeature.Retrieve.Name',
description: "DAGGERHEART.WeaponFeature.Retrieve.Description", description: 'DAGGERHEART.WeaponFeature.Retrieve.Description'
}, },
deflecting: { deflecting: {
label: "DAGGERHEART.WeaponFeature.Deflecting.Name", label: 'DAGGERHEART.WeaponFeature.Deflecting.Name',
description: "DAGGERHEART.WeaponFeature.Deflecting.Description", description: 'DAGGERHEART.WeaponFeature.Deflecting.Description'
}, },
chargedAttack: { chargedAttack: {
label: "DAGGERHEART.WeaponFeature.ChargedAttack.Name", label: 'DAGGERHEART.WeaponFeature.ChargedAttack.Name',
description: "DAGGERHEART.WeaponFeature.ChargedAttack.Description", description: 'DAGGERHEART.WeaponFeature.ChargedAttack.Description'
}, },
sheltering: { sheltering: {
label: "DAGGERHEART.WeaponFeature.Sheltering.Name", label: 'DAGGERHEART.WeaponFeature.Sheltering.Name',
description: "DAGGERHEART.WeaponFeature.Sheltering.Description", description: 'DAGGERHEART.WeaponFeature.Sheltering.Description'
}, },
doubledUp: { doubledUp: {
label: "DAGGERHEART.WeaponFeature.DoubledUp.Name", label: 'DAGGERHEART.WeaponFeature.DoubledUp.Name',
description: "DAGGERHEART.WeaponFeature.DoubledUp.Description", description: 'DAGGERHEART.WeaponFeature.DoubledUp.Description'
}, },
lockedOn: { lockedOn: {
label: "DAGGERHEART.WeaponFeature.LockedOn.Name", label: 'DAGGERHEART.WeaponFeature.LockedOn.Name',
description: "DAGGERHEART.WeaponFeature.LockedOn.Description", description: 'DAGGERHEART.WeaponFeature.LockedOn.Description'
}, }
}; };
export const featureTypes = { export const featureTypes = {
ancestry: { ancestry: {
id: "ancestry", id: 'ancestry',
label: "DAGGERHEART.Feature.Type.Ancestry" label: 'DAGGERHEART.Feature.Type.Ancestry'
}, },
community: { community: {
id: "community", id: 'community',
label: "DAGGERHEART.Feature.Type.Community" label: 'DAGGERHEART.Feature.Type.Community'
}, },
class: { class: {
id: "class", id: 'class',
label: "DAGGERHEART.Feature.Type.Class" label: 'DAGGERHEART.Feature.Type.Class'
}, },
subclass: { subclass: {
id: "subclass", id: 'subclass',
label: "DAGGERHEART.Feature.Type.Subclass" label: 'DAGGERHEART.Feature.Type.Subclass'
}, }
} };
export const valueTypes = { export const valueTypes = {
normal: { normal: {
id: 'normal', id: 'normal',
name: "DAGGERHEART.Feature.ValueType.Normal", name: 'DAGGERHEART.Feature.ValueType.Normal',
data: { data: {
value: 0, value: 0,
max: 0, max: 0
} }
}, },
input: { input: {
id: 'input', id: 'input',
name: "DAGGERHEART.Feature.ValueType.Input", name: 'DAGGERHEART.Feature.ValueType.Input',
data: { data: {
value: null, value: null
} }
}, },
dice: { dice: {
id: 'dice', id: 'dice',
name: "DAGGERHEART.Feature.ValueType.Dice", name: 'DAGGERHEART.Feature.ValueType.Dice',
data: { data: {
value: null, value: null
} }
} }
} };
export const actionTypes = { export const actionTypes = {
passive: { passive: {
id: "passive", id: 'passive',
label: "DAGGERHEART.ActionType.Passive" label: 'DAGGERHEART.ActionType.Passive'
}, },
action: { action: {
id: "action", id: 'action',
label: "DAGGERHEART.ActionType.Action" label: 'DAGGERHEART.ActionType.Action'
}, },
reaction: { reaction: {
id: "reaction", id: 'reaction',
label: "DAGGERHEART.ActionType.Reaction" label: 'DAGGERHEART.ActionType.Reaction'
} }
}; };

View file

@ -1,28 +1,28 @@
export const menu = { export const menu = {
Automation: { Automation: {
Name: "GameSettingsAutomation", Name: 'GameSettingsAutomation',
Icon: "fa-solid fa-robot", Icon: 'fa-solid fa-robot'
}, },
Homebrew: { Homebrew: {
Name: "GameSettingsHomebrew", Name: 'GameSettingsHomebrew',
Icon: "fa-solid fa-flask-vial", Icon: 'fa-solid fa-flask-vial'
}, },
Range: { Range: {
Name: "GameSettingsRange", Name: 'GameSettingsRange',
Icon: "fa-solid fa-ruler", Icon: 'fa-solid fa-ruler'
}, }
}; };
export const gameSettings = { export const gameSettings = {
Automation: { Automation: {
Hope: "AutomationHope", Hope: 'AutomationHope',
ActionPoints: "AutomationActionPoints", ActionPoints: 'AutomationActionPoints'
}, },
Resources: { Resources: {
Fear: "ResourcesFear" Fear: 'ResourcesFear'
}, },
General: { General: {
AbilityArray: "AbilityArray", AbilityArray: 'AbilityArray',
RangeMeasurement: "RangeMeasurement", RangeMeasurement: 'RangeMeasurement'
} }
} };

View file

@ -1,12 +1,12 @@
import * as GENERAL from './generalConfig.mjs'; import * as GENERAL from './generalConfig.mjs';
import * as DOMAIN from "./domainConfig.mjs"; import * as DOMAIN from './domainConfig.mjs';
import * as ACTOR from './actorConfig.mjs'; import * as ACTOR from './actorConfig.mjs';
import * as ITEM from './itemConfig.mjs'; import * as ITEM from './itemConfig.mjs';
import * as SETTINGS from './settingsConfig.mjs'; import * as SETTINGS from './settingsConfig.mjs';
import * as EFFECTS from './effectConfig.mjs'; import * as EFFECTS from './effectConfig.mjs';
import * as ACTIONS from './actionConfig.mjs'; import * as ACTIONS from './actionConfig.mjs';
export const SYSTEM_ID = "daggerheart"; export const SYSTEM_ID = 'daggerheart';
export const SYSTEM = { export const SYSTEM = {
id: SYSTEM_ID, id: SYSTEM_ID,
@ -16,5 +16,5 @@ export const SYSTEM = {
ITEM, ITEM,
SETTINGS, SETTINGS,
EFFECTS, EFFECTS,
ACTIONS, ACTIONS
}; };

View file

@ -15,4 +15,4 @@ export { default as DhpArmor } from './armor.mjs';
export { default as DhpDualityRoll } from './dualityRoll.mjs'; export { default as DhpDualityRoll } from './dualityRoll.mjs';
export { default as DhpAdversaryRoll } from './adversaryRoll.mjs'; export { default as DhpAdversaryRoll } from './adversaryRoll.mjs';
export { default as DhpAbilityUse } from './abilityUse.mjs'; export { default as DhpAbilityUse } from './abilityUse.mjs';
export { default as DhpEnvironment } from './environment.mjs'; export { default as DhpEnvironment } from './environment.mjs';

View file

@ -1,30 +1,32 @@
export default class DhpAbilityUse extends foundry.abstract.TypeDataModel { export default class DhpAbilityUse extends foundry.abstract.TypeDataModel {
static defineSchema() { static defineSchema() {
const fields = foundry.data.fields; const fields = foundry.data.fields;
return { return {
title: new fields.StringField({}), title: new fields.StringField({}),
img: new fields.StringField({}), img: new fields.StringField({}),
name: new fields.StringField({}), name: new fields.StringField({}),
description: new fields.StringField({}), description: new fields.StringField({}),
actions: new fields.ArrayField(new fields.SchemaField({ actions: new fields.ArrayField(
name: new fields.StringField({}), new fields.SchemaField({
damage: new fields.SchemaField({ name: new fields.StringField({}),
type: new fields.StringField({}), damage: new fields.SchemaField({
value: new fields.StringField({}), type: new fields.StringField({}),
}), value: new fields.StringField({})
healing: new fields.SchemaField({ }),
type: new fields.StringField({}), healing: new fields.SchemaField({
value: new fields.StringField({}), type: new fields.StringField({}),
}), value: new fields.StringField({})
cost: new fields.SchemaField({ }),
type: new fields.StringField({ nullable: true }), cost: new fields.SchemaField({
value: new fields.NumberField({ nullable: true }), type: new fields.StringField({ nullable: true }),
}), value: new fields.NumberField({ nullable: true })
target: new fields.SchemaField({ }),
type: new fields.StringField({}), target: new fields.SchemaField({
}), type: new fields.StringField({})
})), })
} })
)
};
} }
} }

View file

@ -1,38 +1,43 @@
export default class DaggerheartAction extends foundry.abstract.DataModel { export default class DaggerheartAction extends foundry.abstract.DataModel {
static defineSchema() { static defineSchema() {
const fields = foundry.data.fields; const fields = foundry.data.fields;
return { return {
id: new fields.StringField({}), id: new fields.StringField({}),
name: new fields.StringField({ initial: 'New Action' }), name: new fields.StringField({ initial: 'New Action' }),
damage: new fields.SchemaField({ damage: new fields.SchemaField({
type: new fields.StringField({ choices: SYSTEM.GENERAL.damageTypes, nullable: true, initial: null }), type: new fields.StringField({ choices: SYSTEM.GENERAL.damageTypes, nullable: true, initial: null }),
value: new fields.StringField({}), value: new fields.StringField({})
}), }),
healing: new fields.SchemaField({ healing: new fields.SchemaField({
type: new fields.StringField({ choices: SYSTEM.GENERAL.healingTypes, nullable: true, initial: null }), type: new fields.StringField({ choices: SYSTEM.GENERAL.healingTypes, nullable: true, initial: null }),
value: new fields.StringField(), value: new fields.StringField()
}), }),
conditions: new fields.ArrayField(new fields.SchemaField({ conditions: new fields.ArrayField(
name: new fields.StringField(), new fields.SchemaField({
icon: new fields.StringField(), name: new fields.StringField(),
description: new fields.StringField(), icon: new fields.StringField(),
})), description: new fields.StringField()
cost: new fields.SchemaField({ })
type: new fields.StringField({ choices: SYSTEM.GENERAL.abilityCosts, nullable: true, initial: null }), ),
value: new fields.NumberField({ nullable: true, initial: null }), cost: new fields.SchemaField({
}), type: new fields.StringField({ choices: SYSTEM.GENERAL.abilityCosts, nullable: true, initial: null }),
target: new fields.SchemaField({ value: new fields.NumberField({ nullable: true, initial: null })
type: new fields.StringField({ choices: SYSTEM.ACTIONS.targetTypes, initial: SYSTEM.ACTIONS.targetTypes.other.id }) }),
}), target: new fields.SchemaField({
// uses: new fields.SchemaField({ type: new fields.StringField({
// nr: new fields.StringField({}), choices: SYSTEM.ACTIONS.targetTypes,
// refreshType: new fields.StringField({ choices: SYSTEM.GENERAL.refreshTypes, initial: SYSTEM.GENERAL.refreshTypes.session.id }), initial: SYSTEM.ACTIONS.targetTypes.other.id
// refreshed: new fields.BooleanField({ initial: true }), })
// }), })
} // uses: new fields.SchemaField({
// nr: new fields.StringField({}),
// refreshType: new fields.StringField({ choices: SYSTEM.GENERAL.refreshTypes, initial: SYSTEM.GENERAL.refreshTypes.session.id }),
// refreshed: new fields.BooleanField({ initial: true }),
// }),
};
} }
use = async () => { use = async () => {
console.log('Test Use'); console.log('Test Use');
}; };
} }

View file

@ -1,48 +1,54 @@
import { MappingField } from "./fields.mjs"; import { MappingField } from './fields.mjs';
export default class DhpAdversary extends foundry.abstract.TypeDataModel { export default class DhpAdversary extends foundry.abstract.TypeDataModel {
static defineSchema() { static defineSchema() {
const fields = foundry.data.fields; const fields = foundry.data.fields;
return { return {
resources: new fields.SchemaField({ resources: new fields.SchemaField({
health: new fields.SchemaField({ health: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true }), value: new fields.NumberField({ initial: 0, integer: true }),
min: new fields.NumberField({ initial: 0, integer: true }), min: new fields.NumberField({ initial: 0, integer: true }),
max: new fields.NumberField({ initial: 0, integer: true }), max: new fields.NumberField({ initial: 0, integer: true })
}), }),
stress: new fields.SchemaField({ stress: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true }), value: new fields.NumberField({ initial: 0, integer: true }),
min: new fields.NumberField({ initial: 0, integer: true }), min: new fields.NumberField({ initial: 0, integer: true }),
max: new fields.NumberField({ initial: 0, integer: true }), max: new fields.NumberField({ initial: 0, integer: true })
}), })
}), }),
tier: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.tiers), integer: false }), tier: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.tiers), integer: false }),
type: new fields.StringField({ choices: Object.keys(SYSTEM.ACTOR.adversaryTypes), integer: false, initial: Object.keys(SYSTEM.ACTOR.adversaryTypes).find(x => x === 'standard') }), type: new fields.StringField({
description: new fields.StringField({}), choices: Object.keys(SYSTEM.ACTOR.adversaryTypes),
motivesAndTactics: new fields.ArrayField(new fields.StringField({})), integer: false,
attackModifier: new fields.NumberField({ integer: true, nullabe: true, initial: null }), initial: Object.keys(SYSTEM.ACTOR.adversaryTypes).find(x => x === 'standard')
attack: new fields.SchemaField({ }),
name: new fields.StringField({}), description: new fields.StringField({}),
range: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.range), integer: false }), motivesAndTactics: new fields.ArrayField(new fields.StringField({})),
damage: new fields.SchemaField({ attackModifier: new fields.NumberField({ integer: true, nullabe: true, initial: null }),
value: new fields.StringField({}), attack: new fields.SchemaField({
type: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.damageTypes), integer: false }), name: new fields.StringField({}),
}) range: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.range), integer: false }),
}), damage: new fields.SchemaField({
difficulty: new fields.NumberField({ initial: 1, integer: true }), value: new fields.StringField({}),
damageThresholds: new fields.SchemaField({ type: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.damageTypes), integer: false })
minor: new fields.NumberField({ initial: 0, integer: true }), })
major: new fields.NumberField({ initial: 0, integer: true }), }),
severe: new fields.NumberField({ initial: 0, integer: true }), difficulty: new fields.NumberField({ initial: 1, integer: true }),
}), damageThresholds: new fields.SchemaField({
experiences: new fields.ArrayField(new fields.SchemaField({ minor: new fields.NumberField({ initial: 0, integer: true }),
name: new fields.StringField({}), major: new fields.NumberField({ initial: 0, integer: true }),
value: new fields.NumberField({ integer: true, nullable: true, initial: null }), severe: new fields.NumberField({ initial: 0, integer: true })
})), }),
} experiences: new fields.ArrayField(
new fields.SchemaField({
name: new fields.StringField({}),
value: new fields.NumberField({ integer: true, nullable: true, initial: null })
})
)
};
} }
get moves(){ get moves() {
return this.parent.items.filter(x => x.type === 'feature'); return this.parent.items.filter(x => x.type === 'feature');
} }
} }

View file

@ -1,50 +1,59 @@
export default class DhpAdversaryRoll extends foundry.abstract.TypeDataModel { export default class DhpAdversaryRoll extends foundry.abstract.TypeDataModel {
static defineSchema() { static defineSchema() {
const fields = foundry.data.fields; const fields = foundry.data.fields;
return { return {
roll: new fields.StringField({}), roll: new fields.StringField({}),
total: new fields.NumberField({ integer: true }), total: new fields.NumberField({ integer: true }),
modifiers: new fields.ArrayField(new fields.SchemaField({ modifiers: new fields.ArrayField(
value: new fields.NumberField({ integer: true }), new fields.SchemaField({
label: new fields.StringField({}), value: new fields.NumberField({ integer: true }),
title: new fields.StringField({}), label: new fields.StringField({}),
})), title: new fields.StringField({})
diceResults: new fields.ArrayField(new fields.SchemaField({ })
value: new fields.NumberField({ integer: true }), ),
discarded: new fields.BooleanField({ initial: false }), diceResults: new fields.ArrayField(
})), new fields.SchemaField({
targets: new fields.ArrayField(new fields.SchemaField({ value: new fields.NumberField({ integer: true }),
id: new fields.StringField({}), discarded: new fields.BooleanField({ initial: false })
name: new fields.StringField({}), })
img: new fields.StringField({}), ),
difficulty: new fields.NumberField({ integer: true, nullable: true }), targets: new fields.ArrayField(
evasion: new fields.NumberField({ integer: true }), new fields.SchemaField({
hit: new fields.BooleanField({ initial: false }), id: new fields.StringField({}),
})), name: new fields.StringField({}),
damage: new fields.SchemaField({ img: new fields.StringField({}),
value: new fields.StringField({}), difficulty: new fields.NumberField({ integer: true, nullable: true }),
type: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.damageTypes), integer: false }), evasion: new fields.NumberField({ integer: true }),
}, { nullable: true, initial: null }) hit: new fields.BooleanField({ initial: false })
} })
),
damage: new fields.SchemaField(
{
value: new fields.StringField({}),
type: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.damageTypes), integer: false })
},
{ nullable: true, initial: null }
)
};
} }
prepareDerivedData(){ prepareDerivedData() {
const diceKeys = Object.keys(this.diceResults); const diceKeys = Object.keys(this.diceResults);
const highestIndex = 0; const highestIndex = 0;
for(var index in diceKeys){ for (var index in diceKeys) {
const resultIndex = Number.parseInt(index); const resultIndex = Number.parseInt(index);
if(highestIndex === resultIndex) continue; if (highestIndex === resultIndex) continue;
const current = this.diceResults[resultIndex]; const current = this.diceResults[resultIndex];
const highest = this.diceResults[highestIndex]; const highest = this.diceResults[highestIndex];
if(current.value > highest.value) this.diceResults[highestIndex].discarded = true; if (current.value > highest.value) this.diceResults[highestIndex].discarded = true;
else this.diceResults[resultIndex].discarded = true; else this.diceResults[resultIndex].discarded = true;
} }
this.targets.forEach(target => { this.targets.forEach(target => {
target.hit = target.difficulty ? this.total >= target.difficulty : this.total >= target.evasion; target.hit = target.difficulty ? this.total >= target.difficulty : this.total >= target.evasion;
}); });
} }
} }

View file

@ -1,11 +1,11 @@
import featuresSchema from "./interface/featuresSchema.mjs"; import featuresSchema from './interface/featuresSchema.mjs';
export default class DhpAncestry extends foundry.abstract.TypeDataModel { export default class DhpAncestry extends foundry.abstract.TypeDataModel {
static defineSchema() { static defineSchema() {
const fields = foundry.data.fields; const fields = foundry.data.fields;
return { return {
description: new fields.HTMLField({}), description: new fields.HTMLField({}),
abilities: featuresSchema(), abilities: featuresSchema()
} };
} }
} }

View file

@ -1,49 +1,47 @@
export default class DhpArmor extends foundry.abstract.TypeDataModel { export default class DhpArmor extends foundry.abstract.TypeDataModel {
static defineSchema() { static defineSchema() {
const fields = foundry.data.fields; const fields = foundry.data.fields;
return { return {
baseScore: new fields.NumberField({ initial: 1, integer: true }), baseScore: new fields.NumberField({ initial: 1, integer: true }),
feature: new fields.StringField({ feature: new fields.StringField({
choices: SYSTEM.ITEM.armorFeatures, choices: SYSTEM.ITEM.armorFeatures,
integer: false, integer: false,
blank: true, blank: true
}), }),
marks: new fields.SchemaField({ marks: new fields.SchemaField({
max: new fields.NumberField({ initial: 6, integer: true }), max: new fields.NumberField({ initial: 6, integer: true }),
value: new fields.NumberField({ initial: 0, integer: true }), value: new fields.NumberField({ initial: 0, integer: true })
}), }),
baseThresholds: new fields.SchemaField({ baseThresholds: new fields.SchemaField({
major: new fields.NumberField({ initial: 0, integer: true }), major: new fields.NumberField({ initial: 0, integer: true }),
severe: new fields.NumberField({ initial: 0, integer: true }), severe: new fields.NumberField({ initial: 0, integer: true })
}), }),
description: new fields.HTMLField({}), description: new fields.HTMLField({})
}; };
}
get featureInfo() {
return this.feature
? CONFIG.daggerheart.ITEM.armorFeatures[this.feature]
: null;
}
prepareDerivedData() {
if (this.parent.parent) {
this.applyLevels();
} }
}
// Currently bugged as it double triggers. Should get fixed in an updated foundry version. get featureInfo() {
applyLevels() { return this.feature ? CONFIG.daggerheart.ITEM.armorFeatures[this.feature] : null;
// let armorBonus = 0; }
// for(var level in this.parent.parent.system.levelData.levelups){
// var levelData = this.parent.parent.system.levelData.levelups[level]; prepareDerivedData() {
// for(var tier in levelData){ if (this.parent.parent) {
// var tierData = levelData[tier]; this.applyLevels();
// if(tierData){ }
// armorBonus += Object.keys(tierData.armorOrEvasionSlot).filter(x => tierData.armorOrEvasionSlot[x] === 'armor').length; }
// }
// } // Currently bugged as it double triggers. Should get fixed in an updated foundry version.
// } applyLevels() {
// this.marks.max += armorBonus; // let armorBonus = 0;
} // for(var level in this.parent.parent.system.levelData.levelups){
// var levelData = this.parent.parent.system.levelData.levelups[level];
// for(var tier in levelData){
// var tierData = levelData[tier];
// if(tierData){
// armorBonus += Object.keys(tierData.armorOrEvasionSlot).filter(x => tierData.armorOrEvasionSlot[x] === 'armor').length;
// }
// }
// }
// this.marks.max += armorBonus;
}
} }

View file

@ -1,93 +1,117 @@
import { getTier } from "../helpers/utils.mjs"; import { getTier } from '../helpers/utils.mjs';
import DhpFeature from "./feature.mjs"; import DhpFeature from './feature.mjs';
export default class DhpClass extends foundry.abstract.TypeDataModel { export default class DhpClass extends foundry.abstract.TypeDataModel {
static defineSchema() { static defineSchema() {
const fields = foundry.data.fields; const fields = foundry.data.fields;
return { return {
domains: new fields.ArrayField(new fields.StringField({})), domains: new fields.ArrayField(new fields.StringField({})),
classItems: new fields.ArrayField(new fields.SchemaField({ classItems: new fields.ArrayField(
name: new fields.StringField({}), new fields.SchemaField({
img: new fields.StringField({}), name: new fields.StringField({}),
uuid: new fields.StringField({}), img: new fields.StringField({}),
})), uuid: new fields.StringField({})
damageThresholds: new fields.SchemaField({ })
minor: new fields.NumberField({ initial: 0, integer: true }), ),
major: new fields.NumberField({ initial: 0, integer: true }), damageThresholds: new fields.SchemaField({
severe: new fields.NumberField({ initial: 0, integer: true }), minor: new fields.NumberField({ initial: 0, integer: true }),
}), major: new fields.NumberField({ initial: 0, integer: true }),
evasion: new fields.NumberField({ initial: 0, integer: true}), severe: new fields.NumberField({ initial: 0, integer: true })
features: new fields.ArrayField(new fields.SchemaField({ }),
name: new fields.StringField({}), evasion: new fields.NumberField({ initial: 0, integer: true }),
img: new fields.StringField({}), features: new fields.ArrayField(
uuid: new fields.StringField({}), new fields.SchemaField({
})), name: new fields.StringField({}),
subclasses: new fields.ArrayField(new fields.SchemaField({ img: new fields.StringField({}),
name: new fields.StringField({}), uuid: new fields.StringField({})
img: new fields.StringField({}), })
uuid: new fields.StringField({}), ),
})), subclasses: new fields.ArrayField(
inventory: new fields.SchemaField({ new fields.SchemaField({
take: new fields.ArrayField(new fields.SchemaField({ name: new fields.StringField({}),
name: new fields.StringField({}), img: new fields.StringField({}),
img: new fields.StringField({}), uuid: new fields.StringField({})
uuid: new fields.StringField({}), })
})), ),
choiceA: new fields.ArrayField(new fields.SchemaField({ inventory: new fields.SchemaField({
name: new fields.StringField({}), take: new fields.ArrayField(
img: new fields.StringField({}), new fields.SchemaField({
uuid: new fields.StringField({}), name: new fields.StringField({}),
})), img: new fields.StringField({}),
choiceB: new fields.ArrayField(new fields.SchemaField({ uuid: new fields.StringField({})
name: new fields.StringField({}), })
img: new fields.StringField({}), ),
uuid: new fields.StringField({}), choiceA: new fields.ArrayField(
})), new fields.SchemaField({
extra: new fields.SchemaField({ name: new fields.StringField({}),
title: new fields.StringField({}), img: new fields.StringField({}),
description: new fields.StringField({}) uuid: new fields.StringField({})
}, { initial: null, nullable: true }), })
}), ),
characterGuide: new fields.SchemaField({ choiceB: new fields.ArrayField(
suggestedTraits: new fields.SchemaField({ new fields.SchemaField({
agility: new fields.NumberField({ initial: 0, integer: true }), name: new fields.StringField({}),
strength: new fields.NumberField({ initial: 0, integer: true }), img: new fields.StringField({}),
finesse: new fields.NumberField({ initial: 0, integer: true }), uuid: new fields.StringField({})
instinct: new fields.NumberField({ initial: 0, integer: true }), })
presence: new fields.NumberField({ initial: 0, integer: true }), ),
knowledge: new fields.NumberField({ initial: 0, integer: true }), extra: new fields.SchemaField(
}), {
suggestedPrimaryWeapon: new fields.SchemaField({ title: new fields.StringField({}),
name: new fields.StringField({}), description: new fields.StringField({})
img: new fields.StringField({}), },
uuid: new fields.StringField({}), { initial: null, nullable: true }
}, { initial: null, nullable: true }), )
suggestedSecondaryWeapon: new fields.SchemaField({ }),
name: new fields.StringField({}), characterGuide: new fields.SchemaField({
img: new fields.StringField({}), suggestedTraits: new fields.SchemaField({
uuid: new fields.StringField({}), agility: new fields.NumberField({ initial: 0, integer: true }),
}, { initial: null, nullable: true }), strength: new fields.NumberField({ initial: 0, integer: true }),
suggestedArmor: new fields.SchemaField({ finesse: new fields.NumberField({ initial: 0, integer: true }),
name: new fields.StringField({}), instinct: new fields.NumberField({ initial: 0, integer: true }),
img: new fields.StringField({}), presence: new fields.NumberField({ initial: 0, integer: true }),
uuid: new fields.StringField({}), knowledge: new fields.NumberField({ initial: 0, integer: true })
}, { initial: null, nullable: true }), }),
characterDescription: new fields.SchemaField({ suggestedPrimaryWeapon: new fields.SchemaField(
clothes: new fields.StringField({}), {
eyes: new fields.StringField({}), name: new fields.StringField({}),
body: new fields.StringField({}), img: new fields.StringField({}),
color: new fields.StringField({}), uuid: new fields.StringField({})
attitude: new fields.StringField({}), },
}), { initial: null, nullable: true }
backgroundQuestions: new fields.ArrayField(new fields.StringField({}), { initial: ['', '', ''] }), ),
connections: new fields.ArrayField(new fields.StringField({}), { initial: ['', '' ,''] }), suggestedSecondaryWeapon: new fields.SchemaField(
}), {
multiclass: new fields.NumberField({ initial: null, nullable: true, integer: true }), name: new fields.StringField({}),
description: new fields.HTMLField({}), img: new fields.StringField({}),
} uuid: new fields.StringField({})
},
{ initial: null, nullable: true }
),
suggestedArmor: new fields.SchemaField(
{
name: new fields.StringField({}),
img: new fields.StringField({}),
uuid: new fields.StringField({})
},
{ initial: null, nullable: true }
),
characterDescription: new fields.SchemaField({
clothes: new fields.StringField({}),
eyes: new fields.StringField({}),
body: new fields.StringField({}),
color: new fields.StringField({}),
attitude: new fields.StringField({})
}),
backgroundQuestions: new fields.ArrayField(new fields.StringField({}), { initial: ['', '', ''] }),
connections: new fields.ArrayField(new fields.StringField({}), { initial: ['', '', ''] })
}),
multiclass: new fields.NumberField({ initial: null, nullable: true, integer: true }),
description: new fields.HTMLField({})
};
} }
get multiclassTier(){ get multiclassTier() {
return getTier(this.multiclass, true); return getTier(this.multiclass, true);
} }
} }

View file

@ -1,9 +1,9 @@
export default class DhpCombat extends foundry.abstract.TypeDataModel { export default class DhpCombat extends foundry.abstract.TypeDataModel {
static defineSchema() { static defineSchema() {
const fields = foundry.data.fields; const fields = foundry.data.fields;
return { return {
actions: new fields.NumberField({ initial: 0, integer: true }), actions: new fields.NumberField({ initial: 0, integer: true }),
activeCombatant: new fields.StringField({}), activeCombatant: new fields.StringField({})
} };
} }
} }

View file

@ -1,8 +1,8 @@
export default class DhpCombatant extends foundry.abstract.TypeDataModel { export default class DhpCombatant extends foundry.abstract.TypeDataModel {
static defineSchema() { static defineSchema() {
const fields = foundry.data.fields; const fields = foundry.data.fields;
return { return {
active: new fields.BooleanField({ initial: false }) active: new fields.BooleanField({ initial: false })
} };
} }
} }

View file

@ -1,11 +1,11 @@
import featuresSchema from "./interface/featuresSchema.mjs"; import featuresSchema from './interface/featuresSchema.mjs';
export default class DhpCommunity extends foundry.abstract.TypeDataModel { export default class DhpCommunity extends foundry.abstract.TypeDataModel {
static defineSchema() { static defineSchema() {
const fields = foundry.data.fields; const fields = foundry.data.fields;
return { return {
description: new fields.HTMLField({}), description: new fields.HTMLField({}),
abilities: featuresSchema(), abilities: featuresSchema()
} };
} }
} }

View file

@ -1,10 +1,10 @@
export default class DhpConsumable extends foundry.abstract.TypeDataModel { export default class DhpConsumable extends foundry.abstract.TypeDataModel {
static defineSchema() { static defineSchema() {
const fields = foundry.data.fields; const fields = foundry.data.fields;
return { return {
description: new fields.HTMLField({}), description: new fields.HTMLField({}),
quantity: new fields.NumberField({ initial: 1, integer: true }), quantity: new fields.NumberField({ initial: 1, integer: true }),
consumeOnUse: new fields.BooleanField({ initial: false }), consumeOnUse: new fields.BooleanField({ initial: false })
} };
} }
} }

View file

@ -1,17 +1,23 @@
import DaggerheartAction from "./action.mjs"; import DaggerheartAction from './action.mjs';
export default class DhpDomainCard extends foundry.abstract.TypeDataModel { export default class DhpDomainCard extends foundry.abstract.TypeDataModel {
static defineSchema() { static defineSchema() {
const fields = foundry.data.fields; const fields = foundry.data.fields;
return { return {
domain: new fields.StringField({ choices: SYSTEM.DOMAIN.domains, integer: false }, { required: true, initial: [] }), domain: new fields.StringField(
level: new fields.NumberField({ initial: 1, integer: true }), { choices: SYSTEM.DOMAIN.domains, integer: false },
recallCost: new fields.NumberField({ initial: 0, integer: true }), { required: true, initial: [] }
type: new fields.StringField({ choices: SYSTEM.DOMAIN.cardTypes, integer: false }, { required: true, initial: [] }), ),
foundation: new fields.BooleanField({ initial: false }), level: new fields.NumberField({ initial: 1, integer: true }),
effect: new fields.HTMLField({}), recallCost: new fields.NumberField({ initial: 0, integer: true }),
inVault: new fields.BooleanField({ initial: false }), type: new fields.StringField(
actions: new fields.ArrayField(new fields.EmbeddedDataField(DaggerheartAction)), { choices: SYSTEM.DOMAIN.cardTypes, integer: false },
} { required: true, initial: [] }
),
foundation: new fields.BooleanField({ initial: false }),
effect: new fields.HTMLField({}),
inVault: new fields.BooleanField({ initial: false }),
actions: new fields.ArrayField(new fields.EmbeddedDataField(DaggerheartAction))
};
} }
} }

View file

@ -1,65 +1,83 @@
const fields = foundry.data.fields; const fields = foundry.data.fields;
const diceField = () => new fields.SchemaField({ const diceField = () =>
dice: new fields.StringField({}), new fields.SchemaField({
value: new fields.NumberField({ integer: true}), dice: new fields.StringField({}),
}); value: new fields.NumberField({ integer: true })
});
export default class DhpDualityRoll extends foundry.abstract.TypeDataModel { export default class DhpDualityRoll extends foundry.abstract.TypeDataModel {
static defineSchema() { static defineSchema() {
return {
return { roll: new fields.StringField({}),
roll: new fields.StringField({}), modifiers: new fields.ArrayField(
modifiers: new fields.ArrayField(new fields.SchemaField({ new fields.SchemaField({
value: new fields.NumberField({ integer: true }), value: new fields.NumberField({ integer: true }),
label: new fields.StringField({}), label: new fields.StringField({}),
title: new fields.StringField({}), title: new fields.StringField({})
})), })
hope: diceField(), ),
fear: diceField(), hope: diceField(),
advantage: diceField(), fear: diceField(),
disadvantage: diceField(), advantage: diceField(),
advantageSelected: new fields.NumberField({ initial: 0 }), disadvantage: diceField(),
targets: new fields.ArrayField(new fields.SchemaField({ advantageSelected: new fields.NumberField({ initial: 0 }),
id: new fields.StringField({}), targets: new fields.ArrayField(
name: new fields.StringField({}), new fields.SchemaField({
img: new fields.StringField({}), id: new fields.StringField({}),
difficulty: new fields.NumberField({ integer: true, nullable: true }), name: new fields.StringField({}),
evasion: new fields.NumberField({ integer: true }), img: new fields.StringField({}),
hit: new fields.BooleanField({ initial: false }), difficulty: new fields.NumberField({ integer: true, nullable: true }),
})), evasion: new fields.NumberField({ integer: true }),
damage: new fields.SchemaField({ hit: new fields.BooleanField({ initial: false })
value: new fields.StringField({}), })
type: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.damageTypes), integer: false }), ),
bonusDamage: new fields.ArrayField(new fields.SchemaField({ damage: new fields.SchemaField({
value: new fields.StringField({}), value: new fields.StringField({}),
type: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.damageTypes), integer: false }), type: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.damageTypes), integer: false }),
initiallySelected: new fields.BooleanField(), bonusDamage: new fields.ArrayField(
appliesOn: new fields.StringField({ choices: Object.keys(SYSTEM.EFFECTS.applyLocations) }, { nullable: true, initial: null }), new fields.SchemaField({
description: new fields.StringField({}), value: new fields.StringField({}),
hopeIncrease: new fields.StringField({ nullable: true }) type: new fields.StringField({
}), { nullable: true, initial: null }) choices: Object.keys(SYSTEM.GENERAL.damageTypes),
}) integer: false
} }),
initiallySelected: new fields.BooleanField(),
appliesOn: new fields.StringField(
{ choices: Object.keys(SYSTEM.EFFECTS.applyLocations) },
{ nullable: true, initial: null }
),
description: new fields.StringField({}),
hopeIncrease: new fields.StringField({ nullable: true })
}),
{ nullable: true, initial: null }
)
})
};
} }
get total() { get total() {
const modifiers = this.modifiers.reduce((acc, x) => acc+x.value, 0); const modifiers = this.modifiers.reduce((acc, x) => acc + x.value, 0);
const advantage = this.advantage.value ?? this.disadvantage.value ? -this.disadvantage.value : 0; const advantage = (this.advantage.value ?? this.disadvantage.value) ? -this.disadvantage.value : 0;
return this.hope.value + this.fear.value + advantage + modifiers; return this.hope.value + this.fear.value + advantage + modifiers;
} }
get totalLabel() { get totalLabel() {
const label = this.hope.value > this.fear.value ? "DAGGERHEART.General.Hope" : this.fear.value > this.hope.value ? "DAGGERHEART.General.Fear" : "DAGGERHEART.General.CriticalSuccess"; const label =
this.hope.value > this.fear.value
? 'DAGGERHEART.General.Hope'
: this.fear.value > this.hope.value
? 'DAGGERHEART.General.Fear'
: 'DAGGERHEART.General.CriticalSuccess';
return game.i18n.localize(label); return game.i18n.localize(label);
} }
prepareDerivedData(){ prepareDerivedData() {
const total = this.total; const total = this.total;
this.targets.forEach(target => { this.targets.forEach(target => {
target.hit = target.difficulty ? total >= target.difficulty : total >= target.evasion; target.hit = target.difficulty ? total >= target.difficulty : total >= target.evasion;
}); });
} }
} }
@ -110,7 +128,7 @@ export default class DhpDualityRoll extends foundry.abstract.TypeDataModel {
// get total() { // get total() {
// const modifiers = this.modifiers.reduce((acc, x) => acc+x.value, 0); // const modifiers = this.modifiers.reduce((acc, x) => acc+x.value, 0);
// const regular = { // const regular = {
// normal: this.disadvantage.value ? Math.min(this.disadvantage.value, this.hope.value) + this.fear.value + modifiers : this.hope.value + this.fear.value + modifiers, // normal: this.disadvantage.value ? Math.min(this.disadvantage.value, this.hope.value) + this.fear.value + modifiers : this.hope.value + this.fear.value + modifiers,
// alternate: this.advantage.value ? this.advantage.value + this.fear.value + modifiers : null, // alternate: this.advantage.value ? this.advantage.value + this.fear.value + modifiers : null,
// }; // };
@ -126,7 +144,7 @@ export default class DhpDualityRoll extends foundry.abstract.TypeDataModel {
// get totalLabel() { // get totalLabel() {
// if(this.advantage.value && this.advantageSelected === 0) return game.i18n.localize("DAGGERHEART.Chat.DualityRoll.AdvantageChooseTitle"); // if(this.advantage.value && this.advantageSelected === 0) return game.i18n.localize("DAGGERHEART.Chat.DualityRoll.AdvantageChooseTitle");
// const hope = !this.advantage.value || this.advantageSelected === 1 ? this.hope.value : this.advantage.value; // const hope = !this.advantage.value || this.advantageSelected === 1 ? this.hope.value : this.advantage.value;
// const label = hope > this.fear.value ? "DAGGERHEART.General.Hope" : this.fear.value > hope ? "DAGGERHEART.General.Fear" : "DAGGERHEART.General.CriticalSuccess"; // const label = hope > this.fear.value ? "DAGGERHEART.General.Hope" : this.fear.value > hope ? "DAGGERHEART.General.Fear" : "DAGGERHEART.General.CriticalSuccess";
// return game.i18n.localize(label); // return game.i18n.localize(label);
@ -147,4 +165,4 @@ export default class DhpDualityRoll extends foundry.abstract.TypeDataModel {
// target.hit = target.difficulty ? total.normal >= target.difficulty : total.normal >= target.evasion; // target.hit = target.difficulty ? total.normal >= target.difficulty : total.normal >= target.evasion;
// }); // });
// } // }
// } // }

View file

@ -1,20 +1,22 @@
export default class DhpEnvironment extends foundry.abstract.TypeDataModel { export default class DhpEnvironment extends foundry.abstract.TypeDataModel {
static defineSchema() { static defineSchema() {
const fields = foundry.data.fields; const fields = foundry.data.fields;
return { return {
resources: new fields.SchemaField({ resources: new fields.SchemaField({}),
tier: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.tiers), integer: false }),
}), type: new fields.StringField({
tier: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.tiers), integer: false }), choices: Object.keys(SYSTEM.ACTOR.adversaryTypes),
type: new fields.StringField({ choices: Object.keys(SYSTEM.ACTOR.adversaryTypes), integer: false, initial: Object.keys(SYSTEM.ACTOR.adversaryTypes).find(x => x === 'standard') }), integer: false,
description: new fields.StringField({}), initial: Object.keys(SYSTEM.ACTOR.adversaryTypes).find(x => x === 'standard')
toneAndFeel: new fields.StringField({}), }),
difficulty: new fields.NumberField({ initial: 1, integer: true }), description: new fields.StringField({}),
potentialAdversaries: new fields.StringField({}), toneAndFeel: new fields.StringField({}),
difficulty: new fields.NumberField({ initial: 1, integer: true }),
potentialAdversaries: new fields.StringField({})
};
} }
}
get features(){ get features() {
return this.parent.items.filter(x => x.type === 'feature'); return this.parent.items.filter(x => x.type === 'feature');
} }
} }

View file

@ -1,77 +1,106 @@
import { getTier } from "../helpers/utils.mjs"; import { getTier } from '../helpers/utils.mjs';
import DaggerheartAction from "./action.mjs"; import DaggerheartAction from './action.mjs';
import { MappingField } from "./fields.mjs"; import { MappingField } from './fields.mjs';
import DhpEffect from "./interface/effects.mjs"; import DhpEffect from './interface/effects.mjs';
export default class DhpFeature extends DhpEffect { export default class DhpFeature extends DhpEffect {
static defineSchema() { static defineSchema() {
const fields = foundry.data.fields; const fields = foundry.data.fields;
return foundry.utils.mergeObject({}, { return foundry.utils.mergeObject(
type: new fields.StringField({ choices: SYSTEM.ITEM.featureTypes }), {},
actionType: new fields.StringField({ choices: SYSTEM.ITEM.actionTypes, initial: SYSTEM.ITEM.actionTypes.passive.id }), {
featureType: new fields.SchemaField({ type: new fields.StringField({ choices: SYSTEM.ITEM.featureTypes }),
type: new fields.StringField({ choices: SYSTEM.ITEM.valueTypes, initial: Object.keys(SYSTEM.ITEM.valueTypes).find(x => x === 'normal') }), actionType: new fields.StringField({
data: new fields.SchemaField({ choices: SYSTEM.ITEM.actionTypes,
value: new fields.StringField({}), initial: SYSTEM.ITEM.actionTypes.passive.id
property: new fields.StringField({ choices: SYSTEM.ACTOR.featureProperties, initial: Object.keys(SYSTEM.ACTOR.featureProperties).find(x => x === 'spellcastingTrait') }), }),
max: new fields.NumberField({ initial: 1, integer: true }), featureType: new fields.SchemaField({
numbers: new MappingField(new fields.SchemaField({ type: new fields.StringField({
value: new fields.NumberField({ integer: true }), choices: SYSTEM.ITEM.valueTypes,
used: new fields.BooleanField({ initial: false }), initial: Object.keys(SYSTEM.ITEM.valueTypes).find(x => x === 'normal')
})), }),
}), data: new fields.SchemaField({
}), value: new fields.StringField({}),
refreshData: new fields.SchemaField({ property: new fields.StringField({
type: new fields.StringField({ choices: SYSTEM.GENERAL.refreshTypes }), choices: SYSTEM.ACTOR.featureProperties,
uses: new fields.NumberField({ initial: 1, integer: true }), initial: Object.keys(SYSTEM.ACTOR.featureProperties).find(x => x === 'spellcastingTrait')
refreshed: new fields.BooleanField({ initial: true }) }),
}, { nullable: true, initial: null }), max: new fields.NumberField({ initial: 1, integer: true }),
multiclass: new fields.NumberField({ initial: null, nullable: true, integer: true }), numbers: new MappingField(
disabled: new fields.BooleanField({ initial: false }), new fields.SchemaField({
description: new fields.HTMLField({}), value: new fields.NumberField({ integer: true }),
effects: new MappingField(new fields.SchemaField({ used: new fields.BooleanField({ initial: false })
type: new fields.StringField({ choices: SYSTEM.EFFECTS.effectTypes }), })
valueType: new fields.StringField({ choices: SYSTEM.EFFECTS.valueTypes }), )
parseType: new fields.StringField({ choices: SYSTEM.EFFECTS.parseTypes }), })
initiallySelected: new fields.BooleanField({ initial: true }), }),
options: new fields.ArrayField(new fields.SchemaField({ refreshData: new fields.SchemaField(
name: new fields.StringField({}), {
value: new fields.StringField({}), type: new fields.StringField({ choices: SYSTEM.GENERAL.refreshTypes }),
}), { nullable: true, initial: null }), uses: new fields.NumberField({ initial: 1, integer: true }),
dataField: new fields.StringField({}), refreshed: new fields.BooleanField({ initial: true })
appliesOn: new fields.StringField({ choices: SYSTEM.EFFECTS.applyLocations }, { nullable: true, initial: null }), },
applyLocationChoices: new MappingField(new fields.StringField({}), { nullable: true, initial: null }), { nullable: true, initial: null }
valueData: new fields.SchemaField({ ),
value: new fields.StringField({}), multiclass: new fields.NumberField({ initial: null, nullable: true, integer: true }),
fromValue: new fields.StringField({ initial: null, nullable: true }), disabled: new fields.BooleanField({ initial: false }),
type: new fields.StringField({ initial: null, nullable: true }), description: new fields.HTMLField({}),
hopeIncrease: new fields.StringField({ initial: null, nullable: true }) effects: new MappingField(
}), new fields.SchemaField({
})), type: new fields.StringField({ choices: SYSTEM.EFFECTS.effectTypes }),
actions: new fields.ArrayField(new fields.EmbeddedDataField(DaggerheartAction)), valueType: new fields.StringField({ choices: SYSTEM.EFFECTS.valueTypes }),
}); parseType: new fields.StringField({ choices: SYSTEM.EFFECTS.parseTypes }),
initiallySelected: new fields.BooleanField({ initial: true }),
options: new fields.ArrayField(
new fields.SchemaField({
name: new fields.StringField({}),
value: new fields.StringField({})
}),
{ nullable: true, initial: null }
),
dataField: new fields.StringField({}),
appliesOn: new fields.StringField(
{ choices: SYSTEM.EFFECTS.applyLocations },
{ nullable: true, initial: null }
),
applyLocationChoices: new MappingField(new fields.StringField({}), {
nullable: true,
initial: null
}),
valueData: new fields.SchemaField({
value: new fields.StringField({}),
fromValue: new fields.StringField({ initial: null, nullable: true }),
type: new fields.StringField({ initial: null, nullable: true }),
hopeIncrease: new fields.StringField({ initial: null, nullable: true })
})
})
),
actions: new fields.ArrayField(new fields.EmbeddedDataField(DaggerheartAction))
}
);
} }
get multiclassTier(){ get multiclassTier() {
return getTier(this.multiclass); return getTier(this.multiclass);
} }
async refresh(){ async refresh() {
if(this.refreshData){ if (this.refreshData) {
if(this.featureType.type === SYSTEM.ITEM.valueTypes.dice.id) { if (this.featureType.type === SYSTEM.ITEM.valueTypes.dice.id) {
const update = { "system.refreshData.refreshed": true }; const update = { 'system.refreshData.refreshed': true };
Object.keys(this.featureType.data.numbers).forEach(x => update[`system.featureType.data.numbers.-=${x}`] = null); Object.keys(this.featureType.data.numbers).forEach(
await this.parent.update(update); x => (update[`system.featureType.data.numbers.-=${x}`] = null)
);
await this.parent.update(update);
} else {
await this.parent.update({ 'system.refreshData.refreshed': true });
}
} }
else {
await this.parent.update({ "system.refreshData.refreshed": true});
}
}
} }
// prepareDerivedData(){ // prepareDerivedData(){
// if(this.featureType.type === SYSTEM.ITEM.valueTypes.dice.id){ // if(this.featureType.type === SYSTEM.ITEM.valueTypes.dice.id){
// this.featureType.numbers = ; // this.featureType.numbers = ;
// } // }
// } // }
} }

View file

@ -1,50 +1,50 @@
export class MappingField extends foundry.data.fields.ObjectField { export class MappingField extends foundry.data.fields.ObjectField {
constructor(model, options) { constructor(model, options) {
if ( !(model instanceof foundry.data.fields.DataField) ) { if (!(model instanceof foundry.data.fields.DataField)) {
throw new Error("MappingField must have a DataField as its contained element"); throw new Error('MappingField must have a DataField as its contained element');
} }
super(options); super(options);
/** /**
* The embedded DataField definition which is contained in this field. * The embedded DataField definition which is contained in this field.
* @type {DataField} * @type {DataField}
*/ */
this.model = model; this.model = model;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @inheritdoc */ /** @inheritdoc */
static get _defaults() { static get _defaults() {
return foundry.utils.mergeObject(super._defaults, { return foundry.utils.mergeObject(super._defaults, {
initialKeys: null, initialKeys: null,
initialValue: null, initialValue: null,
initialKeysOnly: false initialKeysOnly: false
}); });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @inheritdoc */ /** @inheritdoc */
_cleanType(value, options) { _cleanType(value, options) {
Object.entries(value).forEach(([k, v]) => value[k] = this.model.clean(v, options)); Object.entries(value).forEach(([k, v]) => (value[k] = this.model.clean(v, options)));
return value; return value;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @inheritdoc */ /** @inheritdoc */
getInitialValue(data) { getInitialValue(data) {
let keys = this.initialKeys; let keys = this.initialKeys;
const initial = super.getInitialValue(data); const initial = super.getInitialValue(data);
if ( !keys || !foundry.utils.isEmpty(initial) ) return initial; if (!keys || !foundry.utils.isEmpty(initial)) return initial;
if ( !(keys instanceof Array) ) keys = Object.keys(keys); if (!(keys instanceof Array)) keys = Object.keys(keys);
for ( const key of keys ) initial[key] = this._getInitialValueForKey(key); for (const key of keys) initial[key] = this._getInitialValueForKey(key);
return initial; return initial;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/** /**
* Get the initial value for the provided key. * Get the initial value for the provided key.
* @param {string} key Key within the object being built. * @param {string} key Key within the object being built.
@ -52,21 +52,21 @@ export class MappingField extends foundry.data.fields.ObjectField {
* @returns {*} Initial value based on provided field type. * @returns {*} Initial value based on provided field type.
*/ */
_getInitialValueForKey(key, object) { _getInitialValueForKey(key, object) {
const initial = this.model.getInitialValue(); const initial = this.model.getInitialValue();
return this.initialValue?.(key, initial, object) ?? initial; return this.initialValue?.(key, initial, object) ?? initial;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @override */
_validateType(value, options={}) { _validateType(value, options = {}) {
if ( foundry.utils.getType(value) !== "Object" ) throw new Error("must be an Object"); if (foundry.utils.getType(value) !== 'Object') throw new Error('must be an Object');
const errors = this._validateValues(value, options); const errors = this._validateValues(value, options);
if ( !foundry.utils.isEmpty(errors) ) throw new foundry.data.fields.ModelValidationError(errors); if (!foundry.utils.isEmpty(errors)) throw new foundry.data.fields.ModelValidationError(errors);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/** /**
* Validate each value of the object. * Validate each value of the object.
* @param {object} value The object to validate. * @param {object} value The object to validate.
@ -74,36 +74,36 @@ export class MappingField extends foundry.data.fields.ObjectField {
* @returns {Object<Error>} An object of value-specific errors by key. * @returns {Object<Error>} An object of value-specific errors by key.
*/ */
_validateValues(value, options) { _validateValues(value, options) {
const errors = {}; const errors = {};
for ( const [k, v] of Object.entries(value) ) { for (const [k, v] of Object.entries(value)) {
const error = this.model.validate(v, options); const error = this.model.validate(v, options);
if ( error ) errors[k] = error; if (error) errors[k] = error;
} }
return errors; return errors;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @override */
initialize(value, model, options={}) { initialize(value, model, options = {}) {
if ( !value ) return value; if (!value) return value;
const obj = {}; const obj = {};
const initialKeys = (this.initialKeys instanceof Array) ? this.initialKeys : Object.keys(this.initialKeys ?? {}); const initialKeys = this.initialKeys instanceof Array ? this.initialKeys : Object.keys(this.initialKeys ?? {});
const keys = this.initialKeysOnly ? initialKeys : Object.keys(value); const keys = this.initialKeysOnly ? initialKeys : Object.keys(value);
for ( const key of keys ) { for (const key of keys) {
const data = value[key] ?? this._getInitialValueForKey(key, value); const data = value[key] ?? this._getInitialValueForKey(key, value);
obj[key] = this.model.initialize(data, model, options); obj[key] = this.model.initialize(data, model, options);
} }
return obj; return obj;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @inheritdoc */ /** @inheritdoc */
_getField(path) { _getField(path) {
if ( path.length === 0 ) return this; if (path.length === 0) return this;
else if ( path.length === 1 ) return this.model; else if (path.length === 1) return this.model;
path.shift(); path.shift();
return this.model._getField(path); return this.model._getField(path);
} }
} }

View file

@ -1,75 +1,86 @@
import DaggerheartAction from "../action.mjs"; import DaggerheartAction from '../action.mjs';
import { MappingField } from "../fields.mjs"; import { MappingField } from '../fields.mjs';
export default class DhpEffects extends foundry.abstract.TypeDataModel { export default class DhpEffects extends foundry.abstract.TypeDataModel {
static defineSchema() { static defineSchema() {
const fields = foundry.data.fields; const fields = foundry.data.fields;
return { return {
effects: new MappingField(new fields.SchemaField({ effects: new MappingField(
type: new fields.StringField({ choices: Object.keys(SYSTEM.EFFECTS.effectTypes) }), new fields.SchemaField({
valueType: new fields.StringField({ choices: Object.keys(SYSTEM.EFFECTS.valueTypes) }), type: new fields.StringField({ choices: Object.keys(SYSTEM.EFFECTS.effectTypes) }),
parseType: new fields.StringField({ choices: Object.keys(SYSTEM.EFFECTS.parseTypes) }), valueType: new fields.StringField({ choices: Object.keys(SYSTEM.EFFECTS.valueTypes) }),
initiallySelected: new fields.BooleanField({ initial: true }), parseType: new fields.StringField({ choices: Object.keys(SYSTEM.EFFECTS.parseTypes) }),
options: new fields.ArrayField(new fields.SchemaField({ initiallySelected: new fields.BooleanField({ initial: true }),
name: new fields.StringField({}), options: new fields.ArrayField(
value: new fields.StringField({}), new fields.SchemaField({
}), { nullable: true, initial: null }), name: new fields.StringField({}),
dataField: new fields.StringField({}), value: new fields.StringField({})
appliesOn: new fields.StringField({ choices: Object.keys(SYSTEM.EFFECTS.applyLocations) }, { nullable: true, initial: null }), }),
applyLocationChoices: new MappingField(new fields.StringField({}), { nullable: true, initial: null }), { nullable: true, initial: null }
valueData: new fields.SchemaField({ ),
value: new fields.StringField({}), dataField: new fields.StringField({}),
fromValue: new fields.StringField({ initial: null, nullable: true }), appliesOn: new fields.StringField(
type: new fields.StringField({ initial: null, nullable: true }), { choices: Object.keys(SYSTEM.EFFECTS.applyLocations) },
hopeIncrease: new fields.StringField({ initial: null, nullable: true }) { nullable: true, initial: null }
}), ),
})), applyLocationChoices: new MappingField(new fields.StringField({}), {
actions: new fields.ArrayField(new fields.EmbeddedDataField(DaggerheartAction)), nullable: true,
// actions: new fields.SchemaField({ initial: null
// damage: new fields.ArrayField(new fields.SchemaField({ }),
// type: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.extendedDamageTypes), initial: SYSTEM.GENERAL.extendedDamageTypes.physical.id }), valueData: new fields.SchemaField({
// value: new fields.StringField({}), value: new fields.StringField({}),
// })), fromValue: new fields.StringField({ initial: null, nullable: true }),
// uses: new fields.SchemaField({ type: new fields.StringField({ initial: null, nullable: true }),
// nr: new fields.StringField({}), hopeIncrease: new fields.StringField({ initial: null, nullable: true })
// refreshType: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.refreshTypes), initial: SYSTEM.GENERAL.refreshTypes.session.id }), })
// refreshed: new fields.BooleanField({ initial: true }), })
// }), ),
// }), actions: new fields.ArrayField(new fields.EmbeddedDataField(DaggerheartAction))
} // actions: new fields.SchemaField({
// damage: new fields.ArrayField(new fields.SchemaField({
// type: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.extendedDamageTypes), initial: SYSTEM.GENERAL.extendedDamageTypes.physical.id }),
// value: new fields.StringField({}),
// })),
// uses: new fields.SchemaField({
// nr: new fields.StringField({}),
// refreshType: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.refreshTypes), initial: SYSTEM.GENERAL.refreshTypes.session.id }),
// refreshed: new fields.BooleanField({ initial: true }),
// }),
// }),
};
} }
get effectData(){ get effectData() {
const effectValues = Object.values(this.effects); const effectValues = Object.values(this.effects);
const effectCategories = Object.keys(SYSTEM.EFFECTS.effectTypes).reduce((acc, effectType) => { const effectCategories = Object.keys(SYSTEM.EFFECTS.effectTypes).reduce((acc, effectType) => {
acc[effectType] = effectValues.reduce((acc, effect) => { acc[effectType] = effectValues.reduce((acc, effect) => {
if(effect.type === effectType){ if (effect.type === effectType) {
acc.push({ ...effect, valueData: this.#parseValues(effect.parseType, effect.valueData) }); acc.push({ ...effect, valueData: this.#parseValues(effect.parseType, effect.valueData) });
} }
return acc;
}, []);
return acc; return acc;
}, {}); }, []);
return effectCategories; return acc;
}, {});
return effectCategories;
} }
#parseValues(parseType, values){ #parseValues(parseType, values) {
return Object.keys(values).reduce((acc, prop) => { return Object.keys(values).reduce((acc, prop) => {
acc[prop] = this.#parseValue(parseType, values[prop]); acc[prop] = this.#parseValue(parseType, values[prop]);
return acc; return acc;
}, {}); }, {});
} }
#parseValue(parseType, value) { #parseValue(parseType, value) {
switch(parseType){ switch (parseType) {
case SYSTEM.EFFECTS.parseTypes.number.id: case SYSTEM.EFFECTS.parseTypes.number.id:
return Number.parseInt(value); return Number.parseInt(value);
default: default:
return value; return value;
} }
} }
} }

View file

@ -1,10 +1,13 @@
const fields = foundry.data.fields; const fields = foundry.data.fields;
const featuresSchema = () => new fields.ArrayField(new fields.SchemaField({ const featuresSchema = () =>
name: new fields.StringField({}), new fields.ArrayField(
img: new fields.StringField({}), new fields.SchemaField({
uuid: new fields.StringField({}), name: new fields.StringField({}),
subclassLevel: new fields.StringField({}), img: new fields.StringField({}),
})) uuid: new fields.StringField({}),
subclassLevel: new fields.StringField({})
})
);
export default featuresSchema; export default featuresSchema;

View file

@ -1,9 +1,9 @@
export default class DhpMiscellaneous extends foundry.abstract.TypeDataModel { export default class DhpMiscellaneous extends foundry.abstract.TypeDataModel {
static defineSchema() { static defineSchema() {
const fields = foundry.data.fields; const fields = foundry.data.fields;
return { return {
description: new fields.HTMLField({}), description: new fields.HTMLField({}),
quantity: new fields.NumberField({ initial: 1, integer: true }) quantity: new fields.NumberField({ initial: 1, integer: true })
} };
} }
} }

View file

@ -1,36 +1,39 @@
import { getPathValue, getTier } from "../helpers/utils.mjs"; import { getPathValue, getTier } from '../helpers/utils.mjs';
import { MappingField } from "./fields.mjs"; import { MappingField } from './fields.mjs';
const fields = foundry.data.fields; const fields = foundry.data.fields;
const attributeField = () => new fields.SchemaField({ const attributeField = () =>
data: new fields.SchemaField({ new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true }), data: new fields.SchemaField({
base: new fields.NumberField({ initial: 0, integer: true }), value: new fields.NumberField({ initial: 0, integer: true }),
bonus: new fields.NumberField({ initial: 0, integer: true }), base: new fields.NumberField({ initial: 0, integer: true }),
actualValue: new fields.NumberField({ initial: 0, integer: true }), bonus: new fields.NumberField({ initial: 0, integer: true }),
overrideValue: new fields.NumberField({ initial: 0, integer: true }), actualValue: new fields.NumberField({ initial: 0, integer: true }),
}), overrideValue: new fields.NumberField({ initial: 0, integer: true })
levelMarks: new fields.ArrayField(new fields.NumberField({ nullable: true, initial: null, integer: true })), }),
levelMark: new fields.NumberField({ nullable: true, initial: null, integer: true }), levelMarks: new fields.ArrayField(new fields.NumberField({ nullable: true, initial: null, integer: true })),
}); levelMark: new fields.NumberField({ nullable: true, initial: null, integer: true })
});
const levelUpTier = () => ({ const levelUpTier = () => ({
attributes: new MappingField(new fields.BooleanField()), attributes: new MappingField(new fields.BooleanField()),
hitPointSlots: new MappingField(new fields.BooleanField()), hitPointSlots: new MappingField(new fields.BooleanField()),
stressSlots: new MappingField(new fields.BooleanField()), stressSlots: new MappingField(new fields.BooleanField()),
experiences: new MappingField(new fields.ArrayField(new fields.StringField({}))), experiences: new MappingField(new fields.ArrayField(new fields.StringField({}))),
proficiency: new MappingField(new fields.BooleanField()), proficiency: new MappingField(new fields.BooleanField()),
armorOrEvasionSlot: new MappingField(new fields.StringField({})), armorOrEvasionSlot: new MappingField(new fields.StringField({})),
majorDamageThreshold2: new MappingField(new fields.BooleanField()), majorDamageThreshold2: new MappingField(new fields.BooleanField()),
severeDamageThreshold2: new MappingField(new fields.BooleanField()), severeDamageThreshold2: new MappingField(new fields.BooleanField()),
severeDamageThreshold3: new MappingField(new fields.BooleanField()), severeDamageThreshold3: new MappingField(new fields.BooleanField()),
severeDamageThreshold4: new MappingField(new fields.BooleanField()), severeDamageThreshold4: new MappingField(new fields.BooleanField()),
subclass: new MappingField(new fields.SchemaField({ subclass: new MappingField(
multiclass: new fields.BooleanField(), new fields.SchemaField({
feature: new fields.StringField({}), multiclass: new fields.BooleanField(),
})), feature: new fields.StringField({})
multiclass: new MappingField(new fields.BooleanField()), })
),
multiclass: new MappingField(new fields.BooleanField())
}); });
// const weapon = () => new fields.SchemaField({ // const weapon = () => new fields.SchemaField({
@ -48,450 +51,512 @@ const levelUpTier = () => ({
export default class DhpPC extends foundry.abstract.TypeDataModel { export default class DhpPC extends foundry.abstract.TypeDataModel {
static defineSchema() { static defineSchema() {
return { return {
resources: new fields.SchemaField({ resources: new fields.SchemaField({
health: new fields.SchemaField({ health: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true }), value: new fields.NumberField({ initial: 0, integer: true }),
min: new fields.NumberField({ initial: 0, integer: true }), min: new fields.NumberField({ initial: 0, integer: true }),
max: new fields.NumberField({ initial: 6, integer: true }), max: new fields.NumberField({ initial: 6, integer: true })
}), }),
stress: new fields.SchemaField({ stress: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true }), value: new fields.NumberField({ initial: 0, integer: true }),
min: new fields.NumberField({ initial: 0, integer: true }), min: new fields.NumberField({ initial: 0, integer: true }),
max: new fields.NumberField({ initial: 6, integer: true }), max: new fields.NumberField({ initial: 6, integer: true })
}), }),
hope: new fields.SchemaField({ hope: new fields.SchemaField({
value: new fields.NumberField({ initial: -1, integer: true }), // FIXME. Logic is gte and needs -1 in PC/Hope. Change to 0 value: new fields.NumberField({ initial: -1, integer: true }), // FIXME. Logic is gte and needs -1 in PC/Hope. Change to 0
min: new fields.NumberField({ initial: 0, integer: true }), min: new fields.NumberField({ initial: 0, integer: true })
}), })
}),
bonuses: new fields.SchemaField({
damage: new fields.ArrayField(new fields.SchemaField({
value: new fields.NumberField({ integer: true, initial: 0 }),
type: new fields.StringField({ nullable: true }),
initiallySelected: new fields.BooleanField(),
hopeIncrease: new fields.StringField({ initial: null, nullable: true }),
description: new fields.StringField({}),
})),
}),
attributes: new fields.SchemaField({
agility: attributeField(),
strength: attributeField(),
finesse: attributeField(),
instinct: attributeField(),
presence: attributeField(),
knowledge: attributeField(),
}),
proficiency: new fields.SchemaField({
value: new fields.NumberField({ initial: 1, integer: true}),
min: new fields.NumberField({ initial: 1, integer: true}),
max: new fields.NumberField({ initial: 6, integer: true}),
}),
damageThresholds: new fields.SchemaField({
minor: new fields.NumberField({ initial: 0, integer: true }),
major: new fields.NumberField({ initial: 0, integer: true }),
severe: new fields.NumberField({ initial: 0, integer: true }),
}),
evasion: new fields.NumberField({ initial: 0, integer: true }),
// armor: new fields.SchemaField({
// value: new fields.NumberField({ initial: 0, integer: true }),
// customValue: new fields.NumberField({ initial: null, nullable: true }),
// }),
experiences: new fields.ArrayField(new fields.SchemaField({
id: new fields.StringField({ required: true }),
level: new fields.NumberField({ required: true, integer: true }),
description: new fields.StringField({}),
value: new fields.NumberField({ integer: true, nullable: true, initial: null }),
}), {
initial: [
{ id: foundry.utils.randomID(), level: 1, description: '', value: 2 },
{ id: foundry.utils.randomID(), level: 1, description: '', value: 2 },
]
}),
gold: new fields.SchemaField({
coins: new fields.NumberField({ initial: 0, integer: true }),
handfulls: new fields.NumberField({ initial: 0, integer: true }),
bags: new fields.NumberField({ initial: 0, integer: true }),
chests: new fields.NumberField({ initial: 0, integer: true }),
}),
pronouns: new fields.StringField({}),
domainData: new fields.SchemaField({
maxLoadout: new fields.NumberField({ initial: 2, integer: true }),
maxCards: new fields.NumberField({ initial: 2, integer: true }),
}),
levelData: new fields.SchemaField({
currentLevel: new fields.NumberField({ initial: 1, integer: true }),
changedLevel: new fields.NumberField({ initial: 1, integer: true }),
levelups: new MappingField(new fields.SchemaField({
level: new fields.NumberField({ required: true, integer: true }),
tier1: new fields.SchemaField({
...levelUpTier()
}), }),
tier2: new fields.SchemaField({ bonuses: new fields.SchemaField({
...levelUpTier() damage: new fields.ArrayField(
}, { nullable: true, initial: null }), new fields.SchemaField({
tier3: new fields.SchemaField({ value: new fields.NumberField({ integer: true, initial: 0 }),
...levelUpTier() type: new fields.StringField({ nullable: true }),
}, { nullable: true, initial: null }), initiallySelected: new fields.BooleanField(),
})), hopeIncrease: new fields.StringField({ initial: null, nullable: true }),
}), description: new fields.StringField({})
story: new fields.SchemaField({ })
background: new fields.HTMLField(), )
appearance: new fields.HTMLField(), }),
connections: new fields.HTMLField(), attributes: new fields.SchemaField({
scars: new fields.ArrayField(new fields.SchemaField({ agility: attributeField(),
name: new fields.StringField({}), strength: attributeField(),
description: new fields.HTMLField(), finesse: attributeField(),
})), instinct: attributeField(),
}), presence: attributeField(),
description: new fields.StringField({}), knowledge: attributeField()
//Temporary until new FoundryVersion fix --> See Armor.Mjs DataPreparation }),
armorMarks: new fields.SchemaField({ proficiency: new fields.SchemaField({
max: new fields.NumberField({ initial: 6, integer: true }), value: new fields.NumberField({ initial: 1, integer: true }),
value: new fields.NumberField({ initial: 0, integer: true }), min: new fields.NumberField({ initial: 1, integer: true }),
}), max: new fields.NumberField({ initial: 6, integer: true })
} }),
damageThresholds: new fields.SchemaField({
minor: new fields.NumberField({ initial: 0, integer: true }),
major: new fields.NumberField({ initial: 0, integer: true }),
severe: new fields.NumberField({ initial: 0, integer: true })
}),
evasion: new fields.NumberField({ initial: 0, integer: true }),
// armor: new fields.SchemaField({
// value: new fields.NumberField({ initial: 0, integer: true }),
// customValue: new fields.NumberField({ initial: null, nullable: true }),
// }),
experiences: new fields.ArrayField(
new fields.SchemaField({
id: new fields.StringField({ required: true }),
level: new fields.NumberField({ required: true, integer: true }),
description: new fields.StringField({}),
value: new fields.NumberField({ integer: true, nullable: true, initial: null })
}),
{
initial: [
{ id: foundry.utils.randomID(), level: 1, description: '', value: 2 },
{ id: foundry.utils.randomID(), level: 1, description: '', value: 2 }
]
}
),
gold: new fields.SchemaField({
coins: new fields.NumberField({ initial: 0, integer: true }),
handfulls: new fields.NumberField({ initial: 0, integer: true }),
bags: new fields.NumberField({ initial: 0, integer: true }),
chests: new fields.NumberField({ initial: 0, integer: true })
}),
pronouns: new fields.StringField({}),
domainData: new fields.SchemaField({
maxLoadout: new fields.NumberField({ initial: 2, integer: true }),
maxCards: new fields.NumberField({ initial: 2, integer: true })
}),
levelData: new fields.SchemaField({
currentLevel: new fields.NumberField({ initial: 1, integer: true }),
changedLevel: new fields.NumberField({ initial: 1, integer: true }),
levelups: new MappingField(
new fields.SchemaField({
level: new fields.NumberField({ required: true, integer: true }),
tier1: new fields.SchemaField({
...levelUpTier()
}),
tier2: new fields.SchemaField(
{
...levelUpTier()
},
{ nullable: true, initial: null }
),
tier3: new fields.SchemaField(
{
...levelUpTier()
},
{ nullable: true, initial: null }
)
})
)
}),
story: new fields.SchemaField({
background: new fields.HTMLField(),
appearance: new fields.HTMLField(),
connections: new fields.HTMLField(),
scars: new fields.ArrayField(
new fields.SchemaField({
name: new fields.StringField({}),
description: new fields.HTMLField()
})
)
}),
description: new fields.StringField({}),
//Temporary until new FoundryVersion fix --> See Armor.Mjs DataPreparation
armorMarks: new fields.SchemaField({
max: new fields.NumberField({ initial: 6, integer: true }),
value: new fields.NumberField({ initial: 0, integer: true })
})
};
} }
get canLevelUp(){ get canLevelUp() {
// return Object.values(this.levels.data).some(x => !x.completed); // return Object.values(this.levels.data).some(x => !x.completed);
return this.levelData.currentLevel !== this.levelData.changedLevel; return this.levelData.currentLevel !== this.levelData.changedLevel;
} }
get tier(){ get tier() {
return this.#getTier(this.levelData.currentLevel); return this.#getTier(this.levelData.currentLevel);
} }
get ancestry(){ get ancestry() {
return this.parent.items.find(x => x.type === 'ancestry') ?? null; return this.parent.items.find(x => x.type === 'ancestry') ?? null;
} }
get class(){ get class() {
return this.parent.items.find(x => x.type === 'class' && !x.system.multiclass) ?? null; return this.parent.items.find(x => x.type === 'class' && !x.system.multiclass) ?? null;
} }
get multiclass(){ get multiclass() {
return this.parent.items.find(x => x.type === 'class' && x.system.multiclass) ?? null; return this.parent.items.find(x => x.type === 'class' && x.system.multiclass) ?? null;
} }
get multiclassSubclass(){ get multiclassSubclass() {
return this.parent.items.find(x => x.type === 'subclass' && x.system.multiclass) ?? null; return this.parent.items.find(x => x.type === 'subclass' && x.system.multiclass) ?? null;
} }
get subclass(){ get subclass() {
return this.parent.items.find(x => x.type === 'subclass' && !x.system.multiclass) ?? null; return this.parent.items.find(x => x.type === 'subclass' && !x.system.multiclass) ?? null;
} }
get subclassFeatures(){ get subclassFeatures() {
const subclass = this.subclass; const subclass = this.subclass;
const multiclass = this.multiclassSubclass; const multiclass = this.multiclassSubclass;
const subclassItems = this.parent.items.filter(x => x.type === 'feature' && x.system.type === 'subclass'); const subclassItems = this.parent.items.filter(x => x.type === 'feature' && x.system.type === 'subclass');
return { return {
subclass: !subclass ? {} : { subclass: !subclass
foundation: subclassItems.filter(x => subclass.system.foundationFeature.abilities.some(ability => ability.uuid === x.uuid)), ? {}
specialization: subclassItems.filter(x => subclass.system.specializationFeature.abilities.some(ability => ability.uuid === x.uuid)), : {
mastery: subclassItems.filter(x => subclass.system.masteryFeature.abilities.some(ability => ability.uuid === x.uuid)), foundation: subclassItems.filter(x =>
}, subclass.system.foundationFeature.abilities.some(ability => ability.uuid === x.uuid)
multiclassSubclass: !multiclass ? {} : { ),
foundation: subclassItems.filter(x => multiclass.system.foundationFeature.abilities.some(ability => ability.uuid === x.uuid)), specialization: subclassItems.filter(x =>
specialization: subclassItems.filter(x => multiclass.system.specializationFeature.abilities.some(ability => ability.uuid === x.uuid)), subclass.system.specializationFeature.abilities.some(ability => ability.uuid === x.uuid)
mastery: subclassItems.filter(x => multiclass.system.masteryFeature.abilities.some(ability => ability.uuid === x.uuid)), ),
} mastery: subclassItems.filter(x =>
} subclass.system.masteryFeature.abilities.some(ability => ability.uuid === x.uuid)
)
},
multiclassSubclass: !multiclass
? {}
: {
foundation: subclassItems.filter(x =>
multiclass.system.foundationFeature.abilities.some(ability => ability.uuid === x.uuid)
),
specialization: subclassItems.filter(x =>
multiclass.system.specializationFeature.abilities.some(ability => ability.uuid === x.uuid)
),
mastery: subclassItems.filter(x =>
multiclass.system.masteryFeature.abilities.some(ability => ability.uuid === x.uuid)
)
}
};
} }
get community(){ get community() {
return this.parent.items.find(x => x.type === 'community') ?? null; return this.parent.items.find(x => x.type === 'community') ?? null;
} }
get classFeatures(){ get classFeatures() {
return this.parent.items.filter(x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.class.id && !x.system.multiclass); return this.parent.items.filter(
x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.class.id && !x.system.multiclass
);
} }
get multiclassFeatures(){ get multiclassFeatures() {
return this.parent.items.filter(x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.class.id && x.system.multiclass); return this.parent.items.filter(
x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.class.id && x.system.multiclass
);
} }
get domains(){ get domains() {
const classDomains = this.class ? this.class.system.domains : []; const classDomains = this.class ? this.class.system.domains : [];
const multiclassDomains = this.multiclass ? this.multiclass.system.domains : []; const multiclassDomains = this.multiclass ? this.multiclass.system.domains : [];
return [...classDomains, ...multiclassDomains] return [...classDomains, ...multiclassDomains];
} }
get domainCards(){ get domainCards() {
const domainCards = this.parent.items.filter(x => x.type === 'domainCard'); const domainCards = this.parent.items.filter(x => x.type === 'domainCard');
const loadout = domainCards.filter(x => !x.system.inVault); const loadout = domainCards.filter(x => !x.system.inVault);
const vault = domainCards.filter(x => x.system.inVault); const vault = domainCards.filter(x => x.system.inVault);
return { return {
loadout: loadout, loadout: loadout,
vault: vault, vault: vault,
total: [...loadout, ...vault] total: [...loadout, ...vault]
}; };
} }
get armor(){ get armor() {
return this.parent.items.find(x => x.type === 'armor'); return this.parent.items.find(x => x.type === 'armor');
} }
get activeWeapons(){ get activeWeapons() {
const primaryWeapon = this.parent.items.find(x => x.type === 'weapon' && x.system.active && !x.system.secondary); const primaryWeapon = this.parent.items.find(
const secondaryWeapon = this.parent.items.find(x => x.type === 'weapon' && x.system.active && x.system.secondary); x => x.type === 'weapon' && x.system.active && !x.system.secondary
return { );
primary: this.#weaponData(primaryWeapon), const secondaryWeapon = this.parent.items.find(
secondary: this.#weaponData(secondaryWeapon), x => x.type === 'weapon' && x.system.active && x.system.secondary
burden: this.getBurden(primaryWeapon, secondaryWeapon) );
}; return {
primary: this.#weaponData(primaryWeapon),
secondary: this.#weaponData(secondaryWeapon),
burden: this.getBurden(primaryWeapon, secondaryWeapon)
};
} }
get inventoryWeapons(){ get inventoryWeapons() {
const inventoryWeaponFirst = this.parent.items.find(x => x.type === 'weapon' && x.system.inventoryWeapon === 1); const inventoryWeaponFirst = this.parent.items.find(x => x.type === 'weapon' && x.system.inventoryWeapon === 1);
const inventoryWeaponSecond = this.parent.items.find(x => x.type === 'weapon' && x.system.inventoryWeapon === 2); const inventoryWeaponSecond = this.parent.items.find(
return { x => x.type === 'weapon' && x.system.inventoryWeapon === 2
first: this.#weaponData(inventoryWeaponFirst), );
second: this.#weaponData(inventoryWeaponSecond), return {
}; first: this.#weaponData(inventoryWeaponFirst),
second: this.#weaponData(inventoryWeaponSecond)
};
} }
get totalAttributeMarks(){ get totalAttributeMarks() {
return Object.keys(this.levelData.levelups).reduce((nr, level) => { return Object.keys(this.levelData.levelups).reduce((nr, level) => {
const nrAttributeMarks = Object.keys(this.levelData.levelups[level]).reduce((nr, tier) => { const nrAttributeMarks = Object.keys(this.levelData.levelups[level]).reduce((nr, tier) => {
nr += Object.keys(this.levelData.levelups[level][tier]?.attributes ?? {}).length * 2; nr += Object.keys(this.levelData.levelups[level][tier]?.attributes ?? {}).length * 2;
return nr; return nr;
}, 0); }, 0);
nr.push(...Array(nrAttributeMarks).fill(Number.parseInt(level))); nr.push(...Array(nrAttributeMarks).fill(Number.parseInt(level)));
return nr; return nr;
}, []); }, []);
} }
get availableAttributeMarks(){ get availableAttributeMarks() {
const attributeMarks = Object.keys(this.attributes).flatMap(y => this.attributes[y].levelMarks); const attributeMarks = Object.keys(this.attributes).flatMap(y => this.attributes[y].levelMarks);
return this.totalAttributeMarks.reduce((acc, attribute) => { return this.totalAttributeMarks.reduce((acc, attribute) => {
if(!attributeMarks.findSplice(x => x === attribute)){ if (!attributeMarks.findSplice(x => x === attribute)) {
acc.push(attribute); acc.push(attribute);
}
return acc;
}, []);
}
get effects(){
return this.parent.items.reduce((acc, item) => {
const effects = item.system.effectData;
if(effects && !item.system.disabled){
for(var key in effects){
const effect = effects[key];
for(var effectEntry of effect){
if(!acc[key]) acc[key] = [];
acc[key].push({ name: item.name, value: effectEntry });
} }
}
}
return acc; return acc;
}, {}); }, []);
} }
get refreshableFeatures(){ get effects() {
return this.parent.items.reduce((acc, x) => { return this.parent.items.reduce((acc, item) => {
if(x.type === 'feature' && x.system.refreshData.type){ const effects = item.system.effectData;
acc[x.system.refreshData.type].push(x); if (effects && !item.system.disabled) {
} for (var key in effects) {
const effect = effects[key];
for (var effectEntry of effect) {
if (!acc[key]) acc[key] = [];
acc[key].push({ name: item.name, value: effectEntry });
}
}
}
return acc; return acc;
}, { shortRest: [], longRest: [] }); }, {});
} }
#weaponData(weapon){ get refreshableFeatures() {
return weapon ? { return this.parent.items.reduce(
name: weapon.name, (acc, x) => {
trait: CONFIG.daggerheart.ACTOR.abilities[weapon.system.trait].name, //Should not be done in data? if (x.type === 'feature' && x.system.refreshData.type) {
range: CONFIG.daggerheart.GENERAL.range[weapon.system.range], acc[x.system.refreshData.type].push(x);
damage: { }
value: weapon.system.damage.value,
type: CONFIG.daggerheart.GENERAL.damageTypes[weapon.system.damage.type], return acc;
}, },
feature: CONFIG.daggerheart.ITEM.weaponFeatures[weapon.system.feature], { shortRest: [], longRest: [] }
img: weapon.img, );
uuid: weapon.uuid
} : null
} }
prepareDerivedData(){ #weaponData(weapon) {
this.resources.hope.max = 6 - this.story.scars.length; return weapon
if(this.resources.hope.value >= this.resources.hope.max){ ? {
this.resources.hope.value = Math.max(this.resources.hope.max-1, 0); name: weapon.name,
} trait: CONFIG.daggerheart.ACTOR.abilities[weapon.system.trait].name, //Should not be done in data?
range: CONFIG.daggerheart.GENERAL.range[weapon.system.range],
for(var attributeKey in this.attributes){ damage: {
const attribute = this.attributes[attributeKey]; value: weapon.system.damage.value,
type: CONFIG.daggerheart.GENERAL.damageTypes[weapon.system.damage.type]
attribute.levelMark = attribute.levelMarks.find(x => this.isSameTier(x)) ?? null; },
feature: CONFIG.daggerheart.ITEM.weaponFeatures[weapon.system.feature],
const actualValue = attribute.data.base + attribute.levelMarks.length + attribute.data.bonus; img: weapon.img,
attribute.data.actualValue = actualValue; uuid: weapon.uuid
attribute.data.value = attribute.data.overrideValue ? attribute.data.overrideValue : attribute.data.actualValue;
}
this.evasion = this.class?.system?.evasion ?? 0;
// this.armor.value = this.activeArmor?.baseScore ?? 0;
this.damageThresholds = this.class?.system?.damageThresholds ?? { minor: 0, major: 0, severe: 0 };
this.applyLevels();
this.applyEffects();
}
applyLevels(){
let healthBonus = 0, stressBonus = 0, proficiencyBonus = 0, evasionBonus = 0, armorBonus = 0, minorThresholdBonus = 0, majorThresholdBonus = 0, severeThresholdBonus = 0;
let experienceBonuses = {};
let advancementFirst = null, advancementSecond = null;
for(var level in this.levelData.levelups){
var levelData = this.levelData.levelups[level];
for(var tier in levelData){
var tierData = levelData[tier];
if(tierData){
healthBonus += Object.keys(tierData.hitPointSlots).length;
stressBonus += Object.keys(tierData.stressSlots).length;
proficiencyBonus += Object.keys(tierData.proficiency).length;
advancementFirst = Object.keys(tierData.subclass).length > 0 && (level >= 5 && level <= 7) ? { ...tierData.subclass[0], tier: getTier(Number.parseInt(level), true) } : advancementFirst;
advancementSecond = Object.keys(tierData.subclass).length > 0 && (level >= 8 && level <= 10) ? { ...tierData.subclass[0], tier: getTier(Number.parseInt(level), true) } : advancementSecond;
for(var index in Object.keys(tierData.experiences)){
for(var experienceKey in tierData.experiences[index]){
var experience = tierData.experiences[index][experienceKey];
experienceBonuses[experience] = experienceBonuses[experience] ? experienceBonuses[experience]+1 : 1;
} }
: null;
}
prepareDerivedData() {
this.resources.hope.max = 6 - this.story.scars.length;
if (this.resources.hope.value >= this.resources.hope.max) {
this.resources.hope.value = Math.max(this.resources.hope.max - 1, 0);
}
for (var attributeKey in this.attributes) {
const attribute = this.attributes[attributeKey];
attribute.levelMark = attribute.levelMarks.find(x => this.isSameTier(x)) ?? null;
const actualValue = attribute.data.base + attribute.levelMarks.length + attribute.data.bonus;
attribute.data.actualValue = actualValue;
attribute.data.value = attribute.data.overrideValue
? attribute.data.overrideValue
: attribute.data.actualValue;
}
this.evasion = this.class?.system?.evasion ?? 0;
// this.armor.value = this.activeArmor?.baseScore ?? 0;
this.damageThresholds = this.class?.system?.damageThresholds ?? { minor: 0, major: 0, severe: 0 };
this.applyLevels();
this.applyEffects();
}
applyLevels() {
let healthBonus = 0,
stressBonus = 0,
proficiencyBonus = 0,
evasionBonus = 0,
armorBonus = 0,
minorThresholdBonus = 0,
majorThresholdBonus = 0,
severeThresholdBonus = 0;
let experienceBonuses = {};
let advancementFirst = null,
advancementSecond = null;
for (var level in this.levelData.levelups) {
var levelData = this.levelData.levelups[level];
for (var tier in levelData) {
var tierData = levelData[tier];
if (tierData) {
healthBonus += Object.keys(tierData.hitPointSlots).length;
stressBonus += Object.keys(tierData.stressSlots).length;
proficiencyBonus += Object.keys(tierData.proficiency).length;
advancementFirst =
Object.keys(tierData.subclass).length > 0 && level >= 5 && level <= 7
? { ...tierData.subclass[0], tier: getTier(Number.parseInt(level), true) }
: advancementFirst;
advancementSecond =
Object.keys(tierData.subclass).length > 0 && level >= 8 && level <= 10
? { ...tierData.subclass[0], tier: getTier(Number.parseInt(level), true) }
: advancementSecond;
for (var index in Object.keys(tierData.experiences)) {
for (var experienceKey in tierData.experiences[index]) {
var experience = tierData.experiences[index][experienceKey];
experienceBonuses[experience] = experienceBonuses[experience]
? experienceBonuses[experience] + 1
: 1;
}
}
evasionBonus += Object.keys(tierData.armorOrEvasionSlot).filter(
x => tierData.armorOrEvasionSlot[x] === 'evasion'
).length;
armorBonus += Object.keys(tierData.armorOrEvasionSlot).filter(
x => tierData.armorOrEvasionSlot[x] === 'armor'
).length;
majorThresholdBonus += Object.keys(tierData.majorDamageThreshold2).length * 2;
severeThresholdBonus += Object.keys(tierData.severeDamageThreshold2).length * 2;
severeThresholdBonus += Object.keys(tierData.severeDamageThreshold3).length * 3;
severeThresholdBonus += Object.keys(tierData.severeDamageThreshold4).length * 4;
}
}
}
this.resources.health.max += healthBonus;
this.resources.stress.max += stressBonus;
this.proficiency.value += proficiencyBonus;
this.evasion += evasionBonus;
this.armorMarks = {
max: this.armor ? this.armor.system.marks.max + armorBonus : 0,
value: this.armor ? this.armor.system.marks.value : 0
};
this.damageThresholds.minor += minorThresholdBonus;
this.damageThresholds.major += majorThresholdBonus;
this.damageThresholds.severe += severeThresholdBonus;
this.experiences = this.experiences.map(x => ({ ...x, value: x.value + (experienceBonuses[x.id] ?? 0) }));
const subclassFeatures = this.subclassFeatures;
if (advancementFirst) {
if (advancementFirst.multiclass) {
this.multiclassSubclass.system[`${advancementFirst.feature}Feature`].unlocked = true;
this.multiclassSubclass.system[`${advancementFirst.feature}Feature`].tier = advancementFirst.tier;
subclassFeatures.multiclassSubclass[advancementFirst.feature].forEach(x => (x.system.disabled = false));
} else {
this.subclass.system[`${advancementFirst.feature}Feature`].unlocked = true;
this.subclass.system[`${advancementFirst.feature}Feature`].tier = advancementFirst.tier;
subclassFeatures.subclass[advancementFirst.feature].forEach(x => (x.system.disabled = false));
}
}
if (advancementSecond) {
if (advancementSecond.multiclass) {
this.multiclassSubclass.system[`${advancementSecond.feature}Feature`].unlocked = true;
this.multiclassSubclass.system[`${advancementSecond.feature}Feature`].tier = advancementSecond.tier;
subclassFeatures.multiclassSubclass[advancementSecond.feature].forEach(
x => (x.system.disabled = false)
);
} else {
this.subclass.system[`${advancementSecond.feature}Feature`].unlocked = true;
this.subclass.system[`${advancementSecond.feature}Feature`].tier = advancementSecond.tier;
subclassFeatures.subclass[advancementSecond.feature].forEach(x => (x.system.disabled = false));
}
}
//General progression
for (var i = 0; i < this.levelData.currentLevel; i++) {
const tier = getTier(i + 1);
if (tier !== 'tier0') {
this.domainData.maxLoadout = Math.min(this.domainData.maxLoadout + 1, 5);
this.domainData.maxCards += 1;
} }
evasionBonus += Object.keys(tierData.armorOrEvasionSlot).filter(x => tierData.armorOrEvasionSlot[x] === 'evasion').length; switch (tier) {
armorBonus += Object.keys(tierData.armorOrEvasionSlot).filter(x => tierData.armorOrEvasionSlot[x] === 'armor').length; case 'tier1':
this.damageThresholds.severe += 2;
majorThresholdBonus += Object.keys(tierData.majorDamageThreshold2).length * 2; break;
severeThresholdBonus += Object.keys(tierData.severeDamageThreshold2).length * 2; case 'tier2':
severeThresholdBonus += Object.keys(tierData.severeDamageThreshold3).length * 3; this.damageThresholds.major += 1;
severeThresholdBonus += Object.keys(tierData.severeDamageThreshold4).length * 4; this.damageThresholds.severe += 3;
} break;
case 'tier3':
this.damageThresholds.major += 2;
this.damageThresholds.severe += 4;
break;
}
} }
} }
this.resources.health.max += healthBonus; applyEffects() {
this.resources.stress.max += stressBonus; const effects = this.effects;
this.proficiency.value += proficiencyBonus; for (var key in effects) {
this.evasion += evasionBonus; const effectType = effects[key];
this.armorMarks = { for (var effect of effectType) {
max: this.armor ? this.armor.system.marks.max + armorBonus : 0, switch (key) {
value: this.armor ? this.armor.system.marks.value : 0, case SYSTEM.EFFECTS.effectTypes.health.id:
}; this.resources.health.max += effect.value.valueData.value;
this.damageThresholds.minor += minorThresholdBonus; break;
this.damageThresholds.major += majorThresholdBonus; case SYSTEM.EFFECTS.effectTypes.stress.id:
this.damageThresholds.severe += severeThresholdBonus; this.resources.stress.max += effect.value.valueData.value;
break;
this.experiences = this.experiences.map(x => ({ ...x, value: x.value + (experienceBonuses[x.id] ?? 0) })); case SYSTEM.EFFECTS.effectTypes.damage.id:
this.bonuses.damage.push({
const subclassFeatures = this.subclassFeatures; value: getPathValue(effect.value.valueData.value, this),
if(advancementFirst){ type: 'physical',
if(advancementFirst.multiclass){ description: effect.name,
this.multiclassSubclass.system[`${advancementFirst.feature}Feature`].unlocked = true; hopeIncrease: effect.value.valueData.hopeIncrease,
this.multiclassSubclass.system[`${advancementFirst.feature}Feature`].tier = advancementFirst.tier; initiallySelected: effect.value.initiallySelected,
subclassFeatures.multiclassSubclass[advancementFirst.feature].forEach(x => x.system.disabled = false); appliesOn: effect.value.appliesOn
} else { });
this.subclass.system[`${advancementFirst.feature}Feature`].unlocked = true; }
this.subclass.system[`${advancementFirst.feature}Feature`].tier = advancementFirst.tier; }
subclassFeatures.subclass[advancementFirst.feature].forEach(x => x.system.disabled = false);
} }
}
if(advancementSecond){
if(advancementSecond.multiclass){
this.multiclassSubclass.system[`${advancementSecond.feature}Feature`].unlocked = true;
this.multiclassSubclass.system[`${advancementSecond.feature}Feature`].tier = advancementSecond.tier;
subclassFeatures.multiclassSubclass[advancementSecond.feature].forEach(x => x.system.disabled = false);
} else {
this.subclass.system[`${advancementSecond.feature}Feature`].unlocked = true;
this.subclass.system[`${advancementSecond.feature}Feature`].tier = advancementSecond.tier;
subclassFeatures.subclass[advancementSecond.feature].forEach(x => x.system.disabled = false);
}
}
//General progression
for(var i = 0; i < this.levelData.currentLevel; i++){
const tier = getTier(i+1);
if(tier !== 'tier0'){
this.domainData.maxLoadout = Math.min(this.domainData.maxLoadout+1, 5);
this.domainData.maxCards += 1;
}
switch(tier){
case 'tier1':
this.damageThresholds.severe += 2;
break;
case 'tier2':
this.damageThresholds.major += 1;
this.damageThresholds.severe += 3;
break;
case 'tier3':
this.damageThresholds.major += 2;
this.damageThresholds.severe += 4;
break;
}
}
} }
applyEffects(){ getBurden(primary, secondary) {
const effects = this.effects; const twoHanded =
for(var key in effects){ primary?.system?.burden === 'twoHanded' ||
const effectType = effects[key]; secondary?.system?.burden === 'twoHanded' ||
for(var effect of effectType) { (primary?.system?.burden === 'oneHanded' && secondary?.system?.burden === 'oneHanded');
switch(key) { const oneHanded =
case SYSTEM.EFFECTS.effectTypes.health.id: !twoHanded && (primary?.system?.burden === 'oneHanded' || secondary?.system?.burden === 'oneHanded');
this.resources.health.max += effect.value.valueData.value;
break; return twoHanded ? 'twoHanded' : oneHanded ? 'oneHanded' : null;
case SYSTEM.EFFECTS.effectTypes.stress.id:
this.resources.stress.max += effect.value.valueData.value;
break;
case SYSTEM.EFFECTS.effectTypes.damage.id:
this.bonuses.damage.push({
value: getPathValue(effect.value.valueData.value, this),
type: 'physical',
description: effect.name,
hopeIncrease: effect.value.valueData.hopeIncrease,
initiallySelected: effect.value.initiallySelected,
appliesOn: effect.value.appliesOn,
});
}
}
}
} }
getBurden(primary, secondary){ isSameTier(level) {
const twoHanded = return this.#getTier(this.levelData.currentLevel) === this.#getTier(level);
primary?.system?.burden === 'twoHanded' ||
secondary?.system?.burden === 'twoHanded' ||
(
primary?.system?.burden === 'oneHanded' &&
secondary?.system?.burden === 'oneHanded'
);
const oneHanded =
!twoHanded &&
(
primary?.system?.burden === 'oneHanded' ||
secondary?.system?.burden === 'oneHanded'
);
return twoHanded ? 'twoHanded' : oneHanded ? 'oneHanded' : null;
} }
isSameTier(level){ #getTier(level) {
return this.#getTier(this.levelData.currentLevel) === this.#getTier(level); if (level >= 8) return 3;
else if (level >= 5) return 2;
else if (level >= 2) return 1;
else return 0;
} }
}
#getTier(level){
if(level >= 8) return 3;
else if(level >= 5) return 2;
else if(level >= 2) return 1;
else return 0;
}
}

View file

@ -1,34 +1,39 @@
import { getTier } from "../helpers/utils.mjs"; import { getTier } from '../helpers/utils.mjs';
import featuresSchema from "./interface/featuresSchema.mjs"; import featuresSchema from './interface/featuresSchema.mjs';
import DaggerheartFeature from './feature.mjs'; import DaggerheartFeature from './feature.mjs';
export default class DhpSubclass extends foundry.abstract.TypeDataModel { export default class DhpSubclass extends foundry.abstract.TypeDataModel {
static defineSchema() { static defineSchema() {
const fields = foundry.data.fields; const fields = foundry.data.fields;
return { return {
description: new fields.HTMLField({}),
spellcastingTrait: new fields.StringField({ choices: SYSTEM.ACTOR.abilities, integer: false, nullable: true, initial: null }),
foundationFeature: new fields.SchemaField({
description: new fields.HTMLField({}), description: new fields.HTMLField({}),
abilities: new fields.ArrayField(new fields.EmbeddedDataField(DaggerheartFeature)), spellcastingTrait: new fields.StringField({
}), choices: SYSTEM.ACTOR.abilities,
specializationFeature: new fields.SchemaField({ integer: false,
unlocked: new fields.BooleanField({ initial: false }), nullable: true,
tier: new fields.NumberField({ initial: null, nullable: true, integer: true }), initial: null
description: new fields.HTMLField({}), }),
abilities: new fields.ArrayField(new fields.EmbeddedDataField(DaggerheartFeature)), foundationFeature: new fields.SchemaField({
}), description: new fields.HTMLField({}),
masteryFeature: new fields.SchemaField({ abilities: new fields.ArrayField(new fields.EmbeddedDataField(DaggerheartFeature))
unlocked: new fields.BooleanField({ initial: false }), }),
tier: new fields.NumberField({ initial: null, nullable: true, integer: true }), specializationFeature: new fields.SchemaField({
description: new fields.HTMLField({}), unlocked: new fields.BooleanField({ initial: false }),
abilities: new fields.ArrayField(new fields.EmbeddedDataField(DaggerheartFeature)), tier: new fields.NumberField({ initial: null, nullable: true, integer: true }),
}), description: new fields.HTMLField({}),
multiclass: new fields.NumberField({ initial: null, nullable: true, integer: true }), abilities: new fields.ArrayField(new fields.EmbeddedDataField(DaggerheartFeature))
} }),
masteryFeature: new fields.SchemaField({
unlocked: new fields.BooleanField({ initial: false }),
tier: new fields.NumberField({ initial: null, nullable: true, integer: true }),
description: new fields.HTMLField({}),
abilities: new fields.ArrayField(new fields.EmbeddedDataField(DaggerheartFeature))
}),
multiclass: new fields.NumberField({ initial: null, nullable: true, integer: true })
};
} }
get multiclassTier(){ get multiclassTier() {
return getTier(this.multiclass); return getTier(this.multiclass);
} }
} }

View file

@ -1,47 +1,50 @@
export default class DhpWeapon extends foundry.abstract.TypeDataModel { export default class DhpWeapon extends foundry.abstract.TypeDataModel {
static defineSchema() { static defineSchema() {
const fields = foundry.data.fields; const fields = foundry.data.fields;
return { return {
active: new fields.BooleanField({ initial: false }), active: new fields.BooleanField({ initial: false }),
inventoryWeapon: new fields.NumberField({ initial: null, nullable: true, integer: true }), inventoryWeapon: new fields.NumberField({ initial: null, nullable: true, integer: true }),
secondary: new fields.BooleanField({ initial: false }), secondary: new fields.BooleanField({ initial: false }),
trait: new fields.StringField({ choices: SYSTEM.ACTOR.abilities, integer: false }), trait: new fields.StringField({ choices: SYSTEM.ACTOR.abilities, integer: false }),
range: new fields.StringField({ choices: SYSTEM.GENERAL.range, integer: false }), range: new fields.StringField({ choices: SYSTEM.GENERAL.range, integer: false }),
damage: new fields.SchemaField({ damage: new fields.SchemaField({
value: new fields.StringField({}), value: new fields.StringField({}),
type: new fields.StringField({ choices: SYSTEM.GENERAL.damageTypes, integer: false }), type: new fields.StringField({ choices: SYSTEM.GENERAL.damageTypes, integer: false })
}), }),
burden: new fields.StringField({ choices: SYSTEM.GENERAL.burden, integer: false }), burden: new fields.StringField({ choices: SYSTEM.GENERAL.burden, integer: false }),
feature: new fields.StringField({ choices: SYSTEM.ITEM.weaponFeatures, integer: false, blank:true }), feature: new fields.StringField({ choices: SYSTEM.ITEM.weaponFeatures, integer: false, blank: true }),
quantity: new fields.NumberField({ initial: 1, integer: true }), quantity: new fields.NumberField({ initial: 1, integer: true }),
description: new fields.HTMLField({}), description: new fields.HTMLField({})
} };
} }
prepareDerivedData(){ prepareDerivedData() {
if(this.parent.parent){ if (this.parent.parent) {
this.applyEffects(); this.applyEffects();
}
}
applyEffects(){
const effects = this.parent.parent.system.effects;
for(var key in effects){
const effectType = effects[key];
for(var effect of effectType) {
switch(key) {
case SYSTEM.EFFECTS.effectTypes.reach.id:
if(SYSTEM.GENERAL.range[this.range].distance < SYSTEM.GENERAL.range[effect.valueData.value].distance){
this.range = effect.valueData.value;
}
break;
// case SYSTEM.EFFECTS.effectTypes.damage.id:
// if(this.damage.type === 'physical') this.damage.value = (`${this.damage.value} + ${this.parent.parent.system.levelData.currentLevel}`);
// break;
}
} }
}
} }
}
applyEffects() {
const effects = this.parent.parent.system.effects;
for (var key in effects) {
const effectType = effects[key];
for (var effect of effectType) {
switch (key) {
case SYSTEM.EFFECTS.effectTypes.reach.id:
if (
SYSTEM.GENERAL.range[this.range].distance <
SYSTEM.GENERAL.range[effect.valueData.value].distance
) {
this.range = effect.valueData.value;
}
break;
// case SYSTEM.EFFECTS.effectTypes.damage.id:
// if(this.damage.type === 'physical') this.damage.value = (`${this.damage.value} + ${this.parent.parent.system.levelData.currentLevel}`);
// break;
}
}
}
}
}

View file

@ -5,41 +5,41 @@ export default class SelectDialog extends Dialog {
this.data = { this.data = {
title: data.title, title: data.title,
buttons: data.buttons, buttons: data.buttons,
content: renderTemplate("systems/daggerheart/templates/dialog/item-select.hbs", { content: renderTemplate('systems/daggerheart/templates/dialog/item-select.hbs', {
items: data.choices items: data.choices
}), })
}; };
this.actor = data.actor; this.actor = data.actor;
this.actionCostMax = data.actionCostMax; this.actionCostMax = data.actionCostMax;
this.nrChoices = data.nrChoices; this.nrChoices = data.nrChoices;
this.validate= data.validate; this.validate = data.validate;
} }
async getData(options={}) { async getData(options = {}) {
let buttons = Object.keys(this.data.buttons).reduce((obj, key) => { let buttons = Object.keys(this.data.buttons).reduce((obj, key) => {
let b = this.data.buttons[key]; let b = this.data.buttons[key];
b.cssClass = (this.data.default === key ? [key, "default", "bright"] : [key]).join(" "); b.cssClass = (this.data.default === key ? [key, 'default', 'bright'] : [key]).join(' ');
if ( b.condition !== false ) obj[key] = b; if (b.condition !== false) obj[key] = b;
return obj; return obj;
}, {}); }, {});
const content = await this.data.content; const content = await this.data.content;
return { return {
content: content, content: content,
buttons: buttons buttons: buttons
}; };
} }
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
$(html).find('.item-button').click(this.selectChoice); $(html).find('.item-button').click(this.selectChoice);
} }
selectChoice = async (event) => { selectChoice = async event => {
if(this.validate){ if (this.validate) {
if(!this.validate(event.currentTarget.dataset.validateProp)){ if (!this.validate(event.currentTarget.dataset.validateProp)) {
return; return;
} }
} }
@ -48,47 +48,47 @@ export default class SelectDialog extends Dialog {
$(event.currentTarget).find('i')[0].classList.toggle('checked'); $(event.currentTarget).find('i')[0].classList.toggle('checked');
const buttons = $(this.element[0]).find('button.checked'); const buttons = $(this.element[0]).find('button.checked');
if(buttons.length === this.nrChoices){ if (buttons.length === this.nrChoices) {
$(event.currentTarget).closest('.window-content').find('.confirm')[0].disabled = false; $(event.currentTarget).closest('.window-content').find('.confirm')[0].disabled = false;
} else { } else {
$(event.currentTarget).closest('.window-content').find('.confirm')[0].disabled = true; $(event.currentTarget).closest('.window-content').find('.confirm')[0].disabled = true;
} }
} };
/** /**
* *
* @param {*} data * @param {*} data
* choices, actor, title, cancelMessage, nrChoices, validate * choices, actor, title, cancelMessage, nrChoices, validate
* @returns * @returns
*/ */
static async selectItem(data) { static async selectItem(data) {
return this.wait({ return this.wait({
title: data.title ?? "Selection", title: data.title ?? 'Selection',
buttons: { buttons: {
no: { no: {
icon: '<i class="fas fa-times"></i>', icon: '<i class="fas fa-times"></i>',
label: game.i18n.localize("DAGGERHEART.General.Cancel"), label: game.i18n.localize('DAGGERHEART.General.Cancel'),
callback: _ => { callback: _ => {
if(data.cancelMessage){ if (data.cancelMessage) {
ChatMessage.create({content: data.cancelMessage }); ChatMessage.create({ content: data.cancelMessage });
} }
return []; return [];
} }
}, },
confirm: { confirm: {
icon: '<i class="fas fa-check"></i>', icon: '<i class="fas fa-check"></i>',
label: game.i18n.localize("DAGGERHEART.General.OK"), label: game.i18n.localize('DAGGERHEART.General.OK'),
callback: html => { callback: html => {
const buttons = $(html).find('button.checked'); const buttons = $(html).find('button.checked');
return buttons.map(key => Number.parseInt(buttons[key].dataset.index)).toArray(); return buttons.map(key => Number.parseInt(buttons[key].dataset.index)).toArray();
}, },
disabled: true disabled: true
}, }
}, },
choices: data.choices, choices: data.choices,
actor: data.actor, actor: data.actor,
nrChoices: data.nrChoices ?? 1, nrChoices: data.nrChoices ?? 1,
validate: data.validate validate: data.validate
}); });
} }
} }

View file

@ -1,3 +1,3 @@
export { default as DhpActor } from './actor.mjs'; export { default as DhpActor } from './actor.mjs';
export { default as DhpItem } from './item.mjs'; export { default as DhpItem } from './item.mjs';
export { default as DhpCombat } from './combat.mjs'; export { default as DhpCombat } from './combat.mjs';

View file

@ -1,350 +1,416 @@
import DamageSelectionDialog from "../applications/damageSelectionDialog.mjs"; import DamageSelectionDialog from '../applications/damageSelectionDialog.mjs';
import NpcRollSelectionDialog from "../applications/npcRollSelectionDialog.mjs"; import NpcRollSelectionDialog from '../applications/npcRollSelectionDialog.mjs';
import RollSelectionDialog from "../applications/rollSelectionDialog.mjs"; import RollSelectionDialog from '../applications/rollSelectionDialog.mjs';
import { GMUpdateEvent, socketEvent } from "../helpers/socket.mjs"; import { GMUpdateEvent, socketEvent } from '../helpers/socket.mjs';
export default class DhpActor extends Actor { export default class DhpActor extends Actor {
_preCreate(data, changes, user){ _preCreate(data, changes, user) {
if(data.type === 'pc'){ if (data.type === 'pc') {
data.prototypeToken = { actorLink: true, disposition: 1, sight: { enabled: true } }; data.prototypeToken = { actorLink: true, disposition: 1, sight: { enabled: true } };
}
super._preCreate(data, changes, user);
}
prepareData(){
super.prepareData();
}
async _preUpdate(changed, options, user) {
//Level Down
if(changed.system?.levelData?.changedLevel && this.system.levelData.currentLevel > changed.system.levelData.changedLevel){
changed.system.levelData.currentLevel = changed.system.levelData.changedLevel;
changed.system.levelData.levelups = Object.keys(this.system.levelData.levelups).reduce((acc, x) => {
if(x > changed.system.levelData.currentLevel){
acc[`-=${x}`] = null;
}
return acc;
}, {});
changed.system.attributes = Object.keys(this.system.attributes).reduce((acc, key) => {
acc[key] = { levelMarks: this.system.attributes[key].levelMarks.filter(x => x <= changed.system.levelData.currentLevel) };
return acc;
}, {});
changed.system.experiences = this.system.experiences.filter(x => x.level <= changed.system.levelData.currentLevel);
if(this.system.multiclass && this.system.multiclass.system.multiclass > changed.system.levelData.changedLevel){
const multiclassFeatures = this.items.filter(x => x.system.multiclass);
for(var feature of multiclassFeatures){
await feature.delete();
}
} }
}
super._preUpdate(changed, options, user); super._preCreate(data, changes, user);
}
prepareData() {
super.prepareData();
}
async _preUpdate(changed, options, user) {
//Level Down
if (
changed.system?.levelData?.changedLevel &&
this.system.levelData.currentLevel > changed.system.levelData.changedLevel
) {
changed.system.levelData.currentLevel = changed.system.levelData.changedLevel;
changed.system.levelData.levelups = Object.keys(this.system.levelData.levelups).reduce((acc, x) => {
if (x > changed.system.levelData.currentLevel) {
acc[`-=${x}`] = null;
}
return acc;
}, {});
changed.system.attributes = Object.keys(this.system.attributes).reduce((acc, key) => {
acc[key] = {
levelMarks: this.system.attributes[key].levelMarks.filter(
x => x <= changed.system.levelData.currentLevel
)
};
return acc;
}, {});
changed.system.experiences = this.system.experiences.filter(
x => x.level <= changed.system.levelData.currentLevel
);
if (
this.system.multiclass &&
this.system.multiclass.system.multiclass > changed.system.levelData.changedLevel
) {
const multiclassFeatures = this.items.filter(x => x.system.multiclass);
for (var feature of multiclassFeatures) {
await feature.delete();
}
}
}
super._preUpdate(changed, options, user);
} }
async diceRoll(modifier, shiftKey) { async diceRoll(modifier, shiftKey) {
if(this.type === 'pc'){ if (this.type === 'pc') {
return await this.dualityRoll(modifier, shiftKey); return await this.dualityRoll(modifier, shiftKey);
} } else {
else { return await this.npcRoll(modifier, shiftKey);
return await this.npcRoll(modifier, shiftKey); }
}
} }
async npcRoll(modifier, shiftKey) { async npcRoll(modifier, shiftKey) {
let nrDice = 1; let nrDice = 1;
let advantage = null; let advantage = null;
const modifiers = [ const modifiers = [
{ {
value: Number.parseInt(modifier.value), value: Number.parseInt(modifier.value),
label: modifier.value >= 0 ? `+${modifier.value}` : `-${modifier.value}`, label: modifier.value >= 0 ? `+${modifier.value}` : `-${modifier.value}`,
title: modifier.title, title: modifier.title
}
];
if (!shiftKey) {
const dialogClosed = new Promise((resolve, _) => {
new NpcRollSelectionDialog(this.system.experiences, resolve).render(true);
});
const result = await dialogClosed;
nrDice = result.nrDice;
advantage = result.advantage;
result.experiences.forEach(x =>
modifiers.push({
value: x.value,
label: x.value >= 0 ? `+${x.value}` : `-${x.value}`,
title: x.description
})
);
} }
];
if(!shiftKey) {
const dialogClosed = new Promise((resolve, _) => {
new NpcRollSelectionDialog(this.system.experiences, resolve).render(true);
});
const result = await dialogClosed;
nrDice = result.nrDice;
advantage = result.advantage;
result.experiences.forEach(x => modifiers.push({ value: x.value, label: x.value >= 0 ? `+${x.value}` : `-${x.value}`, title: x.description }))
}
const roll = new Roll(`${nrDice}d20${advantage === true ? 'kh' : advantage === false ? 'kl': ''} ${modifiers.map(x => `+ ${x.value}`).join(' ')}`); const roll = new Roll(
let rollResult = await roll.evaluate(); `${nrDice}d20${advantage === true ? 'kh' : advantage === false ? 'kl' : ''} ${modifiers.map(x => `+ ${x.value}`).join(' ')}`
const diceResults = rollResult.dice.flatMap(x => x.results.flatMap(result => ({ value: result.result }))); );
let rollResult = await roll.evaluate();
const diceResults = rollResult.dice.flatMap(x => x.results.flatMap(result => ({ value: result.result })));
return { roll, diceResults: diceResults, modifiers: modifiers }; return { roll, diceResults: diceResults, modifiers: modifiers };
} }
async dualityRoll(modifier, shiftKey, bonusDamage=[]){ async dualityRoll(modifier, shiftKey, bonusDamage = []) {
let hopeDice = 'd12', fearDice = 'd12', advantageDice = null, disadvantageDice = null, bonusDamageString = ""; let hopeDice = 'd12',
fearDice = 'd12',
const modifiers = [ advantageDice = null,
{ disadvantageDice = null,
value: modifier.value ? Number.parseInt(modifier.value) : 0, bonusDamageString = '';
label: modifier.value >= 0 ? `+${modifier.value}` : `-${modifier.value}`,
title: modifier.title, const modifiers = [
{
value: modifier.value ? Number.parseInt(modifier.value) : 0,
label: modifier.value >= 0 ? `+${modifier.value}` : `-${modifier.value}`,
title: modifier.title
}
];
if (!shiftKey) {
const dialogClosed = new Promise((resolve, _) => {
new RollSelectionDialog(
this.system.experiences,
bonusDamage,
this.system.resources.hope.value,
resolve
).render(true);
});
const result = await dialogClosed;
(hopeDice = result.hope),
(fearDice = result.fear),
(advantageDice = result.advantage),
(disadvantageDice = result.disadvantage);
result.experiences.forEach(x =>
modifiers.push({
value: x.value,
label: x.value >= 0 ? `+${x.value}` : `-${x.value}`,
title: x.description
})
);
bonusDamageString = result.bonusDamage;
const automateHope = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.Hope);
if (automateHope && result.hopeUsed) {
await this.update({
'system.resources.hope.value': this.system.resources.hope.value - result.hopeUsed
});
}
}
const roll = new Roll(
`1${hopeDice} + 1${fearDice}${advantageDice ? ` + 1${advantageDice}` : disadvantageDice ? ` - 1${disadvantageDice}` : ''} ${modifiers.map(x => `+ ${x.value}`).join(' ')}`
);
let rollResult = await roll.evaluate();
rollResult.dice[0].options.appearance = {
colorset: 'inspired',
foreground: '#FFFFFF',
background: '#008080',
outline: '#000000',
edge: '#806400',
texture: 'bloodmoon',
material: 'metal',
font: 'Arial Black',
system: 'standard'
};
if (advantageDice || disadvantageDice) {
rollResult.dice[1].options.appearance = {
colorset: 'inspired',
foreground: disadvantageDice ? '#b30000' : '#FFFFFF',
background: '#008080',
outline: disadvantageDice ? '#000000' : '#000000',
edge: '#806400',
texture: 'bloodmoon',
material: 'metal',
font: 'Arial Black',
system: 'standard'
};
rollResult.dice[2].options.appearance = {
colorset: 'bloodmoon',
foreground: '#000000',
background: '#430070',
outline: '#b30000',
edge: '#000000',
texture: 'bloodmoon',
material: 'metal',
font: 'Arial Black',
system: 'standard'
};
} else {
rollResult.dice[1].options.appearance = {
colorset: 'bloodmoon',
foreground: '#000000',
background: '#430070',
outline: '#b30000',
edge: '#000000',
texture: 'bloodmoon',
material: 'metal',
font: 'Arial Black',
system: 'standard'
};
}
const hope = rollResult.dice[0].results[0].result;
const advantage = advantageDice ? rollResult.dice[1].results[0].result : null;
const disadvantage = disadvantageDice ? rollResult.dice[1].results[0].result : null;
const fear =
advantage || disadvantage ? rollResult.dice[2].results[0].result : rollResult.dice[1].results[0].result;
if (disadvantage) {
rollResult = { ...rollResult, total: rollResult.total - Math.max(hope, disadvantage) };
}
if (advantage) {
rollResult = { ...rollResult, total: 'Select Hope Die' };
} }
];
if(!shiftKey) {
const dialogClosed = new Promise((resolve, _) => {
new RollSelectionDialog(this.system.experiences, bonusDamage, this.system.resources.hope.value, resolve).render(true);
});
const result = await dialogClosed;
hopeDice = result.hope, fearDice = result.fear, advantageDice = result.advantage, disadvantageDice = result.disadvantage;
result.experiences.forEach(x => modifiers.push({ value: x.value, label: x.value >= 0 ? `+${x.value}` : `-${x.value}`, title: x.description }))
bonusDamageString = result.bonusDamage;
const automateHope = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.Hope); const automateHope = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.Hope);
if (automateHope && hope > fear) {
if(automateHope && result.hopeUsed){ await this.update({
await this.update({ "system.resources.hope.value": this.system.resources.hope.value - result.hopeUsed }); 'system.resources.hope.value': Math.min(
this.system.resources.hope.value + 1,
this.system.resources.hope.max
)
});
} }
}
const roll = new Roll(`1${hopeDice} + 1${fearDice}${advantageDice ? ` + 1${advantageDice}` : disadvantageDice ? ` - 1${disadvantageDice}` : ''} ${modifiers.map(x => `+ ${x.value}`).join(' ')}`);
let rollResult = await roll.evaluate();
rollResult.dice[0].options.appearance = {
colorset:"inspired",
foreground: "#FFFFFF",
background: "#008080",
outline: "#000000",
edge: "#806400",
texture: "bloodmoon",
material: "metal",
font: "Arial Black",
system: "standard"
};
if(advantageDice || disadvantageDice){
rollResult.dice[1].options.appearance = {
colorset:"inspired",
foreground: disadvantageDice ? "#b30000" : "#FFFFFF",
background: "#008080",
outline: disadvantageDice ? "#000000" : "#000000",
edge: "#806400",
texture: "bloodmoon",
material: "metal",
font: "Arial Black",
system: "standard"
};
rollResult.dice[2].options.appearance = {
colorset:"bloodmoon",
foreground: "#000000",
background: "#430070",
outline: "#b30000",
edge: "#000000",
texture: "bloodmoon",
material: "metal",
font: "Arial Black",
system: "standard"
};
}
else {
rollResult.dice[1].options.appearance = {
colorset:"bloodmoon",
foreground: "#000000",
background: "#430070",
outline: "#b30000",
edge: "#000000",
texture: "bloodmoon",
material: "metal",
font: "Arial Black",
system: "standard"
};
}
const hope = rollResult.dice[0].results[0].result;
const advantage = advantageDice ? rollResult.dice[1].results[0].result : null;
const disadvantage = disadvantageDice ? rollResult.dice[1].results[0].result : null;
const fear = advantage || disadvantage ? rollResult.dice[2].results[0].result : rollResult.dice[1].results[0].result;
if(disadvantage){ if (automateHope && hope === fear) {
rollResult = {...rollResult, total: rollResult.total - Math.max(hope, disadvantage) }; await this.update({
} 'system.resources': {
if(advantage){ 'hope.value': Math.min(this.system.resources.hope.value + 1, this.system.resources.hope.max),
rollResult = {...rollResult, total: 'Select Hope Die' }; 'stress.value': Math.max(this.system.resources.stress.value - 1, 0)
} }
});
const automateHope = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.Hope); }
if (automateHope && hope > fear){
await this.update({ "system.resources.hope.value": Math.min(this.system.resources.hope.value+1, this.system.resources.hope.max) });
}
if(automateHope && hope === fear){ return {
await this.update({ "system.resources": { roll,
"hope.value": Math.min(this.system.resources.hope.value+1, this.system.resources.hope.max), rollResult,
"stress.value": Math.max(this.system.resources.stress.value-1, 0), hope: { dice: hopeDice, value: hope },
}}); fear: { dice: fearDice, value: fear },
} advantage: { dice: advantageDice, value: advantage },
disadvantage: { dice: disadvantageDice, value: disadvantage },
return { roll, rollResult, hope: { dice: hopeDice, value: hope }, fear: { dice: fearDice, value: fear }, advantage: { dice: advantageDice, value: advantage }, disadvantage: { dice: disadvantageDice, value: disadvantage }, modifiers: modifiers, bonusDamageString }; modifiers: modifiers,
bonusDamageString
};
} }
async damageRoll(damage, shiftKey){ async damageRoll(damage, shiftKey) {
let rollString = damage.value; let rollString = damage.value;
let bonusDamage = damage.bonusDamage?.filter(x => x.initiallySelected) ?? []; let bonusDamage = damage.bonusDamage?.filter(x => x.initiallySelected) ?? [];
if(!shiftKey) { if (!shiftKey) {
const dialogClosed = new Promise((resolve, _) => { const dialogClosed = new Promise((resolve, _) => {
new DamageSelectionDialog(rollString, bonusDamage, this.system.resources.hope.value, resolve).render(true); new DamageSelectionDialog(rollString, bonusDamage, this.system.resources.hope.value, resolve).render(
}); true
const result = await dialogClosed; );
bonusDamage = result.bonusDamage; });
rollString = result.rollString; const result = await dialogClosed;
bonusDamage = result.bonusDamage;
const automateHope = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.Hope); rollString = result.rollString;
if(automateHope && result.hopeUsed){
await this.update({ "system.resources.hope.value": this.system.resources.hope.value - result.hopeUsed }); const automateHope = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.Hope);
if (automateHope && result.hopeUsed) {
await this.update({
'system.resources.hope.value': this.system.resources.hope.value - result.hopeUsed
});
}
} }
}
const roll = new Roll(rollString); const roll = new Roll(rollString);
let rollResult = await roll.evaluate(); let rollResult = await roll.evaluate();
const dice = []; const dice = [];
const modifiers = []; const modifiers = [];
for(var i = 0; i < rollResult.terms.length; i++){ for (var i = 0; i < rollResult.terms.length; i++) {
const term = rollResult.terms[i]; const term = rollResult.terms[i];
if(term.faces){ if (term.faces) {
dice.push({type: `d${term.faces}`, value: term.total}); dice.push({ type: `d${term.faces}`, value: term.total });
} } else if (term.operator) {
else if (term.operator){ } else if (term.number) {
const operator = i === 0 ? '' : rollResult.terms[i - 1].operator;
modifiers.push(`${operator}${term.number}`);
}
}
} const cls = getDocumentClass('ChatMessage');
else if(term.number){ const msg = new cls({
const operator = i === 0 ? '' : rollResult.terms[i-1].operator; user: game.user.id,
modifiers.push(`${operator}${term.number}`); content: await renderTemplate('systems/daggerheart/templates/chat/damage-roll.hbs', {
} roll: rollString,
} total: rollResult.total,
dice: dice,
modifiers: modifiers
}),
rolls: [roll]
});
const cls = getDocumentClass("ChatMessage"); cls.create(msg.toObject());
const msg = new cls({
user: game.user.id,
content: await renderTemplate("systems/daggerheart/templates/chat/damage-roll.hbs", {
roll: rollString,
total: rollResult.total,
dice: dice,
modifiers: modifiers
}),
rolls: [roll]
});
cls.create(msg.toObject());
} }
async takeDamage(damage, type){ async takeDamage(damage, type) {
const hpDamage = const hpDamage =
damage >= this.system.damageThresholds.severe ? 3 : damage >= this.system.damageThresholds.severe
damage >= this.system.damageThresholds.major ? 2 : ? 3
damage >= this.system.damageThresholds.minor ? 1 : : damage >= this.system.damageThresholds.major
0; ? 2
: damage >= this.system.damageThresholds.minor
? 1
: 0;
const update = { "system.resources.health.value": Math.min(this.system.resources.health.value+hpDamage, this.system.resources.health.max) }; const update = {
'system.resources.health.value': Math.min(
this.system.resources.health.value + hpDamage,
this.system.resources.health.max
)
};
if(game.user.isGM){ if (game.user.isGM) {
await this.update(update); await this.update(update);
} else { } else {
await game.socket.emit(`system.${SYSTEM.id}`, { await game.socket.emit(`system.${SYSTEM.id}`, {
action: socketEvent.GMUpdate, action: socketEvent.GMUpdate,
data: { data: {
action: GMUpdateEvent.UpdateDocument, action: GMUpdateEvent.UpdateDocument,
uuid: this.uuid, uuid: this.uuid,
update: update, update: update
} }
}); });
} }
} }
async takeHealing(healing, type) { async takeHealing(healing, type) {
let update = { }; let update = {};
switch(type){ switch (type) {
case SYSTEM.GENERAL.healingTypes.health.id: case SYSTEM.GENERAL.healingTypes.health.id:
update = { "system.resources.health.value": Math.max(this.system.resources.health.value - healing, 0) }; update = { 'system.resources.health.value': Math.max(this.system.resources.health.value - healing, 0) };
break; break;
case SYSTEM.GENERAL.healingTypes.stress.id: case SYSTEM.GENERAL.healingTypes.stress.id:
update = { "system.resources.stress.value": Math.max(this.system.resources.stress.value - healing, 0) }; update = { 'system.resources.stress.value': Math.max(this.system.resources.stress.value - healing, 0) };
break; break;
} }
if(game.user.isGM){ if (game.user.isGM) {
await this.update(update); await this.update(update);
} else { } else {
await game.socket.emit(`system.${SYSTEM.id}`, { await game.socket.emit(`system.${SYSTEM.id}`, {
action: socketEvent.GMUpdate, action: socketEvent.GMUpdate,
data: { data: {
action: GMUpdateEvent.UpdateDocument, action: GMUpdateEvent.UpdateDocument,
uuid: this.uuid, uuid: this.uuid,
update: update, update: update
} }
}); });
} }
} }
async emulateItemDrop(data) { async emulateItemDrop(data) {
const event = new DragEvent("drop", { altKey: game.keyboard.isModifierActive("Alt") }); const event = new DragEvent('drop', { altKey: game.keyboard.isModifierActive('Alt') });
return this.sheet._onDropItem(event, { data: data }); return this.sheet._onDropItem(event, { data: data });
} }
//Move to action-scope? //Move to action-scope?
async useAction(action) { async useAction(action) {
const userTargets = Array.from(game.user.targets); const userTargets = Array.from(game.user.targets);
const otherTarget = action.target.type ===SYSTEM.ACTIONS.targetTypes.other.id; const otherTarget = action.target.type === SYSTEM.ACTIONS.targetTypes.other.id;
if(otherTarget && userTargets.length === 0) { if (otherTarget && userTargets.length === 0) {
ui.notifications.error(game.i18n.localize("DAGGERHEART.Notification.Error.ActionRequiresTarget")); ui.notifications.error(game.i18n.localize('DAGGERHEART.Notification.Error.ActionRequiresTarget'));
return; return;
}
if(action.cost.type != null && action.cost.value != null){
if (this.system.resources[action.cost.type].value < action.cost.value-1) {
ui.notifications.error(game.i18n.localize(`Insufficient ${action.cost.type} to use this ability`));
return;
}
}
// const targets = otherTarget ? userTargets : [game.user.character];
if(action.damage.type){
let roll = { formula: action.damage.value, result: action.damage.value };
if(Number.isNaN(Number.parseInt(action.damage.value))){
roll = await new Roll(`1${action.damage.value}`).evaluate();
} }
const cls = getDocumentClass("ChatMessage"); if (action.cost.type != null && action.cost.value != null) {
const msg = new cls({ if (this.system.resources[action.cost.type].value < action.cost.value - 1) {
user: game.user.id, ui.notifications.error(game.i18n.localize(`Insufficient ${action.cost.type} to use this ability`));
content: await renderTemplate("systems/daggerheart/templates/chat/damage-roll.hbs", { return;
roll: roll.formula, }
total: roll.result,
type: action.damage.type,
}),
});
cls.create(msg.toObject());
}
if(action.healing.type){
let roll = { formula: action.healing.value, result: action.healing.value };
if(Number.isNaN(Number.parseInt(action.healing.value))){
roll = await new Roll(`1${action.healing.value}`).evaluate();
} }
const cls = getDocumentClass("ChatMessage"); // const targets = otherTarget ? userTargets : [game.user.character];
const msg = new cls({ if (action.damage.type) {
user: game.user.id, let roll = { formula: action.damage.value, result: action.damage.value };
content: await renderTemplate("systems/daggerheart/templates/chat/healing-roll.hbs", { if (Number.isNaN(Number.parseInt(action.damage.value))) {
roll: roll.formula, roll = await new Roll(`1${action.damage.value}`).evaluate();
total: roll.result, }
type: action.healing.type,
}), const cls = getDocumentClass('ChatMessage');
}); const msg = new cls({
user: game.user.id,
cls.create(msg.toObject()); content: await renderTemplate('systems/daggerheart/templates/chat/damage-roll.hbs', {
} roll: roll.formula,
total: roll.result,
type: action.damage.type
})
});
cls.create(msg.toObject());
}
if (action.healing.type) {
let roll = { formula: action.healing.value, result: action.healing.value };
if (Number.isNaN(Number.parseInt(action.healing.value))) {
roll = await new Roll(`1${action.healing.value}`).evaluate();
}
const cls = getDocumentClass('ChatMessage');
const msg = new cls({
user: game.user.id,
content: await renderTemplate('systems/daggerheart/templates/chat/healing-roll.hbs', {
roll: roll.formula,
total: roll.result,
type: action.healing.type
})
});
cls.create(msg.toObject());
}
} }
} }

View file

@ -1,11 +1,11 @@
import { GMUpdateEvent, socketEvent } from "../helpers/socket.mjs"; import { GMUpdateEvent, socketEvent } from '../helpers/socket.mjs';
export default class DhpCombat extends Combat { export default class DhpCombat extends Combat {
_sortCombatants(a, b) { _sortCombatants(a, b) {
if(a.isNPC !== b.isNPC){ if (a.isNPC !== b.isNPC) {
const aVal = a.isNPC ? 0 : 1; const aVal = a.isNPC ? 0 : 1;
const bVal = b.isNPC ? 0 : 1; const bVal = b.isNPC ? 0 : 1;
return aVal - bVal; return aVal - bVal;
} }
@ -13,20 +13,23 @@ export default class DhpCombat extends Combat {
} }
async useActionToken(combatantId) { async useActionToken(combatantId) {
const automateActionPoints = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.ActionPoints); const automateActionPoints = await game.settings.get(
SYSTEM.id,
SYSTEM.SETTINGS.gameSettings.Automation.ActionPoints
);
if(game.user.isGM){ if (game.user.isGM) {
if(this.system.actions < 1) return; if (this.system.actions < 1) return;
const update = automateActionPoints ? const update = automateActionPoints
{ "system.activeCombatant": combatantId, "system.actions": Math.max(this.system.actions-1, 0) } : ? { 'system.activeCombatant': combatantId, 'system.actions': Math.max(this.system.actions - 1, 0) }
{ "system.activeCombatant": combatantId }; : { 'system.activeCombatant': combatantId };
await this.update(update); await this.update(update);
} else { } else {
const update = automateActionPoints ? const update = automateActionPoints
{ "system.activeCombatant": combatantId, "system.actions": this.system.actions+1} : ? { 'system.activeCombatant': combatantId, 'system.actions': this.system.actions + 1 }
{ "system.activeCombatant": combatantId }; : { 'system.activeCombatant': combatantId };
await game.socket.emit(`system.${SYSTEM.id}`, { await game.socket.emit(`system.${SYSTEM.id}`, {
action: socketEvent.GMUpdate, action: socketEvent.GMUpdate,
@ -38,4 +41,4 @@ export default class DhpCombat extends Combat {
}); });
} }
} }
} }

View file

@ -1,72 +1,79 @@
export default class DhpItem extends Item { export default class DhpItem extends Item {
_preCreate(data, changes, user){ _preCreate(data, changes, user) {
super._preCreate(data, changes, user); super._preCreate(data, changes, user);
} }
prepareData(){ prepareData() {
super.prepareData(); super.prepareData();
if(this.type === 'class'){ if (this.type === 'class') {
// Bad. Make this better. // Bad. Make this better.
// this.system.domains = CONFIG.daggerheart.DOMAIN.classDomainMap[Object.keys(CONFIG.daggerheart.DOMAIN.classDomainMap).find(x => x === this.name.toLowerCase())]; // this.system.domains = CONFIG.daggerheart.DOMAIN.classDomainMap[Object.keys(CONFIG.daggerheart.DOMAIN.classDomainMap).find(x => x === this.name.toLowerCase())];
} }
} }
isInventoryItem(){ isInventoryItem() {
return ['weapon', 'armor', 'miscellaneous', 'consumable'].includes(this.type); return ['weapon', 'armor', 'miscellaneous', 'consumable'].includes(this.type);
} }
_onUpdate(data, options, userId) { _onUpdate(data, options, userId) {
super._onUpdate(data, options, userId); super._onUpdate(data, options, userId);
} }
static async createDialog(data = {}, { parent = null, pack = null, ...options } = {}) { static async createDialog(data = {}, { parent = null, pack = null, ...options } = {}) {
const documentName = this.metadata.name; const documentName = this.metadata.name;
const types = game.documentTypes[documentName].filter(t => t !== CONST.BASE_DOCUMENT_TYPE); const types = game.documentTypes[documentName].filter(t => t !== CONST.BASE_DOCUMENT_TYPE);
let collection; let collection;
if ( !parent ) { if (!parent) {
if ( pack ) collection = game.packs.get(pack); if (pack) collection = game.packs.get(pack);
else collection = game.collections.get(documentName); else collection = game.collections.get(documentName);
} }
const folders = collection?._formatFolderSelectOptions() ?? []; const folders = collection?._formatFolderSelectOptions() ?? [];
const label = game.i18n.localize(this.metadata.label); const label = game.i18n.localize(this.metadata.label);
const title = game.i18n.format("DOCUMENT.Create", {type: label}); const title = game.i18n.format('DOCUMENT.Create', { type: label });
const typeObjects = types.reduce((obj, t) => { const typeObjects = types.reduce((obj, t) => {
const label = CONFIG[documentName]?.typeLabels?.[t] ?? t; const label = CONFIG[documentName]?.typeLabels?.[t] ?? t;
obj[t] = { value: t, label: game.i18n.has(label) ? game.i18n.localize(label) : t }; obj[t] = { value: t, label: game.i18n.has(label) ? game.i18n.localize(label) : t };
return obj; return obj;
}, {}); }, {});
// Render the document creation form // Render the document creation form
const html = await renderTemplate("systems/daggerheart/templates/sidebar/documentCreate.hbs", { const html = await renderTemplate('systems/daggerheart/templates/sidebar/documentCreate.hbs', {
folders, folders,
name: data.name || game.i18n.format("DOCUMENT.New", {type: label}), name: data.name || game.i18n.format('DOCUMENT.New', { type: label }),
folder: data.folder, folder: data.folder,
hasFolders: folders.length >= 1, hasFolders: folders.length >= 1,
type: data.type || CONFIG[documentName]?.defaultType || typeObjects.armor, type: data.type || CONFIG[documentName]?.defaultType || typeObjects.armor,
types: { types: {
Items: [typeObjects.armor, typeObjects.weapon, typeObjects.consumable, typeObjects.miscellaneous], Items: [typeObjects.armor, typeObjects.weapon, typeObjects.consumable, typeObjects.miscellaneous],
Character: [typeObjects.class, typeObjects.subclass, typeObjects.ancestry, typeObjects.community, typeObjects.feature, typeObjects.domainCard], Character: [
}, typeObjects.class,
hasTypes: types.length > 1 typeObjects.subclass,
}); typeObjects.ancestry,
typeObjects.community,
typeObjects.feature,
typeObjects.domainCard
]
},
hasTypes: types.length > 1
});
// Render the confirmation dialog window // Render the confirmation dialog window
return Dialog.prompt({ return Dialog.prompt({
title: title, title: title,
content: html, content: html,
label: title, label: title,
callback: html => { callback: html => {
const form = html[0].querySelector("form"); const form = html[0].querySelector('form');
const fd = new FormDataExtended(form); const fd = new FormDataExtended(form);
foundry.utils.mergeObject(data, fd.object, {inplace: true}); foundry.utils.mergeObject(data, fd.object, { inplace: true });
if ( !data.folder ) delete data.folder; if (!data.folder) delete data.folder;
if ( types.length === 1 ) data.type = types[0]; if (types.length === 1) data.type = types[0];
if ( !data.name?.trim() ) data.name = this.defaultName(); if (!data.name?.trim()) data.name = this.defaultName();
return this.create(data, {parent, pack, renderSheet: true}); return this.create(data, { parent, pack, renderSheet: true });
}, },
rejectClose: false, rejectClose: false,
options options
}); });
} }
} }

View file

@ -1,7 +1,7 @@
import { getWidthOfText } from "./utils.mjs"; import { getWidthOfText } from './utils.mjs';
export default class RegisterHandlebarsHelpers { export default class RegisterHandlebarsHelpers {
static registerHelpers(){ static registerHelpers() {
Handlebars.registerHelper({ Handlebars.registerHelper({
looseEq: this.looseEq, looseEq: this.looseEq,
times: this.times, times: this.times,
@ -11,60 +11,62 @@ export default class RegisterHandlebarsHelpers {
objectSelector: this.objectSelector, objectSelector: this.objectSelector,
includes: this.includes, includes: this.includes,
simpleEditor: this.simpleEditor, simpleEditor: this.simpleEditor,
debug: this.debug, debug: this.debug
}); });
}; }
static looseEq(a, b){ static looseEq(a, b) {
return a == b; return a == b;
} }
static times(nr, block){ static times(nr, block) {
var accum = ''; var accum = '';
for(var i = 0; i < nr; ++i) for (var i = 0; i < nr; ++i) accum += block.fn(i);
accum += block.fn(i);
return accum; return accum;
} }
static join(...options){ static join(...options) {
return options.slice(0, options.length-1); return options.slice(0, options.length - 1);
} }
static add(a, b){ static add(a, b) {
const aNum = Number.parseInt(a); const aNum = Number.parseInt(a);
const bNum = Number.parseInt(b); const bNum = Number.parseInt(b);
return (Number.isNaN(aNum) ? 0 : aNum) + (Number.isNaN(bNum) ? 0 : bNum); return (Number.isNaN(aNum) ? 0 : aNum) + (Number.isNaN(bNum) ? 0 : bNum);
} }
static subtract(a, b){ static subtract(a, b) {
const aNum = Number.parseInt(a); const aNum = Number.parseInt(a);
const bNum = Number.parseInt(b); const bNum = Number.parseInt(b);
return (Number.isNaN(aNum) ? 0 : aNum) - (Number.isNaN(bNum) ? 0 : bNum); return (Number.isNaN(aNum) ? 0 : aNum) - (Number.isNaN(bNum) ? 0 : bNum);
} }
static objectSelector(options){ static objectSelector(options) {
let { title, values, titleFontSize, ids, style } = options.hash; let { title, values, titleFontSize, ids, style } = options.hash;
const titleLength = getWidthOfText(title, titleFontSize, true, true); const titleLength = getWidthOfText(title, titleFontSize, true, true);
const margins = 12; const margins = 12;
const buttons = options.fn(); const buttons = options.fn();
const nrButtons = Math.max($(buttons).length-1, 1); const nrButtons = Math.max($(buttons).length - 1, 1);
const iconWidth = 26; const iconWidth = 26;
const texts = values.reduce((acc, x, index) => { const texts = values
if(x){ .reduce((acc, x, index) => {
acc.push(`<span class="object-select-item" data-action="viewObject" data-value="${ids[index]}">${x}</span>`); if (x) {
} acc.push(
`<span class="object-select-item" data-action="viewObject" data-value="${ids[index]}">${x}</span>`
);
}
return acc; return acc;
}, []).join(' '); }, [])
.join(' ');
const html = const html = `<div ${style ? 'style="' + style + '"' : ''}">
`<div ${style ? 'style="'+style+'"' : ''}">
<div class="object-select-display iconbar"> <div class="object-select-display iconbar">
<span class="object-select-title">${title}</span> <span class="object-select-title">${title}</span>
<div class="object-select-text" style="padding-left: ${titleLength+margins}px; padding-right: ${nrButtons*iconWidth}px;"> <div class="object-select-text" style="padding-left: ${titleLength + margins}px; padding-right: ${nrButtons * iconWidth}px;">
${texts} ${texts}
</div> </div>
${buttons} ${buttons}
@ -76,25 +78,31 @@ export default class RegisterHandlebarsHelpers {
} }
static rangePicker(options) { static rangePicker(options) {
let {name, value, min, max, step} = options.hash; let { name, value, min, max, step } = options.hash;
name = name || "range"; name = name || 'range';
value = value ?? ""; value = value ?? '';
if ( Number.isNaN(value) ) value = ""; if (Number.isNaN(value)) value = '';
const html = const html = `<input type="range" name="${name}" value="${value}" min="${min}" max="${max}" step="${step}"/>
`<input type="range" name="${name}" value="${value}" min="${min}" max="${max}" step="${step}"/>
<span class="range-value">${value}</span>`; <span class="range-value">${value}</span>`;
return new Handlebars.SafeString(html); return new Handlebars.SafeString(html);
} }
static includes(list, item){ static includes(list, item) {
return list.includes(item); return list.includes(item);
} }
static simpleEditor(content, options) { static simpleEditor(content, options) {
const { target, editable=true, button, engine="tinymce", collaborate=false, class: cssClass } = options.hash; const {
const config = {name: target, value: content, button, collaborate, editable, engine}; target,
editable = true,
button,
engine = 'tinymce',
collaborate = false,
class: cssClass
} = options.hash;
const config = { name: target, value: content, button, collaborate, editable, engine };
const element = foundry.applications.fields.createEditorInput(config); const element = foundry.applications.fields.createEditorInput(config);
if ( cssClass ) element.querySelector(".editor-content").classList.add(cssClass); if (cssClass) element.querySelector('.editor-content').classList.add(cssClass);
return new Handlebars.SafeString(element.outerHTML); return new Handlebars.SafeString(element.outerHTML);
} }
@ -102,4 +110,4 @@ export default class RegisterHandlebarsHelpers {
console.log(JSON.stringify(a)); console.log(JSON.stringify(a));
return a; return a;
} }
} }

View file

@ -1,4 +1,4 @@
export function handleSocketEvent({action=null, data={}}={}) { export function handleSocketEvent({ action = null, data = {} } = {}) {
switch (action) { switch (action) {
case socketEvent.GMUpdate: case socketEvent.GMUpdate:
Hooks.callAll(socketEvent.GMUpdate, data.action, data.uuid, data.update); Hooks.callAll(socketEvent.GMUpdate, data.action, data.uuid, data.update);
@ -8,13 +8,13 @@ export function handleSocketEvent({action=null, data={}}={}) {
break; break;
} }
} }
export const socketEvent = { export const socketEvent = {
GMUpdate: "DhpGMUpdate", GMUpdate: 'DhpGMUpdate',
DhpFearUpdate: "DhpFearUpdate", DhpFearUpdate: 'DhpFearUpdate'
}; };
export const GMUpdateEvent = { export const GMUpdateEvent = {
UpdateDocument: "DhpGMUpdateDocument", UpdateDocument: 'DhpGMUpdateDocument',
UpdateFear: "DhpUpdateFear" UpdateFear: 'DhpUpdateFear'
}; };

View file

@ -1,7 +1,7 @@
export const loadCompendiumOptions = async (compendiums) => { export const loadCompendiumOptions = async compendiums => {
const compendiumValues = []; const compendiumValues = [];
for(var compendium of compendiums){ for (var compendium of compendiums) {
const values = await getCompendiumOptions(compendium); const values = await getCompendiumOptions(compendium);
compendiumValues.push(values); compendiumValues.push(values);
} }
@ -9,11 +9,11 @@ export const loadCompendiumOptions = async (compendiums) => {
return compendiumValues; return compendiumValues;
}; };
const getCompendiumOptions = async (compendium) => { const getCompendiumOptions = async compendium => {
const compendiumPack = await game.packs.get(compendium); const compendiumPack = await game.packs.get(compendium);
const values = []; const values = [];
for(var value of compendiumPack.index){ for (var value of compendiumPack.index) {
const document = await compendiumPack.getDocument(value._id); const document = await compendiumPack.getDocument(value._id);
values.push(document); values.push(document);
} }
@ -34,24 +34,23 @@ export const getWidthOfText = (txt, fontsize, allCaps, bold) => {
// getWidthOfText.e.innerText = txt; // getWidthOfText.e.innerText = txt;
// return getWidthOfText.e.offsetWidth; // return getWidthOfText.e.offsetWidth;
const text = allCaps ? txt.toUpperCase() : txt; const text = allCaps ? txt.toUpperCase() : txt;
if(getWidthOfText.c === undefined){ if (getWidthOfText.c === undefined) {
getWidthOfText.c=document.createElement('canvas'); getWidthOfText.c = document.createElement('canvas');
getWidthOfText.ctx=getWidthOfText.c.getContext('2d'); getWidthOfText.ctx = getWidthOfText.c.getContext('2d');
} }
var fontspec = `${bold ? 'bold': ''} ${fontsize}px` + ' ' + 'Signika, sans-serif'; var fontspec = `${bold ? 'bold' : ''} ${fontsize}px` + ' ' + 'Signika, sans-serif';
if(getWidthOfText.ctx.font !== fontspec) if (getWidthOfText.ctx.font !== fontspec) getWidthOfText.ctx.font = fontspec;
getWidthOfText.ctx.font = fontspec;
return getWidthOfText.ctx.measureText(text).width; return getWidthOfText.ctx.measureText(text).width;
} };
export const padArray = (arr, len, fill) => { export const padArray = (arr, len, fill) => {
return arr.concat(Array(len).fill(fill)).slice(0,len); return arr.concat(Array(len).fill(fill)).slice(0, len);
} };
export const getTier = (level, asNr) => { export const getTier = (level, asNr) => {
switch(Math.floor((level+1)/3)){ switch (Math.floor((level + 1) / 3)) {
case 1: case 1:
return asNr ? 1 : 'tier1'; return asNr ? 1 : 'tier1';
case 2: case 2:
return asNr ? 2 : 'tier2'; return asNr ? 2 : 'tier2';
@ -60,23 +59,26 @@ export const getTier = (level, asNr) => {
default: default:
return asNr ? 0 : 'tier0'; return asNr ? 0 : 'tier0';
} }
} };
export const capitalize = (string) => { export const capitalize = string => {
return string.charAt(0).toUpperCase() + string.slice(1); return string.charAt(0).toUpperCase() + string.slice(1);
} };
export const getPathValue = (path, entity, numeric) => { export const getPathValue = (path, entity, numeric) => {
const pathValue = foundry.utils.getProperty(entity, path); const pathValue = foundry.utils.getProperty(entity, path);
if(pathValue) return numeric ? Number.parseInt(pathValue) : pathValue; if (pathValue) return numeric ? Number.parseInt(pathValue) : pathValue;
return numeric ? Number.parseInt(path) : path; return numeric ? Number.parseInt(path) : path;
}; };
export const generateId = (title, length) => { export const generateId = (title, length) => {
const id = title.split(" ").map((w, i) => { const id = title
const p = w.slugify({replacement: "", strict: true}); .split(' ')
return i ? p.titleCase() : p; .map((w, i) => {
}).join(""); const p = w.slugify({ replacement: '', strict: true });
return Number.isNumeric(length) ? id.slice(0, length).padEnd(length, "0") : id; return i ? p.titleCase() : p;
} })
.join('');
return Number.isNumeric(length) ? id.slice(0, length).padEnd(length, '0') : id;
};

View file

@ -1,5 +1,5 @@
export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLog { export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLog {
constructor(){ constructor() {
super(); super();
this.targetTemplate = { this.targetTemplate = {
@ -9,27 +9,37 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
minimizedSheets: [], minimizedSheets: [],
config: undefined, config: undefined,
targets: undefined targets: undefined
} };
this.setupHooks(); this.setupHooks();
} }
addChatListeners = async (app, html, data) => { addChatListeners = async (app, html, data) => {
html.querySelectorAll('.roll-damage-button').forEach(element => element.addEventListener('click', event => this.onRollDamage(event, data.message))); html.querySelectorAll('.roll-damage-button').forEach(element =>
html.querySelectorAll('.target-container').forEach(element => element.addEventListener('hover', hover(this.hoverTarget, this.unhoverTarget))); // ???? element.addEventListener('click', event => this.onRollDamage(event, data.message))
);
html.querySelectorAll('.target-container').forEach(element =>
element.addEventListener('hover', hover(this.hoverTarget, this.unhoverTarget))
); // ????
// html.find('.target-container').mouseout(this.unhoverTarget); // html.find('.target-container').mouseout(this.unhoverTarget);
html.querySelectorAll('.damage-button').forEach(element => element.addEventListener('click', this.onDamage)); html.querySelectorAll('.damage-button').forEach(element => element.addEventListener('click', this.onDamage));
html.querySelectorAll('.healing-button').forEach(element => element.addEventListener('click', this.onHealing)); html.querySelectorAll('.healing-button').forEach(element => element.addEventListener('click', this.onHealing));
html.querySelectorAll('.target-indicator').forEach(element => element.addEventListener('click', this.onToggleTargets)); html.querySelectorAll('.target-indicator').forEach(element =>
element.addEventListener('click', this.onToggleTargets)
);
html.querySelectorAll('.advantage').forEach(element => element.hover(this.hoverAdvantage)); // ?? html.querySelectorAll('.advantage').forEach(element => element.hover(this.hoverAdvantage)); // ??
html.querySelectorAll('.advantage').forEach(element => element.addEventListener('click', event => this.selectAdvantage.bind(this)(event, data.message))); html.querySelectorAll('.advantage').forEach(element =>
html.querySelectorAll('.ability-use-button').forEach(element => element.addEventListener('click', this.abilityUseButton.bind(this)(event, data.message))); element.addEventListener('click', event => this.selectAdvantage.bind(this)(event, data.message))
} );
html.querySelectorAll('.ability-use-button').forEach(element =>
setupHooks(){ element.addEventListener('click', this.abilityUseButton.bind(this)(event, data.message))
);
};
setupHooks() {
Hooks.on('renderChatMessageHTML', this.addChatListeners.bind()); Hooks.on('renderChatMessageHTML', this.addChatListeners.bind());
} }
close(options){ close(options) {
Hooks.off('renderChatMessageHTML', this.addChatListeners); Hooks.off('renderChatMessageHTML', this.addChatListeners);
super.close(options); super.close(options);
} }
@ -40,47 +50,49 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
await game.user.character.damageRoll(message.system.damage, event.shiftKey); await game.user.character.damageRoll(message.system.damage, event.shiftKey);
}; };
hoverTarget = (event) => { hoverTarget = event => {
event.stopPropagation(); event.stopPropagation();
const token = canvas.tokens.get(event.currentTarget.dataset.token); const token = canvas.tokens.get(event.currentTarget.dataset.token);
if ( !token.controlled ) token._onHoverIn(event, {hoverOutOthers: true}); if (!token.controlled) token._onHoverIn(event, { hoverOutOthers: true });
}
unhoverTarget = (event) => {
const token = canvas.tokens.get(event.currentTarget.dataset.token);
if ( !token.controlled ) token._onHoverOut(event);
}; };
onDamage = async (event) => { unhoverTarget = event => {
const token = canvas.tokens.get(event.currentTarget.dataset.token);
if (!token.controlled) token._onHoverOut(event);
};
onDamage = async event => {
event.stopPropagation(); event.stopPropagation();
const damage = Number.parseInt(event.currentTarget.dataset.value); const damage = Number.parseInt(event.currentTarget.dataset.value);
const targets = Array.from(game.user.targets); const targets = Array.from(game.user.targets);
if(targets.length === 0) ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.NoTargetsSelected")); if (targets.length === 0)
ui.notifications.info(game.i18n.localize('DAGGERHEART.Notification.Info.NoTargetsSelected'));
for(var target of targets){ for (var target of targets) {
await target.actor.takeDamage(damage, event.currentTarget.dataset.type); await target.actor.takeDamage(damage, event.currentTarget.dataset.type);
} }
}; };
onHealing = async (event) => { onHealing = async event => {
event.stopPropagation(); event.stopPropagation();
const healing = Number.parseInt(event.currentTarget.dataset.value); const healing = Number.parseInt(event.currentTarget.dataset.value);
const targets = Array.from(game.user.targets); const targets = Array.from(game.user.targets);
if(targets.length === 0) ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.NoTargetsSelected")); if (targets.length === 0)
ui.notifications.info(game.i18n.localize('DAGGERHEART.Notification.Info.NoTargetsSelected'));
for(var target of targets){ for (var target of targets) {
await target.actor.takeHealing(healing, event.currentTarget.dataset.type); await target.actor.takeHealing(healing, event.currentTarget.dataset.type);
} }
} };
onToggleTargets = async (event) => { onToggleTargets = async event => {
event.stopPropagation(); event.stopPropagation();
$($(event.currentTarget).parent()).find('.target-container').toggleClass('hidden'); $($(event.currentTarget).parent()).find('.target-container').toggleClass('hidden');
}; };
hoverAdvantage = (event) => { hoverAdvantage = event => {
$(event.currentTarget).siblings('.advantage').toggleClass('unused'); $(event.currentTarget).siblings('.advantage').toggleClass('unused');
}; };
@ -88,16 +100,16 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
event.stopPropagation(); event.stopPropagation();
const updateMessage = game.messages.get(message._id); const updateMessage = game.messages.get(message._id);
await updateMessage.update({ system: { advantageSelected: event.currentTarget.id === 'hope' ? 1 : 2 }}); await updateMessage.update({ system: { advantageSelected: event.currentTarget.id === 'hope' ? 1 : 2 } });
$(event.currentTarget).siblings('.advantage').off('click'); $(event.currentTarget).siblings('.advantage').off('click');
$(event.currentTarget).off('click'); $(event.currentTarget).off('click');
} };
abilityUseButton = async (event, message) => { abilityUseButton = async (event, message) => {
event.stopPropagation(); event.stopPropagation();
const action = message.system.actions[Number.parseInt(event.currentTarget.dataset.index)]; const action = message.system.actions[Number.parseInt(event.currentTarget.dataset.index)];
await game.user.character.useAction(action); await game.user.character.useAction(action);
} };
} }

View file

@ -1,200 +1,199 @@
import { GMUpdateEvent, socketEvent } from "../helpers/socket.mjs"; import { GMUpdateEvent, socketEvent } from '../helpers/socket.mjs';
export default class DhpCombatTracker extends foundry.applications.sidebar.tabs.CombatTracker { export default class DhpCombatTracker extends foundry.applications.sidebar.tabs.CombatTracker {
constructor(data, context) { constructor(data, context) {
super(data, context); super(data, context);
Hooks.on(socketEvent.DhpFearUpdate, this.onFearUpdate); Hooks.on(socketEvent.DhpFearUpdate, this.onFearUpdate);
} }
get template(){ get template() {
return 'systems/daggerheart/templates/ui/combatTracker.hbs'; return 'systems/daggerheart/templates/ui/combatTracker.hbs';
} }
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
html.on("click", ".token-action-tokens .use-action-token", this.useActionToken.bind(this)); html.on('click', '.token-action-tokens .use-action-token', this.useActionToken.bind(this));
html.on("click", ".encounter-gm-resources .trade-actions", this.tradeActions.bind(this)); html.on('click', '.encounter-gm-resources .trade-actions', this.tradeActions.bind(this));
html.on("click", ".encounter-gm-resources .trade-fear", this.tradeFear.bind(this)); html.on('click', '.encounter-gm-resources .trade-fear', this.tradeFear.bind(this));
html.on("click", ".encounter-gm-resources .icon-button.up", this.increaseResource.bind(this)); html.on('click', '.encounter-gm-resources .icon-button.up', this.increaseResource.bind(this));
html.on("click", ".encounter-gm-resources .icon-button.down", this.decreaseResource.bind(this)); html.on('click', '.encounter-gm-resources .icon-button.down', this.decreaseResource.bind(this));
} }
async useActionToken(event){ async useActionToken(event) {
event.stopPropagation(); event.stopPropagation();
const combatant = event.currentTarget.dataset.combatant; const combatant = event.currentTarget.dataset.combatant;
await game.combat.useActionToken(combatant); await game.combat.useActionToken(combatant);
} }
async tradeActions(event){ async tradeActions(event) {
if(event.currentTarget.classList.contains('disabled')) return; if (event.currentTarget.classList.contains('disabled')) return;
const currentFear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear); const currentFear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear);
const value = currentFear+1; const value = currentFear + 1;
if(value <= 6){ if (value <= 6) {
Hooks.callAll(socketEvent.GMUpdate,GMUpdateEvent.UpdateFear, null, value); Hooks.callAll(socketEvent.GMUpdate, GMUpdateEvent.UpdateFear, null, value);
await game.socket.emit(`system.${SYSTEM.id}`, { await game.socket.emit(`system.${SYSTEM.id}`, {
action: socketEvent.GMUpdate, action: socketEvent.GMUpdate,
data: { action: GMUpdateEvent.UpdateFear, update: value }, data: { action: GMUpdateEvent.UpdateFear, update: value }
}); });
await game.combat.update({ "system.actions": game.combat.system.actions-2 }); await game.combat.update({ 'system.actions': game.combat.system.actions - 2 });
} }
} }
async tradeFear(){ async tradeFear() {
if(event.currentTarget.classList.contains('disabled')) return; if (event.currentTarget.classList.contains('disabled')) return;
const currentFear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear); const currentFear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear);
const value = currentFear-1; const value = currentFear - 1;
if(value >= 0){ if (value >= 0) {
Hooks.callAll(socketEvent.GMUpdate,GMUpdateEvent.UpdateFear, null, value); Hooks.callAll(socketEvent.GMUpdate, GMUpdateEvent.UpdateFear, null, value);
await game.socket.emit(`system.${SYSTEM.id}`, { await game.socket.emit(`system.${SYSTEM.id}`, {
action: socketEvent.GMUpdate, action: socketEvent.GMUpdate,
data: { action: GMUpdateEvent.UpdateFear, update: value }, data: { action: GMUpdateEvent.UpdateFear, update: value }
}); });
await game.combat.update({ "system.actions": game.combat.system.actions+2 }); await game.combat.update({ 'system.actions': game.combat.system.actions + 2 });
} }
} }
async increaseResource(event) { async increaseResource(event) {
if(event.currentTarget.dataset.type === 'action'){ if (event.currentTarget.dataset.type === 'action') {
await game.combat.update({ "system.actions": game.combat.system.actions+1 }); await game.combat.update({ 'system.actions': game.combat.system.actions + 1 });
} }
const currentFear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear); const currentFear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear);
const value = currentFear+1; const value = currentFear + 1;
if(event.currentTarget.dataset.type === 'fear' && value <= 6){ if (event.currentTarget.dataset.type === 'fear' && value <= 6) {
Hooks.callAll(socketEvent.GMUpdate,GMUpdateEvent.UpdateFear, null, value); Hooks.callAll(socketEvent.GMUpdate, GMUpdateEvent.UpdateFear, null, value);
await game.socket.emit(`system.${SYSTEM.id}`, { await game.socket.emit(`system.${SYSTEM.id}`, {
action: socketEvent.GMUpdate, action: socketEvent.GMUpdate,
data: { action: GMUpdateEvent.UpdateFear, update: value }, data: { action: GMUpdateEvent.UpdateFear, update: value }
}); });
} }
this.render(); this.render();
} }
async decreaseResource(event) { async decreaseResource(event) {
if(event.currentTarget.dataset.type === 'action' && game.combat.system.actions-1 >= 0){ if (event.currentTarget.dataset.type === 'action' && game.combat.system.actions - 1 >= 0) {
await game.combat.update({ "system.actions": game.combat.system.actions-1 }); await game.combat.update({ 'system.actions': game.combat.system.actions - 1 });
} }
const currentFear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear); const currentFear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear);
const value = currentFear-1; const value = currentFear - 1;
if(event.currentTarget.dataset.type === 'fear' && value >= 0){ if (event.currentTarget.dataset.type === 'fear' && value >= 0) {
Hooks.callAll(socketEvent.GMUpdate,GMUpdateEvent.UpdateFear, null, value); Hooks.callAll(socketEvent.GMUpdate, GMUpdateEvent.UpdateFear, null, value);
await game.socket.emit(`system.${SYSTEM.id}`, { await game.socket.emit(`system.${SYSTEM.id}`, {
action: socketEvent.GMUpdate, action: socketEvent.GMUpdate,
data: { action: GMUpdateEvent.UpdateFear, update: value }, data: { action: GMUpdateEvent.UpdateFear, update: value }
}); });
} }
this.render(); this.render();
} }
async getData(options={}) { async getData(options = {}) {
let context = await super.getData(options); let context = await super.getData(options);
// Get the combat encounters possible for the viewed Scene // Get the combat encounters possible for the viewed Scene
const combat = this.viewed; const combat = this.viewed;
const hasCombat = combat !== null; const hasCombat = combat !== null;
const combats = this.combats; const combats = this.combats;
const currentIdx = combats.findIndex(c => c === combat); const currentIdx = combats.findIndex(c => c === combat);
const previousId = currentIdx > 0 ? combats[currentIdx-1].id : null; const previousId = currentIdx > 0 ? combats[currentIdx - 1].id : null;
const nextId = currentIdx < combats.length - 1 ? combats[currentIdx+1].id : null; const nextId = currentIdx < combats.length - 1 ? combats[currentIdx + 1].id : null;
const settings = game.settings.get("core", Combat.CONFIG_SETTING); const settings = game.settings.get('core', Combat.CONFIG_SETTING);
// Prepare rendering data // Prepare rendering data
context = foundry.utils.mergeObject(context, { context = foundry.utils.mergeObject(context, {
combats: combats, combats: combats,
currentIndex: currentIdx + 1, currentIndex: currentIdx + 1,
combatCount: combats.length, combatCount: combats.length,
hasCombat: hasCombat, hasCombat: hasCombat,
combat, combat,
turns: [], turns: [],
previousId, previousId,
nextId, nextId,
started: this.started, started: this.started,
control: false, control: false,
settings, settings,
linked: combat?.scene !== null, linked: combat?.scene !== null,
labels: {} labels: {}
}); });
context.labels.scope = game.i18n.localize(`COMBAT.${context.linked ? "Linked" : "Unlinked"}`); context.labels.scope = game.i18n.localize(`COMBAT.${context.linked ? 'Linked' : 'Unlinked'}`);
if ( !hasCombat ) return context; if (!hasCombat) return context;
// Format information about each combatant in the encounter // Format information about each combatant in the encounter
let hasDecimals = false; let hasDecimals = false;
const turns = []; const turns = [];
for ( let [i, combatant] of combat.turns.entries() ) { for (let [i, combatant] of combat.turns.entries()) {
if ( !combatant.visible ) continue; if (!combatant.visible) continue;
// Prepare turn data // Prepare turn data
const resource = combatant.permission >= CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER ? combatant.resource : null; const resource =
const turn = { combatant.permission >= CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER ? combatant.resource : null;
id: combatant.id, const turn = {
name: combatant.name, id: combatant.id,
img: await this._getCombatantThumbnail(combatant), name: combatant.name,
active: combatant.id === combat.system.activeCombatant, img: await this._getCombatantThumbnail(combatant),
owner: combatant.isOwner, active: combatant.id === combat.system.activeCombatant,
defeated: combatant.isDefeated, owner: combatant.isOwner,
hidden: combatant.hidden, defeated: combatant.isDefeated,
initiative: combatant.initiative, hidden: combatant.hidden,
hasRolled: combatant.initiative !== null, initiative: combatant.initiative,
hasResource: resource !== null, hasRolled: combatant.initiative !== null,
resource: resource, hasResource: resource !== null,
canPing: (combatant.sceneId === canvas.scene?.id) && game.user.hasPermission("PING_CANVAS"), resource: resource,
playerCharacter: game.user?.character?.id === combatant.actor.id, canPing: combatant.sceneId === canvas.scene?.id && game.user.hasPermission('PING_CANVAS'),
ownedByPlayer: combatant.hasPlayerOwner, playerCharacter: game.user?.character?.id === combatant.actor.id,
}; ownedByPlayer: combatant.hasPlayerOwner
if ( (turn.initiative !== null) && !Number.isInteger(turn.initiative) ) hasDecimals = true; };
turn.css = [ if (turn.initiative !== null && !Number.isInteger(turn.initiative)) hasDecimals = true;
turn.active ? "active" : "", turn.css = [turn.active ? 'active' : '', turn.hidden ? 'hidden' : '', turn.defeated ? 'defeated' : '']
turn.hidden ? "hidden" : "", .join(' ')
turn.defeated ? "defeated" : "" .trim();
].join(" ").trim();
// Actor and Token status effects
// Actor and Token status effects turn.effects = new Set();
turn.effects = new Set(); if (combatant.token) {
if ( combatant.token ) { combatant.token.effects.forEach(e => turn.effects.add(e));
combatant.token.effects.forEach(e => turn.effects.add(e)); if (combatant.token.overlayEffect) turn.effects.add(combatant.token.overlayEffect);
if ( combatant.token.overlayEffect ) turn.effects.add(combatant.token.overlayEffect);
}
if ( combatant.actor ) {
for ( const effect of combatant.actor.temporaryEffects ) {
if ( effect.statuses.has(CONFIG.specialStatusEffects.DEFEATED) ) turn.defeated = true;
else if ( effect.icon ) turn.effects.add(effect.icon);
} }
} if (combatant.actor) {
turns.push(turn); for (const effect of combatant.actor.temporaryEffects) {
if (effect.statuses.has(CONFIG.specialStatusEffects.DEFEATED)) turn.defeated = true;
else if (effect.icon) turn.effects.add(effect.icon);
}
}
turns.push(turn);
} }
// Format initiative numeric precision // Format initiative numeric precision
const precision = CONFIG.Combat.initiative.decimals; const precision = CONFIG.Combat.initiative.decimals;
turns.forEach(t => { turns.forEach(t => {
if ( t.initiative !== null ) t.initiative = t.initiative.toFixed(hasDecimals ? precision : 0); if (t.initiative !== null) t.initiative = t.initiative.toFixed(hasDecimals ? precision : 0);
}); });
const fear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear); const fear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear);
// Merge update data for rendering // Merge update data for rendering
return foundry.utils.mergeObject(context, { return foundry.utils.mergeObject(context, {
round: combat.round, round: combat.round,
turn: combat.turn, turn: combat.turn,
turns: turns, turns: turns,
control: combat.combatant?.players?.includes(game.user), control: combat.combatant?.players?.includes(game.user),
fear: fear, fear: fear
}); });
} }
onFearUpdate = async () => { onFearUpdate = async () => {
this.render(true); this.render(true);
} };
async close(options){ async close(options) {
Hooks.off(socketEvent.DhpFearUpdate, this.onFearUpdate); Hooks.off(socketEvent.DhpFearUpdate, this.onFearUpdate);
return super.close(options); return super.close(options);
} }
} }

View file

@ -1,53 +1,53 @@
import { GMUpdateEvent, socketEvent } from "../helpers/socket.mjs"; import { GMUpdateEvent, socketEvent } from '../helpers/socket.mjs';
export default class DhpPlayers extends foundry.applications.ui.Players { export default class DhpPlayers extends foundry.applications.ui.Players {
constructor(data, context) { constructor(data, context) {
super(data, context); super(data, context);
Hooks.on(socketEvent.DhpFearUpdate, this.onFearUpdate); Hooks.on(socketEvent.DhpFearUpdate, this.onFearUpdate);
} }
get template(){ get template() {
return 'systems/daggerheart/templates/ui/players.hbs'; return 'systems/daggerheart/templates/ui/players.hbs';
} }
async getData(options={}) { async getData(options = {}) {
const context = super.getData(options); const context = super.getData(options);
context.fear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear); context.fear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear);
context.user = game.user; context.user = game.user;
return context; return context;
} }
activateListeners(html) { activateListeners(html) {
// Toggle online/offline // Toggle online/offline
html.find(".players-mode").click(this._onToggleOfflinePlayers.bind(this)); html.find('.players-mode').click(this._onToggleOfflinePlayers.bind(this));
html.find(".fear-control.up").click(async event => await this.updateFear(event, 1)); html.find('.fear-control.up').click(async event => await this.updateFear(event, 1));
html.find(".fear-control.down").click(async event => await this.updateFear(event, -1)); html.find('.fear-control.down').click(async event => await this.updateFear(event, -1));
// Context menu // Context menu
const contextOptions = this._getUserContextOptions(); const contextOptions = this._getUserContextOptions();
Hooks.call("getUserContextOptions", html, contextOptions); Hooks.call('getUserContextOptions', html, contextOptions);
new ContextMenu(html, ".player", contextOptions); new ContextMenu(html, '.player', contextOptions);
} }
async updateFear(_, change){ async updateFear(_, change) {
const fear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear); const fear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear);
const value = Math.max(Math.min(fear+change, 6), 0); const value = Math.max(Math.min(fear + change, 6), 0);
Hooks.callAll(socketEvent.GMUpdate,GMUpdateEvent.UpdateFear, null, value); Hooks.callAll(socketEvent.GMUpdate, GMUpdateEvent.UpdateFear, null, value);
await game.socket.emit(`system.${SYSTEM.id}`, { await game.socket.emit(`system.${SYSTEM.id}`, {
action: socketEvent.GMUpdate, action: socketEvent.GMUpdate,
data: { action: GMUpdateEvent.UpdateFear, update: value }, data: { action: GMUpdateEvent.UpdateFear, update: value }
}); });
} }
onFearUpdate = async () => { onFearUpdate = async () => {
this.render(true); this.render(true);
} };
async close(options){ async close(options) {
Hooks.off(socketEvent.DhpFearUpdate, this.onFearUpdate); Hooks.off(socketEvent.DhpFearUpdate, this.onFearUpdate);
return super.close(options); return super.close(options);
} }
} }

View file

@ -1,7 +1,7 @@
export default class DhpRuler extends foundry.canvas.interaction.Ruler { export default class DhpRuler extends foundry.canvas.interaction.Ruler {
_getSegmentLabel(segment, totalDistance) { _getSegmentLabel(segment, totalDistance) {
const range = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.General.RangeMeasurement); const range = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.General.RangeMeasurement);
if(!range.enabled) return super._getSegmentLabel(segment, totalDistance); if (!range.enabled) return super._getSegmentLabel(segment, totalDistance);
const segmentDistance = Math.round(segment.distance * 100) / 100; const segmentDistance = Math.round(segment.distance * 100) / 100;
const totalDistanceValue = Math.round(totalDistance * 100) / 100; const totalDistanceValue = Math.round(totalDistance * 100) / 100;
@ -9,21 +9,21 @@ export default class DhpRuler extends foundry.canvas.interaction.Ruler {
return `${this.#getRangeLabel(segmentDistance, range)} [${this.#getRangeLabel(totalDistanceValue, range)}]`; return `${this.#getRangeLabel(segmentDistance, range)} [${this.#getRangeLabel(totalDistanceValue, range)}]`;
} }
#getRangeLabel(distance, settings){ #getRangeLabel(distance, settings) {
if(distance <= settings.melee){ if (distance <= settings.melee) {
return game.i18n.localize("DAGGERHEART.Range.Melee.Name"); return game.i18n.localize('DAGGERHEART.Range.Melee.Name');
} }
if(distance <= settings.veryClose){ if (distance <= settings.veryClose) {
return game.i18n.localize("DAGGERHEART.Range.VeryClose.Name"); return game.i18n.localize('DAGGERHEART.Range.VeryClose.Name');
} }
if(distance <= settings.close){ if (distance <= settings.close) {
return game.i18n.localize("DAGGERHEART.Range.Close.Name"); return game.i18n.localize('DAGGERHEART.Range.Close.Name');
} }
if(distance <= settings.far){ if (distance <= settings.far) {
return game.i18n.localize("DAGGERHEART.Range.Far.Name"); return game.i18n.localize('DAGGERHEART.Range.Far.Name');
} }
if(distance <= settings.veryFar){ if (distance <= settings.veryFar) {
return game.i18n.localize("DAGGERHEART.Range.VeryFar.Name"); return game.i18n.localize('DAGGERHEART.Range.VeryFar.Name');
} }
} }
} }

9402
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,22 +1,28 @@
{ {
"dependencies": { "dependencies": {
"@yaireo/tagify": "^4.17.9", "@yaireo/tagify": "^4.17.9",
"gulp": "^5.0.0", "gulp": "^5.0.0",
"gulp-less": "^5.0.0", "gulp-less": "^5.0.0",
"rollup": "^4.40.0" "rollup": "^4.40.0"
}, },
"scripts": { "scripts": {
"start": "concurrently \"rollup -c --watch\" \"node ../../../../FoundryDev/main.js --dataPath=../../../ --noupnp\" \"gulp\"", "start": "concurrently \"rollup -c --watch\" \"node ../../../../FoundryDev/main.js --dataPath=../../../ --noupnp\" \"gulp\"",
"start-test": "node ./resources/app/main.js --dataPath=./ && rollup -c --watch && gulp", "start-test": "node ./resources/app/main.js --dataPath=./ && rollup -c --watch && gulp",
"pushLDBtoYML": "node ./tools/pushLDBtoYML.mjs", "pushLDBtoYML": "node ./tools/pushLDBtoYML.mjs",
"pullYMLtoLDB": "node ./tools/pullYMLtoLDB.mjs" "pullYMLtoLDB": "node ./tools/pullYMLtoLDB.mjs"
}, },
"devDependencies": { "devDependencies": {
"@foundryvtt/foundryvtt-cli": "^1.0.2", "@foundryvtt/foundryvtt-cli": "^1.0.2",
"@rollup/plugin-commonjs": "^25.0.7", "@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-node-resolve": "^15.2.3",
"concurrently": "^8.2.2", "concurrently": "^8.2.2",
"postcss": "^8.4.32", "husky": "^9.1.5",
"rollup-plugin-postcss": "^4.0.2" "lint-staged": "^15.2.10",
} "postcss": "^8.4.32",
"prettier": "^3.5.3",
"rollup-plugin-postcss": "^4.0.2"
},
"lint-staged": {
"**/*": "prettier --write --ignore-unknown"
}
} }

View file

@ -1,6 +1,6 @@
/** @type {import('postcss-load-config').Config} */ /** @type {import('postcss-load-config').Config} */
const config = { const config = {
plugins: [] plugins: []
} };
module.exports = config module.exports = config;

View file

@ -7,14 +7,14 @@ export default {
output: { output: {
file: 'build/daggerheart.js', file: 'build/daggerheart.js',
format: 'cjs', format: 'cjs',
sourcemap: true, sourcemap: true
}, },
plugins: [ plugins: [
postcss({ postcss({
config: { config: {
path: './postcss.config.js' path: './postcss.config.js'
}, },
use: { use: {
less: { javascriptEnabled: true } less: { javascriptEnabled: true }
}, },
extensions: ['.less'], extensions: ['.less'],
@ -22,8 +22,8 @@ export default {
}), }),
commonjs({ commonjs({
include: /node_modules/, include: /node_modules/,
requireReturnsDefault: 'auto', requireReturnsDefault: 'auto'
}), }),
resolve() resolve()
], ]
} };

View file

@ -1,30 +1,30 @@
{ {
"name": "Clank", "name": "Clank",
"type": "ancestry", "type": "ancestry",
"_id": "AzKMOIpXnCSLLDEB", "_id": "AzKMOIpXnCSLLDEB",
"img": "icons/svg/item-bag.svg", "img": "icons/svg/item-bag.svg",
"system": { "system": {
"description": "<p><strong>Purposeful Design</strong>: Decide who made you and for what purpose. At character creation, choose one of your Experiences that best aligns with this purpose and gain a permanent +1 bonus to it.</p><p><strong>Efficient</strong>: When you take a short rest, you can choose a long rest move instead of a short rest move.</p>", "description": "<p><strong>Purposeful Design</strong>: Decide who made you and for what purpose. At character creation, choose one of your Experiences that best aligns with this purpose and gain a permanent +1 bonus to it.</p><p><strong>Efficient</strong>: When you take a short rest, you can choose a long rest move instead of a short rest move.</p>",
"abilities": [] "abilities": []
}, },
"effects": [], "effects": [],
"folder": null, "folder": null,
"sort": 100000, "sort": 100000,
"ownership": { "ownership": {
"default": 0, "default": 0,
"NqO2eQGMjrvUO6v9": 3 "NqO2eQGMjrvUO6v9": 3
}, },
"flags": {}, "flags": {},
"_stats": { "_stats": {
"compendiumSource": null, "compendiumSource": null,
"duplicateSource": null, "duplicateSource": null,
"exportSource": null, "exportSource": null,
"coreVersion": "13.344", "coreVersion": "13.344",
"systemId": "daggerheart", "systemId": "daggerheart",
"systemVersion": "0.0.1", "systemVersion": "0.0.1",
"createdTime": 1747990113503, "createdTime": 1747990113503,
"modifiedTime": 1747999445342, "modifiedTime": 1747999445342,
"lastModifiedBy": "NqO2eQGMjrvUO6v9" "lastModifiedBy": "NqO2eQGMjrvUO6v9"
}, },
"_key": "!items!AzKMOIpXnCSLLDEB" "_key": "!items!AzKMOIpXnCSLLDEB"
} }

View file

@ -1,44 +1,44 @@
{ {
"name": "Make a Scene", "name": "Make a Scene",
"type": "feature", "type": "feature",
"_id": "Ddk0PAgwM4VLRbyY", "_id": "Ddk0PAgwM4VLRbyY",
"img": "icons/svg/item-bag.svg", "img": "icons/svg/item-bag.svg",
"system": { "system": {
"actionType": "action", "actionType": "action",
"featureType": { "featureType": {
"type": "normal", "type": "normal",
"data": { "data": {
"property": "spellcastingTrait", "property": "spellcastingTrait",
"max": 1, "max": 1,
"numbers": {} "numbers": {}
} }
},
"refreshData": null,
"multiclass": null,
"disabled": false,
"description": "<p>Spend 3 Hope to temporarily Distract a target within Close range, giving them a -2 penalty to their Difficulty.</p>",
"effects": {},
"actions": [],
"type": "class"
}, },
"refreshData": null, "effects": [],
"multiclass": null, "folder": null,
"disabled": false, "sort": 0,
"description": "<p>Spend 3 Hope to temporarily Distract a target within Close range, giving them a -2 penalty to their Difficulty.</p>", "ownership": {
"effects": {}, "default": 0,
"actions": [], "NqO2eQGMjrvUO6v9": 3
"type": "class" },
}, "flags": {},
"effects": [], "_stats": {
"folder": null, "compendiumSource": null,
"sort": 0, "duplicateSource": null,
"ownership": { "exportSource": null,
"default": 0, "coreVersion": "13.344",
"NqO2eQGMjrvUO6v9": 3 "systemId": "daggerheart",
}, "systemVersion": "0.0.1",
"flags": {}, "createdTime": 1747991384366,
"_stats": { "modifiedTime": 1747991421484,
"compendiumSource": null, "lastModifiedBy": "NqO2eQGMjrvUO6v9"
"duplicateSource": null, },
"exportSource": null, "_key": "!items!Ddk0PAgwM4VLRbyY"
"coreVersion": "13.344",
"systemId": "daggerheart",
"systemVersion": "0.0.1",
"createdTime": 1747991384366,
"modifiedTime": 1747991421484,
"lastModifiedBy": "NqO2eQGMjrvUO6v9"
},
"_key": "!items!Ddk0PAgwM4VLRbyY"
} }

View file

@ -1,47 +1,47 @@
{ {
"name": "Rally", "name": "Rally",
"type": "feature", "type": "feature",
"_id": "8uORDWrXtNFzA00U", "_id": "8uORDWrXtNFzA00U",
"img": "icons/svg/item-bag.svg", "img": "icons/svg/item-bag.svg",
"system": { "system": {
"actionType": "action", "actionType": "action",
"featureType": { "featureType": {
"type": "normal", "type": "normal",
"data": { "data": {
"property": "spellcastingTrait", "property": "spellcastingTrait",
"max": 1, "max": 1,
"numbers": {}, "numbers": {},
"value": "d6" "value": "d6"
} }
},
"refreshData": {
"type": "session"
},
"multiclass": null,
"disabled": false,
"description": "<p>Once per session, describe how you rally the party and give yourself and each of your allies a Rally Die. At level 1, your Rally Die is a d6. A PC can spend their Rally Die to roll it, adding the result to their action roll, reaction roll, damage roll, or to clear a number of Stress equal to the result. At the end of each session, clear all unspent Rally Dice.</p><p>At level 5, your Rally Die increases to a d8.</p>",
"effects": {},
"actions": [],
"type": "class"
}, },
"refreshData": { "effects": [],
"type": "session" "folder": null,
"sort": 0,
"ownership": {
"default": 0,
"NqO2eQGMjrvUO6v9": 3
}, },
"multiclass": null, "flags": {},
"disabled": false, "_stats": {
"description": "<p>Once per session, describe how you rally the party and give yourself and each of your allies a Rally Die. At level 1, your Rally Die is a d6. A PC can spend their Rally Die to roll it, adding the result to their action roll, reaction roll, damage roll, or to clear a number of Stress equal to the result. At the end of each session, clear all unspent Rally Dice.</p><p>At level 5, your Rally Die increases to a d8.</p>", "compendiumSource": null,
"effects": {}, "duplicateSource": null,
"actions": [], "exportSource": null,
"type": "class" "coreVersion": "13.344",
}, "systemId": "daggerheart",
"effects": [], "systemVersion": "0.0.1",
"folder": null, "createdTime": 1747991484460,
"sort": 0, "modifiedTime": 1747991546148,
"ownership": { "lastModifiedBy": "NqO2eQGMjrvUO6v9"
"default": 0, },
"NqO2eQGMjrvUO6v9": 3 "_key": "!items!8uORDWrXtNFzA00U"
},
"flags": {},
"_stats": {
"compendiumSource": null,
"duplicateSource": null,
"exportSource": null,
"coreVersion": "13.344",
"systemId": "daggerheart",
"systemVersion": "0.0.1",
"createdTime": 1747991484460,
"modifiedTime": 1747991546148,
"lastModifiedBy": "NqO2eQGMjrvUO6v9"
},
"_key": "!items!8uORDWrXtNFzA00U"
} }

View file

@ -1,104 +1,93 @@
{ {
"name": "Bard", "name": "Bard",
"type": "class", "type": "class",
"_id": "yKicceU4LesCgKwF", "_id": "yKicceU4LesCgKwF",
"img": "systems/daggerheart/assets/icons/classes/bard.png", "img": "systems/daggerheart/assets/icons/classes/bard.png",
"system": { "system": {
"domains": [ "domains": ["grace", "codex"],
"grace", "classItems": [],
"codex" "damageThresholds": {
], "minor": 0,
"classItems": [], "major": 0,
"damageThresholds": { "severe": 0
"minor": 0, },
"major": 0, "evasion": 10,
"severe": 0 "features": [
}, {
"evasion": 10, "name": "Make a Scene",
"features": [ "img": "icons/svg/item-bag.svg",
{ "uuid": "Compendium.daggerheart.class-features.Item.Ddk0PAgwM4VLRbyY"
"name": "Make a Scene", },
"img": "icons/svg/item-bag.svg", {
"uuid": "Compendium.daggerheart.class-features.Item.Ddk0PAgwM4VLRbyY" "img": "icons/svg/item-bag.svg",
}, "name": "Rally",
{ "uuid": "Compendium.daggerheart.class-features.Item.8uORDWrXtNFzA00U"
"img": "icons/svg/item-bag.svg", }
"name": "Rally", ],
"uuid": "Compendium.daggerheart.class-features.Item.8uORDWrXtNFzA00U" "subclasses": [
} {
], "name": "Troubadour",
"subclasses": [ "img": "icons/svg/item-bag.svg",
{ "uuid": "Compendium.daggerheart.subclasses.Item.T1iBO8i0xRF5c8Q2"
"name": "Troubadour", },
"img": "icons/svg/item-bag.svg", {
"uuid": "Compendium.daggerheart.subclasses.Item.T1iBO8i0xRF5c8Q2" "img": "icons/svg/item-bag.svg",
}, "name": "Wordsmith",
{ "uuid": "Compendium.daggerheart.subclasses.Item.FXT65YDVWFy85EI0"
"img": "icons/svg/item-bag.svg", }
"name": "Wordsmith", ],
"uuid": "Compendium.daggerheart.subclasses.Item.FXT65YDVWFy85EI0" "inventory": {
} "take": [],
], "choiceA": [],
"inventory": { "choiceB": [],
"take": [], "extra": {
"choiceA": [], "title": "",
"choiceB": [], "description": ""
"extra": { }
"title": "", },
"characterGuide": {
"suggestedTraits": {
"agility": 0,
"strength": 0,
"finesse": 0,
"instinct": 0,
"presence": 0,
"knowledge": 0
},
"suggestedPrimaryWeapon": null,
"suggestedSecondaryWeapon": null,
"suggestedArmor": null,
"characterDescription": {
"clothes": "",
"eyes": "",
"body": "",
"color": "",
"attitude": ""
},
"backgroundQuestions": ["", "", ""],
"connections": ["", "", ""]
},
"multiclass": null,
"description": "" "description": ""
}
}, },
"characterGuide": { "effects": [],
"suggestedTraits": { "folder": null,
"agility": 0, "sort": 0,
"strength": 0, "ownership": {
"finesse": 0, "default": 0,
"instinct": 0, "NqO2eQGMjrvUO6v9": 3
"presence": 0,
"knowledge": 0
},
"suggestedPrimaryWeapon": null,
"suggestedSecondaryWeapon": null,
"suggestedArmor": null,
"characterDescription": {
"clothes": "",
"eyes": "",
"body": "",
"color": "",
"attitude": ""
},
"backgroundQuestions": [
"",
"",
""
],
"connections": [
"",
"",
""
]
}, },
"multiclass": null, "flags": {},
"description": "" "_stats": {
}, "compendiumSource": null,
"effects": [], "duplicateSource": null,
"folder": null, "exportSource": null,
"sort": 0, "coreVersion": "13.344",
"ownership": { "systemId": "daggerheart",
"default": 0, "systemVersion": "0.0.1",
"NqO2eQGMjrvUO6v9": 3 "createdTime": 1747946810798,
}, "modifiedTime": 1747991996135,
"flags": {}, "lastModifiedBy": "NqO2eQGMjrvUO6v9"
"_stats": { },
"compendiumSource": null, "_key": "!items!yKicceU4LesCgKwF"
"duplicateSource": null,
"exportSource": null,
"coreVersion": "13.344",
"systemId": "daggerheart",
"systemVersion": "0.0.1",
"createdTime": 1747946810798,
"modifiedTime": 1747991996135,
"lastModifiedBy": "NqO2eQGMjrvUO6v9"
},
"_key": "!items!yKicceU4LesCgKwF"
} }

View file

@ -1,70 +1,62 @@
{ {
"name": "Druid", "name": "Druid",
"type": "class", "type": "class",
"_id": "HEh27jDQCJmnPsXH", "_id": "HEh27jDQCJmnPsXH",
"img": "systems/daggerheart/assets/icons/classes/druid.png", "img": "systems/daggerheart/assets/icons/classes/druid.png",
"system": { "system": {
"domains": [], "domains": [],
"classItems": [], "classItems": [],
"damageThresholds": { "damageThresholds": {
"minor": 0, "minor": 0,
"major": 0, "major": 0,
"severe": 0 "severe": 0
},
"evasion": 0,
"features": [],
"subclasses": [],
"inventory": {
"take": [],
"choiceA": [],
"choiceB": [],
"extra": null
},
"characterGuide": {
"suggestedTraits": {
"agility": 0,
"strength": 0,
"finesse": 0,
"instinct": 0,
"presence": 0,
"knowledge": 0
},
"suggestedPrimaryWeapon": null,
"suggestedSecondaryWeapon": null,
"suggestedArmor": null,
"characterDescription": {},
"backgroundQuestions": ["", "", ""],
"connections": ["", "", ""]
},
"multiclass": null,
"description": ""
}, },
"evasion": 0, "effects": [],
"features": [], "folder": null,
"subclasses": [], "sort": 0,
"inventory": { "ownership": {
"take": [], "default": 0,
"choiceA": [], "NqO2eQGMjrvUO6v9": 3
"choiceB": [],
"extra": null
}, },
"characterGuide": { "flags": {},
"suggestedTraits": { "_stats": {
"agility": 0, "compendiumSource": null,
"strength": 0, "duplicateSource": null,
"finesse": 0, "exportSource": null,
"instinct": 0, "coreVersion": "13.344",
"presence": 0, "systemId": "daggerheart",
"knowledge": 0 "systemVersion": "0.0.1",
}, "createdTime": 1747946822837,
"suggestedPrimaryWeapon": null, "modifiedTime": 1747946826150,
"suggestedSecondaryWeapon": null, "lastModifiedBy": "NqO2eQGMjrvUO6v9"
"suggestedArmor": null,
"characterDescription": {},
"backgroundQuestions": [
"",
"",
""
],
"connections": [
"",
"",
""
]
}, },
"multiclass": null, "_key": "!items!HEh27jDQCJmnPsXH"
"description": ""
},
"effects": [],
"folder": null,
"sort": 0,
"ownership": {
"default": 0,
"NqO2eQGMjrvUO6v9": 3
},
"flags": {},
"_stats": {
"compendiumSource": null,
"duplicateSource": null,
"exportSource": null,
"coreVersion": "13.344",
"systemId": "daggerheart",
"systemVersion": "0.0.1",
"createdTime": 1747946822837,
"modifiedTime": 1747946826150,
"lastModifiedBy": "NqO2eQGMjrvUO6v9"
},
"_key": "!items!HEh27jDQCJmnPsXH"
} }

View file

@ -1,70 +1,62 @@
{ {
"name": "Fighter", "name": "Fighter",
"type": "class", "type": "class",
"_id": "HPzaWaZBc6RvElKd", "_id": "HPzaWaZBc6RvElKd",
"img": "systems/daggerheart/assets/icons/classes/fighter.png", "img": "systems/daggerheart/assets/icons/classes/fighter.png",
"system": { "system": {
"domains": [], "domains": [],
"classItems": [], "classItems": [],
"damageThresholds": { "damageThresholds": {
"minor": 0, "minor": 0,
"major": 0, "major": 0,
"severe": 0 "severe": 0
},
"evasion": 0,
"features": [],
"subclasses": [],
"inventory": {
"take": [],
"choiceA": [],
"choiceB": [],
"extra": null
},
"characterGuide": {
"suggestedTraits": {
"agility": 0,
"strength": 0,
"finesse": 0,
"instinct": 0,
"presence": 0,
"knowledge": 0
},
"suggestedPrimaryWeapon": null,
"suggestedSecondaryWeapon": null,
"suggestedArmor": null,
"characterDescription": {},
"backgroundQuestions": ["", "", ""],
"connections": ["", "", ""]
},
"multiclass": null,
"description": ""
}, },
"evasion": 0, "effects": [],
"features": [], "folder": null,
"subclasses": [], "sort": 0,
"inventory": { "ownership": {
"take": [], "default": 0,
"choiceA": [], "NqO2eQGMjrvUO6v9": 3
"choiceB": [],
"extra": null
}, },
"characterGuide": { "flags": {},
"suggestedTraits": { "_stats": {
"agility": 0, "compendiumSource": null,
"strength": 0, "duplicateSource": null,
"finesse": 0, "exportSource": null,
"instinct": 0, "coreVersion": "13.344",
"presence": 0, "systemId": "daggerheart",
"knowledge": 0 "systemVersion": "0.0.1",
}, "createdTime": 1747946839346,
"suggestedPrimaryWeapon": null, "modifiedTime": 1747946842033,
"suggestedSecondaryWeapon": null, "lastModifiedBy": "NqO2eQGMjrvUO6v9"
"suggestedArmor": null,
"characterDescription": {},
"backgroundQuestions": [
"",
"",
""
],
"connections": [
"",
"",
""
]
}, },
"multiclass": null, "_key": "!items!HPzaWaZBc6RvElKd"
"description": ""
},
"effects": [],
"folder": null,
"sort": 0,
"ownership": {
"default": 0,
"NqO2eQGMjrvUO6v9": 3
},
"flags": {},
"_stats": {
"compendiumSource": null,
"duplicateSource": null,
"exportSource": null,
"coreVersion": "13.344",
"systemId": "daggerheart",
"systemVersion": "0.0.1",
"createdTime": 1747946839346,
"modifiedTime": 1747946842033,
"lastModifiedBy": "NqO2eQGMjrvUO6v9"
},
"_key": "!items!HPzaWaZBc6RvElKd"
} }

View file

@ -1,70 +1,62 @@
{ {
"name": "Guardian", "name": "Guardian",
"type": "class", "type": "class",
"_id": "hyfigmrAoLxFPOW2", "_id": "hyfigmrAoLxFPOW2",
"img": "systems/daggerheart/assets/icons/classes/guardian.png", "img": "systems/daggerheart/assets/icons/classes/guardian.png",
"system": { "system": {
"domains": [], "domains": [],
"classItems": [], "classItems": [],
"damageThresholds": { "damageThresholds": {
"minor": 0, "minor": 0,
"major": 0, "major": 0,
"severe": 0 "severe": 0
},
"evasion": 0,
"features": [],
"subclasses": [],
"inventory": {
"take": [],
"choiceA": [],
"choiceB": [],
"extra": null
},
"characterGuide": {
"suggestedTraits": {
"agility": 0,
"strength": 0,
"finesse": 0,
"instinct": 0,
"presence": 0,
"knowledge": 0
},
"suggestedPrimaryWeapon": null,
"suggestedSecondaryWeapon": null,
"suggestedArmor": null,
"characterDescription": {},
"backgroundQuestions": ["", "", ""],
"connections": ["", "", ""]
},
"multiclass": null,
"description": ""
}, },
"evasion": 0, "effects": [],
"features": [], "folder": null,
"subclasses": [], "sort": 0,
"inventory": { "ownership": {
"take": [], "default": 0,
"choiceA": [], "NqO2eQGMjrvUO6v9": 3
"choiceB": [],
"extra": null
}, },
"characterGuide": { "flags": {},
"suggestedTraits": { "_stats": {
"agility": 0, "compendiumSource": null,
"strength": 0, "duplicateSource": null,
"finesse": 0, "exportSource": null,
"instinct": 0, "coreVersion": "13.344",
"presence": 0, "systemId": "daggerheart",
"knowledge": 0 "systemVersion": "0.0.1",
}, "createdTime": 1747946853583,
"suggestedPrimaryWeapon": null, "modifiedTime": 1747946858579,
"suggestedSecondaryWeapon": null, "lastModifiedBy": "NqO2eQGMjrvUO6v9"
"suggestedArmor": null,
"characterDescription": {},
"backgroundQuestions": [
"",
"",
""
],
"connections": [
"",
"",
""
]
}, },
"multiclass": null, "_key": "!items!hyfigmrAoLxFPOW2"
"description": ""
},
"effects": [],
"folder": null,
"sort": 0,
"ownership": {
"default": 0,
"NqO2eQGMjrvUO6v9": 3
},
"flags": {},
"_stats": {
"compendiumSource": null,
"duplicateSource": null,
"exportSource": null,
"coreVersion": "13.344",
"systemId": "daggerheart",
"systemVersion": "0.0.1",
"createdTime": 1747946853583,
"modifiedTime": 1747946858579,
"lastModifiedBy": "NqO2eQGMjrvUO6v9"
},
"_key": "!items!hyfigmrAoLxFPOW2"
} }

View file

@ -1,70 +1,62 @@
{ {
"name": "Ranger", "name": "Ranger",
"type": "class", "type": "class",
"_id": "XoUsU9sCxEq8t3We", "_id": "XoUsU9sCxEq8t3We",
"img": "systems/daggerheart/assets/icons/classes/ranger.png", "img": "systems/daggerheart/assets/icons/classes/ranger.png",
"system": { "system": {
"domains": [], "domains": [],
"classItems": [], "classItems": [],
"damageThresholds": { "damageThresholds": {
"minor": 0, "minor": 0,
"major": 0, "major": 0,
"severe": 0 "severe": 0
},
"evasion": 0,
"features": [],
"subclasses": [],
"inventory": {
"take": [],
"choiceA": [],
"choiceB": [],
"extra": null
},
"characterGuide": {
"suggestedTraits": {
"agility": 0,
"strength": 0,
"finesse": 0,
"instinct": 0,
"presence": 0,
"knowledge": 0
},
"suggestedPrimaryWeapon": null,
"suggestedSecondaryWeapon": null,
"suggestedArmor": null,
"characterDescription": {},
"backgroundQuestions": ["", "", ""],
"connections": ["", "", ""]
},
"multiclass": null,
"description": ""
}, },
"evasion": 0, "effects": [],
"features": [], "folder": null,
"subclasses": [], "sort": 0,
"inventory": { "ownership": {
"take": [], "default": 0,
"choiceA": [], "NqO2eQGMjrvUO6v9": 3
"choiceB": [],
"extra": null
}, },
"characterGuide": { "flags": {},
"suggestedTraits": { "_stats": {
"agility": 0, "compendiumSource": null,
"strength": 0, "duplicateSource": null,
"finesse": 0, "exportSource": null,
"instinct": 0, "coreVersion": "13.344",
"presence": 0, "systemId": "daggerheart",
"knowledge": 0 "systemVersion": "0.0.1",
}, "createdTime": 1747946878680,
"suggestedPrimaryWeapon": null, "modifiedTime": 1747946882593,
"suggestedSecondaryWeapon": null, "lastModifiedBy": "NqO2eQGMjrvUO6v9"
"suggestedArmor": null,
"characterDescription": {},
"backgroundQuestions": [
"",
"",
""
],
"connections": [
"",
"",
""
]
}, },
"multiclass": null, "_key": "!items!XoUsU9sCxEq8t3We"
"description": ""
},
"effects": [],
"folder": null,
"sort": 0,
"ownership": {
"default": 0,
"NqO2eQGMjrvUO6v9": 3
},
"flags": {},
"_stats": {
"compendiumSource": null,
"duplicateSource": null,
"exportSource": null,
"coreVersion": "13.344",
"systemId": "daggerheart",
"systemVersion": "0.0.1",
"createdTime": 1747946878680,
"modifiedTime": 1747946882593,
"lastModifiedBy": "NqO2eQGMjrvUO6v9"
},
"_key": "!items!XoUsU9sCxEq8t3We"
} }

View file

@ -1,70 +1,62 @@
{ {
"name": "Rogue", "name": "Rogue",
"type": "class", "type": "class",
"_id": "V1a5AKCLe8qtoPlA", "_id": "V1a5AKCLe8qtoPlA",
"img": "systems/daggerheart/assets/icons/classes/rogue.png", "img": "systems/daggerheart/assets/icons/classes/rogue.png",
"system": { "system": {
"domains": [], "domains": [],
"classItems": [], "classItems": [],
"damageThresholds": { "damageThresholds": {
"minor": 0, "minor": 0,
"major": 0, "major": 0,
"severe": 0 "severe": 0
},
"evasion": 0,
"features": [],
"subclasses": [],
"inventory": {
"take": [],
"choiceA": [],
"choiceB": [],
"extra": null
},
"characterGuide": {
"suggestedTraits": {
"agility": 0,
"strength": 0,
"finesse": 0,
"instinct": 0,
"presence": 0,
"knowledge": 0
},
"suggestedPrimaryWeapon": null,
"suggestedSecondaryWeapon": null,
"suggestedArmor": null,
"characterDescription": {},
"backgroundQuestions": ["", "", ""],
"connections": ["", "", ""]
},
"multiclass": null,
"description": ""
}, },
"evasion": 0, "effects": [],
"features": [], "folder": null,
"subclasses": [], "sort": 0,
"inventory": { "ownership": {
"take": [], "default": 0,
"choiceA": [], "NqO2eQGMjrvUO6v9": 3
"choiceB": [],
"extra": null
}, },
"characterGuide": { "flags": {},
"suggestedTraits": { "_stats": {
"agility": 0, "compendiumSource": null,
"strength": 0, "duplicateSource": null,
"finesse": 0, "exportSource": null,
"instinct": 0, "coreVersion": "13.344",
"presence": 0, "systemId": "daggerheart",
"knowledge": 0 "systemVersion": "0.0.1",
}, "createdTime": 1747946902620,
"suggestedPrimaryWeapon": null, "modifiedTime": 1747946906032,
"suggestedSecondaryWeapon": null, "lastModifiedBy": "NqO2eQGMjrvUO6v9"
"suggestedArmor": null,
"characterDescription": {},
"backgroundQuestions": [
"",
"",
""
],
"connections": [
"",
"",
""
]
}, },
"multiclass": null, "_key": "!items!V1a5AKCLe8qtoPlA"
"description": ""
},
"effects": [],
"folder": null,
"sort": 0,
"ownership": {
"default": 0,
"NqO2eQGMjrvUO6v9": 3
},
"flags": {},
"_stats": {
"compendiumSource": null,
"duplicateSource": null,
"exportSource": null,
"coreVersion": "13.344",
"systemId": "daggerheart",
"systemVersion": "0.0.1",
"createdTime": 1747946902620,
"modifiedTime": 1747946906032,
"lastModifiedBy": "NqO2eQGMjrvUO6v9"
},
"_key": "!items!V1a5AKCLe8qtoPlA"
} }

View file

@ -1,70 +1,62 @@
{ {
"name": "Seraph", "name": "Seraph",
"type": "class", "type": "class",
"_id": "qW7yLIe87vd5bbto", "_id": "qW7yLIe87vd5bbto",
"img": "systems/daggerheart/assets/icons/classes/seraph.png", "img": "systems/daggerheart/assets/icons/classes/seraph.png",
"system": { "system": {
"domains": [], "domains": [],
"classItems": [], "classItems": [],
"damageThresholds": { "damageThresholds": {
"minor": 0, "minor": 0,
"major": 0, "major": 0,
"severe": 0 "severe": 0
},
"evasion": 0,
"features": [],
"subclasses": [],
"inventory": {
"take": [],
"choiceA": [],
"choiceB": [],
"extra": null
},
"characterGuide": {
"suggestedTraits": {
"agility": 0,
"strength": 0,
"finesse": 0,
"instinct": 0,
"presence": 0,
"knowledge": 0
},
"suggestedPrimaryWeapon": null,
"suggestedSecondaryWeapon": null,
"suggestedArmor": null,
"characterDescription": {},
"backgroundQuestions": ["", "", ""],
"connections": ["", "", ""]
},
"multiclass": null,
"description": ""
}, },
"evasion": 0, "effects": [],
"features": [], "folder": null,
"subclasses": [], "sort": 0,
"inventory": { "ownership": {
"take": [], "default": 0,
"choiceA": [], "NqO2eQGMjrvUO6v9": 3
"choiceB": [],
"extra": null
}, },
"characterGuide": { "flags": {},
"suggestedTraits": { "_stats": {
"agility": 0, "compendiumSource": null,
"strength": 0, "duplicateSource": null,
"finesse": 0, "exportSource": null,
"instinct": 0, "coreVersion": "13.344",
"presence": 0, "systemId": "daggerheart",
"knowledge": 0 "systemVersion": "0.0.1",
}, "createdTime": 1747946916585,
"suggestedPrimaryWeapon": null, "modifiedTime": 1747946919635,
"suggestedSecondaryWeapon": null, "lastModifiedBy": "NqO2eQGMjrvUO6v9"
"suggestedArmor": null,
"characterDescription": {},
"backgroundQuestions": [
"",
"",
""
],
"connections": [
"",
"",
""
]
}, },
"multiclass": null, "_key": "!items!qW7yLIe87vd5bbto"
"description": ""
},
"effects": [],
"folder": null,
"sort": 0,
"ownership": {
"default": 0,
"NqO2eQGMjrvUO6v9": 3
},
"flags": {},
"_stats": {
"compendiumSource": null,
"duplicateSource": null,
"exportSource": null,
"coreVersion": "13.344",
"systemId": "daggerheart",
"systemVersion": "0.0.1",
"createdTime": 1747946916585,
"modifiedTime": 1747946919635,
"lastModifiedBy": "NqO2eQGMjrvUO6v9"
},
"_key": "!items!qW7yLIe87vd5bbto"
} }

View file

@ -1,70 +1,62 @@
{ {
"name": "Sorcerer", "name": "Sorcerer",
"type": "class", "type": "class",
"_id": "aacMxI9mOTmLO4cj", "_id": "aacMxI9mOTmLO4cj",
"img": "systems/daggerheart/assets/icons/classes/sorcerer.png", "img": "systems/daggerheart/assets/icons/classes/sorcerer.png",
"system": { "system": {
"domains": [], "domains": [],
"classItems": [], "classItems": [],
"damageThresholds": { "damageThresholds": {
"minor": 0, "minor": 0,
"major": 0, "major": 0,
"severe": 0 "severe": 0
},
"evasion": 0,
"features": [],
"subclasses": [],
"inventory": {
"take": [],
"choiceA": [],
"choiceB": [],
"extra": null
},
"characterGuide": {
"suggestedTraits": {
"agility": 0,
"strength": 0,
"finesse": 0,
"instinct": 0,
"presence": 0,
"knowledge": 0
},
"suggestedPrimaryWeapon": null,
"suggestedSecondaryWeapon": null,
"suggestedArmor": null,
"characterDescription": {},
"backgroundQuestions": ["", "", ""],
"connections": ["", "", ""]
},
"multiclass": null,
"description": ""
}, },
"evasion": 0, "effects": [],
"features": [], "folder": null,
"subclasses": [], "sort": 0,
"inventory": { "ownership": {
"take": [], "default": 0,
"choiceA": [], "NqO2eQGMjrvUO6v9": 3
"choiceB": [],
"extra": null
}, },
"characterGuide": { "flags": {},
"suggestedTraits": { "_stats": {
"agility": 0, "compendiumSource": null,
"strength": 0, "duplicateSource": null,
"finesse": 0, "exportSource": null,
"instinct": 0, "coreVersion": "13.344",
"presence": 0, "systemId": "daggerheart",
"knowledge": 0 "systemVersion": "0.0.1",
}, "createdTime": 1747946940010,
"suggestedPrimaryWeapon": null, "modifiedTime": 1747946943869,
"suggestedSecondaryWeapon": null, "lastModifiedBy": "NqO2eQGMjrvUO6v9"
"suggestedArmor": null,
"characterDescription": {},
"backgroundQuestions": [
"",
"",
""
],
"connections": [
"",
"",
""
]
}, },
"multiclass": null, "_key": "!items!aacMxI9mOTmLO4cj"
"description": ""
},
"effects": [],
"folder": null,
"sort": 0,
"ownership": {
"default": 0,
"NqO2eQGMjrvUO6v9": 3
},
"flags": {},
"_stats": {
"compendiumSource": null,
"duplicateSource": null,
"exportSource": null,
"coreVersion": "13.344",
"systemId": "daggerheart",
"systemVersion": "0.0.1",
"createdTime": 1747946940010,
"modifiedTime": 1747946943869,
"lastModifiedBy": "NqO2eQGMjrvUO6v9"
},
"_key": "!items!aacMxI9mOTmLO4cj"
} }

View file

@ -1,70 +1,62 @@
{ {
"name": "Warlock", "name": "Warlock",
"type": "class", "type": "class",
"_id": "kSSIqmgxFTm1Xr9s", "_id": "kSSIqmgxFTm1Xr9s",
"img": "systems/daggerheart/assets/icons/classes/warlock.png", "img": "systems/daggerheart/assets/icons/classes/warlock.png",
"system": { "system": {
"domains": [], "domains": [],
"classItems": [], "classItems": [],
"damageThresholds": { "damageThresholds": {
"minor": 0, "minor": 0,
"major": 0, "major": 0,
"severe": 0 "severe": 0
},
"evasion": 0,
"features": [],
"subclasses": [],
"inventory": {
"take": [],
"choiceA": [],
"choiceB": [],
"extra": null
},
"characterGuide": {
"suggestedTraits": {
"agility": 0,
"strength": 0,
"finesse": 0,
"instinct": 0,
"presence": 0,
"knowledge": 0
},
"suggestedPrimaryWeapon": null,
"suggestedSecondaryWeapon": null,
"suggestedArmor": null,
"characterDescription": {},
"backgroundQuestions": ["", "", ""],
"connections": ["", "", ""]
},
"multiclass": null,
"description": ""
}, },
"evasion": 0, "effects": [],
"features": [], "folder": null,
"subclasses": [], "sort": 0,
"inventory": { "ownership": {
"take": [], "default": 0,
"choiceA": [], "NqO2eQGMjrvUO6v9": 3
"choiceB": [],
"extra": null
}, },
"characterGuide": { "flags": {},
"suggestedTraits": { "_stats": {
"agility": 0, "compendiumSource": null,
"strength": 0, "duplicateSource": null,
"finesse": 0, "exportSource": null,
"instinct": 0, "coreVersion": "13.344",
"presence": 0, "systemId": "daggerheart",
"knowledge": 0 "systemVersion": "0.0.1",
}, "createdTime": 1747946952119,
"suggestedPrimaryWeapon": null, "modifiedTime": 1747946955843,
"suggestedSecondaryWeapon": null, "lastModifiedBy": "NqO2eQGMjrvUO6v9"
"suggestedArmor": null,
"characterDescription": {},
"backgroundQuestions": [
"",
"",
""
],
"connections": [
"",
"",
""
]
}, },
"multiclass": null, "_key": "!items!kSSIqmgxFTm1Xr9s"
"description": ""
},
"effects": [],
"folder": null,
"sort": 0,
"ownership": {
"default": 0,
"NqO2eQGMjrvUO6v9": 3
},
"flags": {},
"_stats": {
"compendiumSource": null,
"duplicateSource": null,
"exportSource": null,
"coreVersion": "13.344",
"systemId": "daggerheart",
"systemVersion": "0.0.1",
"createdTime": 1747946952119,
"modifiedTime": 1747946955843,
"lastModifiedBy": "NqO2eQGMjrvUO6v9"
},
"_key": "!items!kSSIqmgxFTm1Xr9s"
} }

View file

@ -1,70 +1,62 @@
{ {
"name": "Warrior", "name": "Warrior",
"type": "class", "type": "class",
"_id": "ishqAXCT8xLgEbBp", "_id": "ishqAXCT8xLgEbBp",
"img": "systems/daggerheart/assets/icons/classes/warrior.png", "img": "systems/daggerheart/assets/icons/classes/warrior.png",
"system": { "system": {
"domains": [], "domains": [],
"classItems": [], "classItems": [],
"damageThresholds": { "damageThresholds": {
"minor": 0, "minor": 0,
"major": 0, "major": 0,
"severe": 0 "severe": 0
},
"evasion": 0,
"features": [],
"subclasses": [],
"inventory": {
"take": [],
"choiceA": [],
"choiceB": [],
"extra": null
},
"characterGuide": {
"suggestedTraits": {
"agility": 0,
"strength": 0,
"finesse": 0,
"instinct": 0,
"presence": 0,
"knowledge": 0
},
"suggestedPrimaryWeapon": null,
"suggestedSecondaryWeapon": null,
"suggestedArmor": null,
"characterDescription": {},
"backgroundQuestions": ["", "", ""],
"connections": ["", "", ""]
},
"multiclass": null,
"description": ""
}, },
"evasion": 0, "effects": [],
"features": [], "folder": null,
"subclasses": [], "sort": 0,
"inventory": { "ownership": {
"take": [], "default": 0,
"choiceA": [], "NqO2eQGMjrvUO6v9": 3
"choiceB": [],
"extra": null
}, },
"characterGuide": { "flags": {},
"suggestedTraits": { "_stats": {
"agility": 0, "compendiumSource": null,
"strength": 0, "duplicateSource": null,
"finesse": 0, "exportSource": null,
"instinct": 0, "coreVersion": "13.344",
"presence": 0, "systemId": "daggerheart",
"knowledge": 0 "systemVersion": "0.0.1",
}, "createdTime": 1747946965065,
"suggestedPrimaryWeapon": null, "modifiedTime": 1747946967544,
"suggestedSecondaryWeapon": null, "lastModifiedBy": "NqO2eQGMjrvUO6v9"
"suggestedArmor": null,
"characterDescription": {},
"backgroundQuestions": [
"",
"",
""
],
"connections": [
"",
"",
""
]
}, },
"multiclass": null, "_key": "!items!ishqAXCT8xLgEbBp"
"description": ""
},
"effects": [],
"folder": null,
"sort": 0,
"ownership": {
"default": 0,
"NqO2eQGMjrvUO6v9": 3
},
"flags": {},
"_stats": {
"compendiumSource": null,
"duplicateSource": null,
"exportSource": null,
"coreVersion": "13.344",
"systemId": "daggerheart",
"systemVersion": "0.0.1",
"createdTime": 1747946965065,
"modifiedTime": 1747946967544,
"lastModifiedBy": "NqO2eQGMjrvUO6v9"
},
"_key": "!items!ishqAXCT8xLgEbBp"
} }

View file

@ -1,70 +1,62 @@
{ {
"name": "Wizard", "name": "Wizard",
"type": "class", "type": "class",
"_id": "uhj2mZPOC8nbIMTy", "_id": "uhj2mZPOC8nbIMTy",
"img": "systems/daggerheart/assets/icons/classes/wizard.png", "img": "systems/daggerheart/assets/icons/classes/wizard.png",
"system": { "system": {
"domains": [], "domains": [],
"classItems": [], "classItems": [],
"damageThresholds": { "damageThresholds": {
"minor": 0, "minor": 0,
"major": 0, "major": 0,
"severe": 0 "severe": 0
},
"evasion": 0,
"features": [],
"subclasses": [],
"inventory": {
"take": [],
"choiceA": [],
"choiceB": [],
"extra": null
},
"characterGuide": {
"suggestedTraits": {
"agility": 0,
"strength": 0,
"finesse": 0,
"instinct": 0,
"presence": 0,
"knowledge": 0
},
"suggestedPrimaryWeapon": null,
"suggestedSecondaryWeapon": null,
"suggestedArmor": null,
"characterDescription": {},
"backgroundQuestions": ["", "", ""],
"connections": ["", "", ""]
},
"multiclass": null,
"description": ""
}, },
"evasion": 0, "effects": [],
"features": [], "folder": null,
"subclasses": [], "sort": 0,
"inventory": { "ownership": {
"take": [], "default": 0,
"choiceA": [], "NqO2eQGMjrvUO6v9": 3
"choiceB": [],
"extra": null
}, },
"characterGuide": { "flags": {},
"suggestedTraits": { "_stats": {
"agility": 0, "compendiumSource": null,
"strength": 0, "duplicateSource": null,
"finesse": 0, "exportSource": null,
"instinct": 0, "coreVersion": "13.344",
"presence": 0, "systemId": "daggerheart",
"knowledge": 0 "systemVersion": "0.0.1",
}, "createdTime": 1747946791380,
"suggestedPrimaryWeapon": null, "modifiedTime": 1747946799247,
"suggestedSecondaryWeapon": null, "lastModifiedBy": "NqO2eQGMjrvUO6v9"
"suggestedArmor": null,
"characterDescription": {},
"backgroundQuestions": [
"",
"",
""
],
"connections": [
"",
"",
""
]
}, },
"multiclass": null, "_key": "!items!uhj2mZPOC8nbIMTy"
"description": ""
},
"effects": [],
"folder": null,
"sort": 0,
"ownership": {
"default": 0,
"NqO2eQGMjrvUO6v9": 3
},
"flags": {},
"_stats": {
"compendiumSource": null,
"duplicateSource": null,
"exportSource": null,
"coreVersion": "13.344",
"systemId": "daggerheart",
"systemVersion": "0.0.1",
"createdTime": 1747946791380,
"modifiedTime": 1747946799247,
"lastModifiedBy": "NqO2eQGMjrvUO6v9"
},
"_key": "!items!uhj2mZPOC8nbIMTy"
} }

View file

@ -1,36 +1,36 @@
{ {
"name": "Highborne", "name": "Highborne",
"type": "community", "type": "community",
"_id": "8AcV556QwoIzkkea", "_id": "8AcV556QwoIzkkea",
"img": "systems/daggerheart/assets/icons/communities/highborne.png", "img": "systems/daggerheart/assets/icons/communities/highborne.png",
"system": { "system": {
"description": "<p>Being part of a highborne community means you're accustomed to life of elegance, opulence, and prestige within the upper echelons of society. Traditionally, members of a highborne community possess incredible material wealth. While this can take a variety of forms depending on the community—including gold and other minerals, land, or controlling the means of production—this status always comes with power and influence. Highborne place great value on titles and possessions, and there is little social mobility within their ranks. Members of a highborne community often control the political and economic status of the areas in which they live due to their ability to influence people and the economy with their substantial wealth. The health and safety of the less affluent people who live in these locations often hinges on the ability of this highborne ruling class to prioritize the well-being of their subjects over profit.</p><p><em>Highborne are often amiable, candid, conniving, enterprising, ostentatious, and unflappable.</em></p>", "description": "<p>Being part of a highborne community means you're accustomed to life of elegance, opulence, and prestige within the upper echelons of society. Traditionally, members of a highborne community possess incredible material wealth. While this can take a variety of forms depending on the community—including gold and other minerals, land, or controlling the means of production—this status always comes with power and influence. Highborne place great value on titles and possessions, and there is little social mobility within their ranks. Members of a highborne community often control the political and economic status of the areas in which they live due to their ability to influence people and the economy with their substantial wealth. The health and safety of the less affluent people who live in these locations often hinges on the ability of this highborne ruling class to prioritize the well-being of their subjects over profit.</p><p><em>Highborne are often amiable, candid, conniving, enterprising, ostentatious, and unflappable.</em></p>",
"abilities": [ "abilities": [
{ {
"img": "icons/svg/item-bag.svg", "img": "icons/svg/item-bag.svg",
"name": "Privilege", "name": "Privilege",
"uuid": "Compendium.world.community-features.Item.WoMZCTnDcK8GPSh1" "uuid": "Compendium.world.community-features.Item.WoMZCTnDcK8GPSh1"
} }
] ]
}, },
"effects": [], "effects": [],
"folder": null, "folder": null,
"sort": 0, "sort": 0,
"ownership": { "ownership": {
"default": 0, "default": 0,
"NqO2eQGMjrvUO6v9": 3 "NqO2eQGMjrvUO6v9": 3
}, },
"flags": {}, "flags": {},
"_stats": { "_stats": {
"compendiumSource": null, "compendiumSource": null,
"duplicateSource": null, "duplicateSource": null,
"exportSource": null, "exportSource": null,
"coreVersion": "13.344", "coreVersion": "13.344",
"systemId": "daggerheart", "systemId": "daggerheart",
"systemVersion": "0.0.1", "systemVersion": "0.0.1",
"createdTime": 1747940320728, "createdTime": 1747940320728,
"modifiedTime": 1747990568291, "modifiedTime": 1747990568291,
"lastModifiedBy": "NqO2eQGMjrvUO6v9" "lastModifiedBy": "NqO2eQGMjrvUO6v9"
}, },
"_key": "!items!8AcV556QwoIzkkea" "_key": "!items!8AcV556QwoIzkkea"
} }

View file

@ -1,36 +1,36 @@
{ {
"name": "Loreborne", "name": "Loreborne",
"type": "community", "type": "community",
"_id": "fgJHuCdoyXX4Q84O", "_id": "fgJHuCdoyXX4Q84O",
"img": "systems/daggerheart/assets/icons/communities/loreborne.png", "img": "systems/daggerheart/assets/icons/communities/loreborne.png",
"system": { "system": {
"description": "<p>Being part of a loreborne community means youre from a society that favors strong academic or political prowess. Loreborne communities highly value knowledge, frequently in the form of historical preservation, political advancement, scientific study, skill development, or lore and mythology compilation. Most members of these communities research in institutions built in bastions of civilization, while some eclectic few thrive in gathering information from the natural world. Some may be isolationists, operating in smaller enclaves, schools, or guilds and following their own unique ethos. Others still wield their knowledge on a larger scale, making deft political maneuvers across governmental landscapes.</p><p><em>Loreborne are often direct, eloquent, inquisitive, patient,</em></p><p>rhapsodic, and witty.</p>", "description": "<p>Being part of a loreborne community means youre from a society that favors strong academic or political prowess. Loreborne communities highly value knowledge, frequently in the form of historical preservation, political advancement, scientific study, skill development, or lore and mythology compilation. Most members of these communities research in institutions built in bastions of civilization, while some eclectic few thrive in gathering information from the natural world. Some may be isolationists, operating in smaller enclaves, schools, or guilds and following their own unique ethos. Others still wield their knowledge on a larger scale, making deft political maneuvers across governmental landscapes.</p><p><em>Loreborne are often direct, eloquent, inquisitive, patient,</em></p><p>rhapsodic, and witty.</p>",
"abilities": [ "abilities": [
{ {
"img": "icons/svg/item-bag.svg", "img": "icons/svg/item-bag.svg",
"name": "Well-Read", "name": "Well-Read",
"uuid": "Compendium.world.community-features.Item.MUfVlf8hoJ3HZidv" "uuid": "Compendium.world.community-features.Item.MUfVlf8hoJ3HZidv"
} }
] ]
}, },
"effects": [], "effects": [],
"folder": null, "folder": null,
"sort": 0, "sort": 0,
"ownership": { "ownership": {
"default": 0, "default": 0,
"NqO2eQGMjrvUO6v9": 3 "NqO2eQGMjrvUO6v9": 3
}, },
"flags": {}, "flags": {},
"_stats": { "_stats": {
"compendiumSource": null, "compendiumSource": null,
"duplicateSource": null, "duplicateSource": null,
"exportSource": null, "exportSource": null,
"coreVersion": "13.344", "coreVersion": "13.344",
"systemId": "daggerheart", "systemId": "daggerheart",
"systemVersion": "0.0.1", "systemVersion": "0.0.1",
"createdTime": 1747940300210, "createdTime": 1747940300210,
"modifiedTime": 1747990671092, "modifiedTime": 1747990671092,
"lastModifiedBy": "NqO2eQGMjrvUO6v9" "lastModifiedBy": "NqO2eQGMjrvUO6v9"
}, },
"_key": "!items!fgJHuCdoyXX4Q84O" "_key": "!items!fgJHuCdoyXX4Q84O"
} }

View file

@ -1,36 +1,36 @@
{ {
"name": "Orderborne", "name": "Orderborne",
"type": "community", "type": "community",
"_id": "Cg39GoSa6lxhXndW", "_id": "Cg39GoSa6lxhXndW",
"img": "systems/daggerheart/assets/icons/communities/orderborne.png", "img": "systems/daggerheart/assets/icons/communities/orderborne.png",
"system": { "system": {
"description": "<p>Being part of an orderborne community means youre from a collective that focuses on discipline or faith, and you uphold a set of principles that reflect your experience there. Orderborne are frequently some of the most powerful among the surrounding communities.</p><p>By aligning the members of their society around a common value or goal, such as a god, doctrine, ethos, or even a shared business or trade, the ruling bodies of these enclaves are able to mobilize larger populations with less effort.</p><p>While orderborne communities take a variety of forms—some even profoundly pacifistic—perhaps the most feared are those that structure themselves around military prowess. In such a case, its not uncommon for orderborne to provide soldiers for hire to other cities or countries.</p><p><em>Orderborne are often ambitious, benevolent, pensive, prudent, sardonic, and stoic.</em></p>", "description": "<p>Being part of an orderborne community means youre from a collective that focuses on discipline or faith, and you uphold a set of principles that reflect your experience there. Orderborne are frequently some of the most powerful among the surrounding communities.</p><p>By aligning the members of their society around a common value or goal, such as a god, doctrine, ethos, or even a shared business or trade, the ruling bodies of these enclaves are able to mobilize larger populations with less effort.</p><p>While orderborne communities take a variety of forms—some even profoundly pacifistic—perhaps the most feared are those that structure themselves around military prowess. In such a case, its not uncommon for orderborne to provide soldiers for hire to other cities or countries.</p><p><em>Orderborne are often ambitious, benevolent, pensive, prudent, sardonic, and stoic.</em></p>",
"abilities": [ "abilities": [
{ {
"img": "icons/svg/item-bag.svg", "img": "icons/svg/item-bag.svg",
"name": "Dedicated", "name": "Dedicated",
"uuid": "Compendium.world.community-features.Item.b7LmL7ti1gL5kfGq" "uuid": "Compendium.world.community-features.Item.b7LmL7ti1gL5kfGq"
} }
] ]
}, },
"effects": [], "effects": [],
"folder": null, "folder": null,
"sort": 0, "sort": 0,
"ownership": { "ownership": {
"default": 0, "default": 0,
"NqO2eQGMjrvUO6v9": 3 "NqO2eQGMjrvUO6v9": 3
}, },
"flags": {}, "flags": {},
"_stats": { "_stats": {
"compendiumSource": null, "compendiumSource": null,
"duplicateSource": null, "duplicateSource": null,
"exportSource": null, "exportSource": null,
"coreVersion": "13.344", "coreVersion": "13.344",
"systemId": "daggerheart", "systemId": "daggerheart",
"systemVersion": "0.0.1", "systemVersion": "0.0.1",
"createdTime": 1747940332147, "createdTime": 1747940332147,
"modifiedTime": 1747990820386, "modifiedTime": 1747990820386,
"lastModifiedBy": "NqO2eQGMjrvUO6v9" "lastModifiedBy": "NqO2eQGMjrvUO6v9"
}, },
"_key": "!items!Cg39GoSa6lxhXndW" "_key": "!items!Cg39GoSa6lxhXndW"
} }

View file

@ -1,36 +1,36 @@
{ {
"name": "Ridgeborne", "name": "Ridgeborne",
"type": "community", "type": "community",
"_id": "DAQoNvVlc9w7NmZd", "_id": "DAQoNvVlc9w7NmZd",
"img": "systems/daggerheart/assets/icons/communities/ridgeborne.png", "img": "systems/daggerheart/assets/icons/communities/ridgeborne.png",
"system": { "system": {
"description": "<p>Being part of a ridgeborne community means youve called the rocky peaks and sharp cliffs of the mountainside home. Those whove lived in the mountains often consider themselves hardier than most because theyve thrived among the most dangerous terrain many continents have to offer. These groups are adept at adaptation, developing unique technologies and equipment to move both people and products across difficult terrain. As such, ridgeborne grow up scrambling and climbing, making them sturdy and strong-willed. Ridgeborne localities appear in a variety of forms—some cities carve out entire cliff faces, others construct castles of stone, and still more live in small homes on windblown peaks. Outside forces often struggle to attack ridgeborne groups, as the small militias and large military forces of the mountains are adept at utilizing their high-ground advantage.</p><p><em>Ridgeborne are often bold, hardy, indomitable, loyal, reserved, and stubborn.</em></p>", "description": "<p>Being part of a ridgeborne community means youve called the rocky peaks and sharp cliffs of the mountainside home. Those whove lived in the mountains often consider themselves hardier than most because theyve thrived among the most dangerous terrain many continents have to offer. These groups are adept at adaptation, developing unique technologies and equipment to move both people and products across difficult terrain. As such, ridgeborne grow up scrambling and climbing, making them sturdy and strong-willed. Ridgeborne localities appear in a variety of forms—some cities carve out entire cliff faces, others construct castles of stone, and still more live in small homes on windblown peaks. Outside forces often struggle to attack ridgeborne groups, as the small militias and large military forces of the mountains are adept at utilizing their high-ground advantage.</p><p><em>Ridgeborne are often bold, hardy, indomitable, loyal, reserved, and stubborn.</em></p>",
"abilities": [ "abilities": [
{ {
"img": "icons/svg/item-bag.svg", "img": "icons/svg/item-bag.svg",
"name": "Steady", "name": "Steady",
"uuid": "Compendium.world.community-features.Item.hKGv54dst9crq3Sw" "uuid": "Compendium.world.community-features.Item.hKGv54dst9crq3Sw"
} }
] ]
}, },
"effects": [], "effects": [],
"folder": null, "folder": null,
"sort": 0, "sort": 0,
"ownership": { "ownership": {
"default": 0, "default": 0,
"NqO2eQGMjrvUO6v9": 3 "NqO2eQGMjrvUO6v9": 3
}, },
"flags": {}, "flags": {},
"_stats": { "_stats": {
"compendiumSource": null, "compendiumSource": null,
"duplicateSource": null, "duplicateSource": null,
"exportSource": null, "exportSource": null,
"coreVersion": "13.344", "coreVersion": "13.344",
"systemId": "daggerheart", "systemId": "daggerheart",
"systemVersion": "0.0.1", "systemVersion": "0.0.1",
"createdTime": 1747940346633, "createdTime": 1747940346633,
"modifiedTime": 1747990891669, "modifiedTime": 1747990891669,
"lastModifiedBy": "NqO2eQGMjrvUO6v9" "lastModifiedBy": "NqO2eQGMjrvUO6v9"
}, },
"_key": "!items!DAQoNvVlc9w7NmZd" "_key": "!items!DAQoNvVlc9w7NmZd"
} }

View file

@ -1,36 +1,36 @@
{ {
"name": "Seaborne", "name": "Seaborne",
"type": "community", "type": "community",
"_id": "ivrXToGxyuVdqZtG", "_id": "ivrXToGxyuVdqZtG",
"img": "systems/daggerheart/assets/icons/communities/seaborne.png", "img": "systems/daggerheart/assets/icons/communities/seaborne.png",
"system": { "system": {
"description": "<p>Being part of a seaborne community means you lived on or near a large body of water. Seaborne communities are built, both physically and culturally, around the specific waters they call home.</p><p>Some of these groups live along the shore, constructing ports for locals and travelers alike. These harbors function as centers of commerce, tourist attractions, or even just a safe place to lay down ones head after weeks of travel. Other seaborne live on the water in small boats or large ships, with the idea of “home” comprising a ship and its crew, rather than any one landmass.</p><p>No matter their exact location, seaborne communities are closely tied to the ocean tides and the creatures who inhabit them. Seaborne learn to fish at a young age, and train from birth to hold their breath and swim in even the most tumultuous waters. Individuals from these groups are highly sought after for their sailing skills, and many become captains of vessels, whether within their own community, working for another, or even at the helm of a powerful naval operation.<br><em><br>Seaborne are often candid, cooperative, exuberant, fierce, resolute, and weathered.</em></p>", "description": "<p>Being part of a seaborne community means you lived on or near a large body of water. Seaborne communities are built, both physically and culturally, around the specific waters they call home.</p><p>Some of these groups live along the shore, constructing ports for locals and travelers alike. These harbors function as centers of commerce, tourist attractions, or even just a safe place to lay down ones head after weeks of travel. Other seaborne live on the water in small boats or large ships, with the idea of “home” comprising a ship and its crew, rather than any one landmass.</p><p>No matter their exact location, seaborne communities are closely tied to the ocean tides and the creatures who inhabit them. Seaborne learn to fish at a young age, and train from birth to hold their breath and swim in even the most tumultuous waters. Individuals from these groups are highly sought after for their sailing skills, and many become captains of vessels, whether within their own community, working for another, or even at the helm of a powerful naval operation.<br><em><br>Seaborne are often candid, cooperative, exuberant, fierce, resolute, and weathered.</em></p>",
"abilities": [ "abilities": [
{ {
"img": "icons/svg/item-bag.svg", "img": "icons/svg/item-bag.svg",
"name": "Know the Tide", "name": "Know the Tide",
"uuid": "Compendium.world.community-features.Item.coBcBEFpXgtxD1Jt" "uuid": "Compendium.world.community-features.Item.coBcBEFpXgtxD1Jt"
} }
] ]
}, },
"effects": [], "effects": [],
"folder": null, "folder": null,
"sort": 0, "sort": 0,
"ownership": { "ownership": {
"default": 0, "default": 0,
"NqO2eQGMjrvUO6v9": 3 "NqO2eQGMjrvUO6v9": 3
}, },
"flags": {}, "flags": {},
"_stats": { "_stats": {
"compendiumSource": null, "compendiumSource": null,
"duplicateSource": null, "duplicateSource": null,
"exportSource": null, "exportSource": null,
"coreVersion": "13.344", "coreVersion": "13.344",
"systemId": "daggerheart", "systemId": "daggerheart",
"systemVersion": "0.0.1", "systemVersion": "0.0.1",
"createdTime": 1747940375520, "createdTime": 1747940375520,
"modifiedTime": 1747990980804, "modifiedTime": 1747990980804,
"lastModifiedBy": "NqO2eQGMjrvUO6v9" "lastModifiedBy": "NqO2eQGMjrvUO6v9"
}, },
"_key": "!items!ivrXToGxyuVdqZtG" "_key": "!items!ivrXToGxyuVdqZtG"
} }

Some files were not shown because too many files have changed in this diff Show more