mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-17 23:49:02 +01:00
Merge branch 'development' into fix/868-initial-trait-modifiers
This commit is contained in:
commit
51760cc04f
41 changed files with 507 additions and 178 deletions
|
|
@ -13,6 +13,7 @@ import { enrichedDualityRoll } from './module/enrichers/DualityRollEnricher.mjs'
|
||||||
import { registerCountdownHooks } from './module/data/countdowns.mjs';
|
import { registerCountdownHooks } from './module/data/countdowns.mjs';
|
||||||
import {
|
import {
|
||||||
handlebarsRegistration,
|
handlebarsRegistration,
|
||||||
|
runMigrations,
|
||||||
settingsRegistration,
|
settingsRegistration,
|
||||||
socketRegistration
|
socketRegistration
|
||||||
} from './module/systemRegistration/_module.mjs';
|
} from './module/systemRegistration/_module.mjs';
|
||||||
|
|
@ -145,6 +146,11 @@ Hooks.once('init', () => {
|
||||||
// Make Compendium Dialog resizable
|
// Make Compendium Dialog resizable
|
||||||
foundry.applications.sidebar.apps.Compendium.DEFAULT_OPTIONS.window.resizable = true;
|
foundry.applications.sidebar.apps.Compendium.DEFAULT_OPTIONS.window.resizable = true;
|
||||||
|
|
||||||
|
DocumentSheetConfig.registerSheet(foundry.documents.Scene, SYSTEM.id, applications.scene.DhSceneConfigSettings, {
|
||||||
|
makeDefault: true,
|
||||||
|
label: 'Daggerheart'
|
||||||
|
});
|
||||||
|
|
||||||
settingsRegistration.registerDHSettings();
|
settingsRegistration.registerDHSettings();
|
||||||
RegisterHandlebarsHelpers.registerHelpers();
|
RegisterHandlebarsHelpers.registerHelpers();
|
||||||
|
|
||||||
|
|
@ -168,6 +174,8 @@ Hooks.on('ready', async () => {
|
||||||
game.user.setFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.userFlags.welcomeMessage, true);
|
game.user.setFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.userFlags.welcomeMessage, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
runMigrations();
|
||||||
});
|
});
|
||||||
|
|
||||||
Hooks.once('dicesoniceready', () => {});
|
Hooks.once('dicesoniceready', () => {});
|
||||||
|
|
|
||||||
61
lang/en.json
61
lang/en.json
|
|
@ -26,6 +26,14 @@
|
||||||
"CONTROLS": {
|
"CONTROLS": {
|
||||||
"inFront": "In Front"
|
"inFront": "In Front"
|
||||||
},
|
},
|
||||||
|
"SCENE": {
|
||||||
|
"TABS": {
|
||||||
|
"SHEET": {
|
||||||
|
"dh": "Daggerheart"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
"DAGGERHEART": {
|
"DAGGERHEART": {
|
||||||
"ACTIONS": {
|
"ACTIONS": {
|
||||||
"TYPES": {
|
"TYPES": {
|
||||||
|
|
@ -194,7 +202,9 @@
|
||||||
"confirmTitle": "Companion Levelup",
|
"confirmTitle": "Companion Levelup",
|
||||||
"confirmText": "Would you like to level up your companion {name} by {levelChange} levels at this time? (You can do it manually later)"
|
"confirmText": "Would you like to level up your companion {name} by {levelChange} levels at this time? (You can do it manually later)"
|
||||||
},
|
},
|
||||||
"viewLevelups": "View Levelups"
|
"viewLevelups": "View Levelups",
|
||||||
|
"InvalidOldCharacterImportTitle": "Old Character Import",
|
||||||
|
"InvalidOldCharacterImportText": "Character data exported prior to system version 1.1 will not generate a complete character. Do you wish to continue?"
|
||||||
},
|
},
|
||||||
"Companion": {
|
"Companion": {
|
||||||
"FIELDS": {
|
"FIELDS": {
|
||||||
|
|
@ -1890,7 +1900,8 @@
|
||||||
"tier4": "tier 4",
|
"tier4": "tier 4",
|
||||||
"domains": "Domains",
|
"domains": "Domains",
|
||||||
"downtime": "Downtime",
|
"downtime": "Downtime",
|
||||||
"rules": "Rules"
|
"rules": "Rules",
|
||||||
|
"types": "Types"
|
||||||
},
|
},
|
||||||
"Tiers": {
|
"Tiers": {
|
||||||
"singular": "Tier",
|
"singular": "Tier",
|
||||||
|
|
@ -2220,6 +2231,10 @@
|
||||||
"deleteDomain": "Delete Domain",
|
"deleteDomain": "Delete Domain",
|
||||||
"deleteDomainText": "Are you sure you want to delete the {name} domain? It will be immediately removed from all Actors in this world where it's currently used. Compendiums are not cleared.",
|
"deleteDomainText": "Are you sure you want to delete the {name} domain? It will be immediately removed from all Actors in this world where it's currently used. Compendiums are not cleared.",
|
||||||
"duplicateDomain": "There is already a domain with this identification."
|
"duplicateDomain": "There is already a domain with this identification."
|
||||||
|
},
|
||||||
|
"adversaryType": {
|
||||||
|
"title": "Custom Adversary Types",
|
||||||
|
"newType": "Adversary Type"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Menu": {
|
"Menu": {
|
||||||
|
|
@ -2283,6 +2298,9 @@
|
||||||
"ResetSettings": {
|
"ResetSettings": {
|
||||||
"resetConfirmationTitle": "Reset Settings",
|
"resetConfirmationTitle": "Reset Settings",
|
||||||
"resetConfirmationText": "Are you sure you want to reset the {settings}?"
|
"resetConfirmationText": "Are you sure you want to reset the {settings}?"
|
||||||
|
},
|
||||||
|
"Scene": {
|
||||||
|
"rangeMeasurementOverride": "Override Global Range Measurement Settings"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"UI": {
|
"UI": {
|
||||||
|
|
@ -2334,6 +2352,42 @@
|
||||||
"playerMessage": "{user} rerolled their {name}"
|
"playerMessage": "{user} rerolled their {name}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ItemBrowser": {
|
||||||
|
"title": "Daggerheart Compendium Browser",
|
||||||
|
"hint": "Select a Folder in sidebar to start browsing through the compendium",
|
||||||
|
"searchPlaceholder": "Search...",
|
||||||
|
"columnName": "Name",
|
||||||
|
"tooltipFilters": "Filters",
|
||||||
|
"tooltipErase": "Erase",
|
||||||
|
"difficultyMin": "Difficulty (Min)",
|
||||||
|
"difficultyMax": "Difficulty (Max)",
|
||||||
|
"hitPointsMin": "Hit Points (Min)",
|
||||||
|
"hitPointsMax": "Hit Points (Max)",
|
||||||
|
"stressMin": "Stress (Min)",
|
||||||
|
"stressMax": "Stress (Max)",
|
||||||
|
"armorScoreMin": "Armor Score (Min)",
|
||||||
|
"armorScoreMax": "Armor Score (Max)",
|
||||||
|
"levelMin": "Level (Min)",
|
||||||
|
"levelMax": "Level (Max)",
|
||||||
|
"recallCostMin": "Recall Cost (Min)",
|
||||||
|
"recallCostMax": "Recall Cost (Max)",
|
||||||
|
"evasionMin": "Evasion (Min)",
|
||||||
|
"evasionMax": "Evasion (Max)",
|
||||||
|
"subtype": "Subtype",
|
||||||
|
"folders": {
|
||||||
|
"adversaries": "Adversaries",
|
||||||
|
"ancestries": "Ancestries",
|
||||||
|
"equipment": "Equipment",
|
||||||
|
"classes": "Classes",
|
||||||
|
"subclasses": "Subclasses",
|
||||||
|
"domainCards": "Domain Cards",
|
||||||
|
"communities": "Communities",
|
||||||
|
"environments": "Environments",
|
||||||
|
"beastforms": "Beastforms",
|
||||||
|
"features": "Features",
|
||||||
|
"items": "Items"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Notifications": {
|
"Notifications": {
|
||||||
"adversaryMissing": "The linked adversary doesn't exist in the world.",
|
"adversaryMissing": "The linked adversary doesn't exist in the world.",
|
||||||
"beastformInapplicable": "A beastform can only be applied to a Character.",
|
"beastformInapplicable": "A beastform can only be applied to a Character.",
|
||||||
|
|
@ -2393,7 +2447,8 @@
|
||||||
"beastformEquipWeapon": "You cannot use weapons while in a Beastform.",
|
"beastformEquipWeapon": "You cannot use weapons while in a Beastform.",
|
||||||
"loadoutMaxReached": "You've reached maximum loadout. Move atleast one domain card to the vault, or increase the limit in homebrew settings if desired.",
|
"loadoutMaxReached": "You've reached maximum loadout. Move atleast one domain card to the vault, or increase the limit in homebrew settings if desired.",
|
||||||
"domainMaxReached": "You've reached the maximum domains for the class. Increase the limit in homebrew settings if desired.",
|
"domainMaxReached": "You've reached the maximum domains for the class. Increase the limit in homebrew settings if desired.",
|
||||||
"insufficientResources": "You have insufficient resources",
|
"insufficientResources": "You don't have enough resources to use that action.",
|
||||||
|
"actionNoUsesRemaining": "That action doesn't have remaining uses.",
|
||||||
"multiclassAlreadyPresent": "You already have a class and multiclass",
|
"multiclassAlreadyPresent": "You already have a class and multiclass",
|
||||||
"subclassesAlreadyPresent": "You already have a class and multiclass subclass",
|
"subclassesAlreadyPresent": "You already have a class and multiclass subclass",
|
||||||
"noDiceSystem": "Your selected dice {system} does not have a {faces} dice"
|
"noDiceSystem": "Your selected dice {system} does not have a {faces} dice"
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ export * as characterCreation from './characterCreation/_module.mjs';
|
||||||
export * as dialogs from './dialogs/_module.mjs';
|
export * as dialogs from './dialogs/_module.mjs';
|
||||||
export * as hud from './hud/_module.mjs';
|
export * as hud from './hud/_module.mjs';
|
||||||
export * as levelup from './levelup/_module.mjs';
|
export * as levelup from './levelup/_module.mjs';
|
||||||
|
export * as scene from './scene/_module.mjs';
|
||||||
export * as settings from './settings/_module.mjs';
|
export * as settings from './settings/_module.mjs';
|
||||||
export * as sheets from './sheets/_module.mjs';
|
export * as sheets from './sheets/_module.mjs';
|
||||||
export * as sheetConfigs from './sheets-configs/_module.mjs';
|
export * as sheetConfigs from './sheets-configs/_module.mjs';
|
||||||
|
|
|
||||||
1
module/applications/scene/_module.mjs
Normal file
1
module/applications/scene/_module.mjs
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export { default as DhSceneConfigSettings } from './sceneConfigSettings.mjs';
|
||||||
25
module/applications/scene/sceneConfigSettings.mjs
Normal file
25
module/applications/scene/sceneConfigSettings.mjs
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
export default class DhSceneConfigSettings extends foundry.applications.sheets.SceneConfig {
|
||||||
|
constructor(options, ...args) {
|
||||||
|
super(options, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
static buildParts() {
|
||||||
|
const { footer, ...parts } = super.PARTS;
|
||||||
|
const tmpParts = {
|
||||||
|
...parts,
|
||||||
|
dh: { template: "systems/daggerheart/templates/scene/dh-config.hbs" },
|
||||||
|
footer
|
||||||
|
}
|
||||||
|
return tmpParts;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PARTS = DhSceneConfigSettings.buildParts();
|
||||||
|
|
||||||
|
static buildTabs() {
|
||||||
|
super.TABS.sheet.tabs.push({ id: "dh", icon: "fa-solid" });
|
||||||
|
return super.TABS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static TABS = DhSceneConfigSettings.buildTabs();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { DhHomebrew } from '../../data/settings/_module.mjs';
|
import { DhHomebrew } from '../../data/settings/_module.mjs';
|
||||||
import { slugify } from '../../helpers/utils.mjs';
|
import { slugify } from '../../helpers/utils.mjs';
|
||||||
|
|
||||||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||||
|
|
||||||
export default class DhHomebrewSettings extends HandlebarsApplicationMixin(ApplicationV2) {
|
export default class DhHomebrewSettings extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
|
|
@ -10,11 +11,14 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
|
||||||
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).toObject()
|
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).toObject()
|
||||||
);
|
);
|
||||||
|
|
||||||
this.selected = {
|
this.selected = this.#getDefaultAdversaryType();
|
||||||
domain: null
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#getDefaultAdversaryType = () => ({
|
||||||
|
domain: null,
|
||||||
|
adversaryType: null
|
||||||
|
});
|
||||||
|
|
||||||
get title() {
|
get title() {
|
||||||
return game.i18n.localize('DAGGERHEART.SETTINGS.Menu.title');
|
return game.i18n.localize('DAGGERHEART.SETTINGS.Menu.title');
|
||||||
}
|
}
|
||||||
|
|
@ -35,6 +39,9 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
|
||||||
addDomain: this.addDomain,
|
addDomain: this.addDomain,
|
||||||
toggleSelectedDomain: this.toggleSelectedDomain,
|
toggleSelectedDomain: this.toggleSelectedDomain,
|
||||||
deleteDomain: this.deleteDomain,
|
deleteDomain: this.deleteDomain,
|
||||||
|
addAdversaryType: this.addAdversaryType,
|
||||||
|
deleteAdversaryType: this.deleteAdversaryType,
|
||||||
|
selectAdversaryType: this.selectAdversaryType,
|
||||||
save: this.save,
|
save: this.save,
|
||||||
reset: this.reset
|
reset: this.reset
|
||||||
},
|
},
|
||||||
|
|
@ -45,6 +52,7 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
|
||||||
tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' },
|
tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' },
|
||||||
settings: { template: 'systems/daggerheart/templates/settings/homebrew-settings/settings.hbs' },
|
settings: { template: 'systems/daggerheart/templates/settings/homebrew-settings/settings.hbs' },
|
||||||
domains: { template: 'systems/daggerheart/templates/settings/homebrew-settings/domains.hbs' },
|
domains: { template: 'systems/daggerheart/templates/settings/homebrew-settings/domains.hbs' },
|
||||||
|
types: { template: 'systems/daggerheart/templates/settings/homebrew-settings/types.hbs' },
|
||||||
downtime: { template: 'systems/daggerheart/templates/settings/homebrew-settings/downtime.hbs' },
|
downtime: { template: 'systems/daggerheart/templates/settings/homebrew-settings/downtime.hbs' },
|
||||||
footer: { template: 'systems/daggerheart/templates/settings/homebrew-settings/footer.hbs' }
|
footer: { template: 'systems/daggerheart/templates/settings/homebrew-settings/footer.hbs' }
|
||||||
};
|
};
|
||||||
|
|
@ -52,12 +60,19 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
|
||||||
/** @inheritdoc */
|
/** @inheritdoc */
|
||||||
static TABS = {
|
static TABS = {
|
||||||
main: {
|
main: {
|
||||||
tabs: [{ id: 'settings' }, { id: 'domains' }, { id: 'downtime' }],
|
tabs: [{ id: 'settings' }, { id: 'domains' }, { id: 'types' }, { id: 'downtime' }],
|
||||||
initial: 'settings',
|
initial: 'settings',
|
||||||
labelPrefix: 'DAGGERHEART.GENERAL.Tabs'
|
labelPrefix: 'DAGGERHEART.GENERAL.Tabs'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
changeTab(tab, group, options) {
|
||||||
|
super.changeTab(tab, group, options);
|
||||||
|
this.selected = this.#getDefaultAdversaryType();
|
||||||
|
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
async _prepareContext(_options) {
|
async _prepareContext(_options) {
|
||||||
const context = await super._prepareContext(_options);
|
const context = await super._prepareContext(_options);
|
||||||
context.settingFields = this.settings;
|
context.settingFields = this.settings;
|
||||||
|
|
@ -79,6 +94,11 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
|
||||||
context.configDomains = CONFIG.DH.DOMAIN.domains;
|
context.configDomains = CONFIG.DH.DOMAIN.domains;
|
||||||
context.homebrewDomains = this.settings.domains;
|
context.homebrewDomains = this.settings.domains;
|
||||||
break;
|
break;
|
||||||
|
case 'types':
|
||||||
|
context.selectedAdversaryType = this.selected.adversaryType
|
||||||
|
? { id: this.selected.adversaryType, ...this.settings.adversaryTypes[this.selected.adversaryType] }
|
||||||
|
: null;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
|
|
@ -301,6 +321,32 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
|
||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async addAdversaryType(_, target) {
|
||||||
|
const newId = foundry.utils.randomID();
|
||||||
|
await this.settings.updateSource({
|
||||||
|
[`adversaryTypes.${newId}`]: {
|
||||||
|
id: newId,
|
||||||
|
label: game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.adversaryType.newType')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.selected.adversaryType = newId;
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async deleteAdversaryType(_, target) {
|
||||||
|
const { key } = target.dataset;
|
||||||
|
await this.settings.updateSource({ [`adversaryTypes.-=${key}`]: null });
|
||||||
|
|
||||||
|
this.selected.adversaryType = this.selected.adversaryType === key ? null : this.selected.adversaryType;
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async selectAdversaryType(_, target) {
|
||||||
|
this.selected.adversaryType = this.selected.adversaryType === target.dataset.type ? null : target.dataset.type;
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
static async save() {
|
static async save() {
|
||||||
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew, this.settings.toObject());
|
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew, this.settings.toObject());
|
||||||
this.close();
|
this.close();
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ export default class AdversarySheet extends DHBaseActorSheet {
|
||||||
async _prepareContext(options) {
|
async _prepareContext(options) {
|
||||||
const context = await super._prepareContext(options);
|
const context = await super._prepareContext(options);
|
||||||
context.systemFields.attack.fields = this.document.system.attack.schema.fields;
|
context.systemFields.attack.fields = this.document.system.attack.schema.fields;
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,6 +66,9 @@ export default class AdversarySheet extends DHBaseActorSheet {
|
||||||
switch (partId) {
|
switch (partId) {
|
||||||
case 'header':
|
case 'header':
|
||||||
await this._prepareHeaderContext(context, options);
|
await this._prepareHeaderContext(context, options);
|
||||||
|
|
||||||
|
const adversaryTypes = CONFIG.DH.ACTOR.allAdversaryTypes();
|
||||||
|
context.adversaryType = game.i18n.localize(adversaryTypes[this.document.system.type].label);
|
||||||
break;
|
break;
|
||||||
case 'notes':
|
case 'notes':
|
||||||
await this._prepareNotesContext(context, options);
|
await this._prepareNotesContext(context, options);
|
||||||
|
|
|
||||||
|
|
@ -639,7 +639,6 @@ export default function DHApplicationMixin(Base) {
|
||||||
if (featureOnCharacter) {
|
if (featureOnCharacter) {
|
||||||
systemData = {
|
systemData = {
|
||||||
originItemType: this.document.type,
|
originItemType: this.document.type,
|
||||||
originId: this.document.id,
|
|
||||||
identifier: this.document.system.isMulticlass ? 'multiclass' : null
|
identifier: this.document.system.isMulticlass ? 'multiclass' : null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -167,12 +167,12 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
|
||||||
const { type } = target.dataset;
|
const { type } = target.dataset;
|
||||||
const cls = foundry.documents.Item.implementation;
|
const cls = foundry.documents.Item.implementation;
|
||||||
|
|
||||||
|
const multiclass = this.document.system.isMulticlass ? 'multiclass' : null;
|
||||||
let systemData = {};
|
let systemData = {};
|
||||||
if (this.document.parent?.type === 'character') {
|
if (this.document.parent?.type === 'character') {
|
||||||
systemData = {
|
systemData = {
|
||||||
originItemType: this.document.type,
|
originItemType: this.document.type,
|
||||||
originId: this.document.id,
|
identifier: multiclass ?? type
|
||||||
identifier: this.document.system.isMulticlass ? 'multiclass' : null
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -293,14 +293,15 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
|
||||||
|
|
||||||
if (this.document.parent?.type === 'character') {
|
if (this.document.parent?.type === 'character') {
|
||||||
const itemData = item.toObject();
|
const itemData = item.toObject();
|
||||||
|
const multiclass = this.document.system.isMulticlass ? 'multiclass' : null;
|
||||||
item = await cls.create(
|
item = await cls.create(
|
||||||
{
|
{
|
||||||
...itemData,
|
...itemData,
|
||||||
|
_stats: { compendiumSource: this.document.uuid },
|
||||||
system: {
|
system: {
|
||||||
...itemData.system,
|
...itemData.system,
|
||||||
originItemType: this.document.type,
|
originItemType: this.document.type,
|
||||||
originId: this.document.id,
|
identifier: multiclass ?? target.dataset.type
|
||||||
identifier: this.document.system.isMulticlass ? 'multiclass' : null
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ parent: this.document.parent }
|
{ parent: this.document.parent }
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
Object.values(config).forEach(c => {
|
Object.values(config).forEach(c => {
|
||||||
const folder = {
|
const folder = {
|
||||||
id: c.id,
|
id: c.id,
|
||||||
label: c.label,
|
label: game.i18n.localize(c.label),
|
||||||
selected: (!parent || parent.selected) && this.selectedMenu.path[depth] === c.id
|
selected: (!parent || parent.selected) && this.selectedMenu.path[depth] === c.id
|
||||||
};
|
};
|
||||||
folder.folders = c.folders
|
folder.folders = c.folders
|
||||||
|
|
@ -173,11 +173,16 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
folderPath = `${compendium}.folders.${folderId}`,
|
folderPath = `${compendium}.folders.${folderId}`,
|
||||||
folderData = foundry.utils.getProperty(config, folderPath);
|
folderData = foundry.utils.getProperty(config, folderPath);
|
||||||
|
|
||||||
|
const columns = ItemBrowser.getFolderConfig(folderData).map(col => ({
|
||||||
|
...col,
|
||||||
|
label: game.i18n.localize(col.label)
|
||||||
|
}));
|
||||||
|
|
||||||
this.selectedMenu = {
|
this.selectedMenu = {
|
||||||
path: folderPath.split('.'),
|
path: folderPath.split('.'),
|
||||||
data: {
|
data: {
|
||||||
...folderData,
|
...folderData,
|
||||||
columns: ItemBrowser.getFolderConfig(folderData)
|
columns: columns
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -237,6 +242,12 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
else if (typeof f.choices === 'function') {
|
else if (typeof f.choices === 'function') {
|
||||||
f.choices = f.choices();
|
f.choices = f.choices();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear field label so template uses our custom label parameter
|
||||||
|
if (f.field && f.label) {
|
||||||
|
f.field.label = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
f.name ??= f.key;
|
f.name ??= f.key;
|
||||||
f.value = this.presets?.filter?.[f.name]?.value ?? null;
|
f.value = this.presets?.filter?.[f.name]?.value ?? null;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -10,29 +10,41 @@ export default class DhMeasuredTemplate extends foundry.canvas.placeables.Measur
|
||||||
const splitRulerText = this.ruler.text.split(' ');
|
const splitRulerText = this.ruler.text.split(' ');
|
||||||
if (splitRulerText.length > 0) {
|
if (splitRulerText.length > 0) {
|
||||||
const rulerValue = Number(splitRulerText[0]);
|
const rulerValue = Number(splitRulerText[0]);
|
||||||
const vagueLabel = this.constructor.getDistanceLabel(rulerValue, rangeMeasurementSettings);
|
const result = this.constructor.getRangeLabels(rulerValue, rangeMeasurementSettings);
|
||||||
this.ruler.text = vagueLabel;
|
this.ruler.text = result.distance + result.units ? (' ' + result.units) : '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static getDistanceLabel(distance, settings) {
|
static getRangeLabels(distance, settings) {
|
||||||
|
let result = { distance: '', units: null }
|
||||||
|
const rangeMeasurementOverride = canvas.scene.flags.daggerheart?.rangeMeasurementOverride;
|
||||||
|
|
||||||
|
if (rangeMeasurementOverride === true) {
|
||||||
|
result.distance = distance;
|
||||||
|
result.units = canvas.scene?.grid?.units;
|
||||||
|
return result
|
||||||
|
}
|
||||||
if (distance <= settings.melee) {
|
if (distance <= settings.melee) {
|
||||||
return game.i18n.localize('DAGGERHEART.CONFIG.Range.melee.name');
|
result.distance = game.i18n.localize('DAGGERHEART.CONFIG.Range.melee.name');
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
if (distance <= settings.veryClose) {
|
if (distance <= settings.veryClose) {
|
||||||
return game.i18n.localize('DAGGERHEART.CONFIG.Range.veryClose.name');
|
result.distance = game.i18n.localize('DAGGERHEART.CONFIG.Range.veryClose.name');
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
if (distance <= settings.close) {
|
if (distance <= settings.close) {
|
||||||
return game.i18n.localize('DAGGERHEART.CONFIG.Range.close.name');
|
result.distance = game.i18n.localize('DAGGERHEART.CONFIG.Range.close.name');
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
if (distance <= settings.far) {
|
if (distance <= settings.far) {
|
||||||
return game.i18n.localize('DAGGERHEART.CONFIG.Range.far.name');
|
result.distance = game.i18n.localize('DAGGERHEART.CONFIG.Range.far.name');
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
if (distance > settings.far) {
|
if (distance > settings.far) {
|
||||||
return game.i18n.localize('DAGGERHEART.CONFIG.Range.veryFar.name');
|
result.distance = game.i18n.localize('DAGGERHEART.CONFIG.Range.veryFar.name');
|
||||||
}
|
}
|
||||||
|
|
||||||
return '';
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@ export default class DhpRuler extends foundry.canvas.interaction.Ruler {
|
||||||
const range = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.variantRules).rangeMeasurement;
|
const range = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.variantRules).rangeMeasurement;
|
||||||
|
|
||||||
if (range.enabled) {
|
if (range.enabled) {
|
||||||
const distance = DhMeasuredTemplate.getDistanceLabel(waypoint.measurement.distance.toNearest(0.01), range);
|
const result = DhMeasuredTemplate.getRangeLabels(waypoint.measurement.distance.toNearest(0.01), range);
|
||||||
context.cost = { total: distance, units: null };
|
context.cost = { total: result.distance, units: result.units };
|
||||||
context.distance = { total: distance, units: null };
|
context.distance = { total: result.distance, units: result.units };
|
||||||
}
|
}
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@ export default class DhpTokenRuler extends foundry.canvas.placeables.tokens.Toke
|
||||||
const range = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.variantRules).rangeMeasurement;
|
const range = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.variantRules).rangeMeasurement;
|
||||||
|
|
||||||
if (range.enabled) {
|
if (range.enabled) {
|
||||||
const distance = DhMeasuredTemplate.getDistanceLabel(waypoint.measurement.distance.toNearest(0.01), range);
|
const result = DhMeasuredTemplate.getRangeLabels(waypoint.measurement.distance.toNearest(0.01), range);
|
||||||
context.cost = { total: distance, units: null };
|
context.cost = { total: result.distance, units: result.units };
|
||||||
context.distance = { total: distance, units: null };
|
context.distance = { total: result.distance, units: result.units };
|
||||||
}
|
}
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
|
|
|
||||||
|
|
@ -157,6 +157,11 @@ export const adversaryTypes = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const allAdversaryTypes = () => ({
|
||||||
|
...adversaryTypes,
|
||||||
|
...game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).adversaryTypes
|
||||||
|
});
|
||||||
|
|
||||||
export const environmentTypes = {
|
export const environmentTypes = {
|
||||||
exploration: {
|
exploration: {
|
||||||
label: 'DAGGERHEART.CONFIG.EnvironmentType.exploration.label',
|
label: 'DAGGERHEART.CONFIG.EnvironmentType.exploration.label',
|
||||||
|
|
|
||||||
|
|
@ -3,63 +3,63 @@ export const typeConfig = {
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
key: "system.tier",
|
key: "system.tier",
|
||||||
label: "Tier"
|
label: "DAGGERHEART.GENERAL.Tiers.singular"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.type",
|
key: "system.type",
|
||||||
label: "Type"
|
label: "DAGGERHEART.GENERAL.type"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
key: "system.tier",
|
key: "system.tier",
|
||||||
label: "Tier",
|
label: "DAGGERHEART.GENERAL.Tiers.singular",
|
||||||
field: 'system.api.models.actors.DhAdversary.schema.fields.tier'
|
field: 'system.api.models.actors.DhAdversary.schema.fields.tier'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.type",
|
key: "system.type",
|
||||||
label: "Type",
|
label: "DAGGERHEART.GENERAL.type",
|
||||||
field: 'system.api.models.actors.DhAdversary.schema.fields.type'
|
field: 'system.api.models.actors.DhAdversary.schema.fields.type'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.difficulty",
|
key: "system.difficulty",
|
||||||
name: "difficulty.min",
|
name: "difficulty.min",
|
||||||
label: "Difficulty (Min)",
|
label: "DAGGERHEART.UI.ItemBrowser.difficultyMin",
|
||||||
field: 'system.api.models.actors.DhAdversary.schema.fields.difficulty',
|
field: 'system.api.models.actors.DhAdversary.schema.fields.difficulty',
|
||||||
operator: "gte"
|
operator: "gte"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.difficulty",
|
key: "system.difficulty",
|
||||||
name: "difficulty.max",
|
name: "difficulty.max",
|
||||||
label: "Difficulty (Max)",
|
label: "DAGGERHEART.UI.ItemBrowser.difficultyMax",
|
||||||
field: 'system.api.models.actors.DhAdversary.schema.fields.difficulty',
|
field: 'system.api.models.actors.DhAdversary.schema.fields.difficulty',
|
||||||
operator: "lte"
|
operator: "lte"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.resources.hitPoints.max",
|
key: "system.resources.hitPoints.max",
|
||||||
name: "hp.min",
|
name: "hp.min",
|
||||||
label: "Hit Points (Min)",
|
label: "DAGGERHEART.UI.ItemBrowser.hitPointsMin",
|
||||||
field: 'system.api.models.actors.DhAdversary.schema.fields.resources.fields.hitPoints.fields.max',
|
field: 'system.api.models.actors.DhAdversary.schema.fields.resources.fields.hitPoints.fields.max',
|
||||||
operator: "gte"
|
operator: "gte"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.resources.hitPoints.max",
|
key: "system.resources.hitPoints.max",
|
||||||
name: "hp.max",
|
name: "hp.max",
|
||||||
label: "Hit Points (Max)",
|
label: "DAGGERHEART.UI.ItemBrowser.hitPointsMax",
|
||||||
field: 'system.api.models.actors.DhAdversary.schema.fields.resources.fields.hitPoints.fields.max',
|
field: 'system.api.models.actors.DhAdversary.schema.fields.resources.fields.hitPoints.fields.max',
|
||||||
operator: "lte"
|
operator: "lte"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.resources.stress.max",
|
key: "system.resources.stress.max",
|
||||||
name: "stress.min",
|
name: "stress.min",
|
||||||
label: "Stress (Min)",
|
label: "DAGGERHEART.UI.ItemBrowser.stressMin",
|
||||||
field: 'system.api.models.actors.DhAdversary.schema.fields.resources.fields.stress.fields.max',
|
field: 'system.api.models.actors.DhAdversary.schema.fields.resources.fields.stress.fields.max',
|
||||||
operator: "gte"
|
operator: "gte"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.resources.stress.max",
|
key: "system.resources.stress.max",
|
||||||
name: "stress.max",
|
name: "stress.max",
|
||||||
label: "Stress (Max)",
|
label: "DAGGERHEART.UI.ItemBrowser.stressMax",
|
||||||
field: 'system.api.models.actors.DhAdversary.schema.fields.resources.fields.stress.fields.max',
|
field: 'system.api.models.actors.DhAdversary.schema.fields.resources.fields.stress.fields.max',
|
||||||
operator: "lte"
|
operator: "lte"
|
||||||
},
|
},
|
||||||
|
|
@ -69,70 +69,70 @@ export const typeConfig = {
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
key: "type",
|
key: "type",
|
||||||
label: "Type"
|
label: "DAGGERHEART.GENERAL.type"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.secondary",
|
key: "system.secondary",
|
||||||
label: "Subtype",
|
label: "DAGGERHEART.UI.ItemBrowser.subtype",
|
||||||
format: (isSecondary) => isSecondary ? "secondary" : (isSecondary === false ? "primary" : '-')
|
format: (isSecondary) => isSecondary ? "secondary" : (isSecondary === false ? "primary" : '-')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.tier",
|
key: "system.tier",
|
||||||
label: "Tier"
|
label: "DAGGERHEART.GENERAL.Tiers.singular"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
key: "type",
|
key: "type",
|
||||||
label: "Type",
|
label: "DAGGERHEART.GENERAL.type",
|
||||||
choices: () => CONFIG.Item.documentClass.TYPES.filter(t => ["armor", "weapon", "consumable", "loot"].includes(t)).map(t => ({ value: t, label: t }))
|
choices: () => CONFIG.Item.documentClass.TYPES.filter(t => ["armor", "weapon", "consumable", "loot"].includes(t)).map(t => ({ value: t, label: t }))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.secondary",
|
key: "system.secondary",
|
||||||
label: "Subtype",
|
label: "DAGGERHEART.UI.ItemBrowser.subtype",
|
||||||
choices: [
|
choices: [
|
||||||
{ value: false, label: "Primary Weapon"},
|
{ value: false, label: "DAGGERHEART.ITEMS.Weapon.primaryWeapon" },
|
||||||
{ value: true, label: "Secondary Weapon"}
|
{ value: true, label: "DAGGERHEART.ITEMS.Weapon.secondaryWeapon" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.tier",
|
key: "system.tier",
|
||||||
label: "Tier",
|
label: "DAGGERHEART.GENERAL.Tiers.singular",
|
||||||
choices: [{ value: "1", label: "1"}, { value: "2", label: "2"}, { value: "3", label: "3"}, { value: "4", label: "4"}]
|
choices: [{ value: "1", label: "1" }, { value: "2", label: "2" }, { value: "3", label: "3" }, { value: "4", label: "4" }]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.burden",
|
key: "system.burden",
|
||||||
label: "Burden",
|
label: "DAGGERHEART.GENERAL.burden",
|
||||||
field: 'system.api.models.items.DHWeapon.schema.fields.burden'
|
field: 'system.api.models.items.DHWeapon.schema.fields.burden'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.attack.roll.trait",
|
key: "system.attack.roll.trait",
|
||||||
label: "Trait",
|
label: "DAGGERHEART.GENERAL.Trait.single",
|
||||||
field: 'system.api.models.actions.actionsTypes.attack.schema.fields.roll.fields.trait'
|
field: 'system.api.models.actions.actionsTypes.attack.schema.fields.roll.fields.trait'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.attack.range",
|
key: "system.attack.range",
|
||||||
label: "Range",
|
label: "DAGGERHEART.GENERAL.range",
|
||||||
field: 'system.api.models.actions.actionsTypes.attack.schema.fields.range'
|
field: 'system.api.models.actions.actionsTypes.attack.schema.fields.range'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.baseScore",
|
key: "system.baseScore",
|
||||||
name: "armor.min",
|
name: "armor.min",
|
||||||
label: "Armor Score (Min)",
|
label: "DAGGERHEART.UI.ItemBrowser.armorScoreMin",
|
||||||
field: 'system.api.models.items.DHArmor.schema.fields.baseScore',
|
field: 'system.api.models.items.DHArmor.schema.fields.baseScore',
|
||||||
operator: "gte"
|
operator: "gte"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.baseScore",
|
key: "system.baseScore",
|
||||||
name: "armor.max",
|
name: "armor.max",
|
||||||
label: "Armor Score (Max)",
|
label: "DAGGERHEART.UI.ItemBrowser.armorScoreMax",
|
||||||
field: 'system.api.models.items.DHArmor.schema.fields.baseScore',
|
field: 'system.api.models.items.DHArmor.schema.fields.baseScore',
|
||||||
operator: "lte"
|
operator: "lte"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.itemFeatures",
|
key: "system.itemFeatures",
|
||||||
label: "Features",
|
label: "DAGGERHEART.GENERAL.features",
|
||||||
choices: () => [...Object.entries(CONFIG.DH.ITEM.weaponFeatures), ...Object.entries(CONFIG.DH.ITEM.armorFeatures)].map(([k,v]) => ({ value: k, label: v.label})),
|
choices: () => [...Object.entries(CONFIG.DH.ITEM.weaponFeatures), ...Object.entries(CONFIG.DH.ITEM.armorFeatures)].map(([k, v]) => ({ value: k, label: v.label })),
|
||||||
operator: "contains3"
|
operator: "contains3"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
@ -149,54 +149,54 @@ export const typeConfig = {
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
key: "system.type",
|
key: "system.type",
|
||||||
label: "Type"
|
label: "DAGGERHEART.GENERAL.type"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.domain",
|
key: "system.domain",
|
||||||
label: "Domain"
|
label: "DAGGERHEART.GENERAL.Domain.single"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.level",
|
key: "system.level",
|
||||||
label: "Level"
|
label: "DAGGERHEART.GENERAL.level"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
key: "system.type",
|
key: "system.type",
|
||||||
label: "Type",
|
label: "DAGGERHEART.GENERAL.type",
|
||||||
field: 'system.api.models.items.DHDomainCard.schema.fields.type'
|
field: 'system.api.models.items.DHDomainCard.schema.fields.type'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.domain",
|
key: "system.domain",
|
||||||
label: "Domain",
|
label: "DAGGERHEART.GENERAL.Domain.single",
|
||||||
field: 'system.api.models.items.DHDomainCard.schema.fields.domain',
|
field: 'system.api.models.items.DHDomainCard.schema.fields.domain',
|
||||||
operator: "contains2"
|
operator: "contains2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.level",
|
key: "system.level",
|
||||||
name: "level.min",
|
name: "level.min",
|
||||||
label: "Level (Min)",
|
label: "DAGGERHEART.UI.ItemBrowser.levelMin",
|
||||||
field: 'system.api.models.items.DHDomainCard.schema.fields.level',
|
field: 'system.api.models.items.DHDomainCard.schema.fields.level',
|
||||||
operator: "gte"
|
operator: "gte"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.level",
|
key: "system.level",
|
||||||
name: "level.max",
|
name: "level.max",
|
||||||
label: "Level (Max)",
|
label: "DAGGERHEART.UI.ItemBrowser.levelMax",
|
||||||
field: 'system.api.models.items.DHDomainCard.schema.fields.level',
|
field: 'system.api.models.items.DHDomainCard.schema.fields.level',
|
||||||
operator: "lte"
|
operator: "lte"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.recallCost",
|
key: "system.recallCost",
|
||||||
name: "recall.min",
|
name: "recall.min",
|
||||||
label: "Recall Cost (Min)",
|
label: "DAGGERHEART.UI.ItemBrowser.recallCostMin",
|
||||||
field: 'system.api.models.items.DHDomainCard.schema.fields.recallCost',
|
field: 'system.api.models.items.DHDomainCard.schema.fields.recallCost',
|
||||||
operator: "gte"
|
operator: "gte"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.recallCost",
|
key: "system.recallCost",
|
||||||
name: "recall.max",
|
name: "recall.max",
|
||||||
label: "Recall Cost (Max)",
|
label: "DAGGERHEART.UI.ItemBrowser.recallCostMax",
|
||||||
field: 'system.api.models.items.DHDomainCard.schema.fields.recallCost',
|
field: 'system.api.models.items.DHDomainCard.schema.fields.recallCost',
|
||||||
operator: "lte"
|
operator: "lte"
|
||||||
}
|
}
|
||||||
|
|
@ -206,50 +206,50 @@ export const typeConfig = {
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
key: "system.evasion",
|
key: "system.evasion",
|
||||||
label: "Evasion"
|
label: "DAGGERHEART.GENERAL.evasion"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.hitPoints",
|
key: "system.hitPoints",
|
||||||
label: "Hit Points"
|
label: "DAGGERHEART.GENERAL.HitPoints.plural"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.domains",
|
key: "system.domains",
|
||||||
label: "Domains"
|
label: "DAGGERHEART.GENERAL.Domain.plural"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
key: "system.evasion",
|
key: "system.evasion",
|
||||||
name: "evasion.min",
|
name: "evasion.min",
|
||||||
label: "Evasion (Min)",
|
label: "DAGGERHEART.UI.ItemBrowser.evasionMin",
|
||||||
field: 'system.api.models.items.DHClass.schema.fields.evasion',
|
field: 'system.api.models.items.DHClass.schema.fields.evasion',
|
||||||
operator: "gte"
|
operator: "gte"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.evasion",
|
key: "system.evasion",
|
||||||
name: "evasion.max",
|
name: "evasion.max",
|
||||||
label: "Evasion (Max)",
|
label: "DAGGERHEART.UI.ItemBrowser.evasionMax",
|
||||||
field: 'system.api.models.items.DHClass.schema.fields.evasion',
|
field: 'system.api.models.items.DHClass.schema.fields.evasion',
|
||||||
operator: "lte"
|
operator: "lte"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.hitPoints",
|
key: "system.hitPoints",
|
||||||
name: "hp.min",
|
name: "hp.min",
|
||||||
label: "Hit Points (Min)",
|
label: "DAGGERHEART.UI.ItemBrowser.hitPointsMin",
|
||||||
field: 'system.api.models.items.DHClass.schema.fields.hitPoints',
|
field: 'system.api.models.items.DHClass.schema.fields.hitPoints',
|
||||||
operator: "gte"
|
operator: "gte"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.hitPoints",
|
key: "system.hitPoints",
|
||||||
name: "hp.max",
|
name: "hp.max",
|
||||||
label: "Hit Points (Max)",
|
label: "DAGGERHEART.UI.ItemBrowser.hitPointsMax",
|
||||||
field: 'system.api.models.items.DHClass.schema.fields.hitPoints',
|
field: 'system.api.models.items.DHClass.schema.fields.hitPoints',
|
||||||
operator: "lte"
|
operator: "lte"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.domains",
|
key: "system.domains",
|
||||||
label: "Domains",
|
label: "DAGGERHEART.GENERAL.Domain.plural",
|
||||||
choices: () => Object.values(CONFIG.DH.DOMAIN.domains).map(d => ({ value: d.id, label: d.label})),
|
choices: () => Object.values(CONFIG.DH.DOMAIN.domains).map(d => ({ value: d.id, label: d.label })),
|
||||||
operator: "contains2"
|
operator: "contains2"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
@ -258,14 +258,14 @@ export const typeConfig = {
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
key: "id",
|
key: "id",
|
||||||
label: "Class",
|
label: "TYPES.Item.class",
|
||||||
format: (id) => {
|
format: (id) => {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.spellcastingTrait",
|
key: "system.spellcastingTrait",
|
||||||
label: "Spellcasting Trait"
|
label: "DAGGERHEART.ITEMS.Subclass.spellcastingTrait"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
filters: []
|
filters: []
|
||||||
|
|
@ -274,22 +274,22 @@ export const typeConfig = {
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
key: "system.tier",
|
key: "system.tier",
|
||||||
label: "Tier"
|
label: "DAGGERHEART.GENERAL.Tiers.singular"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.mainTrait",
|
key: "system.mainTrait",
|
||||||
label: "Main Trait"
|
label: "DAGGERHEART.GENERAL.Trait.single"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
key: "system.tier",
|
key: "system.tier",
|
||||||
label: "Tier",
|
label: "DAGGERHEART.GENERAL.Tiers.singular",
|
||||||
field: 'system.api.models.items.DHBeastform.schema.fields.tier'
|
field: 'system.api.models.items.DHBeastform.schema.fields.tier'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "system.mainTrait",
|
key: "system.mainTrait",
|
||||||
label: "Main Trait",
|
label: "DAGGERHEART.GENERAL.Trait.single",
|
||||||
field: 'system.api.models.items.DHBeastform.schema.fields.mainTrait'
|
field: 'system.api.models.items.DHBeastform.schema.fields.mainTrait'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
@ -304,20 +304,20 @@ export const compendiumConfig = {
|
||||||
"adversaries": {
|
"adversaries": {
|
||||||
id: "adversaries",
|
id: "adversaries",
|
||||||
keys: ["adversaries"],
|
keys: ["adversaries"],
|
||||||
label: "Adversaries",
|
label: "DAGGERHEART.UI.ItemBrowser.folders.adversaries",
|
||||||
type: ["adversary"],
|
type: ["adversary"],
|
||||||
listType: "adversaries"
|
listType: "adversaries"
|
||||||
},
|
},
|
||||||
"ancestries": {
|
"ancestries": {
|
||||||
id: "ancestries",
|
id: "ancestries",
|
||||||
keys: ["ancestries"],
|
keys: ["ancestries"],
|
||||||
label: "Ancestries",
|
label: "DAGGERHEART.UI.ItemBrowser.folders.ancestries",
|
||||||
type: ["ancestry"],
|
type: ["ancestry"],
|
||||||
folders: {
|
folders: {
|
||||||
"features": {
|
"features": {
|
||||||
id: "features",
|
id: "features",
|
||||||
keys: ["ancestries"],
|
keys: ["ancestries"],
|
||||||
label: "Features",
|
label: "DAGGERHEART.UI.ItemBrowser.folders.features",
|
||||||
type: ["feature"]
|
type: ["feature"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -325,26 +325,26 @@ export const compendiumConfig = {
|
||||||
"equipments": {
|
"equipments": {
|
||||||
id: "equipments",
|
id: "equipments",
|
||||||
keys: ["armors", "weapons", "consumables", "loot"],
|
keys: ["armors", "weapons", "consumables", "loot"],
|
||||||
label: "Equipment",
|
label: "DAGGERHEART.UI.ItemBrowser.folders.equipment",
|
||||||
type: ["armor", "weapon", "consumable", "loot"],
|
type: ["armor", "weapon", "consumable", "loot"],
|
||||||
listType: "items"
|
listType: "items"
|
||||||
},
|
},
|
||||||
"classes": {
|
"classes": {
|
||||||
id: "classes",
|
id: "classes",
|
||||||
keys: ["classes"],
|
keys: ["classes"],
|
||||||
label: "Classes",
|
label: "DAGGERHEART.UI.ItemBrowser.folders.classes",
|
||||||
type: ["class"],
|
type: ["class"],
|
||||||
folders: {
|
folders: {
|
||||||
"features": {
|
"features": {
|
||||||
id: "features",
|
id: "features",
|
||||||
keys: ["classes"],
|
keys: ["classes"],
|
||||||
label: "Features",
|
label: "DAGGERHEART.UI.ItemBrowser.folders.features",
|
||||||
type: ["feature"]
|
type: ["feature"]
|
||||||
},
|
},
|
||||||
"items": {
|
"items": {
|
||||||
id: "items",
|
id: "items",
|
||||||
keys: ["classes"],
|
keys: ["classes"],
|
||||||
label: "Items",
|
label: "DAGGERHEART.UI.ItemBrowser.folders.items",
|
||||||
type: ["armor", "weapon", "consumable", "loot"],
|
type: ["armor", "weapon", "consumable", "loot"],
|
||||||
listType: "items"
|
listType: "items"
|
||||||
}
|
}
|
||||||
|
|
@ -354,27 +354,27 @@ export const compendiumConfig = {
|
||||||
"subclasses": {
|
"subclasses": {
|
||||||
id: "subclasses",
|
id: "subclasses",
|
||||||
keys: ["subclasses"],
|
keys: ["subclasses"],
|
||||||
label: "Subclasses",
|
label: "DAGGERHEART.UI.ItemBrowser.folders.subclasses",
|
||||||
type: ["subclass"],
|
type: ["subclass"],
|
||||||
listType: "subclasses"
|
listType: "subclasses"
|
||||||
},
|
},
|
||||||
"domains": {
|
"domains": {
|
||||||
id: "domains",
|
id: "domains",
|
||||||
keys: ["domains"],
|
keys: ["domains"],
|
||||||
label: "Domain Cards",
|
label: "DAGGERHEART.UI.ItemBrowser.folders.domainCards",
|
||||||
type: ["domainCard"],
|
type: ["domainCard"],
|
||||||
listType: "cards"
|
listType: "cards"
|
||||||
},
|
},
|
||||||
"communities": {
|
"communities": {
|
||||||
id: "communities",
|
id: "communities",
|
||||||
keys: ["communities"],
|
keys: ["communities"],
|
||||||
label: "Communities",
|
label: "DAGGERHEART.UI.ItemBrowser.folders.communities",
|
||||||
type: ["community"],
|
type: ["community"],
|
||||||
folders: {
|
folders: {
|
||||||
"features": {
|
"features": {
|
||||||
id: "features",
|
id: "features",
|
||||||
keys: ["communities"],
|
keys: ["communities"],
|
||||||
label: "Features",
|
label: "DAGGERHEART.UI.ItemBrowser.folders.features",
|
||||||
type: ["feature"]
|
type: ["feature"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -382,20 +382,20 @@ export const compendiumConfig = {
|
||||||
"environments": {
|
"environments": {
|
||||||
id: "environments",
|
id: "environments",
|
||||||
keys: ["environments"],
|
keys: ["environments"],
|
||||||
label: "Environments",
|
label: "DAGGERHEART.UI.ItemBrowser.folders.environments",
|
||||||
type: ["environment"]
|
type: ["environment"]
|
||||||
},
|
},
|
||||||
"beastforms": {
|
"beastforms": {
|
||||||
id: "beastforms",
|
id: "beastforms",
|
||||||
keys: ["beastforms"],
|
keys: ["beastforms"],
|
||||||
label: "Beastforms",
|
label: "DAGGERHEART.UI.ItemBrowser.folders.beastforms",
|
||||||
type: ["beastform"],
|
type: ["beastform"],
|
||||||
listType: "beastforms",
|
listType: "beastforms",
|
||||||
folders: {
|
folders: {
|
||||||
"features": {
|
"features": {
|
||||||
id: "features",
|
id: "features",
|
||||||
keys: ["beastforms"],
|
keys: ["beastforms"],
|
||||||
label: "Features",
|
label: "DAGGERHEART.UI.ItemBrowser.folders.features",
|
||||||
type: ["feature"]
|
type: ["feature"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,5 +26,6 @@ export const gameSettings = {
|
||||||
Fear: 'ResourcesFear'
|
Fear: 'ResourcesFear'
|
||||||
},
|
},
|
||||||
LevelTiers: 'LevelTiers',
|
LevelTiers: 'LevelTiers',
|
||||||
Countdowns: 'Countdowns'
|
Countdowns: 'Countdowns',
|
||||||
|
LastMigrationVersion: 'LastMigrationVersion'
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ export default class DhpAdversary extends BaseDataActor {
|
||||||
}),
|
}),
|
||||||
type: new fields.StringField({
|
type: new fields.StringField({
|
||||||
required: true,
|
required: true,
|
||||||
choices: CONFIG.DH.ACTOR.adversaryTypes,
|
choices: CONFIG.DH.ACTOR.allAdversaryTypes,
|
||||||
initial: CONFIG.DH.ACTOR.adversaryTypes.standard.id
|
initial: CONFIG.DH.ACTOR.adversaryTypes.standard.id
|
||||||
}),
|
}),
|
||||||
motivesAndTactics: new fields.StringField(),
|
motivesAndTactics: new fields.StringField(),
|
||||||
|
|
|
||||||
|
|
@ -444,16 +444,12 @@ export default class DhCharacter extends BaseDataActor {
|
||||||
} else if (item.system.originItemType === CONFIG.DH.ITEM.featureTypes.subclass.id) {
|
} else if (item.system.originItemType === CONFIG.DH.ITEM.featureTypes.subclass.id) {
|
||||||
if (this.class.subclass) {
|
if (this.class.subclass) {
|
||||||
const subclassState = this.class.subclass.system.featureState;
|
const subclassState = this.class.subclass.system.featureState;
|
||||||
const subclass =
|
|
||||||
item.system.identifier === 'multiclass' ? this.multiclass.subclass : this.class.subclass;
|
|
||||||
const featureType = subclass
|
|
||||||
? (subclass.system.features.find(x => x.item?.uuid === item.uuid)?.type ?? null)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
featureType === CONFIG.DH.ITEM.featureSubTypes.foundation ||
|
item.system.identifier === CONFIG.DH.ITEM.featureSubTypes.foundation ||
|
||||||
(featureType === CONFIG.DH.ITEM.featureSubTypes.specialization && subclassState >= 2) ||
|
(item.system.identifier === CONFIG.DH.ITEM.featureSubTypes.specialization &&
|
||||||
(featureType === CONFIG.DH.ITEM.featureSubTypes.mastery && subclassState >= 3)
|
subclassState >= 2) ||
|
||||||
|
(item.system.identifier === CONFIG.DH.ITEM.featureSubTypes.mastery && subclassState >= 3)
|
||||||
) {
|
) {
|
||||||
subclassFeatures.push(item);
|
subclassFeatures.push(item);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ export default class CostField extends fields.ArrayField {
|
||||||
config.costs = CostField.calcCosts.call(this, costs);
|
config.costs = CostField.calcCosts.call(this, costs);
|
||||||
const hasCost = CostField.hasCost.call(this, config.costs);
|
const hasCost = CostField.hasCost.call(this, config.costs);
|
||||||
if (config.isFastForward && !hasCost)
|
if (config.isFastForward && !hasCost)
|
||||||
return ui.notifications.warn("You don't have the resources to use that action.");
|
return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.insufficientResources'));
|
||||||
return hasCost;
|
return hasCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ export default class UsesField extends fields.SchemaField {
|
||||||
if (uses && !uses.value) uses.value = 0;
|
if (uses && !uses.value) uses.value = 0;
|
||||||
config.uses = uses;
|
config.uses = uses;
|
||||||
const hasUses = UsesField.hasUses.call(this, config.uses);
|
const hasUses = UsesField.hasUses.call(this, config.uses);
|
||||||
if (config.isFastForward && !hasUses) return ui.notifications.warn("That action doesn't have remaining uses.");
|
if (config.isFastForward && !hasUses) return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.actionNoUsesRemaining'));
|
||||||
return hasUses;
|
return hasUses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -158,50 +158,30 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.actor && this.actor.type === 'character' && this.features) {
|
if (this.actor && this.actor.type === 'character' && this.features) {
|
||||||
const featureUpdates = {};
|
const features = [];
|
||||||
for (let f of this.features) {
|
for (let f of this.features) {
|
||||||
const fBase = f.item ?? f;
|
const fBase = f.item ?? f;
|
||||||
const feature = fBase.system ? fBase : await foundry.utils.fromUuid(fBase.uuid);
|
const feature = fBase.system ? fBase : await foundry.utils.fromUuid(fBase.uuid);
|
||||||
const createData = foundry.utils.mergeObject(
|
const multiclass = this.isMulticlass ? 'multiclass' : null;
|
||||||
feature.toObject(),
|
features.push(
|
||||||
{
|
foundry.utils.mergeObject(
|
||||||
system: {
|
feature.toObject(),
|
||||||
originItemType: this.parent.type,
|
{
|
||||||
originId: data._id,
|
_stats: { compendiumSource: fBase.uuid },
|
||||||
identifier: this.isMulticlass ? 'multiclass' : null
|
system: {
|
||||||
}
|
originItemType: this.parent.type,
|
||||||
},
|
identifier: multiclass ?? (f.item ? f.type : null)
|
||||||
{ inplace: false }
|
}
|
||||||
|
},
|
||||||
|
{ inplace: false }
|
||||||
|
)
|
||||||
);
|
);
|
||||||
const [doc] = await this.actor.createEmbeddedDocuments('Item', [createData]);
|
|
||||||
|
|
||||||
if (!featureUpdates.features)
|
|
||||||
featureUpdates.features = this.features.map(x => (x.item ? { ...x, item: x.item.uuid } : x.uuid));
|
|
||||||
|
|
||||||
if (f.item) {
|
|
||||||
const existingFeature = featureUpdates.features.find(x => x.item === f.item.uuid);
|
|
||||||
existingFeature.item = doc.uuid;
|
|
||||||
} else {
|
|
||||||
const replaceIndex = featureUpdates.features.findIndex(x => x === f.uuid);
|
|
||||||
featureUpdates.features.splice(replaceIndex, 1, doc.uuid);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.updateSource(featureUpdates);
|
await this.actor.createEmbeddedDocuments('Item', features);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async _preDelete() {
|
|
||||||
if (!this.actor || this.actor.type !== 'character') return;
|
|
||||||
|
|
||||||
const items = this.actor.items.filter(item => item.system.originId === this.parent.id);
|
|
||||||
if (items.length > 0)
|
|
||||||
await this.actor.deleteEmbeddedDocuments(
|
|
||||||
'Item',
|
|
||||||
items.map(x => x.id)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async _preUpdate(changed, options, userId) {
|
async _preUpdate(changed, options, userId) {
|
||||||
const allowed = await super._preUpdate(changed, options, userId);
|
const allowed = await super._preUpdate(changed, options, userId);
|
||||||
if (allowed === false) return false;
|
if (allowed === false) return false;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import BaseDataItem from './base.mjs';
|
import BaseDataItem from './base.mjs';
|
||||||
import { ActionField, ActionsField } from '../fields/actionField.mjs';
|
|
||||||
|
|
||||||
export default class DHFeature extends BaseDataItem {
|
export default class DHFeature extends BaseDataItem {
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
|
|
@ -30,24 +29,7 @@ export default class DHFeature extends BaseDataItem {
|
||||||
nullable: true,
|
nullable: true,
|
||||||
initial: null
|
initial: null
|
||||||
}),
|
}),
|
||||||
originId: new fields.StringField({ nullable: true, initial: null }),
|
|
||||||
identifier: new fields.StringField()
|
identifier: new fields.StringField()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
get spellcastingModifier() {
|
|
||||||
let traitValue = 0;
|
|
||||||
if (this.actor && this.originId && ['class', 'subclass'].includes(this.originItemType)) {
|
|
||||||
if (this.originItemType === 'subclass') {
|
|
||||||
traitValue =
|
|
||||||
this.actor.system.traits[this.actor.items.get(this.originId).system.spellcastingTrait]?.value ?? 0;
|
|
||||||
} else {
|
|
||||||
const { value: multiclass, subclass } = this.actor.system.multiclass;
|
|
||||||
const selectedSubclass = multiclass?.id === this.originId ? subclass : this.actor.system.class.subclass;
|
|
||||||
traitValue = this.actor.system.traits[selectedSubclass.system.spellcastingTrait]?.value ?? 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return traitValue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,13 @@ export default class DhHomebrew extends foundry.abstract.DataModel {
|
||||||
}),
|
}),
|
||||||
description: new fields.HTMLField()
|
description: new fields.HTMLField()
|
||||||
})
|
})
|
||||||
|
),
|
||||||
|
adversaryTypes: new fields.TypedObjectField(
|
||||||
|
new fields.SchemaField({
|
||||||
|
id: new fields.StringField({ required: true }),
|
||||||
|
label: new fields.StringField({ required: true, label: 'DAGGERHEART.GENERAL.label' }),
|
||||||
|
description: new fields.StringField()
|
||||||
|
})
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,13 @@ export default class DamageRoll extends DHRoll {
|
||||||
Object.values(config.damage).flatMap(r => r.parts.map(p => p.roll))
|
Object.values(config.damage).flatMap(r => r.parts.map(p => p.roll))
|
||||||
),
|
),
|
||||||
diceRoll = Roll.fromTerms([pool]);
|
diceRoll = Roll.fromTerms([pool]);
|
||||||
await game.dice3d.showForRoll(diceRoll, game.user, true, chatMessage.whisper, chatMessage.blind);
|
await game.dice3d.showForRoll(
|
||||||
|
diceRoll,
|
||||||
|
game.user,
|
||||||
|
true,
|
||||||
|
chatMessage.whisper?.length > 0 ? chatMessage.whisper : null,
|
||||||
|
chatMessage.blind
|
||||||
|
);
|
||||||
}
|
}
|
||||||
await super.buildPost(roll, config, message);
|
await super.buildPost(roll, config, message);
|
||||||
if (config.source?.message) {
|
if (config.source?.message) {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { emitAsGM, GMUpdateEvent } from '../systemRegistration/socket.mjs';
|
import { emitAsGM, GMUpdateEvent } from '../systemRegistration/socket.mjs';
|
||||||
import { LevelOptionType } from '../data/levelTier.mjs';
|
import { LevelOptionType } from '../data/levelTier.mjs';
|
||||||
import DHFeature from '../data/item/feature.mjs';
|
import DHFeature from '../data/item/feature.mjs';
|
||||||
import { createScrollText, damageKeyToNumber } from '../helpers/utils.mjs';
|
import { createScrollText, damageKeyToNumber, versionCompare } from '../helpers/utils.mjs';
|
||||||
import DhCompanionLevelUp from '../applications/levelup/companionLevelup.mjs';
|
import DhCompanionLevelUp from '../applications/levelup/companionLevelup.mjs';
|
||||||
|
|
||||||
export default class DhpActor extends Actor {
|
export default class DhpActor extends Actor {
|
||||||
|
|
@ -772,4 +772,26 @@ export default class DhpActor extends Actor {
|
||||||
this.#scrollTextInterval = setInterval(intervalFunc.bind(this), 600);
|
this.#scrollTextInterval = setInterval(intervalFunc.bind(this), 600);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @inheritdoc */
|
||||||
|
async importFromJSON(json) {
|
||||||
|
if (!this.type === 'character') return await super.importFromJSON(json);
|
||||||
|
|
||||||
|
if (!CONST.WORLD_DOCUMENT_TYPES.includes(this.documentName)) {
|
||||||
|
throw new Error('Only world Documents may be imported');
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsedJSON = JSON.parse(json);
|
||||||
|
if (versionCompare(parsedJSON._stats.systemVersion, '1.1.0')) {
|
||||||
|
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||||
|
window: {
|
||||||
|
title: game.i18n.localize('DAGGERHEART.ACTORS.Character.InvalidOldCharacterImportTitle')
|
||||||
|
},
|
||||||
|
content: game.i18n.localize('DAGGERHEART.ACTORS.Character.InvalidOldCharacterImportText')
|
||||||
|
});
|
||||||
|
if (!confirmed) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await super.importFromJSON(json);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@ export default class RegisterHandlebarsHelpers {
|
||||||
hasProperty: foundry.utils.hasProperty,
|
hasProperty: foundry.utils.hasProperty,
|
||||||
getProperty: foundry.utils.getProperty,
|
getProperty: foundry.utils.getProperty,
|
||||||
setVar: this.setVar,
|
setVar: this.setVar,
|
||||||
empty: this.empty
|
empty: this.empty,
|
||||||
|
pluralize: this.pluralize
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
static add(a, b) {
|
static add(a, b) {
|
||||||
|
|
@ -64,7 +65,7 @@ export default class RegisterHandlebarsHelpers {
|
||||||
return isNumerical ? (!result ? 0 : Number(result)) : result;
|
return isNumerical ? (!result ? 0 : Number(result)) : result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static setVar(name, value, context) {
|
static setVar(name, value) {
|
||||||
this[name] = value;
|
this[name] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,4 +73,20 @@ export default class RegisterHandlebarsHelpers {
|
||||||
if (!(typeof object === 'object')) return true;
|
if (!(typeof object === 'object')) return true;
|
||||||
return Object.keys(object).length === 0;
|
return Object.keys(object).length === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pluralize helper that returns the appropriate localized string based on count
|
||||||
|
* @param {number} count - The number to check for plurality
|
||||||
|
* @param {string} baseKey - The base localization key (e.g., "DAGGERHEART.GENERAL.Target")
|
||||||
|
* @returns {string} The localized singular or plural string
|
||||||
|
*
|
||||||
|
* Usage: {{pluralize currentTargets.length "DAGGERHEART.GENERAL.Target"}}
|
||||||
|
* Returns: "Target" if count is exactly 1, "Targets" if count is 0, 2+, or invalid
|
||||||
|
*/
|
||||||
|
static pluralize(count, baseKey) {
|
||||||
|
const numericCount = Number(count);
|
||||||
|
const isSingular = !isNaN(numericCount) && numericCount === 1;
|
||||||
|
const key = isSingular ? `${baseKey}.single` : `${baseKey}.plural`;
|
||||||
|
return game.i18n.localize(key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -418,3 +418,14 @@ export async function createEmbeddedItemsWithEffects(actor, baseData) {
|
||||||
export const slugify = name => {
|
export const slugify = name => {
|
||||||
return name.toLowerCase().replaceAll(' ', '-').replaceAll('.', '');
|
return name.toLowerCase().replaceAll(' ', '-').replaceAll('.', '');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const versionCompare = (current, target) => {
|
||||||
|
const currentSplit = current.split('.').map(x => Number.parseInt(x));
|
||||||
|
const targetSplit = target.split('.').map(x => Number.parseInt(x));
|
||||||
|
for (var i = 0; i < currentSplit.length; i++) {
|
||||||
|
if (currentSplit[i] < targetSplit[i]) return true;
|
||||||
|
if (currentSplit[i] > targetSplit[i]) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
export { preloadHandlebarsTemplates as handlebarsRegistration } from './handlebars.mjs';
|
export { preloadHandlebarsTemplates as handlebarsRegistration } from './handlebars.mjs';
|
||||||
export * as settingsRegistration from './settings.mjs';
|
export * as settingsRegistration from './settings.mjs';
|
||||||
export * as socketRegistration from './socket.mjs';
|
export * as socketRegistration from './socket.mjs';
|
||||||
|
export { runMigrations } from './migrations.mjs';
|
||||||
|
|
|
||||||
|
|
@ -35,5 +35,8 @@ export const preloadHandlebarsTemplates = async function () {
|
||||||
'systems/daggerheart/templates/ui/chat/parts/damage-part.hbs',
|
'systems/daggerheart/templates/ui/chat/parts/damage-part.hbs',
|
||||||
'systems/daggerheart/templates/ui/chat/parts/target-part.hbs',
|
'systems/daggerheart/templates/ui/chat/parts/target-part.hbs',
|
||||||
'systems/daggerheart/templates/ui/chat/parts/button-part.hbs',
|
'systems/daggerheart/templates/ui/chat/parts/button-part.hbs',
|
||||||
|
|
||||||
|
'systems/daggerheart/templates/scene/dh-config.hbs',
|
||||||
|
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
41
module/systemRegistration/migrations.mjs
Normal file
41
module/systemRegistration/migrations.mjs
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
import { versionCompare } from '../helpers/utils.mjs';
|
||||||
|
|
||||||
|
export async function runMigrations() {
|
||||||
|
let lastMigrationVersion = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LastMigrationVersion);
|
||||||
|
if (!lastMigrationVersion) lastMigrationVersion = '1.0.6';
|
||||||
|
|
||||||
|
if (versionCompare(lastMigrationVersion, '1.1.0')) {
|
||||||
|
const compendiumActors = [];
|
||||||
|
for (let pack of game.packs) {
|
||||||
|
const documents = await pack.getDocuments();
|
||||||
|
compendiumActors.push(...documents.filter(x => x.type === 'character'));
|
||||||
|
}
|
||||||
|
|
||||||
|
[...compendiumActors, ...game.actors].forEach(actor => {
|
||||||
|
const items = actor.items.reduce((acc, item) => {
|
||||||
|
if (item.type === 'feature') {
|
||||||
|
const { originItemType, isMulticlass, identifier } = item.system;
|
||||||
|
const base = originItemType
|
||||||
|
? actor.items.find(
|
||||||
|
x => x.type === originItemType && Boolean(isMulticlass) === Boolean(x.system.isMulticlass)
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
if (base) {
|
||||||
|
const feature = base.system.features.find(x => x.item && x.item.uuid === item.uuid);
|
||||||
|
if (feature && identifier !== 'multiclass') {
|
||||||
|
acc.push({ _id: item.id, system: { identifier: feature.type } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
actor.updateEmbeddedDocuments('Item', items);
|
||||||
|
});
|
||||||
|
|
||||||
|
lastMigrationVersion = '1.1.0';
|
||||||
|
}
|
||||||
|
|
||||||
|
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LastMigrationVersion, lastMigrationVersion);
|
||||||
|
}
|
||||||
|
|
@ -91,6 +91,12 @@ const registerMenus = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const registerNonConfigSettings = () => {
|
const registerNonConfigSettings = () => {
|
||||||
|
game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LastMigrationVersion, {
|
||||||
|
scope: 'world',
|
||||||
|
config: false,
|
||||||
|
type: String
|
||||||
|
});
|
||||||
|
|
||||||
game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers, {
|
game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers, {
|
||||||
scope: 'world',
|
scope: 'world',
|
||||||
config: false,
|
config: false,
|
||||||
|
|
|
||||||
|
|
@ -21,3 +21,4 @@
|
||||||
@import './settings/settings.less';
|
@import './settings/settings.less';
|
||||||
|
|
||||||
@import './settings/homebrew-settings/domains.less';
|
@import './settings/homebrew-settings/domains.less';
|
||||||
|
@import './settings/homebrew-settings/types.less';
|
||||||
|
|
|
||||||
52
styles/less/ui/settings/homebrew-settings/types.less
Normal file
52
styles/less/ui/settings/homebrew-settings/types.less
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
.theme-light .daggerheart.dh-style.setting.homebrew-settings .types.tab {
|
||||||
|
.adversary-types-container .adversary-type-container {
|
||||||
|
background-image: url('../assets/parchments/dh-parchment-light.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.daggerheart.dh-style.setting.homebrew-settings {
|
||||||
|
.types.tab {
|
||||||
|
.adversary-types-container {
|
||||||
|
width: 100%;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
.adversary-type-container {
|
||||||
|
height: 2em;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 8px;
|
||||||
|
border: 1px solid;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 0 8px;
|
||||||
|
border: 1px solid light-dark(@dark-blue, @golden);
|
||||||
|
color: light-dark(@dark, @beige);
|
||||||
|
background-image: url('../assets/parchments/dh-parchment-dark.png');
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: 0.6;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
opacity: 1;
|
||||||
|
background: var(--color-warm-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.type-edit-container {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "daggerheart",
|
"id": "daggerheart",
|
||||||
"title": "Daggerheart",
|
"title": "Daggerheart",
|
||||||
"description": "An unofficial implementation of the Daggerheart system",
|
"description": "An unofficial implementation of the Daggerheart system",
|
||||||
"version": "1.0.6",
|
"version": "1.1.0",
|
||||||
"compatibility": {
|
"compatibility": {
|
||||||
"minimum": "13",
|
"minimum": "13",
|
||||||
"verified": "13.347",
|
"verified": "13.347",
|
||||||
|
|
|
||||||
9
templates/scene/dh-config.hbs
Normal file
9
templates/scene/dh-config.hbs
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<div class="tab{{#if tab.active}} active{{/if}}" data-group="{{tab.group}}" data-tab="{{tab.id}}">
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-fields">
|
||||||
|
<label>{{localize 'DAGGERHEART.SETTINGS.Scene.rangeMeasurementOverride'}}</label>
|
||||||
|
<input type="checkbox" name="flags.daggerheart.rangeMeasurementOverride" {{checked
|
||||||
|
document.flags.daggerheart.rangeMeasurementOverride}} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
28
templates/settings/homebrew-settings/types.hbs
Normal file
28
templates/settings/homebrew-settings/types.hbs
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
<section
|
||||||
|
class="tab {{tabs.types.cssClass}} {{tabs.types.id}}"
|
||||||
|
data-tab="{{tabs.types.id}}"
|
||||||
|
data-group="{{tabs.types.group}}"
|
||||||
|
>
|
||||||
|
<fieldset>
|
||||||
|
<legend>
|
||||||
|
<span>{{localize "DAGGERHEART.SETTINGS.Homebrew.adversaryType.title"}}</span>
|
||||||
|
<a data-action="addAdversaryType"><i class="fa-solid fa-plus"></i></a>
|
||||||
|
</legend>
|
||||||
|
|
||||||
|
<div class="adversary-types-container">
|
||||||
|
{{#each settingFields.adversaryTypes as |type key|}}
|
||||||
|
<div class="adversary-type-container {{#if (eq ../selectedAdversaryType.id key)}}active{{/if}}" data-action="selectAdversaryType" data-type="{{key}}">
|
||||||
|
<span>{{type.label}}</span>
|
||||||
|
<div data-action="deleteAdversaryType" data-key="{{key}}"><i class="fa-solid fa-trash"></i></div>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if selectedAdversaryType}}
|
||||||
|
<div class="type-edit-container">
|
||||||
|
{{formGroup settingFields.schema.fields.adversaryTypes.element.fields.label name=(concat "adversaryTypes." selectedAdversaryType.id ".label") value=selectedAdversaryType.label localize=true }}
|
||||||
|
<textarea name="{{concat "adversaryTypes." selectedAdversaryType.id ".description"}}">{{selectedAdversaryType.description}}</textarea>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</fieldset>
|
||||||
|
</section>
|
||||||
|
|
@ -13,9 +13,7 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="tag">
|
<div class="tag">
|
||||||
<span>
|
<span>{{adversaryType}}</span>
|
||||||
{{localize (concat 'DAGGERHEART.CONFIG.AdversaryType.' source.system.type '.label')}}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
{{#if (eq source.system.type 'horde')}}
|
{{#if (eq source.system.type 'horde')}}
|
||||||
<div class="tag">
|
<div class="tag">
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
type='text'
|
type='text'
|
||||||
name='name'
|
name='name'
|
||||||
value='{{document.name}}'
|
value='{{document.name}}'
|
||||||
placeholder='Actor Name'
|
placeholder='{{localize "DAGGERHEART.GENERAL.actorName"}}'
|
||||||
/>
|
/>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
<div class="roll-part target-section dice-roll" data-action="expandRoll">
|
<div class="roll-part target-section dice-roll" data-action="expandRoll">
|
||||||
<div class="roll-part-header"><div><span>Target</span></div></div>
|
<div class="roll-part-header"><div><span>{{pluralize currentTargets.length "DAGGERHEART.GENERAL.Target"}}</span></div></div>
|
||||||
{{#if (or (and targets.length (or (gt targetShort.hit 0) (gt targetShort.miss 0))) (and hasSave pendingSaves))}}
|
{{#if (or (and targets.length (or (gt targetShort.hit 0) (gt targetShort.miss 0))) (and hasSave pendingSaves))}}
|
||||||
<div class="roll-part-extra on-reduced">
|
<div class="roll-part-extra on-reduced">
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
{{#if (or (gt targetShort.hit 0) (gt targetShort.miss 0))}}
|
{{#if (or (gt targetShort.hit 0) (gt targetShort.miss 0))}}
|
||||||
<div class="target-hit-status">{{targetShort.hit}} {{#if (gt targetShort.hit 1)}}{{localize "DAGGERHEART.GENERAL.hit.single"}}{{else}}{{localize "DAGGERHEART.GENERAL.hit.plural"}}{{/if}}</div>
|
<div class="target-hit-status">{{targetShort.hit}} {{pluralize targetShort.hit "DAGGERHEART.GENERAL.hit"}}</div>
|
||||||
<div class="target-hit-status is-miss">{{targetShort.miss}} {{#if (gt targetShort.miss 1)}}{{localize "DAGGERHEART.GENERAL.miss.single"}}{{else}}{{localize "DAGGERHEART.GENERAL.miss.plural"}}{{/if}}</div>
|
<div class="target-hit-status is-miss">{{targetShort.miss}} {{pluralize targetShort.miss "DAGGERHEART.GENERAL.miss"}}</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if (and hasSave pendingSaves)}}<div class="target-pending-saves" data-tooltip="{{localize "DAGGERHEART.UI.Tooltip.pendingSaves"}}" data-tooltip-direction="UP"><i class="fa-solid fa-shield fa-lg fa-beat"></i></div>{{/if}}
|
{{#if (and hasSave pendingSaves)}}<div class="target-pending-saves" data-tooltip="{{localize "DAGGERHEART.UI.Tooltip.pendingSaves"}}" data-tooltip-direction="UP"><i class="fa-solid fa-shield fa-lg fa-beat"></i></div>{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,12 @@
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
<i class="fa-solid fa-magnifying-glass"></i>
|
<i class="fa-solid fa-magnifying-glass"></i>
|
||||||
</div>
|
</div>
|
||||||
<input type="search" name="search" class="search-input" placeholder="Search...">
|
<input type="search" name="search" class="search-input" placeholder="{{localize 'DAGGERHEART.UI.ItemBrowser.searchPlaceholder'}}">
|
||||||
</div>
|
</div>
|
||||||
{{#if fieldFilter.length}}
|
{{#if fieldFilter.length}}
|
||||||
<a data-tooltip="Filters" data-action="expandContent"><i class="fa-solid fa-filter"></i></a>
|
<a data-tooltip="{{localize 'DAGGERHEART.UI.ItemBrowser.tooltipFilters'}}" data-action="expandContent"><i class="fa-solid fa-filter"></i></a>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<a data-tooltip="Erase" data-action="resetFilters"><i class="fa-solid fa-eraser"></i></a>
|
<a data-tooltip="{{localize 'DAGGERHEART.UI.ItemBrowser.tooltipErase'}}" data-action="resetFilters"><i class="fa-solid fa-eraser"></i></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="filter-content extensible">
|
<div class="filter-content extensible">
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
|
|
@ -55,9 +55,9 @@
|
||||||
{{#if menu.data.columns.length}}
|
{{#if menu.data.columns.length}}
|
||||||
<div class="item-list-header">
|
<div class="item-list-header">
|
||||||
<div class="item-list-img"></div>
|
<div class="item-list-img"></div>
|
||||||
<div class="item-list-name" data-sort-key="name" data-sort-type="ASC" data-action="sortList">Name</div>
|
<div class="item-list-name" data-sort-key="name" data-sort-type="ASC" data-action="sortList">{{localize 'DAGGERHEART.UI.ItemBrowser.columnName'}}</div>
|
||||||
{{#each menu.data.columns}}
|
{{#each menu.data.columns}}
|
||||||
<span data-sort-key="{{key}}" data-sort-type="" data-action="sortList">{{label}}</span>
|
<span data-sort-key="{{key}}" data-sort-type="" data-action="sortList">{{localize label}}</span>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
@ -82,8 +82,8 @@
|
||||||
{{!-- </div> --}}
|
{{!-- </div> --}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="welcome-message">
|
<div class="welcome-message">
|
||||||
<h2 class="title">Daggerheart Compendium Browser</h2>
|
<h2 class="title">{{localize "DAGGERHEART.UI.ItemBrowser.title"}}</h2>
|
||||||
<span class="hint"><i>Select a Folder in sidebar to start browsing trought the compendium</i></span>
|
<span class="hint"><i>{{localize "DAGGERHEART.UI.ItemBrowser.hint"}}</i></span>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="tooltip-information">
|
<div class="tooltip-information">
|
||||||
<label>{{localize "Type"}}</label>
|
<label>{{localize "Type"}}</label>
|
||||||
{{#with (lookup config.ACTOR.adversaryTypes item.system.type) as | type |}}
|
{{#with (lookup adversaryTypes item.system.type) as | type |}}
|
||||||
<div>{{localize type.label}}</div>
|
<div>{{localize type.label}}</div>
|
||||||
{{/with}}
|
{{/with}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue