diff --git a/.editorconfig b/.editorconfig index aa391e00..8bbc2b52 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,6 +1,3 @@ [*] indent_size = 4 indent_style = spaces -end_of_line = lf -[*.yml] -indent_size = 2 diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 56ce8818..00000000 --- a/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -* text=auto eol=lf -*.json text eol=lf diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index fd9b922e..00000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: Project CI - -on: - pull_request: - branches: [main] - push: - branches: [main] - workflow_dispatch: - branches: [main] - -jobs: - build: - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [24.x] - - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - - - uses: pnpm/action-setup@v4 - with: - version: 10 - - - name: Cache NPM Deps - id: cache-npm - uses: actions/cache@v3 - with: - path: node_modules/ - key: npm-${{ hashFiles('package-lock.json') }} - - - name: Install NPM Deps - if: ${{ steps.cache-npm.outputs.cache-hit != 'true' }} - run: npm ci - - - name: Lint - run: npm run lint \ No newline at end of file diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 4ffcc64d..5e2f9ac7 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -35,9 +35,8 @@ jobs: env: version: ${{steps.get_version.outputs.version-without-v}} url: https://github.com/${{github.repository}} - manifest: https://raw.githubusercontent.com/${{github.repository}}/v14/system.json + manifest: https://raw.githubusercontent.com/${{github.repository}}/V13/system.json download: https://github.com/${{github.repository}}/releases/download/${{github.event.release.tag_name}}/system.zip - flags.hotReload: false # Create a zip file with all files required by the module to add to the release - run: zip -r ./system.zip system.json README.md LICENSE build/daggerheart.js build/tagify.css styles/daggerheart.css assets/ templates/ packs/ lang/ diff --git a/.gitignore b/.gitignore index e41a67d3..9a22c0ce 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,3 @@ Build build foundry styles/daggerheart.css -styles/daggerheart.css.map diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..6de9e5d0 --- /dev/null +++ b/.prettierrc @@ -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 +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 261c26bd..b9099005 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,9 +1,78 @@ -# Contributing to Daggerheart +# Contributing to Foundryborne -Thank you for your interest in contributing to the Foundryborne project! +Welcome! This is a community-driven project to bring [Daggerheart](https://www.daggerheart.com/) to [FoundryVTT](https://foundryvtt.com/) as a full system. We're excited to have you here and appreciate your interest in contributing. -To ensure that all contributions align with our project goals and architectural standards, we ask that you **do not submit outside contributions without first receiving feedback from the development team.** +--- -If you have an idea or a fix you'd like to contribute, please start a discussion or open an issue first. We'd love to hear from you and collaborate on the best way to move forward! +## 🀝 How to Contribute -Thank you for your understanding and support. +We welcome contributions of all kinds: + +- Bug reports +- Feature suggestions +- Code contributions +- UI/UX mockups +- Documentation improvements +- Questions and discussions + +Please be respectful and collaborative β€” we’re all here to build something great together. + +### Community Translations + +Please note that we are not accepting community translations in the main project. Instead, community translations should be published as a module. + +--- + +## 🧭 General Guidelines + +- **Use GitHub Issues** to report bugs or propose features +- **Start a Discussion** for larger ideas or questions +- **Open a Pull Request** once you've confirmed your work aligns with project direction +- **Keep things modular and maintainable** β€” if you're not sure how to structure something, ask! +- **Orient your code on existing examples**, and feel free to suggest a standard if it makes things clearer + +--- + +## πŸ—‚οΈ Project Structure + +Please try to follow the general logic of the existing code when submitting PRs. + +We encourage contributors to leave comments or open Discussions when proposing structural or organizational changes. + +--- + +## 🧾 Issue & PR Best Practices + +**For Issues:** + +- Use clear, descriptive titles +- Provide a concise explanation of the problem or idea +- Include reproduction steps or example scenarios if it's a bug +- Add screenshots or logs if helpful + +**For Pull Requests:** + +- Use a clear title summarizing the change +- Provide a brief description of what your code does and why +- Link to any related Issues +- Keep PRs focused β€” smaller is better + +--- + +## πŸ”– Labels and Boards + +We use GitHub labels to help organize contributions. If your issue or PR relates to a specific category, feel free to tag it. There is also a GitHub Project Board to help track active work and priorities. + +--- + +## πŸ“£ Communication + +Discussions are currently happening on GitHub β€” in Issues, PRs, and [GitHub Discussions](https://github.com/Foundryborne/daggerheart/discussions). You're welcome to use any of these, though we may consolidate to one in the future. + +--- + +## πŸ€— Thank You! + +Whether you're fixing a typo or designing entire mechanics β€” every contribution matters. Thank you for helping bring _Daggerheart_ to life in FoundryVTT through **Foundryborne**! + +πŸΈπŸ› οΈ diff --git a/README.md b/README.md index ac3666b3..f59143fd 100644 --- a/README.md +++ b/README.md @@ -66,10 +66,6 @@ You can find the documentation here: https://github.com/Foundryborne/daggerheart Looking to contribute to the project? Look no further, check out our [contributing guide](CONTRIBUTING.md), and keep the [Code of Conduct](coc.md) in mind when working on things. -## AI Policy - -The Foundryborne Daggerheart system does not make use of AI (generative or otherwise) for any area of its implementation. We expect all contributors to follow this same policy when contributing with a pull request; contributions made using AI will be rejected outright. - ## Disclaimer: **Daggerheart System** diff --git a/assets/icons/documents/actors/drama-masks.svg b/assets/icons/documents/actors/drama-masks.svg deleted file mode 100644 index 84307da0..00000000 --- a/assets/icons/documents/actors/drama-masks.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/svg/trait-shield-light.svg b/assets/svg/trait-shield-light.svg index c4d1824d..dc6f77c3 100644 --- a/assets/svg/trait-shield-light.svg +++ b/assets/svg/trait-shield-light.svg @@ -1,3 +1,3 @@ - + diff --git a/assets/svg/trait-shield.svg b/assets/svg/trait-shield.svg index dcb87cf4..87c18dd7 100644 --- a/assets/svg/trait-shield.svg +++ b/assets/svg/trait-shield.svg @@ -1,3 +1,3 @@ - + diff --git a/daggerheart.d.ts b/daggerheart.d.ts index 7ff7fd59..ab754b17 100644 --- a/daggerheart.d.ts +++ b/daggerheart.d.ts @@ -1,11 +1,8 @@ import '@client/global.mjs'; -import '@common/global.mjs'; -import '@common/primitives/global.mjs'; import Canvas from '@client/canvas/board.mjs'; // Foundry's use of `Object.assign(globalThis) means many globally available objects are not read as such // This declare global hopefully fixes that -// Note: eslint is not aware of these, whatever is added here should go in the eslint's globals list declare global { /** * A simple event framework used throughout Foundry Virtual Tabletop. @@ -15,28 +12,9 @@ declare global { class Hooks extends foundry.helpers.Hooks {} const fromUuid = foundry.utils.fromUuid; const fromUuidSync = foundry.utils.fromUuidSync; - /** - * A representation of a color in hexadecimal format. - * This class provides methods for transformations and manipulations of colors. - */ - class Color extends foundry.utils.Color {} + /** * The singleton game canvas */ const canvas: Canvas; - - const ActiveEffect: foundry.documents.ActiveEffect; - const Actor: foundry.documents.Actor; - const BaseScene: foundry.documents.BaseScene; - const ChatMessage: foundry.documents.ChatMessage; - const Combat: foundry.documents.Combat; - const Combatant: foundry.documents.Combatant; - const Item: foundry.documents.Item; - const Macro: foundry.documents.Macro; - const Scene: foundry.documents.Scene; - const TokenDocument: foundry.documents.TokenDocument; - - const Collection: foundry.utils.Collection; - const FormDataExtended: foundry.applications.ux.FormDataExtended; - const TextEditor: foundry.applications.ux.TextEditor; } diff --git a/daggerheart.mjs b/daggerheart.mjs index 7bfdf874..84ce2779 100644 --- a/daggerheart.mjs +++ b/daggerheart.mjs @@ -9,7 +9,10 @@ import * as dice from './module/dice/_module.mjs'; import * as fields from './module/data/fields/_module.mjs'; import RegisterHandlebarsHelpers from './module/helpers/handlebarsHelper.mjs'; import { enricherConfig, enricherRenderSetup } from './module/enrichers/_module.mjs'; +import { getCommandTarget, rollCommandToJSON } from './module/helpers/utils.mjs'; import { BaseRoll, DHRoll, DualityRoll, D20Roll, DamageRoll, FateRoll } from './module/dice/_module.mjs'; +import { enrichedDualityRoll } from './module/enrichers/DualityRollEnricher.mjs'; +import { enrichedFateRoll, getFateTypeData } from './module/enrichers/FateRollEnricher.mjs'; import { handlebarsRegistration, runMigrations, @@ -18,6 +21,7 @@ import { } from './module/systemRegistration/_module.mjs'; import { placeables, DhTokenLayer } from './module/canvas/_module.mjs'; import './node_modules/@yaireo/tagify/dist/tagify.css'; +import TemplateManager from './module/documents/templateManager.mjs'; import TokenManager from './module/documents/tokenManager.mjs'; CONFIG.DH = SYSTEM; @@ -32,13 +36,6 @@ CONFIG.Dice.daggerheart = { FateRoll: FateRoll }; -CONFIG.RegionBehavior.dataModels = { - ...CONFIG.RegionBehavior.dataModels, - ...data.regionBehaviors -}; - -Object.assign(CONFIG.Dice.termTypes, dice.diceTypes); - CONFIG.Actor.documentClass = documents.DhpActor; CONFIG.Actor.dataModels = models.actors.config; CONFIG.Actor.collection = collections.DhActorCollection; @@ -48,7 +45,6 @@ CONFIG.Item.dataModels = models.items.config; CONFIG.ActiveEffect.documentClass = documents.DhActiveEffect; CONFIG.ActiveEffect.dataModels = models.activeEffects.config; -CONFIG.ActiveEffect.changeTypes = { ...CONFIG.ActiveEffect.changeTypes, ...models.activeEffects.changeEffects }; CONFIG.Combat.documentClass = documents.DhpCombat; CONFIG.Combat.dataModels = { base: models.DhCombat }; @@ -60,13 +56,11 @@ CONFIG.ChatMessage.documentClass = documents.DhChatMessage; CONFIG.ChatMessage.template = 'systems/daggerheart/templates/ui/chat/chat-message.hbs'; CONFIG.Canvas.rulerClass = placeables.DhRuler; -CONFIG.Canvas.layers.regions.layerClass = placeables.DhRegionLayer; +CONFIG.Canvas.layers.templates.layerClass = placeables.DhTemplateLayer; CONFIG.Canvas.layers.tokens.layerClass = DhTokenLayer; CONFIG.MeasuredTemplate.objectClass = placeables.DhMeasuredTemplate; -CONFIG.Region.objectClass = placeables.DhRegion; - CONFIG.RollTable.documentClass = documents.DhRollTable; CONFIG.RollTable.resultTemplate = 'systems/daggerheart/templates/ui/chat/table-result.hbs'; @@ -90,6 +84,7 @@ CONFIG.ui.resources = applications.ui.DhFearTracker; CONFIG.ui.countdowns = applications.ui.DhCountdowns; CONFIG.ux.ContextMenu = applications.ux.DHContextMenu; CONFIG.ux.TooltipManager = documents.DhTooltipManager; +CONFIG.ux.TemplateManager = new TemplateManager(); CONFIG.ux.TokenManager = new TokenManager(); CONFIG.debug.triggers = false; @@ -196,11 +191,6 @@ Hooks.once('init', () => { makeDefault: true, label: sheetLabel('TYPES.Actor.environment') }); - Actors.registerSheet(SYSTEM.id, applications.sheets.actors.NPC, { - types: ['npc'], - makeDefault: true, - label: sheetLabel('TYPES.Actor.npc') - }); Actors.registerSheet(SYSTEM.id, applications.sheets.actors.Party, { types: ['party'], makeDefault: true, @@ -223,7 +213,6 @@ Hooks.once('init', () => { SYSTEM.id, applications.sheetConfigs.ActiveEffectConfig, { - types: ['base', 'beastform', 'horde'], makeDefault: true, label: sheetLabel('DOCUMENT.ActiveEffect') } @@ -281,6 +270,7 @@ Hooks.on('setup', () => { ...damageThresholds, 'proficiency', 'evasion', + 'armorScore', 'scars', 'levelData.level.current' ] @@ -342,27 +332,75 @@ Hooks.on('renderHandlebarsApplication', (_, element) => { enricherRenderSetup(element); }); -Hooks.on(CONFIG.DH.HOOKS.hooksConfig.tagTeamStart, async data => { - if (data.openForAllPlayers && data.partyId) { - const party = game.actors.get(data.partyId); - if (!party) return; +Hooks.on('chatMessage', (_, message) => { + if (message.startsWith('/dr')) { + const result = + message.trim().toLowerCase() === '/dr' ? { result: {} } : rollCommandToJSON(message.replace(/\/dr\s?/, '')); + if (!result) { + ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.dualityParsing')); + return false; + } - const TagTeamDialog = game.system.api.applications.dialogs.TagTeamDialog; - const dialog = foundry.applications.instances.get(`TagTeamDialog-${party.id}`) ?? new TagTeamDialog(party); - dialog.tabGroups.application = 'tagTeamRoll'; - await dialog.render({ force: true }); + const { result: rollCommand, flavor } = result; + + const reaction = rollCommand.reaction; + const traitValue = rollCommand.trait?.toLowerCase(); + const advantage = rollCommand.advantage + ? CONFIG.DH.ACTIONS.advantageState.advantage.value + : rollCommand.disadvantage + ? CONFIG.DH.ACTIONS.advantageState.disadvantage.value + : undefined; + const difficulty = rollCommand.difficulty; + const grantResources = rollCommand.grantResources; + + const target = getCommandTarget({ allowNull: true }); + const title = + (flavor ?? traitValue) + ? game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', { + ability: game.i18n.localize(SYSTEM.ACTOR.abilities[traitValue].label) + }) + : game.i18n.localize('DAGGERHEART.GENERAL.duality'); + + enrichedDualityRoll({ + reaction, + traitValue, + target, + difficulty, + title, + label: game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll'), + actionType: null, + advantage, + grantResources + }); + return false; } -}); -Hooks.on(CONFIG.DH.HOOKS.hooksConfig.groupRollStart, async data => { - if (data.openForAllPlayers && data.partyId) { - const party = game.actors.get(data.partyId); - if (!party) return; + if (message.startsWith('/fr')) { + const result = + message.trim().toLowerCase() === '/fr' ? { result: {} } : rollCommandToJSON(message.replace(/\/fr\s?/, '')); - const GroupRollDialog = game.system.api.applications.dialogs.GroupRollDialog; - const dialog = foundry.applications.instances.get(`GroupRollDialog-${party.id}`) ?? new GroupRollDialog(party); - dialog.tabGroups.application = 'groupRoll'; - await dialog.render({ force: true }); + if (!result) { + ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateParsing')); + return false; + } + + const { result: rollCommand, flavor } = result; + const fateTypeData = getFateTypeData(rollCommand?.type); + + if (!fateTypeData) + return ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateTypeParsing')); + + const { value: fateType, label: fateTypeLabel } = fateTypeData; + const target = getCommandTarget({ allowNull: true }); + const title = flavor ?? game.i18n.localize('DAGGERHEART.GENERAL.fateRoll'); + + enrichedFateRoll({ + target, + title, + label: fateTypeLabel, + fateType + }); + return false; } }); @@ -446,33 +484,3 @@ Hooks.on('canvasTearDown', canvas => { Hooks.on('canvasReady', canas => { game.system.registeredTriggers.registerSceneTriggers(canvas.scene); }); - -/** Make the user to select a document type, instead of having a default doc type for them to accidentally keep */ -Hooks.on('renderDialogV2', (_dialog, html) => { - if (!html.classList.contains('dialog')) return; - const cls = html.classList.contains('item-create') - ? documents.DHItem.implementation - : html.classList.contains('actor-create') - ? documents.DhpActor.implementation - : null; - if (!cls) return; - - const form = html.querySelector('form'); - const submit = html.querySelector('button[type=submit]'); - const select = html.querySelector('select[name=type]'); - const nameInput = html.querySelector('input[name=name]'); - if (!form || !select || !submit || !nameInput) return; - - nameInput.placeholder = cls.defaultName({}); - const emptyOption = document.createElement('option'); - emptyOption.value = ''; - emptyOption.selected = true; - select.required = true; - select.prepend(emptyOption); - submit.addEventListener('click', event => { - if (!form.reportValidity()) { - event.preventDefault(); - event.stopPropagation(); - } - }); -}); diff --git a/eslint.config.mjs b/eslint.config.mjs deleted file mode 100644 index 3c9b8fd9..00000000 --- a/eslint.config.mjs +++ /dev/null @@ -1,101 +0,0 @@ -import globals from 'globals'; -import { defineConfig, globalIgnores } from 'eslint/config'; -import tseslint from 'typescript-eslint'; -import js from '@eslint/js'; -import stylistic from '@stylistic/eslint-plugin'; - -/** @type {Partial} */ -export const stylisticRules = { - '@stylistic/indent': [ - 'error', - 4, - { - SwitchCase: 1 - } - ], - '@stylistic/max-len': ['error', { - code: 120, - ignoreComments: true, - ignoreStrings: true, - ignoreTemplateLiterals: true, - ignoreRegExpLiterals: true - }], - '@stylistic/quotes': ['error', 'single', { allowTemplateLiterals: 'always' }], - '@stylistic/arrow-parens': ['error', 'as-needed'], - '@stylistic/quote-props': ['error', 'as-needed'], - '@stylistic/array-bracket-newline': ['error', 'consistent'], - '@stylistic/key-spacing': 'error', - '@stylistic/comma-dangle': ['error', 'never'], - '@stylistic/space-in-parens': ['error', 'never'], - '@stylistic/space-infix-ops': 2, - '@stylistic/keyword-spacing': 2, - '@stylistic/semi-spacing': 2, - '@stylistic/no-multi-spaces': 2, - '@stylistic/no-extra-semi': 2, - '@stylistic/no-whitespace-before-property': 2, - '@stylistic/space-unary-ops': 2 -}; - -export default defineConfig([ - globalIgnores(['foundry/**/*', 'build/**/*']), - { - files: ['gulpfile.js', 'postcss.config.js'], - languageOptions: { globals: globals.node } - }, - { - files: ['**/*.{js,mjs,cjs}'], - plugins: { - '@stylistic': stylistic - }, - languageOptions: { - globals: { - ...globals.browser, - CONFIG: 'readonly', - CONST: 'readonly', - // Global classes - Color: 'readonly', - Handlebars: 'readonly', - Hooks: 'readonly', - PIXI: 'readonly', - ProseMirror: 'readonly', - Roll: 'readonly', - // global namespaces - canvas: 'readonly', - foundry: 'readonly', - game: 'readonly', - ui: 'readonly', - // global functions - fromUuid: 'readonly', - fromUuidSync: 'readonly', - getDocumentClass: 'readonly', - _del: 'readonly', - _replace: 'readonly', - _loc: 'readonly', - // Documents - ActiveEffect: 'readonly', - Actor: 'readonly', - BaseScene: 'readonly', - ChatMessage: 'readonly', - Combat: 'readonly', - Combatant: 'readonly', - Item: 'readonly', - Macro: 'readonly', - Scene: 'readonly', - TokenDocument: 'readonly', - // Other - Collection: 'readonly', - FormDataExtended: 'readonly', - TextEditor: 'readonly' - } - }, - rules: { - 'no-undef': 'error', - // 'no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }], - ...stylisticRules - } - }, - { - files: ['**/*.ts'], - extends: [js.configs.recommended, tseslint.configs.recommended] - } -]); diff --git a/gulpfile.js b/gulpfile.js index 2e873ced..45479a5c 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,15 +1,9 @@ // Less configuration var gulp = require('gulp'); var less = require('gulp-less'); -var sourcemaps = require('gulp-sourcemaps'); gulp.task('less', function (cb) { - gulp.src('styles/daggerheart.less') - .pipe(sourcemaps.init()) - .pipe(less()) - .on('error', console.error.bind(console)) - .pipe(sourcemaps.write('.')) - .pipe(gulp.dest('styles')); + gulp.src('styles/daggerheart.less').pipe(less()).pipe(gulp.dest('styles')); cb(); }); diff --git a/jsconfig.json b/jsconfig.json index a0d51d0b..00bab1f5 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { - "module": "es2022", - "target": "es2022", + "module": "ES6", + "target": "ES6", "paths": { "@client/*": ["./foundry/client/*"], "@common/*": ["./foundry/common/*"] diff --git a/lang/en.json b/lang/en.json index 3a1340e0..8e8f91ec 100755 --- a/lang/en.json +++ b/lang/en.json @@ -14,16 +14,13 @@ "beastform": "Beastform" }, "ActiveEffect": { - "base": "Standard", - "beastform": "Beastform", - "horde": "Horde" + "beastform": "Beastform" }, "Actor": { "character": "Character", "companion": "Companion", "adversary": "Adversary", "environment": "Environment", - "npc": "NPC", "party": "Party" } }, @@ -56,7 +53,6 @@ }, "damage": { "name": "Damage", - "critical": "Damage (Critical)", "tooltip": "Direct damage without a roll." }, "effect": { @@ -89,14 +85,7 @@ }, "Config": { "beastform": { - "exact": { "label": "Beastform Max Tier", "hint": "The Character's Tier is used if empty" }, - "modifications": { - "traitBonuses": { - "label": { "single": "Trait Bonus", "plural": "Trait Bonuses" }, - "hint": "Pick bonuses you apply to freely chosen traits at the time of transforming", - "bonus": "Bonus Amount" - } - } + "exact": { "label": "Beastform Max Tier", "hint": "The Character's Tier is used if empty" } }, "countdown": { "defaultOwnership": "Default Ownership", @@ -110,17 +99,9 @@ "customFormula": "Custom Formula", "formula": "Formula" }, - "area": { - "sectionTitle": "Areas", - "shape": "Shape", - "size": "Size" - }, "displayInChat": "Display in chat", "deleteTriggerTitle": "Delete Trigger", - "deleteTriggerContent": "Are you sure you want to delete the {trigger} trigger?", - "advantageState": "Advantage State", - "damageOnSave": "Damage on Save", - "useDefaultItemValues": "Use default Item values" + "deleteTriggerContent": "Are you sure you want to delete the {trigger} trigger?" }, "RollField": { "diceRolling": { @@ -132,11 +113,10 @@ } }, "Settings": { - "attackModifier": "Attack Modifier", + "attackBonus": "Attack Bonus", "attackName": "Attack Name", "criticalThreshold": "Critical Threshold", "includeBase": { "label": "Include Item Damage" }, - "groupAttack": { "label": "Group Attack" }, "multiplier": "Multiplier", "saveHint": "Set a default Trait to enable Reaction Roll. It can be changed later in Reaction Roll Dialog.", "resultBased": { @@ -167,9 +147,7 @@ "Config": { "rangeDependence": { "title": "Range Dependence" - }, - "stacking": { "title": "Stacking" }, - "targetDispositions": "Affected Dispositions" + } }, "RangeDependance": { "hint": "Settings for an optional distance at which this effect should activate", @@ -221,9 +199,6 @@ "headerTitle": "Adversary Reaction Roll" } }, - "Base": { - "CannotAddType": "Cannot add {itemType} items to {actorType} actors." - }, "Character": { "advantageSources": { "label": "Advantage Sources", @@ -247,8 +222,6 @@ }, "defaultHopeDice": "Default Hope Dice", "defaultFearDice": "Default Fear Dice", - "defaultAdvantageDice": "Default Advantage Dice", - "defaultDisadvantageDice": "Default Disadvantage Dice", "disadvantageSources": { "label": "Disadvantage Sources", "hint": "Add single words or short text as reminders and hints of what a character has disadvantage on." @@ -333,27 +306,6 @@ } }, "newAdversary": "New Adversary" - }, - "NPC": { - "FIELDS": { - "motives": { "label": "Motives" } - } - }, - "Party": { - "Subtitle": { - "character": "{community} {ancestry} | {subclass} {class}", - "companion": "Companion of {partner}" - }, - "RemoveConfirmation": { - "title": "Remove member {name}", - "text": "Are you sure you want to remove {name} from the party?" - }, - "Thresholds": { - "minor": "MIN", - "major": "MAJ", - "severe": "SEV" - }, - "triggerRestContent": "This will trigger a dialog to players make their downtime moves. Are you sure?" } }, "APPLICATIONS": { @@ -389,7 +341,7 @@ "selectSecondaryWeapon": "Select Secondary Weapon", "selectSubclass": "Select Subclass", "setupSkipTitle": "Skipping Character Setup", - "setupSkipContent": "You are skipping the Character Setup by adding this manually. The character setup is the blinking button in the top-right. Are you sure you want to continue?", + "setupSkipContent": "You are skipping the Character Setup by adding this manually. The character setup is the blinking arrows in the top-right. Are you sure you want to continue?", "startingItems": "Starting Items", "story": "Story", "storyExplanation": "Select which background and connection prompts you want to copy into your character's background.", @@ -412,11 +364,7 @@ "giveSpotlight": "Give The Spotlight", "requestingSpotlight": "Requesting The Spotlight", "requestSpotlight": "Request The Spotlight", - "openCountdowns": "Countdowns", - "adversaryCategories": { - "friendly": "Friendly", - "adversaries": "Adversaries" - } + "openCountdowns": "Countdowns" }, "CompendiumBrowserSettings": { "title": "Enable Compendiums", @@ -497,15 +445,14 @@ }, "DaggerheartMenu": { "title": "GM Tools", - "refreshFeatures": "Refresh Features", - "fallingAndCollision": "Falling And Collision Damage" + "refreshFeatures": "Refresh Features" }, "DeleteConfirmation": { "title": "Delete {type} - {name}", "text": "Are you sure you want to delete {name}?" }, "DamageReduction": { - "maxUseableArmor": "Useable Armor Slots", + "armorMarks": "Armor Marks", "armorWithStress": "Spend 1 stress to use an extra mark", "thresholdImmunities": "Threshold Immunities", "stress": "Stress", @@ -711,13 +658,19 @@ }, "PendingReactionsDialog": { "title": "Pending Reaction Rolls Found", - "unfinishedRolls": "Some Tokens have not finished their Reaction Rolls.", - "warning": "Unfinished reaction rolls will be considered as failed.", - "confirmation": "Are you sure you want to continue?" + "unfinishedRolls": "Some Tokens still need to roll their Reaction Roll.", + "confirmation": "Are you sure you want to continue ?", + "warning": "Undone reaction rolls will be considered as failed" }, "ReactionRoll": { "title": "Reaction Roll: {trait}" }, + "RerollDialog": { + "title": "Reroll", + "damageTitle": "Reroll Damage", + "deselectDiceNotification": "Deselect one of the selected dice first", + "acceptCurrentRolls": "Accept Current Rolls" + }, "ResourceDice": { "title": "{name} Resource", "rerollDice": "Reroll Dice" @@ -731,28 +684,15 @@ }, "TagTeamSelect": { "title": "Tag Team Roll", - "FIELDS": { - "initiator": { - "memberId": { "label": "Initiating Character" }, - "cost": { "label": "Hope Cost" } - } - }, "leaderTitle": "Initiating Character", "membersTitle": "Participants", "partyTeam": "Party Team", "hopeCost": "Hope Cost", "initiatingCharacter": "Initiating Character", - "selectParticipants": "Select the two participants", - "startTagTeamRoll": "Start Tag Team Roll", - "openDialogForAll": "Open Dialog For All", - "rollType": "Roll Type", - "makeYourRoll": "Make your roll", - "cancelTagTeamRoll": "Cancel Tag Team Roll", - "finishTagTeamRoll": "Finish Tag Team Roll", "linkMessageHint": "Make a roll from your character sheet to link it to the Tag Team Roll", "damageNotRolled": "Damage not rolled in chat message yet", "insufficientHope": "The initiating character doesn't have enough hope", - "createTagTeam": "Create Tag Team Roll", + "createTagTeam": "Create TagTeam Roll", "chatMessageRollTitle": "Roll", "cancelConfirmTitle": "Cancel Tag Team Roll", "cancelConfirmText": "Are you sure you want to cancel the Tag Team Roll? This will close it for all other players too.", @@ -761,26 +701,8 @@ "selectRoll": "Select which roll value to be used for the Tag Team" } }, - "GroupRollSelect": { - "cancelConfirmText": "Are you sure you want to cancel the Group Roll? This will close it for all other players too.", - "cancelConfirmTitle": "Cancel Group Roll", - "initializationTitle": "Character Selection", - "finishGroupRoll": "Finish Group Roll", - "leader": "Leader", - "leaderRoll": "Leader Roll", - "members": "Members", - "openDialogForAll": "Open Dialog For All", - "removeRoll": "Remove Roll", - "resultsHint": "Results will appear when characters roll", - "selectLeaderHint": "Select one Character to be the leader", - "selectParticipantsHint": "Select one Character to be the leader", - "startGroupRoll": "Start Group Roll", - "title": "Group Roll" - }, "TokenConfig": { - "actorSizeUsed": "Actor size is set, determining the dimensions", - "tokenSize": "Token Size", - "sizeCategory": "Size Category" + "actorSizeUsed": "Actor size is set, determining the dimensions" } }, "CLASS": { @@ -790,15 +712,6 @@ } }, "CONFIG": { - "ActiveEffectDuration": { - "temporary": "Temporary", - "act": "Next Spotlight", - "scene": "Next Scene", - "shortRest": "Next Rest", - "longRest": "Next Long Rest", - "session": "Next Session", - "custom": "Custom" - }, "ActionAutomationChoices": { "never": "Never", "showDialog": "Show Dialog Only", @@ -871,11 +784,6 @@ "bruiser": "for each Bruiser adversary.", "solo": "for each Solo adversary." }, - "ArmorInteraction": { - "none": { "label": "Ignores Armor" }, - "active": { "label": "Active w/ Armor" }, - "inactive": { "label": "Inactive w/ Armor" } - }, "ArmorFeature": { "burning": { "name": "Burning", @@ -1226,12 +1134,6 @@ "description": "" } }, - "fallAndCollision": { - "veryClose": { "label": "Very Close", "chatTitle": "Fall Damage: Very Close" }, - "close": { "label": "Close", "chatTitle": "Fall Damage: Close" }, - "far": { "label": "Far", "chatTitle": "Fall Damage: Far" }, - "collision": { "label": "Collision", "chatTitle": "Dangerous Collision" } - }, "FeatureForm": { "label": "Feature Form", "passive": "Passive", @@ -1342,11 +1244,6 @@ "selectType": "Select Action Type", "selectAction": "Action Selection" }, - "TagTeamRollTypes": { - "trait": "Trait", - "ability": "Ability", - "damageAbility": "Damage Ability" - }, "TargetTypes": { "any": "Any", "friendly": "Friendly", @@ -1359,8 +1256,8 @@ "cone": "Cone", "emanation": "Emanation", "inFront": "In Front", - "rectangle": "Rectangle", - "line": "Line" + "rect": "Rectangle", + "ray": "Ray" }, "TokenSize": { "tiny": "Tiny", @@ -1975,17 +1872,6 @@ "name": "Healing Roll" } }, - "ChangeTypes": { - "armor": { - "newArmorEffect": "Armor Effect", - "FIELDS": { - "interaction": { - "label": "Armor Interaction", - "hint": "Does the character wearing armor suppress this effect?" - } - } - } - }, "Duration": { "passive": "Passive", "temporary": "Temporary" @@ -2010,10 +1896,6 @@ } }, "GENERAL": { - "Ability": { - "single": "Ability", - "plural": "Abilities" - }, "Action": { "single": "Action", "plural": "Actions" @@ -2399,7 +2281,6 @@ "duality": "Duality", "dualityDice": "Duality Dice", "dualityRoll": "Duality Roll", - "effect": "Effect", "enabled": "Enabled", "evasion": "Evasion", "equipment": "Equipment", @@ -2448,11 +2329,9 @@ "single": "Miss", "plural": "Miss" }, - "missingX": "Missing {x}", "maxWithThing": "Max {thing}", "missingDragDropThing": "Drop {thing} here", "multiclass": "Multiclass", - "name": "Name", "newCategory": "New Category", "newThing": "New {thing}", "next": "Next", @@ -2476,10 +2355,6 @@ "rerolled": "Rerolled", "rerollThing": "Reroll {thing}", "resource": "Resource", - "result": { - "single": "Result", - "plural": "Results" - }, "roll": "Roll", "rollAll": "Roll All", "rollDamage": "Roll Damage", @@ -2539,9 +2414,6 @@ "recovery": { "label": "Recovery" }, "type": { "label": "Type" }, "value": { "label": "Value" } - }, - "identifier": { - "label": "Identifier" } }, "Ancestry": { @@ -2567,11 +2439,10 @@ "tokenImg": { "label": "Token Image" }, "tokenRingImg": { "label": "Subject Texture" }, "tokenSize": { - "placeholder": "Token Size", - "disabledPlaceholder": "Token Size", + "placeholder": "Using character dimensions", + "disabledPlaceholder": "Set by character size", "height": { "label": "Height" }, "width": { "label": "Width" }, - "depth": { "label": "Depth" }, "scale": { "label": "Token Scale" } }, "evolved": { @@ -2657,7 +2528,8 @@ "MACROS": { "Spotlight": { "errors": { - "noTokenSelected": "A token on the canvas must either be selected or hovered to spotlight it" + "noActiveCombat": "There is no active encounter", + "noCombatantSelected": "A combatant token must be either selected or hovered to spotlight it" } } }, @@ -2732,10 +2604,6 @@ "hint": "Automatically increase the GM's fear pool on a fear duality roll result." }, "FIELDS": { - "autoExpireActiveEffects": { - "label": "Auto Expire Active Effects", - "hint": "Active Effects with set durations will automatically be removed when their durations are up" - }, "damageReductionRulesDefault": { "label": "Damage Reduction Rules Default", "hint": "Wether using armor and reductions has rules on by default" @@ -2833,15 +2701,6 @@ "hideObserverPermissionInChat": { "label": "Hide Chat Info From Players", "hint": "Information such as hit/miss on attack rolls against adversaries will be hidden" - }, - "hidePartyStats": { - "label": "Hide Party Stats", - "hint": "Resources and stats in the party sheet's member list will be hidden to the following users, even if the user is part of the same party", - "choices": { - "never": "Never, always show", - "players": "Hide From Players", - "always": "Hide from Everyone" - } } } }, @@ -2914,10 +2773,6 @@ } }, "Keybindings": { - "partySheet": { - "name": "Toggle Party Sheet", - "hint": "Open or close the active party's sheet" - }, "spotlight": { "name": "Spotlight Combatant", "hint": "Move the spotlight to a hovered or selected token that's present in an active encounter" @@ -2962,7 +2817,6 @@ "system": "Dice Preset", "font": "Font", "critical": "Duality Critical Animation", - "muted": "Muted", "diceAppearance": "Dice Appearance", "animations": "Animations", "defaultAnimations": "Set Animations As Player Defaults", @@ -3071,6 +2925,18 @@ "immunityTo": "Immunity: {immunities}" }, "featureTitle": "Class Feature", + "groupRoll": { + "title": "Group Roll", + "leader": "Leader", + "partyTeam": "Party Team", + "team": "Team", + "selectLeader": "Select a Leader", + "selectMember": "Select a Member", + "rerollTitle": "Reroll Group Roll", + "rerollContent": "Are you sure you want to reroll your {trait} roll?", + "rerollTooltip": "Reroll", + "wholePartySelected": "The whole party is selected" + }, "healingRoll": { "title": "Heal - {damage}", "heal": "Heal", @@ -3097,7 +2963,6 @@ } }, "ChatLog": { - "rerollActionRoll": "Reroll Action", "rerollDamage": "Reroll Damage", "assignTagRoll": "Assign as Tag Roll" }, @@ -3114,8 +2979,6 @@ }, "EffectsDisplay": { "removeThing": "[Right Click] Remove {thing}", - "increaseStacks": "[Left Click] Increment Stacks", - "decreaseStacks": "[Right Click] Decrement Stacks", "appliedBy": "Applied By: {by}" }, "ItemBrowser": { @@ -3231,6 +3094,7 @@ "subclassesAlreadyPresent": "You already have a class and multiclass subclass", "noDiceSystem": "Your selected dice {system} does not have a {faces} dice", "gmMenuRefresh": "You refreshed all actions and resources {types}", + "subclassAlreadyLinked": "{name} is already a subclass in the class {class}. Remove it from there if you want it to be a subclass to this class.", "gmRequired": "This action requires an online GM", "gmOnly": "This can only be accessed by the GM", "noActorOwnership": "You do not have permissions for this character", @@ -3239,12 +3103,7 @@ "tokenActorsMissing": "[{names}] missing Actors", "domainTouchRequirement": "This domain card requires {nr} {domain} cards in the loadout to be used", "knowTheTide": "Know The Tide gained a token", - "lackingItemTransferPermission": "User {user} lacks owner permission needed to transfer items to {target}", - "noTokenTargeted": "No token is targeted", - "behaviorRegionRequiresGM": "Creating a Region with an attached Behavior requires an online GM" - }, - "Progress": { - "migrationLabel": "Performing system migration. Please wait and do not close Foundry." + "lackingItemTransferPermission": "User {user} lacks owner permission needed to transfer items to {target}" }, "Sidebar": { "actorDirectory": { @@ -3253,8 +3112,6 @@ "companion": "Level {level} - {partner}", "companionNoPartner": "No Partner", "duplicateToNewTier": "Duplicate to New Tier", - "activateParty": "Make Active Party", - "partyIsActive": "Active", "createAdversary": "Create Adversary", "pickTierTitle": "Pick a new tier for this adversary" }, @@ -3267,7 +3124,6 @@ "Tooltip": { "disableEffect": "Disable Effect", "enableEffect": "Enable Effect", - "edit": "Edit", "openItemWorld": "Open Item World", "openActorWorld": "Open Actor World", "sendToChat": "Send to Chat", diff --git a/module/applications/characterCreation/characterCreation.mjs b/module/applications/characterCreation/characterCreation.mjs index 517f95da..467366fc 100644 --- a/module/applications/characterCreation/characterCreation.mjs +++ b/module/applications/characterCreation/characterCreation.mjs @@ -154,8 +154,8 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : this.tabGroups.primary !== 'equipment' - ? v.active - : false; + ? v.active + : false; v.cssClass = v.active ? 'active' : ''; switch (v.id) { @@ -211,9 +211,9 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl context.suggestedTraits = this.setup.class.system ? Object.keys(this.setup.class.system.characterGuide.suggestedTraits).map(traitKey => { - const trait = this.setup.class.system.characterGuide.suggestedTraits[traitKey]; - return `${game.i18n.localize(`DAGGERHEART.CONFIG.Traits.${traitKey}.short`)} ${trait > 0 ? `+${trait}` : trait}`; - }) + const trait = this.setup.class.system.characterGuide.suggestedTraits[traitKey]; + return `${game.i18n.localize(`DAGGERHEART.CONFIG.Traits.${traitKey}.short`)} ${trait > 0 ? `+${trait}` : trait}`; + }) : []; context.traits = { values: Object.keys(this.setup.traits).map(traitKey => { @@ -439,18 +439,15 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl 'system.domain': { key: 'system.domain', value: this.setup.class?.system.domains ?? null } }; - if (type === 'subclasses') { - const classItem = this.setup.class; - const uuid = classItem?._stats.compendiumSource ?? classItem?.uuid; + if (type === 'subclasses') presets.filter = { - 'system.linkedClass': { key: 'system.linkedClass', value: uuid } + 'system.linkedClass.uuid': { key: 'system.linkedClass.uuid', value: this.setup.class?.uuid } }; - } if (equipment.includes(type)) presets.filter = { 'system.tier': { key: 'system.tier', value: 1 }, - type: { key: 'type', value: type } + 'type': { key: 'type', value: type } }; ui.compendiumBrowser.open(presets); @@ -562,7 +559,7 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl experiences: { ...this.setup.experiences, ...Object.keys(this.character.system.experiences).reduce((acc, key) => { - acc[`${key}`] = _del; + acc[`-=${key}`] = null; return acc; }, {}) } @@ -613,8 +610,7 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl [foundry.utils.randomID()]: {} }; } else if (item.type === 'subclass' && event.target.closest('.subclass-card')) { - const classSubclasses = await this.setup.class.system.fetchSubclasses(); - if (classSubclasses.every(subclass => subclass.uuid !== item.uuid)) { + if (this.setup.class.system.subclasses.every(subclass => subclass.uuid !== item.uuid)) { ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.subclassNotInClass')); return; } diff --git a/module/applications/dialogs/CompendiumBrowserSettings.mjs b/module/applications/dialogs/CompendiumBrowserSettings.mjs index b0d83fb3..bef54a6f 100644 --- a/module/applications/dialogs/CompendiumBrowserSettings.mjs +++ b/module/applications/dialogs/CompendiumBrowserSettings.mjs @@ -50,7 +50,7 @@ export default class CompendiumBrowserSettings extends HandlebarsApplicationMixi const excludedSourceData = this.browserSettings.excludedSources; const excludedPackData = this.browserSettings.excludedPacks; context.typePackCollections = game.packs.reduce((acc, pack) => { - const { type, label, packageType, packageName: basePackageName, name, id } = pack.metadata; + const { type, label, packageType, packageName: basePackageName, id } = pack.metadata; if (!CompendiumBrowserSettings.#browserPackTypes.includes(type)) return acc; const isWorldPack = packageType === 'world'; @@ -68,15 +68,13 @@ export default class CompendiumBrowserSettings extends HandlebarsApplicationMixi if (!acc[type].sources[packageName]) acc[type].sources[packageName] = { label: sourceLabel, checked: sourceChecked, packs: [] }; - const included = - !excludedPackData[packageName] || - !excludedPackData[packageName][name]?.excludedDocumentTypes.includes(type); + const checked = !excludedPackData[id] || !excludedPackData[id].excludedDocumentTypes.includes(type); acc[type].sources[packageName].packs.push({ - name, + pack: id, type, label: id === game.system.id ? game.system.title : game.i18n.localize(label), - checked: included + checked: checked }); return acc; @@ -108,16 +106,16 @@ export default class CompendiumBrowserSettings extends HandlebarsApplicationMixi toggleTypedPack(event) { event.stopPropagation(); - const { type, source, packName } = event.target.dataset; - const currentlyExcluded = this.browserSettings.excludedPacks[source]?.[packName] - ? this.browserSettings.excludedPacks[source][packName].excludedDocumentTypes.includes(type) + const { type, pack } = event.target.dataset; + const currentlyExcluded = this.browserSettings.excludedPacks[pack] + ? this.browserSettings.excludedPacks[pack].excludedDocumentTypes.includes(type) : false; - this.browserSettings.excludedPacks[source] ??= {}; - this.browserSettings.excludedPacks[source][packName] ??= { excludedDocumentTypes: [] }; - this.browserSettings.excludedPacks[source][packName].excludedDocumentTypes = currentlyExcluded - ? this.browserSettings.excludedPacks[source][packName].excludedDocumentTypes.filter(x => x !== type) - : [...(this.browserSettings.excludedPacks[source][packName]?.excludedDocumentTypes ?? []), type]; + if (!this.browserSettings.excludedPacks[pack]) + this.browserSettings.excludedPacks[pack] = { excludedDocumentTypes: [] }; + this.browserSettings.excludedPacks[pack].excludedDocumentTypes = currentlyExcluded + ? this.browserSettings.excludedPacks[pack].excludedDocumentTypes.filter(x => x !== type) + : [...(this.browserSettings.excludedPacks[pack]?.excludedDocumentTypes ?? []), type]; this.render(); } diff --git a/module/applications/dialogs/_module.mjs b/module/applications/dialogs/_module.mjs index fc5169b2..a479100a 100644 --- a/module/applications/dialogs/_module.mjs +++ b/module/applications/dialogs/_module.mjs @@ -10,9 +10,10 @@ export { default as ImageSelectDialog } from './imageSelectDialog.mjs'; export { default as ItemTransferDialog } from './itemTransfer.mjs'; export { default as MulticlassChoiceDialog } from './multiclassChoiceDialog.mjs'; export { default as OwnershipSelection } from './ownershipSelection.mjs'; +export { default as RerollDamageDialog } from './rerollDamageDialog.mjs'; export { default as ResourceDiceDialog } from './resourceDiceDialog.mjs'; export { default as ActionSelectionDialog } from './actionSelectionDialog.mjs'; +export { default as GroupRollDialog } from './group-roll-dialog.mjs'; export { default as TagTeamDialog } from './tagTeamDialog.mjs'; -export { default as GroupRollDialog } from './groupRollDialog.mjs'; export { default as RiskItAllDialog } from './riskItAllDialog.mjs'; export { default as CompendiumBrowserSettingsDialog } from './CompendiumBrowserSettings.mjs'; diff --git a/module/applications/dialogs/actionSelectionDialog.mjs b/module/applications/dialogs/actionSelectionDialog.mjs index 6123c970..c421a577 100644 --- a/module/applications/dialogs/actionSelectionDialog.mjs +++ b/module/applications/dialogs/actionSelectionDialog.mjs @@ -72,7 +72,7 @@ export default class ActionSelectionDialog extends HandlebarsApplicationMixin(Ap static async #onChooseAction(event, button) { const { actionId } = button.dataset; - this.#action = this.item.system.actionsList.find(a => a._id === actionId); + this.#action = this.#item.system.actionsList.find(a => a._id === actionId); Object.defineProperty(this.#event, 'shiftKey', { get() { return event.shiftKey; diff --git a/module/applications/dialogs/beastformDialog.mjs b/module/applications/dialogs/beastformDialog.mjs index 8ae6d5fe..09a9222b 100644 --- a/module/applications/dialogs/beastformDialog.mjs +++ b/module/applications/dialogs/beastformDialog.mjs @@ -10,12 +10,6 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat this.selected = null; this.evolved = { form: null }; this.hybrid = { forms: {}, advantages: {}, features: {} }; - this.modifications = { - traitBonuses: configData.modifications.traitBonuses.map(x => ({ - trait: null, - bonus: x.bonus - })) - }; this._dragDrop = this._createDragDropHandlers(); } @@ -34,7 +28,6 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat selectBeastform: this.selectBeastform, toggleHybridFeature: this.toggleHybridFeature, toggleHybridAdvantage: this.toggleHybridAdvantage, - toggleTraitBonus: this.toggleTraitBonus, submitBeastform: this.submitBeastform }, form: { @@ -55,7 +48,6 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat tabs: { template: 'systems/daggerheart/templates/dialogs/beastform/tabs.hbs' }, beastformTier: { template: 'systems/daggerheart/templates/dialogs/beastform/beastformTier.hbs' }, advanced: { template: 'systems/daggerheart/templates/dialogs/beastform/advanced.hbs' }, - modifications: { template: 'systems/daggerheart/templates/dialogs/beastform/modifications.hbs' }, footer: { template: 'systems/daggerheart/templates/dialogs/beastform/footer.hbs' } }; @@ -154,9 +146,6 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat {} ); - context.modifications = this.modifications; - context.traits = CONFIG.DH.ACTOR.abilities; - context.tier = beastformTiers[this.tabGroups.primary]; context.tierKey = this.tabGroups.primary; @@ -166,9 +155,6 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat } canSubmit() { - const modificationsFinished = this.modifications.traitBonuses.every(x => x.trait); - if (!modificationsFinished) return false; - if (this.selected) { switch (this.selected.system.beastformType) { case 'normal': @@ -275,13 +261,6 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat this.render(); } - static toggleTraitBonus(_, button) { - const { index, trait } = button.dataset; - this.modifications.traitBonuses[index].trait = - this.modifications.traitBonuses[index].trait === trait ? null : trait; - this.render(); - } - static async submitBeastform() { await this.close({ submitted: true }); } @@ -313,23 +292,6 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat } } - const beastformEffect = selected.effects.find(x => x.type === 'beastform'); - for (const traitBonus of app.modifications.traitBonuses) { - const existingChange = beastformEffect.changes.find( - x => x.key === `system.traits.${traitBonus.trait}.value` - ); - if (existingChange) { - existingChange.value = Number.parseInt(existingChange.value) + traitBonus.bonus; - } else { - beastformEffect.changes.push({ - key: `system.traits.${traitBonus.trait}.value`, - mode: 2, - priority: null, - value: traitBonus.bonus - }); - } - } - resolve({ selected: selected, evolved: { ...app.evolved, form: evolved }, diff --git a/module/applications/dialogs/characterResetDialog.mjs b/module/applications/dialogs/characterResetDialog.mjs index aecebc7c..0836af9c 100644 --- a/module/applications/dialogs/characterResetDialog.mjs +++ b/module/applications/dialogs/characterResetDialog.mjs @@ -77,8 +77,8 @@ export default class CharacterResetDialog extends HandlebarsApplicationMixin(App if (!this.data.optional.portrait.keep) { foundry.utils.setProperty(update, 'img', this.actor.schema.fields.img.initial(this.actor)); - foundry.utils.setProperty(update, 'prototypeToken.texture', _replace({})); - foundry.utils.setProperty(update, 'prototypeToken.ring', _replace({})); + foundry.utils.setProperty(update, 'prototypeToken.==texture', {}); + foundry.utils.setProperty(update, 'prototypeToken.==ring', {}); } if (this.data.optional.biography.keep) @@ -89,7 +89,7 @@ export default class CharacterResetDialog extends HandlebarsApplicationMixin(App const { system, ...rest } = update; await this.actor.update({ ...rest, - system: _replace(system ?? {}) + '==system': system ?? {} }); const inventoryItemTypes = ['weapon', 'armor', 'consumable', 'loot']; diff --git a/module/applications/dialogs/d20RollDialog.mjs b/module/applications/dialogs/d20RollDialog.mjs index 9a98b197..8e79ba58 100644 --- a/module/applications/dialogs/d20RollDialog.mjs +++ b/module/applications/dialogs/d20RollDialog.mjs @@ -35,6 +35,7 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio updateIsAdvantage: this.updateIsAdvantage, selectExperience: this.selectExperience, toggleReaction: this.toggleReaction, + toggleTagTeamRoll: this.toggleTagTeamRoll, toggleSelectedEffect: this.toggleSelectedEffect, submitRoll: this.submitRoll }, @@ -70,8 +71,8 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio context.rollConfig = this.config; context.hasRoll = !!this.config.roll; context.canRoll = true; - context.selectedMessageMode = this.config.selectedMessageMode ?? game.settings.get('core', 'messageMode'); - context.rollModes = Object.entries(CONFIG.ChatMessage.modes).map(([action, { label, icon }]) => ({ + context.selectedRollMode = this.config.selectedRollMode ?? game.settings.get('core', 'rollMode'); + context.rollModes = Object.entries(CONFIG.Dice.rollModes).map(([action, { label, icon }]) => ({ action, label, icon @@ -123,10 +124,6 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio context.advantage = this.config.roll?.advantage; context.disadvantage = this.config.roll?.disadvantage; context.diceOptions = CONFIG.DH.GENERAL.diceTypes; - context.dieFaces = CONFIG.DH.GENERAL.dieFaces.reduce((acc, face) => { - acc[face] = `d${face}`; - return acc; - }, {}); context.isLite = this.config.roll?.lite; context.extraFormula = this.config.extraFormula; context.formula = this.roll.constructFormula(this.config); @@ -136,6 +133,12 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio context.reactionOverride = this.reactionOverride; } + const tagTeamSetting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll); + if (this.actor && tagTeamSetting.members[this.actor.id] && !this.config.skips?.createMessage) { + context.activeTagTeamRoll = true; + context.tagTeamSelected = this.config.tagTeamSelected; + } + return context; } @@ -146,17 +149,19 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio })); } - static updateRollConfiguration(_event, _, formData) { + static updateRollConfiguration(event, _, formData) { const { ...rest } = foundry.utils.expandObject(formData.object); - this.config.selectedMessageMode = rest.selectedMessageMode; + this.config.selectedRollMode = rest.selectedRollMode; if (this.config.costs) { this.config.costs = foundry.utils.mergeObject(this.config.costs, rest.costs); } if (this.config.uses) this.config.uses = foundry.utils.mergeObject(this.config.uses, rest.uses); if (rest.roll?.dice) { - this.roll = foundry.utils.mergeObject(this.roll, rest.roll.dice); + Object.entries(rest.roll.dice).forEach(([key, value]) => { + this.roll[key] = value; + }); } if (rest.hasOwnProperty('trait')) { this.config.roll.trait = rest.trait; @@ -175,15 +180,6 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio this.disadvantage = advantage === -1; this.config.roll.advantage = this.config.roll.advantage === advantage ? 0 : advantage; - if (this.config.roll.advantage === 0) return this.render(); - - const defaultFaces = - this.config.roll.advantage === 1 - ? this.config.data.rules.roll.defaultAdvantageDice - : this.config.data.rules.roll.defaultDisadvantageDice; - const faces = Number.parseInt(defaultFaces); - this.roll.advantageFaces = Number.isNaN(faces) ? this.roll.advantageFaces : faces; - this.render(); } @@ -196,14 +192,14 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio this.config.costs.indexOf(this.config.costs.find(c => c.extKey === button.dataset.key)) > -1 ? this.config.costs.filter(x => x.extKey !== button.dataset.key) : [ - ...this.config.costs, - { - extKey: button.dataset.key, - key: this.config?.data?.parent?.isNPC ? 'fear' : 'hope', - value: 1, - name: this.config.data?.system.experiences?.[button.dataset.key]?.name - } - ]; + ...this.config.costs, + { + extKey: button.dataset.key, + key: this.config?.data?.parent?.isNPC ? 'fear' : 'hope', + value: 1, + name: this.config.data?.system.experiences?.[button.dataset.key]?.name + } + ]; this.render(); } @@ -213,12 +209,17 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio this.config.actionType = this.reactionOverride ? 'reaction' : this.config.actionType === 'reaction' - ? 'action' - : this.config.actionType; + ? 'action' + : this.config.actionType; this.render(); } } + static toggleTagTeamRoll() { + this.config.tagTeamSelected = !this.config.tagTeamSelected; + this.render(); + } + static toggleSelectedEffect(_event, button) { this.selectedEffects[button.dataset.key].selected = !this.selectedEffects[button.dataset.key].selected; this.render(); diff --git a/module/applications/dialogs/damageDialog.mjs b/module/applications/dialogs/damageDialog.mjs index 46d3d41f..b24570cc 100644 --- a/module/applications/dialogs/damageDialog.mjs +++ b/module/applications/dialogs/damageDialog.mjs @@ -22,8 +22,6 @@ export default class DamageDialog extends HandlebarsApplicationMixin(Application }, actions: { toggleSelectedEffect: this.toggleSelectedEffect, - updateGroupAttack: this.updateGroupAttack, - toggleCritical: this.toggleCritical, submitRoll: this.submitRoll }, form: { @@ -54,9 +52,8 @@ export default class DamageDialog extends HandlebarsApplicationMixin(Application context.formula = this.roll.constructFormula(this.config); context.hasHealing = this.config.hasHealing; context.directDamage = this.config.directDamage; - context.selectedMessageMode = this.config.selectedMessageMode; - context.isCritical = this.config.isCritical; - context.rollModes = Object.entries(CONFIG.ChatMessage.modes).map(([action, { label, icon }]) => ({ + context.selectedRollMode = this.config.selectedRollMode; + context.rollModes = Object.entries(CONFIG.Dice.rollModes).map(([action, { label, icon }]) => ({ action, label, icon @@ -65,45 +62,15 @@ export default class DamageDialog extends HandlebarsApplicationMixin(Application context.hasSelectedEffects = Boolean(Object.keys(this.selectedEffects).length); context.selectedEffects = this.selectedEffects; - context.damageOptions = this.config.damageOptions; - context.rangeOptions = CONFIG.DH.GENERAL.groupAttackRange; - return context; } static updateRollConfiguration(_event, _, formData) { - const data = foundry.utils.expandObject(formData.object); - foundry.utils.mergeObject(this.config.roll, data.roll); - foundry.utils.mergeObject(this.config.modifiers, data.modifiers); - this.config.selectedMessageMode = data.selectedMessageMode; + const { ...rest } = foundry.utils.expandObject(formData.object); + foundry.utils.mergeObject(this.config.roll, rest.roll); + foundry.utils.mergeObject(this.config.modifiers, rest.modifiers); + this.config.selectedRollMode = rest.selectedRollMode; - if (data.damageOptions) { - const numAttackers = data.damageOptions.groupAttack?.numAttackers; - if (typeof numAttackers !== 'number' || numAttackers % 1 !== 0) { - data.damageOptions.groupAttack.numAttackers = null; - } - - foundry.utils.mergeObject(this.config.damageOptions, data.damageOptions); - } - - this.render(); - } - - static updateGroupAttack() { - const targets = Array.from(game.user.targets); - if (targets.length === 0) - return ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.noTokenTargeted')); - - const actorId = this.roll.data.parent.id; - const range = this.config.damageOptions.groupAttack.range; - const groupAttackTokens = game.system.api.fields.ActionFields.DamageField.getGroupAttackTokens(actorId, range); - - this.config.damageOptions.groupAttack.numAttackers = groupAttackTokens.length; - this.render(); - } - - static toggleCritical() { - this.config.isCritical = !this.config.isCritical; this.render(); } diff --git a/module/applications/dialogs/damageReductionDialog.mjs b/module/applications/dialogs/damageReductionDialog.mjs index e5108e34..cd0a5cf7 100644 --- a/module/applications/dialogs/damageReductionDialog.mjs +++ b/module/applications/dialogs/damageReductionDialog.mjs @@ -1,4 +1,4 @@ -import { damageKeyToNumber, getArmorSources, getDamageLabel } from '../../helpers/utils.mjs'; +import { damageKeyToNumber, getDamageLabel } from '../../helpers/utils.mjs'; const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; @@ -10,7 +10,6 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap this.reject = reject; this.actor = actor; this.damage = damage; - this.damageType = damageType; this.rulesDefault = game.settings.get( CONFIG.DH.id, @@ -21,21 +20,14 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap this.rulesDefault ); - const orderedArmorSources = getArmorSources(actor).filter(s => !s.disabled); - const armor = orderedArmorSources.reduce((acc, { name, document }) => { - const { current, max } = document.type === 'armor' ? document.system.armor : document.system.armorData; - acc.push({ - name, - effect: document, - marks: [...Array(max).keys()].reduce((acc, _, index) => { - const spent = index < current; - acc[foundry.utils.randomID()] = { selected: false, disabled: spent, spent }; - return acc; - }, {}) - }); + const canApplyArmor = damageType.every(t => actor.system.armorApplicableDamageTypes[t] === true); + const availableArmor = actor.system.armorScore - actor.system.armor.system.marks.value; + const maxArmorMarks = canApplyArmor ? availableArmor : 0; + const armor = [...Array(maxArmorMarks).keys()].reduce((acc, _) => { + acc[foundry.utils.randomID()] = { selected: false }; return acc; - }, []); + }, {}); const stress = [...Array(actor.system.rules.damageReduction.maxArmorMarked.stressExtra ?? 0).keys()].reduce( (acc, _) => { acc[foundry.utils.randomID()] = { selected: false }; @@ -129,42 +121,36 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap context.thresholdImmunities = Object.keys(this.thresholdImmunities).length > 0 ? this.thresholdImmunities : null; - const { selectedStressMarks, stressReductions, currentMarks, currentDamage, maxArmorUsed, availableArmor } = + const { selectedArmorMarks, selectedStressMarks, stressReductions, currentMarks, currentDamage } = this.getDamageInfo(); - context.armorScore = this.actor.system.armorScore.max; + context.armorScore = this.actor.system.armorScore; context.armorMarks = currentMarks; + context.basicMarksUsed = + selectedArmorMarks.length === this.actor.system.rules.damageReduction.maxArmorMarked.value; const stressReductionStress = this.availableStressReductions ? stressReductions.reduce((acc, red) => acc + red.cost, 0) : 0; - const stress = this.actor.system.resources.stress; context.stress = selectedStressMarks.length > 0 || this.availableStressReductions ? { - value: stress.value + selectedStressMarks.length + stressReductionStress, - max: stress.max - } + value: + this.actor.system.resources.stress.value + selectedStressMarks.length + stressReductionStress, + max: this.actor.system.resources.stress.max + } : null; - context.maxArmorUsed = maxArmorUsed; - context.availableArmor = availableArmor; - context.basicMarksUsed = availableArmor === 0 || selectedStressMarks.length; - - const armorSources = []; - for (const source of this.marks.armor) { - armorSources.push({ - label: source.name, - uuid: source.effect.uuid, - marks: source.marks - }); - } + const maxArmor = this.actor.system.rules.damageReduction.maxArmorMarked.value; context.marks = { - armor: armorSources, + armor: Object.keys(this.marks.armor).reduce((acc, key, index) => { + const mark = this.marks.armor[key]; + if (!this.rulesOn || index + 1 <= maxArmor) acc[key] = mark; + + return acc; + }, {}), stress: this.marks.stress }; - - context.usesStressArmor = Object.keys(context.marks.stress).length; context.availableStressReductions = this.availableStressReductions; context.damage = getDamageLabel(this.damage); @@ -181,31 +167,27 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap } getDamageInfo = () => { - const selectedArmorMarks = this.marks.armor.flatMap(x => Object.values(x.marks).filter(x => x.selected)); + const selectedArmorMarks = Object.values(this.marks.armor).filter(x => x.selected); const selectedStressMarks = Object.values(this.marks.stress).filter(x => x.selected); const stressReductions = this.availableStressReductions ? Object.values(this.availableStressReductions).filter(red => red.selected) : []; - const currentMarks = this.actor.system.armorScore.value + selectedArmorMarks.length; - - const maxArmorUsed = this.actor.system.rules.damageReduction.maxArmorMarked.value + selectedStressMarks.length; - const availableArmor = - maxArmorUsed - - this.marks.armor.reduce((acc, source) => { - acc += Object.values(source.marks).filter(x => x.selected).length; - return acc; - }, 0); + const currentMarks = + this.actor.system.armor.system.marks.value + selectedArmorMarks.length + selectedStressMarks.length; const armorMarkReduction = selectedArmorMarks.length * this.actor.system.rules.damageReduction.increasePerArmorMark; - let currentDamage = Math.max(this.damage - armorMarkReduction - stressReductions.length, 0); + let currentDamage = Math.max( + this.damage - armorMarkReduction - selectedStressMarks.length - stressReductions.length, + 0 + ); if (this.reduceSeverity) { currentDamage = Math.max(currentDamage - this.reduceSeverity, 0); } if (this.thresholdImmunities[currentDamage]) currentDamage = 0; - return { selectedStressMarks, stressReductions, currentMarks, currentDamage, maxArmorUsed, availableArmor }; + return { selectedArmorMarks, selectedStressMarks, stressReductions, currentMarks, currentDamage }; }; static toggleRules() { @@ -213,10 +195,13 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap const maxArmor = this.actor.system.rules.damageReduction.maxArmorMarked.value; this.marks = { - armor: this.marks.armor.map((mark, index) => { + armor: Object.keys(this.marks.armor).reduce((acc, key, index) => { + const mark = this.marks.armor[key]; const keepSelectValue = !this.rulesOn || index + 1 <= maxArmor; - return { ...mark, selected: keepSelectValue ? mark.selected : false }; - }), + acc[key] = { ...mark, selected: keepSelectValue ? mark.selected : false }; + + return acc; + }, {}), stress: this.marks.stress }; @@ -224,8 +209,8 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap } static setMarks(_, target) { - const currentMark = foundry.utils.getProperty(this.marks, target.dataset.path); - const { selectedStressMarks, stressReductions, currentDamage, availableArmor } = this.getDamageInfo(); + const currentMark = this.marks[target.dataset.type][target.dataset.key]; + const { selectedStressMarks, stressReductions, currentMarks, currentDamage } = this.getDamageInfo(); if (!currentMark.selected && currentDamage === 0) { ui.notifications.info(game.i18n.localize('DAGGERHEART.UI.Notifications.damageAlreadyNone')); @@ -233,18 +218,12 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap } if (this.rulesOn) { - if (target.dataset.type === 'armor' && !currentMark.selected && !availableArmor) { + if (!currentMark.selected && currentMarks === this.actor.system.armorScore) { ui.notifications.info(game.i18n.localize('DAGGERHEART.UI.Notifications.noAvailableArmorMarks')); return; } } - const stressUsed = selectedStressMarks.length; - if (target.dataset.type === 'armor' && stressUsed) { - const updateResult = this.updateStressArmor(target.dataset.id, !currentMark.selected); - if (updateResult === false) return; - } - if (currentMark.selected) { const currentDamageLabel = getDamageLabel(currentDamage); for (let reduction of stressReductions) { @@ -253,16 +232,8 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap } } - if (target.dataset.type === 'stress' && currentMark.armorMarkId) { - for (const source of this.marks.armor) { - const match = Object.keys(source.marks).find(key => key === currentMark.armorMarkId); - if (match) { - source.marks[match].selected = false; - break; - } - } - - currentMark.armorMarkId = null; + if (target.dataset.type === 'armor' && selectedStressMarks.length > 0) { + selectedStressMarks.forEach(mark => (mark.selected = false)); } } @@ -270,25 +241,6 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap this.render(); } - updateStressArmor(armorMarkId, select) { - let stressMarkKey = null; - if (select) { - stressMarkKey = Object.keys(this.marks.stress).find( - key => this.marks.stress[key].selected && !this.marks.stress[key].armorMarkId - ); - } else { - stressMarkKey = Object.keys(this.marks.stress).find( - key => this.marks.stress[key].armorMarkId === armorMarkId - ); - if (!stressMarkKey) - stressMarkKey = Object.keys(this.marks.stress).find(key => this.marks.stress[key].selected); - } - - if (!stressMarkKey) return false; - - this.marks.stress[stressMarkKey].armorMarkId = select ? armorMarkId : null; - } - static useStressReduction(_, target) { const damageValue = Number(target.dataset.reduction); const stressReduction = this.availableStressReductions[damageValue]; @@ -327,18 +279,11 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap } static async takeDamage() { - const { selectedStressMarks, stressReductions, currentDamage } = this.getDamageInfo(); - const armorChanges = this.marks.armor.reduce((acc, source) => { - const amount = Object.values(source.marks).filter(x => x.selected).length; - if (amount) acc.push({ uuid: source.effect.uuid, amount }); + const { selectedArmorMarks, selectedStressMarks, stressReductions, currentDamage } = this.getDamageInfo(); + const armorSpent = selectedArmorMarks.length + selectedStressMarks.length; + const stressSpent = selectedStressMarks.length + stressReductions.reduce((acc, red) => acc + red.cost, 0); - return acc; - }, []); - const stressSpent = - selectedStressMarks.filter(x => x.armorMarkId).length + - stressReductions.reduce((acc, red) => acc + red.cost, 0); - - this.resolve({ modifiedDamage: currentDamage, armorChanges, stressSpent }); + this.resolve({ modifiedDamage: currentDamage, armorSpent, stressSpent }); await this.close(true); } diff --git a/module/applications/dialogs/deathMove.mjs b/module/applications/dialogs/deathMove.mjs index 4a949b99..69ff758e 100644 --- a/module/applications/dialogs/deathMove.mjs +++ b/module/applications/dialogs/deathMove.mjs @@ -57,7 +57,6 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV let returnMessage = game.i18n.localize('DAGGERHEART.UI.Chat.deathMove.avoidScar'); if (config.roll.fate.value <= this.actor.system.levelData.level.current) { - const maxHope = this.actor.system.resources.hope.max + this.actor.system.scars; const newScarAmount = this.actor.system.scars + 1; await this.actor.update({ system: { @@ -65,7 +64,7 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV } }); - if (newScarAmount >= maxHope) { + if (newScarAmount >= this.actor.system.resources.hope.max) { await this.actor.setDeathMoveDefeated(CONFIG.DH.GENERAL.defeatedConditionChoices.dead.id); return game.i18n.format('DAGGERHEART.UI.Chat.deathMove.journeysEnd', { scars: newScarAmount }); } diff --git a/module/applications/dialogs/downtime.mjs b/module/applications/dialogs/downtime.mjs index e209cc3b..5dc93bae 100644 --- a/module/applications/dialogs/downtime.mjs +++ b/module/applications/dialogs/downtime.mjs @@ -1,4 +1,4 @@ -import { expireActiveEffects, refreshIsAllowed } from '../../helpers/utils.mjs'; +import { refreshIsAllowed } from '../../helpers/utils.mjs'; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; @@ -203,7 +203,7 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV const msg = { user: game.user.id, system: { - moves: moves.map(move => ({ ...move, actions: Array.from(move.actions) })), + moves: moves, actor: this.actor.uuid }, speaker: cls.getSpeaker(), @@ -259,16 +259,12 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV const resetValue = increasing ? 0 : feature.system.resource.max - ? new Roll( - Roll.replaceFormulaData(feature.system.resource.max, this.actor.getRollData()) - ).evaluateSync().total - : 0; + ? new Roll(Roll.replaceFormulaData(feature.system.resource.max, this.actor)).evaluateSync().total + : 0; await feature.update({ 'system.resource.value': resetValue }); } - expireActiveEffects(this.actor, [this.shortRest ? 'shortRest' : 'longRest']); - this.close(); } else { this.render(); diff --git a/module/applications/dialogs/group-roll-dialog.mjs b/module/applications/dialogs/group-roll-dialog.mjs new file mode 100644 index 00000000..8a3c43d6 --- /dev/null +++ b/module/applications/dialogs/group-roll-dialog.mjs @@ -0,0 +1,204 @@ +import autocomplete from 'autocompleter'; +import { abilities } from '../../config/actorConfig.mjs'; + +const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; + +export default class GroupRollDialog extends HandlebarsApplicationMixin(ApplicationV2) { + constructor(actors) { + super(); + this.actors = actors; + this.actorLeader = {}; + this.actorsMembers = []; + } + + get title() { + return 'Group Roll'; + } + + static DEFAULT_OPTIONS = { + tag: 'form', + classes: ['daggerheart', 'views', 'dh-style', 'dialog', 'group-roll'], + position: { width: 'auto', height: 'auto' }, + window: { + title: 'DAGGERHEART.UI.Chat.groupRoll.title' + }, + actions: { + roll: GroupRollDialog.#roll, + removeLeader: GroupRollDialog.#removeLeader, + removeMember: GroupRollDialog.#removeMember + }, + form: { handler: this.updateData, submitOnChange: true, closeOnSubmit: false } + }; + + static PARTS = { + application: { + id: 'group-roll', + template: 'systems/daggerheart/templates/dialogs/group-roll/group-roll.hbs' + } + }; + + _attachPartListeners(partId, htmlElement, options) { + super._attachPartListeners(partId, htmlElement, options); + const leaderChoices = this.actors.filter(x => this.actorsMembers.every(member => member.actor?.id !== x.id)); + const memberChoices = this.actors.filter( + x => this.actorLeader?.actor?.id !== x.id && this.actorsMembers.every(member => member.actor?.id !== x.id) + ); + + htmlElement.querySelectorAll('.leader-change-input').forEach(element => { + autocomplete({ + input: element, + fetch: function (text, update) { + if (!text) { + update(leaderChoices); + } else { + text = text.toLowerCase(); + var suggestions = leaderChoices.filter(n => n.name.toLowerCase().includes(text)); + update(suggestions); + } + }, + render: function (actor, search) { + const actorName = game.i18n.localize(actor.name); + const matchIndex = actorName.toLowerCase().indexOf(search); + + const beforeText = actorName.slice(0, matchIndex); + const matchText = actorName.slice(matchIndex, matchIndex + search.length); + const after = actorName.slice(matchIndex + search.length, actorName.length); + const img = document.createElement('img'); + img.src = actor.img; + + const element = document.createElement('li'); + element.appendChild(img); + + const label = document.createElement('span'); + label.innerHTML = + `${beforeText}${matchText ? `${matchText}` : ''}${after}`.replaceAll( + ' ', + ' ' + ); + element.appendChild(label); + + return element; + }, + renderGroup: function (label) { + const itemElement = document.createElement('div'); + itemElement.textContent = game.i18n.localize(label); + return itemElement; + }, + onSelect: actor => { + element.value = actor.uuid; + this.actorLeader = { actor: actor, trait: 'agility', difficulty: 0 }; + this.render(); + }, + click: e => e.fetch(), + customize: function (_input, _inputRect, container) { + container.style.zIndex = foundry.applications.api.ApplicationV2._maxZ; + }, + minLength: 0 + }); + }); + + htmlElement.querySelectorAll('.team-push-input').forEach(element => { + autocomplete({ + input: element, + fetch: function (text, update) { + if (!text) { + update(memberChoices); + } else { + text = text.toLowerCase(); + var suggestions = memberChoices.filter(n => n.name.toLowerCase().includes(text)); + update(suggestions); + } + }, + render: function (actor, search) { + const actorName = game.i18n.localize(actor.name); + const matchIndex = actorName.toLowerCase().indexOf(search); + + const beforeText = actorName.slice(0, matchIndex); + const matchText = actorName.slice(matchIndex, matchIndex + search.length); + const after = actorName.slice(matchIndex + search.length, actorName.length); + const img = document.createElement('img'); + img.src = actor.img; + + const element = document.createElement('li'); + element.appendChild(img); + + const label = document.createElement('span'); + label.innerHTML = + `${beforeText}${matchText ? `${matchText}` : ''}${after}`.replaceAll( + ' ', + ' ' + ); + element.appendChild(label); + + return element; + }, + renderGroup: function (label) { + const itemElement = document.createElement('div'); + itemElement.textContent = game.i18n.localize(label); + return itemElement; + }, + onSelect: actor => { + element.value = actor.uuid; + this.actorsMembers.push({ actor: actor, trait: 'agility', difficulty: 0 }); + this.render({ force: true }); + }, + click: e => e.fetch(), + customize: function (_input, _inputRect, container) { + container.style.zIndex = foundry.applications.api.ApplicationV2._maxZ; + }, + minLength: 0 + }); + }); + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.leader = this.actorLeader; + context.members = this.actorsMembers; + context.traitList = abilities; + + context.allSelected = this.actorsMembers.length + (this.actorLeader?.actor ? 1 : 0) === this.actors.length; + context.rollDisabled = context.members.length === 0 || !this.actorLeader?.actor; + + return context; + } + + static updateData(event, _, formData) { + const { actorLeader, actorsMembers } = foundry.utils.expandObject(formData.object); + this.actorLeader = foundry.utils.mergeObject(this.actorLeader, actorLeader); + this.actorsMembers = foundry.utils.mergeObject(this.actorsMembers, actorsMembers); + this.render(true); + } + + static async #removeLeader(_, button) { + this.actorLeader = null; + this.render(); + } + + static async #removeMember(_, button) { + this.actorsMembers = this.actorsMembers.filter(m => m.actor.uuid !== button.dataset.memberUuid); + this.render(); + } + + static async #roll() { + const cls = getDocumentClass('ChatMessage'); + const systemData = { + leader: this.actorLeader, + members: this.actorsMembers + }; + const msg = { + type: 'groupRoll', + user: game.user.id, + speaker: cls.getSpeaker(), + title: game.i18n.localize('DAGGERHEART.UI.Chat.groupRoll.title'), + system: systemData, + content: await foundry.applications.handlebars.renderTemplate( + 'systems/daggerheart/templates/ui/chat/groupRoll.hbs', + { system: systemData } + ) + }; + + cls.create(msg); + this.close(); + } +} diff --git a/module/applications/dialogs/groupRollDialog.mjs b/module/applications/dialogs/groupRollDialog.mjs deleted file mode 100644 index 7196d848..00000000 --- a/module/applications/dialogs/groupRollDialog.mjs +++ /dev/null @@ -1,500 +0,0 @@ -import { ResourceUpdateMap } from '../../data/action/baseAction.mjs'; -import { emitGMUpdate, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; -import Party from '../sheets/actors/party.mjs'; - -const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; - -export default class GroupRollDialog extends HandlebarsApplicationMixin(ApplicationV2) { - constructor(party) { - super({ id: `GroupRollDialog-${party.id}` }); - - this.party = party; - this.partyMembers = party.system.partyMembers - .filter(x => Party.DICE_ROLL_ACTOR_TYPES.includes(x.type)) - .map(member => ({ - ...member.toObject(), - uuid: member.uuid, - id: member.id, - selected: true, - owned: member.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) - })); - - this.leader = null; - this.openForAllPlayers = true; - - this.tabGroups.application = Object.keys(party.system.groupRoll.participants).length - ? 'groupRoll' - : 'initialization'; - - Hooks.on(socketEvent.Refresh, this.groupRollRefresh.bind()); - } - - get title() { - return game.i18n.localize('DAGGERHEART.APPLICATIONS.GroupRollSelect.title'); - } - - static DEFAULT_OPTIONS = { - tag: 'form', - classes: ['daggerheart', 'views', 'dh-style', 'dialog', 'group-roll-dialog'], - position: { width: 390, height: 'auto' }, - window: { - icon: 'fa-solid fa-users' - }, - actions: { - toggleSelectMember: this.#toggleSelectMember, - startGroupRoll: this.#startGroupRoll, - makeRoll: this.#makeRoll, - removeRoll: this.#removeRoll, - rerollDice: this.#rerollDice, - markSuccessful: this.#markSuccessful, - cancelRoll: this.#onCancelRoll, - finishRoll: this.#finishRoll - }, - form: { handler: this.updateData, submitOnChange: true, closeOnSubmit: false } - }; - - static PARTS = { - initialization: { - id: 'initialization', - template: 'systems/daggerheart/templates/dialogs/groupRollDialog/initialization.hbs' - }, - main: { - id: 'main', - template: 'systems/daggerheart/templates/dialogs/groupRollDialog/main.hbs' - }, - leader: { - id: 'leader', - template: 'systems/daggerheart/templates/dialogs/groupRollDialog/parts/member.hbs' - }, - result: { - id: 'result', - template: 'systems/daggerheart/templates/dialogs/groupRollDialog/parts/result.hbs' - }, - footer: { - id: 'footer', - template: 'systems/daggerheart/templates/dialogs/groupRollDialog/parts/footer.hbs' - } - }; - - /** @inheritdoc */ - static TABS = { - application: { - tabs: [{ id: 'initialization' }, { id: 'groupRoll' }] - } - }; - - _attachPartListeners(partId, htmlElement, options) { - super._attachPartListeners(partId, htmlElement, options); - - htmlElement - .querySelector('.main-character-field') - ?.addEventListener('input', this.updateLeaderField.bind(this)); - } - - _configureRenderParts(options) { - const parts = super._configureRenderParts(options); - for (const memberKey of Object.keys(this.party.system.groupRoll.aidingCharacters)) { - parts[memberKey] = { - id: memberKey, - template: 'systems/daggerheart/templates/dialogs/groupRollDialog/parts/member.hbs' - }; - } - return parts; - } - - async _prepareContext(_options) { - const context = await super._prepareContext(_options); - - context.isGM = game.user.isGM; - context.isEditable = - game.user.isGM || - this.party.system.partyMembers.some(actor => { - const selected = Boolean(this.party.system.groupRoll.participants[actor.id]); - return selected && actor.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER); - }); - context.fields = this.party.system.schema.fields.groupRoll.fields; - context.data = this.party.system.groupRoll; - context.traitOptions = CONFIG.DH.ACTOR.abilities; - context.members = {}; - context.aidKeys = Object.keys(this.party.system.groupRoll.aidingCharacters); - context.allHaveRolled = Object.keys(context.data.participants).every(key => { - const data = context.data.participants[key]; - return Boolean(data.rollData); - }); - - return context; - } - - async _preparePartContext(partId, context, options) { - const partContext = await super._preparePartContext(partId, context, options); - partContext.partId = partId; - partContext.leader = this.getRollCharacterData(this.party.system.groupRoll.leader); - - switch (partId) { - case 'initialization': - partContext.groupRollFields = this.party.system.schema.fields.groupRoll.fields; - partContext.memberSelection = this.partyMembers; - - const selectedMembers = partContext.memberSelection.filter(x => x.selected); - - partContext.selectedLeader = this.leader; - partContext.selectedLeaderOptions = selectedMembers - .filter(actor => actor.owned) - .map(x => ({ value: x.id, label: x.name })); - partContext.selectedLeaderDisabled = !selectedMembers.length; - - partContext.canStartGroupRoll = selectedMembers.length > 1 && this.leader?.memberId; - partContext.openForAllPlayers = this.openForAllPlayers; - break; - case 'result': - const leader = this.party.system.groupRoll.leader; - partContext.hasRolled = - leader?.rollData || - Object.values(this.party.system.groupRoll?.aidingCharacters ?? {}).some(x => x.successful !== null); - const { modifierTotal, modifiers } = Object.values(this.party.system.groupRoll.aidingCharacters).reduce( - (acc, curr) => { - const modifier = curr.successful === true ? 1 : curr.successful === false ? -1 : null; - if (modifier) { - acc.modifierTotal += modifier; - acc.modifiers.push(modifier); - } - - return acc; - }, - { modifierTotal: 0, modifiers: [] } - ); - const leaderTotal = leader?.rollData ? leader.roll.total : null; - partContext.groupRoll = { - totalLabel: leader?.rollData - ? game.i18n.format('DAGGERHEART.GENERAL.withThing', { - thing: leader.roll.totalLabel - }) - : null, - totalDualityClass: leader?.roll?.isCritical ? 'critical' : leader?.roll?.withHope ? 'hope' : 'fear', - total: leaderTotal + modifierTotal, - leaderTotal: leaderTotal, - modifiers - }; - break; - case 'footer': - partContext.canFinishRoll = - Boolean(this.party.system.groupRoll.leader?.rollData) && - Object.values(this.party.system.groupRoll.aidingCharacters).every(x => x.successful !== null); - break; - } - - if (Object.keys(this.party.system.groupRoll.aidingCharacters).includes(partId)) { - const characterData = this.party.system.groupRoll.aidingCharacters[partId]; - partContext.members[partId] = this.getRollCharacterData(characterData, partId); - } - - return partContext; - } - - getRollCharacterData(data, partId) { - if (!data) return {}; - - const actor = game.actors.get(data.id); - const isLeader = data === this.party.system.groupRoll.leader; - - const roll = data.roll; - const withTypeSuffix = !roll ? null : roll.isCritical ? 'criticalShort' : roll.withHope ? 'hope' : 'fear'; - const thing = withTypeSuffix ? _loc(`DAGGERHEART.GENERAL.${withTypeSuffix}`) : null; - - return { - ...data, - type: isLeader ? 'leader' : 'aid', - basePath: isLeader ? 'system.groupRoll.leader' : `system.groupRoll.aidingCharacters.${data.id}`, - rollChoiceLabel: _loc(CONFIG.DH.ACTOR.abilities[data.rollChoice]?.label), - roll: data.roll, - isEditable: actor?.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER), - key: partId, - readyToRoll: Boolean(data.rollChoice), - hasRolled: Boolean(data.rollData), - modifier: data.successful ? 1 : data.successful === false ? -1 : 0, - withLabelShort: thing ? _loc('DAGGERHEART.GENERAL.withThing', { thing }) : null - }; - } - - #getCharacterDataById(id) { - if (!id) return null; - - const groupRoll = this.party.system.groupRoll; - if (id === 'leader' || id === groupRoll.leader?.id) { - return { data: groupRoll.leader, basePath: 'system.groupRoll.leader' }; - } else if (id in groupRoll.aidingCharacters) { - return { data: groupRoll.aidingCharacters[id], basePath: `system.groupRoll.aidingCharacters.${id}` }; - } - - return null; - } - - static async updateData(event, _, formData) { - const partyData = foundry.utils.expandObject(formData.object); - this.updatePartyData(partyData, this.getUpdatingParts(event.target)); - } - - async updatePartyData(update, updatingParts, options = { render: true }) { - if (!game.users.activeGM) - return ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.gmRequired')); - - const gmUpdate = async update => { - await this.party.update(update); - this.render({ parts: updatingParts }); - game.socket.emit(`system.${CONFIG.DH.id}`, { - action: socketEvent.Refresh, - data: { refreshType: RefreshType.GroupRoll, action: 'refresh', parts: updatingParts } - }); - }; - - await emitGMUpdate( - GMUpdateEvent.UpdateDocument, - gmUpdate, - update, - this.party.uuid, - options.render ? { refreshType: RefreshType.GroupRoll, action: 'refresh', parts: updatingParts } : undefined - ); - } - - getUpdatingParts(target) { - const { initialization, leader, result, footer } = this.constructor.PARTS; - const isInitialization = this.tabGroups.application === initialization.id; - const updatingMember = target.closest('.member-roll-container.aid')?.dataset?.memberKey; - const updatingLeader = target.closest('.member-roll-container.leader'); - - return [ - ...(isInitialization ? [initialization.id] : []), - ...(updatingMember ? [updatingMember] : []), - ...(updatingLeader ? [leader.id] : []), - ...(!isInitialization ? [result.id, footer.id] : []) - ]; - } - - groupRollRefresh = ({ refreshType, action, parts }) => { - if (refreshType !== RefreshType.GroupRoll) return; - - switch (action) { - case 'startGroupRoll': - this.tabGroups.application = 'groupRoll'; - break; - case 'refresh': - this.render({ parts }); - break; - case 'close': - this.close(); - break; - } - }; - - async close(options = {}) { - /* Opt out of Foundry's standard behavior of closing all application windows marked as UI when Escape is pressed */ - if (options.closeKey) return; - - Hooks.off(socketEvent.Refresh, this.groupRollRefresh); - return super.close(options); - } - - //#region Initialization - static #toggleSelectMember(_, button) { - const member = this.partyMembers.find(x => x.id === button.dataset.id); - member.selected = !member.selected; - if (this.leader?.memberId === member.id) { - this.leader = null; - } - this.render(); - } - - updateLeaderField(event) { - if (!this.leader) this.leader = {}; - this.leader.memberId = event.target.value; - this.render(); - } - - static async #startGroupRoll() { - const leader = this.partyMembers.find(x => x.id === this.leader.memberId); - const aidingCharacters = this.partyMembers.reduce((acc, curr) => { - if (curr.selected && curr.id !== this.leader.memberId) - acc[curr.id] = { id: curr.id, name: curr.name, img: curr.img }; - - return acc; - }, {}); - - await this.party.update({ - 'system.groupRoll': _replace( - new game.system.api.data.GroupRollData({ - ...this.party.system.groupRoll.toObject(), - leader: { id: leader.id, name: leader.name, img: leader.img }, - aidingCharacters - }) - ) - }); - - const hookData = { openForAllPlayers: this.openForAllPlayers, partyId: this.party.id }; - Hooks.callAll(CONFIG.DH.HOOKS.hooksConfig.groupRollStart, hookData); - game.socket.emit(`system.${CONFIG.DH.id}`, { - action: socketEvent.GroupRollStart, - data: hookData - }); - - this.render(); - } - //#endregion - - /** @this GroupRollDialog */ - static async #makeRoll(_event, button) { - const member = button.closest('[data-member-key]').dataset.memberKey; - const { data, basePath } = this.#getCharacterDataById(member); - const actor = game.actors.find(x => x.id === data.id); - if (!actor) return; - - const result = await actor.rollTrait(data.rollChoice, { - skips: { - createMessage: true, - resources: true, - triggers: true - } - }); - - if (!result) return; - - const rollData = result.messageRoll.toJSON(); - delete rollData.options.messageRoll; - this.updatePartyData( - { - [basePath]: { rollData, successful: null } - }, - this.getUpdatingParts(button) - ); - } - - /** @this GroupRollDialog */ - static async #removeRoll(_event, button) { - const member = button.closest('[data-member-key]').dataset.memberKey; - const { basePath } = this.#getCharacterDataById(member); - this.updatePartyData( - { - [basePath]: { - rollData: null, - rollChoice: null, - selected: false, - successful: null - } - }, - this.getUpdatingParts(button) - ); - } - - /** @this GroupRollDialog */ - static async #rerollDice(_, button) { - const { diceType } = button.dataset; - const { data, basePath } = this.#getCharacterDataById(button.dataset.member); - - const dieIndex = diceType === 'hope' ? 0 : diceType === 'fear' ? 1 : 2; - const newRoll = game.system.api.dice.DualityRoll.fromData(data.rollData); - const dice = newRoll.dice[dieIndex]; - await dice.reroll(`/r1=${dice.total}`, { - liveRoll: { - roll: newRoll, - isReaction: true - } - }); - const rollData = newRoll.toJSON(); - this.updatePartyData( - { - [`${basePath}.rollData`]: rollData - }, - this.getUpdatingParts(button) - ); - } - - static #markSuccessful(_event, button) { - const memberKey = button.closest('[data-member-key]').dataset.memberKey; - const previousValue = this.party.system.groupRoll.aidingCharacters[memberKey].successful; - const newValue = Boolean(button.dataset.success === 'true'); - this.updatePartyData( - { - [`system.groupRoll.aidingCharacters.${memberKey}.successful`]: - previousValue === newValue ? null : newValue - }, - this.getUpdatingParts(button) - ); - } - - static async #onCancelRoll(_event, _button, options = { confirm: true }) { - this.cancelRoll(options); - } - - async cancelRoll(options = { confirm: true }) { - if (options.confirm) { - const confirmed = await foundry.applications.api.DialogV2.confirm({ - window: { - title: game.i18n.localize('DAGGERHEART.APPLICATIONS.GroupRollSelect.cancelConfirmTitle') - }, - content: game.i18n.localize('DAGGERHEART.APPLICATIONS.GroupRollSelect.cancelConfirmText') - }); - - if (!confirmed) return; - } - - await this.updatePartyData( - { - 'system.groupRoll': { - leader: null, - aidingCharacters: _replace({}) - } - }, - [], - { render: false } - ); - - this.close(); - game.socket.emit(`system.${CONFIG.DH.id}`, { - action: socketEvent.Refresh, - data: { refreshType: RefreshType.GroupRoll, action: 'close' } - }); - } - - static async #finishRoll() { - const totalRoll = this.party.system.groupRoll.leader.roll; - for (const character of Object.values(this.party.system.groupRoll.aidingCharacters)) { - totalRoll.terms.push(new foundry.dice.terms.OperatorTerm({ operator: character.successful ? '+' : '-' })); - totalRoll.terms.push(new foundry.dice.terms.NumericTerm({ number: 1 })); - } - - await totalRoll._evaluate(); - - const systemData = totalRoll.options; - const actor = game.actors.get(this.party.system.groupRoll.leader.id); - - const cls = getDocumentClass('ChatMessage'), - msgData = { - type: 'dualityRoll', - user: game.user.id, - title: game.i18n.localize('DAGGERHEART.APPLICATIONS.GroupRollSelect.title'), - speaker: cls.getSpeaker({ actor }), - system: systemData, - rolls: [JSON.stringify(totalRoll)], - sound: null, - flags: { core: { RollTable: true } } - }; - - await cls.create(msgData); - - const resourceMap = new ResourceUpdateMap(actor); - if (totalRoll.isCritical) { - resourceMap.addResources([ - { key: 'stress', value: -1, total: 1 }, - { key: 'hope', value: 1, total: 1 } - ]); - } else if (totalRoll.withHope) { - resourceMap.addResources([{ key: 'hope', value: 1, total: 1 }]); - } else { - resourceMap.addResources([{ key: 'fear', value: 1, total: 1 }]); - } - - resourceMap.updateResources(); - - /* Fin */ - this.cancelRoll({ confirm: false }); - } -} diff --git a/module/applications/dialogs/itemTransfer.mjs b/module/applications/dialogs/itemTransfer.mjs index 42e3a727..ad3cf103 100644 --- a/module/applications/dialogs/itemTransfer.mjs +++ b/module/applications/dialogs/itemTransfer.mjs @@ -38,15 +38,13 @@ export default class ItemTransferDialog extends HandlebarsApplicationMixin(Appli originActor ??= item?.actor; const homebrewKey = CONFIG.DH.SETTINGS.gameSettings.Homebrew; const currencySetting = game.settings.get(CONFIG.DH.id, homebrewKey).currency?.[currency] ?? null; - const max = item?.system.quantity ?? originActor.system.gold[currency] ?? 0; return { originActor, targetActor, itemImage: item?.img, currencyIcon: currencySetting?.icon, - max, - initial: targetActor.system.metadata.quantifiable?.includes(item.type) ? max : 1, + max: item?.system.quantity ?? originActor.system.gold[currency] ?? 0, title: item?.name ?? currencySetting?.label }; } diff --git a/module/applications/dialogs/rerollDamageDialog.mjs b/module/applications/dialogs/rerollDamageDialog.mjs new file mode 100644 index 00000000..e1b75eb7 --- /dev/null +++ b/module/applications/dialogs/rerollDamageDialog.mjs @@ -0,0 +1,290 @@ +import { RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; + +const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; + +export default class RerollDamageDialog extends HandlebarsApplicationMixin(ApplicationV2) { + constructor(message, options = {}) { + super(options); + + this.message = message; + this.damage = Object.keys(message.system.damage).reduce((acc, typeKey) => { + const type = message.system.damage[typeKey]; + acc[typeKey] = Object.keys(type.parts).reduce((acc, partKey) => { + const part = type.parts[partKey]; + acc[partKey] = Object.keys(part.dice).reduce((acc, diceKey) => { + const dice = part.dice[diceKey]; + const activeResults = dice.results.filter(x => x.active); + acc[diceKey] = { + dice: dice.dice, + selectedResults: activeResults.length, + maxSelected: activeResults.length, + results: activeResults.map(x => ({ ...x, selected: true })) + }; + + return acc; + }, {}); + + return acc; + }, {}); + + return acc; + }, {}); + } + + static DEFAULT_OPTIONS = { + id: 'reroll-dialog', + classes: ['daggerheart', 'dialog', 'dh-style', 'views', 'reroll-dialog'], + window: { + icon: 'fa-solid fa-dice' + }, + actions: { + toggleResult: RerollDamageDialog.#toggleResult, + selectRoll: RerollDamageDialog.#selectRoll, + doReroll: RerollDamageDialog.#doReroll, + save: RerollDamageDialog.#save + } + }; + + /** @override */ + static PARTS = { + main: { + id: 'main', + template: 'systems/daggerheart/templates/dialogs/rerollDialog/damage/main.hbs' + }, + footer: { + id: 'footer', + template: 'systems/daggerheart/templates/dialogs/rerollDialog/footer.hbs' + } + }; + + get title() { + return game.i18n.localize('DAGGERHEART.APPLICATIONS.RerollDialog.damageTitle'); + } + + _attachPartListeners(partId, htmlElement, options) { + super._attachPartListeners(partId, htmlElement, options); + + htmlElement.querySelectorAll('.to-reroll-input').forEach(element => { + element.addEventListener('change', this.toggleDice.bind(this)); + }); + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.damage = this.damage; + context.disabledReroll = !this.getRerollDice().length; + context.saveDisabled = !this.isSelectionDone(); + + return context; + } + + static async #save() { + const update = { + 'system.damage': Object.keys(this.damage).reduce((acc, typeKey) => { + const type = this.damage[typeKey]; + let typeTotal = 0; + const messageType = this.message.system.damage[typeKey]; + const parts = Object.keys(type).map(partKey => { + const part = type[partKey]; + const messagePart = messageType.parts[partKey]; + let partTotal = messagePart.modifierTotal; + const dice = Object.keys(part).map(diceKey => { + const dice = part[diceKey]; + const total = dice.results.reduce((acc, result) => { + if (result.active) acc += result.result; + return acc; + }, 0); + partTotal += total; + const messageDice = messagePart.dice[diceKey]; + return { + ...messageDice, + total: total, + results: dice.results.map(x => ({ + ...x, + hasRerolls: dice.results.length > 1 + })) + }; + }); + + typeTotal += partTotal; + return { + ...messagePart, + total: partTotal, + dice: dice + }; + }); + + acc[typeKey] = { + ...messageType, + total: typeTotal, + parts: parts + }; + + return acc; + }, {}) + }; + await this.message.update(update); + + Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.TagTeamRoll }); + await game.socket.emit(`system.${CONFIG.DH.id}`, { + action: socketEvent.Refresh, + data: { + refreshType: RefreshType.TagTeamRoll + } + }); + + await this.close(); + } + + getRerollDice() { + const rerollDice = []; + Object.keys(this.damage).forEach(typeKey => { + const type = this.damage[typeKey]; + Object.keys(type).forEach(partKey => { + const part = type[partKey]; + Object.keys(part).forEach(diceKey => { + const dice = part[diceKey]; + Object.keys(dice.results).forEach(resultKey => { + const result = dice.results[resultKey]; + if (result.toReroll) { + rerollDice.push({ + ...result, + dice: dice.dice, + type: typeKey, + part: partKey, + dice: diceKey, + result: resultKey + }); + } + }); + }); + }); + }); + + return rerollDice; + } + + isSelectionDone() { + const diceFinishedData = []; + Object.keys(this.damage).forEach(typeKey => { + const type = this.damage[typeKey]; + Object.keys(type).forEach(partKey => { + const part = type[partKey]; + Object.keys(part).forEach(diceKey => { + const dice = part[diceKey]; + const selected = dice.results.reduce((acc, result) => acc + (result.active ? 1 : 0), 0); + diceFinishedData.push(selected === dice.maxSelected); + }); + }); + }); + + return diceFinishedData.every(x => x); + } + + toggleDice(event) { + const target = event.target; + const { type, part, dice } = target.dataset; + const toggleDice = this.damage[type][part][dice]; + + const existingDiceRerolls = this.getRerollDice().filter( + x => x.type === type && x.part === part && x.dice === dice + ); + + const allRerolled = existingDiceRerolls.length === toggleDice.results.filter(x => x.active).length; + + toggleDice.toReroll = !allRerolled; + toggleDice.results.forEach(result => { + if (result.active) { + result.toReroll = !allRerolled; + } + }); + + this.render(); + } + + static #toggleResult(event) { + event.stopPropagation(); + + const target = event.target.closest('.to-reroll-result'); + const { type, part, dice, result } = target.dataset; + const toggleDice = this.damage[type][part][dice]; + const toggleResult = toggleDice.results[result]; + toggleResult.toReroll = !toggleResult.toReroll; + + const existingDiceRerolls = this.getRerollDice().filter( + x => x.type === type && x.part === part && x.dice === dice + ); + + const allToReroll = existingDiceRerolls.length === toggleDice.results.filter(x => x.active).length; + toggleDice.toReroll = allToReroll; + + this.render(); + } + + static async #selectRoll(_, button) { + const { type, part, dice, result } = button.dataset; + + const diceVal = this.damage[type][part][dice]; + const diceResult = diceVal.results[result]; + if (!diceResult.active && diceVal.results.filter(x => x.active).length === diceVal.maxSelected) { + return ui.notifications.warn( + game.i18n.localize('DAGGERHEART.APPLICATIONS.RerollDialog.deselectDiceNotification') + ); + } + + if (diceResult.active) { + diceVal.toReroll = false; + diceResult.toReroll = false; + } + + diceVal.selectedResults += diceResult.active ? -1 : 1; + diceResult.active = !diceResult.active; + + this.render(); + } + + static async #doReroll() { + const toReroll = this.getRerollDice().map(x => { + const { type, part, dice, result } = x; + const diceData = this.damage[type][part][dice].results[result]; + return { + ...diceData, + dice: this.damage[type][part][dice].dice, + typeKey: type, + partKey: part, + diceKey: dice, + resultsIndex: result + }; + }); + + const roll = await new Roll(toReroll.map(x => `1${x.dice}`).join(' + ')).evaluate(); + + if (game.modules.get('dice-so-nice')?.active) { + const diceSoNiceRoll = { + _evaluated: true, + dice: roll.dice, + options: { appearance: {} } + }; + + await game.dice3d.showForRoll(diceSoNiceRoll, game.user, true); + } + + toReroll.forEach((data, index) => { + const { typeKey, partKey, diceKey, resultsIndex } = data; + const rerolledDice = roll.dice[index]; + + const dice = this.damage[typeKey][partKey][diceKey]; + dice.toReroll = false; + dice.results[resultsIndex].active = false; + dice.results[resultsIndex].discarded = true; + dice.results[resultsIndex].toReroll = false; + dice.results.splice(dice.results.length, 0, { + ...rerolledDice.results[0], + toReroll: false, + selected: true + }); + }); + + this.render(); + } +} diff --git a/module/applications/dialogs/rerollDialog.mjs b/module/applications/dialogs/rerollDialog.mjs new file mode 100644 index 00000000..cae4e53a --- /dev/null +++ b/module/applications/dialogs/rerollDialog.mjs @@ -0,0 +1,279 @@ +const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; + +export default class RerollDialog extends HandlebarsApplicationMixin(ApplicationV2) { + constructor(message, options = {}) { + super(options); + + this.message = message; + this.damage = Object.keys(message.system.damage).reduce((acc, typeKey) => { + const type = message.system.damage[typeKey]; + acc[typeKey] = Object.keys(type.parts).reduce((acc, partKey) => { + const part = type.parts[partKey]; + acc[partKey] = Object.keys(part.dice).reduce((acc, diceKey) => { + const dice = part.dice[diceKey]; + const activeResults = dice.results.filter(x => x.active); + acc[diceKey] = { + dice: dice.dice, + selectedResults: activeResults.length, + maxSelected: activeResults.length, + results: activeResults.map(x => ({ ...x, selected: true })) + }; + + return acc; + }, {}); + + return acc; + }, {}); + + return acc; + }, {}); + } + + static DEFAULT_OPTIONS = { + id: 'reroll-dialog', + classes: ['daggerheart', 'dialog', 'dh-style', 'views', 'reroll-dialog'], + window: { + icon: 'fa-solid fa-dice' + }, + actions: { + toggleResult: RerollDialog.#toggleResult, + selectRoll: RerollDialog.#selectRoll, + doReroll: RerollDialog.#doReroll, + save: RerollDialog.#save + } + }; + + /** @override */ + static PARTS = { + main: { + id: 'main', + template: 'systems/daggerheart/templates/dialogs/rerollDialog/main.hbs' + }, + footer: { + id: 'footer', + template: 'systems/daggerheart/templates/dialogs/rerollDialog/footer.hbs' + } + }; + + get title() { + return game.i18n.localize('DAGGERHEART.APPLICATIONS.RerollDialog.title'); + } + + _attachPartListeners(partId, htmlElement, options) { + super._attachPartListeners(partId, htmlElement, options); + + htmlElement.querySelectorAll('.to-reroll-input').forEach(element => { + element.addEventListener('change', this.toggleDice.bind(this)); + }); + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.damage = this.damage; + context.disabledReroll = !this.getRerollDice().length; + context.saveDisabled = !this.isSelectionDone(); + + return context; + } + + static async #save() { + const update = { + 'system.damage': Object.keys(this.damage).reduce((acc, typeKey) => { + const type = this.damage[typeKey]; + let typeTotal = 0; + const messageType = this.message.system.damage[typeKey]; + const parts = Object.keys(type).map(partKey => { + const part = type[partKey]; + const messagePart = messageType.parts[partKey]; + let partTotal = messagePart.modifierTotal; + const dice = Object.keys(part).map(diceKey => { + const dice = part[diceKey]; + const total = dice.results.reduce((acc, result) => { + if (result.active) acc += result.result; + return acc; + }, 0); + partTotal += total; + const messageDice = messagePart.dice[diceKey]; + return { + ...messageDice, + total: total, + results: dice.results.map(x => ({ + ...x, + hasRerolls: dice.results.length > 1 + })) + }; + }); + + typeTotal += partTotal; + return { + ...messagePart, + total: partTotal, + dice: dice + }; + }); + + acc[typeKey] = { + ...messageType, + total: typeTotal, + parts: parts + }; + + return acc; + }, {}) + }; + await this.message.update(update); + await this.close(); + } + + getRerollDice() { + const rerollDice = []; + Object.keys(this.damage).forEach(typeKey => { + const type = this.damage[typeKey]; + Object.keys(type).forEach(partKey => { + const part = type[partKey]; + Object.keys(part).forEach(diceKey => { + const dice = part[diceKey]; + Object.keys(dice.results).forEach(resultKey => { + const result = dice.results[resultKey]; + if (result.toReroll) { + rerollDice.push({ + ...result, + dice: dice.dice, + type: typeKey, + part: partKey, + dice: diceKey, + result: resultKey + }); + } + }); + }); + }); + }); + + return rerollDice; + } + + isSelectionDone() { + const diceFinishedData = []; + Object.keys(this.damage).forEach(typeKey => { + const type = this.damage[typeKey]; + Object.keys(type).forEach(partKey => { + const part = type[partKey]; + Object.keys(part).forEach(diceKey => { + const dice = part[diceKey]; + const selected = dice.results.reduce((acc, result) => acc + (result.active ? 1 : 0), 0); + diceFinishedData.push(selected === dice.maxSelected); + }); + }); + }); + + return diceFinishedData.every(x => x); + } + + toggleDice(event) { + const target = event.target; + const { type, part, dice } = target.dataset; + const toggleDice = this.damage[type][part][dice]; + + const existingDiceRerolls = this.getRerollDice().filter( + x => x.type === type && x.part === part && x.dice === dice + ); + + const allRerolled = existingDiceRerolls.length === toggleDice.results.filter(x => x.active).length; + + toggleDice.toReroll = !allRerolled; + toggleDice.results.forEach(result => { + if (result.active) { + result.toReroll = !allRerolled; + } + }); + + this.render(); + } + + static #toggleResult(event) { + event.stopPropagation(); + + const target = event.target.closest('.to-reroll-result'); + const { type, part, dice, result } = target.dataset; + const toggleDice = this.damage[type][part][dice]; + const toggleResult = toggleDice.results[result]; + toggleResult.toReroll = !toggleResult.toReroll; + + const existingDiceRerolls = this.getRerollDice().filter( + x => x.type === type && x.part === part && x.dice === dice + ); + + const allToReroll = existingDiceRerolls.length === toggleDice.results.length; + toggleDice.toReroll = allToReroll; + + this.render(); + } + + static async #selectRoll(_, button) { + const { type, part, dice, result } = button.dataset; + + const diceVal = this.damage[type][part][dice]; + const diceResult = diceVal.results[result]; + if (!diceResult.active && diceVal.results.filter(x => x.active).length === diceVal.maxSelected) { + return ui.notifications.warn( + game.i18n.localize('DAGGERHEART.APPLICATIONS.RerollDialog.deselectDiceNotification') + ); + } + + if (diceResult.active) { + diceVal.toReroll = false; + diceResult.toReroll = false; + } + + diceVal.selectedResults += diceResult.active ? -1 : 1; + diceResult.active = !diceResult.active; + + this.render(); + } + + static async #doReroll() { + const toReroll = this.getRerollDice().map(x => { + const { type, part, dice, result } = x; + const diceData = this.damage[type][part][dice].results[result]; + return { + ...diceData, + dice: this.damage[type][part][dice].dice, + typeKey: type, + partKey: part, + diceKey: dice, + resultsIndex: result + }; + }); + + const roll = await new Roll(toReroll.map(x => `1${x.dice}`).join(' + ')).evaluate(); + + if (game.modules.get('dice-so-nice')?.active) { + const diceSoNiceRoll = { + _evaluated: true, + dice: roll.dice, + options: { appearance: {} } + }; + + await game.dice3d.showForRoll(diceSoNiceRoll, game.user, true); + } + + toReroll.forEach((data, index) => { + const { typeKey, partKey, diceKey, resultsIndex } = data; + const rerolledDice = roll.dice[index]; + + const dice = this.damage[typeKey][partKey][diceKey]; + dice.toReroll = false; + dice.results[resultsIndex].active = false; + dice.results[resultsIndex].discarded = true; + dice.results[resultsIndex].toReroll = false; + dice.results.splice(dice.results.length, 0, { + ...rerolledDice.results[0], + toReroll: false, + selected: true + }); + }); + + this.render(); + } +} diff --git a/module/applications/dialogs/resourceDiceDialog.mjs b/module/applications/dialogs/resourceDiceDialog.mjs index 8394538c..32e1e5d8 100644 --- a/module/applications/dialogs/resourceDiceDialog.mjs +++ b/module/applications/dialogs/resourceDiceDialog.mjs @@ -1,4 +1,4 @@ -import { itemAbleRollParse, triggerChatRollFx } from '../../helpers/utils.mjs'; +import { itemAbleRollParse } from '../../helpers/utils.mjs'; const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; @@ -69,7 +69,7 @@ export default class ResourceDiceDialog extends HandlebarsApplicationMixin(Appli const max = itemAbleRollParse(this.item.system.resource.max, this.actor, this.item); const diceFormula = `${max}${this.item.system.resource.dieFaces}`; const roll = await new Roll(diceFormula).evaluate(); - await triggerChatRollFx([roll]); + if (game.modules.get('dice-so-nice')?.active) await game.dice3d.showForRoll(roll, game.user, true); this.rollValues = roll.terms[0].results.map(x => ({ value: x.result, used: false })); this.resetUsed = true; diff --git a/module/applications/dialogs/tagTeamDialog.mjs b/module/applications/dialogs/tagTeamDialog.mjs index b2ce0258..d1a1e123 100644 --- a/module/applications/dialogs/tagTeamDialog.mjs +++ b/module/applications/dialogs/tagTeamDialog.mjs @@ -1,33 +1,21 @@ -import { MemberData } from '../../data/tagTeamData.mjs'; import { getCritDamageBonus } from '../../helpers/utils.mjs'; -import { emitGMUpdate, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; -import Party from '../sheets/actors/party.mjs'; +import { GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; export default class TagTeamDialog extends HandlebarsApplicationMixin(ApplicationV2) { constructor(party) { - super({ id: `TagTeamDialog-${party.id}` }); + super(); + this.data = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll); this.party = party; - this.partyMembers = party.system.partyMembers - .filter(x => Party.DICE_ROLL_ACTOR_TYPES.includes(x.type)) - .map(member => ({ - ...member.toObject(), - uuid: member.uuid, - id: member.id, - selected: false, - owned: member.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) - })); - this.initiator = { cost: 3 }; - this.openForAllPlayers = true; - - this.tabGroups.application = Object.keys(party.system.tagTeam.members).length - ? 'tagTeamRoll' - : 'initialization'; - - Hooks.on(socketEvent.Refresh, this.tagTeamRefresh.bind()); + this.setupHooks = Hooks.on(socketEvent.Refresh, ({ refreshType }) => { + if (refreshType === RefreshType.TagTeamRoll) { + this.data = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll); + this.render(); + } + }); } get title() { @@ -38,750 +26,322 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio tag: 'form', classes: ['daggerheart', 'views', 'dh-style', 'dialog', 'tag-team-dialog'], position: { width: 550, height: 'auto' }, - window: { - icon: 'fa-solid fa-user-group' - }, actions: { - toggleSelectMember: TagTeamDialog.#toggleSelectMember, - startTagTeamRoll: TagTeamDialog.#startTagTeamRoll, - makeRoll: TagTeamDialog.#makeRoll, - removeRoll: TagTeamDialog.#removeRoll, - rerollDice: TagTeamDialog.#rerollDice, - makeDamageRoll: TagTeamDialog.#makeDamageRoll, - removeDamageRoll: TagTeamDialog.#removeDamageRoll, - rerollDamageDice: TagTeamDialog.#rerollDamageDice, - selectRoll: TagTeamDialog.#selectRoll, - cancelRoll: TagTeamDialog.#onCancelRoll, - finishRoll: TagTeamDialog.#finishRoll + removeMember: TagTeamDialog.#removeMember, + unlinkMessage: TagTeamDialog.#unlinkMessage, + selectMessage: TagTeamDialog.#selectMessage, + createTagTeam: TagTeamDialog.#createTagTeam }, form: { handler: this.updateData, submitOnChange: true, closeOnSubmit: false } }; static PARTS = { - initialization: { - id: 'initialization', - template: 'systems/daggerheart/templates/dialogs/tagTeamDialog/initialization.hbs' - }, - tagTeamRoll: { - id: 'tagTeamRoll', - template: 'systems/daggerheart/templates/dialogs/tagTeamDialog/tagTeamRoll.hbs' - }, - rollSelection: { - id: 'rollSelection', - template: 'systems/daggerheart/templates/dialogs/tagTeamDialog/rollSelection.hbs' - }, - result: { - id: 'result', - template: 'systems/daggerheart/templates/dialogs/tagTeamDialog/result.hbs' - } - }; - - /** @inheritdoc */ - static TABS = { application: { - tabs: [{ id: 'initialization' }, { id: 'tagTeamRoll' }] + id: 'tag-team-dialog', + template: 'systems/daggerheart/templates/dialogs/tagTeamDialog.hbs' } }; - _attachPartListeners(partId, htmlElement, options) { - super._attachPartListeners(partId, htmlElement, options); - - for (const element of htmlElement.querySelectorAll('.roll-type-select')) - element.addEventListener('change', this.updateRollType.bind(this)); - - htmlElement - .querySelector('.initiator-member-field') - ?.addEventListener('input', this.updateInitiatorMemberField.bind(this)); - - htmlElement - .querySelector('.initiator-cost-field') - ?.addEventListener('input', this.updateInitiatorCostField.bind(this)); - - htmlElement - .querySelector('.openforall-field') - ?.addEventListener('change', this.updateOpenForAllField.bind(this)); - } - - _configureRenderParts(options) { - const parts = super._configureRenderParts(options); - for (const memberKey of Object.keys(this.party.system.tagTeam.members)) { - parts[memberKey] = { - id: memberKey, - template: 'systems/daggerheart/templates/dialogs/tagTeamDialog/tagTeamMember.hbs' - }; - } - - return parts; - } - async _prepareContext(_options) { const context = await super._prepareContext(_options); - context.isEditable = - game.user.isGM || - this.party.system.partyMembers.some(actor => { - const selected = Boolean(this.party.system.tagTeam.members[actor.id]); - return selected && actor.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER); - }); - context.fields = this.party.system.schema.fields.tagTeam.fields; - context.data = this.party.system.tagTeam; - context.rollTypes = CONFIG.DH.GENERAL.tagTeamRollTypes; - context.traitOptions = CONFIG.DH.ACTOR.abilities; - context.members = {}; - context.allHaveRolled = Object.keys(this.party.system.tagTeam.members).every(key => { - const data = this.party.system.tagTeam.members[key]; - const hasRolled = Boolean(data.rollData); - if (!hasRolled) return false; + context.hopeCost = this.hopeCost; + context.data = this.data; - return !data.rollData.options.hasDamage || Boolean(data.rollData.options.damage); + context.memberOptions = this.party.filter(c => !this.data.members[c.id]); + context.selectedCharacterOptions = this.party.filter(c => this.data.members[c.id]); + + context.members = Object.keys(this.data.members).map(id => { + const roll = this.data.members[id].messageId ? game.messages.get(this.data.members[id].messageId) : null; + + context.usesDamage = + context.usesDamage === undefined + ? roll?.system.hasDamage + : context.usesDamage && roll?.system.hasDamage; + return { + character: this.party.find(x => x.id === id), + selected: this.data.members[id].selected, + roll: roll, + damageValues: roll + ? Object.keys(roll.system.damage).map(key => ({ + key: key, + name: game.i18n.localize(CONFIG.DH.GENERAL.healingTypes[key].label), + total: roll.system.damage[key].total + })) + : null + }; }); - return context; - } + const initiatorChar = this.party.find(x => x.id === this.data.initiator.id); + context.initiator = { + character: initiatorChar, + cost: this.data.initiator.cost + }; - async _preparePartContext(partId, context, options) { - const partContext = await super._preparePartContext(partId, context, options); - partContext.partId = partId; - switch (partId) { - case 'initialization': - partContext.tagTeamFields = this.party.system.schema.fields.tagTeam.fields; - partContext.memberSelection = this.partyMembers; - const selectedMembers = partContext.memberSelection.filter(x => x.selected); + const selectedMember = Object.values(context.members).find(x => x.selected && x.roll); + const selectedIsCritical = selectedMember?.roll?.system?.isCritical; + context.selectedData = { + result: selectedMember + ? `${selectedMember.roll.system.roll.total} ${selectedMember.roll.system.roll.result.label}` + : null, + damageValues: null + }; - partContext.allSelected = selectedMembers.length === 2; - partContext.canStartTagTeam = - partContext.allSelected && this.initiator?.memberId && typeof this.initiator?.cost === 'number'; - partContext.initiator = this.initiator; - partContext.initiatorOptions = selectedMembers - .filter(actor => actor.owned) - .map(x => ({ value: x.id, label: x.name })); - partContext.initiatorDisabled = !selectedMembers.length; - partContext.openForAllPlayers = this.openForAllPlayers; - - break; - case 'tagTeamRoll': - partContext.memberKeys = Object.keys(this.party.system.tagTeam.members); - break; - case 'rollSelection': - partContext.members = Object.keys(this.party.system.tagTeam.members).reduce((acc, key) => { - const member = this.party.system.tagTeam.members[key]; - acc[key] = { selected: member.selected }; - return acc; - }, {}); - break; - case 'result': - const selectedRoll = Object.values(this.party.system.tagTeam.members).find(member => member.selected); - const critSelected = !selectedRoll - ? undefined - : (selectedRoll?.rollData?.options?.roll?.isCritical ?? false); - - partContext.hintText = await this.getInfoTexts(this.party.system.tagTeam.members); - partContext.joinedRoll = await this.getJoinedRoll({ - overrideIsCritical: critSelected, - displayVersion: true - }); - - break; - } - - if (Object.keys(this.party.system.tagTeam.members).includes(partId)) { - const data = await this.#prepareMemberContext(partId); - partContext.hasDamage |= Boolean(data?.damage); - partContext.members[partId] = data; - } - - return partContext; - } - - async #prepareMemberContext(partId) { - const data = this.party.system.tagTeam.members[partId] ?? {}; - const actor = game.actors.get(partId); - if (!actor) console.error(`Failed to get actor ${partId}`); - - const rollOptions = []; - const damageRollOptions = []; - for (const item of actor?.items ?? []) { - if (!item.system.metadata.hasActions) continue; - const actions = [...item.system.actions, ...(item.system.attack ? [item.system.attack] : [])]; - for (const action of actions) { - if (action.hasRoll) { - const collection = action.hasDamage ? damageRollOptions : rollOptions; - collection.push({ - value: action.uuid, - label: action.name, - group: item.name, - baseAction: action.baseAction - }); + for (const member of Object.values(context.members)) { + if (!member.roll) continue; + if (context.usesDamage) { + if (!context.selectedData.damageValues) context.selectedData.damageValues = {}; + for (let damage of member.damageValues) { + const damageTotal = member.roll.system.isCritical + ? damage.total + : selectedIsCritical + ? damage.total + (await getCritDamageBonus(member.roll.system.damage[damage.key].formula)) + : damage.total; + if (context.selectedData.damageValues[damage.key]) { + context.selectedData.damageValues[damage.key].total += damageTotal; + } else { + context.selectedData.damageValues[damage.key] = { + ...foundry.utils.deepClone(damage), + total: damageTotal + }; + } } } } - const selectedRoll = Object.values(this.party.system.tagTeam.members).find(member => member.selected); - const critSelected = !selectedRoll ? undefined : (selectedRoll?.rollData?.options?.roll?.isCritical ?? false); - const damage = data.rollData?.options?.damage; + context.showResult = Object.values(context.members).reduce((enabled, member) => { + if (!member.roll) return enabled; + if (context.usesDamage) { + enabled = enabled === null ? member.damageValues.length > 0 : enabled && member.damageValues.length > 0; + } else { + enabled = enabled === null ? Boolean(member.roll) : enabled && Boolean(member.roll); + } - return { - ...data, - roll: data.roll, - isEditable: actor?.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER), - key: partId, - readyToRoll: Boolean(data.rollChoice), - hasRolled: Boolean(data.rollData), - rollOptions, - damageRollOptions, - damage: damage, - critDamage: await this.getCriticalDamage(damage), - useCritDamage: critSelected || (critSelected === undefined && data.rollData?.options?.roll?.isCritical) - }; + return enabled; + }, null); + + context.createDisabled = + !context.selectedData.result || + !this.data.initiator.id || + Object.keys(this.data.members).length === 0 || + Object.values(context.members).some(x => + context.usesDamage ? !x.damageValues || x.damageValues.length === 0 : !x.roll + ); + + return context; } - getUpdatingParts(target) { - const { initialization, rollSelection, result } = this.constructor.PARTS; - const isInitialization = this.tabGroups.application === initialization.id; - const updatingMember = target.closest('.team-member-container')?.dataset?.memberKey; + async updateSource(update) { + await this.data.updateSource(update); - return [ - ...(isInitialization ? [initialization.id] : []), - ...(updatingMember ? [updatingMember] : []), - ...(!isInitialization ? [rollSelection.id] : []), - ...(!isInitialization ? [result.id] : []) - ]; - } - - static async updateData(event, _, formData) { - const partyData = foundry.utils.expandObject(formData.object); - - this.updatePartyData(partyData, this.getUpdatingParts(event.target)); - } - - async updatePartyData(update, updatingParts, options = { render: true }) { - if (!game.users.activeGM) - return ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.gmRequired')); - - const gmUpdate = async update => { - await this.party.update(update); - this.render({ parts: updatingParts }); - game.socket.emit(`system.${CONFIG.DH.id}`, { + if (game.user.isGM) { + await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll, this.data.toObject()); + Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.TagTeamRoll }); + await game.socket.emit(`system.${CONFIG.DH.id}`, { action: socketEvent.Refresh, - data: { refreshType: RefreshType.TagTeamRoll, action: 'refresh', parts: updatingParts } + data: { + refreshType: RefreshType.TagTeamRoll + } + }); + } else { + await game.socket.emit(`system.${CONFIG.DH.id}`, { + action: socketEvent.GMUpdate, + data: { + action: GMUpdateEvent.UpdateSetting, + uuid: CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll, + update: this.data.toObject(), + refresh: { refreshType: RefreshType.TagTeamRoll } + } }); - }; - - await emitGMUpdate( - GMUpdateEvent.UpdateDocument, - gmUpdate, - update, - this.party.uuid, - options.render - ? { refreshType: RefreshType.TagTeamRoll, action: 'refresh', parts: updatingParts } - : undefined - ); - } - - tagTeamRefresh = ({ refreshType, action, parts }) => { - if (refreshType !== RefreshType.TagTeamRoll) return; - - switch (action) { - case 'startTagTeamRoll': - this.tabGroups.application = 'tagTeamRoll'; - break; - case 'refresh': - this.render({ parts }); - break; - case 'close': - this.close(); - break; } - }; - - async close(options = {}) { - /* Opt out of Foundry's standard behavior of closing all application windows marked as UI when Escape is pressed */ - if (options.closeKey) return; - - Hooks.off(socketEvent.Refresh, this.tagTeamRefresh); - return super.close(options); } - checkInitiatorHopeError(initiator) { - if (initiator.cost && initiator.memberId) { - const actor = game.actors.get(initiator.memberId); - if (actor.system.resources.hope.value < initiator.cost) { + static async updateData(_event, _element, formData) { + const { selectedAddMember, initiator } = foundry.utils.expandObject(formData.object); + const update = { initiator: initiator }; + if (selectedAddMember) { + const member = await foundry.utils.fromUuid(selectedAddMember); + update[`members.${member.id}`] = { messageId: null }; + } + + await this.updateSource(update); + this.render(); + } + + static async #removeMember(_, button) { + const update = { [`members.-=${button.dataset.characterId}`]: null }; + if (this.data.initiator.id === button.dataset.characterId) { + update.iniator = { id: null }; + } + + await this.updateSource(update); + } + + static async #unlinkMessage(_, button) { + await this.updateSource({ [`members.${button.id}.messageId`]: null }); + } + + static async #selectMessage(_, button) { + const member = this.data.members[button.id]; + const currentSelected = Object.keys(this.data.members).find(key => this.data.members[key].selected); + const curretSelectedUpdate = + currentSelected && currentSelected !== button.id ? { [`${currentSelected}`]: { selected: false } } : {}; + await this.updateSource({ + members: { + [`${button.id}`]: { selected: !member.selected }, + ...curretSelectedUpdate + } + }); + } + + static async #createTagTeam() { + const mainRollId = Object.keys(this.data.members).find(key => this.data.members[key].selected); + const mainRoll = game.messages.get(this.data.members[mainRollId].messageId); + + if (this.data.initiator.cost) { + const initiator = this.party.find(x => x.id === this.data.initiator.id); + if (initiator.system.resources.hope.value < this.data.initiator.cost) { return ui.notifications.warn( game.i18n.localize('DAGGERHEART.APPLICATIONS.TagTeamSelect.insufficientHope') ); } } - } - //#region Initialization - static #toggleSelectMember(_, button) { - const member = this.partyMembers.find(x => x.id === button.dataset.id); - if (member.selected && this.initiator?.memberId === member.id) this.initiator = null; + const secondaryRolls = Object.keys(this.data.members) + .filter(key => key !== mainRollId) + .map(key => game.messages.get(this.data.members[key].messageId)); - member.selected = !member.selected; - this.render(); - } - - static async #startTagTeamRoll() { - const error = this.checkInitiatorHopeError(this.initiator); - if (error) return error; - - await this.party.update({ - 'system.tagTeam': _replace( - new game.system.api.data.TagTeamData({ - ...this.party.system.tagTeam.toObject(), - initiator: this.initiator, - members: this.partyMembers.reduce((acc, member) => { - if (member.selected) - acc[member.id] = { - name: member.name, - img: member.img, - rollType: CONFIG.DH.GENERAL.tagTeamRollTypes.trait.id - }; - return acc; - }, {}) - }) - ) - }); - - const hookData = { openForAllPlayers: this.openForAllPlayers, partyId: this.party.id }; - Hooks.callAll(CONFIG.DH.HOOKS.hooksConfig.tagTeamStart, hookData); - game.socket.emit(`system.${CONFIG.DH.id}`, { - action: socketEvent.TagTeamStart, - data: hookData - }); - - this.render(); - } - //#endregion - //#region Tag Team Roll - - async getInfoTexts(members) { - let rollsAreFinished = true; - let rollIsSelected = false; - for (const member of Object.values(members)) { - const rollFinished = Boolean(member.rollData); - const damageFinished = member.rollData?.options?.hasDamage ? Boolean(member.rollData.options.damage) : true; - - rollsAreFinished = rollsAreFinished && rollFinished && damageFinished; - rollIsSelected = rollIsSelected || member.selected; - } - - let hint = null; - if (!rollsAreFinished) hint = game.i18n.localize('DAGGERHEART.APPLICATIONS.TagTeamSelect.hints.completeRolls'); - else if (!rollIsSelected) hint = game.i18n.localize('DAGGERHEART.APPLICATIONS.TagTeamSelect.hints.selectRoll'); - - return hint; - } - - async updateRollType(event) { - this.updatePartyData( - { - [`system.tagTeam.members.${event.target.dataset.member}`]: { - rollType: event.target.value, - rollChoice: null - } - }, - this.getUpdatingParts(event.target) - ); - } - - updateInitiatorMemberField(event) { - if (!this.initiator) this.initiator = {}; - this.initiator.memberId = event.target.value; - this.render(); - } - - updateInitiatorCostField(event) { - if (!this.initiator) this.initiator = {}; - this.initiator.cost = event.target.value ? Number.parseInt(event.target.value) : null; - this.render(); - } - - updateOpenForAllField(event) { - this.openForAllPlayers = event.target.checked; - this.render(); - } - - static async #removeRoll(_, button) { - this.updatePartyData( - { - [`system.tagTeam.members.${button.dataset.member}`]: { - rollData: null, - rollChoice: null, - selected: false - } - }, - this.getUpdatingParts(button) - ); - } - - static async #makeRoll(event, button) { - const { member } = button.dataset; - - let result = null; - switch (this.party.system.tagTeam.members[member].rollType) { - case CONFIG.DH.GENERAL.tagTeamRollTypes.trait.id: - result = await this.makeTraitRoll(member); - break; - case CONFIG.DH.GENERAL.tagTeamRollTypes.ability.id: - case CONFIG.DH.GENERAL.tagTeamRollTypes.damageAbility.id: - result = await this.makeAbilityRoll(event, member); - break; - } - - if (!result) return; - - const rollData = result.messageRoll.toJSON(); - delete rollData.options.messageRoll; - this.updatePartyData( - { - [`system.tagTeam.members.${member}.rollData`]: rollData - }, - this.getUpdatingParts(button) - ); - } - - async makeTraitRoll(memberKey) { - const actor = game.actors.find(x => x.id === memberKey); - if (!actor) return; - - const memberData = this.party.system.tagTeam.members[memberKey]; - return await actor.rollTrait(memberData.rollChoice, { - skips: { - createMessage: true, - resources: true, - triggers: true - } - }); - } - - async makeAbilityRoll(event, memberKey) { - const actor = game.actors.find(x => x.id === memberKey); - if (!actor) return; - - const memberData = this.party.system.tagTeam.members[memberKey]; - const action = await foundry.utils.fromUuid(memberData.rollChoice); - - return await action.use(event, { - skips: { - createMessage: true, - resources: true, - triggers: true - } - }); - } - - static async #rerollDice(_, button) { - const { member, diceType } = button.dataset; - const memberData = this.party.system.tagTeam.members[member]; - - const dieIndex = diceType === 'hope' ? 0 : diceType === 'fear' ? 1 : 2; - const newRoll = game.system.api.dice.DualityRoll.fromData(memberData.rollData); - const dice = newRoll.dice[dieIndex]; - await dice.reroll(`/r1=${dice.total}`, { - liveRoll: { - roll: newRoll, - isReaction: true - } - }); - const rollData = newRoll.toJSON(); - this.updatePartyData( - { - [`system.tagTeam.members.${member}.rollData`]: rollData - }, - this.getUpdatingParts(button) - ); - } - - static async #makeDamageRoll(event, button) { - const { memberKey } = button.dataset; - const actor = game.actors.find(x => x.id === memberKey); - if (!actor) return; - - const memberData = this.party.system.tagTeam.members[memberKey]; - const action = await foundry.utils.fromUuid(memberData.rollChoice); - const config = { - ...memberData.rollData.options, - dialog: { - configure: !event.shiftKey - }, - skips: { - createMessage: true, - resources: true, - triggers: true - } - }; - - await action.workflow.get('damage').execute(config, null, true); - if (!config.damage) return; - - const current = this.party.system.tagTeam.members[memberKey].rollData; - await this.updatePartyData( - { - [`system.tagTeam.members.${memberKey}.rollData`]: { - ...current, - options: { - ...current.options, - damage: config.damage - } - } - }, - this.getUpdatingParts(button) - ); - } - - static async #removeDamageRoll(_, button) { - const { memberKey } = button.dataset; - const current = this.party.system.tagTeam.members[memberKey].rollData; - this.updatePartyData( - { - [`system.tagTeam.members.${memberKey}.rollData`]: { - ...current, - options: { - ...current.options, - damage: null - } - } - }, - this.getUpdatingParts(button) - ); - } - - static async #rerollDamageDice(_, button) { - const { memberKey, damageKey, part, dice } = button.dataset; - const memberData = this.party.system.tagTeam.members[memberKey]; - const partData = memberData.rollData.options.damage[damageKey].parts[part]; - const activeDiceResultKey = Object.keys(partData.dice[dice].results).find( - index => partData.dice[dice].results[index].active - ); - const { parsedRoll, rerolledDice } = await game.system.api.dice.DamageRoll.reroll( - partData, - dice, - activeDiceResultKey - ); - - const rollData = this.party.system.tagTeam.members[memberKey].rollData; - rollData.options.damage[damageKey].parts = rollData.options.damage[damageKey].parts.map((damagePart, index) => { - if (index !== Number.parseInt(part)) return damagePart; - - return { - ...damagePart, - total: parsedRoll.total, - dice: rerolledDice - }; - }); - rollData.options.damage[damageKey].total = rollData.options.damage[damageKey].parts.reduce((acc, part) => { - acc += part.total; - return acc; - }, 0); - - this.updatePartyData( - { - [`system.tagTeam.members.${memberKey}.rollData`]: rollData - }, - this.getUpdatingParts(button) - ); - } - - async getCriticalDamage(damage) { - const newDamage = foundry.utils.deepClone(damage); - for (let key in newDamage) { - var damage = newDamage[key]; - damage.formula = ''; - damage.total = 0; - - for (let part of damage.parts) { - const criticalDamage = await getCritDamageBonus(part.formula); - if (criticalDamage) { - part.modifierTotal += criticalDamage; - part.total += criticalDamage; - part.formula = `${part.dice.map(x => x.formula).join(' + ')} + ${part.modifierTotal}`; - part.roll = new Roll(part.formula); - } - - damage.formula = [damage.formula, part.formula].filter(x => x).join(' + '); - damage.total += part.total; - } - } - - return newDamage; - } - - async getNonCriticalDamage(config) { - const newDamage = foundry.utils.deepClone(config.damage); - for (let key in newDamage) { - var damage = newDamage[key]; - damage.formula = ''; - damage.total = 0; - - for (let part of damage.parts) { - const critDamageBonus = await getCritDamageBonus(part.formula); - part.modifierTotal -= critDamageBonus; - part.total -= critDamageBonus; - part.formula = `${part.dice.map(x => x.formula).join(' + ')} + ${part.modifierTotal}`; - part.roll = new Roll(part.formula); - - damage.formula = [damage.formula, part.formula].filter(x => x).join(' + '); - damage.total += part.total; - } - } - - return newDamage; - } - - static async #selectRoll(_, button) { - const { memberKey } = button.dataset; - this.updatePartyData( - { - [`system.tagTeam.members`]: Object.entries(this.party.system.tagTeam.members).reduce( - (acc, [key, member]) => { - acc[key] = { selected: key === memberKey ? !member.selected : false }; - return acc; - }, - {} - ) - }, - this.getUpdatingParts(button) - ); - } - - async getJoinedRoll({ overrideIsCritical, displayVersion } = {}) { - try { - const memberValues = Object.values(this.party.system.tagTeam.members); - const selectedRoll = memberValues.find(x => x.selected); - const baseMainRoll = selectedRoll ?? memberValues[0]; - const baseSecondaryRoll = selectedRoll - ? memberValues.find(x => !x.selected) - : memberValues.length > 1 - ? memberValues[1] - : null; - - if (!baseMainRoll?.rollData || !baseSecondaryRoll) return null; - - const mainRoll = new MemberData(baseMainRoll.toObject()); - const secondaryRollData = new MemberData(baseSecondaryRoll.toObject()).rollData; - const systemData = mainRoll.rollData.options; - const isCritical = overrideIsCritical ?? systemData.roll.isCritical; - if (isCritical) systemData.damage = await this.getCriticalDamage(systemData.damage); - - if (secondaryRollData?.options.hasDamage) { - const secondaryDamage = (displayVersion ? overrideIsCritical : isCritical) - ? await this.getCriticalDamage(secondaryRollData.options.damage) - : secondaryRollData.options.damage; - if (systemData.damage) { - for (const [key, damage] of Object.entries(secondaryDamage ?? {})) { - if (key in systemData.damage) { - systemData.damage[key].formula = [systemData.damage[key]?.formula, damage.formula] - .filter(x => x) - .join(' + '); - systemData.damage[key].total += damage.total; - systemData.damage[key].parts.push(...damage.parts); - } else { - systemData.damage[key] = damage; + const systemData = foundry.utils.deepClone(mainRoll).system.toObject(); + const criticalRoll = systemData.roll.isCritical; + for (let roll of secondaryRolls) { + if (roll.system.hasDamage) { + for (let key in roll.system.damage) { + var damage = roll.system.damage[key]; + const damageTotal = + !roll.system.isCritical && criticalRoll + ? (await getCritDamageBonus(damage.formula)) + damage.total + : damage.total; + const updatedDamageParts = damage.parts; + if (systemData.damage[key]) { + if (!roll.system.isCritical && criticalRoll) { + for (let part of updatedDamageParts) { + const criticalDamage = await getCritDamageBonus(part.formula); + if (criticalDamage) { + damage.formula = `${damage.formula} + ${criticalDamage}`; + part.formula = `${part.formula} + ${criticalDamage}`; + part.modifierTotal = part.modifierTotal + criticalDamage; + part.total += criticalDamage; + part.roll = new Roll(part.formula); + } + } } + + systemData.damage[key].formula = `${systemData.damage[key].formula} + ${damage.formula}`; + systemData.damage[key].total += damageTotal; + systemData.damage[key].parts = [...systemData.damage[key].parts, ...updatedDamageParts]; + } else { + systemData.damage[key] = { ...damage, total: damageTotal, parts: updatedDamageParts }; } - } else { - systemData.damage = secondaryDamage; } } - - return mainRoll; - } catch (err) { - console.error(err); - return null; - } - } - - static async #onCancelRoll(_event, _button, options = { confirm: true }) { - this.cancelRoll(options); - } - - async cancelRoll(options = { confirm: true }) { - if (options.confirm) { - const confirmed = await foundry.applications.api.DialogV2.confirm({ - window: { - title: game.i18n.localize('DAGGERHEART.APPLICATIONS.TagTeamSelect.cancelConfirmTitle') - }, - content: game.i18n.localize('DAGGERHEART.APPLICATIONS.TagTeamSelect.cancelConfirmText') - }); - - if (!confirmed) return; } - await this.updatePartyData( - { - 'system.tagTeam': { - initiator: null, - members: _replace({}) - } - }, - [], - { render: false } - ); - - this.close(); - game.socket.emit(`system.${CONFIG.DH.id}`, { - action: socketEvent.Refresh, - data: { refreshType: RefreshType.TagTeamRoll, action: 'close' } - }); - } - - static async #finishRoll() { - const error = this.checkInitiatorHopeError(this.party.system.tagTeam.initiator); - if (error) return error; - - const joinedRoll = await this.getJoinedRoll(); - const mainRoll = joinedRoll.rollData; - const finalRoll = foundry.utils.deepClone(joinedRoll.roll); - - const mainActor = this.party.system.partyMembers.find(x => x.uuid === mainRoll.options.source.actor); - mainRoll.options.title = game.i18n.localize('DAGGERHEART.APPLICATIONS.TagTeamSelect.chatMessageRollTitle'); + systemData.title = game.i18n.localize('DAGGERHEART.APPLICATIONS.TagTeamSelect.chatMessageRollTitle'); const cls = getDocumentClass('ChatMessage'), msgData = { type: 'dualityRoll', user: game.user.id, title: game.i18n.localize('DAGGERHEART.APPLICATIONS.TagTeamSelect.title'), - speaker: cls.getSpeaker({ actor: mainActor }), - system: mainRoll.options, - rolls: [JSON.stringify(joinedRoll.roll)], + speaker: cls.getSpeaker({ actor: this.party.find(x => x.id === mainRollId) }), + system: systemData, + rolls: mainRoll.rolls, sound: null, flags: { core: { RollTable: true } } }; await cls.create(msgData); - /* Handle resource updates from the finished TagTeamRoll */ - const tagTeamData = this.party.system.tagTeam; const fearUpdate = { key: 'fear', value: null, total: null, enabled: true }; - for (let memberId in tagTeamData.members) { + for (let memberId of Object.keys(this.data.members)) { const resourceUpdates = []; - const rollGivesHope = finalRoll.isCritical || finalRoll.withHope; - if (memberId === tagTeamData.initiator.memberId) { - const value = tagTeamData.initiator.cost + const rollGivesHope = systemData.roll.isCritical || systemData.roll.result.duality === 1; + if (memberId === this.data.initiator.id) { + const value = this.data.initiator.cost ? rollGivesHope - ? 1 - tagTeamData.initiator.cost - : -tagTeamData.initiator.cost + ? 1 - this.data.initiator.cost + : -this.data.initiator.cost : 1; resourceUpdates.push({ key: 'hope', value: value, total: -value, enabled: true }); } else if (rollGivesHope) { resourceUpdates.push({ key: 'hope', value: 1, total: -1, enabled: true }); } - if (finalRoll.isCritical) resourceUpdates.push({ key: 'stress', value: -1, total: 1, enabled: true }); - if (finalRoll.withFear) { + if (systemData.roll.isCritical) resourceUpdates.push({ key: 'stress', value: -1, total: 1, enabled: true }); + if (systemData.roll.result.duality === -1) { fearUpdate.value = fearUpdate.value === null ? 1 : fearUpdate.value + 1; fearUpdate.total = fearUpdate.total === null ? -1 : fearUpdate.total - 1; } - game.actors.get(memberId).modifyResource(resourceUpdates); + this.party.find(x => x.id === memberId).modifyResource(resourceUpdates); } if (fearUpdate.value) { - mainActor.modifyResource([fearUpdate]); + this.party.find(x => x.id === mainRollId).modifyResource([fearUpdate]); } - /* Fin */ - this.cancelRoll({ confirm: false }); + /* Improve by fetching default from schema */ + const update = { members: [], initiator: { id: null, cost: 3 } }; + if (game.user.isGM) { + await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll, update); + Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.TagTeamRoll }); + await game.socket.emit(`system.${CONFIG.DH.id}`, { + action: socketEvent.Refresh, + data: { + refreshType: RefreshType.TagTeamRoll + } + }); + } else { + await game.socket.emit(`system.${CONFIG.DH.id}`, { + action: socketEvent.GMUpdate, + data: { + action: GMUpdateEvent.UpdateSetting, + uuid: CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll, + update: update, + refresh: { refreshType: RefreshType.TagTeamRoll } + } + }); + } } - //#endregion + static async assignRoll(char, message) { + const settings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll); + const character = settings.members[char.id]; + if (!character) return; + + await settings.updateSource({ [`members.${char.id}.messageId`]: message.id }); + + if (game.user.isGM) { + await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll, settings); + Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.TagTeamRoll }); + await game.socket.emit(`system.${CONFIG.DH.id}`, { + action: socketEvent.Refresh, + data: { + refreshType: RefreshType.TagTeamRoll + } + }); + } else { + await game.socket.emit(`system.${CONFIG.DH.id}`, { + action: socketEvent.GMUpdate, + data: { + action: GMUpdateEvent.UpdateSetting, + uuid: CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll, + update: settings, + refresh: { refreshType: RefreshType.TagTeamRoll } + } + }); + } + } + + async close(options = {}) { + Hooks.off(socketEvent.Refresh, this.setupHooks); + await super.close(options); + } } diff --git a/module/applications/hud/tokenHUD.mjs b/module/applications/hud/tokenHUD.mjs index 4805cd9e..77caaaff 100644 --- a/module/applications/hud/tokenHUD.mjs +++ b/module/applications/hud/tokenHUD.mjs @@ -50,11 +50,11 @@ export default class DHTokenHUD extends foundry.applications.hud.TokenHUD { ).showGenericStatusEffects; context.genericStatusEffects = useGeneric ? Object.keys(context.statusEffects).reduce((acc, key) => { - const effect = context.statusEffects[key]; - if (!effect.systemEffect) acc[key] = effect; + const effect = context.statusEffects[key]; + if (!effect.systemEffect) acc[key] = effect; - return acc; - }, {}) + return acc; + }, {}) : null; context.hasCompanion = this.actor.system.companion; @@ -68,11 +68,11 @@ export default class DHTokenHUD extends foundry.applications.hud.TokenHUD { const warning = tokensWithoutActors.length === 1 ? game.i18n.format('DAGGERHEART.UI.Notifications.tokenActorMissing', { - name: tokensWithoutActors[0].name - }) + name: tokensWithoutActors[0].name + }) : game.i18n.format('DAGGERHEART.UI.Notifications.tokenActorsMissing', { - names: tokensWithoutActors.map(x => x.name).join(', ') - }); + names: tokensWithoutActors.map(x => x.name).join(', ') + }); const tokens = canvas.tokens.controlled .filter(t => t.actor && !DHTokenHUD.#nonCombatTypes.includes(t.actor.type)) @@ -122,16 +122,15 @@ export default class DHTokenHUD extends foundry.applications.hud.TokenHUD { async toggleClowncar(actors) { const animationDuration = 500; - const scene = game.scenes.get(game.user.viewedScene); - /* getDependentTokens returns already removed tokens with id = null. Need to filter that until it's potentially fixed from Foundry */ - const activeTokens = actors.flatMap(member => - member.getDependentTokens({ scenes: scene }).filter(x => x._id && !x._destroyed) - ); + const activeTokens = actors.flatMap(member => member.getActiveTokens()); const { x: actorX, y: actorY } = this.document; if (activeTokens.length > 0) { for (let token of activeTokens) { - await token.update({ x: actorX, y: actorY, alpha: 0 }, { animation: { duration: animationDuration } }); - setTimeout(() => token.delete(), animationDuration); + await token.document.update( + { x: actorX, y: actorY, alpha: 0 }, + { animation: { duration: animationDuration } } + ); + setTimeout(() => token.document.delete(), animationDuration); } } else { const activeScene = game.scenes.find(x => x.id === game.user.viewedScene); @@ -141,16 +140,11 @@ export default class DHTokenHUD extends foundry.applications.hud.TokenHUD { tokenData.push(data.toObject()); } - const viewedLevel = game.scenes.get(game.user.viewedScene).levels.get(game.user.viewedLevel); - const elevation = this.actor.token?.elevation ?? viewedLevel.elevation.bottom; - const newTokens = await activeScene.createEmbeddedDocuments( 'Token', tokenData.map(tokenData => ({ ...tokenData, alpha: 0, - level: viewedLevel, - elevation: elevation, x: actorX, y: actorY })) @@ -174,8 +168,8 @@ export default class DHTokenHUD extends foundry.applications.hud.TokenHUD { nonZeroIndex === sideMiddle ? 0 : nonZeroIndex < sideMiddle - ? -nonZeroIndex - : nonZeroIndex - sideMiddle; + ? -nonZeroIndex + : nonZeroIndex - sideMiddle; return { x: actorX - sizeX * distance, y: actorY - sizeY * distanceCoefficient }; } else if (index < side + inbetween) { const inbetweenIndex = nonZeroIndex - side; @@ -183,8 +177,8 @@ export default class DHTokenHUD extends foundry.applications.hud.TokenHUD { inbetweenIndex === inbetweenMiddle ? 0 : inbetweenIndex < inbetweenMiddle - ? -inbetweenIndex - : inbetweenIndex - inbetweenMiddle; + ? -inbetweenIndex + : inbetweenIndex - inbetweenMiddle; return { x: actorX + sizeX * distanceCoefficient, y: actorY + sizeY * distance }; } else if (index < 2 * side + inbetween) { const sideIndex = nonZeroIndex - side - inbetween; @@ -192,8 +186,8 @@ export default class DHTokenHUD extends foundry.applications.hud.TokenHUD { sideIndex === sideMiddle ? 0 : sideIndex < sideMiddle - ? sideIndex - : -(sideIndex - sideMiddle); + ? sideIndex + : -(sideIndex - sideMiddle); return { x: actorX + sizeX * distance, y: actorY + sizeY * distanceCoefficient }; } else { const inbetweenIndex = nonZeroIndex - 2 * side - inbetween; @@ -201,8 +195,8 @@ export default class DHTokenHUD extends foundry.applications.hud.TokenHUD { inbetweenIndex === inbetweenMiddle ? 0 : inbetweenIndex < inbetweenMiddle - ? inbetweenIndex - : -(inbetweenIndex - inbetweenMiddle); + ? inbetweenIndex + : -(inbetweenIndex - inbetweenMiddle); return { x: actorX - sizeX * distanceCoefficient, y: actorY + sizeY * distance }; } }) diff --git a/module/applications/levelup/characterLevelup.mjs b/module/applications/levelup/characterLevelup.mjs index a2df63c1..f7ef2ffa 100644 --- a/module/applications/levelup/characterLevelup.mjs +++ b/module/applications/levelup/characterLevelup.mjs @@ -156,7 +156,6 @@ export default class DhCharacterLevelUp extends LevelUpBase { if (multiclasses?.[0]) { const data = multiclasses[0]; const multiclass = data.data.length > 0 ? await foundry.utils.fromUuid(data.data[0]) : {}; - const subclasses = (await multiclass?.system?.fetchSubclasses()) ?? []; context.multiclass = { ...data, @@ -176,12 +175,13 @@ export default class DhCharacterLevelUp extends LevelUpBase { alreadySelected }; }) ?? [], - subclasses: subclasses.map(subclass => ({ - ...subclass, - uuid: subclass.uuid, - selected: data.secondaryData.subclass === subclass.uuid, - disabled: data.secondaryData.subclass && data.secondaryData.subclass !== subclass.uuid - })), + subclasses: + multiclass?.system?.subclasses.map(subclass => ({ + ...subclass, + uuid: subclass.uuid, + selected: data.secondaryData.subclass === subclass.uuid, + disabled: data.secondaryData.subclass && data.secondaryData.subclass !== subclass.uuid + })) ?? [], compendium: 'classes', limit: 1 }; @@ -210,9 +210,9 @@ export default class DhCharacterLevelUp extends LevelUpBase { achievementExperiences = level.achievements.experiences ? Object.values(level.achievements.experiences).reduce((acc, experience) => { - if (experience.name) acc.push(experience); - return acc; - }, []) + if (experience.name) acc.push(experience); + return acc; + }, []) : []; } @@ -315,15 +315,15 @@ export default class DhCharacterLevelUp extends LevelUpBase { : null; advancement[choiceKey] = multiclassItem ? { - ...multiclassItem.toObject(), - domain: checkbox.secondaryData.domain - ? game.i18n.localize( - CONFIG.DH.DOMAIN.allDomains()[checkbox.secondaryData.domain] - .label - ) - : null, - subclass: subclass ? subclass.name : null - } + ...multiclassItem.toObject(), + domain: checkbox.secondaryData.domain + ? game.i18n.localize( + CONFIG.DH.DOMAIN.allDomains()[checkbox.secondaryData.domain] + .label + ) + : null, + subclass: subclass ? subclass.name : null + } : {}; break; } diff --git a/module/applications/levelup/companionLevelup.mjs b/module/applications/levelup/companionLevelup.mjs index 92cf3050..7f11ccff 100644 --- a/module/applications/levelup/companionLevelup.mjs +++ b/module/applications/levelup/companionLevelup.mjs @@ -67,7 +67,7 @@ export default class DhCompanionLevelUp extends BaseLevelUp { break; case 'summary': const levelKeys = Object.keys(this.levelup.levels); - const actorDamageDice = this.actor.system.attack.damage.parts.hitPoints.value.dice; + const actorDamageDice = this.actor.system.attack.damage.parts[0].value.dice; const actorRange = this.actor.system.attack.range; let achievementExperiences = []; @@ -77,9 +77,9 @@ export default class DhCompanionLevelUp extends BaseLevelUp { achievementExperiences = level.achievements.experiences ? Object.values(level.achievements.experiences).reduce((acc, experience) => { - if (experience.name) acc.push(experience); - return acc; - }, []) + if (experience.name) acc.push(experience); + return acc; + }, []) : []; } context.achievements = { @@ -155,15 +155,15 @@ export default class DhCompanionLevelUp extends BaseLevelUp { vicious: { damage: advancement.vicious?.damage ? { - old: actorDamageDice, - new: advancement.vicious.damage - } + old: actorDamageDice, + new: advancement.vicious.damage + } : null, range: advancement.vicious?.range ? { - old: game.i18n.localize(`DAGGERHEART.CONFIG.Range.${actorRange}.name`), - new: game.i18n.localize(advancement.vicious.range.label) - } + old: game.i18n.localize(`DAGGERHEART.CONFIG.Range.${actorRange}.name`), + new: game.i18n.localize(advancement.vicious.range.label) + } : null }, simple: advancement.simple ?? {} diff --git a/module/applications/levelup/levelup.mjs b/module/applications/levelup/levelup.mjs index cafc5c89..ba6110cc 100644 --- a/module/applications/levelup/levelup.mjs +++ b/module/applications/levelup/levelup.mjs @@ -135,6 +135,192 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2) context.tabs.advancements.progress = { selected: selections, max: currentLevel.maxSelections }; context.showTabs = this.tabGroups.primary !== 'summary'; break; + + const actorArmor = this.actor.system.armor; + const levelKeys = Object.keys(this.levelup.levels); + let achivementProficiency = 0; + const achievementCards = []; + let achievementExperiences = []; + for (var levelKey of levelKeys) { + const level = this.levelup.levels[levelKey]; + if (Number(levelKey) < this.levelup.startLevel) continue; + + achivementProficiency += level.achievements.proficiency ?? 0; + const cards = level.achievements.domainCards ? Object.values(level.achievements.domainCards) : null; + if (cards) { + for (var card of cards) { + const itemCard = await foundry.utils.fromUuid(card.uuid); + achievementCards.push(itemCard); + } + } + + achievementExperiences = level.achievements.experiences + ? Object.values(level.achievements.experiences).reduce((acc, experience) => { + if (experience.name) acc.push(experience); + return acc; + }, []) + : []; + } + + context.achievements = { + proficiency: { + old: this.actor.system.proficiency, + new: this.actor.system.proficiency + achivementProficiency, + shown: achivementProficiency > 0 + }, + damageThresholds: { + major: { + old: this.actor.system.damageThresholds.major, + new: this.actor.system.damageThresholds.major + changedActorLevel - currentActorLevel + }, + severe: { + old: this.actor.system.damageThresholds.severe, + new: + this.actor.system.damageThresholds.severe + + (actorArmor + ? changedActorLevel - currentActorLevel + : (changedActorLevel - currentActorLevel) * 2) + }, + unarmored: !actorArmor + }, + domainCards: { + values: achievementCards, + shown: achievementCards.length > 0 + }, + experiences: { + values: achievementExperiences + } + }; + + const advancement = {}; + for (var levelKey of levelKeys) { + const level = this.levelup.levels[levelKey]; + if (Number(levelKey) < this.levelup.startLevel) continue; + + for (var choiceKey of Object.keys(level.choices)) { + const choice = level.choices[choiceKey]; + for (var checkbox of Object.values(choice)) { + switch (choiceKey) { + case 'proficiency': + case 'hitPoint': + case 'stress': + case 'evasion': + advancement[choiceKey] = advancement[choiceKey] + ? advancement[choiceKey] + Number(checkbox.value) + : Number(checkbox.value); + break; + case 'trait': + if (!advancement[choiceKey]) advancement[choiceKey] = {}; + for (var traitKey of checkbox.data) { + if (!advancement[choiceKey][traitKey]) advancement[choiceKey][traitKey] = 0; + advancement[choiceKey][traitKey] += 1; + } + break; + case 'domainCard': + if (!advancement[choiceKey]) advancement[choiceKey] = []; + if (checkbox.data.length === 1) { + const choiceItem = await foundry.utils.fromUuid(checkbox.data[0]); + advancement[choiceKey].push(choiceItem.toObject()); + } + break; + case 'experience': + if (!advancement[choiceKey]) advancement[choiceKey] = []; + const data = checkbox.data.map(data => { + const experience = Object.keys(this.actor.system.experiences).find( + x => x === data + ); + return this.actor.system.experiences[experience]?.description ?? ''; + }); + advancement[choiceKey].push({ data: data, value: checkbox.value }); + break; + case 'subclass': + if (checkbox.data[0]) { + const subclassItem = await foundry.utils.fromUuid(checkbox.data[0]); + if (!advancement[choiceKey]) advancement[choiceKey] = []; + advancement[choiceKey].push({ + ...subclassItem.toObject(), + featureLabel: game.i18n.localize( + subclassFeatureLabels[Number(checkbox.secondaryData.featureState)] + ) + }); + } + break; + case 'multiclass': + const multiclassItem = await foundry.utils.fromUuid(checkbox.data[0]); + const subclass = multiclassItem + ? await foundry.utils.fromUuid(checkbox.secondaryData.subclass) + : null; + advancement[choiceKey] = multiclassItem + ? { + ...multiclassItem.toObject(), + domain: checkbox.secondaryData.domain + ? game.i18n.localize( + CONFIG.DH.DOMAIN.allDomains()[checkbox.secondaryData.domain] + .label + ) + : null, + subclass: subclass ? subclass.name : null + } + : {}; + break; + } + } + } + } + + context.advancements = { + statistics: { + proficiency: { + old: context.achievements.proficiency.new, + new: context.achievements.proficiency.new + (advancement.proficiency ?? 0) + }, + hitPoints: { + old: this.actor.system.resources.hitPoints.max, + new: this.actor.system.resources.hitPoints.max + (advancement.hitPoint ?? 0) + }, + stress: { + old: this.actor.system.resources.stress.max, + new: this.actor.system.resources.stress.max + (advancement.stress ?? 0) + }, + evasion: { + old: this.actor.system.evasion, + new: this.actor.system.evasion + (advancement.evasion ?? 0) + } + }, + traits: Object.keys(this.actor.system.traits).reduce((acc, traitKey) => { + if (advancement.trait?.[traitKey]) { + if (!acc) acc = {}; + acc[traitKey] = { + label: game.i18n.localize(abilities[traitKey].label), + old: this.actor.system.traits[traitKey].value, + new: this.actor.system.traits[traitKey].value + advancement.trait[traitKey] + }; + } + return acc; + }, null), + domainCards: advancement.domainCard ?? [], + experiences: + advancement.experience?.flatMap(x => x.data.map(data => ({ name: data, modifier: x.value }))) ?? + [], + multiclass: advancement.multiclass, + subclass: advancement.subclass + }; + + context.advancements.statistics.proficiency.shown = + context.advancements.statistics.proficiency.new > context.advancements.statistics.proficiency.old; + context.advancements.statistics.hitPoints.shown = + context.advancements.statistics.hitPoints.new > context.advancements.statistics.hitPoints.old; + context.advancements.statistics.stress.shown = + context.advancements.statistics.stress.new > context.advancements.statistics.stress.old; + context.advancements.statistics.evasion.shown = + context.advancements.statistics.evasion.new > context.advancements.statistics.evasion.old; + context.advancements.statistics.shown = + context.advancements.statistics.proficiency.shown || + context.advancements.statistics.hitPoints.shown || + context.advancements.statistics.stress.shown || + context.advancements.statistics.evasion.shown; + + break; } return context; @@ -172,14 +358,14 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2) const experienceIncreaseTagify = htmlElement.querySelector('.levelup-experience-increases'); if (experienceIncreaseTagify) { const allExperiences = { + ...this.actor.system.experiences, ...Object.values(this.levelup.levels).reduce((acc, level) => { for (const key of Object.keys(level.achievements.experiences)) { acc[key] = level.achievements.experiences[key]; } return acc; - }, {}), - ...this.actor.system.experiences + }, {}) }; tagifyElement( experienceIncreaseTagify, @@ -198,35 +384,37 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2) this._dragDrop.forEach(d => d.bind(htmlElement)); } - tagifyUpdate = type => async (_, { option, removed }) => { - const updatePath = Object.keys(this.levelup.levels[this.levelup.currentLevel].choices).reduce( - (acc, choiceKey) => { - const choice = this.levelup.levels[this.levelup.currentLevel].choices[choiceKey]; - Object.keys(choice).forEach(checkboxNr => { - const checkbox = choice[checkboxNr]; - if ( - choiceKey === type && - (removed ? checkbox.data.includes(option) : checkbox.data.length < checkbox.amount) - ) { - acc = `levels.${this.levelup.currentLevel}.choices.${choiceKey}.${checkboxNr}.data`; - } - }); + tagifyUpdate = + type => + async (_, { option, removed }) => { + const updatePath = Object.keys(this.levelup.levels[this.levelup.currentLevel].choices).reduce( + (acc, choiceKey) => { + const choice = this.levelup.levels[this.levelup.currentLevel].choices[choiceKey]; + Object.keys(choice).forEach(checkboxNr => { + const checkbox = choice[checkboxNr]; + if ( + choiceKey === type && + (removed ? checkbox.data.includes(option) : checkbox.data.length < checkbox.amount) + ) { + acc = `levels.${this.levelup.currentLevel}.choices.${choiceKey}.${checkboxNr}.data`; + } + }); - return acc; - }, - null - ); + return acc; + }, + null + ); - if (!updatePath) { - ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.noSelectionsLeft')); - return; - } + if (!updatePath) { + ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.noSelectionsLeft')); + return; + } - const currentData = foundry.utils.getProperty(this.levelup, updatePath); - const updatedData = removed ? currentData.filter(x => x !== option) : [...currentData, option]; - await this.levelup.updateSource({ [updatePath]: updatedData }); - this.render(); - }; + const currentData = foundry.utils.getProperty(this.levelup, updatePath); + const updatedData = removed ? currentData.filter(x => x !== option) : [...currentData, option]; + await this.levelup.updateSource({ [updatePath]: updatedData }); + this.render(); + }; static async updateForm(event, _, formData) { const { levelup } = foundry.utils.expandObject(formData.object); @@ -289,7 +477,7 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2) const secondaryData = Object.keys( foundry.utils.getProperty(this.levelup, `${target.dataset.path}.secondaryData`) ).reduce((acc, key) => { - acc[key] = _del; + acc[`-=${key}`] = null; return acc; }, {}); await this.levelup.updateSource({ @@ -323,9 +511,9 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2) const current = foundry.utils.getProperty(this.levelup, `${basePath}.${button.dataset.option}`); if (Number(button.dataset.cost) > 1 || Object.keys(current).length === 1) { // Simple handling that doesn't cover potential Custom LevelTiers. - update[`${basePath}.${button.dataset.option}`] = _del; + update[`${basePath}.-=${button.dataset.option}`] = null; } else { - update[`${basePath}.${button.dataset.option}.${button.dataset.checkboxNr}`] = _del; + update[`${basePath}.${button.dataset.option}.-=${button.dataset.checkboxNr}`] = null; } } else { if (this.levelup.levels[this.levelup.currentLevel].nrSelections.available < Number(button.dataset.cost)) { @@ -405,10 +593,10 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2) const domainCards = this.levelup.levels[this.levelup.currentLevel].achievements.domainCards; const illegalDomainCards = option.secondaryData.domain ? Object.keys(domainCards) - .map(key => ({ ...domainCards[key], key })) - .filter( - x => x.uuid && foundry.utils.fromUuidSync(x.uuid).system.domain === option.secondaryData.domain - ) + .map(key => ({ ...domainCards[key], key })) + .filter( + x => x.uuid && foundry.utils.fromUuidSync(x.uuid).system.domain === option.secondaryData.domain + ) : []; illegalDomainCards.forEach(card => { update[`levels.${this.levelup.currentLevel}.achievements.domainCards.${card.key}.uuid`] = null; diff --git a/module/applications/scene/sceneConfigSettings.mjs b/module/applications/scene/sceneConfigSettings.mjs index 0a999506..57a2bda4 100644 --- a/module/applications/scene/sceneConfigSettings.mjs +++ b/module/applications/scene/sceneConfigSettings.mjs @@ -62,15 +62,7 @@ export default class DhSceneConfigSettings extends foundry.applications.sheets.S } async _onDrop(event) { - event.stopPropagation(); const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event); - if (data.type === 'Level') { - const level = await foundry.documents.Level.fromDropData(data); - if (level?.parent === this.document) return this._onSortLevel(event, level); - - return; - } - const item = await foundry.utils.fromUuid(data.uuid); if (item instanceof game.system.api.documents.DhpActor && item.type === 'environment') { let sceneUuid = data.uuid; @@ -120,6 +112,12 @@ export default class DhSceneConfigSettings extends foundry.applications.sheets.S foundry.utils.fromUuidSync(x) ); + for (const key of Object.keys(this.document._source.flags.daggerheart?.sceneEnvironments ?? {})) { + if (!submitData.flags.daggerheart.sceneEnvironments[key]) { + submitData.flags.daggerheart.sceneEnvironments[`-=${key}`] = null; + } + } + super._processSubmitData(event, form, submitData, options); } } diff --git a/module/applications/settings/appearanceSettings.mjs b/module/applications/settings/appearanceSettings.mjs index 9de9e752..7adf065d 100644 --- a/module/applications/settings/appearanceSettings.mjs +++ b/module/applications/settings/appearanceSettings.mjs @@ -122,7 +122,7 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App type: 'button', action: 'reset', icon: 'fa-solid fa-arrow-rotate-left', - label: game.i18n.localize('SETTINGS.UI.ACTIONS.Reset') + label: game.i18n.localize('Reset') }, { type: 'submit', icon: 'fa-solid fa-floppy-disk', label: game.i18n.localize('EDITOR.Save') } ]; diff --git a/module/applications/settings/homebrewSettings.mjs b/module/applications/settings/homebrewSettings.mjs index c4dfc397..9cc0ecb1 100644 --- a/module/applications/settings/homebrewSettings.mjs +++ b/module/applications/settings/homebrewSettings.mjs @@ -1,5 +1,6 @@ import { DhHomebrew } from '../../data/settings/_module.mjs'; import { Resource } from '../../data/settings/Homebrew.mjs'; +import { slugify } from '../../helpers/utils.mjs'; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; @@ -111,7 +112,7 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli switch (partId) { case 'domains': - const selectedDomain = this.settings.domains[this.selected.domain] ?? null; + const selectedDomain = this.selected.domain ? this.settings.domains[this.selected.domain] : null; const enrichedDescription = selectedDomain ? await foundry.applications.ux.TextEditor.implementation.enrichHTML(selectedDomain.description) : null; @@ -251,8 +252,8 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli const configTitle = isDowntime ? game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.downtimeMove') : type === 'armorFeatures' - ? game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.armorFeature') - : game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.weaponFeature'); + ? game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.armorFeature') + : game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.weaponFeature'); const editedBase = await game.system.api.applications.sheetConfigs.SettingFeatureConfig.configure( configTitle, @@ -297,7 +298,7 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli const isDowntime = ['shortRest', 'longRest'].includes(type); const path = isDowntime ? `restMoves.${type}.moves` : `itemFeatures.${type}`; await this.settings.updateSource({ - [`${path}.${id}`]: _del + [`${path}.-=${id}`]: null }); game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew, this.settings.toObject()); @@ -321,7 +322,7 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli const fields = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).schema.fields; const removeUpdate = Object.keys(this.settings.restMoves[target.dataset.type].moves).reduce((acc, key) => { - acc[key] = _del; + acc[`-=${key}`] = null; return acc; }, {}); @@ -381,7 +382,7 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli [`itemFeatures.${target.dataset.type}`]: Object.keys( this.settings.itemFeatures[target.dataset.type] ).reduce((acc, key) => { - acc[key] = _del; + acc[`-=${key}`] = null; return acc; }, {}) @@ -402,12 +403,12 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli const domainName = button.form.elements.domainName.value; if (!domainName) return; - const newSlug = domainName.slugify(); + const newSlug = slugify(domainName); const existingDomains = [ ...Object.values(this.settings.domains), ...Object.values(CONFIG.DH.DOMAIN.domains) ]; - if (existingDomains.find(x => x.id === newSlug)) { + if (existingDomains.find(x => slugify(game.i18n.localize(x.label)) === newSlug)) { ui.notifications.warn(game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.domains.duplicateDomain')); return; } @@ -454,12 +455,12 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli if (!confirmed) return; await this.settings.updateSource({ - [`domains.${this.selected.domain}`]: _del + [`domains.-=${this.selected.domain}`]: null }); const currentSettings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew); if (currentSettings.domains[this.selected.domain]) { - await currentSettings.updateSource({ [`domains.${this.selected.domain}`]: _del }); + await currentSettings.updateSource({ [`domains.-=${this.selected.domain}`]: null }); await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew, currentSettings); } @@ -506,7 +507,7 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli static async deleteAdversaryType(_, target) { const { key } = target.dataset; - await this.settings.updateSource({ [`adversaryTypes.${key}`]: _del }); + await this.settings.updateSource({ [`adversaryTypes.-=${key}`]: null }); this.selected.adversaryType = this.selected.adversaryType === key ? null : this.selected.adversaryType; this.render(); @@ -528,7 +529,7 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli const identifier = button.form.elements.identifier.value; if (!identifier) return; - const sluggedIdentifier = identifier.slugify(); + const sluggedIdentifier = slugify(identifier); await this.settings.updateSource({ [`resources.${actorType}.resources.${sluggedIdentifier}`]: Resource.getDefaultResourceData(identifier) @@ -562,7 +563,7 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli const { actorType, resourceKey } = target.dataset; await this.settings.updateSource({ - [`resources.${actorType}.resources.${resourceKey}`]: _del + [`resources.${actorType}.resources.-=${resourceKey}`]: null }); game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew, this.settings.toObject()); diff --git a/module/applications/sheets-configs/_module.mjs b/module/applications/sheets-configs/_module.mjs index 9528a424..d3fb3c39 100644 --- a/module/applications/sheets-configs/_module.mjs +++ b/module/applications/sheets-configs/_module.mjs @@ -2,8 +2,8 @@ export { default as ActionConfig } from './action-config.mjs'; export { default as ActionSettingsConfig } from './action-settings-config.mjs'; export { default as CharacterSettings } from './character-settings.mjs'; export { default as AdversarySettings } from './adversary-settings.mjs'; -export { default as NPCSettings } from './npc-settings.mjs'; export { default as CompanionSettings } from './companion-settings.mjs'; +export { default as SettingActiveEffectConfig } from './setting-active-effect-config.mjs'; export { default as SettingFeatureConfig } from './setting-feature-config.mjs'; export { default as EnvironmentSettings } from './environment-settings.mjs'; export { default as ActiveEffectConfig } from './activeEffectConfig.mjs'; diff --git a/module/applications/sheets-configs/action-base-config.mjs b/module/applications/sheets-configs/action-base-config.mjs index b65e1cdf..ce0e7e24 100644 --- a/module/applications/sheets-configs/action-base-config.mjs +++ b/module/applications/sheets-configs/action-base-config.mjs @@ -1,4 +1,3 @@ -import { getUnusedDamageTypes } from '../../helpers/utils.mjs'; import DaggerheartSheet from '../sheets/daggerheart-sheet.mjs'; const { ApplicationV2 } = foundry.applications.api; @@ -36,9 +35,7 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2) editDoc: this.editDoc, addTrigger: this.addTrigger, removeTrigger: this.removeTrigger, - expandTrigger: this.expandTrigger, - addBeastformTraitBonus: this.addBeastformTraitBonus, - removeBeastformTraitBonus: this.removeBeastformTraitBonus + expandTrigger: this.expandTrigger }, form: { handler: this.updateForm, @@ -107,7 +104,7 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2) } }; - static CLEAN_ARRAYS = ['cost', 'effects', 'summon']; + static CLEAN_ARRAYS = ['damage.parts', 'cost', 'effects', 'summon']; _getTabs(tabs) { for (const v of Object.values(tabs)) { @@ -156,13 +153,8 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2) context.openSection = this.openSection; context.tabs = this._getTabs(this.constructor.TABS); context.config = CONFIG.DH; - if (this.action.damage) { - context.allDamageTypesUsed = !getUnusedDamageTypes(this.action.damage.parts).length; - - if (this.action.damage.hasOwnProperty('includeBase') && this.action.type === 'attack') - context.hasBaseDamage = !!this.action.parent.attack; - } - + if (this.action.damage?.hasOwnProperty('includeBase') && this.action.type === 'attack') + context.hasBaseDamage = !!this.action.parent.attack; context.costOptions = this.getCostOptions(); context.getRollTypeOptions = this.getRollTypeOptions(); context.disableOption = this.disableOption.bind(this); @@ -204,7 +196,7 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2) }; } - if (this.action.parent.metadata?.isInventoryItem) { + if (this.action.parent.metadata?.isQuantifiable) { options.quantity = { label: 'DAGGERHEART.GENERAL.itemQuantity', group: 'Global' @@ -264,9 +256,7 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2) key = event.target.closest('[data-key]').dataset.key; if (!this.action[key]) return; - const value = key === 'areas' ? { name: this.action.item.name } : {}; - - data[key].push(this.action.defaultValues[key] ?? value); + data[key].push(this.action.defaultValues[key] ?? {}); this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); } @@ -301,64 +291,18 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2) static addDamage(_event) { if (!this.action.damage.parts) return; - - const choices = getUnusedDamageTypes(this.action._source.damage.parts); - const content = new foundry.data.fields.StringField({ - label: game.i18n.localize('Damage Type'), - choices, - required: true - }).toFormGroup( - {}, - { - name: 'type', - localize: true, - nameAttr: 'value', - labelAttr: 'label' - } - ).outerHTML; - - const callback = (_, button) => { - const data = this.action.toObject(); - const type = choices[button.form.elements.type.value].value; - const part = this.action.schema.fields.damage.fields.parts.element.getInitialValue(); - part.applyTo = type; - if (type === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) - part.type = this.action.schema.fields.damage.fields.parts.element.fields.type.element.initial; - - data.damage.parts[type] = part; - this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); - }; - - const typeDialog = new foundry.applications.api.DialogV2({ - buttons: [ - foundry.utils.mergeObject( - { - action: 'ok', - label: 'Confirm', - icon: 'fas fa-check', - default: true - }, - { callback: callback } - ) - ], - content: content, - rejectClose: false, - modal: false, - window: { - title: game.i18n.localize('Add Damage') - }, - position: { width: 300 } - }); - - typeDialog.render(true); + const data = this.action.toObject(), + part = {}; + if (this.action.actor?.isNPC) part.value = { multiplier: 'flat' }; + data.damage.parts.push(part); + this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); } static removeDamage(_event, button) { if (!this.action.damage.parts) return; - const data = this.action.toObject(); - const key = button.dataset.key; - delete data.damage.parts[key]; - data.damage.parts[`${key}`] = _del; + const data = this.action.toObject(), + index = button.dataset.index; + data.damage.parts.splice(index, 1); this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); } @@ -416,21 +360,6 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2) } } - static async addBeastformTraitBonus() { - const data = this.action.toObject(); - data.beastform.modifications.traitBonuses = [ - ...data.beastform.modifications.traitBonuses, - this.action.schema.fields.beastform.fields.modifications.fields.traitBonuses.element.getInitialValue() - ]; - this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); - } - - static async removeBeastformTraitBonus(_event, button) { - const data = this.action.toObject(); - data.beastform.modifications.traitBonuses.splice(button.dataset.index, 1); - this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); - } - updateSummonCount(event) { event.stopPropagation(); const wrapper = event.target.closest('.summon-count-wrapper'); diff --git a/module/applications/sheets-configs/action-config.mjs b/module/applications/sheets-configs/action-config.mjs index ef529e9b..0dbc377a 100644 --- a/module/applications/sheets-configs/action-config.mjs +++ b/module/applications/sheets-configs/action-config.mjs @@ -19,19 +19,17 @@ export default class DHActionConfig extends DHActionBaseConfig { return context; } - static async addEffect(event) { - const { areaIndex } = event.target.dataset; + static async addEffect(_event) { if (!this.action.effects) return; + const effectData = this._addEffectData.bind(this)(); const data = this.action.toObject(); - const created = await this.action.item.createEmbeddedDocuments('ActiveEffect', [ - game.system.api.data.activeEffects.BaseEffect.getDefaultObject({ transfer: false }) - ]); - - if (areaIndex !== undefined) data.areas[areaIndex].effects.push(created[0]._id); - else data.effects.push({ _id: created[0]._id }); + const [created] = await this.action.item.createEmbeddedDocuments('ActiveEffect', [effectData], { + render: false + }); + data.effects.push({ _id: created._id }); this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); - this.action.item.effects.get(created[0]._id).sheet.render(true); + this.action.item.effects.get(created._id).sheet.render(true); } /** @@ -54,19 +52,9 @@ export default class DHActionConfig extends DHActionBaseConfig { static removeEffect(event, button) { if (!this.action.effects) return; - - const { areaIndex, index } = button.dataset; - let effectId = null; - if (areaIndex !== undefined) { - effectId = this.action.areas[areaIndex].effects[index]; - const data = this.action.toObject(); - data.areas[areaIndex].effects.splice(index, 1); - this.constructor.updateForm.call(this, null, null, { object: foundry.utils.flattenObject(data) }); - } else { + const index = button.dataset.index, effectId = this.action.effects[index]._id; - this.constructor.removeElement.call(this, event, button); - } - + this.constructor.removeElement.bind(this)(event, button); this.action.item.deleteEmbeddedDocuments('ActiveEffect', [effectId]); } diff --git a/module/applications/sheets-configs/action-settings-config.mjs b/module/applications/sheets-configs/action-settings-config.mjs index 24553069..91b85802 100644 --- a/module/applications/sheets-configs/action-settings-config.mjs +++ b/module/applications/sheets-configs/action-settings-config.mjs @@ -31,35 +31,21 @@ export default class DHActionSettingsConfig extends DHActionBaseConfig { } static async addEffect(_event) { - const { areaIndex } = event.target.dataset; if (!this.action.effects) return; - - const effectData = game.system.api.data.activeEffects.BaseEffect.getDefaultObject({ transfer: false }); + const effectData = game.system.api.data.activeEffects.BaseEffect.getDefaultObject(); const data = this.action.toObject(); this.sheetUpdate(data, effectData); this.effects = [...this.effects, effectData]; - - if (areaIndex !== undefined) data.areas[areaIndex].effects.push(effectData.id); - else data.effects.push({ _id: effectData.id }); - + data.effects.push({ _id: effectData.id }); this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); } static removeEffect(event, button) { if (!this.action.effects) return; - const { areaIndex, index } = button.dataset; - let effectId = null; - if (areaIndex !== undefined) { - effectId = this.action.areas[areaIndex].effects[index]; - const data = this.action.toObject(); - data.areas[areaIndex].effects.splice(index, 1); - this.constructor.updateForm.call(this, null, null, { object: foundry.utils.flattenObject(data) }); - } else { + const index = button.dataset.index, effectId = this.action.effects[index]._id; - this.constructor.removeElement.call(this, event, button); - } - + this.constructor.removeElement.bind(this)(event, button); this.sheetUpdate( this.action.toObject(), this.effects.find(x => x.id === effectId), @@ -69,7 +55,7 @@ export default class DHActionSettingsConfig extends DHActionBaseConfig { static async editEffect(event) { const id = event.target.closest('[data-effect-id]')?.dataset?.effectId; - const updatedEffect = await game.system.api.applications.sheetConfigs.ActiveEffectConfig.configureSetting( + const updatedEffect = await game.system.api.applications.sheetConfigs.SettingActiveEffectConfig.configure( this.getEffectDetails(id) ); if (!updatedEffect) return; diff --git a/module/applications/sheets-configs/activeEffectConfig.mjs b/module/applications/sheets-configs/activeEffectConfig.mjs index 2d9eafc3..1f2ba5e0 100644 --- a/module/applications/sheets-configs/activeEffectConfig.mjs +++ b/module/applications/sheets-configs/activeEffectConfig.mjs @@ -18,7 +18,6 @@ export default class DhActiveEffectConfig extends foundry.applications.sheets.Ac settings: { template: 'systems/daggerheart/templates/sheets/activeEffect/settings.hbs' }, changes: { template: 'systems/daggerheart/templates/sheets/activeEffect/changes.hbs', - templates: ['systems/daggerheart/templates/sheets/activeEffect/change.hbs'], scrollable: ['ol[data-changes]'] }, footer: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-form-footer.hbs' } @@ -41,7 +40,7 @@ export default class DhActiveEffectConfig extends foundry.applications.sheets.Ac * @returns {ChangeChoice { value: string, label: string, hint: string, group: string }[]} */ static getChangeChoices() { - const ignoredActorKeys = ['config', 'DhEnvironment', 'DhParty', 'DhNPC']; + const ignoredActorKeys = ['config', 'DhEnvironment', 'DhParty']; const getAllLeaves = (root, group, parentPath = '') => { const leaves = []; @@ -150,18 +149,6 @@ export default class DhActiveEffectConfig extends foundry.applications.sheets.Ac minLength: 0 }); }); - - htmlElement - .querySelector('.stacking-change-checkbox') - ?.addEventListener('change', this.stackingChangeToggle.bind(this)); - - htmlElement - .querySelector('.armor-change-checkbox') - ?.addEventListener('change', this.armorChangeToggle.bind(this)); - - htmlElement - .querySelector('.armor-damage-thresholds-checkbox') - ?.addEventListener('change', this.armorDamageThresholdToggle.bind(this)); } async _prepareContext(options) { @@ -175,7 +162,6 @@ export default class DhActiveEffectConfig extends foundry.applications.sheets.Ac const partContext = await super._preparePartContext(partId, context); switch (partId) { case 'details': - partContext.isItemEffect = partContext.isItemEffect || this.options.isSetting; const useGeneric = game.settings.get( CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance @@ -187,166 +173,8 @@ export default class DhActiveEffectConfig extends foundry.applications.sheets.Ac })); } break; - case 'settings': - const groups = { - time: _loc('EFFECT.DURATION.UNITS.GROUPS.time'), - combat: _loc('EFFECT.DURATION.UNITS.GROUPS.combat') - }; - partContext.durationUnits = CONST.ACTIVE_EFFECT_DURATION_UNITS.map(value => ({ - value, - label: _loc(`EFFECT.DURATION.UNITS.${value}`), - group: CONST.ACTIVE_EFFECT_TIME_DURATION_UNITS.includes(value) ? groups.time : groups.combat - })); - break; - case 'changes': - const singleTypes = ['armor']; - const typedChanges = context.source.changes.reduce((acc, change, index) => { - if (singleTypes.includes(change.type)) { - acc[change.type] = { ...change, index }; - } - return acc; - }, {}); - partContext.changes = partContext.changes.filter(c => !!c); - partContext.typedChanges = typedChanges; - break; } return partContext; } - - stackingChangeToggle(event) { - const stackingFields = this.document.system.schema.fields.stacking.fields; - const systemData = { - stacking: event.target.checked - ? { value: stackingFields.value.initial, max: stackingFields.max.initial } - : null - }; - return this.submit({ updateData: { system: systemData } }); - } - - armorChangeToggle(event) { - if (event.target.checked) { - this.addArmorChange(); - } else { - this.removeTypedChange(event.target.dataset.index); - } - } - - /* Could be generalised if needed later */ - addArmorChange() { - const submitData = this._processFormData(null, this.form, new FormDataExtended(this.form)); - const changes = Object.values(submitData.system?.changes ?? {}); - changes.push(game.system.api.data.activeEffects.changeTypes.armor.getInitialValue()); - return this.submit({ updateData: { system: { changes } } }); - } - - removeTypedChange(indexString) { - const submitData = this._processFormData(null, this.form, new FormDataExtended(this.form)); - const changes = Object.values(submitData.system.changes); - const index = Number(indexString); - changes.splice(index, 1); - return this.submit({ updateData: { system: { changes } } }); - } - - armorDamageThresholdToggle(event) { - const submitData = this._processFormData(null, this.form, new FormDataExtended(this.form)); - const changes = Object.values(submitData.system?.changes ?? {}); - const index = Number(event.target.dataset.index); - if (event.target.checked) { - changes[index].value.damageThresholds = { major: 0, severe: 0 }; - } else { - changes[index].value.damageThresholds = null; - } - - return this.submit({ updateData: { system: { changes } } }); - } - - /** @inheritdoc */ - _renderChange(context) { - const { change, index, defaultPriority } = context; - if (!(change.type in CONFIG.DH.GENERAL.baseActiveEffectModes)) return null; - - const changeTypesSchema = this.document.system.schema.fields.changes.element.types; - const fields = context.fields ?? (changeTypesSchema[change.type] ?? changeTypesSchema.add).fields; - if (typeof change.value !== 'string') change.value = JSON.stringify(change.value); - Object.assign( - change, - ['key', 'type', 'value', 'priority'].reduce((paths, fieldName) => { - paths[`${fieldName}Path`] = `system.changes.${index}.${fieldName}`; - return paths; - }, {}) - ); - return ( - game.system.api.documents.DhActiveEffect.CHANGE_TYPES[change.type].render?.( - change, - index, - defaultPriority - ) ?? - foundry.applications.handlebars.renderTemplate( - 'systems/daggerheart/templates/sheets/activeEffect/change.hbs', - { - change, - index, - defaultPriority, - fields, - types: Object.keys(CONFIG.DH.GENERAL.baseActiveEffectModes).reduce((r, key) => { - r[key] = CONFIG.DH.GENERAL.baseActiveEffectModes[key].label; - return r; - }, {}) - } - ) - ); - } - - /** @inheritDoc */ - _onChangeForm(_formConfig, event) { - if (foundry.utils.isElementInstanceOf(event.target, 'select') && event.target.name === 'system.duration.type') { - const durationSection = this.element.querySelector('.custom-duration-section'); - if (event.target.value === 'custom') durationSection.classList.add('visible'); - else durationSection.classList.remove('visible'); - - const durationDescription = this.element.querySelector('.duration-description'); - if (event.target.value === 'temporary') durationDescription.classList.add('visible'); - else durationDescription.classList.remove('visible'); - } - } - - /** @inheritDoc */ - _processFormData(event, form, formData) { - const submitData = super._processFormData(event, form, formData); - if (submitData.start && !submitData.start.time) submitData.start.time = '0'; - else if (!submitData) submitData.start = null; - - return submitData; - } - - /** @inheritDoc */ - _processSubmitData(event, form, submitData, options) { - if (this.options.isSetting) { - // Settings should update source instead - this.document.updateSource(submitData); - this.render(); - } else { - return super._processSubmitData(event, form, submitData, options); - } - } - - /** Creates an active effect config for a setting */ - static async configureSetting(effect, options = {}) { - const document = new CONFIG.ActiveEffect.documentClass({ ...foundry.utils.duplicate(effect), _id: effect.id }); - return new Promise(resolve => { - const app = new this({ document, ...options, isSetting: true }); - app.addEventListener( - 'close', - () => { - const newEffect = app.document.toObject(true); - newEffect.id = newEffect._id; - delete newEffect._id; - resolve(newEffect); - }, - { once: true } - ); - app.render({ force: true }); - }); - } } diff --git a/module/applications/sheets-configs/adversary-settings.mjs b/module/applications/sheets-configs/adversary-settings.mjs index 57405675..d3d215be 100644 --- a/module/applications/sheets-configs/adversary-settings.mjs +++ b/module/applications/sheets-configs/adversary-settings.mjs @@ -95,7 +95,7 @@ export default class DHAdversarySettings extends DHBaseActorSettings { }); if (!confirmed) return; - await this.actor.update({ [`system.experiences.${target.dataset.experience}`]: _del }); + await this.actor.update({ [`system.experiences.-=${target.dataset.experience}`]: null }); } async _onDragStart(event) { @@ -110,7 +110,6 @@ export default class DHAdversarySettings extends DHBaseActorSettings { } async _onDrop(event) { - event.stopPropagation(); const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event); const item = await fromUuid(data.uuid); diff --git a/module/applications/sheets-configs/character-settings.mjs b/module/applications/sheets-configs/character-settings.mjs index c655b23f..20a09cfc 100644 --- a/module/applications/sheets-configs/character-settings.mjs +++ b/module/applications/sheets-configs/character-settings.mjs @@ -101,8 +101,8 @@ export default class DHCharacterSettings extends DHBaseActorSettings { if (relinkAchievementData.length > 0) { relinkAchievementData.forEach(data => { - updates[`system.levelData.levelups.${data.levelKey}.achievements.experiences.${data.experience}`] = - _del; + updates[`system.levelData.levelups.${data.levelKey}.achievements.experiences.-=${data.experience}`] = + null; }); } else if (relinkSelectionData.length > 0) { relinkSelectionData.forEach(data => { @@ -137,7 +137,7 @@ export default class DHCharacterSettings extends DHBaseActorSettings { await this.actor.update({ ...updates, - [`system.experiences.${target.dataset.experience}`]: _del + [`system.experiences.-=${target.dataset.experience}`]: null }); } } diff --git a/module/applications/sheets-configs/companion-settings.mjs b/module/applications/sheets-configs/companion-settings.mjs index 6c1265af..8aa21479 100644 --- a/module/applications/sheets-configs/companion-settings.mjs +++ b/module/applications/sheets-configs/companion-settings.mjs @@ -117,6 +117,6 @@ export default class DHCompanionSettings extends DHBaseActorSettings { }); if (!confirmed) return; - await this.actor.update({ [`system.experiences.${target.dataset.experience}`]: _del }); + await this.actor.update({ [`system.experiences.-=${target.dataset.experience}`]: null }); } } diff --git a/module/applications/sheets-configs/environment-settings.mjs b/module/applications/sheets-configs/environment-settings.mjs index 6d74f9c6..15f5701d 100644 --- a/module/applications/sheets-configs/environment-settings.mjs +++ b/module/applications/sheets-configs/environment-settings.mjs @@ -68,9 +68,9 @@ export default class DHEnvironmentSettings extends DHBaseActorSettings { */ static async #addCategory() { await this.actor.update({ - [`system.potentialAdversaries.${foundry.utils.randomID()}`]: { - label: game.i18n.localize('DAGGERHEART.ACTORS.Environment.newAdversary') - } + [`system.potentialAdversaries.${foundry.utils.randomID()}.label`]: game.i18n.localize( + 'DAGGERHEART.ACTORS.Environment.newAdversary' + ) }); } @@ -79,7 +79,7 @@ export default class DHEnvironmentSettings extends DHBaseActorSettings { * @type {ApplicationClickAction} */ static async #removeCategory(_, target) { - await this.actor.update({ [`system.potentialAdversaries.${target.dataset.categoryId}`]: _del }); + await this.actor.update({ [`system.potentialAdversaries.-=${target.dataset.categoryId}`]: null }); } /** @@ -121,7 +121,6 @@ export default class DHEnvironmentSettings extends DHBaseActorSettings { } async _onDrop(event) { - event.stopPropagation(); const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event); const item = await fromUuid(data.uuid); if (data.fromInternal && item?.parent?.uuid === this.actor.uuid) return; diff --git a/module/applications/sheets-configs/npc-settings.mjs b/module/applications/sheets-configs/npc-settings.mjs deleted file mode 100644 index c187877c..00000000 --- a/module/applications/sheets-configs/npc-settings.mjs +++ /dev/null @@ -1,85 +0,0 @@ -import DHBaseActorSettings from '../sheets/api/actor-setting.mjs'; - -/**@typedef {import('@client/applications/_types.mjs').ApplicationClickAction} ApplicationClickAction */ - -export default class DHNPCSettings extends DHBaseActorSettings { - /**@inheritdoc */ - static DEFAULT_OPTIONS = { - classes: ['npc-settings'], - position: { width: 455, height: 'auto' }, - actions: {}, - dragDrop: [ - { dragSelector: null, dropSelector: '.tab.features' }, - { dragSelector: '.feature-item', dropSelector: null } - ] - }; - - /**@override */ - static PARTS = { - header: { - id: 'header', - template: 'systems/daggerheart/templates/sheets-settings/npc-settings/header.hbs' - }, - tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' }, - details: { - id: 'details', - template: 'systems/daggerheart/templates/sheets-settings/npc-settings/details.hbs' - }, - features: { - id: 'features', - template: 'systems/daggerheart/templates/sheets-settings/npc-settings/features.hbs' - } - }; - - /** @override */ - static TABS = { - primary: { - tabs: [{ id: 'details' }, { id: 'features' }], - initial: 'details', - labelPrefix: 'DAGGERHEART.GENERAL.Tabs' - } - }; - - async _prepareContext(options) { - const context = await super._prepareContext(options); - - const featureForms = ['passive', 'action', 'reaction']; - context.features = context.document.system.features.sort((a, b) => - a.system.featureForm !== b.system.featureForm - ? featureForms.indexOf(a.system.featureForm) - featureForms.indexOf(b.system.featureForm) - : a.sort - b.sort - ); - - return context; - } - - /* -------------------------------------------- */ - - async _onDragStart(event) { - const featureItem = event.currentTarget.closest('.feature-item'); - - if (featureItem) { - const feature = this.actor.items.get(featureItem.id); - const featureData = { type: 'Item', uuid: feature.uuid, fromInternal: true }; - event.dataTransfer.setData('text/plain', JSON.stringify(featureData)); - event.dataTransfer.setDragImage(featureItem.querySelector('img'), 60, 0); - } - } - - async _onDrop(event) { - event.stopPropagation(); - const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event); - - const item = await fromUuid(data.uuid); - if (item?.type === 'feature') { - if (data.fromInternal && item.parent?.uuid === this.actor.uuid) { - return; - } - - const itemData = item.toObject(); - delete itemData._id; - - await this.actor.createEmbeddedDocuments('Item', [itemData]); - } - } -} diff --git a/module/applications/sheets-configs/setting-active-effect-config.mjs b/module/applications/sheets-configs/setting-active-effect-config.mjs new file mode 100644 index 00000000..12ac90d1 --- /dev/null +++ b/module/applications/sheets-configs/setting-active-effect-config.mjs @@ -0,0 +1,223 @@ +import autocomplete from 'autocompleter'; + +const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; + +export default class SettingActiveEffectConfig extends HandlebarsApplicationMixin(ApplicationV2) { + constructor(effect) { + super({}); + + this.effect = foundry.utils.deepClone(effect); + this.changeChoices = game.system.api.applications.sheetConfigs.ActiveEffectConfig.getChangeChoices(); + } + + static DEFAULT_OPTIONS = { + classes: ['daggerheart', 'sheet', 'dh-style', 'active-effect-config', 'standard-form'], + tag: 'form', + position: { + width: 560 + }, + form: { + submitOnChange: false, + closeOnSubmit: false, + handler: SettingActiveEffectConfig.#onSubmit + }, + actions: { + editImage: SettingActiveEffectConfig.#editImage, + addChange: SettingActiveEffectConfig.#addChange, + deleteChange: SettingActiveEffectConfig.#deleteChange + } + }; + + static PARTS = { + header: { template: 'systems/daggerheart/templates/sheets/activeEffect/header.hbs' }, + tabs: { template: 'templates/generic/tab-navigation.hbs' }, + details: { template: 'systems/daggerheart/templates/sheets/activeEffect/details.hbs', scrollable: [''] }, + settings: { template: 'systems/daggerheart/templates/sheets/activeEffect/settings.hbs' }, + changes: { + template: 'systems/daggerheart/templates/sheets/activeEffect/changes.hbs', + scrollable: ['ol[data-changes]'] + }, + footer: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-form-footer.hbs' } + }; + + static TABS = { + sheet: { + tabs: [ + { id: 'details', icon: 'fa-solid fa-book' }, + { id: 'settings', icon: 'fa-solid fa-bars', label: 'DAGGERHEART.GENERAL.Tabs.settings' }, + { id: 'changes', icon: 'fa-solid fa-gears' } + ], + initial: 'details', + labelPrefix: 'EFFECT.TABS' + } + }; + + /**@inheritdoc */ + async _onFirstRender(context, options) { + await super._onFirstRender(context, options); + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.source = this.effect; + context.fields = game.system.api.documents.DhActiveEffect.schema.fields; + context.systemFields = game.system.api.data.activeEffects.BaseEffect._schema.fields; + + return context; + } + + _attachPartListeners(partId, htmlElement, options) { + super._attachPartListeners(partId, htmlElement, options); + const changeChoices = this.changeChoices; + + htmlElement.querySelectorAll('.effect-change-input').forEach(element => { + autocomplete({ + input: element, + fetch: function (text, update) { + if (!text) { + update(changeChoices); + } else { + text = text.toLowerCase(); + var suggestions = changeChoices.filter(n => n.label.toLowerCase().includes(text)); + update(suggestions); + } + }, + render: function (item, search) { + const label = game.i18n.localize(item.label); + const matchIndex = label.toLowerCase().indexOf(search); + + const beforeText = label.slice(0, matchIndex); + const matchText = label.slice(matchIndex, matchIndex + search.length); + const after = label.slice(matchIndex + search.length, label.length); + + const element = document.createElement('li'); + element.innerHTML = + `${beforeText}${matchText ? `${matchText}` : ''}${after}`.replaceAll( + ' ', + ' ' + ); + if (item.hint) { + element.dataset.tooltip = game.i18n.localize(item.hint); + } + + return element; + }, + renderGroup: function (label) { + const itemElement = document.createElement('div'); + itemElement.textContent = game.i18n.localize(label); + return itemElement; + }, + onSelect: function (item) { + element.value = `system.${item.value}`; + }, + click: e => e.fetch(), + customize: function (_input, _inputRect, container) { + container.style.zIndex = foundry.applications.api.ApplicationV2._maxZ; + }, + minLength: 0 + }); + }); + } + + async _preparePartContext(partId, context) { + if (partId in context.tabs) context.tab = context.tabs[partId]; + switch (partId) { + case 'details': + context.statuses = CONFIG.statusEffects.map(s => ({ value: s.id, label: game.i18n.localize(s.name) })); + context.isActorEffect = false; + context.isItemEffect = true; + const useGeneric = game.settings.get( + CONFIG.DH.id, + CONFIG.DH.SETTINGS.gameSettings.appearance + ).showGenericStatusEffects; + if (!useGeneric) { + context.statuses = [ + ...context.statuses, + Object.values(CONFIG.DH.GENERAL.conditions).map(status => ({ + value: status.id, + label: game.i18n.localize(status.name) + })) + ]; + } + break; + case 'changes': + context.modes = Object.entries(CONST.ACTIVE_EFFECT_MODES).reduce((modes, [key, value]) => { + modes[value] = game.i18n.localize(`EFFECT.MODE_${key}`); + return modes; + }, {}); + + context.priorities = ActiveEffectConfig.DEFAULT_PRIORITIES; + break; + } + + return context; + } + + static async #onSubmit(_event, _form, formData) { + this.data = foundry.utils.expandObject(formData.object); + this.close(); + } + + /** + * Edit a Document image. + * @this {DocumentSheetV2} + * @type {ApplicationClickAction} + */ + static async #editImage(_event, target) { + if (target.nodeName !== 'IMG') { + throw new Error('The editImage action is available only for IMG elements.'); + } + + const attr = target.dataset.edit; + const current = foundry.utils.getProperty(this.effect, attr); + const fp = new FilePicker.implementation({ + current, + type: 'image', + callback: path => (target.src = path), + position: { + top: this.position.top + 40, + left: this.position.left + 10 + } + }); + + await fp.browse(); + } + + /** + * Add a new change to the effect's changes array. + * @this {ActiveEffectConfig} + * @type {ApplicationClickAction} + */ + static async #addChange() { + const { changes, ...rest } = foundry.utils.expandObject(new FormDataExtended(this.form).object); + const updatedChanges = Object.values(changes ?? {}); + updatedChanges.push({}); + + this.effect = { ...rest, changes: updatedChanges }; + this.render(); + } + + /** + * Delete a change from the effect's changes array. + * @this {ActiveEffectConfig} + * @type {ApplicationClickAction} + */ + static async #deleteChange(event) { + const submitData = foundry.utils.expandObject(new FormDataExtended(this.form).object); + const updatedChanges = Object.values(submitData.changes); + const row = event.target.closest('li'); + const index = Number(row.dataset.index) || 0; + updatedChanges.splice(index, 1); + + this.effect = { ...submitData, changes: updatedChanges }; + this.render(); + } + + static async configure(effect, options = {}) { + return new Promise(resolve => { + const app = new this(effect, options); + app.addEventListener('close', () => resolve(app.data), { once: true }); + app.render({ force: true }); + }); + } +} diff --git a/module/applications/sheets-configs/setting-feature-config.mjs b/module/applications/sheets-configs/setting-feature-config.mjs index 531158cd..89421b65 100644 --- a/module/applications/sheets-configs/setting-feature-config.mjs +++ b/module/applications/sheets-configs/setting-feature-config.mjs @@ -147,7 +147,7 @@ export default class SettingFeatureConfig extends HandlebarsApplicationMixin(App const effectIndex = this.move.effects.findIndex(x => x.id === id); const effect = this.move.effects[effectIndex]; const updatedEffect = - await game.system.api.applications.sheetConfigs.ActiveEffectConfig.configureSetting(effect); + await game.system.api.applications.sheetConfigs.SettingActiveEffectConfig.configure(effect); if (!updatedEffect) return; await this.updateMove({ @@ -168,8 +168,8 @@ export default class SettingFeatureConfig extends HandlebarsApplicationMixin(App updatedEffects = deleteEffect ? currentEffects.filter(x => x.id !== effectData.id) : existingEffectIndex === -1 - ? [...currentEffects, effectData] - : currentEffects.with(existingEffectIndex, effectData); + ? [...currentEffects, effectData] + : currentEffects.with(existingEffectIndex, effectData); await this.updateMove({ [`${this.movePath}.effects`]: updatedEffects }); @@ -206,7 +206,7 @@ export default class SettingFeatureConfig extends HandlebarsApplicationMixin(App } }); } else { - await this.updateMove({ [`${this.actionsPath}.${target.dataset.id}`]: _del }); + await this.updateMove({ [`${this.actionsPath}.-=${target.dataset.id}`]: null }); } this.render(); @@ -235,9 +235,9 @@ export default class SettingFeatureConfig extends HandlebarsApplicationMixin(App return this.hasEffects ? tabs : Object.keys(tabs).reduce((acc, key) => { - if (key !== 'effects') acc[key] = tabs[key]; - return acc; - }, {}); + if (key !== 'effects') acc[key] = tabs[key]; + return acc; + }, {}); } /** @override */ diff --git a/module/applications/sheets-configs/token-config-mixin.mjs b/module/applications/sheets-configs/token-config-mixin.mjs index bed7f628..c29b54ff 100644 --- a/module/applications/sheets-configs/token-config-mixin.mjs +++ b/module/applications/sheets-configs/token-config-mixin.mjs @@ -67,9 +67,9 @@ export default function DHTokenConfigMixin(Base) { changes.height = tokenSize; } - // const deletions = { actorId: _del }; - // const mergeOptions = { inplace: false, performDeletions: true, actorLink: false }; - this._preview.updateSource(changes); + const deletions = { '-=actorId': null, '-=actorLink': null }; + const mergeOptions = { inplace: false, performDeletions: true }; + this._preview.updateSource(mergeObject(changes, deletions, mergeOptions)); if (this._preview?.object?.destroyed === false) { this._preview.object.initializeSources(); diff --git a/module/applications/sheets/actors/_module.mjs b/module/applications/sheets/actors/_module.mjs index 1a2bebfb..c4ea2d94 100644 --- a/module/applications/sheets/actors/_module.mjs +++ b/module/applications/sheets/actors/_module.mjs @@ -2,5 +2,4 @@ export { default as Adversary } from './adversary.mjs'; export { default as Character } from './character.mjs'; export { default as Companion } from './companion.mjs'; export { default as Environment } from './environment.mjs'; -export { default as NPC } from './npc.mjs'; export { default as Party } from './party.mjs'; diff --git a/module/applications/sheets/actors/adversary.mjs b/module/applications/sheets/actors/adversary.mjs index 06dd4a0f..04be3efb 100644 --- a/module/applications/sheets/actors/adversary.mjs +++ b/module/applications/sheets/actors/adversary.mjs @@ -31,16 +31,6 @@ export default class AdversarySheet extends DHBaseActorSheet { dragSelector: '[data-item-id][draggable="true"], [data-item-id] [draggable="true"]', dropSelector: null } - ], - contextMenus: [ - { - handler: DHBaseActorSheet.getBaseAttackContextOptions, - selector: '[data-item-uuid][data-type="attack"]', - options: { - parentClassHooks: false, - fixed: true - } - } ] }; diff --git a/module/applications/sheets/actors/character.mjs b/module/applications/sheets/actors/character.mjs index bc2cdb41..14dd1ae7 100644 --- a/module/applications/sheets/actors/character.mjs +++ b/module/applications/sheets/actors/character.mjs @@ -1,9 +1,10 @@ import DHBaseActorSheet from '../api/base-actor.mjs'; import DhDeathMove from '../../dialogs/deathMove.mjs'; +import { abilities } from '../../../config/actorConfig.mjs'; import { CharacterLevelup, LevelupViewMode } from '../../levelup/_module.mjs'; import DhCharacterCreation from '../../characterCreation/characterCreation.mjs'; import FilterMenu from '../../ux/filter-menu.mjs'; -import { getArmorSources, getDocFromElement, getDocFromElementSync, sortBy } from '../../../helpers/utils.mjs'; +import { getDocFromElement, getDocFromElementSync } from '../../../helpers/utils.mjs'; /**@typedef {import('@client/applications/_types.mjs').ApplicationClickAction} ApplicationClickAction */ @@ -12,6 +13,8 @@ export default class CharacterSheet extends DHBaseActorSheet { static DEFAULT_OPTIONS = { classes: ['character'], position: { width: 850, height: 800 }, + /* Foundry adds disabled to all buttons and inputs if editPermission is missing. This is not desired. */ + editPermission: CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER, actions: { toggleVault: CharacterSheet.#toggleVault, rollAttribute: CharacterSheet.#rollAttribute, @@ -32,8 +35,7 @@ export default class CharacterSheet extends DHBaseActorSheet { cancelBeastform: CharacterSheet.#cancelBeastform, toggleResourceManagement: CharacterSheet.#toggleResourceManagement, useDowntime: this.useDowntime, - viewParty: CharacterSheet.#viewParty, - toggleArmorMangement: CharacterSheet.#toggleArmorManagement + viewParty: CharacterSheet.#viewParty }, window: { resizable: true, @@ -57,22 +59,6 @@ export default class CharacterSheet extends DHBaseActorSheet { } ], contextMenus: [ - { - handler: CharacterSheet.#getCreationMainContextOptions, - selector: '.character-details [data-action="editDoc"]', - options: { - parentClassHooks: false, - fixed: true - } - }, - { - handler: DHBaseActorSheet.getBaseAttackContextOptions, - selector: '[data-item-uuid][data-type="attack"]', - options: { - parentClassHooks: false, - fixed: true - } - }, { handler: CharacterSheet.#getDomainCardContextOptions, selector: '[data-item-uuid][data-type="domainCard"]', @@ -82,7 +68,7 @@ export default class CharacterSheet extends DHBaseActorSheet { } }, { - handler: CharacterSheet.#getEquipmentContextOptions, + handler: CharacterSheet.#getEquipamentContextOptions, selector: '[data-item-uuid][data-type="armor"], [data-item-uuid][data-type="weapon"]', options: { parentClassHooks: false, @@ -184,19 +170,6 @@ export default class CharacterSheet extends DHBaseActorSheet { return applicationOptions; } - /** @inheritdoc */ - _toggleDisabled(disabled) { - // Overriden to only disable text inputs by default. - // Everything else is done by checking @root.editable in the sheet - const form = this.form; - for (const input of form.querySelectorAll('input:not([type=search]), .editor.prosemirror')) { - input.disabled = disabled; - } - for (const element of form.querySelectorAll('.input[contenteditable]')) { - element.classList.toggle('disabled', disabled); - } - } - /** @inheritDoc */ async _onRender(context, options) { await super._onRender(context, options); @@ -228,9 +201,8 @@ export default class CharacterSheet extends DHBaseActorSheet { context.attributes = Object.keys(this.document.system.traits).reduce((acc, key) => { acc[key] = { ...this.document.system.traits[key], - label: _loc(CONFIG.DH.ACTOR.abilities[key].label), - verbs: CONFIG.DH.ACTOR.abilities[key].verbs.map(x => game.i18n.localize(x)), - isSpellcasting: this.document.system.spellcastModifierTrait?.key === key + name: game.i18n.localize(CONFIG.DH.ACTOR.abilities[key].name), + verbs: CONFIG.DH.ACTOR.abilities[key].verbs.map(x => game.i18n.localize(x)) }; return acc; @@ -246,11 +218,6 @@ export default class CharacterSheet extends DHBaseActorSheet { context.resources.stress.emptyPips = context.resources.stress.max < maxResource ? maxResource - context.resources.stress.max : 0; - context.equippedItems = sortBy( - this.document.items.filter(i => i.system.equipped && (i.type === 'weapon' || i.usable)), - i => (i.type === 'weapon' ? (i.system.secondary ? 1 : 0) : 2) - ); - context.beastformActive = this.document.effects.find(x => x.type === 'beastform'); return context; @@ -338,56 +305,6 @@ export default class CharacterSheet extends DHBaseActorSheet { /* Context Menu */ /* -------------------------------------------- */ - static #getCreationMainContextOptions() { - /** Returns true if the item is managed by the level up wizard. Such items shouldn't allow things like manual removal */ - function isItemWizardManaged(item) { - const actor = item?.actor; - if (!actor) return false; - - // If levelup automation is off in general or for this character, all items are unmanaged - // This is disabled until we have proper granted feature removal, for now this feature is to correct errors - // const levelupAuto = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).levelupAuto; - // if (!levelupAuto) return false; - - // Core items aren't part of levelup data. TODO: add some way to flag a specific character as no auto leveling - const classPair = actor.system.class; - const coreItems = [actor.system.ancestry, actor.system.community, classPair?.value, classPair?.subclass]; - if (coreItems.includes(item)) return true; - - const levelups = Object.values(actor.system.levelData?.levelups) ?? []; - const uuid = item.uuid; - const sourceUuid = item._stats.compendiumSource; // on older characters this may be missing - return levelups.some(data => { - if (item.type === 'subclass') { - const selectedSubclasses = data.selections.map(s => s.secondaryData?.subclass).filter(s => !!s); - return sourceUuid - ? selectedSubclasses.includes(sourceUuid) - : selectedSubclasses.length && item.system.isMulticlass; - } - - const matchesCard = data.achievements.domainCards.some(i => i.itemUuid === uuid); - const matchesSelection = data.selections.some(s => s.itemUuid === uuid); - return matchesCard || matchesSelection; - }); - } - - return [ - { - label: 'CONTROLS.CommonDelete', - icon: 'fa-solid fa-trash', - visible: target => { - const doc = getDocFromElementSync(target); - return doc?.isOwner && !isItemWizardManaged(doc); - }, - onClick: async (event, target) => { - const doc = await getDocFromElement(target); - if (event.shiftKey) return doc.delete(); - else return doc.deleteDialog(); - } - } - ]; - } - /** * Get the set of ContextMenu options for DomainCards. * @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance @@ -398,13 +315,13 @@ export default class CharacterSheet extends DHBaseActorSheet { /**@type {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} */ const options = [ { - label: 'toLoadout', + name: 'toLoadout', icon: 'fa-solid fa-arrow-up', - visible: target => { + condition: target => { const doc = getDocFromElementSync(target); - return doc?.isOwner && doc.system.inVault; + return doc && doc.system.inVault; }, - onClick: async (_, target) => { + callback: async target => { const doc = await getDocFromElement(target); const actorLoadout = doc.actor.system.loadoutSlot; if (actorLoadout.available) return doc.update({ 'system.inVault': false }); @@ -412,13 +329,13 @@ export default class CharacterSheet extends DHBaseActorSheet { } }, { - label: 'recall', + name: 'recall', icon: 'fa-solid fa-bolt-lightning', - visible: target => { + condition: target => { const doc = getDocFromElementSync(target); - return doc?.isOwner && doc.system.inVault; + return doc && doc.system.inVault; }, - onClick: async (event, target) => { + callback: async (target, event) => { const doc = await getDocFromElement(target); const actorLoadout = doc.actor.system.loadoutSlot; if (!actorLoadout.available) { @@ -451,17 +368,17 @@ export default class CharacterSheet extends DHBaseActorSheet { } }, { - label: 'toVault', + name: 'toVault', icon: 'fa-solid fa-arrow-down', - visible: target => { + condition: target => { const doc = getDocFromElementSync(target); - return doc?.isOwner && !doc.system.inVault; + return doc && !doc.system.inVault; }, - onClick: async (_, target) => (await getDocFromElement(target)).update({ 'system.inVault': true }) + callback: async target => (await getDocFromElement(target)).update({ 'system.inVault': true }) } ].map(option => ({ ...option, - label: `DAGGERHEART.APPLICATIONS.ContextMenu.${option.label}`, + name: `DAGGERHEART.APPLICATIONS.ContextMenu.${option.name}`, icon: `` })); @@ -474,29 +391,29 @@ export default class CharacterSheet extends DHBaseActorSheet { * @this {CharacterSheet} * @protected */ - static #getEquipmentContextOptions() { + static #getEquipamentContextOptions() { const options = [ { - label: 'equip', + name: 'equip', icon: 'fa-solid fa-hands', - visible: target => { + condition: target => { const doc = getDocFromElementSync(target); - return doc.isOwner && doc && !doc.system.equipped; + return doc && !doc.system.equipped; }, - onClick: (event, target) => CharacterSheet.#toggleEquipItem.call(this, event, target) + callback: (target, event) => CharacterSheet.#toggleEquipItem.call(this, event, target) }, { - label: 'unequip', + name: 'unequip', icon: 'fa-solid fa-hands', - visible: target => { + condition: target => { const doc = getDocFromElementSync(target); - return doc.isOwner && doc && doc.system.equipped; + return doc && doc.system.equipped; }, - onClick: (event, target) => CharacterSheet.#toggleEquipItem.call(this, event, target) + callback: (target, event) => CharacterSheet.#toggleEquipItem.call(this, event, target) } ].map(option => ({ ...option, - label: `DAGGERHEART.APPLICATIONS.ContextMenu.${option.label}`, + name: `DAGGERHEART.APPLICATIONS.ContextMenu.${option.name}`, icon: `` })); @@ -722,12 +639,12 @@ export default class CharacterSheet extends DHBaseActorSheet { } async updateArmorMarks(event) { - const inputValue = Number(event.currentTarget.value); - const { value, max } = this.document.system.armorScore; - const changeValue = Math.min(inputValue - value, max - value); + const armor = this.document.system.armor; + if (!armor) return; - event.currentTarget.value = inputValue < 0 ? 0 : value + changeValue; - this.document.system.updateArmorValue({ value: changeValue }); + const maxMarks = this.document.system.armorScore; + const value = Math.min(Math.max(Number(event.currentTarget.value), 0), maxMarks); + await armor.update({ 'system.marks.value': value }); } /* -------------------------------------------- */ @@ -785,11 +702,11 @@ export default class CharacterSheet extends DHBaseActorSheet { filter: key === 'subclasses' ? { - 'system.linkedClass.uuid': { - key: 'system.linkedClass.uuid', - value: this.document.system.class.value?._stats.compendiumSource - } - } + 'system.linkedClass.uuid': { + key: 'system.linkedClass.uuid', + value: this.document.system.class.value._stats.compendiumSource + } + } : undefined, render: { noFolder: true @@ -803,16 +720,35 @@ export default class CharacterSheet extends DHBaseActorSheet { * Rolls an attribute check based on the clicked button's dataset attribute. * @type {ApplicationClickAction} */ - static async #rollAttribute(_event, button) { - const result = await this.document.rollTrait(button.dataset.attribute); + static async #rollAttribute(event, button) { + const abilityLabel = game.i18n.localize(abilities[button.dataset.attribute].label); + const config = { + event: event, + title: `${game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll')}: ${this.actor.name}`, + headerTitle: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', { + ability: abilityLabel + }), + effects: await game.system.api.data.actions.actionsTypes.base.getEffects(this.document), + roll: { + trait: button.dataset.attribute, + type: 'trait' + }, + hasRoll: true, + actionType: 'action', + headerTitle: `${game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll')}: ${this.actor.name}`, + title: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', { + ability: abilityLabel + }) + }; + const result = await this.document.diceRoll(config); if (!result) return; /* This could be avoided by baking config.costs into config.resourceUpdates. Didn't feel like messing with it at the time */ const costResources = result.costs?.filter(x => x.enabled).map(cost => ({ ...cost, value: -cost.value, total: -cost.total })) || {}; - result.resourceUpdates.addResources(costResources); - await result.resourceUpdates.updateResources(); + config.resourceUpdates.addResources(costResources); + await config.resourceUpdates.updateResources(); } //TODO: redo toggleEquipItem method @@ -887,13 +823,10 @@ export default class CharacterSheet extends DHBaseActorSheet { * Toggles ArmorScore resource value. * @type {ApplicationClickAction} */ - static async #toggleArmor(_, button, _element) { - const { value, max } = this.document.system.armorScore; - const inputValue = Number.parseInt(button.dataset.value); - const newValue = value >= inputValue ? inputValue - 1 : inputValue; - const changeValue = Math.min(newValue - value, max - value); - - this.document.system.updateArmorValue({ value: changeValue }); + static async #toggleArmor(_, button, element) { + const ArmorValue = Number.parseInt(button.dataset.value); + const newValue = this.document.system.armor.system.marks.value >= ArmorValue ? ArmorValue - 1 : ArmorValue; + await this.document.system.armor.update({ 'system.marks.value': newValue }); } /** @@ -1019,99 +952,6 @@ export default class CharacterSheet extends DHBaseActorSheet { }); } - static async #toggleArmorManagement(_event, target) { - const existingTooltip = document.body.querySelector('.locked-tooltip .armor-management-container'); - if (existingTooltip) { - game.tooltip.dismissLockedTooltips(); - return; - } - - const armorSources = getArmorSources(this.document) - .filter(s => !s.disabled) - .toReversed() - .map(({ name, document, data }) => ({ - ...data, - uuid: document.uuid, - name - })); - if (!armorSources.length) return; - - const useResourcePips = game.settings.get( - CONFIG.DH.id, - CONFIG.DH.SETTINGS.gameSettings.appearance - ).useResourcePips; - const html = document.createElement('div'); - html.innerHTML = await foundry.applications.handlebars.renderTemplate( - `systems/daggerheart/templates/ui/tooltip/armorManagement.hbs`, - { - sources: armorSources, - useResourcePips - } - ); - - game.tooltip.dismissLockedTooltips(); - game.tooltip.activate(target, { - html, - locked: true, - cssClass: 'bordered-tooltip dh-style', - direction: 'DOWN' - }); - - html.querySelectorAll('.armor-slot').forEach(element => { - element.addEventListener('click', CharacterSheet.armorSourcePipUpdate); - }); - } - - static async armorSourceInput(event) { - const effect = await foundry.utils.fromUuid(event.target.dataset.uuid); - const value = Math.max(Math.min(Number.parseInt(event.target.value), effect.system.armorData.max), 0); - event.target.value = value; - const progressBar = event.target.closest('.status-bar.armor-slots').querySelector('progress'); - progressBar.value = value; - } - - /** Update specific armor source */ - static async armorSourcePipUpdate(event) { - const target = event.target.closest('.armor-slot'); - const { uuid, value } = target.dataset; - const document = await foundry.utils.fromUuid(uuid); - - let inputValue = Number.parseInt(value); - let decreasing = false; - let newCurrent = 0; - - if (document.type === 'armor') { - decreasing = document.system.armor.current >= inputValue; - newCurrent = decreasing ? inputValue - 1 : inputValue; - await document.update({ 'system.armor.current': newCurrent }); - } else if (document.system.armorData) { - const { current } = document.system.armorData; - decreasing = current >= inputValue; - newCurrent = decreasing ? inputValue - 1 : inputValue; - - const newChanges = document.system.changes.map(change => ({ - ...change, - value: change.type === 'armor' ? { ...change.value, current: newCurrent } : change.value - })); - - await document.update({ 'system.changes': newChanges }); - } else { - return; - } - - const container = target.closest('.slot-bar'); - for (const armorSlot of container.querySelectorAll('.armor-slot i')) { - const index = Number.parseInt(armorSlot.dataset.index); - if (decreasing && index >= newCurrent) { - armorSlot.classList.remove('fa-shield'); - armorSlot.classList.add('fa-shield-halved'); - } else if (!decreasing && index < newCurrent) { - armorSlot.classList.add('fa-shield'); - armorSlot.classList.remove('fa-shield-halved'); - } - } - } - static async #toggleResourceManagement(event, button) { event.stopPropagation(); const existingTooltip = document.body.querySelector('.locked-tooltip .resource-management-container'); @@ -1145,11 +985,12 @@ export default class CharacterSheet extends DHBaseActorSheet { ); const target = button.closest('.resource-section'); + game.tooltip.dismissLockedTooltips(); game.tooltip.activate(target, { html, locked: true, - cssClass: 'bordered-tooltip dh-style', + cssClass: 'bordered-tooltip', direction: 'DOWN', noOffset: true }); diff --git a/module/applications/sheets/actors/companion.mjs b/module/applications/sheets/actors/companion.mjs index a01b4a64..b30b9c07 100644 --- a/module/applications/sheets/actors/companion.mjs +++ b/module/applications/sheets/actors/companion.mjs @@ -11,17 +11,7 @@ export default class DhCompanionSheet extends DHBaseActorSheet { toggleStress: DhCompanionSheet.#toggleStress, actionRoll: DhCompanionSheet.#actionRoll, levelManagement: DhCompanionSheet.#levelManagement - }, - contextMenus: [ - { - handler: DHBaseActorSheet.getBaseAttackContextOptions, - selector: '[data-item-uuid][data-type="attack"]', - options: { - parentClassHooks: false, - fixed: true - } - } - ] + } }; static PARTS = { diff --git a/module/applications/sheets/actors/npc.mjs b/module/applications/sheets/actors/npc.mjs deleted file mode 100644 index 8c9048c2..00000000 --- a/module/applications/sheets/actors/npc.mjs +++ /dev/null @@ -1,136 +0,0 @@ -import DHBaseActorSheet from '../api/base-actor.mjs'; - -export default class NPCSheet extends DHBaseActorSheet { - /** @inheritDoc */ - static DEFAULT_OPTIONS = { - classes: ['npc'], - position: { width: 660, height: 600 }, - window: { resizable: true }, - actions: {}, - window: { - resizable: true, - controls: [ - { - icon: 'fa-solid fa-signature', - label: 'DAGGERHEART.UI.Tooltip.configureAttribution', - action: 'editAttribution' - } - ] - }, - dragDrop: [ - { - dragSelector: '[data-item-id][draggable="true"], [data-item-id] [draggable="true"]', - dropSelector: null - } - ] - }; - - static PARTS = { - header: { template: 'systems/daggerheart/templates/sheets/actors/npc/header.hbs' }, - tabs: { template: 'systems/daggerheart/templates/sheets/actors/npc/navigation.hbs' }, - features: { - template: 'systems/daggerheart/templates/sheets/actors/npc/features.hbs', - scrollable: ['.feature-section'] - }, - notes: { - template: 'systems/daggerheart/templates/sheets/actors/npc/notes.hbs' - } - }; - - /** @inheritdoc */ - static TABS = { - primary: { - tabs: [{ id: 'notes' }, { id: 'features' }], - initial: 'notes', - labelPrefix: 'DAGGERHEART.GENERAL.Tabs' - } - }; - - /** @inheritdoc */ - _prepareTabs(group) { - const result = super._prepareTabs(group); - if (group === 'primary') { - result.features.empty = this.document.system.features.length === 0; - } - return result; - } - - /** @inheritdoc */ - async _preparePartContext(partId, context, options) { - context = await super._preparePartContext(partId, context, options); - switch (partId) { - case 'header': - await this._prepareHeaderContext(context, options); - break; - case 'features': - await this._prepareFeaturesContext(context, options); - break; - case 'notes': - await this._prepareNotesContext(context, options); - break; - } - - return context; - } - - /** - * Prepare render context for the Header part. - * @param {ApplicationRenderContext} context - * @param {ApplicationRenderOptions} options - * @returns {Promise} - * @protected - */ - async _prepareHeaderContext(context, _options) { - const { system } = this.document; - const { TextEditor } = foundry.applications.ux; - - context.description = await TextEditor.implementation.enrichHTML(system.description, { - secrets: this.document.isOwner, - relativeTo: this.document - }); - } - - /** - * Prepare render context for the Features part. - * @param {ApplicationRenderContext} context - * @param {ApplicationRenderOptions} options - * @returns {Promise} - * @protected - */ - async _prepareFeaturesContext(context, _options) { - const featureForms = ['passive', 'action', 'reaction']; - context.features = this.document.system.features.sort((a, b) => - a.system.featureForm !== b.system.featureForm - ? featureForms.indexOf(a.system.featureForm) - featureForms.indexOf(b.system.featureForm) - : a.sort - b.sort - ); - } - - /** - * Prepare render context for the Biography part. - * @param {ApplicationRenderContext} context - * @param {ApplicationRenderOptions} options - * @returns {Promise} - * @protected - */ - async _prepareNotesContext(context, _options) { - const { system } = this.document; - const { TextEditor } = foundry.applications.ux; - - const paths = { - notes: 'notes' - }; - - for (const [key, path] of Object.entries(paths)) { - const value = foundry.utils.getProperty(system, path); - context[key] = { - field: system.schema.getField(path), - value, - enriched: await TextEditor.implementation.enrichHTML(value, { - secrets: this.document.isOwner, - relativeTo: this.document - }) - }; - } - } -} diff --git a/module/applications/sheets/actors/party.mjs b/module/applications/sheets/actors/party.mjs index 3af8ea5f..53316c8b 100644 --- a/module/applications/sheets/actors/party.mjs +++ b/module/applications/sheets/actors/party.mjs @@ -1,9 +1,10 @@ import DHBaseActorSheet from '../api/base-actor.mjs'; -import { getDocFromElement, sortBy } from '../../../helpers/utils.mjs'; +import { getDocFromElement } from '../../../helpers/utils.mjs'; import { ItemBrowser } from '../../ui/itemBrowser.mjs'; import FilterMenu from '../../ux/filter-menu.mjs'; import DaggerheartMenu from '../../sidebar/tabs/daggerheartMenu.mjs'; import { socketEvent } from '../../../systemRegistration/socket.mjs'; +import GroupRollDialog from '../../dialogs/group-roll-dialog.mjs'; import DhpActor from '../../../documents/actor.mjs'; export default class Party extends DHBaseActorSheet { @@ -17,15 +18,15 @@ export default class Party extends DHBaseActorSheet { static DEFAULT_OPTIONS = { classes: ['party'], position: { - width: 600, + width: 550, height: 900 }, window: { resizable: true }, actions: { - openDocument: Party.#openDocument, deletePartyMember: Party.#deletePartyMember, + deleteItem: Party.#deleteItem, toggleHope: Party.#toggleHope, toggleHitPoints: Party.#toggleHitPoints, toggleStress: Party.#toggleStress, @@ -34,7 +35,9 @@ export default class Party extends DHBaseActorSheet { refeshActions: Party.#refeshActions, triggerRest: Party.#triggerRest, tagTeamRoll: Party.#tagTeamRoll, - groupRoll: Party.#groupRoll + groupRoll: Party.#groupRoll, + selectRefreshable: DaggerheartMenu.selectRefreshable, + refreshActors: DaggerheartMenu.refreshActors }, dragDrop: [{ dragSelector: '[data-item-id]', dropSelector: null }] }; @@ -43,10 +46,16 @@ export default class Party extends DHBaseActorSheet { static PARTS = { header: { template: 'systems/daggerheart/templates/sheets/actors/party/header.hbs' }, tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' }, - partyMembers: { - template: 'systems/daggerheart/templates/sheets/actors/party/party-members.hbs', + partyMembers: { template: 'systems/daggerheart/templates/sheets/actors/party/party-members.hbs' }, + resources: { + template: 'systems/daggerheart/templates/sheets/actors/party/resources.hbs', scrollable: [''] }, + /* NOT YET IMPLEMENTED */ + // projects: { + // template: 'systems/daggerheart/templates/sheets/actors/party/projects.hbs', + // scrollable: [''] + // }, inventory: { template: 'systems/daggerheart/templates/sheets/actors/party/inventory.hbs', scrollable: ['.tab.inventory .items-section'] @@ -57,13 +66,20 @@ export default class Party extends DHBaseActorSheet { /** @inheritdoc */ static TABS = { primary: { - tabs: [{ id: 'partyMembers' }, { id: 'inventory' }, { id: 'notes' }], + tabs: [ + { id: 'partyMembers' }, + { id: 'resources' }, + /* NOT YET IMPLEMENTED */ + // { id: 'projects' }, + { id: 'inventory' }, + { id: 'notes' } + ], initial: 'partyMembers', labelPrefix: 'DAGGERHEART.GENERAL.Tabs' } }; - static ALLOWED_ACTOR_TYPES = ['character', 'companion', 'adversary', 'npc']; + static ALLOWED_ACTOR_TYPES = ['character', 'companion', 'adversary']; static DICE_ROLL_ACTOR_TYPES = ['character']; async _onRender(context, options) { @@ -76,22 +92,12 @@ export default class Party extends DHBaseActorSheet { /* Prepare Context */ /* -------------------------------------------- */ - async _prepareContext(options) { - const context = await super._prepareContext(options); - const settings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Metagaming); - context.showStats = - settings.hidePartyStats === 'never' || (settings.hidePartyStats === 'players' && game.user.isGM); - return context; - } - async _preparePartContext(partId, context, options) { context = await super._preparePartContext(partId, context, options); switch (partId) { case 'header': await this._prepareHeaderContext(context, options); break; - case 'partyMembers': - await this._prepareMembersContext(context, options); case 'notes': await this._prepareNotesContext(context, options); break; @@ -114,61 +120,6 @@ export default class Party extends DHBaseActorSheet { secrets: this.document.isOwner, relativeTo: this.document }); - context.tagTeamActive = Boolean(this.document.system.tagTeam.initiator); - context.groupRollActive = Boolean(this.document.system.groupRoll.leader); - } - - async _prepareMembersContext(context, _options) { - context.partyMembers = []; - const traits = ['agility', 'strength', 'finesse', 'instinct', 'presence', 'knowledge']; - for (const actor of this.document.system.partyMembers) { - const weapons = []; - if (actor.type === 'character') { - if (actor.system.usedUnarmed) { - weapons.push(actor.system.usedUnarmed); - } - const equipped = actor.items.filter(i => i.system.equipped && i.type === 'weapon'); - weapons.push(...sortBy(equipped, i => (i.system.secondary ? 1 : 0))); - } - - context.partyMembers.push({ - uuid: actor.uuid, - img: actor.img, - name: actor.name, - subtitle: (() => { - if (!['character', 'companion'].includes(actor.type)) { - return game.i18n.format(`TYPES.Actor.${actor.type}`); - } - - const { value: classItem, subclass } = actor.system.class ?? {}; - const partner = actor.system.partner; - const ancestry = actor.system.ancestry; - const community = actor.system.community; - if (partner || (classItem && subclass && ancestry && community)) { - return game.i18n.format(`DAGGERHEART.ACTORS.Party.Subtitle.${actor.type}`, { - class: classItem?.name, - subclass: subclass?.name, - partner: partner?.name, - ancestry: ancestry?.name, - community: community?.name - }); - } - })(), - type: actor.type, - resources: actor.system.resources, - armorScore: actor.system.armorScore, - damageThresholds: actor.system.damageThresholds, - evasion: actor.system.evasion, - difficulty: actor.system.difficulty, - traits: actor.system.traits - ? traits.map(t => ({ - label: game.i18n.localize(`DAGGERHEART.CONFIG.Traits.${t}.short`), - value: actor.system.traits[t].value - })) - : null, - weapons - }); - } } /** @@ -199,12 +150,6 @@ export default class Party extends DHBaseActorSheet { } } - static async #openDocument(_, target) { - const uuid = target.dataset.uuid; - const document = await foundry.utils.fromUuid(uuid); - document?.sheet?.render(true); - } - /** * Toggles a hope resource value. * @type {ApplicationClickAction} @@ -245,14 +190,11 @@ export default class Party extends DHBaseActorSheet { * Toggles a armor slot resource value. * @type {ApplicationClickAction} */ - static async #toggleArmorSlot(_, target) { - const actor = await foundry.utils.fromUuid(target.dataset.actorId); - const { value, max } = actor.system.armorScore; - const inputValue = Number.parseInt(target.dataset.value); - const newValue = value >= inputValue ? inputValue - 1 : inputValue; - const changeValue = Math.min(newValue - value, max - value); - - await actor.system.updateArmorValue({ value: changeValue }); + static async #toggleArmorSlot(_, target, element) { + const armorItem = await foundry.utils.fromUuid(target.dataset.itemUuid); + const armorValue = Number.parseInt(target.dataset.value); + const newValue = armorItem.system.marks.value >= armorValue ? armorValue - 1 : armorValue; + await armorItem.update({ 'system.marks.value': newValue }); this.render(); } @@ -306,18 +248,24 @@ export default class Party extends DHBaseActorSheet { static async downtimeMoveQuery({ actorId, downtimeType }) { const actor = await foundry.utils.fromUuid(actorId); - if (!actor || !actor?.isOwner) return; + if (!actor || !actor?.isOwner) reject(); new game.system.api.applications.dialogs.Downtime(actor, downtimeType === 'shortRest').render({ force: true }); } static async #tagTeamRoll() { - new game.system.api.applications.dialogs.TagTeamDialog(this.document).render({ force: true }); + new game.system.api.applications.dialogs.TagTeamDialog( + this.document.system.partyMembers.filter(x => Party.DICE_ROLL_ACTOR_TYPES.includes(x.type)) + ).render({ + force: true + }); } static async #groupRoll(_params) { - new game.system.api.applications.dialogs.GroupRollDialog(this.document).render({ force: true }); + new GroupRollDialog( + this.document.system.partyMembers.filter(x => Party.DICE_ROLL_ACTOR_TYPES.includes(x.type)) + ).render({ force: true }); } /* -------------------------------------------- */ @@ -479,22 +427,43 @@ export default class Party extends DHBaseActorSheet { } static async #deletePartyMember(event, target) { - const doc = await foundry.utils.fromUuid(target.closest('[data-uuid]')?.dataset.uuid); + const doc = await getDocFromElement(target.closest('.inventory-item')); + if (!event.shiftKey) { const confirmed = await foundry.applications.api.DialogV2.confirm({ window: { - title: game.i18n.format('DAGGERHEART.ACTORS.Party.RemoveConfirmation.title', { + title: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.title', { + type: game.i18n.localize('TYPES.Actor.adversary'), name: doc.name }) }, - content: game.i18n.format('DAGGERHEART.ACTORS.Party.RemoveConfirmation.text', { name: doc.name }) + content: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.text', { name: doc.name }) }); if (!confirmed) return; } const currentMembers = this.document.system.partyMembers.map(x => x.uuid); - const newMembersList = currentMembers.filter(uuid => uuid !== doc.uuid); - await this.document.update({ 'system.partyMembers': newMembersList }); + const newMemberdList = currentMembers.filter(uuid => uuid !== doc.uuid); + await this.document.update({ 'system.partyMembers': newMemberdList }); + } + + static async #deleteItem(event, target) { + const doc = await getDocFromElement(target.closest('.inventory-item')); + if (!event.shiftKey) { + const confirmed = await foundry.applications.api.DialogV2.confirm({ + window: { + title: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.title', { + type: game.i18n.localize('TYPES.Actor.party'), + name: doc.name + }) + }, + content: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.text', { name: doc.name }) + }); + + if (!confirmed) return; + } + + this.document.deleteEmbeddedDocuments('Item', [doc.id]); } } diff --git a/module/applications/sheets/api/application-mixin.mjs b/module/applications/sheets/api/application-mixin.mjs index 63bbb536..baa4d173 100644 --- a/module/applications/sheets/api/application-mixin.mjs +++ b/module/applications/sheets/api/application-mixin.mjs @@ -72,15 +72,20 @@ const typeSettingsMap = { */ export default function DHApplicationMixin(Base) { class DHSheetV2 extends HandlebarsApplicationMixin(Base) { - #nonHeaderAttribution = ['environment', 'ancestry', 'community', 'domainCard']; - /** * @param {DHSheetV2Configuration} [options={}] */ constructor(options = {}) { super(options); + /** + * @type {foundry.applications.ux.DragDrop[]} + * @private + */ + this._dragDrop = this._createDragDropHandlers(); } + #nonHeaderAttribution = ['environment', 'ancestry', 'community', 'domainCard']; + /** * The default options for the sheet. * @type {DHSheetV2Configuration} @@ -89,7 +94,7 @@ export default function DHApplicationMixin(Base) { classes: ['daggerheart', 'sheet', 'dh-style'], actions: { triggerContextMenu: DHSheetV2.#triggerContextMenu, - createDoc: DHSheetV2.#onCreateDoc, + createDoc: DHSheetV2.#createDoc, editDoc: DHSheetV2.#editDoc, deleteDoc: DHSheetV2.#deleteDoc, toChat: DHSheetV2.#toChat, @@ -97,8 +102,8 @@ export default function DHApplicationMixin(Base) { viewItem: DHSheetV2.#viewItem, toggleEffect: DHSheetV2.#toggleEffect, toggleExtended: DHSheetV2.#toggleExtended, - addNewItem: DHSheetV2.#onAddNewItem, - browseItem: DHSheetV2.#onBrowseItem, + addNewItem: DHSheetV2.#addNewItem, + browseItem: DHSheetV2.#browseItem, editAttribution: DHSheetV2.#editAttribution }, contextMenus: [ @@ -172,6 +177,7 @@ export default function DHApplicationMixin(Base) { /**@inheritdoc */ _attachPartListeners(partId, htmlElement, options) { super._attachPartListeners(partId, htmlElement, options); + this._dragDrop.forEach(d => d.bind(htmlElement)); // Handle delta inputs for (const deltaInput of htmlElement.querySelectorAll('input[data-allow-delta]')) { @@ -284,16 +290,6 @@ export default function DHApplicationMixin(Base) { async _onRender(context, options) { await super._onRender(context, options); this._createTagifyElements(this.options.tagifyConfigs); - - for (const d of this.options.dragDrop) { - new foundry.applications.ux.DragDrop.implementation({ - ...d, - callbacks: { - dragstart: this._onDragStart.bind(this), - drop: this._onDrop.bind(this) - } - }).bind(this.element); - } } /* -------------------------------------------- */ @@ -354,6 +350,21 @@ export default function DHApplicationMixin(Base) { /* Drag and Drop */ /* -------------------------------------------- */ + /** + * Creates drag-drop handlers from the configured options. + * @returns {foundry.applications.ux.DragDrop[]} + * @private + */ + _createDragDropHandlers() { + return this.options.dragDrop.map(d => { + d.callbacks = { + dragstart: this._onDragStart.bind(this), + drop: this._onDrop.bind(this) + }; + return new foundry.applications.ux.DragDrop.implementation(d); + }); + } + /** * Handle dragStart event. * @param {DragEvent} event @@ -418,26 +429,26 @@ export default function DHApplicationMixin(Base) { /**@type {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} */ const options = [ { - label: 'disableEffect', + name: 'disableEffect', icon: 'fa-solid fa-lightbulb', - visible: element => { + condition: element => { const target = element.closest('[data-item-uuid]'); return !target.dataset.disabled && target.dataset.itemType !== 'beastform'; }, - onClick: async (_, target) => (await getDocFromElement(target)).update({ disabled: true }) + callback: async target => (await getDocFromElement(target)).update({ disabled: true }) }, { - label: 'enableEffect', + name: 'enableEffect', icon: 'fa-regular fa-lightbulb', - visible: element => { + condition: element => { const target = element.closest('[data-item-uuid]'); return target.dataset.disabled && target.dataset.itemType !== 'beastform'; }, - onClick: async (_, target) => (await getDocFromElement(target)).update({ disabled: false }) + callback: async target => (await getDocFromElement(target)).update({ disabled: false }) } ].map(option => ({ ...option, - label: `DAGGERHEART.APPLICATIONS.ContextMenu.${option.label}`, + name: `DAGGERHEART.APPLICATIONS.ContextMenu.${option.name}`, icon: `` })); @@ -468,34 +479,29 @@ export default function DHApplicationMixin(Base) { _getContextMenuCommonOptions({ usable = false, toChat = false, deletable = true }) { const options = [ { - label: 'CONTROLS.CommonEdit', + name: 'CONTROLS.CommonEdit', icon: 'fa-solid fa-pen-to-square', - visible: target => { + condition: target => { const { dataset } = target.closest('[data-item-uuid]'); const doc = getDocFromElementSync(target); return ( (!dataset.noCompendiumEdit && !doc) || - (doc?.isOwner && (!doc?.hasOwnProperty('systemPath') || doc?.inCollection)) + (doc && (!doc?.hasOwnProperty('systemPath') || doc?.inCollection)) ); }, - onClick: async (_, target) => { - return (await getDocFromElement(target)).sheet.render({ force: true }); - } + callback: async target => (await getDocFromElement(target)).sheet.render({ force: true }) } ]; if (usable) { options.unshift({ - label: 'DAGGERHEART.GENERAL.damage', + name: 'DAGGERHEART.GENERAL.damage', icon: 'fa-solid fa-explosion', - visible: target => { + condition: target => { const doc = getDocFromElementSync(target); - const hasDamage = - !foundry.utils.isEmpty(doc?.system?.attack?.damage.parts) || - !foundry.utils.isEmpty(doc?.damage?.parts); - return doc?.isOwner && hasDamage; + return doc?.system?.attack?.damage.parts.length || doc?.damage?.parts.length; }, - onClick: async (event, target) => { + callback: async (target, event) => { const doc = await getDocFromElement(target), action = doc?.system?.attack ?? doc; const config = action.prepareConfig(event); @@ -509,33 +515,32 @@ export default function DHApplicationMixin(Base) { }); options.unshift({ - label: 'DAGGERHEART.APPLICATIONS.ContextMenu.useItem', + name: 'DAGGERHEART.APPLICATIONS.ContextMenu.useItem', icon: 'fa-solid fa-burst', - visible: target => { + condition: target => { const doc = getDocFromElementSync(target); - return doc?.isOwner && !(doc.type === 'domainCard' && doc.system.inVault); + return doc && !(doc.type === 'domainCard' && doc.system.inVault); }, - onClick: async (event, target) => (await getDocFromElement(target)).use(event) + callback: async (target, event) => (await getDocFromElement(target)).use(event) }); } if (toChat) options.push({ - label: 'DAGGERHEART.APPLICATIONS.ContextMenu.sendToChat', + name: 'DAGGERHEART.APPLICATIONS.ContextMenu.sendToChat', icon: 'fa-solid fa-message', - onClick: async (_, target) => (await getDocFromElement(target)).toChat(this.document.uuid) + callback: async target => (await getDocFromElement(target)).toChat(this.document.uuid) }); if (deletable) options.push({ - label: 'CONTROLS.CommonDelete', + name: 'CONTROLS.CommonDelete', icon: 'fa-solid fa-trash', - visible: element => { + condition: element => { const target = element.closest('[data-item-uuid]'); - const doc = getDocFromElementSync(target); - return doc?.isOwner !== false && target.dataset.itemType !== 'beastform'; + return target.dataset.itemType !== 'beastform'; }, - onClick: async (event, target) => { + callback: async (target, event) => { const doc = await getDocFromElement(target); if (event.shiftKey) return doc.delete(); else return doc.deleteDialog(); @@ -641,7 +646,7 @@ export default function DHApplicationMixin(Base) { /* Application Clicks Actions */ /* -------------------------------------------- */ - static async #onAddNewItem(event, target) { + static async #addNewItem(event, target) { const createChoice = await foundry.applications.api.DialogV2.wait({ classes: ['dh-style', 'two-big-buttons'], buttons: [ @@ -660,11 +665,11 @@ export default function DHApplicationMixin(Base) { if (!createChoice) return; - if (createChoice === 'browse') return DHSheetV2.#onBrowseItem.call(this, event, target); - else return DHSheetV2.#onCreateDoc.call(this, event, target); + if (createChoice === 'browse') return DHSheetV2.#browseItem.call(this, event, target); + else return DHSheetV2.#createDoc.call(this, event, target); } - static async #onBrowseItem(_event, target) { + static async #browseItem(event, target) { const type = target.dataset.compendium ?? target.dataset.type; const presets = { @@ -715,17 +720,17 @@ export default function DHApplicationMixin(Base) { * Create an embedded document. * @type {ApplicationClickAction} */ - static async #onCreateDoc(event, target) { + static async #createDoc(event, target) { const { documentClass, type, inVault, disabled } = target.dataset; const parentIsItem = this.document.documentName === 'Item'; const featureOnCharacter = this.document.parent?.type === 'character' && type === 'feature'; const parent = featureOnCharacter ? this.document.parent : parentIsItem && documentClass === 'Item' - ? type === 'action' - ? this.document.system - : null - : this.document; + ? type === 'action' + ? this.document.system + : null + : this.document; let systemData = {}; if (featureOnCharacter) { @@ -737,21 +742,15 @@ export default function DHApplicationMixin(Base) { const cls = type === 'action' ? game.system.api.models.actions.actionsTypes.base : getDocumentClass(documentClass); - const data = { name: cls.defaultName({ type, parent }), type, system: systemData }; + if (inVault) data['system.inVault'] = true; if (disabled) data.disabled = true; - - if (type === 'domainCard') { - if (parent?.system.domains?.length) data.system.domain = parent.system.domains[0]; - if (inVault) data.system.inVault = true; - } else if (type === 'weapon') { - // Passing an empty system object to weapon causes validation failure due to attack action initialization - // todo: determine why, fix it at its source, then remove this fallback - delete data.system; + if (type === 'domainCard' && parent?.system.domains?.length) { + data.system.domain = parent.system.domains[0]; } const doc = await cls.create(data, { parent, renderSheet: !event.shiftKey }); diff --git a/module/applications/sheets/api/base-actor.mjs b/module/applications/sheets/api/base-actor.mjs index 812ad311..6f994faf 100644 --- a/module/applications/sheets/api/base-actor.mjs +++ b/module/applications/sheets/api/base-actor.mjs @@ -73,7 +73,7 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) { .hideAttribution; // Prepare inventory data - if (this.document.system.metadata.hasInventory) { + if (['party', 'character'].includes(this.document.type)) { context.inventory = { currencies: {}, weapons: this.document.itemTypes.weapon.sort((a, b) => a.sort - b.sort), @@ -160,21 +160,12 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) { inactives: [] }; - for (const effect of this.actor.allApplicableEffects({ noTransferArmor: true })) { + for (const effect of this.actor.allApplicableEffects()) { const list = effect.active ? context.effects.actives : context.effects.inactives; list.push(effect); } } - /** Add support for input content editables */ - _toggleDisabled(disabled) { - super._toggleDisabled(disabled); - const form = this.form; - for (const element of form.querySelectorAll('.input[contenteditable]')) { - element.classList.toggle('disabled', disabled); - } - } - /* -------------------------------------------- */ /* Context Menu */ /* -------------------------------------------- */ @@ -189,43 +180,6 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) { return this._getContextMenuCommonOptions.call(this, { usable: true, toChat: true }); } - /** - * Get the set of ContextMenu options for the base attack. - * @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance - * @this {CharacterSheet} - * @protected - */ - static getBaseAttackContextOptions() { - /**@type {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} */ - return [ - { - label: 'DAGGERHEART.CONFIG.RollTypes.attack.name', - icon: 'fa-solid fa-burst', - onClick: async (event, target) => (await getDocFromElement(target)).use(event) - }, - { - label: 'DAGGERHEART.GENERAL.damage', - icon: 'fa-solid fa-explosion', - onClick: async (event, target) => { - const doc = await getDocFromElement(target), - action = doc?.system?.attack ?? doc; - const config = action.prepareConfig(event); - config.effects = await game.system.api.data.actions.actionsTypes.base.getEffects( - this.document, - doc - ); - config.hasRoll = false; - return action && action.workflow.get('damage').execute(config, null, true); - } - }, - { - label: 'DAGGERHEART.APPLICATIONS.ContextMenu.sendToChat', - icon: 'fa-solid fa-message', - onClick: async (_, target) => (await getDocFromElement(target)).toChat(this.document.uuid) - } - ]; - } - /* -------------------------------------------- */ /* Application Listener Actions */ /* -------------------------------------------- */ @@ -274,6 +228,7 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) { 'systems/daggerheart/templates/ui/chat/action.hbs', systemData ), + title: game.i18n.localize('DAGGERHEART.ACTIONS.Config.displayInChat'), speaker: cls.getSpeaker(), flags: { daggerheart: { @@ -329,7 +284,11 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) { async _onDropItem(event, item) { const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event); const originActor = item.actor; - if (!originActor || originActor.uuid === this.document.uuid || !this.document.system.metadata.hasInventory) { + if ( + item.actor?.uuid === this.document.uuid || + !originActor || + !['character', 'party'].includes(this.document.type) + ) { return super._onDropItem(event, item); } @@ -344,79 +303,47 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) { ); } - // Perform the actual transfer, showing a dialog when doing it - const availableQuantity = Math.max(1, item.system.quantity); - const actorItem = originActor.items.get(data.originId) ?? item; - if (availableQuantity > 1) { - const quantityTransferred = await game.system.api.applications.dialogs.ItemTransferDialog.configure({ + if (item.system.metadata.isQuantifiable) { + const actorItem = originActor.items.get(data.originId); + const quantityTransfered = await game.system.api.applications.dialogs.ItemTransferDialog.configure({ item, targetActor: this.document }); - return this.#transferItem(actorItem, quantityTransferred); + + if (quantityTransfered) { + const existingItem = this.document.items.find(x => itemIsIdentical(x, item)); + if (existingItem) { + await existingItem.update({ + 'system.quantity': existingItem.system.quantity + quantityTransfered + }); + } else { + const createData = item.toObject(); + await this.document.createEmbeddedDocuments('Item', [ + { + ...createData, + system: { + ...createData.system, + quantity: quantityTransfered + } + } + ]); + } + + if (quantityTransfered === actorItem.system.quantity) { + await originActor.deleteEmbeddedDocuments('Item', [data.originId]); + } else { + await actorItem.update({ + 'system.quantity': actorItem.system.quantity - quantityTransfered + }); + } + } } else { - return this.#transferItem(actorItem, availableQuantity); + await this.document.createEmbeddedDocuments('Item', [item.toObject()]); + await originActor.deleteEmbeddedDocuments('Item', [data.originId]); } } } - /** - * Helper to perform the actual transfer of an item to this actor, including stack/unstack logic based on target quantifiability. - * Make sure item is the actor item before calling this method or there will be issues - */ - async #transferItem(item, quantity) { - const originActor = item.actor; - const targetActor = this.document; - const allowStacking = targetActor.system.metadata.quantifiable?.includes(item.type); - - const batch = []; - - // First add/update the item to the target actor - const existing = allowStacking ? targetActor.items.find(x => itemIsIdentical(x, item)) : null; - if (existing) { - batch.push({ - action: 'update', - documentName: 'Item', - parent: targetActor, - updates: [{ _id: existing.id, 'system.quantity': existing.system.quantity + quantity }] - }); - } else { - const itemsToCreate = []; - if (allowStacking) { - itemsToCreate.push(foundry.utils.mergeObject(item.toObject(true), { system: { quantity } })); - } else { - const createData = new Array(Math.max(1, quantity)) - .fill(0) - .map(() => foundry.utils.mergeObject(item.toObject(), { system: { quantity: 1 } })); - itemsToCreate.push(...createData); - } - batch.push({ - action: 'create', - documentName: 'Item', - parent: targetActor, - data: itemsToCreate - }); - } - - // Remove the item from the original actor (by either deleting it, or updating its quantity) - if (quantity >= item.system.quantity) { - batch.push({ - action: 'delete', - documentName: 'Item', - parent: originActor, - ids: [item.id] - }); - } else { - batch.push({ - action: 'update', - documentName: 'Item', - parent: originActor, - updates: [{ _id: item.id, 'system.quantity': item.system.quantity - quantity }] - }); - } - - return foundry.documents.modifyBatch(batch); - } - /** * On dragStart on the item. * @param {DragEvent} event - The drag event diff --git a/module/applications/sheets/api/base-item.mjs b/module/applications/sheets/api/base-item.mjs index 1e08fc05..e3568b23 100644 --- a/module/applications/sheets/api/base-item.mjs +++ b/module/applications/sheets/api/base-item.mjs @@ -126,7 +126,7 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) { options.push({ name: 'CONTROLS.CommonDelete', icon: '', - onClick: async (_, target) => { + callback: async target => { const feature = await getDocFromElement(target); if (!feature) return; const confirmed = await foundry.applications.api.DialogV2.confirm({ diff --git a/module/applications/sheets/api/item-attachment-sheet.mjs b/module/applications/sheets/api/item-attachment-sheet.mjs index ea4d5352..bcf2fc3c 100644 --- a/module/applications/sheets/api/item-attachment-sheet.mjs +++ b/module/applications/sheets/api/item-attachment-sheet.mjs @@ -29,6 +29,16 @@ export default function ItemAttachmentSheet(Base) { } }; + async _preparePartContext(partId, context) { + await super._preparePartContext(partId, context); + + if (partId === 'attachments') { + context.attachedItems = await prepareAttachmentContext(this.document); + } + + return context; + } + async _onDrop(event) { const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event); diff --git a/module/applications/sheets/items/ancestry.mjs b/module/applications/sheets/items/ancestry.mjs index cf040e02..8c0a5620 100644 --- a/module/applications/sheets/items/ancestry.mjs +++ b/module/applications/sheets/items/ancestry.mjs @@ -31,12 +31,11 @@ export default class AncestrySheet extends DHHeritageSheet { if (data.type === 'ActiveEffect') return super._onDrop(event); const target = event.target.closest('fieldset.drop-section'); - if (target) { - const typeField = - this.document.system[target.dataset.type === 'primary' ? 'primaryFeature' : 'secondaryFeature']; - if (!typeField) { - super._onDrop(event); - } + const typeField = + this.document.system[target.dataset.type === 'primary' ? 'primaryFeature' : 'secondaryFeature']; + + if (!typeField) { + super._onDrop(event); } } } diff --git a/module/applications/sheets/items/armor.mjs b/module/applications/sheets/items/armor.mjs index 54685fee..2550b415 100644 --- a/module/applications/sheets/items/armor.mjs +++ b/module/applications/sheets/items/armor.mjs @@ -47,15 +47,6 @@ export default class ArmorSheet extends ItemAttachmentSheet(DHBaseItemSheet) { return context; } - async updateArmorEffect(event) { - const value = Number.parseInt(event.target.value); - const armorEffect = this.document.system.armorEffect; - if (Number.isNaN(value) || !armorEffect) return; - - await armorEffect.system.armorChange.updateArmorMax(value); - this.render(); - } - /** * Callback function used by `tagifyElement`. * @param {Array} selectedOptions - The currently selected tag objects. diff --git a/module/applications/sheets/items/beastform.mjs b/module/applications/sheets/items/beastform.mjs index 0c9991c4..880c0796 100644 --- a/module/applications/sheets/items/beastform.mjs +++ b/module/applications/sheets/items/beastform.mjs @@ -102,7 +102,7 @@ export default class BeastformSheet extends DHBaseItemSheet { async advantageOnRemove(event) { await this.document.update({ - [`system.advantageOn.${event.detail.data.value}`]: _del + [`system.advantageOn.-=${event.detail.data.value}`]: null }); } } diff --git a/module/applications/sheets/items/class.mjs b/module/applications/sheets/items/class.mjs index 25c631fe..05bb0229 100644 --- a/module/applications/sheets/items/class.mjs +++ b/module/applications/sheets/items/class.mjs @@ -104,10 +104,9 @@ export default class ClassSheet extends DHBaseItemSheet { } /**@inheritdoc */ - async _prepareContext(options) { - const context = await super._prepareContext(options); + async _prepareContext(_options) { + const context = await super._prepareContext(_options); context.domains = this.document.system.domains; - context.subclasses = await this.document.system.fetchSubclasses(); return context; } @@ -129,8 +128,20 @@ export default class ClassSheet extends DHBaseItemSheet { const item = await fromUuid(data.uuid); const itemType = data.type === 'ActiveEffect' ? data.type : item.type; const target = event.target.closest('fieldset.drop-section'); - - if (['feature', 'ActiveEffect'].includes(itemType)) { + if (itemType === 'subclass') { + if (item.system.linkedClass) { + return ui.notifications.warn( + game.i18n.format('DAGGERHEART.UI.Notifications.subclassAlreadyLinked', { + name: item.name, + class: this.document.name + }) + ); + } + await item.update({ 'system.linkedClass': this.document.uuid }); + await this.document.update({ + 'system.subclasses': [...this.document.system.subclasses.map(x => x.uuid), item.uuid] + }); + } else if (['feature', 'ActiveEffect'].includes(itemType)) { super._onDrop(event); } else if (this.document.parent?.type !== 'character') { if (itemType === 'weapon') { @@ -189,6 +200,12 @@ export default class ClassSheet extends DHBaseItemSheet { static async #removeItemFromCollection(_event, element) { const { uuid, target } = element.dataset; const prop = foundry.utils.getProperty(this.document.system, target); + + if (target === 'subclasses') { + const subclass = await foundry.utils.fromUuid(uuid); + await subclass?.update({ 'system.linkedClass': null }); + } + await this.document.update({ [`system.${target}`]: prop.filter(i => i && i.uuid !== uuid).map(x => x.uuid) }); } diff --git a/module/applications/sheets/items/feature.mjs b/module/applications/sheets/items/feature.mjs index 7f9028d5..6ff98ca7 100644 --- a/module/applications/sheets/items/feature.mjs +++ b/module/applications/sheets/items/feature.mjs @@ -31,7 +31,7 @@ export default class FeatureSheet extends DHBaseItemSheet { labelPrefix: 'DAGGERHEART.GENERAL.Tabs' } }; - //Might be wrong location but testing out if here is okay. +//Might be wrong location but testing out if here is okay. /**@override */ async _prepareContext(options) { const context = await super._prepareContext(options); diff --git a/module/applications/sheets/items/subclass.mjs b/module/applications/sheets/items/subclass.mjs index e9d8370e..5c731777 100644 --- a/module/applications/sheets/items/subclass.mjs +++ b/module/applications/sheets/items/subclass.mjs @@ -40,36 +40,4 @@ export default class SubclassSheet extends DHBaseItemSheet { get relatedDocs() { return this.document.system.features.map(x => x.item); } - - async _prepareContext(options) { - const context = await super._prepareContext(options); - if (this.document.system.linkedClass) { - const classData = await fromUuid(this.document.system.linkedClass); - context.class = classData ?? { - name: _loc('DAGGERHEART.GENERAL.missingX', { x: _loc('TYPES.Item.class') }), - missing: true - }; - } - return context; - } - - async _onDrop(event) { - event.stopPropagation(); - const data = TextEditor.getDragEventData(event); - const item = await fromUuid(data.uuid); - const itemType = data.type === 'ActiveEffect' ? data.type : item.type; - if (itemType === 'class') { - const uuid = item._stats.compendiumSource ?? item.uuid; - if (this.document.system.linkedClass !== uuid) { - await this.document.update({ 'system.linkedClass': uuid }); - // Re-render all class sheets for instant feedback - for (const app of foundry.applications.instances.values()) { - if (app.document?.type === 'class') app.render(); - } - } - return; - } - - return super._onDrop(event); - } } diff --git a/module/applications/sheets/rollTables/rollTable.mjs b/module/applications/sheets/rollTables/rollTable.mjs index d7498e80..9ead6814 100644 --- a/module/applications/sheets/rollTables/rollTable.mjs +++ b/module/applications/sheets/rollTables/rollTable.mjs @@ -108,15 +108,14 @@ export default class DhRollTableSheet extends foundry.applications.sheets.RollTa getSystemFlagUpdate() { const deleteUpdate = Object.keys(this.document._source.flags.daggerheart?.altFormula ?? {}).reduce( (acc, formulaKey) => { - if (!this.daggerheartFlag.altFormula[formulaKey]) acc.altFormula[formulaKey] = _del; + if (!this.daggerheartFlag.altFormula[formulaKey]) acc.altFormula[`-=${formulaKey}`] = null; return acc; }, { altFormula: {} } ); - const flagData = this.daggerheartFlag.toObject(); - return { ...flagData, altFormula: { ...flagData.altFormula, ...deleteUpdate.altFormula } }; + return { ['flags.daggerheart']: foundry.utils.mergeObject(this.daggerheartFlag.toObject(), deleteUpdate) }; } static async #addFormula() { @@ -128,7 +127,7 @@ export default class DhRollTableSheet extends foundry.applications.sheets.RollTa static async #removeFormula(_event, target) { await this.daggerheartFlag.updateSource({ - [`altFormula.${target.dataset.key}`]: _del + [`altFormula.-=${target.dataset.key}`]: null }); this.render({ internalRefresh: true }); } diff --git a/module/applications/sidebar/sidebar.mjs b/module/applications/sidebar/sidebar.mjs index 64f7473d..ab6b0cdb 100644 --- a/module/applications/sidebar/sidebar.mjs +++ b/module/applications/sidebar/sidebar.mjs @@ -1,19 +1,52 @@ export default class DhSidebar extends foundry.applications.sidebar.Sidebar { - static buildTabs() { - const { settings, ...tabs } = super.TABS; - return { - ...tabs, - daggerheartMenu: { - tooltip: 'DAGGERHEART.UI.Sidebar.daggerheartMenu.title', - img: 'systems/daggerheart/assets/logos/FoundryBorneLogoWhite.svg', - gmOnly: true - }, - settings - }; - } - /** @override */ - static TABS = DhSidebar.buildTabs(); + static TABS = { + chat: { + documentName: 'ChatMessage' + }, + combat: { + documentName: 'Combat' + }, + scenes: { + documentName: 'Scene', + gmOnly: true + }, + actors: { + documentName: 'Actor' + }, + items: { + documentName: 'Item' + }, + journal: { + documentName: 'JournalEntry', + tooltip: 'SIDEBAR.TabJournal' + }, + tables: { + documentName: 'RollTable' + }, + cards: { + documentName: 'Cards' + }, + macros: { + documentName: 'Macro' + }, + playlists: { + documentName: 'Playlist' + }, + compendium: { + tooltip: 'SIDEBAR.TabCompendium', + icon: 'fa-solid fa-book-atlas' + }, + daggerheartMenu: { + tooltip: 'DAGGERHEART.UI.Sidebar.daggerheartMenu.title', + img: 'systems/daggerheart/assets/logos/FoundryBorneLogoWhite.svg', + gmOnly: true + }, + settings: { + tooltip: 'SIDEBAR.TabSettings', + icon: 'fa-solid fa-gears' + } + }; /** @override */ static PARTS = { diff --git a/module/applications/sidebar/tabs/actorDirectory.mjs b/module/applications/sidebar/tabs/actorDirectory.mjs index a6f48b54..e9484553 100644 --- a/module/applications/sidebar/tabs/actorDirectory.mjs +++ b/module/applications/sidebar/tabs/actorDirectory.mjs @@ -13,8 +13,8 @@ export default class DhActorDirectory extends foundry.applications.sidebar.tabs. return document.type === 'adversary' ? game.i18n.localize(adversaryTypes[document.system.type]?.label ?? 'TYPES.Actor.adversary') : document.type === 'environment' - ? game.i18n.localize(environmentTypes[document.system.type]?.label ?? 'TYPES.Actor.environment') - : null; + ? game.i18n.localize(environmentTypes[document.system.type]?.label ?? 'TYPES.Actor.environment') + : null; }; } @@ -46,67 +46,50 @@ export default class DhActorDirectory extends foundry.applications.sidebar.tabs. _getEntryContextOptions() { const options = super._getEntryContextOptions(); - options.push( - { - label: 'DAGGERHEART.UI.Sidebar.actorDirectory.duplicateToNewTier', - icon: ``, - visible: li => { - const actor = game.actors.get(li.dataset.entryId); - return actor?.type === 'adversary' && actor.system.type !== 'social'; - }, - callback: async li => { - const actor = game.actors.get(li.dataset.entryId); - if (!actor) throw new Error('Unexpected missing actor'); - - const tiers = [1, 2, 3, 4].filter(t => t !== actor.system.tier); - const content = document.createElement('div'); - const select = document.createElement('select'); - select.name = 'tier'; - select.append( - ...tiers.map(t => { - const option = document.createElement('option'); - option.value = t; - option.textContent = game.i18n.localize(`DAGGERHEART.GENERAL.Tiers.${t}`); - return option; - }) - ); - content.append(select); - - const tier = await foundry.applications.api.Dialog.input({ - classes: ['dh-style', 'dialog'], - window: { title: 'DAGGERHEART.UI.Sidebar.actorDirectory.pickTierTitle' }, - content, - ok: { - label: 'DAGGERHEART.UI.Sidebar.actorDirectory.createAdversary', - callback: (event, button, dialog) => Number(button.form.elements.tier.value) - } - }); - - if (tier === actor.system.tier) { - ui.notifications.warn('This actor is already at this tier'); - } else if (tier) { - const source = actor.system.adjustForTier(tier); - await Actor.create(source); - ui.notifications.info(`Tier ${tier} ${actor.name} created`); - } - } + options.push({ + name: 'DAGGERHEART.UI.Sidebar.actorDirectory.duplicateToNewTier', + icon: ``, + condition: li => { + const actor = game.actors.get(li.dataset.entryId); + return actor?.type === 'adversary' && actor.system.type !== 'social'; }, - { - label: 'DAGGERHEART.UI.Sidebar.actorDirectory.activateParty', - icon: ``, - visible: li => { - const actor = game.actors.get(li.dataset.entryId); - return actor && actor.type === 'party' && !actor.system.active; - }, - callback: async li => { - const actor = game.actors.get(li.dataset.entryId); - if (!actor) throw new Error('Unexpected missing actor'); + callback: async li => { + const actor = game.actors.get(li.dataset.entryId); + if (!actor) throw new Error('Unexpected missing actor'); - await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.ActiveParty, actor.id); - ui.actors.render(); + const tiers = [1, 2, 3, 4].filter(t => t !== actor.system.tier); + const content = document.createElement('div'); + const select = document.createElement('select'); + select.name = 'tier'; + select.append( + ...tiers.map(t => { + const option = document.createElement('option'); + option.value = t; + option.textContent = game.i18n.localize(`DAGGERHEART.GENERAL.Tiers.${t}`); + return option; + }) + ); + content.append(select); + + const tier = await foundry.applications.api.Dialog.input({ + classes: ['dh-style', 'dialog'], + window: { title: 'DAGGERHEART.UI.Sidebar.actorDirectory.pickTierTitle' }, + content, + ok: { + label: 'DAGGERHEART.UI.Sidebar.actorDirectory.createAdversary', + callback: (event, button, dialog) => Number(button.form.elements.tier.value) + } + }); + + if (tier === actor.system.tier) { + ui.notifications.warn('This actor is already at this tier'); + } else if (tier) { + const source = actor.system.adjustForTier(tier); + await Actor.create(source); + ui.notifications.info(`Tier ${tier} ${actor.name} created`); } } - ); + }); return options; } diff --git a/module/applications/sidebar/tabs/daggerheartMenu.mjs b/module/applications/sidebar/tabs/daggerheartMenu.mjs index 86c1b8cb..26ae484b 100644 --- a/module/applications/sidebar/tabs/daggerheartMenu.mjs +++ b/module/applications/sidebar/tabs/daggerheartMenu.mjs @@ -31,8 +31,7 @@ export default class DaggerheartMenu extends HandlebarsApplicationMixin(Abstract }, actions: { selectRefreshable: DaggerheartMenu.#selectRefreshable, - refreshActors: DaggerheartMenu.#refreshActors, - createFallCollisionDamage: DaggerheartMenu.#createFallCollisionDamage + refreshActors: DaggerheartMenu.#refreshActors } }; @@ -51,7 +50,6 @@ export default class DaggerheartMenu extends HandlebarsApplicationMixin(Abstract const context = await super._prepareContext(options); context.refreshables = this.refreshSelections; context.disableRefresh = Object.values(this.refreshSelections).every(x => !x.selected); - context.fallAndCollision = CONFIG.DH.GENERAL.fallAndCollisionDamage; return context; } @@ -73,22 +71,4 @@ export default class DaggerheartMenu extends HandlebarsApplicationMixin(Abstract this.refreshSelections = DaggerheartMenu.defaultRefreshSelections(); this.render(); } - - static async #createFallCollisionDamage(_event, button) { - const data = CONFIG.DH.GENERAL.fallAndCollisionDamage[button.dataset.key]; - const roll = new Roll(data.damageFormula); - await roll.evaluate(); - - /* class BaseRoll needed to get rendered by foundryRoll.hbs */ - const rollJSON = roll.toJSON(); - rollJSON.class = 'BaseRoll'; - - foundry.documents.ChatMessage.implementation.create({ - title: game.i18n.localize(data.chatTitle), - author: game.user.id, - speaker: foundry.documents.ChatMessage.implementation.getSpeaker(), - rolls: [rollJSON], - sound: CONFIG.sounds.dice - }); - } } diff --git a/module/applications/ui/_module.mjs b/module/applications/ui/_module.mjs index 80d3ebe4..8c5c020e 100644 --- a/module/applications/ui/_module.mjs +++ b/module/applications/ui/_module.mjs @@ -7,4 +7,3 @@ export { default as DhFearTracker } from './fearTracker.mjs'; export { default as DhHotbar } from './hotbar.mjs'; export { default as DhSceneNavigation } from './sceneNavigation.mjs'; export { ItemBrowser } from './itemBrowser.mjs'; -export { default as DhProgress } from './progress.mjs'; diff --git a/module/applications/ui/chatLog.mjs b/module/applications/ui/chatLog.mjs index 199ee87d..2b489f58 100644 --- a/module/applications/ui/chatLog.mjs +++ b/module/applications/ui/chatLog.mjs @@ -1,6 +1,5 @@ -import { enrichedDualityRoll } from '../../enrichers/DualityRollEnricher.mjs'; -import { enrichedFateRoll, getFateTypeData } from '../../enrichers/FateRollEnricher.mjs'; -import { getCommandTarget, rollCommandToJSON } from '../../helpers/utils.mjs'; +import { abilities } from '../../config/actorConfig.mjs'; +import { emitAsGM, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLog { constructor(options) { @@ -22,114 +21,35 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo classes: ['daggerheart'] }; - static CHAT_COMMANDS = { - ...super.CHAT_COMMANDS, - dr: { - rgx: /^(?:\/dr)((?:\s)[^]*)?/, - fn: (_, match) => { - const argString = match[1]?.trim(); - const result = argString ? rollCommandToJSON(argString) : { result: {} }; - if (!result) { - ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.dualityParsing')); - return false; - } - - const { result: rollCommand, flavor } = result; - - const reaction = rollCommand.reaction; - const traitValue = rollCommand.trait?.toLowerCase(); - const advantage = rollCommand.advantage - ? CONFIG.DH.ACTIONS.advantageState.advantage.value - : rollCommand.disadvantage - ? CONFIG.DH.ACTIONS.advantageState.disadvantage.value - : undefined; - const difficulty = rollCommand.difficulty; - const grantResources = rollCommand.grantResources; - - const target = getCommandTarget({ allowNull: true }); - const title = - (flavor ?? traitValue) - ? game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', { - ability: game.i18n.localize(CONFIG.DH.ACTOR.abilities[traitValue].label) - }) - : game.i18n.localize('DAGGERHEART.GENERAL.duality'); - - enrichedDualityRoll({ - reaction, - traitValue, - target, - difficulty, - title, - label: game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll'), - actionType: null, - advantage, - grantResources - }); - return false; - } - }, - fr: { - rgx: /^(?:\/fr)((?:\s)[^]*)?/, - fn: (_, match) => { - const argString = match[1]?.trim(); - const result = argString ? rollCommandToJSON(argString) : { result: {} }; - - if (!result) { - ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateParsing')); - return false; - } - - const { result: rollCommand, flavor } = result; - const fateTypeData = getFateTypeData(rollCommand?.type); - - if (!fateTypeData) - return ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateTypeParsing')); - - const { value: fateType, label: fateTypeLabel } = fateTypeData; - const target = getCommandTarget({ allowNull: true }); - const title = flavor ?? game.i18n.localize('DAGGERHEART.GENERAL.fateRoll'); - - enrichedFateRoll({ - target, - title, - label: fateTypeLabel, - fateType - }); - return false; - } - } - }; - _getEntryContextOptions() { return [ ...super._getEntryContextOptions(), + // { + // name: 'Reroll', + // icon: '', + // condition: li => { + // const message = game.messages.get(li.dataset.messageId); + + // return (game.user.isGM || message.isAuthor) && message.rolls.length > 0; + // }, + // callback: li => { + // const message = game.messages.get(li.dataset.messageId); + // new game.system.api.applications.dialogs.RerollDialog(message).render({ force: true }); + // } + // }, { - label: 'DAGGERHEART.UI.ChatLog.rerollActionRoll', + name: game.i18n.localize('DAGGERHEART.UI.ChatLog.rerollDamage'), icon: '', - visible: li => { - const message = game.messages.get(li.dataset.messageId); - return message.system.hasRoll && (game.user.isGM || message.isAuthor); - }, - callback: async li => { - const message = game.messages.get(li.dataset.messageId); - const reroll = await message.rolls[0].reroll({ liveRoll: true }); - message.update({ rolls: [reroll] }); - } - }, - { - label: 'DAGGERHEART.UI.ChatLog.rerollDamage', - icon: '', - visible: li => { + condition: li => { const message = game.messages.get(li.dataset.messageId); const hasRolledDamage = message.system.hasDamage ? Object.keys(message.system.damage).length > 0 : false; return (game.user.isGM || message.isAuthor) && hasRolledDamage; }, - callback: async li => { + callback: li => { const message = game.messages.get(li.dataset.messageId); - const update = await message.system.getRerolledDamage(); - message.update(update); + new game.system.api.applications.dialogs.RerollDamageDialog(message).render({ force: true }); } } ]; @@ -149,6 +69,18 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo html.querySelectorAll('.reroll-button').forEach(element => element.addEventListener('click', event => this.rerollEvent(event, message)) ); + html.querySelectorAll('.group-roll-button').forEach(element => + element.addEventListener('click', event => this.groupRollButton(event, message)) + ); + html.querySelectorAll('.group-roll-reroll').forEach(element => + element.addEventListener('click', event => this.groupRollReroll(event, message)) + ); + html.querySelectorAll('.group-roll-success').forEach(element => + element.addEventListener('click', event => this.groupRollSuccessEvent(event, message)) + ); + html.querySelectorAll('.group-roll-header-expand-section').forEach(element => + element.addEventListener('click', this.groupRollExpandSection) + ); html.querySelectorAll('.risk-it-all-button').forEach(element => element.addEventListener('click', event => this.riskItAllClearStressAndHitPoints(event, data)) ); @@ -243,7 +175,7 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo action.use(event); } - async rerollEvent(event, messageData) { + async rerollEvent(event, message) { event.stopPropagation(); if (!event.shiftKey) { const confirmed = await foundry.applications.api.DialogV2.confirm({ @@ -255,43 +187,208 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo if (!confirmed) return; } - const message = game.messages.get(messageData._id); const target = event.target.closest('[data-die-index]'); if (target.dataset.type === 'damage') { - const { damageType, part, dice, result } = target.dataset; - const damagePart = message.system.damage[damageType].parts[part]; - const { parsedRoll, rerolledDice } = await game.system.api.dice.DamageRoll.reroll(damagePart, dice, result); - const damageParts = message.system.damage[damageType].parts.map((damagePart, index) => { - if (index !== Number(part)) return damagePart; - return { - ...damagePart, - total: parsedRoll.total, - dice: rerolledDice - }; - }); - const updateMessage = game.messages.get(message._id); - await updateMessage.update({ - [`system.damage.${damageType}`]: { - total: parsedRoll.total, - parts: damageParts - } - }); + game.system.api.dice.DamageRoll.reroll(target, message); } else { - const rerollDice = message.system.roll.dice[target.dataset.dieIndex]; - await rerollDice.reroll(`/r1=${rerollDice.total}`, { - liveRoll: { - roll: message.system.roll, - actor: message.system.actionActor, - isReaction: message.system.roll.options.actionType === 'reaction' - } + let originalRoll_parsed = message.rolls.map(roll => JSON.parse(roll))[0]; + const rollClass = + game.system.api.dice[ + message.type === 'dualityRoll' + ? 'DualityRoll' + : target.dataset.type === 'damage' + ? 'DHRoll' + : 'D20Roll' + ]; + + if (!game.modules.get('dice-so-nice')?.active) foundry.audio.AudioHelper.play({ src: CONFIG.sounds.dice }); + + const { newRoll, parsedRoll } = await rollClass.reroll(originalRoll_parsed, target, message); + + await game.messages.get(message._id).update({ + 'system.roll': newRoll, + 'rolls': [parsedRoll] }); - await message.update({ - rolls: [message.system.roll.toJSON()] + + Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.TagTeamRoll }); + await game.socket.emit(`system.${CONFIG.DH.id}`, { + action: socketEvent.Refresh, + data: { + refreshType: RefreshType.TagTeamRoll + } }); } } + async groupRollButton(event, message) { + const path = event.currentTarget.dataset.path; + const isLeader = path === 'leader'; + const { actor: actorData, trait } = foundry.utils.getProperty(message.system, path); + const actor = game.actors.get(actorData._id); + + if (!actor) { + return ui.notifications.error( + game.i18n.format('DAGGERHEART.UI.Notifications.documentIsMissing', { + documentType: game.i18n.localize('TYPES.Actor.character') + }) + ); + } + + if (!actor.testUserPermission(game.user, 'OWNER')) { + return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.noActorOwnership')); + } + + const traitLabel = game.i18n.localize(abilities[trait].label); + const config = { + event: event, + title: `${game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll')}: ${actor.name}`, + headerTitle: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', { + ability: traitLabel + }), + roll: { + trait: trait, + advantage: 0, + modifiers: [{ label: traitLabel, value: actor.system.traits[trait].value }] + }, + hasRoll: true, + skips: { + createMessage: true, + resources: !isLeader, + updateCountdowns: !isLeader + } + }; + const result = await actor.diceRoll({ + ...config, + headerTitle: `${game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll')}: ${actor.name}`, + title: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', { + ability: traitLabel + }) + }); + + if (!result) return; + + const newMessageData = foundry.utils.deepClone(message.system); + foundry.utils.setProperty(newMessageData, `${path}.result`, result.roll); + const renderData = { system: new game.system.api.models.chatMessages.config.groupRoll(newMessageData) }; + + const updatedContent = await foundry.applications.handlebars.renderTemplate( + 'systems/daggerheart/templates/ui/chat/groupRoll.hbs', + { ...renderData, user: game.user } + ); + const mess = game.messages.get(message._id); + + await emitAsGM( + GMUpdateEvent.UpdateDocument, + mess.update.bind(mess), + { + ...renderData, + content: updatedContent + }, + mess.uuid + ); + } + + async groupRollReroll(event, message) { + const path = event.currentTarget.dataset.path; + const { actor: actorData, trait } = foundry.utils.getProperty(message.system, path); + const actor = game.actors.get(actorData._id); + + if (!actor.testUserPermission(game.user, 'OWNER')) { + return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.noActorOwnership')); + } + + const traitLabel = game.i18n.localize(abilities[trait].label); + + const config = { + event: event, + title: `${game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll')}: ${actor.name}`, + headerTitle: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', { + ability: traitLabel + }), + roll: { + trait: trait, + advantage: 0, + modifiers: [{ label: traitLabel, value: actor.system.traits[trait].value }] + }, + hasRoll: true, + skips: { + createMessage: true, + updateCountdowns: true + } + }; + const result = await actor.diceRoll({ + ...config, + headerTitle: `${game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll')}: ${actor.name}`, + title: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', { + ability: traitLabel + }) + }); + + const newMessageData = foundry.utils.deepClone(message.system); + foundry.utils.setProperty(newMessageData, `${path}.result`, { ...result.roll, rerolled: true }); + const renderData = { system: new game.system.api.models.chatMessages.config.groupRoll(newMessageData) }; + + const updatedContent = await foundry.applications.handlebars.renderTemplate( + 'systems/daggerheart/templates/ui/chat/groupRoll.hbs', + { ...renderData, user: game.user } + ); + const mess = game.messages.get(message._id); + await emitAsGM( + GMUpdateEvent.UpdateDocument, + mess.update.bind(mess), + { + ...renderData, + content: updatedContent + }, + mess.uuid + ); + } + + async groupRollSuccessEvent(event, message) { + if (!game.user.isGM) { + return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.gmOnly')); + } + + const { path, success } = event.currentTarget.dataset; + const { actor: actorData } = foundry.utils.getProperty(message.system, path); + const actor = game.actors.get(actorData._id); + + if (!actor.testUserPermission(game.user, 'OWNER')) { + return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.noActorOwnership')); + } + + const newMessageData = foundry.utils.deepClone(message.system); + foundry.utils.setProperty(newMessageData, `${path}.manualSuccess`, Boolean(success)); + const renderData = { system: new game.system.api.models.chatMessages.config.groupRoll(newMessageData) }; + + const updatedContent = await foundry.applications.handlebars.renderTemplate( + 'systems/daggerheart/templates/ui/chat/groupRoll.hbs', + { ...renderData, user: game.user } + ); + const mess = game.messages.get(message._id); + await emitAsGM( + GMUpdateEvent.UpdateDocument, + mess.update.bind(mess), + { + ...renderData, + content: updatedContent + }, + mess.uuid + ); + } + + async groupRollExpandSection(event) { + event.target + .closest('.group-roll-header-expand-section') + .querySelectorAll('i') + .forEach(element => { + element.classList.toggle('fa-angle-up'); + element.classList.toggle('fa-angle-down'); + }); + event.target.closest('.group-roll-section').querySelector('.group-roll-content').classList.toggle('closed'); + } + async riskItAllClearStressAndHitPoints(event, data) { const resourceValue = event.target.dataset.resourceValue; const actor = game.actors.get(event.target.dataset.actorId); diff --git a/module/applications/ui/combatTracker.mjs b/module/applications/ui/combatTracker.mjs index 25f3e06b..fc47f085 100644 --- a/module/applications/ui/combatTracker.mjs +++ b/module/applications/ui/combatTracker.mjs @@ -1,6 +1,4 @@ import { AdversaryBPPerEncounter } from '../../config/encounterConfig.mjs'; -import { expireActiveEffects } from '../../helpers/utils.mjs'; -import { clearPreviousSpotlight } from '../../macros/spotlightCombatant.mjs'; export default class DhCombatTracker extends foundry.applications.sidebar.tabs.CombatTracker { static DEFAULT_OPTIONS = { @@ -56,9 +54,7 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C async _prepareTrackerContext(context, options) { await super._prepareTrackerContext(context, options); - const npcs = context.turns?.filter(x => x.isNPC) ?? []; - const adversaries = npcs.filter(x => x.disposition !== CONST.TOKEN_DISPOSITIONS.FRIENDLY); - const friendlies = npcs.filter(x => x.disposition === CONST.TOKEN_DISPOSITIONS.FRIENDLY); + const adversaries = context.turns?.filter(x => x.isNPC) ?? []; const characters = context.turns?.filter(x => !x.isNPC) ?? []; const spotlightQueueEnabled = game.settings.get( CONFIG.DH.id, @@ -77,56 +73,25 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C Object.assign(context, { actionTokens: game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.variantRules).actionTokens, adversaries, - friendlies, allCharacters: characters, characters: characters.filter(x => !spotlightQueueEnabled || x.system.spotlight.requestOrderIndex == 0), spotlightRequests }); } - /** - * Open the dialog used to edit the name of the currently viewed Combat encounter. - * @this {CombatTracker} - * @returns {Promise} - */ - static async #onEditName() { - const combat = this.viewed; - if (!combat || !game.user.isGM) return null; - const field = combat.schema.fields.name; - const inputHTML = field.toFormGroup({}, { name: 'name', value: combat.name, autofocus: true }).outerHTML; - const formData = await foundry.applications.api.DialogV2.input({ - window: { icon: 'fa-solid fa-tag', title: 'COMBAT.ACTIONS.EditNameTitle' }, - position: { width: 480 }, - content: inputHTML - }); - await combat.update({ name: formData.name || '' }); - } - _getCombatContextOptions() { return [ { - label: 'COMBAT.ACTIONS.EditName', - icon: 'fa-solid fa-tag', - visible: () => game.user.isGM && !!this.viewed, - onClick: () => DhCombatTracker.#onEditName.call(this) + name: 'COMBAT.ClearMovementHistories', + icon: '', + condition: () => game.user.isGM && this.viewed?.combatants.size > 0, + callback: () => this.viewed.clearMovementHistories() }, { - label: 'COMBAT.ACTIONS.LinkToScene', - icon: '', - visible: () => game.user.isGM && !this.scene, - onClick: () => this.viewed.toggleSceneLink() - }, - { - label: 'COMBAT.ACTIONS.UnlinkFromScene', - icon: '', - visible: () => game.user.isGM && !!this.scene, - onClick: () => this.viewed.toggleSceneLink() - }, - { - label: 'COMBAT.End', - icon: 'fa-solid fa-xmark', - visible: () => game.user.isGM && !!this.viewed, - onClick: () => this.viewed.endCombat() + name: 'COMBAT.Delete', + icon: '', + condition: () => game.user.isGM && !!this.viewed, + callback: () => this.viewed.endCombat() } ]; } @@ -162,8 +127,7 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C active: index === combat.turn, canPing: combatant.sceneId === canvas.scene?.id && game.user.hasPermission('PING_CANVAS'), type: combatant.actor?.system?.type, - img: await this._getCombatantThumbnail(combatant), - disposition: combatant.token?.disposition + img: await this._getCombatantThumbnail(combatant) }; turn.css = [turn.active ? 'active' : null, hidden ? 'hide' : null, isDefeated ? 'defeated' : null].filterJoin( @@ -185,13 +149,13 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C } async setCombatantSpotlight(combatantId) { - const combatant = this.viewed.combatants.get(combatantId); const update = { system: { 'spotlight.requesting': false, 'spotlight.requestOrderIndex': 0 } }; + const combatant = this.viewed.combatants.get(combatantId); const toggleTurn = this.viewed.combatants.contents .sort(this.viewed._sortCombatants) @@ -213,8 +177,6 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C if (autoPoints) { update.system.actionTokens = Math.max(combatant.system.actionTokens - 1, 0); } - - if (combatant.actor) expireActiveEffects(combatant.actor, [CONFIG.DH.GENERAL.activeEffectDurations.act.id]); } await this.viewed.update({ @@ -222,14 +184,6 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C round: this.viewed.round + 1 }); await combatant.update(update); - if (combatant.token) clearPreviousSpotlight(); - } - - async clearTurn() { - await this.viewed.update({ - turn: null, - round: this.viewed.round + 1 - }); } static async requestSpotlight(_, target) { diff --git a/module/applications/ui/countdownEdit.mjs b/module/applications/ui/countdownEdit.mjs index 5974e1f2..7f1deea3 100644 --- a/module/applications/ui/countdownEdit.mjs +++ b/module/applications/ui/countdownEdit.mjs @@ -1,6 +1,6 @@ import { DhCountdown } from '../../data/countdowns.mjs'; import { waitForDiceSoNice } from '../../helpers/utils.mjs'; -import { emitGMUpdate, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; +import { emitAsGM, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; @@ -56,8 +56,8 @@ export default class CountdownEdit extends HandlebarsApplicationMixin(Applicatio ? countdown.progress.looping === CONFIG.DH.GENERAL.countdownLoopingTypes.increasing.id ? 'DAGGERHEART.UI.Countdowns.increasingLoop' : countdown.progress.looping === CONFIG.DH.GENERAL.countdownLoopingTypes.decreasing.id - ? 'DAGGERHEART.UI.Countdowns.decreasingLoop' - : 'DAGGERHEART.UI.Countdowns.loop' + ? 'DAGGERHEART.UI.Countdowns.decreasingLoop' + : 'DAGGERHEART.UI.Countdowns.loop' : null; const randomizeValid = !new Roll(countdown.progress.startFormula ?? '').isDeterministic; acc[key] = { @@ -114,7 +114,7 @@ export default class CountdownEdit extends HandlebarsApplicationMixin(Applicatio } await this.data.updateSource(update); - await emitGMUpdate(GMUpdateEvent.UpdateCountdowns, this.gmSetSetting.bind(this.data), this.data, null, { + await emitAsGM(GMUpdateEvent.UpdateCountdowns, this.gmSetSetting.bind(this.data), this.data, null, { refreshType: RefreshType.Countdown }); @@ -148,11 +148,11 @@ export default class CountdownEdit extends HandlebarsApplicationMixin(Applicatio } async gmSetSetting(data) { - await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, data); - game.socket.emit(`system.${CONFIG.DH.id}`, { - action: socketEvent.Refresh, - data: { refreshType: RefreshType.Countdown } - }); + await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, data), + game.socket.emit(`system.${CONFIG.DH.id}`, { + action: socketEvent.Refresh, + data: { refreshType: RefreshType.Countdown } + }); Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.Countdown }); } @@ -233,6 +233,6 @@ export default class CountdownEdit extends HandlebarsApplicationMixin(Applicatio } if (this.editingCountdowns.has(countdownId)) this.editingCountdowns.delete(countdownId); - this.updateSetting({ [`countdowns.${countdownId}`]: _del }); + this.updateSetting({ [`countdowns.-=${countdownId}`]: null }); } } diff --git a/module/applications/ui/countdowns.mjs b/module/applications/ui/countdowns.mjs index 2a2a113e..42920a4a 100644 --- a/module/applications/ui/countdowns.mjs +++ b/module/applications/ui/countdowns.mjs @@ -1,5 +1,5 @@ import { waitForDiceSoNice } from '../../helpers/utils.mjs'; -import { emitGMUpdate, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; +import { emitAsGM, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; @@ -21,19 +21,19 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application static DEFAULT_OPTIONS = { id: 'countdowns', tag: 'div', - classes: ['daggerheart', 'dh-style', 'countdowns'], + classes: ['daggerheart', 'dh-style', 'countdowns', 'faded-ui'], window: { icon: 'fa-solid fa-clock-rotate-left', - frame: false, + frame: true, title: 'DAGGERHEART.UI.Countdowns.title', positioned: false, resizable: false, minimizable: false }, actions: { - toggleViewMode: DhCountdowns.#onToggleViewMode, - editCountdowns: DhCountdowns.#onEditCountdowns, - loopCountdown: DhCountdowns.#onLoopCountdown, + toggleViewMode: DhCountdowns.#toggleViewMode, + editCountdowns: DhCountdowns.#editCountdowns, + loopCountdown: DhCountdowns.#loopCountdown, decreaseCountdown: (_, target) => this.editCountdown(false, target), increaseCountdown: (_, target) => this.editCountdown(true, target) }, @@ -52,6 +52,10 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application } }; + get element() { + return document.body.querySelector('.daggerheart.dh-style.countdowns'); + } + /**@inheritdoc */ async _renderFrame(options) { const frame = await super._renderFrame(options); @@ -62,6 +66,19 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application if (iconOnly) frame.classList.add('icon-only'); else frame.classList.remove('icon-only'); + const header = frame.querySelector('.window-header'); + header.querySelector('button[data-action="close"]').remove(); + + if (game.user.isGM) { + const editTooltip = game.i18n.localize('DAGGERHEART.APPLICATIONS.CountdownEdit.editTitle'); + const editButton = ``; + header.insertAdjacentHTML('beforeEnd', editButton); + } + + const minimizeTooltip = game.i18n.localize('DAGGERHEART.UI.Countdowns.toggleIconMode'); + const minimizeButton = ``; + header.insertAdjacentHTML('beforeEnd', minimizeButton); + return frame; } @@ -101,8 +118,8 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application ? countdown.progress.looping === CONFIG.DH.GENERAL.countdownLoopingTypes.increasing.id ? 'DAGGERHEART.UI.Countdowns.increasingLoop' : countdown.progress.looping === CONFIG.DH.GENERAL.countdownLoopingTypes.decreasing.id - ? 'DAGGERHEART.UI.Countdowns.decreasingLoop' - : 'DAGGERHEART.UI.Countdowns.loop' + ? 'DAGGERHEART.UI.Countdowns.decreasingLoop' + : 'DAGGERHEART.UI.Countdowns.loop' : null; const loopDisabled = !countdownEditable || @@ -123,8 +140,6 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application } static #getPlayerOwnership(user, setting, countdown) { - if (user.isGM) return CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER; - const playerOwnership = countdown.ownership[user.id]; return playerOwnership === undefined || playerOwnership === CONST.DOCUMENT_OWNERSHIP_LEVELS.INHERIT ? setting.defaultOwnership @@ -147,7 +162,7 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application return true; } - static async #onToggleViewMode() { + static async #toggleViewMode() { const currentMode = game.user.getFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.userFlags.countdownMode); const appMode = CONFIG.DH.GENERAL.countdownAppMode; const newMode = currentMode === appMode.textIcon ? appMode.iconOnly : appMode.textIcon; @@ -158,16 +173,15 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application this.render(); } - static async #onEditCountdowns() { + static async #editCountdowns() { new game.system.api.applications.ui.CountdownEdit().render(true); } - static async #onLoopCountdown(_, target) { + static async #loopCountdown(_, target) { if (!DhCountdowns.canPerformEdit()) return; const settings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns); - const countdownId = target.closest('[data-countdown]').dataset.countdown; - const countdown = settings.countdowns[countdownId]; + const countdown = settings.countdowns[target.id]; let progressMax = countdown.progress.start; let message = null; @@ -181,17 +195,17 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application countdown.progress.looping === CONFIG.DH.GENERAL.countdownLoopingTypes.increasing.id ? Number(progressMax) + 1 : countdown.progress.looping === CONFIG.DH.GENERAL.countdownLoopingTypes.decreasing.id - ? Math.max(Number(progressMax) - 1, 0) - : progressMax; + ? Math.max(Number(progressMax) - 1, 0) + : progressMax; await waitForDiceSoNice(message); await settings.updateSource({ - [`countdowns.${countdownId}.progress`]: { + [`countdowns.${target.id}.progress`]: { current: newMax, start: newMax } }); - await emitGMUpdate(GMUpdateEvent.UpdateCountdowns, DhCountdowns.gmSetSetting.bind(settings), settings, null, { + await emitAsGM(GMUpdateEvent.UpdateCountdowns, DhCountdowns.gmSetSetting.bind(settings), settings, null, { refreshType: RefreshType.Countdown }); } @@ -200,23 +214,22 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application if (!DhCountdowns.canPerformEdit()) return; const settings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns); - const countdownId = target.closest('[data-countdown]').dataset.countdown; - const countdown = settings.countdowns[countdownId]; + const countdown = settings.countdowns[target.id]; const newCurrent = increase ? Math.min(countdown.progress.current + 1, countdown.progress.start) : Math.max(countdown.progress.current - 1, 0); - await settings.updateSource({ [`countdowns.${countdownId}.progress.current`]: newCurrent }); - await emitGMUpdate(GMUpdateEvent.UpdateCountdowns, DhCountdowns.gmSetSetting.bind(settings), settings, null, { + await settings.updateSource({ [`countdowns.${target.id}.progress.current`]: newCurrent }); + await emitAsGM(GMUpdateEvent.UpdateCountdowns, DhCountdowns.gmSetSetting.bind(settings), settings, null, { refreshType: RefreshType.Countdown }); } static async gmSetSetting(data) { - await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, data); - game.socket.emit(`system.${CONFIG.DH.id}`, { - action: socketEvent.Refresh, - data: { refreshType: RefreshType.Countdown } - }); + await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, data), + game.socket.emit(`system.${CONFIG.DH.id}`, { + action: socketEvent.Refresh, + data: { refreshType: RefreshType.Countdown } + }); Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.Countdown }); } @@ -265,8 +278,10 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application return acc; }, {}) }; - await emitGMUpdate(GMUpdateEvent.UpdateCountdowns, DhCountdowns.gmSetSetting.bind(settings), settings, null, { - refreshType: RefreshType.Countdown + await emitAsGM(GMUpdateEvent.UpdateCountdowns, + DhCountdowns.gmSetSetting.bind(settings), + settings, null, { + refreshType: RefreshType.Countdown }); } diff --git a/module/applications/ui/effectsDisplay.mjs b/module/applications/ui/effectsDisplay.mjs index a64b1b22..e0fa7ae2 100644 --- a/module/applications/ui/effectsDisplay.mjs +++ b/module/applications/ui/effectsDisplay.mjs @@ -1,4 +1,3 @@ -import { getIconVisibleActiveEffects } from '../../helpers/utils.mjs'; import { RefreshType } from '../../systemRegistration/socket.mjs'; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; @@ -49,9 +48,11 @@ export default class DhEffectsDisplay extends HandlebarsApplicationMixin(Applica _attachPartListeners(partId, htmlElement, options) { super._attachPartListeners(partId, htmlElement, options); - for (const element of this.element?.querySelectorAll('.effect-container a') ?? []) { - element.addEventListener('click', e => this.#onClickEffect(e)); - element.addEventListener('contextmenu', e => this.#onClickEffect(e, -1)); + + if (this.element) { + this.element.querySelectorAll('.effect-container a').forEach(element => { + element.addEventListener('contextmenu', this.removeEffect.bind(this)); + }); } } @@ -67,11 +68,11 @@ export default class DhEffectsDisplay extends HandlebarsApplicationMixin(Applica const actor = token ? token.actor : canvas.tokens.controlled.length === 0 - ? !game.user.isGM - ? game.user.character - : null - : canvas.tokens.controlled[0].actor; - return getIconVisibleActiveEffects(actor?.getActiveEffects() ?? []); + ? !game.user.isGM + ? game.user.character + : null + : canvas.tokens.controlled[0].actor; + return actor?.getActiveEffects() ?? []; }; toggleHidden(token, focused) { @@ -85,22 +86,11 @@ export default class DhEffectsDisplay extends HandlebarsApplicationMixin(Applica this.render(); } - async #onClickEffect(event, delta = 1) { + async removeEffect(event) { const element = event.target.closest('.effect-container'); const effects = DhEffectsDisplay.getTokenEffects(); const effect = effects.find(x => x.id === element.dataset.effectId); - if (!effect || (delta >= 0 && !effect.system.stacking)) { - return; - } - - const maxValue = effect.system.stacking?.max ?? Infinity; - const newValue = Math.clamp((effect.system.stacking?.value ?? 1) + delta, 0, maxValue); - if (newValue > 0) { - await effect.update({ 'system.stacking.value': newValue }); - } else { - await effect.delete(); - } - this.render(); + await effect.delete(); } setupHooks() { diff --git a/module/applications/ui/fearTracker.mjs b/module/applications/ui/fearTracker.mjs index 8c247f79..4e5e1132 100644 --- a/module/applications/ui/fearTracker.mjs +++ b/module/applications/ui/fearTracker.mjs @@ -1,4 +1,4 @@ -import { emitGMUpdate, GMUpdateEvent } from '../../systemRegistration/socket.mjs'; +import { emitAsGM, GMUpdateEvent } from '../../systemRegistration/socket.mjs'; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; @@ -104,7 +104,7 @@ export default class FearTracker extends HandlebarsApplicationMixin(ApplicationV } async updateFear(value) { - return emitGMUpdate( + return emitAsGM( GMUpdateEvent.UpdateFear, game.settings.set.bind(game.settings, CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear), value diff --git a/module/applications/ui/itemBrowser.mjs b/module/applications/ui/itemBrowser.mjs index 8f38918a..67a16f6a 100644 --- a/module/applications/ui/itemBrowser.mjs +++ b/module/applications/ui/itemBrowser.mjs @@ -1,4 +1,3 @@ -import { getDocFromElement } from '../../helpers/utils.mjs'; import { RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; @@ -48,8 +47,7 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { expandContent: this.expandContent, resetFilters: this.resetFilters, sortList: this.sortList, - openSettings: this.openSettings, - viewSheet: this.#onViewSheet + openSettings: this.openSettings }, position: { left: 100, @@ -111,8 +109,8 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { CONFIG.DH.id, CONFIG.DH.FLAGS[`${this.compendiumBrowserTypeKey}`].position ); + options.position = userPresetPosition ?? ItemBrowser.DEFAULT_OPTIONS.position; - delete options.position.zIndex; if (!userPresetPosition) { const width = noFolder === true || lite === true ? 600 : 850; @@ -279,7 +277,7 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { (await foundry.applications.ux.TextEditor.implementation.enrichHTML(item.description)); } - this.fieldFilter = await this._createFieldFilter(); + this.fieldFilter = this._createFieldFilter(); if (this.presets?.filter) { Object.entries(this.presets.filter).forEach(([k, v]) => { @@ -308,8 +306,7 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { { items: this.items, menu: this.selectedMenu, - formatLabel: this.formatLabel, - viewSheet: this.items[0] instanceof Actor + formatLabel: this.formatLabel } ); @@ -358,12 +355,12 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { ); } - async _createFieldFilter() { + _createFieldFilter() { const filters = ItemBrowser.getFolderConfig(this.selectedMenu.data, 'filters'); - for (const f of filters) { + filters.forEach(f => { if (typeof f.field === 'string') f.field = foundry.utils.getProperty(game, f.field); else if (typeof f.choices === 'function') { - f.choices = await f.choices(this.items); + f.choices = f.choices(this.items); } // Clear field label so template uses our custom label parameter @@ -373,8 +370,7 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { f.name ??= f.key; f.value = this.presets?.filter?.[f.name]?.value ?? null; - } - + }); return filters; } @@ -571,11 +567,6 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { } } - static async #onViewSheet(_, target) { - const document = await getDocFromElement(target); - document?.sheet?.render(true); - } - _createDragProcess() { new foundry.applications.ux.DragDrop.implementation({ dragSelector: '.item-container', @@ -614,16 +605,7 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { items: { folder: 'equipments', render: { - folders: [ - 'equipments', - 'ancestries', - 'classes', - 'subclasses', - 'domains', - 'communities', - 'beastforms' - // excluded: features - ] + noFolder: true } }, compendium: {} diff --git a/module/applications/ui/progress.mjs b/module/applications/ui/progress.mjs deleted file mode 100644 index 2fb1b445..00000000 --- a/module/applications/ui/progress.mjs +++ /dev/null @@ -1,27 +0,0 @@ -export default class DhProgress { - #notification; - - constructor({ max, label = '' }) { - this.max = max; - this.label = label; - this.#notification = ui.notifications.info(this.label, { progress: true }); - } - - updateMax(newMax) { - this.max = newMax; - } - - advance({ by = 1, label = this.label } = {}) { - if (this.value === this.max) return; - this.value = (this.value ?? 0) + Math.abs(by); - this.#notification.update({ message: label, pct: this.value / this.max }); - } - - close({ label = '' } = {}) { - this.#notification.update({ message: label, pct: 1 }); - } - - static createMigrationProgress(max = 0) { - return new DhProgress({ max, label: game.i18n.localize('DAGGERHEART.UI.Progress.migrationLabel') }); - } -} diff --git a/module/applications/ui/sceneNavigation.mjs b/module/applications/ui/sceneNavigation.mjs index 982063e7..67bfe0b4 100644 --- a/module/applications/ui/sceneNavigation.mjs +++ b/module/applications/ui/sceneNavigation.mjs @@ -1,4 +1,4 @@ -import { emitGMUpdate, GMUpdateEvent } from '../../systemRegistration/socket.mjs'; +import { emitAsGM, GMUpdateEvent } from '../../systemRegistration/socket.mjs'; export default class DhSceneNavigation extends foundry.applications.ui.SceneNavigation { /** @inheritdoc */ @@ -31,7 +31,7 @@ export default class DhSceneNavigation extends foundry.applications.ui.SceneNavi const environments = daggerheartInfo.sceneEnvironments.filter( x => x && x.testUserPermission(game.user, 'LIMITED') ); - const hasEnvironments = environments.length > 0 && x.active; + const hasEnvironments = environments.length > 0 && x.isView; return { ...x, hasEnvironments, @@ -39,10 +39,9 @@ export default class DhSceneNavigation extends foundry.applications.ui.SceneNavi environments: environments }; }); - context.scenes.active = extendScenes(context.scenes.active); context.scenes.inactive = extendScenes(context.scenes.inactive); - context.scenes.viewed = context.scenes.viewed ? extendScenes([context.scenes.viewed])[0] : null; + return context; } @@ -68,7 +67,7 @@ export default class DhSceneNavigation extends foundry.applications.ui.SceneNavi 1 )[0]; newEnvironments.unshift(newFirst); - emitGMUpdate( + emitAsGM( GMUpdateEvent.UpdateDocument, scene.update.bind(scene), { 'flags.daggerheart.sceneEnvironments': newEnvironments }, diff --git a/module/applications/ux/contextMenu.mjs b/module/applications/ux/contextMenu.mjs index 0b208585..081e6ba0 100644 --- a/module/applications/ux/contextMenu.mjs +++ b/module/applications/ux/contextMenu.mjs @@ -1,4 +1,97 @@ +/** + * @typedef ContextMenuEntry + * @property {string} name The context menu label. Can be localized. + * @property {string} [icon] A string containing an HTML icon element for the menu item. + * @property {string} [classes] Additional CSS classes to apply to this menu item. + * @property {string} [group] An identifier for a group this entry belongs to. + * @property {ContextMenuJQueryCallback} callback The function to call when the menu item is clicked. + * @property {ContextMenuCondition|boolean} [condition] A function to call or boolean value to determine if this entry + * appears in the menu. + */ + +/** + * @callback ContextMenuCondition + * @param {jQuery|HTMLElement} html The element of the context menu entry. + * @returns {boolean} Whether the entry should be rendered in the context menu. + */ + +/** + * @callback ContextMenuCallback + * @param {HTMLElement} target The element that the context menu has been triggered for. + * @returns {unknown} + */ + +/** + * @callback ContextMenuJQueryCallback + * @param {HTMLElement|jQuery} target The element that the context menu has been triggered for. Will + * either be a jQuery object or an HTMLElement instance, depending + * on how the ContextMenu was configured. + * @returns {unknown} + */ + +/** + * @typedef ContextMenuOptions + * @property {string} [eventName="contextmenu"] Optionally override the triggering event which can spawn the menu. If + * the menu is using fixed positioning, this event must be a MouseEvent. + * @property {ContextMenuCallback} [onOpen] A function to call when the context menu is opened. + * @property {ContextMenuCallback} [onClose] A function to call when the context menu is closed. + * @property {boolean} [fixed=false] If true, the context menu is given a fixed position rather than being + * injected into the target. + * @property {boolean} [jQuery=true] If true, callbacks will be passed jQuery objects instead of HTMLElement + * instances. + */ + +/** + * @typedef ContextMenuRenderOptions + * @property {Event} [event] The event that triggered the context menu opening. + * @property {boolean} [animate=true] Animate the context menu opening. + */ + +/** + * A subclass of ContextMenu. + * @extends {foundry.applications.ux.ContextMenu} + */ export default class DHContextMenu extends foundry.applications.ux.ContextMenu { + /** + * @param {HTMLElement|jQuery} container - The HTML element that contains the context menu targets. + * @param {string} selector - A CSS selector which activates the context menu. + * @param {ContextMenuEntry[]} menuItems - An Array of entries to display in the menu + * @param {ContextMenuOptions} [options] - Additional options to configure the context menu. + */ + constructor(container, selector, menuItems, options) { + super(container, selector, menuItems, options); + + /** @deprecated since v13 until v15 */ + this.#jQuery = options.jQuery; + } + + /** + * Whether to pass jQuery objects or HTMLElement instances to callback. + * @type {boolean} + */ + #jQuery; + + /**@inheritdoc */ + activateListeners(menu) { + menu.addEventListener('click', this.#onClickItem.bind(this)); + } + + /** + * Handle click events on context menu items. + * @param {PointerEvent} event The click event + */ + #onClickItem(event) { + event.preventDefault(); + event.stopPropagation(); + const element = event.target.closest('.context-item'); + if (!element) return; + const item = this.menuItems.find(i => i.element === element); + item?.callback(this.#jQuery ? $(this.target) : this.target, event); + this.close(); + } + + /* -------------------------------------------- */ + /** * Trigger a context menu event in response to a normal click on a additional options button. * @param {PointerEvent} event @@ -6,11 +99,8 @@ export default class DHContextMenu extends foundry.applications.ux.ContextMenu { static triggerContextMenu(event, altSelector) { event.preventDefault(); event.stopPropagation(); - - const selector = altSelector ?? '[data-item-uuid]'; - if (ui.context?.selector === selector) return; - const { clientX, clientY } = event; + const selector = altSelector ?? '[data-item-uuid]'; const target = event.target.closest(selector) ?? event.currentTarget.closest(selector); target?.dispatchEvent( new PointerEvent('contextmenu', { diff --git a/module/canvas/placeables/_module.mjs b/module/canvas/placeables/_module.mjs index 8746aabd..78242839 100644 --- a/module/canvas/placeables/_module.mjs +++ b/module/canvas/placeables/_module.mjs @@ -1,6 +1,5 @@ export { default as DhMeasuredTemplate } from './measuredTemplate.mjs'; export { default as DhRuler } from './ruler.mjs'; -export { default as DhRegion } from './region.mjs'; -export { default as DhRegionLayer } from './regionLayer.mjs'; +export { default as DhTemplateLayer } from './templateLayer.mjs'; export { default as DhTokenPlaceable } from './token.mjs'; export { default as DhTokenRuler } from './tokenRuler.mjs'; diff --git a/module/canvas/placeables/region.mjs b/module/canvas/placeables/region.mjs deleted file mode 100644 index 7ad94b2f..00000000 --- a/module/canvas/placeables/region.mjs +++ /dev/null @@ -1,12 +0,0 @@ -import DhMeasuredTemplate from './measuredTemplate.mjs'; - -export default class DhRegion extends foundry.canvas.placeables.Region { - /**@inheritdoc */ - _formatMeasuredDistance(distance) { - const range = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.variantRules).rangeMeasurement; - if (!range.enabled) return super._formatMeasuredDistance(distance); - - const { distance: resultDistance, units } = DhMeasuredTemplate.getRangeLabels(distance, range); - return `${resultDistance} ${units}`; - } -} diff --git a/module/canvas/placeables/regionLayer.mjs b/module/canvas/placeables/regionLayer.mjs deleted file mode 100644 index 684fdd5e..00000000 --- a/module/canvas/placeables/regionLayer.mjs +++ /dev/null @@ -1,155 +0,0 @@ -export default class DhRegionLayer extends foundry.canvas.layers.RegionLayer { - static prepareSceneControls() { - const sc = foundry.applications.ui.SceneControls; - const { tools, ...rest } = super.prepareSceneControls(); - - return { - ...rest, - tools: { - select: tools.select, - templateMode: tools.templateMode, - rectangle: tools.rectangle, - circle: tools.circle, - ellipse: tools.ellipse, - cone: tools.cone, - inFront: { - name: 'inFront', - order: 7, - title: 'CONTROLS.inFront', - icon: 'fa-solid fa-eye', - toolclip: { - src: 'toolclips/tools/measure-cone.webm', - heading: 'CONTROLS.inFront', - items: sc.buildToolclipItems(['create', 'move', 'edit', 'hide', 'delete', 'rotate']) - } - }, - ring: { ...tools.ring, order: 8 }, - line: { ...tools.line, order: 9 }, - emanation: { ...tools.emanation, order: 10 }, - polygon: { ...tools.polygon, order: 11 }, - hole: { ...tools.hole, order: 12 }, - snap: { ...tools.snap, order: 13 }, - clear: { ...tools.clear, order: 14 } - } - }; - } - - /** @inheritDoc */ - _isCreationToolActive() { - return this.active && (game.activeTool === 'inFront' || game.activeTool in foundry.data.BaseShapeData.TYPES); - } - - _createDragShapeData(event) { - const hole = ui.controls.controls[this.options.name].tools.hole?.active ?? false; - if (game.activeTool === 'inFront') return { type: 'cone', x: 0, y: 0, radius: 0, angle: 180, hole }; - - const shape = super._createDragShapeData(event); - const token = - shape?.type === 'emanation' && shape.base?.type === 'token' - ? this.#findTokenInBounds(event.interactionData.origin) - : null; - if (token) { - shape.base.width = token.width; - shape.base.height = token.height; - event.interactionData.origin = token.getCenterPoint(); - } - return shape; - } - - async placeRegion(data, options = {}) { - const preConfirm = data => { - const shape = data.document.shapes[0]; - const isEmanation = shape.type === 'emanation'; - if (isEmanation) { - const token = this.#findTokenInBounds(shape.base.origin); - if (!token) return options.preConfirm?.(data) ?? true; - const shapeData = shape.toObject(); - data.document.updateSource({ - shapes: [ - { - ...shapeData, - base: { - ...shapeData.base, - height: token.height, - width: token.width, - x: token.x, - y: token.y - } - } - ] - }); - } - - return options?.preConfirm?.(data) ?? true; - }; - - return await super.placeRegion(data, { ...options, preConfirm }); - } - - /** Searches for token at origin point, returning null if there are no tokens or multiple overlapping tokens */ - #findTokenInBounds(origin) { - const { x, y } = origin; - const gridSize = canvas.grid.size; - const inBounds = canvas.scene.tokens.filter(t => { - return x.between(t.x, t.x + t.width * gridSize) && y.between(t.y, t.y + t.height * gridSize); - }); - return inBounds.length === 1 ? inBounds[0] : null; - } - - static getTemplateShape({ type, angle, range, direction } = {}) { - const { line, rectangle, inFront, cone, circle, emanation } = CONFIG.DH.GENERAL.templateTypes; - - /* Length calculation */ - const { grid, distance } = CONFIG.Scene.documentClass.schema.fields.grid.fields; - const sceneGridSize = canvas.scene?.grid.size ?? grid.size.initial; - const sceneGridDistance = canvas.scene?.grid.distance ?? distance.getInitialValue(); - const dimensionConstant = sceneGridSize / sceneGridDistance; - - const settings = canvas.scene?.rangeSettings; - const rangeNumber = Number(range); - const length = (!Number.isNaN(rangeNumber) ? rangeNumber : settings ? settings[range] : 0) * dimensionConstant; - /*----*/ - - const shapeData = { - ...canvas.mousePosition, - type: type, - direction: direction ?? 0 - }; - - switch (type) { - case rectangle.id: - shapeData.width = length; - shapeData.height = length; - break; - case line.id: - shapeData.length = length; - shapeData.width = 5 * dimensionConstant; - break; - case cone.id: - shapeData.angle = angle ?? CONFIG.MeasuredTemplate.defaults.angle; - shapeData.radius = length; - break; - case inFront.id: - shapeData.angle = '180'; - shapeData.radius = length; - shapeData.type = cone.id; - break; - case circle.id: - shapeData.radius = length; - break; - case emanation.id: - shapeData.radius = length; - shapeData.base = { - type: 'token', - x: 0, - y: 0, - width: 1, - height: 1, - shape: game.canvas.grid.isHexagonal ? CONST.TOKEN_SHAPES.ELLIPSE_1 : CONST.TOKEN_SHAPES.RECTANGLE_1 - }; - break; - } - - return shapeData; - } -} diff --git a/module/canvas/placeables/templateLayer.mjs b/module/canvas/placeables/templateLayer.mjs new file mode 100644 index 00000000..551a06cc --- /dev/null +++ b/module/canvas/placeables/templateLayer.mjs @@ -0,0 +1,116 @@ +export default class DhTemplateLayer extends foundry.canvas.layers.TemplateLayer { + static prepareSceneControls() { + const sc = foundry.applications.ui.SceneControls; + return { + name: 'templates', + order: 2, + title: 'CONTROLS.GroupMeasure', + icon: 'fa-solid fa-ruler-combined', + visible: game.user.can('TEMPLATE_CREATE'), + onChange: (event, active) => { + if (active) canvas.templates.activate(); + }, + onToolChange: () => canvas.templates.setAllRenderFlags({ refreshState: true }), + tools: { + circle: { + name: 'circle', + order: 1, + title: 'CONTROLS.MeasureCircle', + icon: 'fa-regular fa-circle', + toolclip: { + src: 'toolclips/tools/measure-circle.webm', + heading: 'CONTROLS.MeasureCircle', + items: sc.buildToolclipItems(['create', 'move', 'edit', 'hide', 'delete']) + } + }, + cone: { + name: 'cone', + order: 2, + title: 'CONTROLS.MeasureCone', + icon: 'fa-solid fa-angle-left', + toolclip: { + src: 'toolclips/tools/measure-cone.webm', + heading: 'CONTROLS.MeasureCone', + items: sc.buildToolclipItems(['create', 'move', 'edit', 'hide', 'delete', 'rotate']) + } + }, + inFront: { + name: 'inFront', + order: 3, + title: 'CONTROLS.inFront', + icon: 'fa-solid fa-eye', + toolclip: { + src: 'toolclips/tools/measure-cone.webm', + heading: 'CONTROLS.inFront', + items: sc.buildToolclipItems(['create', 'move', 'edit', 'hide', 'delete', 'rotate']) + } + }, + rect: { + name: 'rect', + order: 4, + title: 'CONTROLS.MeasureRect', + icon: 'fa-regular fa-square', + toolclip: { + src: 'toolclips/tools/measure-rect.webm', + heading: 'CONTROLS.MeasureRect', + items: sc.buildToolclipItems(['create', 'move', 'edit', 'hide', 'delete', 'rotate']) + } + }, + ray: { + name: 'ray', + order: 5, + title: 'CONTROLS.MeasureRay', + icon: 'fa-solid fa-up-down', + toolclip: { + src: 'toolclips/tools/measure-ray.webm', + heading: 'CONTROLS.MeasureRay', + items: sc.buildToolclipItems(['create', 'move', 'edit', 'hide', 'delete', 'rotate']) + } + }, + clear: { + name: 'clear', + order: 6, + title: 'CONTROLS.MeasureClear', + icon: 'fa-solid fa-trash', + visible: game.user.isGM, + onChange: () => canvas.templates.deleteAll(), + button: true + } + }, + activeTool: 'circle' + }; + } + + _onDragLeftStart(event) { + const interaction = event.interactionData; + + // Snap the origin to the grid + if (!event.shiftKey) interaction.origin = this.getSnappedPoint(interaction.origin); + + // Create a pending MeasuredTemplateDocument + const tool = game.activeTool === 'inFront' ? 'cone' : game.activeTool; + const previewData = { + user: game.user.id, + t: tool, + x: interaction.origin.x, + y: interaction.origin.y, + sort: Math.max(this.getMaxSort() + 1, 0), + distance: 1, + direction: 0, + fillColor: game.user.color || '#FF0000', + hidden: event.altKey + }; + const defaults = CONFIG.MeasuredTemplate.defaults; + if (game.activeTool === 'cone') previewData.angle = defaults.angle; + else if (game.activeTool === 'inFront') previewData.angle = 180; + else if (game.activeTool === 'ray') previewData.width = defaults.width * canvas.dimensions.distance; + const cls = foundry.utils.getDocumentClass('MeasuredTemplate'); + const doc = new cls(previewData, { parent: canvas.scene }); + + // Create a preview MeasuredTemplate object + const template = new this.constructor.placeableClass(doc); + doc._object = template; + interaction.preview = this.preview.addChild(template); + template.draw(); + } +} diff --git a/module/canvas/placeables/token.mjs b/module/canvas/placeables/token.mjs index 02eed7db..148466c1 100644 --- a/module/canvas/placeables/token.mjs +++ b/module/canvas/placeables/token.mjs @@ -1,4 +1,3 @@ -import { getIconVisibleActiveEffects } from '../../helpers/utils.mjs'; import DhMeasuredTemplate from './measuredTemplate.mjs'; export default class DhTokenPlaceable extends foundry.canvas.placeables.Token { @@ -10,36 +9,6 @@ export default class DhTokenPlaceable extends foundry.canvas.placeables.Token { this.previewHelp ||= this.addChild(this.#drawPreviewHelp()); } - /**@inheritdoc */ - _refreshTurnMarker() { - // Should a Turn Marker be active? - const { turnMarker } = this.document; - const markersEnabled = - CONFIG.Combat.settings.turnMarker.enabled && turnMarker.mode !== CONST.TOKEN_TURN_MARKER_MODES.DISABLED; - const spotlighted = game.settings - .get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.SpotlightTracker) - .spotlightedTokens.has(this.document.uuid); - - const turnIsSet = typeof game.combat?.turn === 'number'; - const isTurn = game.combat?.combatant?.tokenId === this.id; - const markerActive = markersEnabled && turnIsSet ? isTurn : spotlighted; - - // Activate a Turn Marker - if (markerActive) { - if (!this.turnMarker) - this.turnMarker = this.addChildAt(new foundry.canvas.placeables.tokens.TokenTurnMarker(this), 0); - canvas.tokens.turnMarkers.add(this); - this.turnMarker.draw(); - } - - // Remove a Turn Marker - else if (this.turnMarker) { - canvas.tokens.turnMarkers.delete(this); - this.turnMarker.destroy(); - this.turnMarker = null; - } - } - /** @inheritDoc */ async _drawEffects() { this.effects.renderable = false; @@ -51,7 +20,7 @@ export default class DhTokenPlaceable extends foundry.canvas.placeables.Token { this.effects.overlay = null; // Categorize effects - const activeEffects = getIconVisibleActiveEffects(Array.from(this.actor?.allApplicableEffects() ?? [])); + const activeEffects = this.actor?.getActiveEffects() ?? []; const overlayEffect = activeEffects.findLast(e => e.img && e.getFlag?.('core', 'overlay')); // Draw effects @@ -60,8 +29,8 @@ export default class DhTokenPlaceable extends foundry.canvas.placeables.Token { if (!effect.img) continue; const promise = effect === overlayEffect - ? this._drawOverlay(effect.img, effect.tint, effect) - : this._drawEffect(effect.img, effect.tint, effect); + ? this._drawOverlay(effect.img, effect.tint) + : this._drawEffect(effect.img, effect.tint); promises.push( promise.then(e => { if (e) e.zIndex = i; @@ -75,39 +44,6 @@ export default class DhTokenPlaceable extends foundry.canvas.placeables.Token { this.renderFlags.set({ refreshEffects: true }); } - /**@inheritdoc */ - async _drawEffect(src, tint, effect) { - if (!src) return; - const tex = await foundry.canvas.loadTexture(src, { fallback: 'icons/svg/hazard.svg' }); - const icon = new PIXI.Sprite(tex); - icon.tint = tint ?? 0xffffff; - - if (effect.system.stacking?.value > 1) { - const stackOverlay = new PIXI.Text(effect.system.stacking.value, { - fill: '#f3c267', - stroke: '#000000', - fontSize: 96, - strokeThickness: 4 - }); - const nrDigits = Math.floor(Math.log10(effect.system.stacking.value)) + 1; - stackOverlay.y = -8; - /* This does not account for 1:s being much less wide than other digits. I don't think it's desired however as it makes it look jumpy */ - stackOverlay.x = icon.width - 8 - nrDigits * 56; - stackOverlay.anchor.set(0, 0); - - icon.addChild(stackOverlay); - } - - return this.effects.addChild(icon); - } - - async _drawOverlay(src, tint, effect) { - const icon = await this._drawEffect(src, tint, effect); - if (icon) icon.alpha = 0.8; - this.effects.overlay = icon ?? null; - return icon; - } - /** * Returns the distance from this token to another token object. * This value is corrected to handle alternate token sizes and other grid types @@ -155,15 +91,15 @@ export default class DhTokenPlaceable extends foundry.canvas.placeables.Token { const targetEdge = this.#getEdgeBoundary(targetBounds, originPoint, targetPoint); const adjustedOriginPoint = originEdge ? canvas.grid.getTopLeftPoint({ - x: originEdge.x + Math.sign(originPoint.x - originEdge.x), - y: originEdge.y + Math.sign(originPoint.y - originEdge.y) - }) + x: originEdge.x + Math.sign(originPoint.x - originEdge.x), + y: originEdge.y + Math.sign(originPoint.y - originEdge.y) + }) : originPoint; const adjustDestinationPoint = targetEdge ? canvas.grid.getTopLeftPoint({ - x: targetEdge.x + Math.sign(targetPoint.x - targetEdge.x), - y: targetEdge.y + Math.sign(targetPoint.y - targetEdge.y) - }) + x: targetEdge.x + Math.sign(targetPoint.x - targetEdge.x), + y: targetEdge.y + Math.sign(targetPoint.y - targetEdge.y) + }) : targetPoint; const distance = canvas.grid.measurePath([ { ...adjustedOriginPoint, elevation: 0 }, @@ -249,6 +185,9 @@ export default class DhTokenPlaceable extends foundry.canvas.placeables.Token { /** @inheritDoc */ _drawBar(number, bar, data) { + const val = Number(data.value); + const pct = Math.clamp(val, 0, data.max) / data.max; + // Determine sizing const { width, height } = this.document.getSize(); const s = canvas.dimensions.uiScale; @@ -256,19 +195,17 @@ export default class DhTokenPlaceable extends foundry.canvas.placeables.Token { const bh = 8 * (this.document.height >= 2 ? 1.5 : 1) * s; // Determine the color to use - const Color = foundry.utils.Color; - const fillColor = number === 0 ? Color.fromRGB([1, 0, 0]) : Color.fromString('#0032b1'); - const emptyColor = Color.fromRGB([0, 0, 0]); + const fillColor = + number === 0 ? foundry.utils.Color.fromRGB([1, 0, 0]) : foundry.utils.Color.fromString('#0032b1'); - // Draw the bar (accounting floating point numbers from bar animations) - const widthUnit = bw / Math.ceil(data.max); + // Draw the bar + const widthUnit = bw / data.max; bar.clear().lineStyle(s, 0x000000, 1.0); - const sections = [...Array(Math.ceil(data.max)).keys()]; - for (const mark of sections) { + const sections = [...Array(data.max).keys()]; + for (let mark of sections) { const x = mark * widthUnit; - const marked = mark < Math.ceil(data.value); - const remainder = mark === Math.ceil(data.value) - 1 ? data.value % 1 : 0; - const color = !marked ? emptyColor : remainder ? emptyColor.mix(fillColor, remainder) : fillColor; + const marked = mark + 1 <= data.value; + const color = marked ? fillColor : foundry.utils.Color.fromRGB([0, 0, 0]); if (mark === 0 || mark === sections.length - 1) { bar.beginFill(color, marked ? 1.0 : 0.5).drawRect(x, 0, widthUnit, bh, 2 * s); // Would like drawRoundedRect, but it's very troublsome with the corners. Leaving for now. } else { diff --git a/module/canvas/tokens.mjs b/module/canvas/tokens.mjs index 9ca140e0..9813cd48 100644 --- a/module/canvas/tokens.mjs +++ b/module/canvas/tokens.mjs @@ -1 +1,16 @@ -export default class DhTokenLayer extends foundry.canvas.layers.TokenLayer {} +export default class DhTokenLayer extends foundry.canvas.layers.TokenLayer { + async _createPreview(createData, options) { + if (options.actor) { + const tokenSizes = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).tokenSizes; + if (options.actor?.system.metadata.usesSize) { + const tokenSize = tokenSizes[options.actor.system.size]; + if (tokenSize && options.actor.system.size !== CONFIG.DH.ACTOR.tokenSize.custom.id) { + createData.width = tokenSize; + createData.height = tokenSize; + } + } + } + + return super._createPreview(createData, options); + } +} diff --git a/module/config/actionConfig.mjs b/module/config/actionConfig.mjs index a6c04e18..0b1bf91d 100644 --- a/module/config/actionConfig.mjs +++ b/module/config/actionConfig.mjs @@ -115,10 +115,3 @@ export const advantageState = { value: 1 } }; - -export const areaTypes = { - placed: { - id: 'placed', - label: 'Placed Area' - } -}; diff --git a/module/config/generalConfig.mjs b/module/config/generalConfig.mjs index 6fc85ec5..2557e562 100644 --- a/module/config/generalConfig.mjs +++ b/module/config/generalConfig.mjs @@ -70,40 +70,10 @@ export const range = { } }; -export const groupAttackRange = { - melee: range.melee, - veryClose: range.veryClose, - close: range.close, - far: range.far, - veryFar: range.veryFar -}; - -/* circle|cone|rect|ray used to be CONST.MEASURED_TEMPLATE_TYPES. Hardcoded for now */ export const templateTypes = { - circle: { - id: 'circle', - label: 'Circle' - }, - cone: { - id: 'cone', - label: 'Cone' - }, - rectangle: { - id: 'rectangle', - label: 'Rectangle' - }, - line: { - id: 'line', - label: 'Line' - }, - emanation: { - id: 'emanation', - label: 'Emanation' - }, - inFront: { - id: 'inFront', - label: 'In Front' - } + ...CONST.MEASURED_TEMPLATE_TYPES, + EMANATION: 'emanation', + INFRONT: 'inFront' }; export const rangeInclusion = { @@ -271,8 +241,8 @@ export const defaultRestOptions = { type: 'friendly' }, damage: { - parts: { - hitPoints: { + parts: [ + { applyTo: healingTypes.hitPoints.id, value: { custom: { @@ -281,7 +251,7 @@ export const defaultRestOptions = { } } } - } + ] } } }, @@ -305,8 +275,8 @@ export const defaultRestOptions = { type: 'self' }, damage: { - parts: { - stress: { + parts: [ + { applyTo: healingTypes.stress.id, value: { custom: { @@ -315,7 +285,7 @@ export const defaultRestOptions = { } } } - } + ] } } }, @@ -340,8 +310,8 @@ export const defaultRestOptions = { type: 'friendly' }, damage: { - parts: { - armor: { + parts: [ + { applyTo: healingTypes.armor.id, value: { custom: { @@ -350,7 +320,7 @@ export const defaultRestOptions = { } } } - } + ] } } }, @@ -374,8 +344,8 @@ export const defaultRestOptions = { type: 'self' }, damage: { - parts: { - hope: { + parts: [ + { applyTo: healingTypes.hope.id, value: { custom: { @@ -384,7 +354,7 @@ export const defaultRestOptions = { } } } - } + ] } }, prepareWithFriends: { @@ -398,8 +368,8 @@ export const defaultRestOptions = { type: 'self' }, damage: { - parts: { - hope: { + parts: [ + { applyTo: healingTypes.hope.id, value: { custom: { @@ -408,7 +378,7 @@ export const defaultRestOptions = { } } } - } + ] } } }, @@ -435,8 +405,8 @@ export const defaultRestOptions = { type: 'friendly' }, damage: { - parts: { - hitPoints: { + parts: [ + { applyTo: healingTypes.hitPoints.id, value: { custom: { @@ -445,7 +415,7 @@ export const defaultRestOptions = { } } } - } + ] } } }, @@ -469,8 +439,8 @@ export const defaultRestOptions = { type: 'self' }, damage: { - parts: { - stress: { + parts: [ + { applyTo: healingTypes.stress.id, value: { custom: { @@ -479,7 +449,7 @@ export const defaultRestOptions = { } } } - } + ] } } }, @@ -504,17 +474,17 @@ export const defaultRestOptions = { type: 'friendly' }, damage: { - parts: { - armor: { + parts: [ + { applyTo: healingTypes.armor.id, value: { custom: { enabled: true, - formula: '@system.armorScore.max' + formula: '@system.armorScore' } } } - } + ] } } }, @@ -538,8 +508,8 @@ export const defaultRestOptions = { type: 'self' }, damage: { - parts: { - hope: { + parts: [ + { applyTo: healingTypes.hope.id, value: { custom: { @@ -548,7 +518,7 @@ export const defaultRestOptions = { } } } - } + ] } }, prepareWithFriends: { @@ -562,8 +532,8 @@ export const defaultRestOptions = { type: 'self' }, damage: { - parts: { - hope: { + parts: [ + { applyTo: healingTypes.hope.id, value: { custom: { @@ -572,7 +542,7 @@ export const defaultRestOptions = { } } } - } + ] } } }, @@ -734,14 +704,14 @@ const getDiceSoNiceSFX = sfxOptions => { if (sfxOptions.critical && criticalAnimationData.class) { return { specialEffect: criticalAnimationData.class, - options: { ...criticalAnimationData.options } + options: {} }; } if (sfxOptions.higher && sfxOptions.data.higher) { return { specialEffect: sfxOptions.data.higher.class, - options: { ...sfxOptions.data.higher.options } + options: {} }; } @@ -984,144 +954,3 @@ export const sceneRangeMeasurementSetting = { label: 'DAGGERHEART.CONFIG.SceneRangeMeasurementTypes.custom' } }; - -export const tagTeamRollTypes = { - trait: { - id: 'trait', - label: 'DAGGERHEART.CONFIG.TagTeamRollTypes.trait' - }, - ability: { - id: 'ability', - label: 'DAGGERHEART.CONFIG.TagTeamRollTypes.ability' - }, - damageAbility: { - id: 'damageAbility', - label: 'DAGGERHEART.CONFIG.TagTeamRollTypes.damageAbility' - } -}; - -export const baseActiveEffectModes = { - custom: { - id: 'custom', - priority: 0, - label: 'EFFECT.CHANGES.TYPES.custom' - }, - multiply: { - id: 'multiply', - priority: 10, - label: 'EFFECT.CHANGES.TYPES.multiply' - }, - add: { - id: 'add', - priority: 20, - label: 'EFFECT.CHANGES.TYPES.add' - }, - subtract: { - id: 'subtract', - priority: 20, - label: 'EFFECT.CHANGES.TYPES.subtract' - }, - downgrade: { - id: 'downgrade', - priority: 30, - label: 'EFFECT.CHANGES.TYPES.downgrade' - }, - upgrade: { - id: 'upgrade', - priority: 40, - label: 'EFFECT.CHANGES.TYPES.upgrade' - }, - override: { - id: 'override', - priority: 50, - label: 'EFFECT.CHANGES.TYPES.override' - } -}; - -export const activeEffectModes = { - armor: { - id: 'armor', - priority: 20, - label: 'TYPES.ActiveEffect.armor' - }, - ...baseActiveEffectModes -}; - -export const activeEffectArmorInteraction = { - none: { id: 'none', label: 'DAGGERHEART.CONFIG.ArmorInteraction.none.label' }, - active: { id: 'active', label: 'DAGGERHEART.CONFIG.ArmorInteraction.active.label' }, - inactive: { id: 'inactive', label: 'DAGGERHEART.CONFIG.ArmorInteraction.inactive.label' } -}; - -export const activeEffectDurations = { - temporary: { - id: 'temporary', - label: 'DAGGERHEART.CONFIG.ActiveEffectDuration.temporary' - }, - act: { - id: 'act', - label: 'DAGGERHEART.CONFIG.ActiveEffectDuration.act' - }, - scene: { - id: 'scene', - label: 'DAGGERHEART.CONFIG.ActiveEffectDuration.scene' - }, - shortRest: { - id: 'shortRest', - label: 'DAGGERHEART.CONFIG.ActiveEffectDuration.shortRest' - }, - longRest: { - id: 'longRest', - label: 'DAGGERHEART.CONFIG.ActiveEffectDuration.longRest' - }, - session: { - id: 'session', - label: 'DAGGERHEART.CONFIG.ActiveEffectDuration.session' - }, - custom: { - id: 'custom', - label: 'DAGGERHEART.CONFIG.ActiveEffectDuration.custom' - } -}; - -export const fallAndCollisionDamage = { - veryClose: { - id: 'veryClose', - label: 'DAGGERHEART.CONFIG.fallAndCollision.veryClose.label', - chatTitle: 'DAGGERHEART.CONFIG.fallAndCollision.veryClose.chatTitle', - damageFormula: '1d10 + 3' - }, - close: { - id: 'veryClose', - label: 'DAGGERHEART.CONFIG.fallAndCollision.close.label', - chatTitle: 'DAGGERHEART.CONFIG.fallAndCollision.close.chatTitle', - damageFormula: '1d20 + 5' - }, - far: { - id: 'veryClose', - label: 'DAGGERHEART.CONFIG.fallAndCollision.far.label', - chatTitle: 'DAGGERHEART.CONFIG.fallAndCollision.far.chatTitle', - damageFormula: '1d100 + 15' - }, - collision: { - id: 'veryClose', - label: 'DAGGERHEART.CONFIG.fallAndCollision.collision.label', - chatTitle: 'DAGGERHEART.CONFIG.fallAndCollision.collision.chatTitle', - damageFormula: '1d20 + 5' - } -}; - -export const simpleDispositions = { - [-1]: { - id: -1, - label: 'TOKEN.DISPOSITION.HOSTILE' - }, - [0]: { - id: 0, - label: 'TOKEN.DISPOSITION.NEUTRAL' - }, - [1]: { - id: 1, - label: 'TOKEN.DISPOSITION.FRIENDLY' - } -}; diff --git a/module/config/hooksConfig.mjs b/module/config/hooksConfig.mjs index c0930d90..61ba594c 100644 --- a/module/config/hooksConfig.mjs +++ b/module/config/hooksConfig.mjs @@ -1,6 +1,4 @@ export const hooksConfig = { effectDisplayToggle: 'DHEffectDisplayToggle', - lockedTooltipDismissed: 'DHLockedTooltipDismissed', - tagTeamStart: 'DHTagTeamRollStart', - groupRollStart: 'DHGroupRollStart' + lockedTooltipDismissed: 'DHLockedTooltipDismissed' }; diff --git a/module/config/itemBrowserConfig.mjs b/module/config/itemBrowserConfig.mjs index 83572dc0..638c1504 100644 --- a/module/config/itemBrowserConfig.mjs +++ b/module/config/itemBrowserConfig.mjs @@ -70,65 +70,17 @@ export const typeConfig = { } ] }, - environments: { - columns: [ - { - key: 'system.tier', - label: 'DAGGERHEART.GENERAL.Tiers.singular' - }, - { - key: 'system.type', - label: 'DAGGERHEART.GENERAL.type', - format: type => { - if (!type) return '-'; - - return CONFIG.DH.ACTOR.environmentTypes[type].label; - } - } - ], - filters: [ - { - key: 'system.tier', - label: 'DAGGERHEART.GENERAL.Tiers.singular', - field: 'system.api.models.actors.DhEnvironment.schema.fields.tier' - }, - { - key: 'system.type', - label: 'DAGGERHEART.GENERAL.type', - field: 'system.api.models.actors.DhEnvironment.schema.fields.type' - }, - { - key: 'system.difficulty', - name: 'difficulty.min', - label: 'DAGGERHEART.UI.ItemBrowser.difficultyMin', - field: 'system.api.models.actors.DhEnvironment.schema.fields.difficulty', - operator: 'gte' - }, - { - key: 'system.difficulty', - name: 'difficulty.max', - label: 'DAGGERHEART.UI.ItemBrowser.difficultyMax', - field: 'system.api.models.actors.DhEnvironment.schema.fields.difficulty', - operator: 'lte' - } - ] - }, items: { columns: [ { key: 'type', label: 'DAGGERHEART.GENERAL.type', - format: type => (type ? `TYPES.Item.${type}` : '-') + format: type => type ? `TYPES.Item.${type}` : '-' }, { key: 'system.secondary', label: 'DAGGERHEART.UI.ItemBrowser.subtype', - format: isSecondary => - isSecondary - ? 'DAGGERHEART.ITEMS.Weapon.secondaryWeapon.short' - : isSecondary === false - ? 'DAGGERHEART.ITEMS.Weapon.primaryWeapon.short' - : '-' + format: isSecondary => (isSecondary ? 'DAGGERHEART.ITEMS.Weapon.secondaryWeapon.short' : isSecondary === false ? 'DAGGERHEART.ITEMS.Weapon.primaryWeapon.short' : '-') }, { key: 'system.tier', @@ -220,8 +172,8 @@ export const typeConfig = { key: 'system.secondary', label: 'DAGGERHEART.UI.ItemBrowser.subtype', choices: [ - { value: false, label: 'DAGGERHEART.ITEMS.Weapon.primaryWeapon.full' }, - { value: true, label: 'DAGGERHEART.ITEMS.Weapon.secondaryWeapon.full' } + { value: false, label: 'DAGGERHEART.ITEMS.Weapon.primaryWeapon.short' }, + { value: true, label: 'DAGGERHEART.ITEMS.Weapon.secondaryWeapon.short' } ] }, { @@ -308,12 +260,12 @@ export const typeConfig = { { key: 'system.type', label: 'DAGGERHEART.GENERAL.type', - format: type => (type ? `DAGGERHEART.CONFIG.DomainCardTypes.${type}` : '-') + format: type => type ? `DAGGERHEART.CONFIG.DomainCardTypes.${type}` : '-' }, { key: 'system.domain', label: 'DAGGERHEART.GENERAL.Domain.single', - format: domain => (domain ? CONFIG.DH.DOMAIN.allDomains()[domain].label : '-') + format: domain => domain ? CONFIG.DH.DOMAIN.allDomains()[domain].label : '-' }, { key: 'system.level', @@ -426,8 +378,7 @@ export const typeConfig = { { key: 'system.linkedClass', label: 'TYPES.Item.class', - format: linkedClass => - foundry.utils.fromUuidSync(linkedClass)?.name ?? 'DAGGERHEART.UI.ItemBrowser.missing' + format: linkedClass => linkedClass?.name ?? 'DAGGERHEART.UI.ItemBrowser.missing' }, { key: 'system.spellcastingTrait', @@ -437,20 +388,15 @@ export const typeConfig = { ], filters: [ { - key: 'system.linkedClass', + key: 'system.linkedClass.uuid', label: 'TYPES.Item.class', - choices: async items => { - const list = []; - for (const item of items.filter(item => item.system.linkedClass)) { - const linkedClass = await foundry.utils.fromUuid(item.system.linkedClass); - if (linkedClass) { - list.push({ - value: linkedClass.uuid, - label: linkedClass.name - }); - } - } - + choices: items => { + const list = items + .filter(item => item.system.linkedClass) + .map(item => ({ + value: item.system.linkedClass.uuid, + label: item.system.linkedClass.name + })); return list.reduce((a, c) => { if (!a.find(i => i.value === c.value)) a.push(c); return a; @@ -604,8 +550,7 @@ export const compendiumConfig = { id: 'environments', keys: ['environments'], label: 'DAGGERHEART.UI.ItemBrowser.folders.environments', - type: ['environment'], - listType: 'environments' + type: ['environment'] }, beastforms: { id: 'beastforms', diff --git a/module/config/itemConfig.mjs b/module/config/itemConfig.mjs index 43054ec5..11330aee 100644 --- a/module/config/itemConfig.mjs +++ b/module/config/itemConfig.mjs @@ -14,8 +14,8 @@ export const armorFeatures = { type: 'hostile' }, damage: { - parts: { - stress: { + parts: [ + { applyTo: 'stress', value: { custom: { @@ -24,7 +24,7 @@ export const armorFeatures = { } } } - } + ] } } ] @@ -453,7 +453,7 @@ export const allArmorFeatures = () => { const feature = homebrewFeatures[key]; const actions = feature.actions.map(action => ({ ...action, - effects: action.effects?.map(effect => feature.effects.find(x => x.id === effect._id)) ?? [], + effects: action.effects?.map(effect => feature.effects.find(x => x.id === effect._id))??[], type: action.type })); const actionEffects = actions.flatMap(a => a.effects); @@ -489,18 +489,15 @@ export const weaponFeatures = { description: 'DAGGERHEART.CONFIG.WeaponFeature.barrier.effects.barrier.description', img: 'icons/skills/melee/shield-block-bash-blue.webp', changes: [ + { + key: 'system.armorScore', + mode: 2, + value: 'ITEM.@system.tier + 1' + }, { key: 'system.evasion', mode: 2, value: '-1' - }, - { - key: 'Armor', - type: 'armor', - typeData: { - type: 'armor', - max: 'ITEM.@system.tier + 1' - } } ] } @@ -735,8 +732,8 @@ export const weaponFeatures = { type: 'hostile' }, damage: { - parts: { - stress: { + parts: [ + { applyTo: 'stress', value: { custom: { @@ -745,7 +742,7 @@ export const weaponFeatures = { } } } - } + ] } } ], @@ -792,6 +789,11 @@ export const weaponFeatures = { description: 'DAGGERHEART.CONFIG.WeaponFeature.doubleDuty.effects.doubleDuty.description', img: 'icons/skills/melee/sword-shield-stylized-white.webp', changes: [ + { + key: 'system.armorScore', + mode: 2, + value: '1' + }, { key: 'system.bonuses.damage.primaryWeapon.bonus', mode: 2, @@ -806,22 +808,6 @@ export const weaponFeatures = { type: 'withinRange' } } - }, - { - name: 'DAGGERHEART.CONFIG.WeaponFeature.doubleDuty.effects.doubleDuty.name', - description: 'DAGGERHEART.CONFIG.WeaponFeature.doubleDuty.effects.doubleDuty.description', - img: 'icons/skills/melee/sword-shield-stylized-white.webp', - changes: [ - { - key: 'Armor', - type: 'armor', - value: 0, - typeData: { - type: 'armor', - max: 1 - } - } - ] } ] }, @@ -928,8 +914,8 @@ export const weaponFeatures = { type: 'self' }, damage: { - parts: { - hitPoints: { + parts: [ + { applyTo: 'hitPoints', value: { custom: { @@ -938,7 +924,7 @@ export const weaponFeatures = { } } } - } + ] } } ] @@ -1205,13 +1191,9 @@ export const weaponFeatures = { img: 'icons/skills/melee/shield-block-gray-orange.webp', changes: [ { - key: 'Armor', - type: 'armor', - value: 0, - typeData: { - type: 'armor', - max: 'ITEM.@system.tier' - } + key: 'system.armorScore', + mode: 2, + value: 'ITEM.@system.tier' } ] } @@ -1407,7 +1389,7 @@ export const allWeaponFeatures = () => { const actions = feature.actions.map(action => ({ ...action, - effects: action.effects?.map(effect => feature.effects.find(x => x.id === effect._id)) ?? [], + effects: action.effects?.map(effect => feature.effects.find(x => x.id === effect._id))??[], type: action.type })); const actionEffects = actions.flatMap(a => a.effects); diff --git a/module/config/resourceConfig.mjs b/module/config/resourceConfig.mjs index d33d7ab3..1306d327 100644 --- a/module/config/resourceConfig.mjs +++ b/module/config/resourceConfig.mjs @@ -60,7 +60,7 @@ const companionBaseResources = Object.freeze({ max: 3, reverse: true, label: 'DAGGERHEART.GENERAL.stress' - } + }, }); export const character = { diff --git a/module/config/settingsConfig.mjs b/module/config/settingsConfig.mjs index 50841084..8036d789 100644 --- a/module/config/settingsConfig.mjs +++ b/module/config/settingsConfig.mjs @@ -1,6 +1,5 @@ export const keybindings = { - spotlight: 'DHSpotlight', - partySheet: 'DHPartySheet' + spotlight: 'DHSpotlight' }; export const menu = { @@ -39,10 +38,9 @@ export const gameSettings = { LevelTiers: 'LevelTiers', Countdowns: 'Countdowns', LastMigrationVersion: 'LastMigrationVersion', + TagTeamRoll: 'TagTeamRoll', SpotlightRequestQueue: 'SpotlightRequestQueue', - CompendiumBrowserSettings: 'CompendiumBrowserSettings', - SpotlightTracker: 'SpotlightTracker', - ActiveParty: 'ActiveParty' + CompendiumBrowserSettings: 'CompendiumBrowserSettings' }; export const actionAutomationChoices = { diff --git a/module/data/_module.mjs b/module/data/_module.mjs index a54da0e1..52fa689e 100644 --- a/module/data/_module.mjs +++ b/module/data/_module.mjs @@ -1,11 +1,9 @@ export { default as DhCombat } from './combat.mjs'; export { default as DhCombatant } from './combatant.mjs'; +export { default as DhTagTeamRoll } from './tagTeamRoll.mjs'; export { default as DhRollTable } from './rollTable.mjs'; export { default as RegisteredTriggers } from './registeredTriggers.mjs'; export { default as CompendiumBrowserSettings } from './compendiumBrowserSettings.mjs'; -export { default as TagTeamData } from './tagTeamData.mjs'; -export { default as GroupRollData } from './groupRollData.mjs'; -export { default as SpotlightTracker } from './spotlightTracker.mjs'; export * as countdowns from './countdowns.mjs'; export * as actions from './action/_module.mjs'; @@ -15,4 +13,3 @@ export * as chatMessages from './chat-message/_modules.mjs'; export * as fields from './fields/_module.mjs'; export * as items from './item/_module.mjs'; export * as scenes from './scene/_module.mjs'; -export * as regionBehaviors from './regionBehavior/_module.mjs'; diff --git a/module/data/action/attackAction.mjs b/module/data/action/attackAction.mjs index 1988b1d8..60112c40 100644 --- a/module/data/action/attackAction.mjs +++ b/module/data/action/attackAction.mjs @@ -1,3 +1,4 @@ +import { DHDamageData } from '../fields/action/damageField.mjs'; import DHDamageAction from './damageAction.mjs'; export default class DHAttackAction extends DHDamageAction { @@ -11,19 +12,8 @@ export default class DHAttackAction extends DHDamageAction { super.prepareData(); if (!!this.item?.system?.attack) { if (this.damage.includeBase) { - const baseDamage = this.getParentHitPointDamage(); - if (baseDamage) { - if (!this.damage.parts.hitPoints) { - this.damage.parts.hitPoints = baseDamage; - } else { - for (const type of baseDamage.type) this.damage.parts.hitPoints.type.add(type); - - this.damage.parts.hitPoints.value.custom = { - enabled: true, - formula: `${baseDamage.value.getFormula()} + ${this.damage.parts.hitPoints.value.getFormula()}` - }; - } - } + const baseDamage = this.getParentDamage(); + this.damage.parts.unshift(new DHDamageData(baseDamage)); } if (this.roll.useDefault) { this.roll.trait = this.item.system.attack.roll.trait; @@ -32,19 +22,27 @@ export default class DHAttackAction extends DHDamageAction { } } - getParentHitPointDamage() { - return this.item?.system?.attack.damage.parts.hitPoints; + getParentDamage() { + return { + value: { + multiplier: 'prof', + dice: this.item?.system?.attack.damage.parts[0].value.dice, + bonus: this.item?.system?.attack.damage.parts[0].value.bonus ?? 0 + }, + type: this.item?.system?.attack.damage.parts[0].type, + base: true + }; } get damageFormula() { - const hitPointsPart = this.damage.parts.hitPoints; + const hitPointsPart = this.damage.parts.find(x => x.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id); if (!hitPointsPart) return '0'; return hitPointsPart.value.getFormula(); } get altDamageFormula() { - const hitPointsPart = this.damage.parts.hitPoints; + const hitPointsPart = this.damage.parts.find(x => x.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id); if (!hitPointsPart) return '0'; return hitPointsPart.valueAlt.getFormula(); @@ -52,8 +50,9 @@ export default class DHAttackAction extends DHDamageAction { async use(event, options) { const result = await super.use(event, options); + if (!result.message) return; - if (result?.message?.system.action?.roll?.type === 'attack') { + if (result.message.system.action.roll?.type === 'attack') { const { updateCountdowns } = game.system.api.applications.ui.DhCountdowns; await updateCountdowns(CONFIG.DH.GENERAL.countdownProgressionTypes.characterAttack.id); } @@ -75,12 +74,7 @@ export default class DHAttackAction extends DHDamageAction { const useAltDamage = this.actor?.effects?.find(x => x.type === 'horde')?.active; for (const { value, valueAlt, type } of damage.parts) { const usedValue = useAltDamage ? valueAlt : value; - const damageString = Roll.replaceFormulaData(usedValue.getFormula(), this.actor?.getRollData() ?? {}); - const str = damageString - ? damageString - : game.i18n.format('DAGGERHEART.GENERAL.missingX', { - x: game.i18n.localize('DAGGERHEART.GENERAL.damage') - }); + const str = Roll.replaceFormulaData(usedValue.getFormula(), this.actor?.getRollData() ?? {}); const icons = Array.from(type) .map(t => CONFIG.DH.GENERAL.damageTypes[t]?.icon) diff --git a/module/data/action/baseAction.mjs b/module/data/action/baseAction.mjs index c71f5ef9..992e1714 100644 --- a/module/data/action/baseAction.mjs +++ b/module/data/action/baseAction.mjs @@ -15,7 +15,7 @@ const fields = foundry.data.fields; */ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel) { - static extraSchemas = ['areas', 'cost', 'uses', 'range']; + static extraSchemas = ['cost', 'uses', 'range']; /** @inheritDoc */ static defineSchema() { @@ -110,11 +110,6 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel return this._id; } - /** Returns true if the current user is the owner of the containing item */ - get isOwner() { - return this.item?.isOwner ?? true; - } - /** * Return Item the action is attached too. */ @@ -144,18 +139,8 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel return this.item instanceof DhpActor ? this.item : this.item?.parent instanceof DhpActor - ? this.item.parent - : null; - } - - /** - * Returns true if the action is usable. - * An action is usable on any actor type. For example, an adversary might have a base attack action. - */ - get usable() { - const actor = this.actor; - const pack = actor?.pack ? game.packs.get(actor.pack) : null; - return !pack?.locked && this.isOwner; + ? this.item.parent + : null; } static getRollType(parent) { @@ -222,10 +207,10 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel * @param {Event} event Event from the button used to trigger the Action * @returns {object} */ - async use(event, configOptions = {}) { - if (!this.actor) throw new Error('An Action can\'t be used outside of an Actor context.'); + async use(event) { + if (!this.actor) throw new Error("An Action can't be used outside of an Actor context."); - let config = this.prepareConfig(event, configOptions); + let config = this.prepareConfig(event); if (!config) return; config.effects = await game.system.api.data.actions.actionsTypes.base.getEffects(this.actor, this.item); @@ -246,7 +231,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel if (Hooks.call(`${CONFIG.DH.id}.postUseAction`, this, config) === false) return; - if (this.chatDisplay && !config.skips.createMessage && !config.actionChatMessageHandled) await this.toChat(); + if (this.chatDisplay && !config.actionChatMessageHandled) await this.toChat(); return config; } @@ -256,7 +241,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel * @param {Event} event Event from the button used to trigger the Action * @returns {object} */ - prepareBaseConfig(event, configOptions = {}) { + prepareBaseConfig(event) { const isActor = this.item instanceof CONFIG.Actor.documentClass; const actionTitle = game.i18n.localize(this.name); const itemTitle = isActor || this.item.name === actionTitle ? '' : `${this.item.name} - `; @@ -279,42 +264,13 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel hasSave: this.hasSave, onSave: this.save?.damageMod, isDirect: !!this.damage?.direct, - selectedMessageMode: game.settings.get('core', 'messageMode'), + selectedRollMode: game.settings.get('core', 'rollMode'), data: this.getRollData(), evaluate: this.hasRoll, resourceUpdates: new ResourceUpdateMap(this.actor), - targetUuid: this.targetUuid, - ...configOptions, - skips: { - resources: false, - triggers: false, - createMessage: false, - updateCountdowns: false, - reaction: false, - ...(configOptions.skips ?? {}) - } + targetUuid: this.targetUuid }; - if (this.damage) { - config.isDirect = this.damage.direct; - - const groupAttackTokens = this.damage.groupAttack - ? game.system.api.fields.ActionFields.DamageField.getGroupAttackTokens( - this.actor.id, - this.damage.groupAttack - ) - : null; - - config.damageOptions = { - groupAttack: this.damage.groupAttack - ? { - numAttackers: Math.max(groupAttackTokens.length, 1), - range: this.damage.groupAttack - } - : null - }; - } - DHBaseAction.applyKeybindings(config); return config; } @@ -324,8 +280,8 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel * @param {Event} event Event from the button used to trigger the Action * @returns {object} */ - prepareConfig(event, configOptions = {}) { - const config = this.prepareBaseConfig(event, configOptions); + prepareConfig(event) { + const config = this.prepareBaseConfig(event); for (const clsField of Object.values(this.schema.fields)) { if (clsField?.prepareConfig) if (clsField.prepareConfig.call(this, config) === false) return false; } @@ -341,19 +297,17 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel static async getEffects(actor, effectParent) { if (!actor) return []; - return Array.from(await actor.allApplicableEffects({ noTransferArmor: true, noSelfArmor: true })).filter( - effect => { - /* Effects on weapons only ever apply for the weapon itself */ - if (effect.parent.type === 'weapon') { - /* Unless they're secondary - then they apply only to other primary weapons */ - if (effect.parent.system.secondary) { - if (effectParent?.type !== 'weapon' || effectParent?.system.secondary) return false; - } else if (effectParent?.id !== effect.parent.id) return false; - } - - return !effect.isSuppressed; + return Array.from(await actor.allApplicableEffects()).filter(effect => { + /* Effects on weapons only ever apply for the weapon itself */ + if (effect.parent.type === 'weapon') { + /* Unless they're secondary - then they apply only to other primary weapons */ + if (effect.parent.system.secondary) { + if (effectParent?.type !== 'weapon' || effectParent?.system.secondary) return false; + } else if (effectParent?.id !== effect.parent.id) return false; } - ); + + return !effect.isSuppressed; + }); } /** @@ -372,7 +326,6 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel * @param {boolean} successCost */ async consume(config, successCost = false) { - config.resourceUpdates = new ResourceUpdateMap(config.actionActor); await this.workflow.get('cost')?.execute(config, successCost); await this.workflow.get('uses')?.execute(config, successCost); @@ -401,11 +354,11 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel } get hasDamage() { - return Boolean(Object.keys(this.damage?.parts ?? {}).length) && this.type !== 'healing'; + return this.damage?.parts?.length && this.type !== 'healing'; } get hasHealing() { - return Boolean(Object.keys(this.damage?.parts ?? {}).length) && this.type === 'healing'; + return this.damage?.parts?.length && this.type === 'healing'; } get hasSave() { @@ -425,15 +378,6 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel return tags; } - - static migrateData(source) { - if (source.damage?.parts && Array.isArray(source.damage.parts)) { - source.damage.parts = source.damage.parts.reduce((acc, part) => { - acc[part.applyTo] = part; - return acc; - }, {}); - } - } } export class ResourceUpdateMap extends Map { diff --git a/module/data/action/beastformAction.mjs b/module/data/action/beastformAction.mjs index 8855b122..657cfde2 100644 --- a/module/data/action/beastformAction.mjs +++ b/module/data/action/beastformAction.mjs @@ -2,4 +2,84 @@ import DHBaseAction from './baseAction.mjs'; export default class DhBeastformAction extends DHBaseAction { static extraSchemas = [...super.extraSchemas, 'beastform']; + + /* async use(event, options) { + const beastformConfig = this.prepareBeastformConfig(); + + const abort = await this.handleActiveTransformations(); + if (abort) return; + + const calcCosts = game.system.api.fields.ActionFields.CostField.calcCosts.call(this, this.cost); + const hasCost = game.system.api.fields.ActionFields.CostField.hasCost.call(this, calcCosts); + if (!hasCost) { + ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.insufficientResources')); + return; + } + + const { selected, evolved, hybrid } = await BeastformDialog.configure(beastformConfig, this.item); + if (!selected) return; + + const result = await super.use(event, options); + if (!result) return; + + await this.transform(selected, evolved, hybrid); + } + + prepareBeastformConfig(config) { + const settingsTiers = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers).tiers; + const actorLevel = this.actor.system.levelData.level.current; + const actorTier = + Object.values(settingsTiers).find( + tier => actorLevel >= tier.levels.start && actorLevel <= tier.levels.end + ) ?? 1; + + return { + tierLimit: this.beastform.tierAccess.exact ?? actorTier + }; + } + + async transform(selectedForm, evolvedData, hybridData) { + const formData = evolvedData?.form ? evolvedData.form.toObject() : selectedForm.toObject(); + const beastformEffect = formData.effects.find(x => x.type === 'beastform'); + if (!beastformEffect) { + ui.notifications.error('DAGGERHEART.UI.Notifications.beastformMissingEffect'); + return; + } + + if (evolvedData?.form) { + const evolvedForm = selectedForm.effects.find(x => x.type === 'beastform'); + if (!evolvedForm) { + ui.notifications.error('DAGGERHEART.UI.Notifications.beastformMissingEffect'); + return; + } + + beastformEffect.changes = [...beastformEffect.changes, ...evolvedForm.changes]; + formData.system.features = [...formData.system.features, ...selectedForm.system.features.map(x => x.uuid)]; + } + + if (selectedForm.system.beastformType === CONFIG.DH.ITEM.beastformTypes.hybrid.id) { + formData.system.advantageOn = Object.values(hybridData.advantages).reduce((advantages, formCategory) => { + Object.keys(formCategory).forEach(advantageKey => { + advantages[advantageKey] = formCategory[advantageKey]; + }); + return advantages; + }, {}); + formData.system.features = [ + ...formData.system.features, + ...Object.values(hybridData.features).flatMap(x => Object.keys(x)) + ]; + } + + this.actor.createEmbeddedDocuments('Item', [formData]); + } + + async handleActiveTransformations() { + const beastformEffects = this.actor.effects.filter(x => x.type === 'beastform'); + const existingEffects = beastformEffects.length > 0; + await this.actor.deleteEmbeddedDocuments( + 'ActiveEffect', + beastformEffects.map(x => x.id) + ); + return existingEffects; + } */ } diff --git a/module/data/action/countdownAction.mjs b/module/data/action/countdownAction.mjs index cb141637..abcc6b40 100644 --- a/module/data/action/countdownAction.mjs +++ b/module/data/action/countdownAction.mjs @@ -36,7 +36,7 @@ export default class DhCountdownAction extends DHBaseAction { /** @inheritDoc */ static migrateData(source) { - for (const countdown of Object.values(source.countdown)) { + for (const countdown of source.countdown) { if (countdown.progress.max) { countdown.progress.startFormula = countdown.progress.max; countdown.progress.start = 1; diff --git a/module/data/activeEffect/_module.mjs b/module/data/activeEffect/_module.mjs index 3c933a9c..1a50088a 100644 --- a/module/data/activeEffect/_module.mjs +++ b/module/data/activeEffect/_module.mjs @@ -1,7 +1,6 @@ import BaseEffect from './baseEffect.mjs'; import BeastformEffect from './beastformEffect.mjs'; import HordeEffect from './hordeEffect.mjs'; -export { changeTypes, changeEffects } from './changeTypes/_module.mjs'; export { BaseEffect, BeastformEffect, HordeEffect }; diff --git a/module/data/activeEffect/baseEffect.mjs b/module/data/activeEffect/baseEffect.mjs index 9b17164d..ea74531d 100644 --- a/module/data/activeEffect/baseEffect.mjs +++ b/module/data/activeEffect/baseEffect.mjs @@ -12,50 +12,11 @@ * "Anything that uses another data model value as its value": +1 - Effects that increase traits have to be calculated first at Base priority. (EX: Raise evasion by half your agility) */ -import { getScrollTextData } from '../../helpers/utils.mjs'; -import { changeTypes } from './_module.mjs'; - -export default class BaseEffect extends foundry.data.ActiveEffectTypeDataModel { +export default class BaseEffect extends foundry.abstract.TypeDataModel { static defineSchema() { const fields = foundry.data.fields; - const baseChanges = Object.keys(CONFIG.DH.GENERAL.baseActiveEffectModes).reduce((r, type) => { - r[type] = new fields.SchemaField({ - key: new fields.StringField({ required: true }), - type: new fields.StringField({ - required: true, - choices: [type], - initial: type, - validate: BaseEffect.#validateType - }), - value: new fields.AnyField({ - required: true, - nullable: true, - serializable: true, - initial: '' - }), - phase: new fields.StringField({ required: true, blank: false, initial: 'initial' }), - priority: new fields.NumberField() - }); - return r; - }, {}); - return { - ...super.defineSchema(), - changes: new fields.ArrayField( - new fields.TypedSchemaField( - { ...changeTypes, ...baseChanges }, - { initial: baseChanges.add.getInitialValue() } - ) - ), - duration: new fields.SchemaField({ - type: new fields.StringField({ - choices: CONFIG.DH.GENERAL.activeEffectDurations, - blank: true, - label: 'DAGGERHEART.GENERAL.type' - }), - description: new fields.HTMLField({ label: 'DAGGERHEART.GENERAL.description' }) - }), rangeDependence: new fields.SchemaField({ enabled: new fields.BooleanField({ required: true, @@ -80,71 +41,17 @@ export default class BaseEffect extends foundry.data.ActiveEffectTypeDataModel { initial: CONFIG.DH.GENERAL.range.melee.id, label: 'DAGGERHEART.GENERAL.range' }) - }), - stacking: new fields.SchemaField( - { - value: new fields.NumberField({ - initial: 1, - min: 1, - integer: true, - nullable: false, - label: 'DAGGERHEART.GENERAL.value' - }), - max: new fields.NumberField({ integer: true, label: 'DAGGERHEART.GENERAL.max' }) - }, - { nullable: true, initial: null } - ), - targetDispositions: new fields.SetField( - new fields.NumberField({ - choices: CONFIG.DH.GENERAL.simpleDispositions - }), - { label: 'DAGGERHEART.ACTIVEEFFECT.Config.targetDispositions' } - ) + }) }; } - /** - * Validate that an {@link EffectChangeData#type} string is well-formed. - * @param {string} type The string to be validated - * @returns {true} - * @throws {Error} An error if the type string is malformed - */ - static #validateType(type) { - if (type.length < 3) throw new Error('must be at least three characters long'); - if (!/^custom\.-?\d+$/.test(type) && !type.split('.').every(s => /^[a-z0-9]+$/i.test(s))) { - throw new Error( - 'A change type must either be a sequence of dot-delimited, alpha-numeric substrings or of the form' + - ' "custom.{number}"' - ); - } - return true; - } - - get isSuppressed() { - for (const change of this.changes) { - if (change.isSuppressed) return true; - } - } - - get armorChange() { - return this.changes.find(x => x.type === CONFIG.DH.GENERAL.activeEffectModes.armor.id); - } - - get armorData() { - const armorChange = this.armorChange; - if (!armorChange) return null; - - return armorChange.getArmorData(); - } - - static getDefaultObject(options = { transfer: true }) { + static getDefaultObject() { return { name: 'New Effect', id: foundry.utils.randomID(), disabled: false, img: 'icons/magic/life/heart-cross-blue.webp', description: '', - transfer: options.transfer, statuses: [], changes: [], system: { @@ -157,32 +64,4 @@ export default class BaseEffect extends foundry.data.ActiveEffectTypeDataModel { } }; } - - async _preUpdate(changed, options, userId) { - const allowed = await super._preUpdate(changed, options, userId); - if (allowed === false) return false; - - const autoSettings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation); - if ( - autoSettings.resourceScrollTexts && - this.parent.actor?.type === 'character' && - this.parent.actor.system.resources.armor - ) { - const armorEffect = changed.system?.changes?.find(x => x.type === 'armor'); - const newArmorTotal = - armorEffect?.value?.current + (this.parent.actor.system.armor?.system?.armor?.current ?? 0); - - if (armorEffect && newArmorTotal !== this.parent.actor.system.armorScore.value) { - const armorData = getScrollTextData(this.parent.actor, { value: newArmorTotal }, 'armor'); - options.scrollingTextData = [armorData]; - } - } - } - - _onUpdate(changed, options, userId) { - super._onUpdate(changed, options, userId); - - if (this.parent.actor && options.scrollingTextData) - this.parent.actor.queueScrollText(options.scrollingTextData); - } } diff --git a/module/data/activeEffect/beastformEffect.mjs b/module/data/activeEffect/beastformEffect.mjs index 7e037f5b..65e36606 100644 --- a/module/data/activeEffect/beastformEffect.mjs +++ b/module/data/activeEffect/beastformEffect.mjs @@ -5,7 +5,6 @@ export default class BeastformEffect extends BaseEffect { static defineSchema() { const fields = foundry.data.fields; return { - ...super.defineSchema(), characterTokenData: new fields.SchemaField({ usesDynamicToken: new fields.BooleanField({ initial: false }), tokenImg: new fields.FilePathField({ @@ -25,7 +24,7 @@ export default class BeastformEffect extends BaseEffect { width: new fields.NumberField({ integer: false, nullable: true }) }) }), - advantageOn: new fields.TypedObjectField(new fields.SchemaField({ value: new fields.StringField() })), + advantageOn: new fields.ArrayField(new fields.StringField()), featureIds: new fields.ArrayField(new fields.StringField()), effectIds: new fields.ArrayField(new fields.StringField()) }; @@ -35,7 +34,6 @@ export default class BeastformEffect extends BaseEffect { static migrateData(source) { if (!source.characterTokenData.tokenSize.height) source.characterTokenData.tokenSize.height = 1; if (!source.characterTokenData.tokenSize.width) source.characterTokenData.tokenSize.width = 1; - if (!source.characterTokenData.tokenSize.depth) source.characterTokenData.tokenSize.depth = 1; return super.migrateData(source); } @@ -53,8 +51,7 @@ export default class BeastformEffect extends BaseEffect { if (this.parent.parent.type === 'character') { const baseUpdate = { height: this.characterTokenData.tokenSize.height, - width: this.characterTokenData.tokenSize.width, - depth: this.characterTokenData.tokenSize.depth + width: this.characterTokenData.tokenSize.width }; const update = { ...baseUpdate, @@ -90,19 +87,19 @@ export default class BeastformEffect extends BaseEffect { ...baseUpdate, x, y, - texture: { + 'texture': { enabled: this.characterTokenData.usesDynamicToken, src: token.flags.daggerheart?.beastformTokenImg ?? this.characterTokenData.tokenImg, scaleX: this.characterTokenData.tokenSize.scale, scaleY: this.characterTokenData.tokenSize.scale }, - ring: { + 'ring': { subject: { texture: token.flags.daggerheart?.beastformSubjectTexture ?? this.characterTokenData.tokenRingImg } }, - 'flags.daggerheart': { beastformTokenImg: _del, beastformSubjectTexture: _del } + 'flags.daggerheart': { '-=beastformTokenImg': null, '-=beastformSubjectTexture': null } }; }; diff --git a/module/data/activeEffect/changeTypes/_module.mjs b/module/data/activeEffect/changeTypes/_module.mjs deleted file mode 100644 index cf872304..00000000 --- a/module/data/activeEffect/changeTypes/_module.mjs +++ /dev/null @@ -1,9 +0,0 @@ -import Armor from './armor.mjs'; - -export const changeEffects = { - armor: Armor.changeEffect -}; - -export const changeTypes = { - armor: Armor -}; diff --git a/module/data/activeEffect/changeTypes/armor.mjs b/module/data/activeEffect/changeTypes/armor.mjs deleted file mode 100644 index 0c226513..00000000 --- a/module/data/activeEffect/changeTypes/armor.mjs +++ /dev/null @@ -1,209 +0,0 @@ -import { itemAbleRollParse } from '../../../helpers/utils.mjs'; - -const fields = foundry.data.fields; - -export default class ArmorChange extends foundry.abstract.DataModel { - static defineSchema() { - return { - type: new fields.StringField({ required: true, choices: ['armor'], initial: 'armor' }), - priority: new fields.NumberField(), - phase: new fields.StringField({ required: true, blank: false, initial: 'initial' }), - value: new fields.SchemaField({ - current: new fields.NumberField({ integer: true, min: 0, initial: 0 }), - max: new fields.StringField({ - required: true, - nullable: false, - initial: '1', - label: 'DAGGERHEART.GENERAL.max' - }), - damageThresholds: new fields.SchemaField( - { - major: new fields.StringField({ - initial: '0', - label: 'DAGGERHEART.GENERAL.DamageThresholds.majorThreshold' - }), - severe: new fields.StringField({ - initial: '0', - label: 'DAGGERHEART.GENERAL.DamageThresholds.severeThreshold' - }) - }, - { nullable: true, initial: null } - ), - interaction: new fields.StringField({ - required: true, - choices: CONFIG.DH.GENERAL.activeEffectArmorInteraction, - initial: CONFIG.DH.GENERAL.activeEffectArmorInteraction.none.id, - label: 'DAGGERHEART.EFFECTS.ChangeTypes.armor.FIELDS.interaction.label', - hint: 'DAGGERHEART.EFFECTS.ChangeTypes.armor.FIELDS.interaction.hint' - }) - }) - }; - } - - static changeEffect = { - label: 'Armor', - defaultPriority: 20, - handler: (actor, change, _options, _field, replacementData) => { - const baseParsedMax = itemAbleRollParse(change.value.max, actor, change.effect.parent); - const parsedMax = new Roll(baseParsedMax).evaluateSync().total; - game.system.api.documents.DhActiveEffect.applyChange( - actor, - { - ...change, - key: 'system.armorScore.value', - type: CONFIG.DH.GENERAL.activeEffectModes.add.id, - value: change.value.current - }, - replacementData - ); - game.system.api.documents.DhActiveEffect.applyChange( - actor, - { - ...change, - key: 'system.armorScore.max', - type: CONFIG.DH.GENERAL.activeEffectModes.add.id, - value: parsedMax - }, - replacementData - ); - - if (change.value.damageThresholds) { - const getThresholdValue = value => { - const parsed = itemAbleRollParse(value, actor, change.effect.parent); - const roll = new Roll(parsed).evaluateSync(); - return roll ? (roll.isDeterministic ? roll.total : null) : null; - }; - const major = getThresholdValue(change.value.damageThresholds.major); - const severe = getThresholdValue(change.value.damageThresholds.severe); - - if (major) { - game.system.api.documents.DhActiveEffect.applyChange( - actor, - { - ...change, - key: 'system.damageThresholds.major', - type: CONFIG.DH.GENERAL.activeEffectModes.add.id, - priority: 50, - value: major - }, - replacementData - ); - } - - if (severe) { - game.system.api.documents.DhActiveEffect.applyChange( - actor, - { - ...change, - key: 'system.damageThresholds.severe', - type: CONFIG.DH.GENERAL.activeEffectModes.add.id, - priority: 50, - value: severe - }, - replacementData - ); - } - } - - return {}; - }, - render: null - }; - - get isSuppressed() { - if (!this.parent.parent?.actor) return false; - - switch (this.value.interaction) { - case CONFIG.DH.GENERAL.activeEffectArmorInteraction.active.id: - return !this.parent.parent?.actor.system.armor; - case CONFIG.DH.GENERAL.activeEffectArmorInteraction.inactive.id: - return Boolean(this.parent.parent?.actor.system.armor); - default: - return false; - } - } - - static getInitialValue() { - return { - type: CONFIG.DH.GENERAL.activeEffectModes.armor.id, - value: { - current: 0, - max: 0 - }, - phase: 'initial', - priority: 20 - }; - } - - static getDefaultArmorEffect() { - return { - name: game.i18n.localize('DAGGERHEART.EFFECTS.ChangeTypes.armor.newArmorEffect'), - img: 'icons/equipment/chest/breastplate-helmet-metal.webp', - system: { - changes: [ArmorChange.getInitialValue()] - } - }; - } - - /* Helpers */ - - getArmorData() { - const actor = this.parent.parent?.actor?.type === 'character' ? this.parent.parent.actor : null; - const maxParse = actor ? itemAbleRollParse(this.value.max, actor, this.parent.parent.parent) : null; - const maxRoll = maxParse ? new Roll(maxParse).evaluateSync() : null; - const maxEvaluated = maxRoll ? (maxRoll.isDeterministic ? maxRoll.total : null) : null; - - return { - current: this.value.current, - max: maxEvaluated ?? this.value.max - }; - } - - async updateArmorMax(newMax) { - const newChanges = [ - ...this.parent.changes.map(change => ({ - ...change, - value: - change.type === 'armor' - ? { - ...change.value, - current: Math.min(change.value.current, newMax), - max: newMax - } - : change.value - })) - ]; - await this.parent.parent.update({ 'system.changes': newChanges }); - } - - static orderEffectsForAutoChange(armorEffects, increasing) { - const getEffectWeight = effect => { - switch (effect.parent.type) { - case 'class': - case 'subclass': - case 'ancestry': - case 'community': - case 'feature': - case 'domainCard': - return 2; - case 'armor': - return 3; - case 'loot': - case 'consumable': - return 4; - case 'weapon': - return 5; - case 'character': - return 6; - default: - return 1; - } - }; - - return armorEffects - .filter(x => !x.disabled && !x.isSuppressed) - .sort((a, b) => - increasing ? getEffectWeight(b) - getEffectWeight(a) : getEffectWeight(a) - getEffectWeight(b) - ); - } -} diff --git a/module/data/actor/_module.mjs b/module/data/actor/_module.mjs index 1fe1ef3f..99577620 100644 --- a/module/data/actor/_module.mjs +++ b/module/data/actor/_module.mjs @@ -1,17 +1,15 @@ import DhCharacter from './character.mjs'; import DhCompanion from './companion.mjs'; import DhAdversary from './adversary.mjs'; -import DhNPC from './npc.mjs'; import DhEnvironment from './environment.mjs'; import DhParty from './party.mjs'; -export { DhCharacter, DhCompanion, DhAdversary, DhNPC, DhEnvironment, DhParty }; +export { DhCharacter, DhCompanion, DhAdversary, DhEnvironment, DhParty }; export const config = { character: DhCharacter, companion: DhCompanion, adversary: DhAdversary, - npc: DhNPC, environment: DhEnvironment, party: DhParty }; diff --git a/module/data/actor/adversary.mjs b/module/data/actor/adversary.mjs index d6d0dcdf..dd41f290 100644 --- a/module/data/actor/adversary.mjs +++ b/module/data/actor/adversary.mjs @@ -3,7 +3,8 @@ import { ActionField } from '../fields/actionField.mjs'; import { commonActorRules } from './base.mjs'; import DhCreature from './creature.mjs'; import { bonusField } from '../fields/actorField.mjs'; -import { getTierAdjustedAdversary } from './tierAdjustment.mjs'; +import { calculateExpectedValue, parseTermsFromSimpleFormula } from '../../helpers/utils.mjs'; +import { adversaryExpectedDamage, adversaryScalingData } from '../../config/actorConfig.mjs'; export default class DhpAdversary extends DhCreature { static LOCALIZATION_PREFIXES = ['DAGGERHEART.ACTORS.Adversary']; @@ -84,14 +85,14 @@ export default class DhpAdversary extends DhCreature { type: 'attack' }, damage: { - parts: { - hitPoints: { + parts: [ + { type: ['physical'], value: { multiplier: 'flat' } } - } + ] } } }), @@ -132,7 +133,7 @@ export default class DhpAdversary extends DhCreature { } isItemValid(source) { - return super.isItemValid(source) || source.type === 'feature'; + return source.type === 'feature'; } async _preUpdate(changes, options, user) { @@ -205,6 +206,207 @@ export default class DhpAdversary extends DhCreature { /** Returns source data for this actor adjusted to a new tier, which can be used to create a new actor. */ adjustForTier(tier) { const source = this.parent.toObject(true); - return getTierAdjustedAdversary(source, tier); + + /** @type {(2 | 3 | 4)[]} */ + const tiers = new Array(Math.abs(tier - this.tier)) + .fill(0) + .map((_, idx) => idx + Math.min(tier, this.tier) + 1); + if (tier < this.tier) tiers.reverse(); + const typeData = adversaryScalingData[source.system.type] ?? adversaryScalingData[source.system.standard]; + const tierEntries = tiers.map(t => ({ tier: t, ...typeData[t] })); + + // Apply simple tier changes + const scale = tier > this.tier ? 1 : -1; + for (const entry of tierEntries) { + source.system.difficulty += scale * entry.difficulty; + source.system.damageThresholds.major += scale * entry.majorThreshold; + source.system.damageThresholds.severe += scale * entry.severeThreshold; + source.system.resources.hitPoints.max += scale * entry.hp; + source.system.resources.stress.max += scale * entry.stress; + source.system.attack.roll.bonus += scale * entry.attack; + } + + // Get the mean and standard deviation of expected damage in the previous and new tier + // The data we have is for attack scaling, but we reuse this for action scaling later + const expectedDamageData = adversaryExpectedDamage[source.system.type] ?? adversaryExpectedDamage.basic; + const damageMeta = { + currentDamageRange: { tier: source.system.tier, ...expectedDamageData[source.system.tier] }, + newDamageRange: { tier, ...expectedDamageData[tier] }, + type: 'attack' + }; + + // Update damage of base attack + try { + this.#adjustActionDamage(source.system.attack, damageMeta); + } catch (err) { + ui.notifications.warn('Failed to convert attack damage of adversary'); + console.error(err); + } + + // Update damage of each item action, making sure to also update the description if possible + const damageRegex = /@Damage\[([^\[\]]*)\]({[^}]*})?/g; + for (const item of source.items) { + // Replace damage inlines with new formulas + for (const withDescription of [item.system, ...Object.values(item.system.actions)]) { + withDescription.description = withDescription.description.replace(damageRegex, (match, inner) => { + const { value: formula } = parseInlineParams(inner); + if (!formula || !type) return match; + + try { + const adjusted = this.#calculateAdjustedDamage(formula, { ...damageMeta, type: 'action' }); + const newFormula = [ + adjusted.diceQuantity ? `${adjusted.diceQuantity}d${adjusted.faces}` : null, + adjusted.bonus + ] + .filter(p => !!p) + .join('+'); + return match.replace(formula, newFormula); + } catch { + return match; + } + }); + } + + // Update damage in item actions + for (const action of Object.values(item.system.actions)) { + if (!action.damage) continue; + + // Parse damage, and convert all formula matches in the descriptions to the new damage + try { + const result = this.#adjustActionDamage(action, { ...damageMeta, type: 'action' }); + for (const { previousFormula, formula } of Object.values(result)) { + const oldFormulaRegexp = new RegExp( + previousFormula.replace(' ', '').replace('+', '(?:\\s)?\\+(?:\\s)?') + ); + item.system.description = item.system.description.replace(oldFormulaRegexp, formula); + action.description = action.description.replace(oldFormulaRegexp, formula); + } + } catch (err) { + ui.notifications.warn(`Failed to convert action damage for item ${item.name}`); + console.error(err); + } + } + } + + // Finally set the tier of the source data, now that everything is complete + source.system.tier = tier; + return source; + } + + /** + * Converts a damage object to a new damage range + * @returns {{ diceQuantity: number; faces: number; bonus: number }} the adjusted result as a combined term + * @throws error if the formula is the wrong type + */ + #calculateAdjustedDamage(formula, { currentDamageRange, newDamageRange, type }) { + const terms = parseTermsFromSimpleFormula(formula); + const flatTerms = terms.filter(t => t.diceQuantity === 0); + const diceTerms = terms.filter(t => t.diceQuantity > 0); + if (flatTerms.length > 1 || diceTerms.length > 1) { + throw new Error('invalid formula for conversion'); + } + const value = { + ...(diceTerms[0] ?? { diceQuantity: 0, faces: 1 }), + bonus: flatTerms[0]?.bonus ?? 0 + }; + const previousExpected = calculateExpectedValue(value); + if (previousExpected === 0) return value; // nothing to do + + const dieSizes = [4, 6, 8, 10, 12, 20]; + const steps = newDamageRange.tier - currentDamageRange.tier; + const increasing = steps > 0; + const deviation = (previousExpected - currentDamageRange.mean) / currentDamageRange.deviation; + const expected = Math.max(1, newDamageRange.mean + newDamageRange.deviation * deviation); + + // If this was just a flat number, convert to the expected damage and exit + if (value.diceQuantity === 0) { + value.bonus = Math.round(expected); + return value; + } + + const getExpectedDie = () => calculateExpectedValue({ diceQuantity: 1, faces: value.faces }) || 1; + const getBaseAverage = () => calculateExpectedValue({ ...value, bonus: 0 }); + + // Check the number of base overages over the expected die. In the end, if the bonus inflates too much, we add a die + const baseOverages = Math.floor(value.bonus / getExpectedDie()); + + // Prestep. Change number of dice for attacks, bump up/down for actions + // We never bump up to d20, though we might bump down from it + if (type === 'attack') { + const minimum = increasing ? value.diceQuantity : 0; + value.diceQuantity = Math.max(minimum, newDamageRange.tier); + } else { + const currentIdx = dieSizes.indexOf(value.faces); + value.faces = dieSizes[Math.clamp(currentIdx + steps, 0, 4)]; + } + + value.bonus = Math.round(expected - getBaseAverage()); + + // Attempt to handle negative values. + // If we can do it with only step downs, do so. Otherwise remove tier dice, and try again + if (value.bonus < 0) { + let stepsRequired = Math.ceil(Math.abs(value.bonus) / value.diceQuantity); + const currentIdx = dieSizes.indexOf(value.faces); + + // If step downs alone don't suffice, change the flat modifier, then calculate steps required again + // If this isn't sufficient, the result will be slightly off. This is unlikely to happen + if (type !== 'attack' && stepsRequired > currentIdx && value.diceQuantity > 0) { + value.diceQuantity -= increasing ? 1 : Math.abs(steps); + value.bonus = Math.round(expected - getBaseAverage()); + if (value.bonus >= 0) return value; // complete + } + + stepsRequired = Math.ceil(Math.abs(value.bonus) / value.diceQuantity); + value.faces = dieSizes[Math.max(0, currentIdx - stepsRequired)]; + value.bonus = Math.max(0, Math.round(expected - getBaseAverage())); + } + + // If value is really high, we add a number of dice based on the number of overages + // This attempts to preserve a similar amount of variance when increasing an action + const overagesToRemove = Math.floor(value.bonus / getExpectedDie()) - baseOverages; + if (type !== 'attack' && increasing && overagesToRemove > 0) { + value.diceQuantity += overagesToRemove; + value.bonus = Math.round(expected - getBaseAverage()); + } + + return value; + } + + /** + * Updates damage to reflect a specific value. + * @throws if damage structure is invalid for conversion + * @returns the converted formula and value as a simplified term + */ + #adjustActionDamage(action, damageMeta) { + // The current algorithm only returns a value if there is a single damage part + const hpDamageParts = action.damage.parts.filter(d => d.applyTo === 'hitPoints'); + if (hpDamageParts.length !== 1) throw new Error('incorrect number of hp parts'); + + const result = {}; + for (const property of ['value', 'valueAlt']) { + const data = hpDamageParts[0][property]; + const previousFormula = data.custom.enabled + ? data.custom.formula + : [data.flatMultiplier ? `${data.flatMultiplier}${data.dice}` : 0, data.bonus ?? 0] + .filter(p => !!p) + .join('+'); + const value = this.#calculateAdjustedDamage(previousFormula, damageMeta); + const formula = [value.diceQuantity ? `${value.diceQuantity}d${value.faces}` : null, value.bonus] + .filter(p => !!p) + .join('+'); + if (value.diceQuantity) { + data.custom.enabled = false; + data.bonus = value.bonus; + data.dice = `d${value.faces}`; + data.flatMultiplier = value.diceQuantity; + } else if (!value.diceQuantity) { + data.custom.enabled = true; + data.custom.formula = formula; + } + + result[property] = { previousFormula, formula, value }; + } + + return result; } } diff --git a/module/data/actor/base.mjs b/module/data/actor/base.mjs index 9efbe7d7..e2f910a0 100644 --- a/module/data/actor/base.mjs +++ b/module/data/actor/base.mjs @@ -1,6 +1,6 @@ import DHBaseActorSettings from '../../applications/sheets/api/actor-setting.mjs'; import DHItem from '../../documents/item.mjs'; -import { createShallowProxy, getScrollTextData } from '../../helpers/utils.mjs'; +import { getScrollTextData } from '../../helpers/utils.mjs'; const fields = foundry.data.fields; @@ -107,8 +107,7 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel { hasResistances: true, hasAttribution: false, hasLimitedView: true, - usesSize: false, - hasInventory: false + usesSize: false }; } @@ -169,18 +168,14 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel { /* -------------------------------------------- */ - isItemValid(source) { - const inventoryTypes = ['weapon', 'armor', 'consumable', 'loot']; - return this.metadata.hasInventory && inventoryTypes.includes(source.type); - } - /** * Obtain a data object used to evaluate any dice rolls associated with this Item Type * @param {object} [options] - Options which modify the getRollData method. * @returns {object} */ getRollData() { - return createShallowProxy(this); + const data = { ...this }; + return data; } /** @@ -194,6 +189,21 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel { return true; } + async _preDelete() { + /* Clear all partyMembers from tagTeam setting.*/ + /* Revisit this when tagTeam is improved for many parties */ + if (this.parent.parties.size > 0) { + const tagTeam = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll); + await tagTeam.updateSource({ + initiator: this.parent.id === tagTeam.initiator ? null : tagTeam.initiator, + members: Object.keys(tagTeam.members).find(x => x === this.parent.id) + ? { [`-=${this.parent.id}`]: null } + : {} + }); + await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll, tagTeam); + } + } + async _preUpdate(changes, options, userId) { const allowed = await super._preUpdate(changes, options, userId); if (allowed === false) return; diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index aed27650..bea3a3ec 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -3,10 +3,9 @@ import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs'; import DhLevelData from '../levelData.mjs'; import { commonActorRules } from './base.mjs'; import DhCreature from './creature.mjs'; -import { attributeField, stressDamageReductionRule, bonusField, GoldField } from '../fields/actorField.mjs'; +import { attributeField, stressDamageReductionRule, bonusField } from '../fields/actorField.mjs'; import { ActionField } from '../fields/actionField.mjs'; import DHCharacterSettings from '../../applications/sheets-configs/character-settings.mjs'; -import { getArmorSources } from '../../helpers/utils.mjs'; export default class DhCharacter extends DhCreature { /**@override */ @@ -18,9 +17,7 @@ export default class DhCharacter extends DhCreature { label: 'TYPES.Actor.character', type: 'character', settingSheet: DHCharacterSettings, - isNPC: false, - hasInventory: true, - quantifiable: ['loot', 'consumable'] + isNPC: false }); } @@ -44,16 +41,17 @@ export default class DhCharacter extends DhCreature { label: 'DAGGERHEART.GENERAL.proficiency' }), evasion: new fields.NumberField({ initial: 0, integer: true, label: 'DAGGERHEART.GENERAL.evasion' }), + armorScore: new fields.NumberField({ integer: true, initial: 0, label: 'DAGGERHEART.GENERAL.armorScore' }), damageThresholds: new fields.SchemaField({ - major: new fields.NumberField({ - integer: true, - initial: 0, - label: 'DAGGERHEART.GENERAL.DamageThresholds.majorThreshold' - }), severe: new fields.NumberField({ integer: true, initial: 0, label: 'DAGGERHEART.GENERAL.DamageThresholds.severeThreshold' + }), + major: new fields.NumberField({ + integer: true, + initial: 0, + label: 'DAGGERHEART.GENERAL.DamageThresholds.majorThreshold' }) }), experiences: new fields.TypedObjectField( @@ -64,7 +62,12 @@ export default class DhCharacter extends DhCreature { core: new fields.BooleanField({ initial: false }) }) ), - gold: new GoldField(), + gold: new fields.SchemaField({ + coins: new fields.NumberField({ initial: 0, integer: true }), + handfuls: new fields.NumberField({ initial: 1, integer: true }), + bags: new fields.NumberField({ initial: 0, integer: true }), + chests: new fields.NumberField({ initial: 0, integer: true }) + }), scars: new fields.NumberField({ initial: 0, integer: true, label: 'DAGGERHEART.GENERAL.scars' }), biography: new fields.SchemaField({ background: new fields.HTMLField(), @@ -93,8 +96,8 @@ export default class DhCharacter extends DhCreature { trait: 'strength' }, damage: { - parts: { - hitPoints: { + parts: [ + { type: ['physical'], value: { custom: { @@ -103,7 +106,7 @@ export default class DhCharacter extends DhCreature { } } } - } + ] } } }), @@ -150,6 +153,7 @@ export default class DhCharacter extends DhCreature { shortMoves: new fields.NumberField({ required: true, integer: true, + min: 0, initial: 0, label: 'DAGGERHEART.GENERAL.Bonuses.rest.shortRest.shortRestMoves.label', hint: 'DAGGERHEART.GENERAL.Bonuses.rest.shortRest.shortRestMoves.hint' @@ -157,6 +161,7 @@ export default class DhCharacter extends DhCreature { longMoves: new fields.NumberField({ required: true, integer: true, + min: 0, initial: 0, label: 'DAGGERHEART.GENERAL.Bonuses.rest.shortRest.longRestMoves.label', hint: 'DAGGERHEART.GENERAL.Bonuses.rest.shortRest.longRestMoves.hint' @@ -166,6 +171,7 @@ export default class DhCharacter extends DhCreature { shortMoves: new fields.NumberField({ required: true, integer: true, + min: 0, initial: 0, label: 'DAGGERHEART.GENERAL.Bonuses.rest.longRest.shortRestMoves.label', hint: 'DAGGERHEART.GENERAL.Bonuses.rest.longRest.shortRestMoves.hint' @@ -173,6 +179,7 @@ export default class DhCharacter extends DhCreature { longMoves: new fields.NumberField({ required: true, integer: true, + min: 0, initial: 0, label: 'DAGGERHEART.GENERAL.Bonuses.rest.longRest.longRestMoves.label', hint: 'DAGGERHEART.GENERAL.Bonuses.rest.longRest.longRestMoves.hint' @@ -286,22 +293,6 @@ export default class DhCharacter extends DhCreature { guaranteedCritical: new fields.BooleanField({ label: 'DAGGERHEART.ACTORS.Character.roll.guaranteedCritical.label', hint: 'DAGGERHEART.ACTORS.Character.roll.guaranteedCritical.hint' - }), - defaultAdvantageDice: new fields.NumberField({ - nullable: true, - required: true, - integer: true, - choices: CONFIG.DH.GENERAL.dieFaces, - initial: null, - label: 'DAGGERHEART.ACTORS.Character.defaultAdvantageDice' - }), - defaultDisadvantageDice: new fields.NumberField({ - nullable: true, - required: true, - integer: true, - choices: CONFIG.DH.GENERAL.dieFaces, - initial: null, - label: 'DAGGERHEART.ACTORS.Character.defaultDisadvantageDice' }) }) }) @@ -315,8 +306,8 @@ export default class DhCharacter extends DhCreature { return currentLevel === 1 ? 1 : Object.values(game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers).tiers).find( - tier => currentLevel >= tier.levels.start && currentLevel <= tier.levels.end - ).tier; + tier => currentLevel >= tier.levels.start && currentLevel <= tier.levels.end + ).tier; } get ancestry() { @@ -391,9 +382,8 @@ export default class DhCharacter extends DhCreature { return this.domains.map(key => { const domain = allDomainData[key]; return { - id: key, ...domain, - label: game.i18n.localize(domain?.label) ?? key + label: game.i18n.localize(domain.label) }; }); } @@ -411,11 +401,14 @@ export default class DhCharacter extends DhCreature { } get loadoutSlot() { - const loadoutCount = this.domainCards.loadout?.length ?? 0; - const worldSetting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxLoadout; + const loadoutCount = this.domainCards.loadout?.length ?? 0, + worldSetting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxLoadout, + max = !worldSetting ? null : worldSetting + this.bonuses.maxLoadout; + return { current: loadoutCount, - available: loadoutCount < worldSetting + available: !max ? true : Math.max(max - loadoutCount, 0), + max }; } @@ -445,11 +438,6 @@ export default class DhCharacter extends DhCreature { return attack; } - /* All items are valid on characters */ - isItemValid() { - return true; - } - /** @inheritDoc */ isItemAvailable(item) { if (!super.isItemAvailable(this)) return false; @@ -477,108 +465,11 @@ export default class DhCharacter extends DhCreature { } } - async updateArmorValue({ value: armorChange = 0, clear = false }) { - if (armorChange === 0 && !clear) return; - - const increasing = armorChange >= 0; - let remainingChange = Math.abs(armorChange); - const orderedSources = getArmorSources(this.parent).filter(s => !s.disabled); - - const handleArmorData = (embeddedUpdates, doc, armorData) => { - let usedArmorChange = 0; - if (clear) { - usedArmorChange -= armorData.current; - } else { - if (increasing) { - const remainingArmor = armorData.max - armorData.current; - usedArmorChange = Math.min(remainingChange, remainingArmor); - remainingChange -= usedArmorChange; - } else { - const changeChange = Math.min(armorData.current, remainingChange); - usedArmorChange -= changeChange; - remainingChange -= changeChange; - } - } - - if (!usedArmorChange) return usedArmorChange; - else { - if (!embeddedUpdates[doc.id]) embeddedUpdates[doc.id] = { doc: doc, updates: [] }; - - return usedArmorChange; - } - }; - - const armorUpdates = []; - const effectUpdates = []; - for (const { document: armorSource } of orderedSources) { - const usedArmorChange = handleArmorData( - armorSource.type === 'armor' ? armorUpdates : effectUpdates, - armorSource.parent, - armorSource.type === 'armor' ? armorSource.system.armor : armorSource.system.armorData - ); - if (!usedArmorChange) continue; - - if (armorSource.type === 'armor') { - armorUpdates[armorSource.parent.id].updates.push({ - _id: armorSource.id, - 'system.armor.current': armorSource.system.armor.current + usedArmorChange - }); - } else { - effectUpdates[armorSource.parent.id].updates.push({ - _id: armorSource.id, - 'system.changes': armorSource.system.changes.map(change => ({ - ...change, - value: - change.type === 'armor' - ? { - ...change.value, - current: armorSource.system.armorChange.value.current + usedArmorChange - } - : change.value - })) - }); - } - - if (remainingChange === 0 && !clear) break; - } - - const armorUpdateValues = Object.values(armorUpdates); - for (const [index, { doc, updates }] of armorUpdateValues.entries()) - await doc.updateEmbeddedDocuments('Item', updates, { render: index === armorUpdateValues.length - 1 }); - - const effectUpdateValues = Object.values(effectUpdates); - for (const [index, { doc, updates }] of effectUpdateValues.entries()) - await doc.updateEmbeddedDocuments('ActiveEffect', updates, { - render: index === effectUpdateValues.length - 1 - }); - } - - async updateArmorEffectValue({ uuid, value }) { - const source = await foundry.utils.fromUuid(uuid); - if (source.type === 'armor') { - await source.update({ - 'system.armor.current': source.system.armor.current + value - }); - } else { - const effectValue = source.system.armorChange.value; - await source.update({ - 'system.changes': [ - { - ...source.system.armorChange, - value: { ...effectValue, current: effectValue.current + value } - } - ] - }); - } - } - get sheetLists() { const ancestryFeatures = [], communityFeatures = [], classFeatures = [], subclassFeatures = [], - multiclassFeatures = [], - multiclassSubclassFeatures = [], companionFeatures = [], features = []; @@ -588,9 +479,9 @@ export default class DhCharacter extends DhCreature { } else if (item.system.originItemType === CONFIG.DH.ITEM.featureTypes.community.id) { communityFeatures.push(item); } else if (item.system.originItemType === CONFIG.DH.ITEM.featureTypes.class.id) { - (item.system.multiclassOrigin ? multiclassFeatures : classFeatures).push(item); + classFeatures.push(item); } else if (item.system.originItemType === CONFIG.DH.ITEM.featureTypes.subclass.id) { - (item.system.multiclassOrigin ? multiclassSubclassFeatures : subclassFeatures).push(item); + subclassFeatures.push(item); } else if (item.system.originItemType === CONFIG.DH.ITEM.featureTypes.companion.id) { companionFeatures.push(item); } else if (item.type === 'feature' && !item.system.type) { @@ -619,24 +510,6 @@ export default class DhCharacter extends DhCreature { type: 'subclass', values: subclassFeatures }, - ...(multiclassFeatures.length - ? { - multiclassFeatures: { - title: `${game.i18n.localize('DAGGERHEART.GENERAL.multiclass')} - ${this.multiclass.value?.name}`, - type: 'multiclass', - values: multiclassFeatures - } - } - : {}), - ...(multiclassSubclassFeatures.length - ? { - multiclassSubclassFeatures: { - title: `${game.i18n.localize('DAGGERHEART.GENERAL.multiclass')} ${game.i18n.localize('TYPES.Item.subclass')} - ${this.multiclass.subclass?.name}`, - type: 'multiclassSubclass', - values: multiclassSubclassFeatures - } - } - : {}), companionFeatures: { title: game.i18n.localize('DAGGERHEART.ACTORS.Character.companionFeatures'), type: 'companion', @@ -659,8 +532,8 @@ export default class DhCharacter extends DhCreature { (this.primaryWeapon && this.secondaryWeapon) ? burden.twoHanded.value : this.primaryWeapon || this.secondaryWeapon - ? burden.oneHanded.value - : null; + ? burden.oneHanded.value + : null; } get deathMoveViable() { @@ -715,10 +588,6 @@ export default class DhCharacter extends DhCreature { prepareBaseData() { super.prepareBaseData(); - this.armorScore = { - max: this.armor?.system.armor.max ?? 0, - value: this.armor?.system.armor.current ?? 0 - }; this.evasion += this.class.value?.system?.evasion ?? 0; const currentLevel = this.levelData.level.current; @@ -726,8 +595,8 @@ export default class DhCharacter extends DhCreature { currentLevel === 1 ? null : Object.values(game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers).tiers).find( - tier => currentLevel >= tier.levels.start && currentLevel <= tier.levels.end - ).tier; + tier => currentLevel >= tier.levels.start && currentLevel <= tier.levels.end + ).tier; if (game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).levelupAuto) { for (let levelKey in this.levelData.levelups) { const level = this.levelData.levelups[levelKey]; @@ -768,22 +637,15 @@ export default class DhCharacter extends DhCreature { } } - /* Armor and ArmorEffects can set a Base Damage Threshold. Characters only gain level*2 bonus to severe if this is not present */ - const severeThresholdMulitplier = - this.armor || - this.parent.appliedEffects.some(x => - x.system.changes.some(x => x.type === 'armor' && x.value.damageThresholds) - ) - ? 1 - : 2; - + const armor = this.armor; + this.armorScore = armor ? armor.system.baseScore : 0; this.damageThresholds = { - major: this.armor - ? this.armor.system.baseThresholds.major + this.levelData.level.current + major: armor + ? armor.system.baseThresholds.major + this.levelData.level.current : this.levelData.level.current, - severe: this.armor - ? this.armor.system.baseThresholds.severe + this.levelData.level.current - : this.levelData.level.current * severeThresholdMulitplier + severe: armor + ? armor.system.baseThresholds.severe + this.levelData.level.current + : this.levelData.level.current * 2 }; const globalHopeMax = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxHope; @@ -816,12 +678,13 @@ export default class DhCharacter extends DhCreature { this.attack.roll.trait = this.rules.attack.roll.trait ?? this.attack.roll.trait; this.resources.armor = { - ...this.armorScore, label: 'DAGGERHEART.GENERAL.armor', + value: this.armor?.system?.marks?.value ?? 0, + max: this.armorScore, isReversed: true }; - this.attack.damage.parts.hitPoints.value.custom.formula = `@prof${this.basicAttackDamageDice}${this.rules.attack.damage.bonus ? ` + ${this.rules.attack.damage.bonus}` : ''}`; + this.attack.damage.parts[0].value.custom.formula = `@prof${this.basicAttackDamageDice}${this.rules.attack.damage.bonus ? ` + ${this.rules.attack.damage.bonus}` : ''}`; // Clamp resources (must be done last to ensure all updates occur) this.resources.clamp(); @@ -856,17 +719,16 @@ export default class DhCharacter extends DhCreature { /* Scars can alter the amount of current hope */ if (changes.system?.scars) { - const diff = this.scars - changes.system.scars; - const newHopeMax = this.resources.hope.max + diff; - const newHopeValue = Math.min(newHopeMax, this.resources.hope.value); - if (newHopeValue != this.resources.hope.value) { - changes.system = foundry.utils.mergeObject(changes.system ?? {}, { - resources: { - hope: { - value: (changes.system?.resources?.hope?.value ?? 0) + newHopeMax - } - } - }); + const diff = this.system.scars - changes.system.scars; + const newHopeMax = this.system.resources.hope.max + diff; + const newHopeValue = Math.min(newHopeMax, this.system.resources.hope.value); + if (newHopeValue != this.system.resources.hope.value) { + if (!changes.system.resources.hope) changes.system.resources.hope = { value: 0 }; + + changes.system.resources.hope = { + ...changes.system.resources.hope, + value: changes.system.resources.hope.value + newHopeValue + }; } } diff --git a/module/data/actor/companion.mjs b/module/data/actor/companion.mjs index 300bd698..c6768e95 100644 --- a/module/data/actor/companion.mjs +++ b/module/data/actor/companion.mjs @@ -61,24 +61,6 @@ export default class DhCompanion extends DhCreature { initial: false, label: 'DAGGERHEART.GENERAL.Rules.conditionImmunities.vulnerable' }) - }), - roll: new fields.SchemaField({ - defaultAdvantageDice: new fields.NumberField({ - nullable: true, - required: true, - integer: true, - choices: CONFIG.DH.GENERAL.dieFaces, - initial: null, - label: 'DAGGERHEART.ACTORS.Character.defaultAdvantageDice' - }), - defaultDisadvantageDice: new fields.NumberField({ - nullable: true, - required: true, - integer: true, - choices: CONFIG.DH.GENERAL.dieFaces, - initial: null, - label: 'DAGGERHEART.ACTORS.Character.defaultDisadvantageDice' - }) }) }), attack: new ActionField({ @@ -99,15 +81,15 @@ export default class DhCompanion extends DhCreature { bonus: 0 }, damage: { - parts: { - hitPoints: { + parts: [ + { type: ['physical'], value: { dice: 'd6', multiplier: 'prof' } } - } + ] } } }), @@ -136,6 +118,10 @@ export default class DhCompanion extends DhCreature { return this.levelupChoicesLeft > 0; } + isItemValid() { + return false; + } + prepareBaseData() { super.prepareBaseData(); this.attack.roll.bonus = this.partner?.system?.spellcastModifier ?? 0; @@ -146,9 +132,7 @@ export default class DhCompanion extends DhCreature { switch (selection.type) { case 'vicious': if (selection.data[0] === 'damage') { - this.attack.damage.parts.hitPoints.value.dice = adjustDice( - this.attack.damage.parts.hitPoints.value.dice - ); + this.attack.damage.parts[0].value.dice = adjustDice(this.attack.damage.parts[0].value.dice); } else { this.attack.range = adjustRange(this.attack.range).id; } diff --git a/module/data/actor/environment.mjs b/module/data/actor/environment.mjs index e037e004..0aaf8eb0 100644 --- a/module/data/actor/environment.mjs +++ b/module/data/actor/environment.mjs @@ -56,7 +56,7 @@ export default class DhEnvironment extends BaseDataActor { } isItemValid(source) { - return super.isItemValid(source) || source.type === 'feature'; + return source.type === 'feature'; } _onUpdate(changes, options, userId) { @@ -75,6 +75,10 @@ export default class DhEnvironment extends BaseDataActor { ); scene.update({ 'flags.daggerheart.sceneEnvironments': newSceneEnvironments }).then(() => { Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.Scene }); + game.socket.emit(`system.${CONFIG.DH.id}`, { + action: socketEvent.Refresh, + data: { refreshType: RefreshType.TagTeamRoll } + }); }); } } diff --git a/module/data/actor/npc.mjs b/module/data/actor/npc.mjs deleted file mode 100644 index 2ccaf926..00000000 --- a/module/data/actor/npc.mjs +++ /dev/null @@ -1,43 +0,0 @@ -import DHNPCSettings from '../../applications/sheets-configs/npc-settings.mjs'; -import BaseDataActor from './base.mjs'; - -export default class DhpNPC extends BaseDataActor { - static LOCALIZATION_PREFIXES = ['DAGGERHEART.ACTORS.NPC']; - - static get metadata() { - return foundry.utils.mergeObject(super.metadata, { - label: 'TYPES.Actor.npc', - type: 'npc', - settingSheet: DHNPCSettings, - hasResistances: false, - hasAttribution: true - }); - } - - static defineSchema() { - const fields = foundry.data.fields; - return { - ...super.defineSchema(), - difficulty: new fields.NumberField({ - nullable: true, - initial: null, - integer: true, - label: 'DAGGERHEART.GENERAL.difficulty' - }), - description: new fields.HTMLField({ label: 'DAGGERHEART.GENERAL.description' }), - motives: new fields.StringField(), - notes: new fields.HTMLField() - }; - } - - /**@inheritdoc */ - static DEFAULT_ICON = 'systems/daggerheart/assets/icons/documents/actors/drama-masks.svg'; - - get features() { - return this.parent.items.filter(x => x.type === 'feature'); - } - - isItemValid(source) { - return super.isItemValid(source) || source.type === 'feature'; - } -} diff --git a/module/data/actor/party.mjs b/module/data/actor/party.mjs index 5b9cccab..236d65db 100644 --- a/module/data/actor/party.mjs +++ b/module/data/actor/party.mjs @@ -1,35 +1,23 @@ import BaseDataActor from './base.mjs'; import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs'; -import TagTeamData from '../tagTeamData.mjs'; -import GroupRollData from '../groupRollData.mjs'; -import { GoldField } from '../fields/actorField.mjs'; export default class DhParty extends BaseDataActor { - /** @inheritdoc */ - static get metadata() { - return foundry.utils.mergeObject(super.metadata, { - hasInventory: true, - quantifiable: ['weapon', 'armor', 'loot', 'consumable'] - }); - } - /**@inheritdoc */ static defineSchema() { const fields = foundry.data.fields; return { ...super.defineSchema(), - partyMembers: new ForeignDocumentUUIDArrayField({ type: 'Actor' }), + partyMembers: new ForeignDocumentUUIDArrayField({ type: 'Actor' }, { prune: true }), notes: new fields.HTMLField(), - gold: new GoldField(), - tagTeam: new fields.EmbeddedDataField(TagTeamData), - groupRoll: new fields.EmbeddedDataField(GroupRollData) + gold: new fields.SchemaField({ + coins: new fields.NumberField({ initial: 0, integer: true }), + handfuls: new fields.NumberField({ initial: 1, integer: true }), + bags: new fields.NumberField({ initial: 0, integer: true }), + chests: new fields.NumberField({ initial: 0, integer: true }) + }) }; } - get active() { - return game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.ActiveParty) === this.parent.id; - } - /* -------------------------------------------- */ /**@inheritdoc */ @@ -37,6 +25,10 @@ export default class DhParty extends BaseDataActor { /* -------------------------------------------- */ + isItemValid(source) { + return ['weapon', 'armor', 'consumable', 'loot'].includes(source.type); + } + prepareBaseData() { super.prepareBaseData(); @@ -48,14 +40,21 @@ export default class DhParty extends BaseDataActor { } } - _onCreate(data, options, userId) { - super._onCreate(data, options, userId); + async _preDelete() { + /* Clear all partyMembers from tagTeam setting.*/ + /* Revisit this when tagTeam is improved for many parties */ + const tagTeam = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll); + await tagTeam.updateSource({ + initiator: this.partyMembers.some(x => x.id === tagTeam.initiator) ? null : tagTeam.initiator, + members: Object.keys(tagTeam.members).reduce((acc, key) => { + if (this.partyMembers.find(x => x.id === key)) { + acc[`-=${key}`] = null; + } - if (game.user.isActiveGM && !game.actors.party) { - game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.ActiveParty, this.parent.id).then(_ => { - ui.actors.render(); - }); - } + return acc; + }, {}) + }); + await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll, tagTeam); } _onDelete(options, userId) { @@ -65,11 +64,5 @@ export default class DhParty extends BaseDataActor { for (const member of this.partyMembers) { member?.parties?.delete(this.parent); } - - // If this *was* the active party, delete it. We can't use game.actors.party as this actor was already deleted - const isWorldActor = !this.parent?.parent && !this.parent.compendium; - const activePartyId = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.ActiveParty); - if (isWorldActor && this.id === activePartyId) - game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.ActiveParty, null); } } diff --git a/module/data/actor/tierAdjustment.mjs b/module/data/actor/tierAdjustment.mjs deleted file mode 100644 index bc6ad176..00000000 --- a/module/data/actor/tierAdjustment.mjs +++ /dev/null @@ -1,219 +0,0 @@ -import { calculateExpectedValue, parseTermsFromSimpleFormula } from '../../helpers/utils.mjs'; -import { adversaryExpectedDamage, adversaryScalingData } from '../../config/actorConfig.mjs'; -import { parseInlineParams } from '../../enrichers/parser.mjs'; - -export function getTierAdjustedAdversary(source, tier) { - const currentTier = source.tier ?? 1; - - /** @type {(2 | 3 | 4)[]} */ - const tiers = new Array(Math.abs(tier - currentTier)) - .fill(0) - .map((_, idx) => idx + Math.min(tier, currentTier) + 1); - if (tier < currentTier) tiers.reverse(); - const typeData = adversaryScalingData[source.system.type] ?? adversaryScalingData[source.system.standard]; - const tierEntries = tiers.map(t => ({ tier: t, ...typeData[t] })); - - // Apply simple tier changes - const scale = tier > currentTier ? 1 : -1; - for (const entry of tierEntries) { - source.system.difficulty += scale * entry.difficulty; - source.system.damageThresholds.major += scale * entry.majorThreshold; - source.system.damageThresholds.severe += scale * entry.severeThreshold; - source.system.resources.hitPoints.max += scale * entry.hp; - source.system.resources.stress.max += scale * entry.stress; - source.system.attack.roll.bonus += scale * entry.attack; - } - - // Get the mean and standard deviation of expected damage in the previous and new tier - // The data we have is for attack scaling, but we reuse this for action scaling later - const expectedDamageData = adversaryExpectedDamage[source.system.type] ?? adversaryExpectedDamage.basic; - const damageMeta = { - currentDamageRange: { tier: source.system.tier, ...expectedDamageData[source.system.tier] }, - newDamageRange: { tier, ...expectedDamageData[tier] } - }; - - // Store initial attack damage for abilities that have you deal a "standard attack" - const initialAttack = { - type: source.system.attack.damage?.parts.hitPoints?.type?.toSorted(), - value: getDamagePartsFormula(source.system.attack.damage?.parts.hitPoints?.value) - }; - - // Update damage of base attack. - try { - const damage = source.system.attack.damage; - if (!damage?.parts.hitPoints) throw new Error('Unexpected missing attack in adversary'); - - for (const property of ['value', 'valueAlt']) { - const data = damage.parts.hitPoints[property]; - const previousFormula = getDamagePartsFormula(data); - const { value, formula } = calculateAdjustedDamage(previousFormula, 'attack', damageMeta); - applyAdjustedDamage(data, value, formula); - } - } catch (err) { - ui.notifications.warn('Failed to convert attack damage of adversary'); - console.error(err); - } - - // Update damage of each item action, making sure to also update the description if possible - const damageRegex = /@Damage\[([^\[\]]*)\]({[^}]*})?/g; - for (const item of source.items) { - // Replace damage inlines with new formulas. Keep a record for a specific check later - const descriptionFormulas = []; - for (const withDescription of [item.system, ...Object.values(item.system.actions)]) { - withDescription.description = withDescription.description.replace(damageRegex, (match, inner) => { - const { value: formula } = parseInlineParams(inner, { first: 'value' }); - if (!formula) return match; - - try { - const newFormula = calculateAdjustedDamage(formula, 'action', damageMeta)?.formula; - descriptionFormulas.push(formula); - return match.replace(formula, newFormula); - } catch { - return match; - } - }); - } - - // Update damage in item actions and convert all formula matches in the descriptions to the new damage - for (const action of Object.values(item.system.actions)) { - if (!action.damage?.parts.hitPoints) continue; - try { - // Apply conversions and save a record. If it matches attack damage *and* Its not in the description, use attack conversion instead - const result = []; - for (const property of ['value', 'valueAlt']) { - const { [property]: data, type: damageType } = action.damage.parts.hitPoints; - const previousFormula = getDamagePartsFormula(data); - const isActuallyAttack = - previousFormula === initialAttack.value && - foundry.utils.equals(damageType.toSorted(), initialAttack.type) && - !descriptionFormulas.includes(previousFormula); - const type = isActuallyAttack ? 'attack' : 'action'; - const { value, formula } = calculateAdjustedDamage(previousFormula, type, damageMeta); - applyAdjustedDamage(data, value, formula); - result.push({ previousFormula, formula }); - } - - // Override text in the description with those values - for (const { previousFormula, formula } of Object.values(result)) { - const oldFormulaRegexp = new RegExp( - previousFormula.replace(' ', '').replace('+', '(?:\\s)?\\+(?:\\s)?') - ); - item.system.description = item.system.description.replace(oldFormulaRegexp, formula); - action.description = action.description.replace(oldFormulaRegexp, formula); - } - } catch (err) { - ui.notifications.warn(`Failed to convert action damage for item ${item.name}`); - console.error(err); - } - } - } - - // Finally set the tier of the source data, now that everything is complete - source.system.tier = tier; - return source; -} - -/** - * Converts a damage object to a new damage range - * @returns {{ diceQuantity: number; faces: number; bonus: number }} the adjusted result as a combined term - * @throws error if the formula is the wrong type - */ -function calculateAdjustedDamage(formula, type, { currentDamageRange, newDamageRange }) { - const terms = parseTermsFromSimpleFormula(formula); - const flatTerms = terms.filter(t => t.diceQuantity === 0); - const diceTerms = terms.filter(t => t.diceQuantity > 0); - if (flatTerms.length > 1 || diceTerms.length > 1) { - throw new Error('invalid formula for conversion'); - } - const value = { - ...(diceTerms[0] ?? { diceQuantity: 0, faces: 1 }), - bonus: flatTerms[0]?.bonus ?? 0 - }; - const previousExpected = calculateExpectedValue(value); - if (previousExpected === 0) return value; // nothing to do - - const dieSizes = [4, 6, 8, 10, 12, 20]; - const steps = newDamageRange.tier - currentDamageRange.tier; - const increasing = steps > 0; - const deviation = (previousExpected - currentDamageRange.mean) / currentDamageRange.deviation; - const expected = Math.max(1, newDamageRange.mean + newDamageRange.deviation * deviation); - - // If this was just a flat number, convert to the expected damage and exit - if (value.diceQuantity === 0) { - value.bonus = Math.round(expected); - return value; - } - - const getExpectedDie = () => calculateExpectedValue({ diceQuantity: 1, faces: value.faces }) || 1; - const getBaseAverage = () => calculateExpectedValue({ ...value, bonus: 0 }); - - // Check the number of base overages over the expected die. In the end, if the bonus inflates too much, we add a die - const baseOverages = Math.floor(value.bonus / getExpectedDie()); - - // Prestep. Change number of dice for attacks, bump up/down for actions - // We never bump up to d20, though we might bump down from it - if (type === 'attack') { - const minimum = increasing ? value.diceQuantity : 0; - value.diceQuantity = Math.max(minimum, newDamageRange.tier); - } else { - const currentIdx = dieSizes.indexOf(value.faces); - value.faces = dieSizes[Math.clamp(currentIdx + steps, 0, 4)]; - } - - value.bonus = Math.round(expected - getBaseAverage()); - - // Attempt to handle negative values. - // If we can do it with only step downs, do so. Otherwise remove tier dice, and try again - if (value.bonus < 0) { - let stepsRequired = Math.ceil(Math.abs(value.bonus) / value.diceQuantity); - const currentIdx = dieSizes.indexOf(value.faces); - - // If step downs alone don't suffice, change the flat modifier, then calculate steps required again - // If this isn't sufficient, the result will be slightly off. This is unlikely to happen - if (type !== 'attack' && stepsRequired > currentIdx && value.diceQuantity > 0) { - value.diceQuantity -= increasing ? 1 : Math.abs(steps); - value.bonus = Math.round(expected - getBaseAverage()); - if (value.bonus >= 0) return value; // complete - } - - stepsRequired = Math.ceil(Math.abs(value.bonus) / value.diceQuantity); - value.faces = dieSizes[Math.max(0, currentIdx - stepsRequired)]; - value.bonus = Math.max(0, Math.round(expected - getBaseAverage())); - } - - // If value is really high, we add a number of dice based on the number of overages - // This attempts to preserve a similar amount of variance when increasing an action - const overagesToRemove = Math.floor(value.bonus / getExpectedDie()) - baseOverages; - if (type !== 'attack' && increasing && overagesToRemove > 0) { - value.diceQuantity += overagesToRemove; - value.bonus = Math.round(expected - getBaseAverage()); - } - - const newFormula = [value.diceQuantity ? `${value.diceQuantity}d${value.faces}` : null, value.bonus] - .filter(p => !!p) - .join('+'); - return { value, formula: newFormula }; -} - -function getDamagePartsFormula(data) { - return data.custom.enabled - ? data.custom.formula - : [data.flatMultiplier ? `${data.flatMultiplier}${data.dice}` : 0, data.bonus ?? 0].filter(p => !!p).join('+'); -} - -/** - * Updates damage to reflect a specific value. - * @throws if damage structure is invalid for conversion - * @returns the converted formula and value as a simplified term, or null if it doesn't deal HP damage - */ -function applyAdjustedDamage(diceData, value, formula) { - if (value.diceQuantity) { - diceData.custom.enabled = false; - diceData.bonus = value.bonus; - diceData.dice = `d${value.faces}`; - diceData.flatMultiplier = value.diceQuantity; - } else if (!value.diceQuantity) { - diceData.custom.enabled = true; - diceData.custom.formula = formula; - } -} diff --git a/module/data/chat-message/_modules.mjs b/module/data/chat-message/_modules.mjs index 450d1ba2..c671de31 100644 --- a/module/data/chat-message/_modules.mjs +++ b/module/data/chat-message/_modules.mjs @@ -1,5 +1,6 @@ import DHAbilityUse from './abilityUse.mjs'; import DHActorRoll from './actorRoll.mjs'; +import DHGroupRoll from './groupRoll.mjs'; import DHSystemMessage from './systemMessage.mjs'; export const config = { @@ -8,5 +9,6 @@ export const config = { damageRoll: DHActorRoll, dualityRoll: DHActorRoll, fateRoll: DHActorRoll, + groupRoll: DHGroupRoll, systemMessage: DHSystemMessage }; diff --git a/module/data/chat-message/abilityUse.mjs b/module/data/chat-message/abilityUse.mjs index 465461c0..07209fe2 100644 --- a/module/data/chat-message/abilityUse.mjs +++ b/module/data/chat-message/abilityUse.mjs @@ -7,31 +7,26 @@ export default class DHAbilityUse extends foundry.abstract.TypeDataModel { img: new fields.StringField({}), name: new fields.StringField({}), description: new fields.StringField({}), - source: new fields.SchemaField({ - actor: new fields.StringField(), - item: new fields.StringField(), - action: new fields.StringField() - }) + actions: new fields.ArrayField( + new fields.ObjectField({ + name: new fields.StringField({}), + damage: new fields.SchemaField({ + type: new fields.StringField({}), + value: new fields.StringField({}) + }), + healing: new fields.SchemaField({ + type: new fields.StringField({}), + value: new fields.StringField({}) + }), + cost: new fields.SchemaField({ + type: new fields.StringField({}), + value: new fields.NumberField({}) + }), + target: new fields.SchemaField({ + type: new fields.StringField({ nullable: true }) + }) + }) + ) }; } - - get actionActor() { - if (!this.source.actor) return null; - return fromUuidSync(this.source.actor); - } - - get actionItem() { - const actionActor = this.actionActor; - if (!actionActor || !this.source.item) return null; - - const item = actionActor.items.get(this.source.item); - return item ? item.system.actions?.find(a => a.id === this.source.action) : null; - } - - get action() { - const { actionItem: itemAction } = this; - if (!this.source.action) return null; - if (itemAction) return itemAction; - return null; - } } diff --git a/module/data/chat-message/actorRoll.mjs b/module/data/chat-message/actorRoll.mjs index ccfe25ea..1ea7ff93 100644 --- a/module/data/chat-message/actorRoll.mjs +++ b/module/data/chat-message/actorRoll.mjs @@ -1,5 +1,3 @@ -import { triggerChatRollFx } from '../../helpers/utils.mjs'; - const fields = foundry.data.fields; const targetsField = () => @@ -34,6 +32,7 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel { return { title: new fields.StringField(), actionDescription: new fields.HTMLField(), + roll: new fields.ObjectField(), targets: targetsField(), hasRoll: new fields.BooleanField({ initial: false }), hasDamage: new fields.BooleanField({ initial: false }), @@ -42,6 +41,7 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel { hasSave: new fields.BooleanField({ initial: false }), hasTarget: new fields.BooleanField({ initial: false }), isDirect: new fields.BooleanField({ initial: false }), + isCritical: new fields.BooleanField({ initial: false }), onSave: new fields.StringField(), source: new fields.SchemaField({ actor: new fields.StringField(), @@ -50,25 +50,11 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel { action: new fields.StringField() }), damage: new fields.ObjectField(), - damageOptions: new fields.ObjectField(), costs: new fields.ArrayField(new fields.ObjectField()), successConsumed: new fields.BooleanField({ initial: false }) }; } - get roll() { - switch (this.parent.type) { - case 'adversaryRoll': - return this.parent.rolls.find(x => x instanceof game.system.api.dice.D20Roll); - case 'dualityRoll': - return this.parent.rolls.find(x => x instanceof game.system.api.dice.DualityRoll); - case 'fateRoll': - return this.parent.rolls.find(x => x instanceof game.system.api.dice.FateRoll); - } - - return null; - } - get actionActor() { if (!this.source.actor) return null; return fromUuidSync(this.source.actor); @@ -132,35 +118,6 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel { }); } - /* TODO: Change how damage data is stored somehow to enable better rerolling */ - async getRerolledDamage() { - if (!this.damage) return; - - const rerolls = []; - const update = { system: { damage: {} } }; - for (const partKey in this.damage) { - const part = this.damage[partKey]; - const testRoll = Roll.fromData(part.parts[0].roll); - const rerolled = await testRoll.reroll(); - rerolls.push(rerolled); - - if (!update.system.damage[partKey]) update.system.damage[partKey] = { parts: [part.parts[0]] }; - const partData = update.system.damage[partKey].parts[0]; - update.system.damage[partKey].total = rerolled.total; - partData.modifierTotal = rerolled.terms.reduce((acc, x) => { - if (x.isDeterministic && !x.operator) acc += x.total; - return acc; - }, 0); - partData.dice = rerolled.dice.map(d => ({ ...d.toJSON(), dice: d.denomination })); - partData.total = rerolled.total; - partData.roll = rerolled.toJSON(); - } - - await triggerChatRollFx(rerolls); - - return update; - } - registerTargetHook() { if (!this.parent.isAuthor || !this.hasTarget) return; if (this.targetMode && this.parent.targetHook !== null) { diff --git a/module/data/chat-message/groupRoll.mjs b/module/data/chat-message/groupRoll.mjs new file mode 100644 index 00000000..a5308323 --- /dev/null +++ b/module/data/chat-message/groupRoll.mjs @@ -0,0 +1,39 @@ +import { abilities } from '../../config/actorConfig.mjs'; + +export default class DHGroupRoll extends foundry.abstract.TypeDataModel { + static defineSchema() { + const fields = foundry.data.fields; + + return { + leader: new fields.EmbeddedDataField(GroupRollMemberField), + members: new fields.ArrayField(new fields.EmbeddedDataField(GroupRollMemberField)) + }; + } + + get totalModifier() { + return this.members.reduce((acc, m) => { + if (m.manualSuccess === null) return acc; + + return acc + (m.manualSuccess ? 1 : -1); + }, 0); + } +} + +class GroupRollMemberField extends foundry.abstract.DataModel { + static defineSchema() { + const fields = foundry.data.fields; + + return { + actor: new fields.ObjectField(), + trait: new fields.StringField({ choices: abilities }), + difficulty: new fields.StringField(), + result: new fields.ObjectField({ nullable: true, initial: null }), + manualSuccess: new fields.BooleanField({ nullable: true, initial: null }) + }; + } + + /* Can be expanded if we handle automation of success/failure */ + get success() { + return manualSuccess; + } +} diff --git a/module/data/companionLevelup.mjs b/module/data/companionLevelup.mjs index e24820de..7ab61210 100644 --- a/module/data/companionLevelup.mjs +++ b/module/data/companionLevelup.mjs @@ -22,12 +22,12 @@ export class DhCompanionLevelup extends foundry.abstract.DataModel { const initialAchievements = i === tier.levels.start ? tier.initialAchievements : {}; const experiences = initialAchievements.experience ? [...Array(initialAchievements.experience.nr).keys()].reduce((acc, _) => { - acc[foundry.utils.randomID()] = { - name: '', - modifier: initialAchievements.experience.modifier - }; - return acc; - }, {}) + acc[foundry.utils.randomID()] = { + name: '', + modifier: initialAchievements.experience.modifier + }; + return acc; + }, {}) : {}; const currentChoices = pcLevelData.levelups[i]?.selections?.length; @@ -302,9 +302,9 @@ export class DhLevelupLevel extends foundry.abstract.DataModel { experiences: levelData.achievements?.experiences ?? achievements.experiences ?? {}, domainCards: levelData.achievements?.domainCards ? levelData.achievements.domainCards.reduce((acc, card, index) => { - acc[index] = { ...card }; - return acc; - }, {}) + acc[index] = { ...card }; + return acc; + }, {}) : (achievements.domainCards ?? {}), proficiency: levelData.achievements?.proficiency ?? achievements.proficiency ?? null }, diff --git a/module/data/compendiumBrowserSettings.mjs b/module/data/compendiumBrowserSettings.mjs index ed70c88f..ea71c439 100644 --- a/module/data/compendiumBrowserSettings.mjs +++ b/module/data/compendiumBrowserSettings.mjs @@ -11,13 +11,11 @@ export default class CompendiumBrowserSettings extends foundry.abstract.DataMode }) ), excludedPacks: new fields.TypedObjectField( - new fields.TypedObjectField( - new fields.SchemaField({ - excludedDocumentTypes: new fields.ArrayField( - new fields.StringField({ required: true, choices: CONST.SYSTEM_SPECIFIC_COMPENDIUM_TYPES }) - ) - }) - ) + new fields.SchemaField({ + excludedDocumentTypes: new fields.ArrayField( + new fields.StringField({ required: true, choices: CONST.SYSTEM_SPECIFIC_COMPENDIUM_TYPES }) + ) + }) ) }; } @@ -30,7 +28,7 @@ export default class CompendiumBrowserSettings extends foundry.abstract.DataMode const excludedSourceData = this.excludedSources[packageName]; if (excludedSourceData && excludedSourceData.excludedDocumentTypes.includes(pack.metadata.type)) return true; - const excludedPackData = this.excludedPacks[packageName]?.[pack.metadata.name]; + const excludedPackData = this.excludedPacks[item.pack]; if (excludedPackData && excludedPackData.excludedDocumentTypes.includes(pack.metadata.type)) return true; return false; diff --git a/module/data/countdowns.mjs b/module/data/countdowns.mjs index 54971d34..b944bf73 100644 --- a/module/data/countdowns.mjs +++ b/module/data/countdowns.mjs @@ -5,6 +5,10 @@ export default class DhCountdowns extends foundry.abstract.DataModel { const fields = foundry.data.fields; return { + /* Outdated and unused. Needed for migration. Remove in next minor version. (1.3) */ + narrative: new fields.EmbeddedDataField(DhCountdownData), + encounter: new fields.EmbeddedDataField(DhCountdownData), + /**/ countdowns: new fields.TypedObjectField(new fields.EmbeddedDataField(DhCountdown)), defaultOwnership: new fields.NumberField({ required: true, @@ -15,6 +19,122 @@ export default class DhCountdowns extends foundry.abstract.DataModel { } } +/* Outdated and unused. Needed for migration. Remove in next minor version. (1.3) */ +class DhCountdownData extends foundry.abstract.DataModel { + static defineSchema() { + const fields = foundry.data.fields; + return { + countdowns: new fields.TypedObjectField(new fields.EmbeddedDataField(DhOldCountdown)), + ownership: new fields.SchemaField({ + default: new fields.NumberField({ + required: true, + choices: Object.values(CONST.DOCUMENT_OWNERSHIP_LEVELS), + initial: CONST.DOCUMENT_OWNERSHIP_LEVELS.NONE + }), + players: new fields.TypedObjectField( + new fields.SchemaField({ + type: new fields.NumberField({ + required: true, + choices: Object.values(CONST.DOCUMENT_OWNERSHIP_LEVELS), + initial: CONST.DOCUMENT_OWNERSHIP_LEVELS.INHERIT + }) + }) + ) + }), + window: new fields.SchemaField({}) + }; + } + + get playerOwnership() { + return Array.from(game.users).reduce((acc, user) => { + acc[user.id] = { + value: user.isGM + ? CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER + : this.ownership.players[user.id] && this.ownership.players[user.id].type !== -1 + ? this.ownership.players[user.id].type + : this.ownership.default, + isGM: user.isGM + }; + + return acc; + }, {}); + } +} + +/* Outdated and unused. Needed for migration. Remove in next minor version. (1.3) */ +class DhOldCountdown extends foundry.abstract.DataModel { + static defineSchema() { + const fields = foundry.data.fields; + return { + name: new fields.StringField({ + required: true, + label: 'DAGGERHEART.APPLICATIONS.Countdown.FIELDS.countdowns.element.name.label' + }), + img: new fields.FilePathField({ + categories: ['IMAGE'], + base64: false, + initial: 'icons/magic/time/hourglass-yellow-green.webp' + }), + ownership: new fields.SchemaField({ + default: new fields.NumberField({ + required: true, + choices: Object.values(CONST.DOCUMENT_OWNERSHIP_LEVELS), + initial: CONST.DOCUMENT_OWNERSHIP_LEVELS.NONE + }), + players: new fields.TypedObjectField( + new fields.SchemaField({ + type: new fields.NumberField({ + required: true, + choices: Object.values(CONST.DOCUMENT_OWNERSHIP_LEVELS), + initial: CONST.DOCUMENT_OWNERSHIP_LEVELS.INHERIT + }) + }) + ) + }), + progress: new fields.SchemaField({ + current: new fields.NumberField({ + required: true, + integer: true, + initial: 1, + label: 'DAGGERHEART.APPLICATIONS.Countdown.FIELDS.countdowns.element.progress.current.label' + }), + max: new fields.NumberField({ + required: true, + integer: true, + initial: 1, + label: 'DAGGERHEART.APPLICATIONS.Countdown.FIELDS.countdowns.element.progress.max.label' + }), + type: new fields.SchemaField({ + value: new fields.StringField({ + required: true, + choices: CONFIG.DH.GENERAL.countdownProgressionTypes, + initial: CONFIG.DH.GENERAL.countdownProgressionTypes.custom.id, + label: 'DAGGERHEART.GENERAL.type' + }), + label: new fields.StringField({ + label: 'DAGGERHEART.APPLICATIONS.Countdown.FIELDS.countdowns.element.progress.type.label.label' + }) + }) + }) + }; + } + + get playerOwnership() { + return Array.from(game.users).reduce((acc, user) => { + acc[user.id] = { + value: user.isGM + ? CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER + : this.ownership.players[user.id] && this.ownership.players[user.id].type !== -1 + ? this.ownership.players[user.id].type + : this.ownership.default, + isGM: user.isGM + }; + + return acc; + }, {}); + } +} + export class DhCountdown extends foundry.abstract.DataModel { static defineSchema() { const fields = foundry.data.fields; @@ -77,11 +197,11 @@ export class DhCountdown extends foundry.abstract.DataModel { static defaultCountdown(type, playerHidden) { const ownership = playerHidden ? game.users.reduce((acc, user) => { - if (!user.isGM) { - acc[user.id] = CONST.DOCUMENT_OWNERSHIP_LEVELS.NONE; - } - return acc; - }, {}) + if (!user.isGM) { + acc[user.id] = CONST.DOCUMENT_OWNERSHIP_LEVELS.NONE; + } + return acc; + }, {}) : undefined; return { @@ -102,8 +222,8 @@ export class DhCountdown extends foundry.abstract.DataModel { value: user.isGM ? CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER : this.ownership.players[user.id] && this.ownership.players[user.id].type !== -1 - ? this.ownership.players[user.id].type - : this.ownership.default, + ? this.ownership.players[user.id].type + : this.ownership.default, isGM: user.isGM }; diff --git a/module/data/fields/_module.mjs b/module/data/fields/_module.mjs index 930814e2..2a8ba454 100644 --- a/module/data/fields/_module.mjs +++ b/module/data/fields/_module.mjs @@ -1,7 +1,7 @@ export { ActionCollection } from './actionField.mjs'; -export { default as IterableTypedObjectField } from './iterableTypedObjectField.mjs'; export { default as FormulaField } from './formulaField.mjs'; export { default as ForeignDocumentUUIDField } from './foreignDocumentUUIDField.mjs'; export { default as ForeignDocumentUUIDArrayField } from './foreignDocumentUUIDArrayField.mjs'; export { default as TriggerField } from './triggerField.mjs'; +export { default as MappingField } from './mappingField.mjs'; export * as ActionFields from './action/_module.mjs'; diff --git a/module/data/fields/action/_module.mjs b/module/data/fields/action/_module.mjs index f6c34817..fa3b1cd5 100644 --- a/module/data/fields/action/_module.mjs +++ b/module/data/fields/action/_module.mjs @@ -1,4 +1,3 @@ -export { default as AreasField } from './areasField.mjs'; export { default as CostField } from './costField.mjs'; export { default as CountdownField } from './countdownField.mjs'; export { default as UsesField } from './usesField.mjs'; diff --git a/module/data/fields/action/areasField.mjs b/module/data/fields/action/areasField.mjs deleted file mode 100644 index 52110045..00000000 --- a/module/data/fields/action/areasField.mjs +++ /dev/null @@ -1,40 +0,0 @@ -const fields = foundry.data.fields; - -export default class AreasField extends fields.ArrayField { - /** - * Action Workflow order - */ - static order = 150; - - /** @inheritDoc */ - constructor(options = {}, context = {}) { - const element = new fields.SchemaField({ - name: new fields.StringField({ - nullable: false, - initial: 'Area', - label: 'DAGGERHEART.GENERAL.name' - }), - type: new fields.StringField({ - nullable: false, - choices: CONFIG.DH.ACTIONS.areaTypes, - initial: CONFIG.DH.ACTIONS.areaTypes.placed.id, - label: 'DAGGERHEART.GENERAL.type' - }), - shape: new fields.StringField({ - nullable: false, - choices: CONFIG.DH.GENERAL.templateTypes, - initial: CONFIG.DH.GENERAL.templateTypes.circle.id, - label: 'DAGGERHEART.ACTIONS.Config.area.shape' - }), - /* Could be opened up to allow numbers to be input aswell. Probably best handled via an autocomplete in that case to allow the select options but also free text */ - size: new fields.StringField({ - nullable: false, - choices: CONFIG.DH.GENERAL.range, - initial: CONFIG.DH.GENERAL.range.veryClose.id, - label: 'DAGGERHEART.ACTIONS.Config.area.size' - }), - effects: new fields.ArrayField(new fields.DocumentIdField()) - }); - super(element, options, context); - } -} diff --git a/module/data/fields/action/beastformField.mjs b/module/data/fields/action/beastformField.mjs index 0eeb95c2..5e9c75f0 100644 --- a/module/data/fields/action/beastformField.mjs +++ b/module/data/fields/action/beastformField.mjs @@ -31,18 +31,6 @@ export default class BeastformField extends fields.SchemaField { label: 'DAGGERHEART.ACTIONS.Config.beastform.exact.label', hint: 'DAGGERHEART.ACTIONS.Config.beastform.exact.hint' }) - }), - modifications: new fields.SchemaField({ - traitBonuses: new fields.ArrayField( - new fields.SchemaField({ - bonus: new fields.NumberField({ - integer: true, - initial: 1, - min: 1, - label: 'DAGGERHEART.ACTIONS.Config.beastform.modifications.traitBonuses.bonus' - }) - }) - ) }) }; super(beastformFields, options, context); @@ -79,9 +67,15 @@ export default class BeastformField extends fields.SchemaField { ) ?? 1; config.tierLimit = this.beastform.tierAccess.exact ?? actorTier; - config.modifications = this.beastform.modifications; } + /** + * TODO by Harry + * @param {*} selectedForm + * @param {*} evolvedData + * @param {*} hybridData + * @returns + */ static async transform(selectedForm, evolvedData, hybridData) { const formData = evolvedData?.form ?? selectedForm; const beastformEffect = formData.effects.find(x => x.type === 'beastform'); @@ -105,8 +99,8 @@ export default class BeastformField extends fields.SchemaField { baseSize === 'custom' ? 'custom' : (Object.keys(CONFIG.DH.ACTOR.tokenSize).find( - x => CONFIG.DH.ACTOR.tokenSize[x].value === CONFIG.DH.ACTOR.tokenSize[baseSize].value + 1 - ) ?? baseSize); + x => CONFIG.DH.ACTOR.tokenSize[x].value === CONFIG.DH.ACTOR.tokenSize[baseSize].value + 1 + ) ?? baseSize); formData.system.tokenSize = { ...evolvedData.form.system.tokenSize, size: evolvedSize diff --git a/module/data/fields/action/costField.mjs b/module/data/fields/action/costField.mjs index 82cfcd23..9271f6b0 100644 --- a/module/data/fields/action/costField.mjs +++ b/module/data/fields/action/costField.mjs @@ -103,7 +103,7 @@ export default class CostField extends fields.ArrayField { static calcCosts(costs) { const resources = CostField.getResources.call(this, costs); let filteredCosts = costs; - if (this.parent?.isInventoryItem && this.parent.consumeOnUse === false) { + if (this.parent?.metadata.isQuantifiable && this.parent.consumeOnUse === false) { filteredCosts = filteredCosts.filter(c => c.key !== 'quantity'); } @@ -116,8 +116,8 @@ export default class CostField extends fields.ArrayField { c.key === 'fear' ? game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear) : resources[c.key].isReversed - ? resources[c.key].max - resources[c.key].value - : resources[c.key].value; + ? resources[c.key].max - resources[c.key].value + : resources[c.key].value; if (c.scalable) c.maxStep = Math.floor((c.max - c.value) / c.step); return c; }); @@ -149,8 +149,8 @@ export default class CostField extends fields.ArrayField { !resources[c.key] ? a : a && resources[c.key].isReversed - ? resources[c.key].value + (c.total ?? c.value) <= resources[c.key].max - : resources[c.key]?.value >= (c.total ?? c.value), + ? resources[c.key].value + (c.total ?? c.value) <= resources[c.key].max + : resources[c.key]?.value >= (c.total ?? c.value), true ); } diff --git a/module/data/fields/action/countdownField.mjs b/module/data/fields/action/countdownField.mjs index 96d9dd91..f49e71ad 100644 --- a/module/data/fields/action/countdownField.mjs +++ b/module/data/fields/action/countdownField.mjs @@ -1,4 +1,4 @@ -import { emitGMUpdate, GMUpdateEvent, RefreshType, socketEvent } from '../../../systemRegistration/socket.mjs'; +import { emitAsGM, GMUpdateEvent, RefreshType, socketEvent } from '../../../systemRegistration/socket.mjs'; const fields = foundry.data.fields; @@ -57,10 +57,6 @@ export default class CountdownField extends fields.ArrayField { data.countdowns[foundry.utils.randomID()] = { ...countdown, - ownership: game.users.reduce((acc, curr) => { - if (!curr.isGM) acc[curr.id] = countdown.defaultOwnership; - return acc; - }, {}), progress: { ...countdown.progress, current: countdownStart, @@ -78,7 +74,7 @@ export default class CountdownField extends fields.ArrayField { ); } - await emitGMUpdate( + await emitAsGM( GMUpdateEvent.UpdateCountdowns, async () => { const countdownSetting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns); @@ -87,11 +83,11 @@ export default class CountdownField extends fields.ArrayField { CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, countdownSetting.toObject() - ); - game.socket.emit(`system.${CONFIG.DH.id}`, { - action: socketEvent.Refresh, - data: { refreshType: RefreshType.Countdown } - }); + ), + game.socket.emit(`system.${CONFIG.DH.id}`, { + action: socketEvent.Refresh, + data: { refreshType: RefreshType.Countdown } + }); Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.Countdown }); }, data, diff --git a/module/data/fields/action/damageField.mjs b/module/data/fields/action/damageField.mjs index 9b21d3ba..6c091f8b 100644 --- a/module/data/fields/action/damageField.mjs +++ b/module/data/fields/action/damageField.mjs @@ -1,6 +1,5 @@ import FormulaField from '../formulaField.mjs'; import { setsEqual } from '../../../helpers/utils.mjs'; -import IterableTypedObjectField from '../iterableTypedObjectField.mjs'; const fields = foundry.data.fields; @@ -13,17 +12,12 @@ export default class DamageField extends fields.SchemaField { /** @inheritDoc */ constructor(options, context = {}) { const damageFields = { - parts: new IterableTypedObjectField(DHDamageData), + parts: new fields.ArrayField(new fields.EmbeddedDataField(DHDamageData)), includeBase: new fields.BooleanField({ initial: false, label: 'DAGGERHEART.ACTIONS.Settings.includeBase.label' }), - direct: new fields.BooleanField({ initial: false, label: 'DAGGERHEART.CONFIG.DamageType.direct.name' }), - groupAttack: new fields.StringField({ - choices: CONFIG.DH.GENERAL.groupAttackRange, - blank: true, - label: 'DAGGERHEART.ACTIONS.Settings.groupAttack.label' - }) + direct: new fields.BooleanField({ initial: false, label: 'DAGGERHEART.CONFIG.DamageType.direct.name' }) }; super(damageFields, options, context); } @@ -54,14 +48,11 @@ export default class DamageField extends fields.SchemaField { formulas = DamageField.formatFormulas.call(this, formulas, config); - messageId = config.message?._id ?? messageId; - const message = game.messages.get(messageId); const damageConfig = { - dialog: {}, ...config, roll: formulas, - data: this.getRollData(), - isCritical: Boolean(message?.system.roll?.isCritical) + dialog: {}, + data: this.getRollData() }; delete damageConfig.evaluate; @@ -69,9 +60,12 @@ export default class DamageField extends fields.SchemaField { damageConfig.dialog.configure = false; if (config.hasSave) config.onSave = damageConfig.onSave = this.save.damageMod; - damageConfig.source.message = messageId; + damageConfig.source.message = config.message?._id ?? messageId; damageConfig.directDamage = !!damageConfig.source?.message; + // if(damageConfig.source?.message && game.modules.get('dice-so-nice')?.active) + // await game.dice3d.waitFor3DAnimationByMessageID(damageConfig.source.message); + const damageResult = await CONFIG.Dice.daggerheart.DamageRoll.build(damageConfig); if (!damageResult) return false; if (damageResult.actionChatMessageHandled) config.actionChatMessageHandled = true; @@ -226,22 +220,6 @@ export default class DamageField extends fields.SchemaField { game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.damageApply.players) ); } - - static getGroupAttackTokens(actorId, range) { - if (!canvas.scene) return []; - - const targets = Array.from(game.user.targets); - const rangeSettings = canvas.scene?.rangeSettings; - if (!rangeSettings) return []; - - const maxDistance = rangeSettings[range]; - return canvas.scene.tokens.filter(x => { - if (x.actor?.id !== actorId) return false; - if (targets.every(target => x.object.distanceTo(target) > maxDistance)) return false; - - return true; - }); - } } export class DHActionDiceData extends foundry.abstract.DataModel { @@ -250,7 +228,7 @@ export class DHActionDiceData extends foundry.abstract.DataModel { return { multiplier: new fields.StringField({ choices: CONFIG.DH.GENERAL.multiplierTypes, - initial: 'flat', + initial: 'prof', label: 'DAGGERHEART.ACTIONS.Config.damage.multiplier', nullable: false, required: true @@ -262,7 +240,7 @@ export class DHActionDiceData extends foundry.abstract.DataModel { }), dice: new fields.StringField({ choices: CONFIG.DH.GENERAL.diceTypes, - initial: CONFIG.DH.GENERAL.diceTypes.d6, + initial: 'd6', label: 'DAGGERHEART.GENERAL.Dice.single', nullable: false, required: true diff --git a/module/data/fields/action/effectsField.mjs b/module/data/fields/action/effectsField.mjs index e943d63d..6afd470b 100644 --- a/module/data/fields/action/effectsField.mjs +++ b/module/data/fields/action/effectsField.mjs @@ -1,3 +1,5 @@ +import { emitAsGM, GMUpdateEvent } from '../../../systemRegistration/socket.mjs'; + const fields = foundry.data.fields; export default class EffectsField extends fields.ArrayField { @@ -25,14 +27,15 @@ export default class EffectsField extends fields.ArrayField { static async execute(config, targets = null, force = false) { if (!config.hasEffect) return; let message = config.message ?? ui.chat.collection.get(config.parent?._id); - if (!message && !config.skips.createMessage) { + if (!message) { const roll = new CONFIG.Dice.daggerheart.DHRoll(''); roll._evaluated = true; message = config.message = await CONFIG.Dice.daggerheart.DHRoll.toMessage(roll, config); } if (EffectsField.getAutomation() || force) { targets ??= (message.system?.targets ?? config.targets).filter(t => !config.hasRoll || t.hit); - EffectsField.applyEffects.call(this, targets); + await emitAsGM(GMUpdateEvent.UpdateEffect, EffectsField.applyEffects.bind(this), targets, this.uuid); + // EffectsField.applyEffects.call(this, config.targets.filter(t => !config.hasRoll || t.hit)); } } @@ -56,16 +59,16 @@ export default class EffectsField extends fields.ArrayField { if (!token) return; const messageToken = token.document ?? token; - const conditionImmunities = messageToken.actor.system.rules?.conditionImmunities ?? {}; + const conditionImmunities = messageToken.actor.system.rules.conditionImmunities ?? {}; messageTargets.push({ token: messageToken, conditionImmunities: Object.values(conditionImmunities).some(x => x) ? game.i18n.format('DAGGERHEART.UI.Chat.effectSummary.immunityTo', { - immunities: Object.keys(conditionImmunities) - .filter(x => conditionImmunities[x]) - .map(x => game.i18n.localize(conditions[x].name)) - .join(', ') - }) + immunities: Object.keys(conditionImmunities) + .filter(x => conditionImmunities[x]) + .map(x => game.i18n.localize(conditions[x].name)) + .join(', ') + }) : null }); @@ -103,11 +106,22 @@ export default class EffectsField extends fields.ArrayField { } /** - * Apply an Effect to a target + * Apply an Effect to a target or enable it if already on it * @param {object} effect Effect object containing ActiveEffect UUID * @param {object} actor Actor Document */ static async applyEffect(effect, actor) { + const existingEffect = actor.effects.find(e => e.origin === effect.uuid); + if (existingEffect) { + return effect.update( + foundry.utils.mergeObject({ + ...effect.constructor.getInitialDuration(), + disabled: false + }) + ); + } + + // Otherwise, create a new effect on the target const effectData = foundry.utils.mergeObject({ ...(effect.toObject?.() ?? effect), disabled: false, diff --git a/module/data/fields/action/saveField.mjs b/module/data/fields/action/saveField.mjs index 7343ab85..c9030036 100644 --- a/module/data/fields/action/saveField.mjs +++ b/module/data/fields/action/saveField.mjs @@ -38,7 +38,7 @@ export default class SaveField extends fields.SchemaField { if (!config.hasSave) return; let message = config.message ?? ui.chat.collection.get(config.parent?._id); - if (!message && !config.skips.createMessage) { + if (!message) { const roll = new CONFIG.Dice.daggerheart.DHRoll(''); roll._evaluated = true; message = config.message = await CONFIG.Dice.daggerheart.DHRoll.toMessage(roll, config); @@ -69,11 +69,11 @@ export default class SaveField extends fields.SchemaField { game.user === actor.owner ? SaveField.rollSave.call(this, actor, event) : actor.owner.query('reactionRoll', { - actionId: this.uuid, - actorId: actor.uuid, - event, - message - }); + actionId: this.uuid, + actorId: actor.uuid, + event, + message + }); const result = await rollSave; await SaveField.updateSaveMessage.call(this, result, message, target.id); subResolve(); @@ -97,8 +97,8 @@ export default class SaveField extends fields.SchemaField { const title = actor.isNPC ? game.i18n.localize('DAGGERHEART.GENERAL.reactionRoll') : game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', { - ability: game.i18n.localize(abilities[this.save.trait]?.label) - }), + ability: game.i18n.localize(abilities[this.save.trait]?.label) + }), rollConfig = { event, title, diff --git a/module/data/fields/action/summonField.mjs b/module/data/fields/action/summonField.mjs index a2275fa5..dce6414c 100644 --- a/module/data/fields/action/summonField.mjs +++ b/module/data/fields/action/summonField.mjs @@ -1,4 +1,3 @@ -import { itemAbleRollParse, triggerChatRollFx } from '../../../helpers/utils.mjs'; import FormulaField from '../formulaField.mjs'; const fields = foundry.data.fields; @@ -37,47 +36,54 @@ export default class DHSummonField extends fields.ArrayField { const rolls = []; const summonData = []; for (const summon of this.summon) { - const roll = new Roll(itemAbleRollParse(summon.count, this.actor, this.item)); - await roll.evaluate(); - const count = roll.total; - if (!roll.isDeterministic) rolls.push(roll); + let count = summon.count; + const roll = new Roll(summon.count); + if (!roll.isDeterministic) { + await roll.evaluate(); + if (game.modules.get('dice-so-nice')?.active) rolls.push(roll); + count = roll.total; + } - const actor = await DHSummonField.getWorldActor(await foundry.utils.fromUuid(summon.actorUUID)); + const actor = DHSummonField.getWorldActor(await foundry.utils.fromUuid(summon.actorUUID)); /* Extending summon data in memory so it's available in actionField.toChat. Think it's harmless, but ugly. Could maybe find a better way. */ + summon.rolledCount = count; summon.actor = actor.toObject(); - const countNumber = Number.parseInt(count); - for (let i = 0; i < countNumber; i++) { - const remaining = countNumber - i; - summonData.push({ - actor, - tokenPreviewName: `${actor.prototypeToken.name}${remaining > 1 ? ` (${remaining}x)` : ''}` - }); - } + summonData.push({ actor, count: count }); } - if (rolls.length) await triggerChatRollFx(rolls); + if (rolls.length) await Promise.all(rolls.map(roll => game.dice3d.showForRoll(roll, game.user, true))); this.actor.sheet?.minimize(); DHSummonField.handleSummon(summonData, this.actor); } - /* Check for any available instances of the actor present in the world if we're missing artwork in the compendium. If none exists, create one. */ - static async getWorldActor(baseActor) { + /* Check for any available instances of the actor present in the world if we're missing artwork in the compendium */ + static getWorldActor(baseActor) { const dataType = game.system.api.data.actors[`Dh${baseActor.type.capitalize()}`]; if (baseActor.inCompendium && dataType && baseActor.img === dataType.DEFAULT_ICON) { const worldActorCopy = game.actors.find(x => x.name === baseActor.name); - if (worldActorCopy) return worldActorCopy; - - return await game.system.api.documents.DhpActor.create(baseActor.toObject()); + return worldActorCopy ?? baseActor; } return baseActor; } - static async handleSummon(summonData, actionActor) { - await CONFIG.ux.TokenManager.createTokensWithPreview(summonData, { elevation: actionActor.token?.elevation }); + static async handleSummon(summonData, actionActor, summonIndex = 0) { + const summon = summonData[summonIndex]; + const result = await CONFIG.ux.TokenManager.createPreviewAsync(summon.actor, { + name: `${summon.actor.prototypeToken.name}${summon.count > 1 ? ` (${summon.count}x)` : ''}` + }); - return actionActor.sheet?.maximize(); + if (!result) return actionActor.sheet?.maximize(); + summon.actor = result.actor; + + summon.count--; + if (summon.count <= 0) { + summonIndex++; + if (summonIndex === summonData.length) return actionActor.sheet?.maximize(); + } + + DHSummonField.handleSummon(summonData, actionActor, summonIndex); } } diff --git a/module/data/fields/actionField.mjs b/module/data/fields/actionField.mjs index 83672c8e..89c3c287 100644 --- a/module/data/fields/actionField.mjs +++ b/module/data/fields/actionField.mjs @@ -1,5 +1,6 @@ import DHActionConfig from '../../applications/sheets-configs/action-config.mjs'; import { itemAbleRollParse } from '../../helpers/utils.mjs'; +import MappingField from './mappingField.mjs'; /** * Specialized collection type for stored actions. @@ -10,9 +11,9 @@ export class ActionCollection extends Collection { constructor(model, entries) { super(); this.#model = model; - for (const [key, value] of entries) { - if (!(value instanceof game.system.api.models.actions.actionsTypes.base)) continue; - this.set(key, value); + for (const entry of entries) { + if (!(entry instanceof game.system.api.models.actions.actionsTypes.base)) continue; + this.set(entry._id, entry); } } @@ -60,7 +61,7 @@ export class ActionCollection extends Collection { /** * Field that stores actions. */ -export class ActionsField extends foundry.data.fields.TypedObjectField { +export class ActionsField extends MappingField { constructor(options) { super(new ActionField(), options); } @@ -69,7 +70,7 @@ export class ActionsField extends foundry.data.fields.TypedObjectField { /** @inheritDoc */ initialize(value, model, options) { - const actions = Object.entries(super.initialize(value, model, options)); + const actions = Object.values(super.initialize(value, model, options)); return new ActionCollection(model, actions); } } @@ -87,11 +88,10 @@ export class ActionField extends foundry.data.fields.ObjectField { /* -------------------------------------------- */ /** @override */ - _cleanType(value, options, _state) { + _cleanType(value, options) { if (!(typeof value === 'object')) value = {}; - value = super._cleanType(value, options, _state); const cls = this.getModel(value); - if (cls) return cls.cleanData(value, options, _state); + if (cls) return cls.cleanData(value, options); return value; } @@ -111,17 +111,9 @@ export class ActionField extends foundry.data.fields.ObjectField { * @param {object} sourceData Candidate source data of the root model. * @param {any} fieldData The value of this field within the source data. */ - _migrate(sourceData, _fieldData) { - const source = sourceData ?? this.options.initial; - if (!source) return sourceData; - - const cls = this.getModel(source); - if (cls) { - cls.migrateDataSafe(source); - return source; - } - - return sourceData; + migrateSource(sourceData, fieldData) { + const cls = this.getModel(fieldData); + if (cls) cls.migrateDataSafe(fieldData); } } @@ -245,11 +237,11 @@ export function ActionMixin(Base) { : foundry.utils.getProperty(result, basePath); } - async delete() { + delete() { if (!this.inCollection) return this.item; const action = foundry.utils.getProperty(this.item, `system.${this.systemPath}`)?.get(this.id); if (!action) return this.item; - await this.item.update({ [`system.${this.systemPath}.${this.id}`]: _del }); // Does not work. Unsure why. It worked in v13 <_<' + this.item.update({ [`system.${this.systemPath}.-=${this.id}`]: null }); this.constructor._sheets.get(this.uuid)?.close(); } @@ -281,14 +273,8 @@ export function ActionMixin(Base) { name: this.name, img: this.baseAction ? this.parent.parent.img : this.img, tags: this.tags ? this.tags : ['Spell', 'Arcana', 'Lv 10'], - areas: this.areas, summon: this.summon }, - source: { - actor: this.actor.uuid, - item: this.item.id, - action: this.id - }, itemOrigin: this.item, description: this.description || (this.item instanceof Item ? this.item.system.description : '') }; @@ -316,7 +302,7 @@ export function ActionMixin(Base) { } }; - ChatMessage.applyMode(msg, game.settings.get('core', 'messageMode')); + ChatMessage.applyRollMode(msg, game.settings.get('core', 'rollMode')); cls.create(msg); } } diff --git a/module/data/fields/actorField.mjs b/module/data/fields/actorField.mjs index a5f6f379..ac7dd5ef 100644 --- a/module/data/fields/actorField.mjs +++ b/module/data/fields/actorField.mjs @@ -52,8 +52,8 @@ class ResourcesField extends fields.TypedObjectField { return key in CONFIG.DH.RESOURCE[this.actorType].all; } - _cleanType(value, options, _state) { - value = super._cleanType(value, options, _state); + _cleanType(value, options) { + value = super._cleanType(value, options); // If not partial, ensure all data exists if (!options.partial) { @@ -101,13 +101,13 @@ class ResourcesField extends fields.TypedObjectField { */ _getField(path) { if (path.length === 0) return this; - const name = path.pop(); - if (name === this.element.name) return this.element_getField(path); + const first = path.shift(); + if (first === this.element.name) return this.element_getField(path); const resources = CONFIG.DH.RESOURCE[this.actorType].all; - if (name in resources) { + if (first in resources) { const field = this.element._getField(path); - field.label = resources[name].label; + field.label = resources[first].label; return field; } @@ -115,15 +115,4 @@ class ResourcesField extends fields.TypedObjectField { } } -class GoldField extends fields.SchemaField { - constructor() { - super({ - coins: new fields.NumberField({ initial: 0, integer: true }), - handfuls: new fields.NumberField({ initial: 1, integer: true }), - bags: new fields.NumberField({ initial: 0, integer: true }), - chests: new fields.NumberField({ initial: 0, integer: true }) - }); - } -} - -export { attributeField, ResourcesField, GoldField, stressDamageReductionRule, bonusField }; +export { attributeField, ResourcesField, stressDamageReductionRule, bonusField }; diff --git a/module/data/fields/foreignDocumentUUIDArrayField.mjs b/module/data/fields/foreignDocumentUUIDArrayField.mjs index f8969d33..0ddd126c 100644 --- a/module/data/fields/foreignDocumentUUIDArrayField.mjs +++ b/module/data/fields/foreignDocumentUUIDArrayField.mjs @@ -10,12 +10,11 @@ export default class ForeignDocumentUUIDArrayField extends foundry.data.fields.A */ constructor(fieldOption = {}, options = {}, context = {}) { super(new ForeignDocumentUUIDField(fieldOption), options, context); - this.options.prune ??= true; } /** @inheritdoc */ initialize(value, model, options = {}) { - const v = super.initialize(value ?? [], model, options); + const v = super.initialize(value, model, options); return () => { const data = v.map(entry => (typeof entry === 'function' ? entry() : entry)); return this.options.prune ? data.filter(d => !!d) : data; diff --git a/module/data/fields/iterableTypedObjectField.mjs b/module/data/fields/iterableTypedObjectField.mjs deleted file mode 100644 index d360b641..00000000 --- a/module/data/fields/iterableTypedObjectField.mjs +++ /dev/null @@ -1,32 +0,0 @@ -export default class IterableTypedObjectField extends foundry.data.fields.TypedObjectField { - constructor(model, options = { collectionClass: foundry.utils.Collection }, context = {}) { - super(new foundry.data.fields.EmbeddedDataField(model), options, context); - this.#elementClass = model; - } - - #elementClass; - - /** Initializes an object with an iterator. This modifies the prototype instead of */ - initialize(values) { - const object = Object.create(IterableObjectPrototype); - for (const [key, value] of Object.entries(values)) { - object[key] = new this.#elementClass(value); - } - return object; - } -} - -/** - * The prototype of an iterable object. - * This allows the functionality of a class but also allows foundry.utils.getType() to return "Object" instead of "Unknown". - */ -const IterableObjectPrototype = { - [Symbol.iterator]: function* () { - for (const value of Object.values(this)) { - yield value; - } - }, - map: function (func) { - return Array.from(this, func); - } -}; diff --git a/module/data/fields/mappingField.mjs b/module/data/fields/mappingField.mjs new file mode 100644 index 00000000..31d91c76 --- /dev/null +++ b/module/data/fields/mappingField.mjs @@ -0,0 +1,128 @@ +/** + * A subclass of ObjectField that represents a mapping of keys to the provided DataField type. + * + * @param {DataField} model The class of DataField which should be embedded in this field. + * @param {MappingFieldOptions} [options={}] Options which configure the behavior of the field. + * @property {string[]} [initialKeys] Keys that will be created if no data is provided. + * @property {MappingFieldInitialValueBuilder} [initialValue] Function to calculate the initial value for a key. + * @property {boolean} [initialKeysOnly=false] Should the keys in the initialized data be limited to the keys provided + * by `options.initialKeys`? + */ +export default class MappingField extends foundry.data.fields.ObjectField { + constructor(model, options) { + if (!(model instanceof foundry.data.fields.DataField)) { + throw new Error('MappingField must have a DataField as its contained element'); + } + super(options); + + /** + * The embedded DataField definition which is contained in this field. + * @type {DataField} + */ + this.model = model; + model.parent = this; + } + + /* -------------------------------------------- */ + + /** @inheritDoc */ + static get _defaults() { + return foundry.utils.mergeObject(super._defaults, { + initialKeys: null, + initialValue: null, + initialKeysOnly: false + }); + } + + /* -------------------------------------------- */ + + /** @inheritDoc */ + _cleanType(value, options) { + Object.entries(value).forEach(([k, v]) => { + if (k.startsWith('-=')) return; + value[k] = this.model.clean(v, options); + }); + return value; + } + + /* -------------------------------------------- */ + + /** @inheritDoc */ + getInitialValue(data) { + let keys = this.initialKeys; + const initial = super.getInitialValue(data); + if (!keys || !foundry.utils.isEmpty(initial)) return initial; + if (!(keys instanceof Array)) keys = Object.keys(keys); + for (const key of keys) initial[key] = this._getInitialValueForKey(key); + return initial; + } + + /* -------------------------------------------- */ + + /** + * Get the initial value for the provided key. + * @param {string} key Key within the object being built. + * @param {object} [object] Any existing mapping data. + * @returns {*} Initial value based on provided field type. + */ + _getInitialValueForKey(key, object) { + const initial = this.model.getInitialValue(); + return this.initialValue?.(key, initial, object) ?? initial; + } + + /* -------------------------------------------- */ + + /** @override */ + _validateType(value, options = {}) { + if (foundry.utils.getType(value) !== 'Object') throw new Error('must be an Object'); + const errors = this._validateValues(value, options); + if (!foundry.utils.isEmpty(errors)) { + const failure = new foundry.data.validation.DataModelValidationFailure(); + failure.elements = Object.entries(errors).map(([id, failure]) => ({ id, failure })); + throw failure.asError(); + } + } + + /* -------------------------------------------- */ + + /** + * Validate each value of the object. + * @param {object} value The object to validate. + * @param {object} options Validation options. + * @returns {Record} An object of value-specific errors by key. + */ + _validateValues(value, options) { + const errors = {}; + for (const [k, v] of Object.entries(value)) { + if (k.startsWith('-=')) continue; + const error = this.model.validate(v, options); + if (error) errors[k] = error; + } + return errors; + } + + /* -------------------------------------------- */ + + /** @override */ + initialize(value, model, options = {}) { + if (!value) return value; + const obj = {}; + const initialKeys = this.initialKeys instanceof Array ? this.initialKeys : Object.keys(this.initialKeys ?? {}); + const keys = this.initialKeysOnly ? initialKeys : Object.keys(value); + for (const key of keys) { + const data = value[key] ?? this._getInitialValueForKey(key, value); + obj[key] = this.model.initialize(data, model, options); + } + return obj; + } + + /* -------------------------------------------- */ + + /** @inheritDoc */ + _getField(path) { + if (path.length === 0) return this; + else if (path.length === 1) return this.model; + path.shift(); + return this.model._getField(path); + } +} diff --git a/module/data/groupRollData.mjs b/module/data/groupRollData.mjs deleted file mode 100644 index 10123152..00000000 --- a/module/data/groupRollData.mjs +++ /dev/null @@ -1,40 +0,0 @@ -export default class GroupRollData extends foundry.abstract.DataModel { - static defineSchema() { - const fields = foundry.data.fields; - - return { - leader: new fields.EmbeddedDataField(CharacterData, { nullable: true, initial: null }), - aidingCharacters: new fields.TypedObjectField(new fields.EmbeddedDataField(CharacterData)) - }; - } - - get participants() { - return { - ...(this.leader ? { [this.leader.id]: this.leader } : {}), - ...this.aidingCharacters - }; - } -} - -export class CharacterData extends foundry.abstract.DataModel { - static defineSchema() { - const fields = foundry.data.fields; - - return { - id: new fields.StringField({ required: true }), - name: new fields.StringField({ required: true }), - img: new fields.StringField({ required: true }), - rollChoice: new fields.StringField({ - choices: CONFIG.DH.ACTOR.abilities, - initial: CONFIG.DH.ACTOR.abilities.agility.id - }), - rollData: new fields.JSONField({ nullable: true, initial: null }), - selected: new fields.BooleanField({ initial: false }), - successful: new fields.BooleanField({ nullable: true, initial: null }) - }; - } - - get roll() { - return this.rollData ? CONFIG.Dice.daggerheart.DualityRoll.fromData(this.rollData) : null; - } -} diff --git a/module/data/item/ancestry.mjs b/module/data/item/ancestry.mjs index eae1136c..b9253a3c 100644 --- a/module/data/item/ancestry.mjs +++ b/module/data/item/ancestry.mjs @@ -1,6 +1,6 @@ import BaseDataItem from './base.mjs'; import ItemLinkFields from '../../data/fields/itemLinkFields.mjs'; -import { fromUuids, getFeaturesHTMLData } from '../../helpers/utils.mjs'; +import { getFeaturesHTMLData } from '../../helpers/utils.mjs'; export default class DHAncestry extends BaseDataItem { /** @inheritDoc */ @@ -45,10 +45,6 @@ export default class DHAncestry extends BaseDataItem { /**@inheritdoc */ async getDescriptionData() { - // Preload all ancestry features for acquisition from the cache - // todo: make feature acquisition async and replace feature helpers for methods - await fromUuids(this._source.features.map(f => f.item)); - const baseDescription = this.description; const features = await getFeaturesHTMLData(this.features); diff --git a/module/data/item/armor.mjs b/module/data/item/armor.mjs index 21c56f9a..0958a9f3 100644 --- a/module/data/item/armor.mjs +++ b/module/data/item/armor.mjs @@ -19,14 +19,7 @@ export default class DHArmor extends AttachableItem { ...super.defineSchema(), tier: new fields.NumberField({ required: true, integer: true, initial: 1, min: 1 }), equipped: new fields.BooleanField({ initial: false }), - armor: new fields.SchemaField({ - current: new fields.NumberField({ integer: true, min: 0, initial: 0 }), - max: new fields.NumberField({ required: true, integer: true, initial: 0 }) - }), - baseThresholds: new fields.SchemaField({ - major: new fields.NumberField({ integer: true, initial: 0 }), - severe: new fields.NumberField({ integer: true, initial: 0 }) - }), + baseScore: new fields.NumberField({ integer: true, initial: 0 }), armorFeatures: new fields.ArrayField( new fields.SchemaField({ value: new fields.StringField({ @@ -35,7 +28,14 @@ export default class DHArmor extends AttachableItem { effectIds: new fields.ArrayField(new fields.StringField({ required: true })), actionIds: new fields.ArrayField(new fields.StringField({ required: true })) }) - ) + ), + marks: new fields.SchemaField({ + value: new fields.NumberField({ initial: 0, integer: true }) + }), + baseThresholds: new fields.SchemaField({ + major: new fields.NumberField({ integer: true, initial: 0 }), + severe: new fields.NumberField({ integer: true, initial: 0 }) + }) }; } @@ -84,7 +84,7 @@ export default class DHArmor extends AttachableItem { } await this.parent.deleteEmbeddedDocuments('ActiveEffect', effectIds); changes.system.actions = actionIds.reduce((acc, id) => { - acc[id] = _del; + acc[`-=${id}`] = null; return acc; }, {}); @@ -141,10 +141,13 @@ export default class DHArmor extends AttachableItem { } } - /** @inheritDoc */ - static migrateDocumentData(source) { - if (!source.system.armor) { - source.system.armor = { current: source.system.marks?.value ?? 0, max: source.system.baseScore ?? 0 }; + _onUpdate(a, b, c) { + super._onUpdate(a, b, c); + + if (this.actor?.type === 'character') { + for (const party of this.actor.parties) { + party.render(); + } } } @@ -154,7 +157,7 @@ export default class DHArmor extends AttachableItem { */ _getTags() { const tags = [ - `${game.i18n.localize('DAGGERHEART.ITEMS.Armor.baseScore')}: ${this.armor.max}`, + `${game.i18n.localize('DAGGERHEART.ITEMS.Armor.baseScore')}: ${this.baseScore}`, `${game.i18n.localize('DAGGERHEART.ITEMS.Armor.baseThresholds.base')}: ${this.baseThresholds.major} / ${this.baseThresholds.severe}` ]; @@ -166,7 +169,9 @@ export default class DHArmor extends AttachableItem { * @returns {(string | { value: string, icons: string[] })[]} An array of localized strings and damage label objects. */ _getLabels() { - const labels = [`${game.i18n.localize('DAGGERHEART.ITEMS.Armor.baseScore')}: ${this.armor.max}`]; + const labels = []; + if (this.baseScore) + labels.push(`${game.i18n.localize('DAGGERHEART.ITEMS.Armor.baseScore')}: ${this.baseScore}`); return labels; } diff --git a/module/data/item/base.mjs b/module/data/item/base.mjs index ba114fda..6f3256e3 100644 --- a/module/data/item/base.mjs +++ b/module/data/item/base.mjs @@ -4,15 +4,11 @@ * @property {string} label - A localizable label used on application. * @property {string} type - The system type that this data model represents. * @property {boolean} hasDescription - Indicates whether items of this type have description field + * @property {boolean} isQuantifiable - Indicates whether items of this type have quantity field * @property {boolean} isInventoryItem- Indicates whether items of this type is a Inventory Item */ -import { - addLinkedItemsDiff, - getScrollTextData, - createShallowProxy, - updateLinkedItemApps -} from '../../helpers/utils.mjs'; +import { addLinkedItemsDiff, getScrollTextData, updateLinkedItemApps } from '../../helpers/utils.mjs'; import { ActionsField } from '../fields/actionField.mjs'; import FormulaField from '../fields/formulaField.mjs'; @@ -28,6 +24,7 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { type: 'base', hasDescription: false, hasResource: false, + isQuantifiable: false, isInventoryItem: false, hasActions: false, hasAttribution: true @@ -86,7 +83,7 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { ); } - if (this.metadata.isInventoryItem) + if (this.metadata.isQuantifiable) schema.quantity = new fields.NumberField({ integer: true, initial: 1, min: 0, required: true }); if (this.metadata.hasActions) schema.actions = new ActionsField(); @@ -113,10 +110,6 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { } get actionsList() { - // No actions on non-characters - if (this.metadata.isInventoryItem && this.actor && this.actor.type !== 'character') { - return []; - } return this.actions; } @@ -164,8 +157,8 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { * @returns {object} */ getRollData(options = {}) { - const data = this.actor?.getRollData() ?? {}; - data.item = createShallowProxy(this); + const actorRollData = this.actor?.getRollData() ?? {}; + const data = { ...actorRollData, item: { ...this } }; return data; } @@ -200,7 +193,7 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { const features = []; for (let f of this.features) { const fBase = f.item ?? f; - const feature = fBase.pack ? await foundry.utils.fromUuid(fBase.uuid) : fBase; + const feature = fBase.system ? fBase : await foundry.utils.fromUuid(fBase.uuid); features.push( foundry.utils.mergeObject( feature.toObject(), @@ -229,22 +222,17 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { const autoSettings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation); const armorChanged = - changed.system?.armor?.current !== undefined && changed.system.armor.current !== this.armor.current; + changed.system?.marks?.value !== undefined && changed.system.marks.value !== this.marks.value; if (armorChanged && autoSettings.resourceScrollTexts && this.parent.parent?.type === 'character') { - const armorChangeValue = changed.system.armor.current - this.armor.current; - const armorData = getScrollTextData( - this.parent.parent, - { value: armorChangeValue + this.parent.parent.system.armorScore.value }, - 'armor' - ); + const armorData = getScrollTextData(this.parent.parent, changed.system.marks, 'armor'); options.scrollingTextData = [armorData]; } if (changed.system?.actions) { const triggersToRemove = Object.keys(changed.system.actions).reduce((acc, key) => { - const action = changed.system.actions[key]; - if (action && Object.keys(action).length === 0) { - acc.push(...this.actions.get(key).triggers.map(x => x.trigger)); + if (!changed.system.actions[key]) { + const strippedKey = key.replace('-=', ''); + acc.push(...this.actions.get(strippedKey).triggers.map(x => x.trigger)); } return acc; diff --git a/module/data/item/beastform.mjs b/module/data/item/beastform.mjs index ba274cc7..3a41aa7e 100644 --- a/module/data/item/beastform.mjs +++ b/module/data/item/beastform.mjs @@ -51,8 +51,7 @@ export default class DHBeastform extends BaseDataItem { }), scale: new fields.NumberField({ nullable: false, min: 0.2, max: 3, step: 0.05, initial: 1 }), height: new fields.NumberField({ integer: true, min: 1, initial: null, nullable: true }), - width: new fields.NumberField({ integer: true, min: 1, initial: null, nullable: true }), - depth: new fields.NumberField({ integer: true, min: 1, initial: null, nullable: true }) + width: new fields.NumberField({ integer: true, min: 1, initial: null, nullable: true }) }), mainTrait: new fields.StringField({ required: true, @@ -100,22 +99,17 @@ export default class DHBeastform extends BaseDataItem { get beastformAttackData() { const effect = this.parent.effects.find(x => x.type === 'beastform'); - return DHBeastform.getBeastformAttackData(effect); - } - - static getBeastformAttackData(effect) { if (!effect) return null; - const mainTrait = effect.system.changes.find(x => x.key === 'system.rules.attack.roll.trait')?.value; - const traitBonus = effect.system.changes.find(x => x.key === `system.traits.${mainTrait}.value`)?.value ?? 0; - const evasionBonus = effect.system.changes.find(x => x.key === 'system.evasion')?.value ?? 0; + const traitBonus = effect.changes.find(x => x.key === `system.traits.${this.mainTrait}.value`)?.value ?? 0; + const evasionBonus = effect.changes.find(x => x.key === 'system.evasion')?.value ?? 0; - const damageDiceIndex = effect.system.changes.find(x => x.key === 'system.rules.attack.damage.diceIndex'); + const damageDiceIndex = effect.changes.find(x => x.key === 'system.rules.attack.damage.diceIndex'); const damageDice = damageDiceIndex ? Object.keys(CONFIG.DH.GENERAL.diceTypes)[damageDiceIndex.value] : null; - const damageBonus = effect.system.changes.find(x => x.key === 'system.rules.attack.damage.bonus')?.value ?? 0; + const damageBonus = effect.changes.find(x => x.key === 'system.rules.attack.damage.bonus')?.value ?? 0; return { - trait: game.i18n.localize(CONFIG.DH.ACTOR.abilities[mainTrait]?.label), + trait: game.i18n.localize(CONFIG.DH.ACTOR.abilities[this.mainTrait].label), traitBonus: traitBonus ? Number(traitBonus).signedString() : '', evasionBonus: evasionBonus ? Number(evasionBonus).signedString() : '', damageDice: damageDice, @@ -175,17 +169,17 @@ export default class DHBeastform extends BaseDataItem { const beastformEffect = this.parent.effects.find(x => x.type === 'beastform'); await beastformEffect.updateSource({ + changes: [ + ...beastformEffect.changes, + { + key: 'system.advantageSources', + mode: 2, + value: Object.values(this.advantageOn) + .map(x => x.value) + .join(', ') + } + ], system: { - changes: [ - ...beastformEffect.system.changes, - { - key: 'system.advantageSources', - mode: 2, - value: Object.values(this.advantageOn) - .map(x => x.value) - .join(', ') - } - ], characterTokenData: { usesDynamicToken: this.parent.parent.prototypeToken.ring.enabled, tokenImg: this.parent.parent.prototypeToken.texture.src, @@ -193,8 +187,7 @@ export default class DHBeastform extends BaseDataItem { tokenSize: { scale: this.parent.parent.prototypeToken.texture.scaleX, height: this.parent.parent.prototypeToken.height, - width: this.parent.parent.prototypeToken.width, - depth: this.parent.parent.prototypeToken.depth + width: this.parent.parent.prototypeToken.width } }, advantageOn: this.advantageOn, @@ -208,17 +201,15 @@ export default class DHBeastform extends BaseDataItem { const autoTokenSize = this.tokenSize.size !== 'custom' ? game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).tokenSizes[ - this.tokenSize.size - ] + this.tokenSize.size + ] : null; const width = autoTokenSize ?? this.tokenSize.width; const height = autoTokenSize ?? this.tokenSize.height; - const depth = autoTokenSize ?? this.tokenSize.depth; const prototypeTokenUpdate = { height, width, - depth, texture: { src: this.tokenImg, scaleX: this.tokenSize.scale, diff --git a/module/data/item/class.mjs b/module/data/item/class.mjs index 470a1e3c..d3738318 100644 --- a/module/data/item/class.mjs +++ b/module/data/item/class.mjs @@ -2,7 +2,7 @@ import BaseDataItem from './base.mjs'; import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs'; import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs'; import ItemLinkFields from '../fields/itemLinkFields.mjs'; -import { addLinkedItemsDiff, fromUuids, getFeaturesHTMLData, updateLinkedItemApps } from '../../helpers/utils.mjs'; +import { addLinkedItemsDiff, getFeaturesHTMLData, updateLinkedItemApps } from '../../helpers/utils.mjs'; export default class DHClass extends BaseDataItem { /** @inheritDoc */ @@ -30,6 +30,7 @@ export default class DHClass extends BaseDataItem { }), evasion: new fields.NumberField({ initial: 0, integer: true, label: 'DAGGERHEART.GENERAL.evasion' }), features: new ItemLinkFields(), + subclasses: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }), inventory: new fields.SchemaField({ take: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }), choiceA: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }), @@ -69,25 +70,6 @@ export default class DHClass extends BaseDataItem { return this.features.filter(x => x.type === CONFIG.DH.ITEM.featureSubTypes.class).map(x => x.item); } - async fetchSubclasses() { - const uuids = [this.parent.uuid, this.parent._stats?.compendiumSource].filter(u => !!u); - const subclasses = game.items.filter(x => x.type === 'subclass' && uuids.includes(x.system.linkedClass)); - for (const pack of game.packs) { - const packIds = []; - const indexes = await pack.getIndex({ fields: ['system.linkedClass'] }); - for (const index of indexes) { - if (index.type !== 'subclass') continue; - if (!uuids.includes(index.system?.linkedClass)) continue; - if (subclasses.find(x => x.uuid === index.uuid)) continue; - packIds.push(index._id); - } - - if (packIds.length > 0) subclasses.push(...(await pack.getDocuments({ _id__in: packIds }))); - } - - return subclasses; - } - async _preCreate(data, options, user) { if (this.actor?.type === 'character') { const levelupAuto = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).levelupAuto; @@ -217,10 +199,6 @@ export default class DHClass extends BaseDataItem { classItems.push(contentLink.outerHTML); } - // Preload all class features for acquisition from the cache - // todo: make feature acquisition async and replace feature helpers for methods - await fromUuids(this._source.features.map(f => f.item)); - const hopeFeatures = await getFeaturesHTMLData(this.hopeFeatures); const classFeatures = await getFeaturesHTMLData(this.classFeatures); diff --git a/module/data/item/community.mjs b/module/data/item/community.mjs index 6f4470b8..6d054976 100644 --- a/module/data/item/community.mjs +++ b/module/data/item/community.mjs @@ -1,4 +1,4 @@ -import { fromUuids, getFeaturesHTMLData } from '../../helpers/utils.mjs'; +import { getFeaturesHTMLData } from '../../helpers/utils.mjs'; import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs'; import BaseDataItem from './base.mjs'; @@ -27,10 +27,6 @@ export default class DHCommunity extends BaseDataItem { /**@inheritdoc */ async getDescriptionData() { - // Preload all community features for acquisition from the cache - // todo: make feature acquisition async and replace feature helpers for methods - await fromUuids(this._source.features); - const baseDescription = this.description; const features = await getFeaturesHTMLData(this.features); diff --git a/module/data/item/consumable.mjs b/module/data/item/consumable.mjs index e83a1a53..ab527967 100644 --- a/module/data/item/consumable.mjs +++ b/module/data/item/consumable.mjs @@ -7,6 +7,7 @@ export default class DHConsumable extends BaseDataItem { label: 'TYPES.Item.consumable', type: 'consumable', hasDescription: true, + isQuantifiable: true, isInventoryItem: true, hasActions: true }); diff --git a/module/data/item/loot.mjs b/module/data/item/loot.mjs index d4092934..cdb0855e 100644 --- a/module/data/item/loot.mjs +++ b/module/data/item/loot.mjs @@ -7,6 +7,7 @@ export default class DHLoot extends BaseDataItem { label: 'TYPES.Item.loot', type: 'loot', hasDescription: true, + isQuantifiable: true, isInventoryItem: true, hasActions: true }); diff --git a/module/data/item/subclass.mjs b/module/data/item/subclass.mjs index 934b55d3..06a80f7b 100644 --- a/module/data/item/subclass.mjs +++ b/module/data/item/subclass.mjs @@ -1,4 +1,5 @@ -import { fromUuids, getFeaturesHTMLData } from '../../helpers/utils.mjs'; +import { getFeaturesHTMLData } from '../../helpers/utils.mjs'; +import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs'; import ItemLinkFields from '../fields/itemLinkFields.mjs'; import BaseDataItem from './base.mjs'; @@ -27,7 +28,7 @@ export default class DHSubclass extends BaseDataItem { features: new ItemLinkFields(), featureState: new fields.NumberField({ required: true, initial: 1, min: 1 }), isMulticlass: new fields.BooleanField({ initial: false }), - linkedClass: new fields.DocumentUUIDField({ type: 'Item', nullable: true, initial: null }) + linkedClass: new ForeignDocumentUUIDField({ type: 'Item', nullable: true, initial: null }) }; } @@ -51,36 +52,43 @@ export default class DHSubclass extends BaseDataItem { } async _preCreate(data, options, user) { - const allowed = await super._preCreate(data, options, user); - if (allowed === false) return; - if (this.actor?.type === 'character') { - const { value: actorClass, subclass: existingSubclass } = this.actor.system.class; - const { value: multiclass, subclass: existingMultisubclass } = this.actor.system.multiclass; - if (!actorClass && !multiclass) { - ui.notifications.warn('DAGGERHEART.UI.Notifications.missingClass', { localize: true }); - return false; - } - if (existingSubclass && existingMultisubclass) { - ui.notifications.warn('DAGGERHEART.UI.Notifications.subclassesAlreadyPresent', { localize: true }); - return false; - } - if (existingSubclass && !multiclass) { - ui.notifications.warn('DAGGERHEART.UI.Notifications.missingMulticlass', { localize: true }); - return false; - } + const dataUuid = data.uuid ?? data._stats.compendiumSource ?? `Item.${data._id}`; + if (this.actor.system.class.subclass) { + if (this.actor.system.multiclass.subclass) { + ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.subclassesAlreadyPresent')); + return false; + } else { + const multiclass = this.actor.items.find(x => x.type === 'class' && x.system.isMulticlass); + if (!multiclass) { + ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.missingMulticlass')); + return false; + } - const match = [multiclass, actorClass].find( - c => c && (c._stats.compendiumSource ?? c.uuid) === this.linkedClass - ); - if (!match) { - const key = multiclass ? 'subclassNotInMulticlass' : 'subclassNotInClass'; - ui.notifications.warn(`DAGGERHEART.UI.Notifications.${key}`, { localize: true }); - return false; - } else if (match.system.isMulticlass) { - await this.updateSource({ isMulticlass: true }); + if (multiclass.system.subclasses.every(x => x.uuid !== dataUuid)) { + ui.notifications.error( + game.i18n.localize('DAGGERHEART.UI.Notifications.subclassNotInMulticlass') + ); + return false; + } + + await this.updateSource({ isMulticlass: true }); + } + } else { + const actorClass = this.actor.items.find(x => x.type === 'class' && !x.system.isMulticlass); + if (!actorClass) { + ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.missingClass')); + return false; + } + if (actorClass.system.subclasses.every(x => x.uuid !== dataUuid)) { + ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.subclassNotInClass')); + return false; + } } } + + const allowed = await super._preCreate(data, options, user); + if (allowed === false) return; } /**@inheritdoc */ @@ -90,11 +98,6 @@ export default class DHSubclass extends BaseDataItem { const spellcastTrait = this.spellcastingTrait ? game.i18n.localize(CONFIG.DH.ACTOR.abilities[this.spellcastingTrait].label) : null; - - // Preload all subclass features for acquisition from the cache - // todo: make feature acquisition async and replace feature helpers for methods - await fromUuids(this._source.features.map(f => f.item)); - const foundationFeatures = await getFeaturesHTMLData(this.foundationFeatures); const specializationFeatures = await getFeaturesHTMLData(this.specializationFeatures); const masteryFeatures = await getFeaturesHTMLData(this.masteryFeatures); diff --git a/module/data/item/weapon.mjs b/module/data/item/weapon.mjs index 84e4de7f..04d1db7a 100644 --- a/module/data/item/weapon.mjs +++ b/module/data/item/weapon.mjs @@ -28,10 +28,7 @@ export default class DHWeapon extends AttachableItem { equipped: new fields.BooleanField({ initial: false }), //SETTINGS - secondary: new fields.BooleanField({ - initial: false, - label: 'DAGGERHEART.ITEMS.Weapon.secondaryWeapon.full' - }), + secondary: new fields.BooleanField({ initial: false, label: 'DAGGERHEART.ITEMS.Weapon.secondaryWeapon.full' }), burden: new fields.StringField({ required: true, choices: CONFIG.DH.GENERAL.burden, @@ -66,15 +63,15 @@ export default class DHWeapon extends AttachableItem { type: 'attack' }, damage: { - parts: { - hitPoints: { + parts: [ + { type: ['physical'], value: { multiplier: 'prof', dice: 'd8' } } - } + ] } } }), @@ -102,9 +99,7 @@ export default class DHWeapon extends AttachableItem { /* -------------------------------------------- */ get actionsList() { - // No actions on non-characters - if (this.actor && this.actor.type !== 'character') return []; - return [this.attack, ...super.actionsList]; + return [this.attack, ...this.actions]; } get customActions() { @@ -153,7 +148,7 @@ export default class DHWeapon extends AttachableItem { await this.parent.deleteEmbeddedDocuments('ActiveEffect', removedEffectsUpdate); changes.system.actions = removedActionsUpdate.reduce((acc, id) => { - acc[id] = _del; + acc[`-=${id}`] = null; return acc; }, {}); diff --git a/module/data/levelup.mjs b/module/data/levelup.mjs index e30bf52d..4dc1c058 100644 --- a/module/data/levelup.mjs +++ b/module/data/levelup.mjs @@ -19,12 +19,12 @@ export class DhLevelup extends foundry.abstract.DataModel { const initialAchievements = i === tier.levels.start ? tier.initialAchievements : {}; const experiences = initialAchievements.experience ? [...Array(initialAchievements.experience.nr).keys()].reduce((acc, _) => { - acc[foundry.utils.randomID()] = { - name: '', - modifier: initialAchievements.experience.modifier - }; - return acc; - }, {}) + acc[foundry.utils.randomID()] = { + name: '', + modifier: initialAchievements.experience.modifier + }; + return acc; + }, {}) : {}; const domainCards = [...Array(tier.domainCardByLevel).keys()].reduce((acc, _) => { @@ -298,9 +298,9 @@ export class DhLevelupLevel extends foundry.abstract.DataModel { experiences: levelData.achievements?.experiences ?? achievements.experiences ?? {}, domainCards: levelData.achievements?.domainCards ? levelData.achievements.domainCards.reduce((acc, card, index) => { - acc[index] = { ...card }; - return acc; - }, {}) + acc[index] = { ...card }; + return acc; + }, {}) : (achievements.domainCards ?? {}), proficiency: levelData.achievements?.proficiency ?? achievements.proficiency ?? null }, diff --git a/module/data/regionBehavior/_module.mjs b/module/data/regionBehavior/_module.mjs deleted file mode 100644 index d0c8172d..00000000 --- a/module/data/regionBehavior/_module.mjs +++ /dev/null @@ -1 +0,0 @@ -export { default as applyActiveEffect } from './applyActiveEffect.mjs'; diff --git a/module/data/regionBehavior/applyActiveEffect.mjs b/module/data/regionBehavior/applyActiveEffect.mjs deleted file mode 100644 index 51406cfa..00000000 --- a/module/data/regionBehavior/applyActiveEffect.mjs +++ /dev/null @@ -1,40 +0,0 @@ -export default class DhApplyActiveEffect extends CONFIG.RegionBehavior.dataModels.applyActiveEffect { - static async #getApplicableEffects(token) { - const effects = await Promise.all(this.effects.map(foundry.utils.fromUuid)); - return effects.filter( - effect => !effect.system.targetDispositions.size || effect.system.targetDispositions.has(token.disposition) - ); - } - - static async #onTokenEnter(event) { - if (!event.user.isSelf) return; - const { token, movement } = event.data; - const actor = token.actor; - if (!actor) return; - const resumeMovement = movement ? token.pauseMovement() : undefined; - const effects = await DhApplyActiveEffect.#getApplicableEffects.bind(this)(event.data.token); - const toCreate = []; - for (const effect of effects) { - const data = effect.toObject(); - delete data._id; - if (effect.compendium) { - data._stats.duplicateSource = null; - data._stats.compendiumSource = effect.uuid; - } else { - data._stats.duplicateSource = effect.uuid; - data._stats.compendiumSource = null; - } - data._stats.exportSource = null; - data.origin = this.parent.uuid; - toCreate.push(data); - } - if (toCreate.length) await actor.createEmbeddedDocuments('ActiveEffect', toCreate); - await resumeMovement?.(); - } - - /** @override */ - static events = { - ...CONFIG.RegionBehavior.dataModels.applyActiveEffect.events, - [CONST.REGION_EVENTS.TOKEN_ENTER]: this.#onTokenEnter - }; -} diff --git a/module/data/scene/scene.mjs b/module/data/scene/scene.mjs index 50416573..f2a24308 100644 --- a/module/data/scene/scene.mjs +++ b/module/data/scene/scene.mjs @@ -19,7 +19,7 @@ export default class DHScene extends foundry.abstract.DataModel { close: new fields.NumberField({ integer: true, label: 'DAGGERHEART.CONFIG.Range.close.name' }), far: new fields.NumberField({ integer: true, label: 'DAGGERHEART.CONFIG.Range.far.name' }) }), - sceneEnvironments: new ForeignDocumentUUIDArrayField({ type: 'Actor' }) + sceneEnvironments: new ForeignDocumentUUIDArrayField({ type: 'Actor', prune: true }) }; } } diff --git a/module/data/settings/Appearance.mjs b/module/data/settings/Appearance.mjs index 4db27be0..9da3afac 100644 --- a/module/data/settings/Appearance.mjs +++ b/module/data/settings/Appearance.mjs @@ -8,9 +8,6 @@ export default class DhAppearance extends foundry.abstract.DataModel { initial: null, blank: true, choices: CONFIG.DH.GENERAL.diceSoNiceSFXClasses - }), - options: new foundry.data.fields.SchemaField({ - muteSound: new foundry.data.fields.BooleanField() }) }); diff --git a/module/data/settings/Automation.mjs b/module/data/settings/Automation.mjs index 35e87327..20fe0baf 100644 --- a/module/data/settings/Automation.mjs +++ b/module/data/settings/Automation.mjs @@ -196,11 +196,6 @@ export default class DhAutomation extends foundry.abstract.DataModel { }) }) }), - autoExpireActiveEffects: new fields.BooleanField({ - required: true, - initial: true, - label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.autoExpireActiveEffects.label' - }), triggers: new fields.SchemaField({ enabled: new fields.BooleanField({ nullable: false, diff --git a/module/data/settings/Homebrew.mjs b/module/data/settings/Homebrew.mjs index 31247458..d4b7b03f 100644 --- a/module/data/settings/Homebrew.mjs +++ b/module/data/settings/Homebrew.mjs @@ -1,5 +1,4 @@ import { defaultRestOptions } from '../../config/generalConfig.mjs'; -import { resetAndRerenderActors } from '../../helpers/utils.mjs'; import { ActionsField } from '../fields/actionField.mjs'; const currencyField = (initial, label, icon) => @@ -55,7 +54,7 @@ export default class DhHomebrew extends foundry.abstract.DataModel { maxDomains: new fields.NumberField({ required: true, integer: true, - min: 0, + min: 1, initial: 2, label: 'DAGGERHEART.SETTINGS.Homebrew.FIELDS.maxDomains.label' }), @@ -197,12 +196,6 @@ export default class DhHomebrew extends foundry.abstract.DataModel { return source; } - _initialize(options) { - super._initialize(options); - this.maxDomains ||= Infinity; - this.maxLoadout ||= Infinity; - } - /** Invoked by the setting when data changes */ handleChange() { if (this.maxFear) { @@ -210,7 +203,7 @@ export default class DhHomebrew extends foundry.abstract.DataModel { } this.refreshConfig(); - resetAndRerenderActors(); + this.#resetActors(); } /** Update config values based on homebrew data. Make sure the references don't change */ @@ -231,6 +224,29 @@ export default class DhHomebrew extends foundry.abstract.DataModel { }); } } + + /** + * Triggers a reset and non-forced re-render on all given actors (if given) + * or all world actors and actors in all scenes to show immediate results for a changed setting. + */ + #resetActors() { + const actors = new Set( + [ + game.actors.contents, + game.scenes.contents.flatMap(s => s.tokens.contents).flatMap(t => t.actor ?? []) + ].flat() + ); + for (const actor of actors) { + for (const app of Object.values(actor.apps)) { + for (const element of app.element?.querySelectorAll('prose-mirror.active')) { + element.open = false; // This triggers a save + } + } + + actor.reset(); + actor.render(); + } + } } export class Resource extends foundry.abstract.DataModel { diff --git a/module/data/settings/Metagaming.mjs b/module/data/settings/Metagaming.mjs index 3694e09e..2bb5afdf 100644 --- a/module/data/settings/Metagaming.mjs +++ b/module/data/settings/Metagaming.mjs @@ -1,5 +1,3 @@ -import { resetAndRerenderActors } from '../../helpers/utils.mjs'; - export default class DhMetagaming extends foundry.abstract.DataModel { static defineSchema() { const fields = foundry.data.fields; @@ -8,24 +6,7 @@ export default class DhMetagaming extends foundry.abstract.DataModel { initial: false, label: 'DAGGERHEART.SETTINGS.Metagaming.FIELDS.hideObserverPermissionInChat.label', hint: 'DAGGERHEART.SETTINGS.Metagaming.FIELDS.hideObserverPermissionInChat.hint' - }), - hidePartyStats: new fields.StringField({ - initial: 'never', - label: 'DAGGERHEART.SETTINGS.Metagaming.FIELDS.hidePartyStats.label', - hint: 'DAGGERHEART.SETTINGS.Metagaming.FIELDS.hidePartyStats.hint', - required: true, - nullable: false, - choices: { - never: 'DAGGERHEART.SETTINGS.Metagaming.FIELDS.hidePartyStats.choices.never', - players: 'DAGGERHEART.SETTINGS.Metagaming.FIELDS.hidePartyStats.choices.players', - always: 'DAGGERHEART.SETTINGS.Metagaming.FIELDS.hidePartyStats.choices.always' - } }) }; } - - /** Invoked by the setting when data changes */ - handleChange() { - resetAndRerenderActors(); - } } diff --git a/module/data/spotlightTracker.mjs b/module/data/spotlightTracker.mjs deleted file mode 100644 index 57f54e16..00000000 --- a/module/data/spotlightTracker.mjs +++ /dev/null @@ -1,9 +0,0 @@ -export default class SpotlightTracker extends foundry.abstract.DataModel { - static defineSchema() { - const fields = foundry.data.fields; - - return { - spotlightedTokens: new fields.SetField(new fields.DocumentUUIDField()) - }; - } -} diff --git a/module/data/tagTeamData.mjs b/module/data/tagTeamData.mjs deleted file mode 100644 index 640c2f6c..00000000 --- a/module/data/tagTeamData.mjs +++ /dev/null @@ -1,47 +0,0 @@ -export default class TagTeamData extends foundry.abstract.DataModel { - static defineSchema() { - const fields = foundry.data.fields; - - return { - initiator: new fields.SchemaField( - { - memberId: new fields.StringField({ - required: true, - label: 'DAGGERHEART.APPLICATIONS.TagTeamSelect.FIELDS.initiator.memberId.label' - }), - cost: new fields.NumberField({ - integer: true, - initial: 3, - label: 'DAGGERHEART.APPLICATIONS.TagTeamSelect.FIELDS.initiator.cost.label' - }) - }, - { nullable: true, initial: null } - ), - members: new fields.TypedObjectField(new fields.EmbeddedDataField(MemberData)) - }; - } -} - -export class MemberData extends foundry.abstract.DataModel { - static defineSchema() { - const fields = foundry.data.fields; - - return { - name: new fields.StringField({ required: true }), - img: new fields.StringField({ required: true }), - rollType: new fields.StringField({ - required: true, - choices: CONFIG.DH.GENERAL.tagTeamRollTypes, - initial: CONFIG.DH.GENERAL.tagTeamRollTypes.trait.id, - label: game.i18n.localize('DAGGERHEART.APPLICATIONS.TagTeamSelect.rollType') - }), - rollChoice: new fields.StringField({ nullable: true, initial: null }), - rollData: new fields.JSONField({ nullable: true, initial: null }), - selected: new fields.BooleanField({ initial: false }) - }; - } - - get roll() { - return this.rollData ? CONFIG.Dice.daggerheart.DualityRoll.fromData(this.rollData) : null; - } -} diff --git a/module/data/tagTeamRoll.mjs b/module/data/tagTeamRoll.mjs new file mode 100644 index 00000000..de71a11b --- /dev/null +++ b/module/data/tagTeamRoll.mjs @@ -0,0 +1,20 @@ +import { DhCharacter } from './actor/_module.mjs'; + +export default class DhTagTeamRoll extends foundry.abstract.DataModel { + static defineSchema() { + const fields = foundry.data.fields; + + return { + initiator: new fields.SchemaField({ + id: new fields.StringField({ nullable: true, initial: null }), + cost: new fields.NumberField({ integer: true, min: 0, initial: 3 }) + }), + members: new fields.TypedObjectField( + new fields.SchemaField({ + messageId: new fields.StringField({ required: true, nullable: true, initial: null }), + selected: new fields.BooleanField({ required: true, initial: false }) + }) + ) + }; + } +} diff --git a/module/dice/_module.mjs b/module/dice/_module.mjs index e1206f82..b9339d87 100644 --- a/module/dice/_module.mjs +++ b/module/dice/_module.mjs @@ -4,4 +4,3 @@ export { default as DamageRoll } from './damageRoll.mjs'; export { default as DHRoll } from './dhRoll.mjs'; export { default as DualityRoll } from './dualityRoll.mjs'; export { default as FateRoll } from './fateRoll.mjs'; -export { diceTypes } from './die/_module.mjs'; diff --git a/module/dice/d20Roll.mjs b/module/dice/d20Roll.mjs index b1d3bd0b..f117ff65 100644 --- a/module/dice/d20Roll.mjs +++ b/module/dice/d20Roll.mjs @@ -1,5 +1,4 @@ import D20RollDialog from '../applications/dialogs/d20RollDialog.mjs'; -import { triggerChatRollFx } from '../helpers/utils.mjs'; import DHRoll from './dhRoll.mjs'; export default class D20Roll extends DHRoll { @@ -37,7 +36,7 @@ export default class D20Roll extends DHRoll { get isCritical() { if (!this.d20._evaluated) return; - const criticalThreshold = this.options.actionType === 'reaction' ? 20 : this.data.criticalThreshold; + const criticalThreshold = this.options.actionType === 'reaction' ? 20 : this.data.system.criticalThreshold; return this.d20.total >= criticalThreshold; } @@ -208,7 +207,7 @@ export default class D20Roll extends DHRoll { rerolls: dice.results.filter(x => x.rerolled) } })); - data.isCritical = roll.isCritical; + data.isCritical = config.isCritical = roll.isCritical; data.extra = roll.dice .filter(d => !roll.baseTerms.includes(d)) .map(d => { @@ -218,7 +217,7 @@ export default class D20Roll extends DHRoll { results: d.results }; }); - data.modifierTotal = roll.modifierTotal; + data.modifierTotal = this.calculateTotalModifiers(roll); return data; } @@ -226,14 +225,41 @@ export default class D20Roll extends DHRoll { return (this._formula = this.constructor.getFormula(this.terms)); } - async reroll(options) { - const result = await super.reroll(options); - if (this instanceof game.system.api.dice.DualityRoll) return result; + static async reroll(rollString, _target, message) { + let parsedRoll = game.system.api.dice.D20Roll.fromData(rollString); + parsedRoll = await parsedRoll.reroll(); + const newRoll = game.system.api.dice.D20Roll.postEvaluate(parsedRoll, { + targets: message.system.targets, + roll: { + advantage: message.system.roll.advantage?.type, + difficulty: message.system.roll.difficulty ? Number(message.system.roll.difficulty) : null + } + }); - if (options?.liveRoll) { - await triggerChatRollFx([result]); + if (game.modules.get('dice-so-nice')?.active) { + await game.dice3d.showForRoll(parsedRoll, game.user, true); } - return result; + const rerolled = { + any: true, + rerolls: [ + ...(message.system.roll.dice[0].rerolled?.rerolls?.length > 0 + ? [message.system.roll.dice[0].rerolled?.rerolls] + : []), + rollString.terms[0].results + ] + }; + return { + newRoll: { + ...newRoll, + dice: [ + { + ...newRoll.dice[0], + rerolled: rerolled + } + ] + }, + parsedRoll + }; } } diff --git a/module/dice/damageRoll.mjs b/module/dice/damageRoll.mjs index ef810ed7..ef5f9434 100644 --- a/module/dice/damageRoll.mjs +++ b/module/dice/damageRoll.mjs @@ -1,5 +1,6 @@ import DamageDialog from '../applications/dialogs/damageDialog.mjs'; -import { parseRallyDice, triggerChatRollFx } from '../helpers/utils.mjs'; +import { parseRallyDice } from '../helpers/utils.mjs'; +import { RefreshType, socketEvent } from '../systemRegistration/socket.mjs'; import DHRoll from './dhRoll.mjs'; export default class DamageRoll extends DHRoll { @@ -7,10 +8,6 @@ export default class DamageRoll extends DHRoll { super(formula, data, options); } - get isCritical() { - return !!this.options.isCritical; - } - static DefaultDialog = DamageDialog; static async buildEvaluate(roll, config = {}, message = {}) { @@ -18,12 +15,7 @@ export default class DamageRoll extends DHRoll { if (config.evaluate !== false) for (const roll of config.roll) await roll.roll.evaluate(); roll._evaluated = true; - - const parts = []; - for (const roll of config.roll) { - parts.push(this.postEvaluate(roll)); - roll.roll = JSON.stringify(roll.roll.toJSON()); - } + const parts = config.roll.map(r => this.postEvaluate(r)); config.damage = this.unifyDamageRoll(parts); } @@ -42,25 +34,26 @@ export default class DamageRoll extends DHRoll { static async buildPost(roll, config, message) { const chatMessage = config.source?.message ? ui.chat.collection.get(config.source.message) - : getDocumentClass('ChatMessage').applyMode({}, config.rollMode ?? 'public'); - - const diceRolls = []; + : getDocumentClass('ChatMessage').applyRollMode({}, config.rollMode ?? CONST.DICE_ROLL_MODES.PUBLIC); if (game.modules.get('dice-so-nice')?.active) { - config.mute = true; const pool = foundry.dice.terms.PoolTerm.fromRolls( - 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]); + await game.dice3d.showForRoll( + diceRoll, + game.user, + true, + chatMessage.whisper?.length > 0 ? chatMessage.whisper : null, + chatMessage.blind ); - diceRolls.push(Roll.fromTerms([pool])); + config.mute = true; } - - await triggerChatRollFx(diceRolls, { - whisper: chatMessage.whisper?.length > 0 ? chatMessage.whisper : null, - blind: chatMessage.blind - }); await super.buildPost(roll, config, message); - if (config.source?.message) { chatMessage.update({ 'system.damage': config.damage }); + + if (!game.modules.get('dice-so-nice')?.active) foundry.audio.AudioHelper.play({ src: CONFIG.sounds.dice }); } } @@ -146,63 +139,57 @@ export default class DamageRoll extends DHRoll { } constructFormula(config) { - this.options.isCritical = config.isCritical; - for (const [index, part] of this.options.roll.entries()) { - const isHitpointPart = part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id; + this.options.roll.forEach((part, index) => { part.roll = new Roll(Roll.replaceFormulaData(part.formula, config.data)); - part.roll.terms = Roll.parse(part.roll.formula, config.data); - if (part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) { - part.modifiers = this.applyBaseBonus(part); - this.addModifiers(part); - part.modifiers?.forEach(m => { - part.roll.terms.push(...this.formatModifier(m.value)); - }); - } - - /* To Remove When Reaction System */ - if (index === 0 && part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) { - for (const mod in config.modifiers) { - const modifier = config.modifiers[mod]; - if (modifier.beforeCrit === true && (modifier.enabled || modifier.value)) modifier.callback(part); - } - } - - if (part.extraFormula) { - part.roll.terms.push( - new foundry.dice.terms.OperatorTerm({ operator: '+' }), - ...this.constructor.parse(part.extraFormula, this.options.data) - ); - } - - if (config.damageOptions.groupAttack?.numAttackers > 1 && isHitpointPart) { - const damageTypes = [foundry.dice.terms.Die, foundry.dice.terms.NumericTerm]; - for (const term of part.roll.terms) { - if (damageTypes.some(type => term instanceof type)) { - term.number *= config.damageOptions.groupAttack.numAttackers; - } - } - } - - if (config.isCritical && isHitpointPart) { - const total = part.roll.dice.reduce((acc, term) => acc + term._faces * term._number, 0); - if (total > 0) { - part.roll.terms.push(...this.formatModifier(total)); - } - } - - /* To Remove When Reaction System */ - if (index === 0 && part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) { - for (const mod in config.modifiers) { - const modifier = config.modifiers[mod]; - if (!modifier.beforeCrit && (modifier.enabled || modifier.value)) modifier.callback(part); - } - } - - part.roll._formula = this.constructor.getFormula(part.roll.terms); - } + this.constructFormulaPart(config, part, index); + }); return this.options.roll; } + constructFormulaPart(config, part, index) { + part.roll.terms = Roll.parse(part.roll.formula, config.data); + + if (part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) { + part.modifiers = this.applyBaseBonus(part); + this.addModifiers(part); + part.modifiers?.forEach(m => { + part.roll.terms.push(...this.formatModifier(m.value)); + }); + } + + /* To Remove When Reaction System */ + if (index === 0 && part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) { + for (const mod in config.modifiers) { + const modifier = config.modifiers[mod]; + if (modifier.beforeCrit === true && (modifier.enabled || modifier.value)) modifier.callback(part); + } + } + + if (part.extraFormula) { + part.roll.terms.push( + new foundry.dice.terms.OperatorTerm({ operator: '+' }), + ...this.constructor.parse(part.extraFormula, this.options.data) + ); + } + + if (config.isCritical && part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) { + const total = part.roll.dice.reduce((acc, term) => acc + term._faces * term._number, 0); + if (total > 0) { + part.roll.terms.push(...this.formatModifier(total)); + } + } + + /* To Remove When Reaction System */ + if (index === 0 && part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) { + for (const mod in config.modifiers) { + const modifier = config.modifiers[mod]; + if (!modifier.beforeCrit && (modifier.enabled || modifier.value)) modifier.callback(part); + } + } + + return (part.roll._formula = this.constructor.getFormula(part.roll.terms)); + } + /* To Remove When Reaction System */ static temporaryModifierBuilder(config) { const mods = {}; @@ -210,7 +197,7 @@ export default class DamageRoll extends DHRoll { if (config.data.parent.appliedEffects) { // Bardic Rally const rallyChoices = config.data?.parent?.appliedEffects.reduce((a, c) => { - const change = c.system.changes.find(ch => ch.key === 'system.bonuses.rally'); + const change = c.changes.find(ch => ch.key === 'system.bonuses.rally'); if (change) a.push({ value: c.id, label: parseRallyDice(change.value, c) }); return a; }, []); @@ -294,7 +281,10 @@ export default class DamageRoll extends DHRoll { return mods; } - static async reroll(rollPart, dice, result) { + static async reroll(target, message) { + const { damageType, part, dice, result } = target.dataset; + const rollPart = message.system.damage[damageType].parts[part]; + let diceIndex = 0; let parsedRoll = game.system.api.dice.DamageRoll.fromData({ ...rollPart.roll, @@ -323,10 +313,9 @@ export default class DamageRoll extends DHRoll { const newIndex = parsedDiceTerms[dice].results.length; await term.reroll(`/r1=${termResult.result}`); - const diceRolls = []; if (game.modules.get('dice-so-nice')?.active) { const newResult = parsedDiceTerms[dice].results[newIndex]; - diceRolls.push({ + const diceSoNiceRoll = { _evaluated: true, dice: [ new foundry.dice.terms.Die({ @@ -337,10 +326,11 @@ export default class DamageRoll extends DHRoll { }) ], options: { appearance: {} } - }); + }; + + await game.dice3d.showForRoll(diceSoNiceRoll, game.user, true); } - await triggerChatRollFx(diceRolls); await parsedRoll.evaluate(); const results = parsedRoll.dice[dice].results.map(result => ({ @@ -363,6 +353,29 @@ export default class DamageRoll extends DHRoll { }; }); - return { parsedRoll, rerolledDice }; + const updateMessage = game.messages.get(message._id); + const damageParts = updateMessage.system.damage[damageType].parts.map((damagePart, index) => { + if (index !== Number(part)) return damagePart; + return { + ...rollPart, + total: parsedRoll.total, + dice: rerolledDice + }; + }); + await updateMessage.update({ + [`system.damage.${damageType}`]: { + ...updateMessage, + total: parsedRoll.total, + parts: damageParts + } + }); + + Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.TagTeamRoll }); + await game.socket.emit(`system.${CONFIG.DH.id}`, { + action: socketEvent.Refresh, + data: { + refreshType: RefreshType.TagTeamRoll + } + }); } } diff --git a/module/dice/dhRoll.mjs b/module/dice/dhRoll.mjs index c28db98f..c216e740 100644 --- a/module/dice/dhRoll.mjs +++ b/module/dice/dhRoll.mjs @@ -1,5 +1,4 @@ import D20RollDialog from '../applications/dialogs/d20RollDialog.mjs'; -import { triggerChatRollFx } from '../helpers/utils.mjs'; export default class DHRoll extends Roll { baseTerms = []; @@ -13,10 +12,6 @@ export default class DHRoll extends Roll { return game.i18n.localize('DAGGERHEART.GENERAL.Roll.basic'); } - get modifierTotal() { - return this.constructor.calculateTotalModifiers(this); - } - static messageType = 'adversaryRoll'; static CHAT_TEMPLATE = 'systems/daggerheart/templates/ui/chat/roll.hbs'; @@ -26,9 +21,6 @@ export default class DHRoll extends Roll { static async build(config = {}, message = {}) { const roll = await this.buildConfigure(config, message); if (!roll) return; - - if (config.skips?.createMessage) config.messageRoll = roll; - await this.buildEvaluate(roll, config, (message = {})); await this.buildPost(roll, config, (message = {})); return config; @@ -37,7 +29,12 @@ export default class DHRoll extends Roll { static async buildConfigure(config = {}, message = {}) { config.hooks = [...this.getHooks(), '']; config.dialog ??= {}; - config.damageOptions ??= {}; + + const actorIdSplit = config.source?.actor?.split('.'); + if (actorIdSplit) { + const tagTeamSettings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll); + config.tagTeamSelected = Boolean(tagTeamSettings.members[actorIdSplit[actorIdSplit.length - 1]]); + } for (const hook of config.hooks) { if (Hooks.call(`${CONFIG.DH.id}.preRoll${hook.capitalize()}`, config, message) === false) return null; @@ -77,7 +74,9 @@ export default class DHRoll extends Roll { } if (config.skips?.createMessage) { - await triggerChatRollFx([roll]); + if (game.modules.get('dice-so-nice')?.active) { + await game.dice3d.showForRoll(roll, game.user, true); + } } else if (!config.source?.message) { config.message = await this.toMessage(roll, config); } @@ -85,7 +84,6 @@ export default class DHRoll extends Roll { static postEvaluate(roll, config = {}) { return { - ...roll.options.roll, total: roll.total, formula: roll.formula, dice: roll.dice.map(d => ({ @@ -104,9 +102,9 @@ export default class DHRoll extends Roll { if (action?.chatDisplay) { actionDescription = action ? await foundry.applications.ux.TextEditor.implementation.enrichHTML(action.description, { - relativeTo: config.data, - rollData: config.data.getRollData?.() ?? {} - }) + relativeTo: config.data, + rollData: config.data.getRollData?.() ?? {} + }) : null; config.actionChatMessageHandled = true; } @@ -122,10 +120,14 @@ export default class DHRoll extends Roll { rolls: [roll] }; - config.selectedMessageMode ??= game.settings.get('core', 'messageMode'); + config.selectedRollMode ??= game.settings.get('core', 'rollMode'); if (roll._evaluated) { - const message = await cls.create(msgData, { messageMode: config.selectedMessageMode }); + const message = await cls.create(msgData, { rollMode: config.selectedRollMode }); + + if (config.tagTeamSelected) { + game.system.api.applications.dialogs.TagTeamDialog.assignRoll(message.speakerActor, message); + } if (roll.formula !== '' && game.modules.get('dice-so-nice')?.active) { await game.dice3d.waitFor3DAnimationByMessageID(message.id); @@ -142,11 +144,9 @@ export default class DHRoll extends Roll { const metagamingSettings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Metagaming); const chatData = await this._prepareChatRenderContext({ flavor, isPrivate, ...options }); return foundry.applications.handlebars.renderTemplate(template, { - roll: this, ...chatData, parent: chatData.parent, targetMode: chatData.targetMode, - areas: chatData.action?.areas, metagamingSettings }); } @@ -248,21 +248,16 @@ export default class DHRoll extends Roll { return (this._formula = this.constructor.getFormula(this.terms)); } - /** - * Calculate total modifiers of any rolls, including non-dh rolls. - * This exists because damage rolls still may receive base roll classes - */ static calculateTotalModifiers(roll) { let modifierTotal = 0; for (let i = 0; i < roll.terms.length; i++) { - if (!roll.terms[i].isDeterministic) continue; - const termTotal = roll.terms[i].total; - if (typeof termTotal === 'number') { - const multiplier = roll.terms[i - 1]?.operator === '-' ? -1 : 1; - modifierTotal += multiplier * termTotal; - } + if ( + roll.terms[i] instanceof foundry.dice.terms.NumericTerm && + !!roll.terms[i - 1] && + roll.terms[i - 1] instanceof foundry.dice.terms.OperatorTerm + ) + modifierTotal += Number(`${roll.terms[i - 1].operator}${roll.terms[i].total}`); } - return modifierTotal; } @@ -274,12 +269,12 @@ export default class DHRoll extends Roll { const changeKeys = this.getActionChangeKeys(); return ( this.options.effects?.reduce((acc, effect) => { - if (effect.system.changes.some(x => changeKeys.some(key => x.key?.includes(key)))) { + if (effect.changes.some(x => changeKeys.some(key => x.key.includes(key)))) { acc[effect.id] = { id: effect.id, name: effect.name, description: effect.description, - changes: effect.system.changes, + changes: effect.changes, origEffect: effect, selected: !effect.disabled }; diff --git a/module/dice/die/_module.mjs b/module/dice/die/_module.mjs deleted file mode 100644 index 19ca951a..00000000 --- a/module/dice/die/_module.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import DualityDie from './dualityDie.mjs'; -import HopeDie from './hopeDie.mjs'; -import FearDie from './fearDie.mjs'; -import AdvantageDie from './advantageDie.mjs'; -import DisadvantageDie from './disadvantageDie.mjs'; - -export const diceTypes = { - DualityDie, - HopeDie, - FearDie, - AdvantageDie, - DisadvantageDie -}; diff --git a/module/dice/die/advantageDie.mjs b/module/dice/die/advantageDie.mjs deleted file mode 100644 index 9c2f0b03..00000000 --- a/module/dice/die/advantageDie.mjs +++ /dev/null @@ -1,7 +0,0 @@ -export default class AdvantageDie extends foundry.dice.terms.Die { - constructor(options) { - super(options); - - this.modifiers = []; - } -} diff --git a/module/dice/die/disadvantageDie.mjs b/module/dice/die/disadvantageDie.mjs deleted file mode 100644 index f56ebe96..00000000 --- a/module/dice/die/disadvantageDie.mjs +++ /dev/null @@ -1,7 +0,0 @@ -export default class DisadvantageDie extends foundry.dice.terms.Die { - constructor(options) { - super(options); - - this.modifiers = []; - } -} diff --git a/module/dice/die/dualityDie.mjs b/module/dice/die/dualityDie.mjs deleted file mode 100644 index cc7ee75e..00000000 --- a/module/dice/die/dualityDie.mjs +++ /dev/null @@ -1,52 +0,0 @@ -import { updateResourcesForDualityReroll } from '../helpers.mjs'; - -export default class DualityDie extends foundry.dice.terms.Die { - constructor(options) { - super(options); - - this.modifiers = []; - } - - #getDualityState(roll) { - if (!roll) return null; - return roll.withHope ? 1 : roll.withFear ? -1 : 0; - } - - async reroll(modifier, options) { - const oldDuality = this.#getDualityState(options.liveRoll.roll); - await super.reroll(modifier, options); - - if (options?.liveRoll) { - /* Can't currently test since DiceSoNice is not v14. Might need to set the appearance earlier if a roll is triggered by super.reroll */ - if (game.modules.get('dice-so-nice')?.active) { - const diceSoNiceRoll = { - _evaluated: true, - dice: [this], - options: { appearance: {} } - }; - - const diceAppearance = await this.getDiceSoNiceAppearance(options.liveRoll.roll); - diceSoNiceRoll.dice[0].options.appearance = diceAppearance.appearance; - diceSoNiceRoll.dice[0].options.modelFile = diceAppearance.modelFile; - diceSoNiceRoll.dice[0].results = diceSoNiceRoll.dice[0].results.filter(x => x.active); - - await game.dice3d.showForRoll(diceSoNiceRoll, game.user, true); - } else { - foundry.audio.AudioHelper.play({ src: CONFIG.sounds.dice }); - } - - await options.liveRoll.roll._evaluate(); - if (options.liveRoll.isReaction) return; - - const newDuality = this.#getDualityState(options.liveRoll.roll); - updateResourcesForDualityReroll(oldDuality, newDuality, options.liveRoll.actor); - } - } - - /** - * Overridden by extending classes HopeDie and FearDie - */ - async getDiceSoNiceAppearance() { - return {}; - } -} diff --git a/module/dice/die/fearDie.mjs b/module/dice/die/fearDie.mjs deleted file mode 100644 index 2a09d432..00000000 --- a/module/dice/die/fearDie.mjs +++ /dev/null @@ -1,9 +0,0 @@ -import { getDiceSoNicePresets } from '../../config/generalConfig.mjs'; -import DualityDie from './dualityDie.mjs'; - -export default class FearDie extends DualityDie { - async getDiceSoNiceAppearance(roll) { - const { fear } = await getDiceSoNicePresets(roll, this.denomination, this.denomination); - return fear; - } -} diff --git a/module/dice/die/hopeDie.mjs b/module/dice/die/hopeDie.mjs deleted file mode 100644 index af5a4425..00000000 --- a/module/dice/die/hopeDie.mjs +++ /dev/null @@ -1,9 +0,0 @@ -import { getDiceSoNicePresets } from '../../config/generalConfig.mjs'; -import DualityDie from './dualityDie.mjs'; - -export default class HopeDie extends DualityDie { - async getDiceSoNiceAppearance(roll) { - const { hope } = await getDiceSoNicePresets(roll, this.denomination, this.denomination); - return hope; - } -} diff --git a/module/dice/dualityRoll.mjs b/module/dice/dualityRoll.mjs index 1cfed094..75fbdf55 100644 --- a/module/dice/dualityRoll.mjs +++ b/module/dice/dualityRoll.mjs @@ -2,9 +2,10 @@ import D20RollDialog from '../applications/dialogs/d20RollDialog.mjs'; import D20Roll from './d20Roll.mjs'; import { parseRallyDice, setDiceSoNiceForDualityRoll } from '../helpers/utils.mjs'; import { getDiceSoNicePresets } from '../config/generalConfig.mjs'; -import { updateResourcesForDualityReroll } from './helpers.mjs'; +import { ResourceUpdateMap } from '../data/action/baseAction.mjs'; export default class DualityRoll extends D20Roll { + _advantageFaces = 6; _advantageNumber = 1; _rallyIndex; @@ -12,11 +13,6 @@ export default class DualityRoll extends D20Roll { super(formula, data, options); this.rallyChoices = this.setRallyChoices(); this.guaranteedCritical = options.guaranteedCritical; - - const advantageFaces = data.rules?.roll?.defaultAdvantageDice - ? Number.parseInt(data.rules.roll.defaultAdvantageDice) - : 6; - this.advantageFaces = Number.isNaN(advantageFaces) ? 6 : advantageFaces; } static messageType = 'dualityRoll'; @@ -30,31 +26,35 @@ export default class DualityRoll extends D20Roll { } get dHope() { - if (!(this.dice[0] instanceof game.system.api.dice.diceTypes.HopeDie)) this.createBaseDice(); + if (!(this.dice[0] instanceof foundry.dice.terms.Die)) this.createBaseDice(); return this.dice[0]; } set dHope(faces) { - // TODO this should not be asymmetrical with the getter. updateRollConfiguration() should use dHope.faces - this.dHope.faces = this.getFaces(faces); + if (!(this.dice[0] instanceof foundry.dice.terms.Die)) this.createBaseDice(); + this.dice[0].faces = this.getFaces(faces); } get dFear() { - if (!(this.dice[1] instanceof game.system.api.dice.diceTypes.FearDie)) this.createBaseDice(); + if (!(this.dice[1] instanceof foundry.dice.terms.Die)) this.createBaseDice(); return this.dice[1]; } set dFear(faces) { - // TODO this should not be asymmetrical with the getter. updateRollConfiguration() should use dFear.faces - this.dFear.faces = this.getFaces(faces); + if (!(this.dice[1] instanceof foundry.dice.terms.Die)) this.createBaseDice(); + this.dice[1].faces = this.getFaces(faces); } get dAdvantage() { - return this.dice[2] instanceof game.system.api.dice.diceTypes.AdvantageDie ? this.dice[2] : null; + return this.dice[2]; } - get dDisadvantage() { - return this.dice[2] instanceof game.system.api.dice.diceTypes.DisadvantageDie ? this.dice[2] : null; + get advantageFaces() { + return this._advantageFaces; + } + + set advantageFaces(faces) { + this._advantageFaces = this.getFaces(faces); } get advantageNumber() { @@ -65,14 +65,9 @@ export default class DualityRoll extends D20Roll { this._advantageNumber = Number(value); } - get extraDice() { - const { HopeDie, FearDie, AdvantageDie, DisadvantageDie } = game.system.api.dice.diceTypes; - return this.dice.filter(x => ![HopeDie, FearDie, AdvantageDie, DisadvantageDie].some(die => x instanceof die)); - } - setRallyChoices() { return this.data?.parent?.appliedEffects.reduce((a, c) => { - const change = c.system.changes.find(ch => ch.key === 'system.bonuses.rally'); + const change = c.changes.find(ch => ch.key === 'system.bonuses.rally'); if (change) a.push({ value: c.id, label: parseRallyDice(change.value, c) }); return a; }, []); @@ -109,10 +104,10 @@ export default class DualityRoll extends D20Roll { const label = this.guaranteedCritical ? 'DAGGERHEART.GENERAL.guaranteedCriticalSuccess' : this.isCritical - ? 'DAGGERHEART.GENERAL.criticalSuccess' - : this.withHope - ? 'DAGGERHEART.GENERAL.hope' - : 'DAGGERHEART.GENERAL.fear'; + ? 'DAGGERHEART.GENERAL.criticalSuccess' + : this.withHope + ? 'DAGGERHEART.GENERAL.hope' + : 'DAGGERHEART.GENERAL.fear'; return game.i18n.localize(label); } @@ -123,43 +118,35 @@ export default class DualityRoll extends D20Roll { /** @inheritDoc */ static fromData(data) { - data.terms[0].class = 'HopeDie'; - data.terms[2].class = 'FearDie'; - if (data.options.roll.advantage?.type && data.terms[4]?.faces) { - data.terms[4].class = data.options.roll.advantage.type === 1 ? 'AdvantageDie' : 'DisadvantageDie'; - } + data.terms[0].class = foundry.dice.terms.Die.name; + data.terms[2].class = foundry.dice.terms.Die.name; return super.fromData(data); } createBaseDice() { - this.terms = [this.terms[0], this.terms[1], this.terms[2]]; + if (this.dice[0] instanceof foundry.dice.terms.Die && this.dice[1] instanceof foundry.dice.terms.Die) { + this.terms = [this.terms[0], this.terms[1], this.terms[2]]; + return; + } - this.terms[0] = new game.system.api.dice.diceTypes.HopeDie({ - faces: this.terms[0]?.faces ?? this.data.rules.dualityRoll?.defaultHopeDice ?? 12 + this.terms[0] = new foundry.dice.terms.Die({ + faces: this.data.rules.dualityRoll?.defaultHopeDice ?? 12 }); this.terms[1] = new foundry.dice.terms.OperatorTerm({ operator: '+' }); - this.terms[2] = new game.system.api.dice.diceTypes.FearDie({ - faces: this.terms[2]?.faces ?? this.data.rules.dualityRoll?.defaultFearDice ?? 12 + this.terms[2] = new foundry.dice.terms.Die({ + faces: this.data.rules.dualityRoll?.defaultFearDice ?? 12 }); } applyAdvantage() { - const advDieClass = this.hasAdvantage - ? game.system.api.dice.diceTypes.AdvantageDie - : this.hasDisadvantage - ? game.system.api.dice.diceTypes.DisadvantageDie - : null; - if (advDieClass) { - const advDie = new advDieClass({ faces: this.advantageFaces, number: this.advantageNumber }); - if (this.terms.length < 4) { - if (this.advantageNumber > 1) advDie.modifiers = ['kh']; - this.terms.push( - new foundry.dice.terms.OperatorTerm({ operator: this.hasDisadvantage ? '-' : '+' }), - advDie - ); - } else { - this.terms[4] = advDie; - } + if (this.hasAdvantage || this.hasDisadvantage) { + const dieFaces = this.advantageFaces, + advDie = new foundry.dice.terms.Die({ faces: dieFaces, number: this.advantageNumber }); + if (this.advantageNumber > 1) advDie.modifiers = ['kh']; + this.terms.push( + new foundry.dice.terms.OperatorTerm({ operator: this.hasDisadvantage ? '-' : '+' }), + advDie + ); } if (this.rallyFaces) this.terms.push( @@ -192,7 +179,7 @@ export default class DualityRoll extends D20Roll { static async buildConfigure(config = {}, message = {}) { config.dialog ??= {}; config.guaranteedCritical = config.data?.parent?.appliedEffects.reduce((a, c) => { - const change = c.system.changes.find(ch => ch.key === 'system.rules.roll.guaranteedCritical'); + const change = c.changes.find(ch => ch.key === 'system.rules.roll.guaranteedCritical'); if (change) a = true; return a; }, false); @@ -318,6 +305,7 @@ export default class DualityRoll extends D20Roll { !config.source?.actor || (game.user.isGM ? !hopeFearAutomation.gm : !hopeFearAutomation.players) || config.actionType === 'reaction' || + config.tagTeamSelected || config.skips?.resources ) return; @@ -358,6 +346,7 @@ export default class DualityRoll extends D20Roll { if ( automationSettings.countdownAutomation && config.actionType !== 'reaction' && + !config.tagTeamSelected && !config.skips?.updateCountdowns ) { const { updateCountdowns } = game.system.api.applications.ui.DhCountdowns; @@ -385,39 +374,60 @@ export default class DualityRoll extends D20Roll { } } - async reroll(options) { - const oldDuality = this.withHope ? 1 : this.withFear ? -1 : 0; - const rerolled = DualityRoll.fromData((await super.reroll(options)).toJSON()); + static async reroll(rollString, target, message) { + let parsedRoll = game.system.api.dice.DualityRoll.fromData({ ...rollString, evaluated: false }); + const term = parsedRoll.terms[target.dataset.dieIndex]; + await term.reroll(`/r1=${term.total}`); + const result = await parsedRoll.evaluate(); - if (options?.liveRoll) { - if (game.modules.get('dice-so-nice')?.active) { - const diceAppearance = await getDiceSoNicePresets( - rerolled, - rerolled.dHope.denomination, - rerolled.dFear.denomination - ); - rerolled.dHope.options.appearance = diceAppearance.hope.appearance; - rerolled.dFear.options.appearance = diceAppearance.fear.appearance; - if (rerolled.dAdvantage) rerolled.dAdvantage.options.appearance = diceAppearance.advantage.appearance; - if (rerolled.dDisadvantage) - rerolled.dDisadvantage.options.appearance = diceAppearance.disadvantage.appearance; + if (game.modules.get('dice-so-nice')?.active) { + const diceSoNiceRoll = { + _evaluated: true, + dice: [ + new foundry.dice.terms.Die({ + ...term, + faces: term._faces, + results: term.results.filter(x => !x.rerolled) + }) + ], + options: { appearance: {} } + }; - await game.dice3d.showForRoll(rerolled, game.user, true); - } else { - foundry.audio.AudioHelper.play({ src: CONFIG.sounds.dice }); + const diceSoNicePresets = await getDiceSoNicePresets(result, `d${term._faces}`, `d${term._faces}`); + const type = target.dataset.type; + if (diceSoNicePresets[type]) { + diceSoNiceRoll.dice[0].options = diceSoNicePresets[type]; } - if (this.options.actionType === 'reaction') return; - - const newDuality = rerolled.withHope ? 1 : rerolled.withFear ? -1 : 0; - const actor = await foundry.utils.fromUuid(this.options.source.actor); - updateResourcesForDualityReroll(oldDuality, newDuality, actor); + await game.dice3d.showForRoll(diceSoNiceRoll, game.user, true); } - return rerolled; - } + const newRoll = game.system.api.dice.DualityRoll.postEvaluate(parsedRoll, { + targets: message.system.targets, + roll: { + advantage: message.system.roll.advantage?.type, + difficulty: message.system.roll.difficulty ? Number(message.system.roll.difficulty) : null + } + }); - fromJSON(json) { - return super.fromJSON(json); + const extraIndex = newRoll.advantage ? 3 : 2; + newRoll.extra = newRoll.extra.slice(extraIndex); + + const tagTeamSettings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll); + + const actor = message.system.source.actor ? await foundry.utils.fromUuid(message.system.source.actor) : null; + const config = { + source: { actor: message.system.source.actor ?? '' }, + targets: message.system.targets, + tagTeamSelected: Object.values(tagTeamSettings.members).some(x => x.messageId === message._id), + roll: newRoll, + rerolledRoll: message.system.roll, + resourceUpdates: new ResourceUpdateMap(actor) + }; + + await DualityRoll.addDualityResourceUpdates(config); + await config.resourceUpdates.updateResources(); + + return { newRoll, parsedRoll }; } } diff --git a/module/dice/fateRoll.mjs b/module/dice/fateRoll.mjs index 114fad59..418c8465 100644 --- a/module/dice/fateRoll.mjs +++ b/module/dice/fateRoll.mjs @@ -21,8 +21,8 @@ export default class FateRoll extends D20Roll { } set dHope(faces) { - // TODO this should not be asymmetrical with the getter. updateRollConfiguration() should use dHope.faces - this.dHope.faces = this.getFaces(faces); + if (!(this.dice[0] instanceof foundry.dice.terms.Die)) this.createBaseDice(); + this.dice[0].faces = this.getFaces(faces); } get dFear() { @@ -31,8 +31,8 @@ export default class FateRoll extends D20Roll { } set dFear(faces) { - // TODO this should not be asymmetrical with the getter. updateRollConfiguration() should use dFear.faces - this.dFear.faces = this.getFaces(faces); + if (!(this.dice[0] instanceof foundry.dice.terms.Die)) this.createBaseDice(); + this.dice[0].faces = this.getFaces(faces); } get isCritical() { @@ -43,20 +43,6 @@ export default class FateRoll extends D20Roll { return this.data.fateType; } - get withHope() { - return this.data.fateType === 'Hope'; - } - - get withFear() { - return this.data.fateType === 'Fear'; - } - - get totalLabel() { - const label = this.withHope ? 'DAGGERHEART.GENERAL.hope' : 'DAGGERHEART.GENERAL.fear'; - - return game.i18n.localize(label); - } - static getHooks(hooks) { return [...(hooks ?? []), 'Fate']; } diff --git a/module/dice/helpers.mjs b/module/dice/helpers.mjs deleted file mode 100644 index 35adb8b7..00000000 --- a/module/dice/helpers.mjs +++ /dev/null @@ -1,19 +0,0 @@ -import { ResourceUpdateMap } from '../data/action/baseAction.mjs'; - -export function updateResourcesForDualityReroll(oldDuality, newDuality, actor) { - const { hopeFear } = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation); - if (game.user.isGM ? !hopeFear.gm : !hopeFear.players) return; - - const updates = []; - const hope = (newDuality >= 0 ? 1 : 0) - (oldDuality >= 0 ? 1 : 0); - const stress = (newDuality === 0 ? 1 : 0) - (oldDuality === 0 ? 1 : 0); - const fear = (newDuality === -1 ? 1 : 0) - (oldDuality === -1 ? 1 : 0); - - if (hope !== 0) updates.push({ key: 'hope', value: hope, total: -1 * hope, enabled: true }); - if (stress !== 0) updates.push({ key: 'stress', value: -1 * stress, total: stress, enabled: true }); - if (fear !== 0) updates.push({ key: 'fear', value: fear, total: -1 * fear, enabled: true }); - - const resourceUpdates = new ResourceUpdateMap(actor); - resourceUpdates.addResources(updates); - resourceUpdates.updateResources(); -} diff --git a/module/documents/_module.mjs b/module/documents/_module.mjs index aa08f0f4..b9cfd3f2 100644 --- a/module/documents/_module.mjs +++ b/module/documents/_module.mjs @@ -8,4 +8,5 @@ export { default as DhRollTable } from './rollTable.mjs'; export { default as DhScene } from './scene.mjs'; export { default as DhToken } from './token.mjs'; export { default as DhTooltipManager } from './tooltipManager.mjs'; +export { default as DhTemplateManager } from './templateManager.mjs'; export { default as DhTokenManager } from './tokenManager.mjs'; diff --git a/module/documents/activeEffect.mjs b/module/documents/activeEffect.mjs index 3518210b..dd5f1b55 100644 --- a/module/documents/activeEffect.mjs +++ b/module/documents/activeEffect.mjs @@ -1,4 +1,5 @@ import { itemAbleRollParse } from '../helpers/utils.mjs'; +import { RefreshType, socketEvent } from '../systemRegistration/socket.mjs'; export default class DhActiveEffect extends foundry.documents.ActiveEffect { /* -------------------------------------------- */ @@ -7,8 +8,6 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect { /**@override */ get isSuppressed() { - if (this.system.isSuppressed === true) return true; - // If this is a copied effect from an attachment, never suppress it // (These effects have attachmentSource metadata) if (this.flags?.daggerheart?.attachmentSource) { @@ -16,7 +15,7 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect { } // Then apply the standard suppression rules - if (['weapon', 'armor'].includes(this.parent?.type) && this.transfer) { + if (['weapon', 'armor'].includes(this.parent?.type)) { return !this.parent.system.equipped; } @@ -51,55 +50,10 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect { }); } - /** - * Whether this Active Effect is eligible to be registered with the {@link ActiveEffectRegistry} - */ - get isExpiryTrackable() { - return ( - this.persisted && - !this.inCompendium && - this.modifiesActor && - this.start && - this.isTemporary && - !this.isExpired - ); - } - /* -------------------------------------------- */ /* Event Handlers */ /* -------------------------------------------- */ - /** @inheritdoc */ - static async createDialog(data = {}, createOptions = {}, options = {}) { - const { folders, types, template, context = {}, ...dialogOptions } = options; - - if (types?.length === 0) { - throw new Error('The array of sub-types to restrict to must not be empty.'); - } - - const creatableEffects = types || ['base']; - const documentTypes = this.TYPES.filter(type => creatableEffects.includes(type)).map(type => { - const labelKey = `TYPES.ActiveEffect.${type}`; - const label = game.i18n.has(labelKey) ? game.i18n.localize(labelKey) : type; - - return { value: type, label }; - }); - - if (!documentTypes.length) { - throw new Error('No document types were permitted to be created.'); - } - - const sortedTypes = documentTypes.sort((a, b) => a.label.localeCompare(b.label, game.i18n.lang)); - - return await super.createDialog(data, createOptions, { - folders, - types, - template, - context: { types: sortedTypes, ...context }, - ...dialogOptions - }); - } - /**@inheritdoc*/ async _preCreate(data, options, user) { const update = {}; @@ -107,41 +61,25 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect { update.img = 'icons/magic/life/heart-cross-blue.webp'; } - if (this.actor && data.origin) { - const existingEffect = this.actor.effects.find(x => x.origin === data.origin); - const stacks = Boolean(data.system?.stacking); - if (existingEffect && !stacks) return false; - - if (existingEffect && stacks) { - const incrementedValue = existingEffect.system.stacking.value + 1; - await existingEffect.update({ - 'system.stacking.value': Math.min(incrementedValue, existingEffect.system.stacking.max ?? Infinity) - }); - return false; - } - } - - if (this.parent) { - const statuses = Object.keys(data.statuses ?? {}); - const immuneStatuses = - statuses.filter( - status => - this.parent.system.rules?.conditionImmunities && - this.parent.system.rules.conditionImmunities[status] - ) ?? []; - if (immuneStatuses.length > 0) { - update.statuses = statuses.filter(x => !immuneStatuses.includes(x)); - const conditions = CONFIG.DH.GENERAL.conditions(); - const scrollingTexts = immuneStatuses.map(status => ({ - text: game.i18n.format('DAGGERHEART.ACTIVEEFFECT.immuneStatusText', { - status: game.i18n.localize(conditions[status].name) - }) - })); - if (update.statuses.length > 0) { - setTimeout(() => scrollingTexts, 500); - } else { - this.parent.queueScrollText(scrollingTexts); - } + const statuses = Object.keys(data.statuses ?? {}); + const immuneStatuses = + statuses.filter( + status => + this.parent.system.rules?.conditionImmunities && + this.parent.system.rules.conditionImmunities[status] + ) ?? []; + if (immuneStatuses.length > 0) { + update.statuses = statuses.filter(x => !immuneStatuses.includes(x)); + const conditions = CONFIG.DH.GENERAL.conditions(); + const scrollingTexts = immuneStatuses.map(status => ({ + text: game.i18n.format('DAGGERHEART.ACTIVEEFFECT.immuneStatusText', { + status: game.i18n.localize(conditions[status].name) + }) + })); + if (update.statuses.length > 0) { + setTimeout(() => scrollingTexts, 500); + } else { + this.parent.queueScrollText(scrollingTexts); } } @@ -152,53 +90,53 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect { await super._preCreate(data, options, user); } + /** @inheritdoc */ + _onCreate(data, options, userId) { + super._onCreate(data, options, userId); + + Hooks.callAll(RefreshType.EffectsDisplay); + } + + /** @inheritdoc */ + _onDelete(data, options, userId) { + super._onDelete(data, options, userId); + + Hooks.callAll(RefreshType.EffectsDisplay); + } + /* -------------------------------------------- */ /* Methods */ /* -------------------------------------------- */ /**@inheritdoc*/ - static applyChangeField(model, change, field) { - change.value = Number.isNumeric(change.value) - ? change.value - : DhActiveEffect.getChangeValue(model, change, change.effect); - super.applyChangeField(model, change, field); + static applyField(model, change, field) { + change.value = DhActiveEffect.getChangeValue(model, change, change.effect); + super.applyField(model, change, field); } - static _applyChangeUnguided(actor, change, changes, options) { + _applyLegacy(actor, change, changes) { change.value = DhActiveEffect.getChangeValue(actor, change, change.effect); - super._applyChangeUnguided(actor, change, changes, options); - } - - /** Recursively finds the first parent document of the given object */ - static #resolveParentDocument(model, documentClass) { - if (!model) return null; - return model instanceof documentClass - ? model - : model.parent - ? this.#resolveParentDocument(model.parent, documentClass) - : null; + super._applyLegacy(actor, change, changes); } + /** */ static getChangeValue(model, change, effect) { - let value = change.value.toString(); - const useOrigin = value.toLowerCase().includes('origin.@') && effect.origin; - let origin = null; - if (effect.origin) { - if (useOrigin) value = value.replaceAll(/origin\.@/gi, '@'); - const originEffect = foundry.utils.fromUuidSync(effect.origin); - origin = this.#resolveParentDocument(originEffect, Item); + let value = change.value; + const isOriginTarget = value.toLowerCase().includes('origin.@'); + let parseModel = model; + if (isOriginTarget && effect.origin) { + value = change.value.replaceAll(/origin\.@/gi, '@'); + try { + const originEffect = foundry.utils.fromUuidSync(effect.origin); + const doc = + originEffect.parent?.parent instanceof game.system.api.documents.DhpActor + ? originEffect.parent + : originEffect.parent.parent; + if (doc) parseModel = doc; + } catch (_) {} } - // Get the actor and item documents. Note that actor roll data is inclusive of system roll data - const actor = this.#resolveParentDocument(model, Actor); - const item = - (useOrigin ? origin : null) ?? - this.#resolveParentDocument(effect.parent, Item) ?? - (origin?.actor === actor ? origin : null); - const stackingParsedValue = effect.system.stacking - ? Roll.replaceFormulaData(value, { stacks: effect.system.stacking.value }) - : value; - const evalValue = this.effectSafeEval(itemAbleRollParse(stackingParsedValue, actor, item)); + const evalValue = this.effectSafeEval(itemAbleRollParse(value, parseModel, effect.parent)); return evalValue ?? value; } @@ -210,6 +148,7 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect { static effectSafeEval(expression) { let result; try { + // eslint-disable-next-line no-new-func const evl = new Function('sandbox', `with (sandbox) { return ${expression}}`); result = evl(Roll.MATH_PROXY); } catch (err) { diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index fb10435f..eea2e212 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -1,10 +1,9 @@ -import { emitGMUpdate, GMUpdateEvent } from '../systemRegistration/socket.mjs'; +import { emitAsGM, GMUpdateEvent } from '../systemRegistration/socket.mjs'; import { LevelOptionType } from '../data/levelTier.mjs'; import DHFeature from '../data/item/feature.mjs'; -import { createScrollText, damageKeyToNumber, getDamageKey, createShallowProxy } from '../helpers/utils.mjs'; +import { createScrollText, damageKeyToNumber, getDamageKey } from '../helpers/utils.mjs'; import DhCompanionLevelUp from '../applications/levelup/companionLevelup.mjs'; import { ResourceUpdateMap } from '../data/action/baseAction.mjs'; -import { abilities } from '../config/actorConfig.mjs'; export default class DhpActor extends Actor { parties = new Set(); @@ -35,7 +34,7 @@ export default class DhpActor extends Actor { // Update effects if it is the user's character or is controlled if (canvas.ready) { - const controlled = canvas.tokens.controlled.some(t => t.actor === this); + const controlled = canvas.tokens.controlled.some((t) => t.actor === this); if (game.user.character === this || controlled) { ui.effectsDisplay.render(); } @@ -65,11 +64,6 @@ export default class DhpActor extends Actor { }; } - static createDialog(data, createOptions, options, renderOptions) { - options.classes = [options.classes ?? [], 'actor-create'].flat(); // handled in hook - return super.createDialog(data, createOptions, options, renderOptions); - } - /* -------------------------------------------- */ /** @inheritDoc */ @@ -104,7 +98,7 @@ export default class DhpActor extends Actor { } // Configure prototype token settings - if (['character', 'companion', 'party'].includes(this.type)) { + if (['character', 'companion', 'party'].includes(this.type)) Object.assign(update, { prototypeToken: { sight: { enabled: true }, @@ -112,41 +106,17 @@ export default class DhpActor extends Actor { disposition: CONST.TOKEN_DISPOSITIONS.FRIENDLY } }); - } - - if (this.type === 'npc') { - Object.assign(update, { - prototypeToken: { - disposition: CONST.TOKEN_DISPOSITIONS.FRIENDLY - } - }); - } - this.updateSource(update); } - /** Perform a render, debounced in order to prevent overloading repeat render requests */ - renderDebounced = foundry.utils.debounce(options => { - return this.render(options); - }, 10); - - _onUpdateDescendantDocuments(parent, collection, documents, changes, options, userId) { - super._onUpdateDescendantDocuments(parent, collection, documents, changes, options, userId); - for (const party of this.parties) { - party.renderDebounced({ parts: ['partyMembers'] }); - } - } - _onUpdate(changes, options, userId) { super._onUpdate(changes, options, userId); for (const party of this.parties) { - party.renderDebounced({ parts: ['partyMembers'] }); + party.render(); } } - async _preDelete(options, user) { - if ((await super._preDelete(options, user)) === false) return false; - + async _preDelete() { if (this.prototypeToken.actorLink) { game.system.registeredTriggers.unregisterItemTriggers(this.items); } else { @@ -159,20 +129,17 @@ export default class DhpActor extends Actor { _onDelete(options, userId) { super._onDelete(options, userId); for (const party of this.parties) { - party.renderDebounced({ parts: ['partyMembers'] }); + party.render(); } } async updateLevel(newLevel) { if (!['character', 'companion'].includes(this.type) || newLevel === this.system.levelData.level.changed) return; - const tiers = Object.values(game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers).tiers); - const maxLevel = tiers.reduce((acc, tier) => Math.max(acc, tier.levels.end), 0); - const multiclassMinLevel = Math.min( - maxLevel, - ...tiers.filter(t => t.options.multiclass).map(t => t.levels.start) - ); if (newLevel > this.system.levelData.level.current) { + const maxLevel = Object.values( + game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers).tiers + ).reduce((acc, tier) => Math.max(acc, tier.levels.end), 0); if (newLevel > maxLevel) { ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.tooHighLevel')); } @@ -187,7 +154,7 @@ export default class DhpActor extends Actor { } const updatedLevelups = Object.keys(this.system.levelData.levelups).reduce((acc, level) => { - if (Number(level) > usedLevel) acc[level] = _del; + if (Number(level) > usedLevel) acc[`-=${level}`] = null; return acc; }, {}); @@ -232,7 +199,7 @@ export default class DhpActor extends Actor { if (experiences.length > 0) { const getUpdate = () => ({ 'system.experiences': experiences.reduce((acc, key) => { - acc[key] = _del; + acc[`-=${key}`] = null; return acc; }, {}) }); @@ -247,19 +214,18 @@ export default class DhpActor extends Actor { this.system.multiclass.subclass.update({ 'system.featureState': subclassFeatureState.multiclass }); } - // Remove multiclass if we're removing a multiclass feature or if we're below the multiclass minimum level - // Multclasses cannot be manually removed on the sheet, so this allows recovering in the case of errors - if (multiclass || newLevel < multiclassMinLevel) { - const multiclassItems = this.items.filter( - x => - x.uuid === multiclass?.itemUuid || - x.system.isMulticlass || - (['class', 'subclass'].includes(x.system.originItemType) && x.system.multiclassOrigin) + if (multiclass) { + const multiclassItem = this.items.find(x => x.uuid === multiclass.itemUuid); + const multiclassFeatures = this.items.filter( + x => x.system.originItemType === 'class' && x.system.multiclassOrigin + ); + const subclassFeatures = this.items.filter( + x => x.system.originItemType === 'subclass' && x.system.multiclassOrigin ); this.deleteEmbeddedDocuments( 'Item', - multiclassItems.map(x => x.id) + [multiclassItem, ...multiclassFeatures, ...subclassFeatures].map(x => x.id) ); this.update({ @@ -298,7 +264,6 @@ export default class DhpActor extends Actor { async levelUp(levelupData) { const levelupAuto = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).levelupAuto; - const getStatsWithSource = document => ({ ...(document._stats ?? {}), compendiumSource: document.uuid }); const levelups = {}; for (var levelKey of Object.keys(levelupData)) { @@ -411,8 +376,8 @@ export default class DhpActor extends Actor { const embeddedItem = await this.createEmbeddedDocuments('Item', [ { ...multiclassData, - uuid: multiclassItem.uuid, // todo: replace with setting an id and using keepId - _stats: getStatsWithSource(multiclassItem), + uuid: multiclassItem.uuid, + _stats: multiclassItem._stats, system: { ...multiclassData.system, features: multiclassData.system.features.filter(x => x.type !== 'hope'), @@ -425,8 +390,8 @@ export default class DhpActor extends Actor { await this.createEmbeddedDocuments('Item', [ { ...subclassData, - uuid: subclassItem.uuid, // todo: replace with setting an id and using keepId - _stats: getStatsWithSource(subclassItem), + uuid: subclassItem.uuid, + _stats: subclassItem._stats, system: { ...subclassData.system, isMulticlass: true @@ -446,8 +411,8 @@ export default class DhpActor extends Actor { const embeddedItem = await this.createEmbeddedDocuments('Item', [ { ...cardData, - uuid: cardItem.uuid, // todo: replace with setting an id and using keepId - _stats: getStatsWithSource(cardItem), + uuid: cardItem.uuid, + _stats: cardItem._stats, system: { ...cardData.system, inVault: true @@ -468,7 +433,8 @@ export default class DhpActor extends Actor { const embeddedItem = await this.createEmbeddedDocuments('Item', [ { ...cardData, - _stats: getStatsWithSource(cardItem), + uuid: cardItem.uuid, + _stats: cardItem._stats, system: { ...cardData.system, inVault: true @@ -555,30 +521,6 @@ export default class DhpActor extends Actor { return await rollClass.build(config); } - async rollTrait(trait, options = {}) { - const abilityLabel = game.i18n.localize(abilities[trait].label); - const config = { - event: event, - title: `${game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll')}: ${this.name}`, - headerTitle: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', { - ability: abilityLabel - }), - effects: await game.system.api.data.actions.actionsTypes.base.getEffects(this), - roll: { - trait: trait, - type: 'trait' - }, - hasRoll: true, - actionType: 'action', - headerTitle: `${game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll')}: ${this.name}`, - title: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', { - ability: abilityLabel - }), - ...options - }; - return await this.diceRoll(config); - } - get rollClass() { return CONFIG.Dice.daggerheart[['character', 'companion'].includes(this.type) ? 'DualityRoll' : 'D20Roll']; } @@ -624,13 +566,15 @@ export default class DhpActor extends Actor { /**@inheritdoc */ getRollData() { - const rollData = createShallowProxy(super.getRollData()); + const rollData = foundry.utils.deepClone(super.getRollData()); + /* system gets repeated infinately which causes issues when trying to use the data for document creation */ + delete rollData.system; + rollData.id = this.id; rollData.name = this.name; rollData.system = this.system.getRollData(); rollData.prof = this.system.proficiency ?? 1; rollData.cast = this.system.spellcastModifier ?? 1; - return rollData; } @@ -641,7 +585,8 @@ export default class DhpActor extends Actor { const availableStress = this.system.resources.stress.max - this.system.resources.stress.value; const canUseArmor = - this.system.armorScore.value < this.system.armorScore.max && + this.system.armor && + this.system.armor.system.marks.value < this.system.armorScore && type.every(t => this.system.armorApplicableDamageTypes[t] === true); const canUseStress = Object.keys(stressDamageReduction).reduce((acc, x) => { const rule = stressDamageReduction[x]; @@ -681,7 +626,12 @@ export default class DhpActor extends Actor { const hpDamage = updates.find(u => u.key === CONFIG.DH.GENERAL.healingTypes.hitPoints.id); if (hpDamage?.value) { hpDamage.value = this.convertDamageToThreshold(hpDamage.value); - if (this.type === 'character' && !isDirect && this.#canReduceDamage(hpDamage.value, hpDamage.damageTypes)) { + if ( + this.type === 'character' && + !isDirect && + this.system.armor && + this.#canReduceDamage(hpDamage.value, hpDamage.damageTypes) + ) { const armorSlotResult = await this.owner.query( 'armorSlot', { @@ -694,10 +644,12 @@ export default class DhpActor extends Actor { } ); if (armorSlotResult) { - const { modifiedDamage, armorChanges, stressSpent } = armorSlotResult; + const { modifiedDamage, armorSpent, stressSpent } = armorSlotResult; updates.find(u => u.key === 'hitPoints').value = modifiedDamage; - for (const armorChange of armorChanges) { - updates.push({ value: armorChange.amount, key: 'armor', uuid: armorChange.uuid }); + if (armorSpent) { + const armorUpdate = updates.find(u => u.key === 'armor'); + if (armorUpdate) armorUpdate.value += armorSpent; + else updates.push({ value: armorSpent, key: 'armor' }); } if (stressSpent) { const stressUpdate = updates.find(u => u.key === 'stress'); @@ -834,8 +786,12 @@ export default class DhpActor extends Actor { ); break; case 'armor': - if (!r.uuid) this.system.updateArmorValue(r); - else this.system.updateArmorEffectValue(r); + if (this.system.armor?.system?.marks) { + updates.armor.resources['system.marks.value'] = Math.max( + Math.min(valueFunc(this.system.armor.system.marks, r), this.system.armorScore), + 0 + ); + } break; default: if (this.system.resources?.[r.key]) { @@ -856,7 +812,7 @@ export default class DhpActor extends Actor { const u = updates[key]; if (key === 'items') { Object.values(u).forEach(async item => { - await emitGMUpdate( + await emitAsGM( GMUpdateEvent.UpdateDocument, item.target.update.bind(item.target), item.resources, @@ -865,7 +821,7 @@ export default class DhpActor extends Actor { }); } else { if (Object.keys(u.resources).length > 0) { - await emitGMUpdate( + await emitAsGM( GMUpdateEvent.UpdateDocument, u.target.update.bind(u.target), u.resources, @@ -1051,20 +1007,4 @@ export default class DhpActor extends Actor { return allTokens; } - - /**@inheritdoc */ - *allApplicableEffects({ noSelfArmor, noTransferArmor } = {}) { - for (const effect of this.effects) { - if (!noSelfArmor || effect.type !== 'armor') yield effect; - } - for (const item of this.items) { - for (const effect of item.effects) { - if (effect.transfer && (!noTransferArmor || effect.type !== 'armor')) yield effect; - } - } - } - - applyActiveEffects(phase) { - super.applyActiveEffects(phase); - } } diff --git a/module/documents/chatMessage.mjs b/module/documents/chatMessage.mjs index 480f8c69..acc14439 100644 --- a/module/documents/chatMessage.mjs +++ b/module/documents/chatMessage.mjs @@ -1,4 +1,4 @@ -import { emitGMUpdate, emitGMCreate, GMUpdateEvent } from '../systemRegistration/socket.mjs'; +import { emitAsGM, GMUpdateEvent, RefreshType, socketEvent } from '../systemRegistration/socket.mjs'; export default class DhpChatMessage extends foundry.documents.ChatMessage { targetHook = null; @@ -9,9 +9,9 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage { actor && this.isContentVisible ? actor : { - img: this.author.avatar ? this.author.avatar : 'icons/svg/mystery-man.svg', - name: '' - }; + img: this.author.avatar ? this.author.avatar : 'icons/svg/mystery-man.svg', + name: '' + }; /* We can change to fully implementing the renderHTML function if needed, instead of augmenting it. */ const html = await super.renderHTML({ actor: actorData, author: this.author }); @@ -78,14 +78,25 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage { if (this.isContentVisible) { if (this.type === 'dualityRoll') { html.classList.add('duality'); - if (this.system.roll.withHope) html.classList.add('hope'); - else if (this.system.roll.withFear) html.classList.add('fear'); - else html.classList.add('critical'); + switch (this.system.roll?.result?.duality) { + case 1: + html.classList.add('hope'); + break; + case -1: + html.classList.add('fear'); + break; + default: + html.classList.add('critical'); + break; + } } if (this.type === 'fateRoll') { html.classList.add('fate'); - if (this.system.roll?.fateDie) { - html.classList.add(this.system.roll.fateDie.toLowerCase()); + if (this.system.roll?.fate.fateDie == 'Hope') { + html.classList.add('hope'); + } + if (this.system.roll?.fate.fateDie == 'Fear') { + html.classList.add('fear'); } } @@ -137,10 +148,6 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage { element.addEventListener('click', this.onApplyEffect.bind(this)) ); - for (const element of html.querySelectorAll('.action-areas')) { - element.addEventListener('click', this.onCreateAreas.bind(this)); - } - html.querySelectorAll('.roll-target').forEach(element => { element.addEventListener('mouseenter', this.hoverTarget); element.addEventListener('mouseleave', this.unhoverTarget); @@ -170,6 +177,14 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage { config.effects = await game.system.api.data.actions.actionsTypes.base.getEffects(actor, item); await this.system.action.workflow.get('damage')?.execute(config, this._id, true); } + + Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.TagTeamRoll }); + await game.socket.emit(`system.${CONFIG.DH.id}`, { + action: socketEvent.Refresh, + data: { + refreshType: RefreshType.TagTeamRoll + } + }); } async onApplyDamage(event) { @@ -183,11 +198,7 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage { if (pendingingSaves.length) { const confirm = await foundry.applications.api.DialogV2.confirm({ window: { title: game.i18n.localize('DAGGERHEART.APPLICATIONS.PendingReactionsDialog.title') }, - content: ` -

${game.i18n.localize('DAGGERHEART.APPLICATIONS.PendingReactionsDialog.unfinishedRolls')}

-

${game.i18n.localize('DAGGERHEART.APPLICATIONS.PendingReactionsDialog.warning')}

-

${game.i18n.localize('DAGGERHEART.APPLICATIONS.PendingReactionsDialog.confirmation')}

- ` + content: `

${game.i18n.localize('DAGGERHEART.APPLICATIONS.PendingReactionsDialog.unfinishedRolls')}

${game.i18n.localize('DAGGERHEART.APPLICATIONS.PendingReactionsDialog.confirmation')}

${game.i18n.localize('DAGGERHEART.APPLICATIONS.PendingReactionsDialog.warning')}

` }); if (!confirm) return; } @@ -218,7 +229,7 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage { const action = this.system.action; if (!action || !action?.hasSave) return; game.system.api.fields.ActionFields.SaveField.rollSave.call(action, token.actor, event).then(result => - emitGMUpdate( + emitAsGM( GMUpdateEvent.UpdateSaveMessage, game.system.api.fields.ActionFields.SaveField.updateSaveMessage.bind( action, @@ -251,96 +262,12 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage { const targets = this.filterPermTargets(this.system.hitTargets), config = foundry.utils.deepClone(this.system); config.event = event; - if (targets.length === 0) - return ui.notifications.info(game.i18n.localize('DAGGERHEART.UI.Notifications.noTargetsSelectedOrPerm')); - else if (config.hasSave) { - const pendingingSaves = targets.filter(t => t.saved.success === null); - if (pendingingSaves.length) { - const confirm = await foundry.applications.api.DialogV2.confirm({ - window: { title: game.i18n.localize('DAGGERHEART.APPLICATIONS.PendingReactionsDialog.title') }, - content: ` -

${game.i18n.localize('DAGGERHEART.APPLICATIONS.PendingReactionsDialog.unfinishedRolls')}

-

${game.i18n.localize('DAGGERHEART.APPLICATIONS.PendingReactionsDialog.warning')}

-

${game.i18n.localize('DAGGERHEART.APPLICATIONS.PendingReactionsDialog.confirmation')}

- ` - }); - if (!confirm) return; - } - } - + ui.notifications.info(game.i18n.localize('DAGGERHEART.UI.Notifications.noTargetsSelectedOrPerm')); this.consumeOnSuccess(); this.system.action?.workflow.get('effects')?.execute(config, targets, true); } - async onCreateAreas(event) { - const createArea = async selectedArea => { - const effects = selectedArea.effects.map(effect => this.system.action.item.effects.get(effect).uuid); - const { shape: type, size: range } = selectedArea; - const shapeData = CONFIG.Canvas.layers.regions.layerClass.getTemplateShape({ type, range }); - - const scene = game.scenes.get(game.user.viewedScene); - const level = scene.levels.find(x => x.isView); - - const regionData = { - name: selectedArea.name, - levels: level ? [level.id] : [], - shapes: [shapeData], - restriction: { enabled: false, type: 'move', priority: 0 }, - behaviors: - effects.length > 0 - ? [ - { - name: game.i18n.localize('TYPES.RegionBehavior.applyActiveEffect'), - type: 'applyActiveEffect', - system: { - effects: effects - } - } - ] - : [], - displayMeasurements: true, - locked: false, - ownership: { default: CONST.DOCUMENT_OWNERSHIP_LEVELS.NONE }, - visibility: CONST.REGION_VISIBILITY.ALWAYS - }; - const placeRegion = data => { - canvas.regions.placeRegion(data, { create: true }); - }; - - // Regions with effects must be placed by the GM - if (effects.length > 0 && !game.user.isGM) { - if (!game.users.activeGM) - return ui.notifications.error( - game.i18n.localize('DAGGERHEART.UI.Notifications.behaviorRegionRequiresGM') - ); - - const region = await canvas.regions.placeRegion(regionData, { create: false }); - emitGMCreate('Region', placeRegion, region, scene.id); - } else { - placeRegion(regionData); - } - }; - - if (this.system.action.areas.length === 1) createArea(this.system.action.areas[0]); - else if (this.system.action.areas.length > 1) { - new foundry.applications.ux.ContextMenu.implementation( - event.target, - '.action-areas', - this.system.action.areas.map(area => ({ - label: area.name, - onClick: () => createArea(area) - })), - { - jQuery: false, - fixed: true - } - ); - - CONFIG.ux.ContextMenu.triggerContextMenu(event, '.action-areas'); - } - } - filterPermTargets(targets) { return targets.filter(t => fromUuidSync(t.actorId)?.canUserModify(game.user, 'update')); } diff --git a/module/documents/collections/actorCollection.mjs b/module/documents/collections/actorCollection.mjs index 115dd694..a3714b30 100644 --- a/module/documents/collections/actorCollection.mjs +++ b/module/documents/collections/actorCollection.mjs @@ -1,11 +1,4 @@ export default class DhActorCollection extends foundry.documents.collections.Actors { - /** @returns the active party */ - get party() { - const id = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.ActiveParty); - const actor = game.actors.get(id); - return actor?.type === 'party' ? actor : null; - } - /** Ensure companions are initialized after all other subtypes. */ _initialize() { super._initialize(); diff --git a/module/documents/item.mjs b/module/documents/item.mjs index 4716068d..67f7d253 100644 --- a/module/documents/item.mjs +++ b/module/documents/item.mjs @@ -31,13 +31,8 @@ export default class DHItem extends foundry.documents.Item { static async createDocuments(sources, operation) { // Ensure that items being created are valid to the actor its being added to const actor = operation.parent; - const filtered = actor ? sources.filter(s => actor.system.isItemValid(s)) : sources; - if (actor && filtered.length === 0 && sources.length > 0) { - const itemType = _loc(`TYPES.Item.${sources[0].type}`); - const actorType = _loc(`TYPES.Actor.${actor.type}`); - ui.notifications.error('DAGGERHEART.ACTORS.Base.CannotAddType', { format: { itemType, actorType } }); - } - return super.createDocuments(filtered, operation); + sources = actor?.system?.isItemValid ? sources.filter(s => actor.system.isItemValid(s)) : sources; + return super.createDocuments(sources, operation); } /* -------------------------------------------- */ @@ -54,7 +49,13 @@ export default class DHItem extends foundry.documents.Item { * @returns */ getRollData(options = {}) { - let data = this.system.getRollData(options); + let data; + if (this.system.getRollData) data = this.system.getRollData(options); + else { + const actorRollData = this.actor?.getRollData(options) ?? {}; + data = { ...actorRollData, item: { ...this.system } }; + } + if (data?.item) { data.item.flags = { ...this.flags }; data.item.name = this.name; @@ -70,19 +71,9 @@ export default class DHItem extends foundry.documents.Item { return this.system.metadata.isInventoryItem ?? false; } - /** Returns true if the item can be used */ - get usable() { - const actor = this.actor; - const pack = actor?.pack ? game.packs.get(actor.pack) : null; - const hasActions = this.system.actionsList?.size || this.system.actionsList?.length; - const isValidType = actor?.type === 'character' || this.type === 'feature'; - return !pack?.locked && this.isOwner && isValidType && hasActions; - } - /** @inheritdoc */ static async createDialog(data = {}, createOptions = {}, options = {}) { const { folders, types, template, context = {}, ...dialogOptions } = options; - dialogOptions.classes = [options.classes ?? [], 'item-create'].flat(); // handled in hook if (types?.length === 0) { throw new Error('The array of sub-types to restrict to must not be empty.'); @@ -98,8 +89,8 @@ export default class DHItem extends foundry.documents.Item { isInventoryItem === true ? 'Inventory Items' //TODO localize : isInventoryItem === false - ? 'Character Items' //TODO localize - : 'Other'; //TODO localize + ? 'Character Items' //TODO localize + : 'Other'; //TODO localize return { value: type, label, group }; } @@ -206,6 +197,7 @@ export default class DHItem extends foundry.documents.Item { actor: item.parent, speaker: cls.getSpeaker(), system: systemData, + title: game.i18n.localize('DAGGERHEART.ACTIONS.Config.displayInChat'), content: await foundry.applications.handlebars.renderTemplate( 'systems/daggerheart/templates/ui/chat/ability-use.hbs', systemData @@ -238,14 +230,4 @@ export default class DHItem extends foundry.documents.Item { async _preDelete() { this.deleteTriggers(); } - - /** @inheritDoc */ - static migrateData(source) { - const documentClass = game.system.api.data.items[`DH${source.type?.capitalize()}`]; - if (documentClass?.migrateDocumentData) { - documentClass.migrateDocumentData(source); - } - - return super.migrateData(source); - } } diff --git a/module/documents/rollTable.mjs b/module/documents/rollTable.mjs index 59652f44..50b8fe63 100644 --- a/module/documents/rollTable.mjs +++ b/module/documents/rollTable.mjs @@ -76,7 +76,7 @@ export default class DhRollTable extends foundry.documents.RollTable { } async toMessage(results, { roll, messageData = {}, messageOptions = {} } = {}) { - messageOptions.rollMode ??= game.settings.get('core', 'messageMode'); + messageOptions.rollMode ??= game.settings.get('core', 'rollMode'); // Construct chat data messageData = foundry.utils.mergeObject( diff --git a/module/documents/scene.mjs b/module/documents/scene.mjs index bf700610..1c2faa34 100644 --- a/module/documents/scene.mjs +++ b/module/documents/scene.mjs @@ -1,16 +1,6 @@ import DHToken from './token.mjs'; export default class DhScene extends Scene { - get rangeSettings() { - const { custom } = CONFIG.DH.GENERAL.sceneRangeMeasurementSetting; - const sceneMeasurements = this.flags.daggerheart?.rangeMeasurement; - const globalMeasurements = game.settings.get( - CONFIG.DH.id, - CONFIG.DH.SETTINGS.gameSettings.variantRules - ).rangeMeasurement; - return sceneMeasurements?.setting === custom.id ? sceneMeasurements : globalMeasurements; - } - /** A map of `TokenDocument` IDs embedded in this scene long with new dimensions from actor size-category changes */ #sizeSyncBatch = new Map(); @@ -20,7 +10,7 @@ export default class DhScene extends Scene { const prototype = tokenDoc.actor?.prototypeToken ?? tokenDoc; this.#sizeSyncBatch.set(tokenDoc.id, { size: tokenSize, - prototypeSize: { width: prototype.width, height: prototype.height, depth: prototype.depth }, + prototypeSize: { width: prototype.width, height: prototype.height }, position: { x: tokenDoc.x, y: tokenDoc.y, elevation: tokenDoc.elevation } }); this.#processSyncBatch(); @@ -36,13 +26,11 @@ export default class DhScene extends Scene { const tokenSize = tokenSizes[size]; const width = size !== CONFIG.DH.ACTOR.tokenSize.custom.id ? tokenSize : prototypeSize.width; const height = size !== CONFIG.DH.ACTOR.tokenSize.custom.id ? tokenSize : prototypeSize.height; - const depth = size !== CONFIG.DH.ACTOR.tokenSize.custom.id ? tokenSize : prototypeSize.depth; const updatedPosition = DHToken.getSnappedPositionInSquareGrid(this.grid, position, width, height); return { _id, width, height, - depth, ...updatedPosition }; }); diff --git a/module/documents/templateManager.mjs b/module/documents/templateManager.mjs new file mode 100644 index 00000000..cf15c2e3 --- /dev/null +++ b/module/documents/templateManager.mjs @@ -0,0 +1,105 @@ +/** + * A singleton class that handles preview templates. + */ + +export default class DhTemplateManager { + #activePreview; + + /** + * Create a template preview, deactivating any existing ones. + * @param {object} data + */ + async createPreview(data) { + const template = await canvas.templates._createPreview(data, { renderSheet: false }); + + this.#activePreview = { + document: template.document, + object: template, + origin: { x: template.document.x, y: template.document.y } + }; + + this.#activePreview.events = { + contextmenu: this.#cancelTemplate.bind(this), + mousedown: this.#confirmTemplate.bind(this), + mousemove: this.#onDragMouseMove.bind(this), + wheel: this.#onMouseWheel.bind(this) + }; + canvas.stage.on('mousemove', this.#activePreview.events.mousemove); + canvas.stage.on('mousedown', this.#activePreview.events.mousedown); + + canvas.app.view.addEventListener('wheel', this.#activePreview.events.wheel, true); + canvas.app.view.addEventListener('contextmenu', this.#activePreview.events.contextmenu); + } + + /** + * Handles the movement of the temlate preview on mousedrag. + * @param {mousemove Event} event + */ + #onDragMouseMove(event) { + event.stopPropagation(); + const { moveTime, object } = this.#activePreview; + const update = {}; + + const now = Date.now(); + if (now - (moveTime || 0) <= 16) return; + this.#activePreview.moveTime = now; + + let cursor = event.getLocalPosition(canvas.templates); + + Object.assign(update, canvas.grid.getCenterPoint(cursor)); + + object.document.updateSource(update); + object.renderFlags.set({ refresh: true }); + } + + /** + * Handles the rotation of the preview template on scrolling. + * @param {wheel Event} event + */ + #onMouseWheel(event) { + if (!this.#activePreview) { + return; + } + if (!event.shiftKey && !event.ctrlKey) return; + event.stopPropagation(); + event.preventDefault(); + const { moveTime, object } = this.#activePreview; + + const now = Date.now(); + if (now - (moveTime || 0) <= 16) return; + this.#activePreview.moveTime = now; + + const multiplier = event.shiftKey ? 0.2 : 0.1; + + object.document.updateSource({ + direction: object.document.direction + event.deltaY * multiplier + }); + object.renderFlags.set({ refresh: true }); + } + + /** + * Cancels the preview template on right-click. + * @param {contextmenu Event} event + */ + #cancelTemplate(event) { + const { mousemove, mousedown, contextmenu, wheel } = this.#activePreview.events; + canvas.templates._onDragLeftCancel(event); + + canvas.stage.off('mousemove', mousemove); + canvas.stage.off('mousedown', mousedown); + canvas.app.view.removeEventListener('contextmenu', contextmenu); + canvas.app.view.removeEventListener('wheel', wheel); + } + + /** + * Creates a real MeasuredTemplate at the preview location and cancels the preview. + * @param {click Event} event + */ + #confirmTemplate(event) { + event.stopPropagation(); + this.#cancelTemplate(event); + + canvas.scene.createEmbeddedDocuments('MeasuredTemplate', [this.#activePreview.document.toObject()]); + this.#activePreview = undefined; + } +} diff --git a/module/documents/token.mjs b/module/documents/token.mjs index 8e91d4f0..4ee7ce05 100644 --- a/module/documents/token.mjs +++ b/module/documents/token.mjs @@ -66,8 +66,7 @@ export default class DHToken extends CONFIG.Token.documentClass { if (tokenSize && actor.system.size !== CONFIG.DH.ACTOR.tokenSize.custom.id) { document.updateSource({ width: tokenSize, - height: tokenSize, - depth: tokenSize + height: tokenSize }); } } @@ -91,7 +90,7 @@ export default class DHToken extends CONFIG.Token.documentClass { ) { const tokenSizes = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).tokenSizes; const tokenSize = tokenSizes[update.system.size]; - if (tokenSize !== this.width || tokenSize !== this.height || tokenSize !== this.depth) { + if (tokenSize !== this.width || tokenSize !== this.height) { this.parent?.syncTokenDimensions(this, update.system.size); } } @@ -324,7 +323,7 @@ export default class DHToken extends CONFIG.Token.documentClass { } let x = 0.5 * bottom; let y = 0.25; - for (let k = width - bottom; k--;) { + for (let k = width - bottom; k--; ) { points.push(x, y); x += 0.5; y -= 0.25; @@ -333,7 +332,7 @@ export default class DHToken extends CONFIG.Token.documentClass { y += 0.25; } points.push(x, y); - for (let k = bottom; k--;) { + for (let k = bottom; k--; ) { y += 0.5; points.push(x, y); x += 0.5; @@ -341,14 +340,14 @@ export default class DHToken extends CONFIG.Token.documentClass { points.push(x, y); } y += 0.5; - for (let k = top; k--;) { + for (let k = top; k--; ) { points.push(x, y); x -= 0.5; y += 0.25; points.push(x, y); y += 0.5; } - for (let k = width - top; k--;) { + for (let k = width - top; k--; ) { points.push(x, y); x -= 0.5; y += 0.25; @@ -357,7 +356,7 @@ export default class DHToken extends CONFIG.Token.documentClass { y -= 0.25; } points.push(x, y); - for (let k = top; k--;) { + for (let k = top; k--; ) { y -= 0.5; points.push(x, y); x -= 0.5; @@ -365,7 +364,7 @@ export default class DHToken extends CONFIG.Token.documentClass { points.push(x, y); } y -= 0.5; - for (let k = bottom; k--;) { + for (let k = bottom; k--; ) { points.push(x, y); x += 0.5; y -= 0.25; diff --git a/module/documents/tokenManager.mjs b/module/documents/tokenManager.mjs index 7678d2c7..f766a677 100644 --- a/module/documents/tokenManager.mjs +++ b/module/documents/tokenManager.mjs @@ -1,69 +1,104 @@ /** - * A singleton class that handles creating tokens. + * A singleton class that handles preview tokens. */ export default class DhTokenManager { + #activePreview; + #actor; + #resolve; + /** - * Create a token previer - * @param {Actor} actor - * @param {object} tokenData + * Create a template preview, deactivating any existing ones. + * @param {object} data */ async createPreview(actor, tokenData) { - const tokenSizes = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).tokenSizes; - if (actor?.system.metadata.usesSize) { - const tokenSize = tokenSizes[actor.system.size]; - if (tokenSize && actor.system.size !== CONFIG.DH.ACTOR.tokenSize.custom.id) { - tokenData.width = tokenSize; - tokenData.height = tokenSize; - tokenData.depth = tokenSize; - } - } - - return await canvas.tokens.placeTokens( - [ - { - ...actor.prototypeToken.toObject(), - actorId: actor.id, - displayName: 50, - ...tokenData - } - ], - { create: false } + this.#actor = actor; + const token = await canvas.tokens._createPreview( + { + ...actor.prototypeToken, + displayName: 50, + ...tokenData + }, + { renderSheet: false, actor } ); + + this.#activePreview = { + document: token.document, + object: token, + origin: { x: token.document.x, y: token.document.y } + }; + + this.#activePreview.events = { + contextmenu: this.#cancelTemplate.bind(this), + mousedown: this.#confirmTemplate.bind(this), + mousemove: this.#onDragMouseMove.bind(this) + }; + + canvas.stage.on('mousemove', this.#activePreview.events.mousemove); + canvas.stage.on('mousedown', this.#activePreview.events.mousedown); + canvas.app.view.addEventListener('contextmenu', this.#activePreview.events.contextmenu); + } + + /* Currently intended for using as a preview of where to create a token. (note the flag) */ + async createPreviewAsync(actor, tokenData = {}) { + return new Promise(resolve => { + this.#resolve = resolve; + this.createPreview(actor, { ...tokenData, flags: { daggerheart: { createPlacement: true } } }); + }); } /** - * Creates new tokens on the canvas by placing previews. - * @param {object} tokenData - * @param {object} options + * Handles the movement of the token preview on mousedrag. + * @param {mousemove Event} event */ - async createTokensWithPreview(tokensData, { elevation } = {}) { - const scene = game.scenes.get(game.user.viewedScene); - if (!scene) return; + #onDragMouseMove(event) { + event.stopPropagation(); + const { moveTime, object } = this.#activePreview; + const update = {}; - const level = scene.levels.get(game.user.viewedLevel); - if (!level) return; + const now = Date.now(); + if (now - (moveTime || 0) <= 16) return; + this.#activePreview.moveTime = now; - const createElevation = elevation ?? level.elevation.bottom; - for (const tokenData of tokensData) { - const previewTokens = await this.createPreview(tokenData.actor, { - name: tokenData.tokenPreviewName, - level: game.user.viewedLevel, - elevation: createElevation, - flags: { daggerheart: { createPlacement: true } } - }); - if (!previewTokens?.length) return null; + let cursor = event.getLocalPosition(canvas.templates); - await canvas.scene.createEmbeddedDocuments( - 'Token', - previewTokens.map(x => ({ - ...x.toObject(), - name: tokenData.actor.prototypeToken.name, - displayName: tokenData.actor.prototypeToken.displayName, - flags: tokenData.actor.prototypeToken.flags - })), - { controlObject: true, parent: canvas.scene } - ); - } + Object.assign(update, canvas.grid.getTopLeftPoint(cursor)); + + object.document.updateSource(update); + object.renderFlags.set({ refresh: true }); + } + + /** + * Cancels the preview token on right-click. + * @param {contextmenu Event} event + */ + #cancelTemplate(_event, resolved) { + const { mousemove, mousedown, contextmenu } = this.#activePreview.events; + this.#activePreview.object.destroy(); + + canvas.stage.off('mousemove', mousemove); + canvas.stage.off('mousedown', mousedown); + canvas.app.view.removeEventListener('contextmenu', contextmenu); + if (this.#resolve && !resolved) this.#resolve(false); + } + + /** + * Creates a real Actor and token at the preview location and cancels the preview. + * @param {click Event} event + */ + async #confirmTemplate(event) { + event.stopPropagation(); + this.#cancelTemplate(event, true); + + const actor = this.#actor.inCompendium + ? await game.system.api.documents.DhpActor.create(this.#actor.toObject()) + : this.#actor; + const tokenData = await actor.getTokenDocument(); + const result = await canvas.scene.createEmbeddedDocuments('Token', [ + { ...tokenData.toObject(), x: this.#activePreview.document.x, y: this.#activePreview.document.y } + ]); + + this.#activePreview = undefined; + if (this.#resolve && result.length) this.#resolve(result[0]); } } diff --git a/module/documents/tooltipManager.mjs b/module/documents/tooltipManager.mjs index 3e3f4a16..bf107a42 100644 --- a/module/documents/tooltipManager.mjs +++ b/module/documents/tooltipManager.mjs @@ -3,6 +3,7 @@ import { AdversaryBPPerEncounter, BaseBPPerEncounter } from '../config/encounter export default class DhTooltipManager extends foundry.helpers.interaction.TooltipManager { #wide = false; #bordered = false; + #active = false; async activate(element, options = {}) { const { TextEditor } = foundry.applications.ux; @@ -30,39 +31,12 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti this.#bordered = true; let effect = {}; if (element.dataset.uuid) { - const effectItem = await foundry.utils.fromUuid(element.dataset.uuid); - const effectData = effectItem.toObject(); - + const effectData = (await foundry.utils.fromUuid(element.dataset.uuid)).toObject(); effect = { ...effectData, - name: game.i18n.localize(effectData.name) + name: game.i18n.localize(effectData.name), + description: game.i18n.localize(effectData.description ?? effectData.parent.system.description) }; - - if (effectData.type === 'beastform') { - const beastformData = { - features: [], - advantageOn: effectData.system.advantageOn, - beastformAttackData: game.system.api.data.items.DHBeastform.getBeastformAttackData(effectItem) - }; - - const features = effectItem.parent.items.filter(x => effectItem.system.featureIds.includes(x.id)); - for (const feature of features) { - const featureData = feature.toObject(); - featureData.enrichedDescription = await feature.system.getEnrichedDescription(); - beastformData.features.push(featureData); - } - - effect.description = await foundry.applications.handlebars.renderTemplate( - 'systems/daggerheart/templates/ui/tooltip/parts/beastformData.hbs', - { - item: { system: beastformData } - } - ); - } else { - effect.description = game.i18n.localize( - effectData.description ?? effectData.parent.system.description - ); - } } else { const conditions = CONFIG.DH.GENERAL.conditions(); const condition = conditions[element.dataset.condition]; @@ -349,9 +323,7 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti async getBattlepointHTML(combatId) { const combat = game.combats.get(combatId); const adversaries = - combat.turns - ?.filter(x => x.actor?.isNPC && x.token.disposition === CONST.TOKEN_DISPOSITIONS.HOSTILE) - ?.map(x => ({ ...x.actor, type: x.actor.system.type })) ?? []; + combat.turns?.filter(x => x.actor?.isNPC)?.map(x => ({ ...x.actor, type: x.actor.system.type })) ?? []; const characters = combat.turns?.filter(x => !x.isNPC && x.actor) ?? []; const nrCharacters = characters.length; diff --git a/module/enrichers/DamageEnricher.mjs b/module/enrichers/DamageEnricher.mjs index db0e8729..e3f9c42a 100644 --- a/module/enrichers/DamageEnricher.mjs +++ b/module/enrichers/DamageEnricher.mjs @@ -1,7 +1,7 @@ import { parseInlineParams } from './parser.mjs'; export default function DhDamageEnricher(match, _options) { - const { value, type, inline } = parseInlineParams(match[1], { first: 'value' }); + const { value, type, inline } = parseInlineParams(match[1]); if (!value || !type) return match[0]; return getDamageMessage(value, type, inline, match[0]); } @@ -59,7 +59,7 @@ export const renderDamageButton = async event => { { formula: value, applyTo: CONFIG.DH.GENERAL.healingTypes.hitPoints.id, - damageTypes: type + type: type } ] }; diff --git a/module/enrichers/DualityRollEnricher.mjs b/module/enrichers/DualityRollEnricher.mjs index a7db01a4..5b66179f 100644 --- a/module/enrichers/DualityRollEnricher.mjs +++ b/module/enrichers/DualityRollEnricher.mjs @@ -15,8 +15,8 @@ function getDualityMessage(roll, flavor) { (roll?.trait ? game.i18n.format('DAGGERHEART.GENERAL.rollWith', { roll: trait }) : roll?.reaction - ? game.i18n.localize('DAGGERHEART.GENERAL.reactionRoll') - : game.i18n.localize('DAGGERHEART.GENERAL.duality')); + ? game.i18n.localize('DAGGERHEART.GENERAL.reactionRoll') + : game.i18n.localize('DAGGERHEART.GENERAL.duality')); const dataLabel = trait ? game.i18n.localize(abilities[roll.trait].label) @@ -25,14 +25,14 @@ function getDualityMessage(roll, flavor) { const advantage = roll?.advantage ? CONFIG.DH.ACTIONS.advantageState.advantage.value : roll?.disadvantage - ? CONFIG.DH.ACTIONS.advantageState.disadvantage.value - : undefined; + ? CONFIG.DH.ACTIONS.advantageState.disadvantage.value + : undefined; const advantageLabel = advantage === CONFIG.DH.ACTIONS.advantageState.advantage.value ? 'Advantage' : advantage === CONFIG.DH.ACTIONS.advantageState.disadvantage.value - ? 'Disadvantage' - : undefined; + ? 'Disadvantage' + : undefined; const dualityElement = document.createElement('span'); dualityElement.innerHTML = ` diff --git a/module/enrichers/TemplateEnricher.mjs b/module/enrichers/TemplateEnricher.mjs index bbe93b17..74462e00 100644 --- a/module/enrichers/TemplateEnricher.mjs +++ b/module/enrichers/TemplateEnricher.mjs @@ -8,11 +8,11 @@ export default function DhTemplateEnricher(match, _options) { const range = params.range && Number.isNaN(Number(params.range)) ? Object.values(CONFIG.DH.GENERAL.templateRanges).find( - x => x.id.toLowerCase() === params.range || x.short === params.range - )?.id + x => x.id.toLowerCase() === params.range || x.short === params.range + )?.id : params.range; - if (!CONFIG.DH.GENERAL.templateTypes[type] || !range) return match[0]; + if (!Object.values(CONFIG.DH.GENERAL.templateTypes).find(x => x === type) || !range) return match[0]; const label = game.i18n.localize(`DAGGERHEART.CONFIG.TemplateTypes.${type}`); const rangeDisplay = Number.isNaN(Number(range)) @@ -57,24 +57,46 @@ export const renderMeasuredTemplate = async event => { if (!type || !range || !game.canvas.scene) return; - const shapeData = CONFIG.Canvas.layers.regions.layerClass.getTemplateShape({ - type, - angle, - range, - direction - }); + const usedType = type === 'inFront' ? 'cone' : type === 'emanation' ? 'circle' : type; + const usedAngle = + type === CONST.MEASURED_TEMPLATE_TYPES.CONE + ? (angle ?? CONFIG.MeasuredTemplate.defaults.angle) + : type === CONFIG.DH.GENERAL.templateTypes.INFRONT + ? '180' + : undefined; - await canvas.regions.placeRegion( - { - name: type.capitalize(), - shapes: [shapeData], - restriction: { enabled: false, type: 'move', priority: 0 }, - behaviors: [], - displayMeasurements: true, - locked: false, - ownership: { default: CONST.DOCUMENT_OWNERSHIP_LEVELS.NONE }, - visibility: CONST.REGION_VISIBILITY.ALWAYS - }, - { create: true } - ); + const distance = getTemplateDistance(range, type); + + const { width, height } = game.canvas.scene.dimensions; + const data = { + x: width / 2, + y: height / 2, + t: usedType, + distance: distance, + width: type === CONST.MEASURED_TEMPLATE_TYPES.RAY ? 5 : undefined, + angle: usedAngle, + direction: direction + }; + + CONFIG.ux.TemplateManager.createPreview(data); +}; + +const getTemplateDistance = (range, type) => { + const rangeNumber = Number(range); + if (!Number.isNaN(rangeNumber)) return rangeNumber; + + const { custom } = CONFIG.DH.GENERAL.sceneRangeMeasurementSetting; + const sceneMeasurements = canvas.scene?.flags.daggerheart?.rangeMeasurement; + const globalMeasurements = game.settings.get( + CONFIG.DH.id, + CONFIG.DH.SETTINGS.gameSettings.variantRules + ).rangeMeasurement; + + const settings = sceneMeasurements?.setting === custom.id ? sceneMeasurements : globalMeasurements; + const baseDistance = settings[range]; + + if (type !== CONFIG.DH.GENERAL.templateTypes.EMANATION) return baseDistance; + + const emanationAddDistance = settings.melee / 2; + return baseDistance + emanationAddDistance; }; diff --git a/module/enrichers/parser.mjs b/module/enrichers/parser.mjs index 76ea0b73..365caec9 100644 --- a/module/enrichers/parser.mjs +++ b/module/enrichers/parser.mjs @@ -8,7 +8,7 @@ export function parseInlineParams(paramString, { first } = {}) { const parts = paramString.split('|').map(x => x.trim()); const params = {}; for (const [idx, param] of parts.entries()) { - if (first && idx === 0 && !param.includes(':')) { + if (first && idx === 0) { params[first] = param; } else { const parts = param.split(':'); diff --git a/module/helpers/handlebarsHelper.mjs b/module/helpers/handlebarsHelper.mjs index 7f30d970..2faea830 100644 --- a/module/helpers/handlebarsHelper.mjs +++ b/module/helpers/handlebarsHelper.mjs @@ -49,8 +49,9 @@ export default class RegisterHandlebarsHelpers { } static damageSymbols(damageParts) { - const allTypes = [...new Set([...damageParts].flatMap(x => Array.from(x.type)))]; - const symbols = allTypes.map(p => CONFIG.DH.GENERAL.damageTypes[p].icon); + const symbols = [...new Set(damageParts.reduce((a, c) => a.concat([...c.type]), []))].map( + p => CONFIG.DH.GENERAL.damageTypes[p].icon + ); return new Handlebars.SafeString(Array.from(symbols).map(symbol => ``)); } diff --git a/module/helpers/utils.mjs b/module/helpers/utils.mjs index af6c2777..b49a98ca 100644 --- a/module/helpers/utils.mjs +++ b/module/helpers/utils.mjs @@ -108,9 +108,9 @@ export const tagifyElement = (element, baseOptions, onChange, tagifyOptions = {} const options = Array.isArray(baseOptions) ? baseOptions : Object.keys(baseOptions).map(optionKey => ({ - ...baseOptions[optionKey], - id: optionKey - })); + ...baseOptions[optionKey], + id: optionKey + })); const tagifyElement = new Tagify(element, { tagTextProp: 'name', @@ -177,10 +177,10 @@ export const getDeleteKeys = (property, innerProperty, innerPropertyDefaultValue [innerProperty]: innerPropertyDefaultValue }; } else { - acc[`${key}.${innerProperty}`] = _del; + acc[`${key}.-=${innerProperty}`] = null; } } else { - acc[`${key}`] = _del; + acc[`-=${key}`] = null; } return acc; @@ -190,13 +190,10 @@ export const getDeleteKeys = (property, innerProperty, innerPropertyDefaultValue // Fix on Foundry native formula replacement for DH const nativeReplaceFormulaData = Roll.replaceFormulaData; Roll.replaceFormulaData = function (formula, data = {}, { missing, warn = false } = {}) { - /* Inserting global data */ - const defaultingTypes = [ - ...Object.keys(CONFIG.DH.GENERAL.multiplierTypes).map(x => ({ term: x, default: 1 })), - { term: 'partySize', default: game.actors?.party?.system.partyMembers.length ?? 0 } - ]; - - formula = defaultingTypes.reduce((a, c) => a.replaceAll(`@${c.term}`, data[c.term] ?? c.default), formula); + const terms = Object.keys(CONFIG.DH.GENERAL.multiplierTypes).map(type => { + return { term: type, default: 1 }; + }); + formula = terms.reduce((a, c) => a.replaceAll(`@${c.term}`, data[c.term] ?? c.default), formula); return nativeReplaceFormulaData(formula, data, { missing, warn }); }; @@ -372,11 +369,10 @@ export const itemAbleRollParse = (value, actor, item) => { const isItemTarget = value.toLowerCase().includes('item.@'); const slicedValue = isItemTarget ? value.replaceAll(/item\.@/gi, '@') : value; - const model = isItemTarget || item instanceof Item ? item : actor; - const rollData = isItemTarget || !model?.getRollData ? model : model.getRollData(); + const model = isItemTarget ? item : actor; try { - return Roll.replaceFormulaData(slicedValue, rollData); + return Roll.replaceFormulaData(slicedValue, isItemTarget || !model?.getRollData ? model : model.getRollData()); } catch (_) { return ''; } @@ -426,12 +422,7 @@ export async function createEmbeddedItemWithEffects(actor, baseData, update) { ...baseData, id: data.id, uuid: data.uuid, - _uuid: data.uuid, - effects: data.effects?.map(effect => effect.toObject()), - _stats: { - ...data._stats, - compendiumSource: data.pack ? `Compendium.${data.pack}.Item.${data.id}` : null - } + effects: data.effects?.map(effect => effect.toObject()) } ]); @@ -449,9 +440,14 @@ export async function createEmbeddedItemsWithEffects(actor, baseData) { effects: data.effects?.map(effect => effect.toObject()) }); } + await actor.createEmbeddedDocuments('Item', effectData); } +export const slugify = name => { + return name.toLowerCase().replaceAll(' ', '-').replaceAll('.', ''); +}; + export function shuffleArray(array) { let currentIndex = array.length; while (currentIndex != 0) { @@ -479,8 +475,6 @@ export async function waitForDiceSoNice(message) { } export function refreshIsAllowed(allowedTypes, typeToCheck) { - if (!allowedTypes) return true; - switch (typeToCheck) { case CONFIG.DH.GENERAL.refreshTypes.scene.id: case CONFIG.DH.GENERAL.refreshTypes.session.id: @@ -497,38 +491,9 @@ export function refreshIsAllowed(allowedTypes, typeToCheck) { } } -function expireActiveEffectIsAllowed(allowedTypes, typeToCheck) { - if (typeToCheck === CONFIG.DH.GENERAL.activeEffectDurations.act.id) return true; - - return refreshIsAllowed(allowedTypes, typeToCheck); -} - -export function expireActiveEffects(actor, allowedTypes = null) { - const shouldExpireEffects = game.settings.get( - CONFIG.DH.id, - CONFIG.DH.SETTINGS.gameSettings.Automation - ).autoExpireActiveEffects; - if (!shouldExpireEffects) return; - - const effectsToExpire = actor - .getActiveEffects() - .filter(effect => { - if (!effect.system?.duration.type) return false; - - const { temporary, custom } = CONFIG.DH.GENERAL.activeEffectDurations; - if ([temporary.id, custom.id].includes(effect.system.duration.type)) return false; - - return expireActiveEffectIsAllowed(allowedTypes, effect.system.duration.type); - }) - .map(x => x.id); - - actor.deleteEmbeddedDocuments('ActiveEffect', effectsToExpire); -} - export async function getCritDamageBonus(formula) { const critRoll = new Roll(formula); - await critRoll.evaluate(); - return critRoll.dice.reduce((acc, dice) => acc + dice.faces * dice.results.filter(r => r.active).length, 0); + return critRoll.dice.reduce((acc, dice) => acc + dice.faces * dice.number, 0); } export function htmlToText(html) { @@ -538,16 +503,6 @@ export function htmlToText(html) { return tempDivElement.textContent || tempDivElement.innerText || ''; } -export function getIconVisibleActiveEffects(effects) { - return effects.filter(effect => { - if (!(effect instanceof game.system.api.documents.DhActiveEffect)) return true; - - const alwaysShown = effect.showIcon === CONST.ACTIVE_EFFECT_SHOW_ICON.ALWAYS; - const conditionalShown = effect.showIcon === CONST.ACTIVE_EFFECT_SHOW_ICON.CONDITIONAL && !effect.transfer; // TODO: system specific logic - - return !effect.disabled && (alwaysShown || conditionalShown); - }); -} export async function getFeaturesHTMLData(features) { const result = []; for (const feature of features) { @@ -605,8 +560,8 @@ export function calculateExpectedValue(formulaOrTerms) { const terms = Array.isArray(formulaOrTerms) ? formulaOrTerms : typeof formulaOrTerms === 'string' - ? parseTermsFromSimpleFormula(formulaOrTerms) - : [formulaOrTerms]; + ? parseTermsFromSimpleFormula(formulaOrTerms) + : [formulaOrTerms]; return terms.reduce((r, t) => r + (t.bonus ?? 0) + (t.diceQuantity ? (t.diceQuantity * (t.faces + 1)) / 2 : 0), 0); } @@ -633,8 +588,6 @@ export async function RefreshFeatures( const refreshedActors = {}; for (let actor of game.actors) { if (actorTypes.includes(actor.type) && actor.prototypeToken.actorLink) { - expireActiveEffects(actor, refreshTypes); - const updates = {}; for (let item of actor.items) { if ( @@ -656,8 +609,8 @@ export async function RefreshFeatures( 'resource.value': increasing ? 0 : game.system.api.documents.DhActiveEffect.effectSafeEval( - Roll.replaceFormulaData(item.system.resource.max, actor.getRollData()) - ) + Roll.replaceFormulaData(item.system.resource.max, actor.getRollData()) + ) }; } if (item.system.metadata?.hasActions) { @@ -729,193 +682,3 @@ export async function RefreshFeatures( return refreshedActors; } - -export function getUnusedDamageTypes(parts) { - const usedKeys = Object.keys(parts); - return Object.keys(CONFIG.DH.GENERAL.healingTypes).reduce((acc, key) => { - if (!usedKeys.includes(key)) - acc.push({ - value: key, - label: game.i18n.localize(CONFIG.DH.GENERAL.healingTypes[key].label) - }); - - return acc; - }, []); -} - -/** Returns resolved armor sources ordered by application order */ -export function getArmorSources(actor) { - const rawArmorSources = Array.from(actor.allApplicableEffects()).filter(x => x.system.armorData); - if (actor.system.armor) rawArmorSources.push(actor.system.armor); - - const data = rawArmorSources.map(doc => { - // Get the origin item. Since the actor is already loaded, it should already be cached - // Consider the relative function versions if this causes an issue - const origin = doc.origin ? foundry.utils.fromUuidSync(doc.origin) : doc; - const useParentName = doc.parent && !(doc.parent instanceof Actor); - const name = doc.origin || !useParentName ? doc.name : doc.parent.name; - - return { - origin, - name, - document: doc, - data: doc.system.armor ?? doc.system.armorData, - disabled: !!doc.disabled || !!doc.isSuppressed - }; - }); - - return sortBy(data, ({ origin }) => { - switch (origin?.type) { - case 'class': - case 'subclass': - case 'ancestry': - case 'community': - case 'feature': - case 'domainCard': - return 2; - case 'loot': - case 'consumable': - return 3; - case 'character': - return 4; - case 'weapon': - return 5; - case 'armor': - return 6; - default: - return 1; - } - }); -} - -/** - * Triggers a reset and non-forced re-render on all given actors (if given) - * or all world actors and actors in all scenes to show immediate results for a changed setting. - */ -export function resetAndRerenderActors() { - const actors = new Set( - [game.actors.contents, game.scenes.contents.flatMap(s => s.tokens.contents).flatMap(t => t.actor ?? [])].flat() - ); - for (const actor of actors) { - for (const app of Object.values(actor.apps)) { - for (const element of app.element?.querySelectorAll('prose-mirror.active')) { - element.open = false; // This triggers a save - } - } - - actor.reset(); - actor.render(); - } -} - -/** - * Returns an array sorted by a function that returns a thing to compare, or an array to compare in order - * Similar to lodash's sortBy function. - */ -export function sortBy(arr, fn) { - const directCompare = (a, b) => (a < b ? -1 : a > b ? 1 : 0); - const cmp = (a, b) => { - const resultA = fn(a); - const resultB = fn(b); - if (Array.isArray(resultA) && Array.isArray(resultB)) { - for (let idx = 0; idx < Math.min(resultA.length, resultB.length); idx++) { - const result = directCompare(resultA[idx], resultB[idx]); - if (result !== 0) return result; - } - return 0; - } - return directCompare(resultA, resultB); - }; - return arr.sort(cmp); -} - -/** - * Creates a proxy that allows retrieval of top data but diverts updates to a different object. - * Generally used for roll data - */ -export function createShallowProxy(obj) { - if (obj._isShallowProxy) return obj; - - const overrides = {}; - return new Proxy(obj, { - get(target, prop, receiver) { - if (prop === '_isShallowProxy') return true; - if (prop in overrides) return overrides[prop]; - return Reflect.get(target, prop, receiver); - }, - set(_target, prop, newValue) { - overrides[prop] = newValue; - return true; - }, - deleteProperty(_target, prop) { - delete overrides[prop]; - return true; - }, - has(target, key) { - return key in overrides || key in target; - } - }); -} - -export function camelize(str) { - return str - .replace(/(?:^\w|[A-Z]|\b\w)/g, (part, index) => { - return index === 0 ? part.toLowerCase() : part.toUpperCase(); - }) - .replace(/\s+/g, ''); -} - -/** Bulk load a list of documents using uuids. Returns the documents in the same order */ -export async function fromUuids(uuids) { - // Set up base entries. Each step works on a sublist of these objects - const entries = uuids.map(uuid => ({ - uuid, - parsed: foundry.utils.parseUuid(uuid), - value: foundry.utils.fromUuidSync(uuid) - })); - - // Handle missing uuids for embedded documents first - // A value may be index data, so we check if its a document - const packEmbeddedEntries = entries.filter( - e => - !(e.value instanceof Document) && - e.parsed && - e.parsed.collection instanceof foundry.documents.collections.CompendiumCollection && - e.parsed.embedded.length > 0 - ); - await Promise.all( - packEmbeddedEntries.map(async e => { - e.value = await fromUuid(e.uuid); - return true; - }) - ); - - // Handle missing top level pack stuff, by batching per pack - const missingTopLevel = entries.filter(e => !(e.value instanceof Document) && e.value?.pack); - for (const packGroup of Object.values(Object.groupBy(missingTopLevel, e => e.value.pack))) { - const pack = game.packs.get(packGroup[0].value.pack); - if (!pack) continue; - - const ids = packGroup.map(p => p.parsed?.id).filter(id => !!id); - const documents = await pack.getDocuments({ _id__in: ids }); - for (const p of packGroup) { - p.value = documents.find(d => d.id === p.parsed.id) ?? p.value; - } - } - - return entries.map(e => e.value); -} -/** - * Triggers DiceSoNice rolls or dice roll audio for rolls. Not used for duality rolls. - * @param { Roll[] } rolls - * @return { void } - */ -export async function triggerChatRollFx(rolls, options = { whisper: false, blind: false }) { - const { whisper, blind } = options; - if (game.modules.get('dice-so-nice')?.active) { - const rerollPromises = rolls.map(roll => game.dice3d.showForRoll(roll, game.user, true, whisper, blind)); - await Promise.allSettled(rerollPromises); - } else { - foundry.audio.AudioHelper.play({ src: CONFIG.sounds.dice }); - } -} diff --git a/module/macros/spotlightCombatant.mjs b/module/macros/spotlightCombatant.mjs index dc8339ac..68a26ff9 100644 --- a/module/macros/spotlightCombatant.mjs +++ b/module/macros/spotlightCombatant.mjs @@ -1,50 +1,21 @@ /** - * Spotlight a token on the canvas. If it is a combatant, run it through combatTracker's spotlight logic. - * @param {TokenDocument} token - The token to spotlight - * @returns {void} + * Spotlights a combatant. + * The combatant can be selected in a number of ways. If many are applied at the same time, the following order is used: + * 1) SelectedCombatant + * 2) HoveredCombatant */ -const spotlightCombatantMacro = async token => { - if (!token) - return ui.notifications.error(game.i18n.localize('DAGGERHEART.MACROS.Spotlight.errors.noTokenSelected')); +const spotlightCombatant = () => { + if (!game.combat) + return ui.notifications.error(game.i18n.localize('DAGGERHEART.MACROS.Spotlight.errors.noActiveCombat')); - const combatantCombat = token.combatant - ? game.combat - : game.combats.find(combat => combat.combatants.some(x => x.token && x.token.id === token.document.id)); - if (combatantCombat) { - const combatant = combatantCombat.combatants.find(x => x.token.id === token.document.id); - if (!combatantCombat.active) { - await combatantCombat.activate(); - if (combatantCombat.combatant?.id !== combatant.id) ui.combat.setCombatantSpotlight(combatant.id); - } else { - ui.combat.setCombatantSpotlight(combatant.id); - } - } else { - if (game.combat) await ui.combat.clearTurn(); + const selectedCombatant = canvas.tokens.controlled.length > 0 ? canvas.tokens.controlled[0].combatant : null; + const hoveredCombatant = game.canvas.tokens.hover?.combatant; - const spotlightTracker = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.SpotlightTracker); - const isSpotlighted = spotlightTracker.spotlightedTokens.has(token.document.uuid); - if (!isSpotlighted) await clearPreviousSpotlight(); + const combatant = selectedCombatant ?? hoveredCombatant; + if (!combatant) + return ui.notifications.error(game.i18n.localize('DAGGERHEART.MACROS.Spotlight.errors.noCombatantSelected')); - spotlightTracker.updateSource({ - spotlightedTokens: isSpotlighted ? [] : [token.document.uuid] - }); - - await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.SpotlightTracker, spotlightTracker); - token.renderFlags.set({ refreshTurnMarker: true }); - } + ui.combat.setCombatantSpotlight(combatant.id); }; -export const clearPreviousSpotlight = async () => { - const spotlightTracker = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.SpotlightTracker); - const previouslySpotlightedUuid = - spotlightTracker.spotlightedTokens.size > 0 ? spotlightTracker.spotlightedTokens.first() : null; - if (!previouslySpotlightedUuid) return; - - spotlightTracker.updateSource({ spotlightedTokens: [] }); - await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.SpotlightTracker, spotlightTracker); - - const previousToken = await foundry.utils.fromUuid(previouslySpotlightedUuid); - previousToken.object.renderFlags.set({ refreshTurnMarker: true }); -}; - -export default spotlightCombatantMacro; +export default spotlightCombatant; diff --git a/module/systemRegistration/handlebars.mjs b/module/systemRegistration/handlebars.mjs index 1b08e0ad..f51e1035 100644 --- a/module/systemRegistration/handlebars.mjs +++ b/module/systemRegistration/handlebars.mjs @@ -10,7 +10,6 @@ export const preloadHandlebarsTemplates = async function () { 'templates/generic/tab-navigation.hbs', 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs', 'systems/daggerheart/templates/sheets/global/partials/action-item.hbs', - 'systems/daggerheart/templates/sheets/global/partials/gold.hbs', 'systems/daggerheart/templates/sheets/global/partials/domain-card-item.hbs', 'systems/daggerheart/templates/sheets/global/partials/item-resource.hbs', 'systems/daggerheart/templates/sheets/global/partials/resource-section/resource-section.hbs', @@ -29,7 +28,6 @@ export const preloadHandlebarsTemplates = async function () { 'systems/daggerheart/templates/actionTypes/uses.hbs', 'systems/daggerheart/templates/actionTypes/roll.hbs', 'systems/daggerheart/templates/actionTypes/save.hbs', - 'systems/daggerheart/templates/actionTypes/areas.hbs', 'systems/daggerheart/templates/actionTypes/cost.hbs', 'systems/daggerheart/templates/actionTypes/range-target.hbs', 'systems/daggerheart/templates/actionTypes/effect.hbs', @@ -38,11 +36,9 @@ export const preloadHandlebarsTemplates = async function () { 'systems/daggerheart/templates/actionTypes/summon.hbs', 'systems/daggerheart/templates/actionTypes/transform.hbs', 'systems/daggerheart/templates/settings/components/settings-item-line.hbs', - 'systems/daggerheart/templates/ui/tooltip/parts/beastformData.hbs', 'systems/daggerheart/templates/ui/tooltip/parts/tooltipChips.hbs', 'systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs', 'systems/daggerheart/templates/dialogs/downtime/activities.hbs', - 'systems/daggerheart/templates/dialogs/tagTeamDialog/parts/tagTeamDamageParts.hbs', 'systems/daggerheart/templates/dialogs/dice-roll/costSelection.hbs', 'systems/daggerheart/templates/ui/chat/parts/roll-part.hbs', 'systems/daggerheart/templates/ui/chat/parts/description-part.hbs', @@ -51,7 +47,6 @@ export const preloadHandlebarsTemplates = async function () { 'systems/daggerheart/templates/ui/chat/parts/button-part.hbs', 'systems/daggerheart/templates/ui/itemBrowser/itemContainer.hbs', 'systems/daggerheart/templates/scene/dh-config.hbs', - 'systems/daggerheart/templates/settings/appearance-settings/diceSoNiceTab.hbs', - 'systems/daggerheart/templates/sheets/activeEffect/typeChanges/armorChange.hbs' + 'systems/daggerheart/templates/settings/appearance-settings/diceSoNiceTab.hbs' ]); }; diff --git a/module/systemRegistration/migrations.mjs b/module/systemRegistration/migrations.mjs index b718a127..743d42a4 100644 --- a/module/systemRegistration/migrations.mjs +++ b/module/systemRegistration/migrations.mjs @@ -1,4 +1,3 @@ -import { defaultRestOptions } from '../config/generalConfig.mjs'; import { RefreshType, socketEvent } from './socket.mjs'; export async function runMigrations() { @@ -24,8 +23,8 @@ export async function runMigrations() { const { originItemType, isMulticlass, identifier } = item.system; const base = originItemType ? actor.items.find( - x => x.type === originItemType && Boolean(isMulticlass) === Boolean(x.system.isMulticlass) - ) + 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); @@ -194,11 +193,11 @@ export async function runMigrations() { } if (foundry.utils.isNewerVersion('1.2.7', lastMigrationVersion)) { - const tagTeam = game.settings.get(CONFIG.DH.id, 'TagTeamRoll'); + const tagTeam = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll); const initatorMissing = tagTeam.initiator && !game.actors.some(actor => actor.id === tagTeam.initiator); const missingMembers = Object.keys(tagTeam.members).reduce((acc, id) => { if (!game.actors.some(actor => actor.id === id)) { - acc[id] = _del; + acc[`-=${id}`] = null; } return acc; }, {}); @@ -207,7 +206,7 @@ export async function runMigrations() { initiator: initatorMissing ? null : tagTeam.initiator, members: missingMembers }); - await game.settings.set(CONFIG.DH.id, 'TagTeamRoll', tagTeam); + await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll, tagTeam); lastMigrationVersion = '1.2.7'; } @@ -247,113 +246,6 @@ export async function runMigrations() { lastMigrationVersion = '1.6.0'; } - - if (foundry.utils.isNewerVersion('2.0.0', lastMigrationVersion)) { - const progress = game.system.api.applications.ui.DhProgress.createMigrationProgress(0); - const progressBuffer = 50; - - //#region Data Setup - const lockedPacks = []; - const itemPacks = game.packs.filter(x => x.metadata.type === 'Item'); - const actorPacks = game.packs.filter(x => x.metadata.type === 'Actor'); - - const getIndexes = async (packs, type) => { - const indexes = []; - for (const pack of packs) { - const indexValues = pack.index.values().reduce((acc, index) => { - if (!type || index.type === type) acc.push(index.uuid); - return acc; - }, []); - - if (indexValues.length && pack.locked) { - lockedPacks.push(pack.collection); - await pack.configure({ locked: false }); - } - - indexes.push(...indexValues); - } - - return indexes; - }; - - const itemEntries = await getIndexes(itemPacks); - const characterEntries = await getIndexes(actorPacks, 'character'); - - const worldItems = game.items; - const worldCharacters = game.actors.filter(x => x.type === 'character'); - - /* The async fetches are the mainstay of time. Leaving 1 progress for the sync logic */ - const newMax = itemEntries.length + characterEntries.length + progressBuffer; - progress.updateMax(newMax); - - const compendiumItems = []; - for (const entry of itemEntries) { - const item = await foundry.utils.fromUuid(entry); - compendiumItems.push(item); - progress.advance(); - } - - const compendiumCharacters = []; - for (const entry of characterEntries) { - const character = await foundry.utils.fromUuid(entry); - compendiumCharacters.push(character); - progress.advance(); - } - //#endregion - - /* Migrate existing effects modifying armor, creating new Armor Effects instead */ - const migrateEffects = async entity => { - for (const effect of entity.effects) { - if (effect.system.changes.every(x => x.key !== 'system.armorScore')) continue; - - effect.update({ - 'system.changes': effect.system.changes.map(change => ({ - ...change, - type: change.key === 'system.armorScore' ? 'armor' : change.type, - value: change.key === 'system.armorScore' ? { current: 0, max: change.value } : change.value - })) - }); - } - }; - - /* Migrate existing armors effects */ - const migrateItems = async items => { - for (const item of items) { - await migrateEffects(item); - } - }; - - await migrateItems([...compendiumItems, ...worldItems]); - progress.advance({ by: progressBuffer / 2 }); - - for (const actor of [...compendiumCharacters, ...worldCharacters]) { - await migrateEffects(actor); - await migrateItems(actor.items); - } - - progress.advance({ by: progressBuffer / 2 }); - - for (let packId of lockedPacks) { - const pack = game.packs.get(packId); - await pack.configure({ locked: true }); - } - - progress.close(); - - lastMigrationVersion = '2.0.0'; - } - - if (foundry.utils.isNewerVersion('2.1.0', lastMigrationVersion)) { - const downtimeMoves = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew); - if (downtimeMoves.restMoves.longRest.moves.repairArmor) { - await downtimeMoves.updateSource({ - 'restMoves.longRest.moves.repairArmor': defaultRestOptions.longRest().repairArmor - }); - game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew, downtimeMoves.toObject()); - } - - lastMigrationVersion = '2.1.0'; - } //#endregion await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LastMigrationVersion, lastMigrationVersion); diff --git a/module/systemRegistration/settings.mjs b/module/systemRegistration/settings.mjs index a66323c7..17dab6f7 100644 --- a/module/systemRegistration/settings.mjs +++ b/module/systemRegistration/settings.mjs @@ -15,8 +15,7 @@ import { DhMetagamingSettings, DhVariantRuleSettings } from '../applications/settings/_module.mjs'; -import { CompendiumBrowserSettings } from '../data/_module.mjs'; -import SpotlightTracker from '../data/spotlightTracker.mjs'; +import { CompendiumBrowserSettings, DhTagTeamRoll } from '../data/_module.mjs'; export const registerDHSettings = () => { registerKeyBindings(); @@ -41,38 +40,12 @@ export const registerKeyBindings = () => { hint: game.i18n.localize('DAGGERHEART.SETTINGS.Keybindings.spotlight.hint'), uneditable: [], editable: [], - onDown: () => { - const selectedTokens = canvas.tokens.controlled.length > 0 ? canvas.tokens.controlled[0] : null; - const hoveredTokens = game.canvas.tokens.hover ? game.canvas.tokens.hover : null; - const tokens = selectedTokens ?? hoveredTokens; - game.system.api.macros.spotlightCombatant(tokens); - }, + onDown: game.system.api.macros.spotlightCombatant, onUp: () => {}, restricted: true, reservedModifiers: [], precedence: CONST.KEYBINDING_PRECEDENCE.NORMAL }); - - game.keybindings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.keybindings.partySheet, { - name: _loc('DAGGERHEART.SETTINGS.Keybindings.partySheet.name'), - hint: _loc('DAGGERHEART.SETTINGS.Keybindings.partySheet.hint'), - editable: [{ key: 'KeyP' }], - onDown: () => { - const controlled = canvas.ready ? canvas.tokens.controlled : []; - const selectedParty = controlled.find(c => c.actor?.type === 'party')?.actor; - const party = selectedParty ?? game.actors.party; - if (!party) return; - - const sheet = party.sheet; - if (!sheet.rendered) { - sheet.render(true); - } else if (sheet.minimized) { - sheet.maximize(); - } else { - sheet.close(); - } - } - }); }; const registerMenuSettings = () => { @@ -91,10 +64,7 @@ const registerMenuSettings = () => { game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Metagaming, { scope: 'world', config: false, - type: DhMetagaming, - onChange: value => { - value.handleChange(); - } + type: DhMetagaming }); game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew, { @@ -202,22 +172,15 @@ const registerNonConfigSettings = () => { type: DhCountdowns }); + game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll, { + scope: 'world', + config: false, + type: DhTagTeamRoll + }); + game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.CompendiumBrowserSettings, { scope: 'world', config: false, type: CompendiumBrowserSettings }); - - game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.SpotlightTracker, { - scope: 'world', - config: false, - type: SpotlightTracker - }); - - game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.ActiveParty, { - scope: 'world', - config: false, - type: String, - default: null - }); }; diff --git a/module/systemRegistration/socket.mjs b/module/systemRegistration/socket.mjs index de9bf00c..173ef02b 100644 --- a/module/systemRegistration/socket.mjs +++ b/module/systemRegistration/socket.mjs @@ -6,9 +6,6 @@ export function handleSocketEvent({ action = null, data = {} } = {}) { case socketEvent.GMUpdate: Hooks.callAll(socketEvent.GMUpdate, data); break; - case socketEvent.GMCreate: - Hooks.callAll(socketEvent.GMCreate, data); - break; case socketEvent.DhpFearUpdate: Hooks.callAll(socketEvent.DhpFearUpdate); break; @@ -18,22 +15,14 @@ export function handleSocketEvent({ action = null, data = {} } = {}) { case socketEvent.DowntimeTrigger: Party.downtimeMoveQuery(data); break; - case socketEvent.TagTeamStart: - Hooks.callAll(CONFIG.DH.HOOKS.hooksConfig.tagTeamStart, data); - break; - case socketEvent.GroupRollStart: - Hooks.callAll(CONFIG.DH.HOOKS.hooksConfig.groupRollStart, data); } } export const socketEvent = { GMUpdate: 'DhGMUpdate', - GMCreate: 'DhGMCreate', Refresh: 'DhRefresh', DhpFearUpdate: 'DhFearUpdate', - DowntimeTrigger: 'DowntimeTrigger', - TagTeamStart: 'DhTagTeamStart', - GroupRollStart: 'DhGroupRollStart' + DowntimeTrigger: 'DowntimeTrigger' }; export const GMUpdateEvent = { @@ -48,7 +37,6 @@ export const GMUpdateEvent = { export const RefreshType = { Countdown: 'DhCoundownRefresh', TagTeamRoll: 'DhTagTeamRollRefresh', - GroupRoll: 'DhGroupRollRefresh', EffectsDisplay: 'DhEffectsDisplayRefresh', Scene: 'DhSceneRefresh', CompendiumBrowser: 'DhCompendiumBrowserRefresh' @@ -60,14 +48,14 @@ export const registerSocketHooks = () => { const document = data.uuid ? await fromUuid(data.uuid) : null; switch (data.action) { case GMUpdateEvent.UpdateDocument: - if (document && data.data) await document.update(data.data); + if (document && data.update) await document.update(data.update); break; case GMUpdateEvent.UpdateEffect: - if (document && data.data) - await game.system.api.fields.ActionFields.EffectsField.applyEffects.call(document, data.data); + if (document && data.update) + await game.system.api.fields.ActionFields.EffectsField.applyEffects.call(document, data.update); break; case GMUpdateEvent.UpdateSetting: - await game.settings.set(CONFIG.DH.id, data.uuid, data.data); + await game.settings.set(CONFIG.DH.id, data.uuid, data.update); break; case GMUpdateEvent.UpdateFear: await game.settings.set( @@ -77,22 +65,22 @@ export const registerSocketHooks = () => { 0, Math.min( game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxFear, - data.data + data.update ) ) ); break; case GMUpdateEvent.UpdateCountdowns: - await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, data.data); + await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, data.update); Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.Countdown }); break; case GMUpdateEvent.UpdateSaveMessage: - const message = game.messages.get(data.data.message); + const message = game.messages.get(data.update.message); if (!message) return; game.system.api.fields.ActionFields.SaveField.updateSaveMessage( - data.data.result, + data.update.result, message, - data.data.token + data.update.token ); break; } @@ -106,17 +94,6 @@ export const registerSocketHooks = () => { } } }); - - Hooks.on(socketEvent.GMCreate, async ({ data, documentType, scene }) => { - if (!game.user.isGM) return; - - switch (documentType) { - default: - const cls = getDocumentClass(documentType); - cls.create(data, { parent: game.scenes.get(scene) }); - break; - } - }); }; export const registerUserQueries = () => { @@ -124,21 +101,18 @@ export const registerUserQueries = () => { CONFIG.queries.reactionRoll = game.system.api.fields.ActionFields.SaveField.rollSaveQuery; }; -export const emitGMUpdate = async (eventName, callback, update, uuid = null, refresh = null) => { - return await emitAsGM(socketEvent.GMUpdate, { action: eventName, callback, data: update, uuid, refresh }); -}; - -export const emitGMCreate = async (documentType, callback, data, scene) => { - return await emitAsGM(socketEvent.GMCreate, { documentType, callback, data, scene }); -}; - -export const emitAsGM = async (event, data = { callback: () => {}, data: {} }) => { +export const emitAsGM = async (eventName, callback, update, uuid = null, refresh = null) => { if (!game.user.isGM) { return await game.socket.emit(`system.${CONFIG.DH.id}`, { - action: event, - data: data + action: socketEvent.GMUpdate, + data: { + action: eventName, + uuid, + update, + refresh + } }); - } else return data.callback(data.data); + } else return callback(update); }; export const emitAsOwner = (eventName, userId, args) => { diff --git a/package-lock.json b/package-lock.json index dee096eb..864d027c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,24 +9,18 @@ "autocompleter": "^9.3.2", "gulp": "^5.0.0", "gulp-less": "^5.0.0", - "gulp-sourcemaps": "^3.0.0", "rollup": "^4.40.0" }, "devDependencies": { - "@eslint/js": "^10.0.1", "@foundryvtt/foundryvtt-cli": "^1.0.2", "@rollup/plugin-commonjs": "^25.0.7", "@rollup/plugin-node-resolve": "^15.2.3", - "@stylistic/eslint-plugin": "^5.10.0", "concurrently": "^8.2.2", - "eslint": "^10.2.1", - "globals": "^17.5.0", - "husky": "^9.1.7", - "lint-staged": "^16.4.0", + "husky": "^9.1.5", + "lint-staged": "^15.2.10", "postcss": "^8.4.32", - "rollup-plugin-postcss": "^4.0.2", - "typescript": "^6.0.3", - "typescript-eslint": "^8.60.1" + "prettier": "^3.5.3", + "rollup-plugin-postcss": "^4.0.2" } }, "node_modules/@babel/runtime": { @@ -38,173 +32,6 @@ "node": ">=6.9.0" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.23.5", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", - "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^3.0.5", - "debug": "^4.3.1", - "minimatch": "^10.2.4" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/config-array/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.5.tgz", - "integrity": "sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^1.2.1" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/core": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", - "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/js": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", - "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "eslint": "^10.0.0" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/@eslint/object-schema": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", - "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.1.tgz", - "integrity": "sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^1.2.1", - "levn": "^0.4.1" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, "node_modules/@foundryvtt/foundryvtt-cli": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@foundryvtt/foundryvtt-cli/-/foundryvtt-cli-1.1.0.tgz", @@ -226,132 +53,6 @@ "node": ">17.0.0" } }, - "node_modules/@gulp-sourcemaps/identity-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-2.0.1.tgz", - "integrity": "sha512-Tb+nSISZku+eQ4X1lAkevcQa+jknn/OVUgZ3XCxEKIsLsqYuPoJwJOPQeaOk75X3WPftb29GWY1eqE7GLsXb1Q==", - "license": "MIT", - "dependencies": { - "acorn": "^6.4.1", - "normalize-path": "^3.0.0", - "postcss": "^7.0.16", - "source-map": "^0.6.0", - "through2": "^3.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/@gulp-sourcemaps/identity-map/node_modules/acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/@gulp-sourcemaps/identity-map/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "license": "ISC" - }, - "node_modules/@gulp-sourcemaps/identity-map/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "license": "MIT", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/@gulp-sourcemaps/identity-map/node_modules/through2": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", - "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "2 || 3" - } - }, - "node_modules/@gulp-sourcemaps/map-sources": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz", - "integrity": "sha512-o/EatdaGt8+x2qpb0vFLC/2Gug/xYPRXb6a+ET1wGYKozKN3krDWC/zZFZAtrzxJHuDL12mwdfEFKcKMNvc55A==", - "license": "MIT", - "dependencies": { - "normalize-path": "^2.0.1", - "through2": "^2.0.3" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/@gulp-sourcemaps/map-sources/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", - "license": "MIT", - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@gulp-sourcemaps/map-sources/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/@gulp-sourcemaps/map-sources/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/@gulp-sourcemaps/map-sources/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/@gulp-sourcemaps/map-sources/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "license": "MIT", - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, "node_modules/@gulpjs/messages": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@gulpjs/messages/-/messages-1.1.0.tgz", @@ -371,72 +72,6 @@ "node": ">=10.13.0" } }, - "node_modules/@humanfs/core": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", - "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/types": "^0.15.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", - "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.2", - "@humanfs/types": "^0.15.0", - "@humanwhocodes/retry": "^0.4.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/types": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", - "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", @@ -771,58 +406,6 @@ "util": "^0.12.4" } }, - "node_modules/@stylistic/eslint-plugin": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.10.0.tgz", - "integrity": "sha512-nPK52ZHvot8Ju/0A4ucSX1dcPV2/1clx0kLcH5wDmrE4naKso7TUC/voUyU1O9OTKTrR6MYip6LP0ogEMQ9jPQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/types": "^8.56.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "estraverse": "^5.3.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "peerDependencies": { - "eslint": "^9.0.0 || ^10.0.0" - } - }, - "node_modules/@stylistic/eslint-plugin/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@stylistic/eslint-plugin/node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", @@ -832,313 +415,17 @@ "node": ">=10.13.0" } }, - "node_modules/@types/esrecurse": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", - "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==" }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/resolve": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", "dev": true }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.60.1.tgz", - "integrity": "sha512-JQ4S5GB0tfjO8BuJ4fcX+HodkzJjYBV+7OJ+wLygaX7OGQ7FudyHL4NSCA6ob+w3Yn+5MkKIozOwQhXeM7opVg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.60.1", - "@typescript-eslint/type-utils": "8.60.1", - "@typescript-eslint/utils": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.60.1", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.60.1.tgz", - "integrity": "sha512-A0M6ua6H252bVjPvvtSgl2QA4+ET9S5Mtkb2GDyTxIhH/C4qDItT7RQNO5PhMC6NXGYXOR9dIalcDDgBKT7oFA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.60.1", - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/typescript-estree": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.1.tgz", - "integrity": "sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.60.1", - "@typescript-eslint/types": "^8.60.1", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.1.tgz", - "integrity": "sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.1.tgz", - "integrity": "sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.60.1.tgz", - "integrity": "sha512-sdwTrpjosW7ANQYJ39ZBF1ZyEMEGVB2UsikrserVM/30a/F1dTLnu9bGxEdosugyu5caigjLrR2qiD11asjI1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/typescript-estree": "8.60.1", - "@typescript-eslint/utils": "8.60.1", - "debug": "^4.4.3", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.1.tgz", - "integrity": "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.1.tgz", - "integrity": "sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.60.1", - "@typescript-eslint/tsconfig-utils": "8.60.1", - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.2.tgz", - "integrity": "sha512-c8jsqUZm3omBOI66G90z1Dyw5z622G8oLG+omfsHBJf3CWQTlOcwOjvOG6wtiNfW6anKm/eA39LMwMtMez2TiQ==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.60.1.tgz", - "integrity": "sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.60.1", - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/typescript-estree": "8.60.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.1.tgz", - "integrity": "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.60.1", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@yaireo/tagify": { "version": "4.35.1", "resolved": "https://registry.npmjs.org/@yaireo/tagify/-/tagify-4.35.1.tgz", @@ -1171,46 +458,6 @@ "node": ">=12" } }, - "node_modules/acorn": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/ansi-colors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", @@ -1223,11 +470,10 @@ } }, "node_modules/ansi-escapes": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", - "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", "dev": true, - "license": "MIT", "dependencies": { "environment": "^1.0.0" }, @@ -1239,11 +485,10 @@ } }, "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -1252,11 +497,10 @@ } }, "node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -1365,18 +609,6 @@ "node": ">= 10.13.0" } }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "license": "(MIT OR Apache-2.0)", - "bin": { - "atob": "bin/atob.js" - }, - "engines": { - "node": ">= 4.5.0" - } - }, "node_modules/autocompleter": { "version": "9.3.2", "resolved": "https://registry.npmjs.org/autocompleter/-/autocompleter-9.3.2.tgz", @@ -1693,7 +925,6 @@ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", "dev": true, - "license": "MIT", "dependencies": { "restore-cursor": "^5.0.0" }, @@ -1705,34 +936,39 @@ } }, "node_modules/cli-truncate": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.2.0.tgz", - "integrity": "sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", "dev": true, - "license": "MIT", "dependencies": { - "slice-ansi": "^8.0.0", - "string-width": "^8.2.0" + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" }, "engines": { - "node": ">=20" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cli-truncate/node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true + }, "node_modules/cli-truncate/node_modules/string-width": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.0.tgz", - "integrity": "sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, - "license": "MIT", "dependencies": { - "get-east-asian-width": "^1.5.0", - "strip-ansi": "^7.1.2" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=20" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -1839,17 +1075,15 @@ "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/commander": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", - "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", "dev": true, - "license": "MIT", "engines": { - "node": ">=20" + "node": ">=18" } }, "node_modules/commondir": { @@ -1965,12 +1199,6 @@ "node": ">= 10.13.0" } }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "license": "MIT" - }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -1985,17 +1213,6 @@ "node": ">= 8" } }, - "node_modules/css": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz", - "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "source-map": "^0.6.1", - "source-map-resolve": "^0.6.0" - } - }, "node_modules/css-declaration-sorter": { "version": "6.4.1", "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", @@ -2167,19 +1384,6 @@ "node": ">=8.0.0" } }, - "node_modules/d": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", - "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", - "license": "ISC", - "dependencies": { - "es5-ext": "^0.10.64", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.12" - } - }, "node_modules/date-fns": { "version": "2.30.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", @@ -2197,11 +1401,10 @@ } }, "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "dev": true, - "license": "MIT", "dependencies": { "ms": "^2.1.3" }, @@ -2214,42 +1417,6 @@ } } }, - "node_modules/debug-fabulous": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/debug-fabulous/-/debug-fabulous-1.1.0.tgz", - "integrity": "sha512-GZqvGIgKNlUnHUPQhepnUZFIMoi3dgZKQBzKDeL2g7oJF9SNAji/AAu36dusFUas0O+pae74lNeoIPHqXWDkLg==", - "license": "MIT", - "dependencies": { - "debug": "3.X", - "memoizee": "0.4.X", - "object-assign": "4.X" - } - }, - "node_modules/debug-fabulous/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -2284,15 +1451,6 @@ "node": ">=0.10.0" } }, - "node_modules/detect-newline": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha512-CwffZFvlJffUg9zZA0uqrjQayUTC8ob94pnr5sFwaVv3IOmkfUHcWH+jXaQK3askE51Cqe8/9Ql/0uXNwqZ8Zg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/dom-serializer": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", @@ -2407,7 +1565,6 @@ "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -2457,58 +1614,6 @@ "node": ">= 0.4" } }, - "node_modules/es5-ext": { - "version": "0.10.64", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", - "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", - "hasInstallScript": true, - "license": "ISC", - "dependencies": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "esniff": "^2.0.1", - "next-tick": "^1.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "license": "MIT", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-symbol": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", - "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", - "license": "ISC", - "dependencies": { - "d": "^1.0.2", - "ext": "^1.7.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "license": "ISC", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -2517,159 +1622,6 @@ "node": ">=6" } }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.2.1.tgz", - "integrity": "sha512-wiyGaKsDgqXvF40P8mDwiUp/KQjE1FdrIEJsM8PZ3XCiniTMXS3OHWWUe5FI5agoCnr8x4xPrTDZuxsBlNHl+Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.2", - "@eslint/config-array": "^0.23.5", - "@eslint/config-helpers": "^0.5.5", - "@eslint/core": "^1.2.1", - "@eslint/plugin-kit": "^0.7.1", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.14.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^9.1.2", - "eslint-visitor-keys": "^5.0.1", - "espree": "^11.2.0", - "esquery": "^1.7.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "minimatch": "^10.2.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", - "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@types/esrecurse": "^4.3.1", - "@types/estree": "^1.0.8", - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/esm": { "version": "3.2.25", "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", @@ -2679,107 +1631,40 @@ "node": ">=6" } }, - "node_modules/esniff": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", - "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", - "license": "ISC", - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.62", - "event-emitter": "^0.3.5", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/espree": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", - "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.16.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^5.0.1" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", - "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, "node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "dev": true }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", - "license": "MIT", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, "node_modules/eventemitter3": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", - "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true + }, + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", "dev": true, - "license": "MIT" + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } }, "node_modules/expand-tilde": { "version": "2.0.2", @@ -2792,15 +1677,6 @@ "node": ">=0.10.0" } }, - "node_modules/ext": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", - "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", - "license": "ISC", - "dependencies": { - "type": "^2.7.2" - } - }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -2818,25 +1694,11 @@ "node": ">=0.10.0" } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, "node_modules/fast-fifo": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==" }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, "node_modules/fast-levenshtein": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-3.0.0.tgz", @@ -2861,37 +1723,6 @@ "reusify": "^1.0.4" } }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -2903,23 +1734,6 @@ "node": ">=8" } }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/findup-sync": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-5.0.0.tgz", @@ -2957,27 +1771,6 @@ "node": ">= 10.13.0" } }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", - "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", - "dev": true, - "license": "ISC" - }, "node_modules/for-each": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", @@ -3069,11 +1862,10 @@ } }, "node_modules/get-east-asian-width": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", - "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", + "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -3118,6 +1910,18 @@ "node": ">= 0.4" } }, + "node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", @@ -3229,19 +2033,6 @@ "which": "bin/which" } }, - "node_modules/globals": { - "version": "17.5.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.5.0.tgz", - "integrity": "sha512-qoV+HK2yFl/366t2/Cb3+xxPUo5BuMynomoDmiaZBIdbs+0pYbjfZU+twLhGKp4uCZ/+NbtpVepH5bGCxRyy2g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/glogg": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/glogg/-/glogg-2.2.0.tgz", @@ -3438,86 +2229,6 @@ "node": ">=6" } }, - "node_modules/gulp-sourcemaps": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-3.0.0.tgz", - "integrity": "sha512-RqvUckJkuYqy4VaIH60RMal4ZtG0IbQ6PXMNkNsshEGJ9cldUPRb/YCgboYae+CLAs1HQNb4ADTKCx65HInquQ==", - "license": "ISC", - "dependencies": { - "@gulp-sourcemaps/identity-map": "^2.0.1", - "@gulp-sourcemaps/map-sources": "^1.0.0", - "acorn": "^6.4.1", - "convert-source-map": "^1.0.0", - "css": "^3.0.0", - "debug-fabulous": "^1.0.0", - "detect-newline": "^2.0.0", - "graceful-fs": "^4.0.0", - "source-map": "^0.6.0", - "strip-bom-string": "^1.0.0", - "through2": "^2.0.0" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/gulp-sourcemaps/node_modules/acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/gulp-sourcemaps/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "license": "MIT" - }, - "node_modules/gulp-sourcemaps/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/gulp-sourcemaps/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/gulp-sourcemaps/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/gulp-sourcemaps/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "license": "MIT", - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, "node_modules/gulplog": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-2.2.0.tgz", @@ -3598,12 +2309,20 @@ "node": ">=0.10.0" } }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, "node_modules/husky": { "version": "9.1.7", "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", "dev": true, - "license": "MIT", "bin": { "husky": "bin.js" }, @@ -3662,16 +2381,6 @@ } ] }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, "node_modules/image-size": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", @@ -3714,16 +2423,6 @@ "node": ">=8" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -3872,16 +2571,12 @@ } }, "node_modules/is-fullwidth-code-point": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", - "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.3.1" - }, "engines": { - "node": ">=18" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -3946,12 +2641,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "license": "MIT" - }, "node_modules/is-reference": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", @@ -3990,6 +2679,18 @@ "node": ">=0.10.0" } }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-typed-array": { "version": "1.1.15", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", @@ -4037,12 +2738,6 @@ "node": ">=0.10.0" } }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -4074,37 +2769,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, "node_modules/last-run": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/last-run/-/last-run-2.0.0.tgz", @@ -4168,20 +2832,6 @@ "node": ">=12" } }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/lie": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", @@ -4208,38 +2858,52 @@ "node": ">=10.13.0" } }, - "node_modules/lint-staged": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.4.0.tgz", - "integrity": "sha512-lBWt8hujh/Cjysw5GYVmZpFHXDCgZzhrOm8vbcUdobADZNOK/bRshr2kM3DfgrrtR1DQhfupW9gnIXOfiFi+bw==", + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lint-staged": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.5.2.tgz", + "integrity": "sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w==", "dev": true, - "license": "MIT", "dependencies": { - "commander": "^14.0.3", - "listr2": "^9.0.5", - "picomatch": "^4.0.3", + "chalk": "^5.4.1", + "commander": "^13.1.0", + "debug": "^4.4.0", + "execa": "^8.0.1", + "lilconfig": "^3.1.3", + "listr2": "^8.2.5", + "micromatch": "^4.0.8", + "pidtree": "^0.6.0", "string-argv": "^0.3.2", - "tinyexec": "^1.0.4", - "yaml": "^2.8.2" + "yaml": "^2.7.0" }, "bin": { "lint-staged": "bin/lint-staged.js" }, "engines": { - "node": ">=20.17" + "node": ">=18.12.0" }, "funding": { "url": "https://opencollective.com/lint-staged" } }, "node_modules/listr2": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", - "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.3.3.tgz", + "integrity": "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==", "dev": true, - "license": "MIT", "dependencies": { - "cli-truncate": "^5.0.0", + "cli-truncate": "^4.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", "log-update": "^6.1.0", @@ -4247,7 +2911,7 @@ "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">=20.0.0" + "node": ">=18.0.0" } }, "node_modules/loader-utils": { @@ -4268,22 +2932,6 @@ "lie": "3.1.1" } }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -4313,7 +2961,6 @@ "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", "dev": true, - "license": "MIT", "dependencies": { "ansi-escapes": "^7.0.0", "cli-cursor": "^5.0.0", @@ -4328,12 +2975,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-update/node_modules/slice-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", - "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", + "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", + "dev": true, + "dependencies": { + "get-east-asian-width": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", + "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" @@ -4357,15 +3018,6 @@ "loose-envify": "cli.js" } }, - "node_modules/lru-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", - "license": "MIT", - "dependencies": { - "es5-ext": "~0.10.2" - } - }, "node_modules/magic-string": { "version": "0.30.17", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", @@ -4411,24 +3063,11 @@ "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", "dev": true }, - "node_modules/memoizee": { - "version": "0.4.17", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.17.tgz", - "integrity": "sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==", - "license": "ISC", - "dependencies": { - "d": "^1.0.2", - "es5-ext": "^0.10.64", - "es6-weak-map": "^2.0.3", - "event-emitter": "^0.3.5", - "is-promise": "^2.2.2", - "lru-queue": "^0.1.0", - "next-tick": "^1.1.0", - "timers-ext": "^0.1.7" - }, - "engines": { - "node": ">=0.12" - } + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true }, "node_modules/micromatch": { "version": "4.0.8", @@ -4465,12 +3104,23 @@ "node": ">=4" } }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/mimic-function": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -4517,7 +3167,8 @@ "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true }, "node_modules/mute-stdout": { "version": "2.0.0", @@ -4551,13 +3202,6 @@ "integrity": "sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g==", "dev": true }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, "node_modules/nedb-promises": { "version": "6.2.3", "resolved": "https://registry.npmjs.org/nedb-promises/-/nedb-promises-6.2.3.tgz", @@ -4583,12 +3227,6 @@ "node": ">= 4.4.x" } }, - "node_modules/next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", - "license": "ISC" - }, "node_modules/node-gyp-build": { "version": "4.8.4", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", @@ -4637,6 +3275,33 @@ "node": ">= 10.13.0" } }, + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -4691,46 +3356,20 @@ } }, "node_modules/onetime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", "dev": true, - "license": "MIT", "dependencies": { - "mimic-function": "^5.0.0" + "mimic-fn": "^4.0.0" }, "engines": { - "node": ">=18" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/optionator/node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, "node_modules/p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -4740,38 +3379,6 @@ "node": ">=4" } }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/p-queue": { "version": "6.6.2", "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", @@ -4835,16 +3442,6 @@ "node": ">=0.10.0" } }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -4885,11 +3482,10 @@ "dev": true }, "node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -4897,6 +3493,18 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", @@ -5532,22 +4140,21 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "node_modules/prettier": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", "dev": true, - "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, "engines": { - "node": ">= 0.8.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "license": "MIT" - }, "node_modules/promise.series": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/promise.series/-/promise.series-0.2.0.tgz", @@ -5574,16 +4181,6 @@ "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", "optional": true }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -5762,7 +4359,6 @@ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", "dev": true, - "license": "MIT", "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" @@ -5774,6 +4370,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -5787,8 +4398,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/rollup": { "version": "4.44.0", @@ -6068,7 +4678,6 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, - "license": "ISC", "engines": { "node": ">=14" }, @@ -6077,17 +4686,16 @@ } }, "node_modules/slice-ansi": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-8.0.0.tgz", - "integrity": "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", "dev": true, - "license": "MIT", "dependencies": { - "ansi-styles": "^6.2.3", - "is-fullwidth-code-point": "^5.1.0" + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" }, "engines": { - "node": ">=20" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/slice-ansi?sponsor=1" @@ -6097,6 +4705,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -6110,17 +4719,6 @@ "node": ">=0.10.0" } }, - "node_modules/source-map-resolve": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", - "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", - "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", - "license": "MIT", - "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0" - } - }, "node_modules/sparkles": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-2.1.0.tgz", @@ -6231,13 +4829,12 @@ } }, "node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, - "license": "MIT", "dependencies": { - "ansi-regex": "^6.2.2" + "ansi-regex": "^6.0.1" }, "engines": { "node": ">=12" @@ -6246,13 +4843,16 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/strip-bom-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", - "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", - "license": "MIT", + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/style-inject": { @@ -6374,46 +4974,6 @@ "readable-stream": "3" } }, - "node_modules/timers-ext": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.8.tgz", - "integrity": "sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==", - "license": "ISC", - "dependencies": { - "es5-ext": "^0.10.64", - "next-tick": "^1.1.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/tinyexec": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.1.tgz", - "integrity": "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -6445,81 +5005,11 @@ "tree-kill": "cli.js" } }, - "node_modules/ts-api-utils": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", - "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12" - }, - "peerDependencies": { - "typescript": ">=4.8.4" - } - }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" }, - "node_modules/type": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", - "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", - "license": "ISC" - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/typescript": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", - "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.60.1.tgz", - "integrity": "sha512-6m5hkkRAp8lKvhVpcprAIn5KkehQEh+47oHH2VGnExEh7dhNxXlg6GPAOIu6TxbVQxhebrJDvjl3020ooiWCMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.60.1", - "@typescript-eslint/parser": "8.60.1", - "@typescript-eslint/typescript-estree": "8.60.1", - "@typescript-eslint/utils": "8.60.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, "node_modules/unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", @@ -6580,16 +5070,6 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, "node_modules/util": { "version": "0.12.5", "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", @@ -6742,22 +5222,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", @@ -6771,18 +5240,16 @@ } }, "node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true, - "license": "MIT" + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true }, "node_modules/wrap-ansi/node_modules/string-width": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, - "license": "MIT", "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", @@ -6800,15 +5267,6 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -6818,19 +5276,15 @@ } }, "node_modules/yaml": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", - "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", "dev": true, - "license": "ISC", "bin": { "yaml": "bin.mjs" }, "engines": { "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" } }, "node_modules/yargs": { @@ -6859,19 +5313,6 @@ "engines": { "node": ">=12" } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } } } } diff --git a/package.json b/package.json index ede90401..183d2de2 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,6 @@ "autocompleter": "^9.3.2", "gulp": "^5.0.0", "gulp-less": "^5.0.0", - "gulp-sourcemaps": "^3.0.0", "rollup": "^4.40.0" }, "scripts": { @@ -18,28 +17,20 @@ "pullYMLtoLDB": "node ./tools/pullYMLtoLDB.mjs", "pullYMLtoLDBBuild": "node ./tools/pullYMLtoLDB.mjs --build", "createSymlink": "node ./tools/create-symlink.mjs", - "setup:dev": "node ./tools/dev-setup.mjs", - "lint": "eslint", - "lint:fix": "eslint --fix", - "prepare": "husky" + "setup:dev": "node ./tools/dev-setup.mjs" }, "devDependencies": { - "@eslint/js": "^10.0.1", "@foundryvtt/foundryvtt-cli": "^1.0.2", "@rollup/plugin-commonjs": "^25.0.7", "@rollup/plugin-node-resolve": "^15.2.3", - "@stylistic/eslint-plugin": "^5.10.0", "concurrently": "^8.2.2", - "eslint": "^10.2.1", - "globals": "^17.5.0", - "husky": "^9.1.7", - "lint-staged": "^16.4.0", + "husky": "^9.1.5", + "lint-staged": "^15.2.10", "postcss": "^8.4.32", - "rollup-plugin-postcss": "^4.0.2", - "typescript": "^6.0.3", - "typescript-eslint": "^8.60.1" + "prettier": "^3.5.3", + "rollup-plugin-postcss": "^4.0.2" }, "lint-staged": { - "**/*": "eslint --fix" + "**/*": "prettier --write --ignore-unknown" } } diff --git a/src/packs/adversaries/adversary_Acid_Burrower_89yAh30vaNQOALlz.json b/src/packs/adversaries/adversary_Acid_Burrower_89yAh30vaNQOALlz.json index d3c8c955..e2b3a444 100644 --- a/src/packs/adversaries/adversary_Acid_Burrower_89yAh30vaNQOALlz.json +++ b/src/packs/adversaries/adversary_Acid_Burrower_89yAh30vaNQOALlz.json @@ -91,8 +91,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -118,7 +118,7 @@ }, "base": false } - }, + ], "includeBase": false }, "_id": "TCKVaVweyJzhEArX", @@ -169,9 +169,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -222,7 +225,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -248,8 +251,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -317,7 +319,7 @@ "_id": "ctXYwil2D1zfsekT", "img": "icons/magic/earth/barrier-stone-explosion-red.webp", "system": { - "description": "

Mark a Stress to have the @Lookup[@name] burst out of the ground. All creatures within Very Close range must succeed on an Agility Reaction Roll or be knocked over, making them Vulnerable until they next act.

", + "description": "

Mark a Stress to have the @Lookup[@name] burst out of the ground. All creatures within Very Close range must succeed on an Agility Reaction Roll or be knocked over, making them Vulnerable until they next act.

@Template[type:emanation|range:vc]

", "resource": null, "actions": { "4ppSeiTdbqnMzWAs": { @@ -341,9 +343,8 @@ "recovery": null }, "damage": { - "parts": {}, - "includeBase": false, - "groupAttack": "" + "parts": [], + "includeBase": false }, "target": { "type": "any", @@ -377,16 +378,7 @@ }, "name": "Roll Save", "img": "icons/magic/earth/barrier-stone-explosion-red.webp", - "range": "veryClose", - "areas": [ - { - "name": "Earth Eruption", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "veryClose" } }, "originItemType": null, @@ -408,18 +400,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "act" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -431,16 +423,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!89yAh30vaNQOALlz.ctXYwil2D1zfsekT.9PsnogEPsp1OOK64" } ], @@ -479,8 +461,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -507,7 +489,7 @@ } } }, - "armor": { + { "value": { "custom": { "enabled": true, @@ -532,7 +514,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -589,7 +571,7 @@ "_id": "aNIVT5LKhwLyjKpI", "img": "icons/magic/acid/dissolve-drip-droplet-smoke.webp", "system": { - "description": "

When the @Lookup[@name] takes Severe damage, all creatures within Close range are bathed in their acidic blood, taking 1d10 physical damage. This splash covers the ground within Very Close range with blood, and all creatures other than the @Lookup[@name] who move through it take 1d6 physical damage.

", + "description": "

When the @Lookup[@name] takes Severe damage, all creatures within Close range are bathed in their acidic blood, taking 1d10 physical damage. This splash covers the ground within Very Close range with blood, and all creatures other than the @Lookup[@name] who move through it take 1d6 physical damage.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "XbtTzOBvlTaxOKTy": { @@ -606,8 +588,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -634,9 +616,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -645,23 +626,7 @@ "effects": [], "name": "Splash", "img": "icons/magic/acid/dissolve-drip-droplet-smoke.webp", - "range": "close", - "areas": [ - { - "name": "Acid Bath: Damage Area", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - }, - { - "name": "Acid Ground", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "close" }, "xpcp1ECTWF20kxve": { "type": "damage", @@ -677,8 +642,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -705,7 +670,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -715,8 +680,7 @@ "effects": [], "name": "Acid Ground", "img": "icons/magic/acid/dissolve-pool-bubbles.webp", - "range": "", - "areas": [] + "range": "" } }, "originItemType": null, diff --git a/src/packs/adversaries/adversary_Adult_Flickerfly_G7jiltRjgvVhZewm.json b/src/packs/adversaries/adversary_Adult_Flickerfly_G7jiltRjgvVhZewm.json index ecb93d1b..16fb61d8 100644 --- a/src/packs/adversaries/adversary_Adult_Flickerfly_G7jiltRjgvVhZewm.json +++ b/src/packs/adversaries/adversary_Adult_Flickerfly_G7jiltRjgvVhZewm.json @@ -75,8 +75,8 @@ }, "range": "veryClose", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -102,7 +102,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -132,9 +132,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -185,7 +188,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -211,8 +214,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -374,7 +376,7 @@ "name": "Whirlwind", "type": "feature", "system": { - "description": "

Spend a Fear to whirl, making an attack against all targets within Very Close range. Targets the @Lookup[@name] succeeds against take 3d8 direct physical damage.

", + "description": "

Spend a Fear to whirl, making an attack against all targets within Very Close range. Targets the @Lookup[@name] succeeds against take 3d8 direct physical damage.

@Template[type:emanation|range:vc]

", "resource": null, "actions": { "RV1wKufKrMPN6MOo": { @@ -398,8 +400,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -425,10 +427,9 @@ } } } - }, + ], "includeBase": false, - "direct": true, - "groupAttack": "" + "direct": true }, "target": { "type": "any", @@ -457,16 +458,7 @@ }, "name": "Attack", "img": "icons/skills/melee/strike-slashes-orange.webp", - "range": "veryClose", - "areas": [ - { - "name": "Whirlwind", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "veryClose" } }, "originItemType": null, @@ -492,7 +484,7 @@ "name": "Mind Dance", "type": "feature", "system": { - "description": "

Mark a Stress to create a magically dazzling display that grapples the minds of nearby foes. All targets within Close range must make an Instinct Reaction Roll. For each target who failed, you gain a Fear and the @Lookup[@name] learns one of the target’s fears.

", + "description": "

Mark a Stress to create a magically dazzling display that grapples the minds of nearby foes. All targets within Close range must make an Instinct Reaction Roll. For each target who failed, you gain a Fear and the @Lookup[@name] learns one of the target’s fears.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "GNwsDlCabx3fiG4g": { @@ -516,9 +508,8 @@ "recovery": null }, "damage": { - "parts": {}, - "includeBase": false, - "groupAttack": "" + "parts": [], + "includeBase": false }, "target": { "type": "any", @@ -547,16 +538,7 @@ }, "name": "Roll Save", "img": "icons/magic/light/explosion-glow-spiral-yellow.webp", - "range": "close", - "areas": [ - { - "name": "Mind Dance", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "originItemType": null, @@ -582,14 +564,14 @@ "name": "Hallucinatory Breath", "type": "feature", "system": { - "description": "

Countdown (Loop 1d6). When the @Lookup[@name] takes damage for the first time, activate the countdown. When it triggers, the @Lookup[@name] breathes hallucinatory gas on all targets in front of them up to Far range. Targets must make an Instinct Reaction Roll or be tormented by fearful hallucinations. Targets whose fears are known to the @Lookup[@name] have disadvantage on this roll. Targets who fail lose 2 Hope and take 3d8+3 direct magic damage.

", + "description": "

Countdown (Loop 1d6). When the @Lookup[@name] takes damage for the first time, activate the countdown. When it triggers, the @Lookup[@name] breathes hallucinatory gas on all targets in front of them up to Far range. Targets must make an Instinct Reaction Roll or be tormented by fearful hallucinations. Targets whose fears are known to the @Lookup[@name] have disadvantage on this roll. Targets who fail lose 2 Hope and take 3d8+3 direct magic damage.

@Template[type:inFront|range:f]

", "resource": null, "actions": { "YOyKyKGTUEWkMmJe": { "type": "attack", "_id": "YOyKyKGTUEWkMmJe", "systemPath": "actions", - "description": "", + "description": "

The @Lookup[@name] breathes hallucinatory gas on all targets in front of them up to Far range. Targets must make an Instinct Reaction Roll or be tormented by fearful hallucinations. Targets whose fears are known to the @Lookup[@name] have disadvantage on this roll. Targets who fail lose 2 Hope and take 3d8+3 direct magic damage.

@Template[type:inFront|range:f]

", "chatDisplay": true, "actionType": "action", "cost": [], @@ -599,8 +581,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -626,7 +608,7 @@ } } }, - "hope": { + { "value": { "custom": { "enabled": true, @@ -651,9 +633,8 @@ }, "type": [] } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -682,16 +663,7 @@ }, "name": "Roll Save", "img": "icons/magic/air/fog-gas-smoke-purple.webp", - "range": "far", - "areas": [ - { - "name": "Hallucinatory Breath", - "type": "placed", - "shape": "inFront", - "size": "far", - "effects": [] - } - ] + "range": "far" }, "lBhmLc33pcXzJHT3": { "type": "countdown", diff --git a/src/packs/adversaries/adversary_Apprentice_Assassin_vNIbYQ4YSzNf0WPE.json b/src/packs/adversaries/adversary_Apprentice_Assassin_vNIbYQ4YSzNf0WPE.json index 12ec35ae..23f1f339 100644 --- a/src/packs/adversaries/adversary_Apprentice_Assassin_vNIbYQ4YSzNf0WPE.json +++ b/src/packs/adversaries/adversary_Apprentice_Assassin_vNIbYQ4YSzNf0WPE.json @@ -72,8 +72,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -100,7 +100,7 @@ }, "base": false } - } + ] }, "img": "icons/weapons/daggers/dagger-bone-black.webp", "type": "attack", @@ -131,9 +131,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -184,7 +187,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -210,8 +213,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -247,95 +249,33 @@ "description": "

Spend a Fear to choose a target and spotlight all @Lookup[@name]s within Close range of them. Those Minions move into Melee range of the target and make one shared attack roll. On a success, they deal @Lookup[@system.attack.damageFormula] physical damage each. Combine this damage.

", "resource": null, "actions": { - "SrNyZgPvCXMpbCLG": { - "type": "attack", - "_id": "SrNyZgPvCXMpbCLG", + "vgguNWz8vG8aoLXR": { + "type": "effect", + "_id": "vgguNWz8vG8aoLXR", "systemPath": "actions", - "baseAction": false, "description": "", "chatDisplay": true, - "originItem": { - "type": "itemCollection" - }, "actionType": "action", - "triggers": [], "cost": [ { "scalable": false, "key": "fear", "value": 1, - "itemId": null, - "step": null, - "consumeOnSuccess": false + "step": null } ], "uses": { "value": null, "max": "", - "recovery": null, - "consumeOnSuccess": false - }, - "damage": { - "parts": { - "hitPoints": { - "applyTo": "hitPoints", - "resultBased": false, - "value": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": true, - "formula": "4" - } - }, - "valueAlt": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": false, - "formula": "" - } - }, - "base": false, - "type": [ - "physical" - ] - } - }, - "includeBase": false, - "direct": false, - "groupAttack": "close" + "recovery": null }, + "effects": [], "target": { "type": "any", "amount": null }, - "effects": [], - "roll": { - "type": "attack", - "trait": null, - "difficulty": null, - "bonus": null, - "advState": "neutral", - "diceRolling": { - "multiplier": "prof", - "flatMultiplier": 1, - "dice": "d6", - "compare": null, - "treshold": null - }, - "useDefault": false - }, - "save": { - "trait": null, - "difficulty": null, - "damageMod": "none" - }, "name": "Spend Fear", + "img": "icons/magic/unholy/orb-hands-pink.webp", "range": "" } }, diff --git a/src/packs/adversaries/adversary_Arch_Necromancer_WPEOIGfclNJxWb87.json b/src/packs/adversaries/adversary_Arch_Necromancer_WPEOIGfclNJxWb87.json index 5da74eb3..d4e506cb 100644 --- a/src/packs/adversaries/adversary_Arch_Necromancer_WPEOIGfclNJxWb87.json +++ b/src/packs/adversaries/adversary_Arch_Necromancer_WPEOIGfclNJxWb87.json @@ -85,8 +85,8 @@ }, "range": "far", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -112,7 +112,7 @@ }, "base": false } - } + ] }, "img": "icons/magic/unholy/beam-ringed-impact-purple.webp", "type": "attack", @@ -143,9 +143,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -196,7 +199,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -222,8 +225,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -254,7 +256,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -310,7 +312,7 @@ "name": "Beam Of Decay", "type": "feature", "system": { - "description": "

Mark 2 Stress to cause all targets within Far range to make a Strength Reaction Roll. Targets who fail take 2d20+12 magic damage and you gain a Fear. Targets who succeed take half damage. A target who marks 2 or more HP must also mark 2 Stress and becomes Vulnerable until they roll with Hope.

", + "description": "

Mark 2 Stress to cause all targets within Far range to make a Strength Reaction Roll. Targets who fail take 2d20+12 magic damage and you gain a Fear. Targets who succeed take half damage. A target who marks 2 or more HP must also mark 2 Stress and becomes Vulnerable until they roll with Hope.

@Template[type:emanation|range:f]

", "resource": null, "actions": { "vaXLESD4sRkQ3Ahn": { @@ -334,8 +336,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -361,9 +363,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -397,16 +398,7 @@ }, "name": "Roll Save", "img": "icons/magic/unholy/projectile-missile-green.webp", - "range": "far", - "areas": [ - { - "name": "Beam Of Decay", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "far" }, "ME8AMAjgTAChHa3C": { "type": "healing", @@ -422,8 +414,8 @@ "recovery": null }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -448,7 +440,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -496,19 +488,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until you roll with Hope.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Vulnerable until you roll with Hope.

", "tint": "#ffffff", @@ -520,16 +511,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!WPEOIGfclNJxWb87.4EECsXzHFG0RoIg0.KGdf2eqcXkdigg0u" } ], @@ -627,7 +608,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -700,8 +681,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -727,7 +708,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Archer_Guard_JRhrrEg5UroURiAD.json b/src/packs/adversaries/adversary_Archer_Guard_JRhrrEg5UroURiAD.json index 965c5168..5a13b3d9 100644 --- a/src/packs/adversaries/adversary_Archer_Guard_JRhrrEg5UroURiAD.json +++ b/src/packs/adversaries/adversary_Archer_Guard_JRhrrEg5UroURiAD.json @@ -80,8 +80,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - } + ] }, "img": "icons/weapons/bows/longbow-recurve-leather-brown.webp", "type": "attack", @@ -246,8 +246,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -273,7 +273,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Archer_Squadron_0ts6CGd93lLqGZI5.json b/src/packs/adversaries/adversary_Archer_Squadron_0ts6CGd93lLqGZI5.json index 1e45b90a..5b15bc09 100644 --- a/src/packs/adversaries/adversary_Archer_Squadron_0ts6CGd93lLqGZI5.json +++ b/src/packs/adversaries/adversary_Archer_Squadron_0ts6CGd93lLqGZI5.json @@ -68,8 +68,8 @@ "description": "

A group of trained archers bearing massive bows.

", "attack": { "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -95,7 +95,7 @@ "resultBased": false, "base": false } - } + ] }, "name": "Longbow", "img": "icons/weapons/bows/longbow-recurve-leather-brown.webp", @@ -132,9 +132,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -185,7 +188,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -211,8 +214,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -244,7 +246,7 @@ "name": "Focused Volley", "type": "feature", "system": { - "description": "

Spend a Fear to target a point within Far range. Make an attack with advantage against all targets within Close range of that point. Targets the @Lookup[@name] succeeds against take 1d10+4 physical damage.

", + "description": "

Spend a Fear to target a point within Far range. Make an attack with advantage against all targets within Close range of that point. Targets the @Lookup[@name] succeeds against take 1d10+4 physical damage.

@Template[type:circle|range:c]

", "resource": null, "actions": { "uG7Hl2DqaT69aNs1": { @@ -268,8 +270,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -293,9 +295,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -324,16 +325,7 @@ }, "name": "Attack", "img": "icons/skills/ranged/arrows-flying-triple-brown.webp", - "range": "far", - "areas": [ - { - "name": "Focused Volley", - "type": "placed", - "shape": "circle", - "size": "close", - "effects": [] - } - ] + "range": "far" } }, "originItemType": null, @@ -359,7 +351,7 @@ "name": "Supressing Fire", "type": "feature", "system": { - "description": "

Mark a Stress to target a point within Far range. Until the next roll with Fear, a creature who moves within Close range of that point must make an Agility Reaction Roll. On a failure, they take 2d6+3 physical damage. On a success, they take half damage.

", + "description": "

Mark a Stress to target a point within Far range. Until the next roll with Fear, a creature who moves within Close range of that point must make an Agility Reaction Roll. On a failure, they take 2d6+3 physical damage. On a success, they take half damage.

@Template[type:circle|range:c]

", "resource": null, "actions": { "mH6mmJIMM1fwzePt": { @@ -376,8 +368,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -401,9 +393,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -432,16 +423,7 @@ }, "name": "Agility Roll", "img": "icons/skills/ranged/arrows-flying-salvo-blue.webp", - "range": "", - "areas": [ - { - "name": "Supressing Fire", - "type": "placed", - "shape": "circle", - "size": "close", - "effects": [] - } - ] + "range": "" } }, "originItemType": null, diff --git a/src/packs/adversaries/adversary_Assassin_Poisoner_h5RuhzGL17dW5FBT.json b/src/packs/adversaries/adversary_Assassin_Poisoner_h5RuhzGL17dW5FBT.json index c1bce57b..8b553c83 100644 --- a/src/packs/adversaries/adversary_Assassin_Poisoner_h5RuhzGL17dW5FBT.json +++ b/src/packs/adversaries/adversary_Assassin_Poisoner_h5RuhzGL17dW5FBT.json @@ -81,8 +81,8 @@ }, "range": "close", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -108,7 +108,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -138,9 +138,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -191,7 +194,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -217,8 +220,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -275,21 +277,20 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until you clear a HP.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

Vulnerable until you clear a HP.

", + "description": "

Vulnerable until you clear a HP.

", "tint": "#ffffff", "statuses": [ "vulnerable" @@ -299,16 +300,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!h5RuhzGL17dW5FBT.Fz2lnUEeBxsDpx0G.2iBVUGHtGW3I9VIj" } ], @@ -397,7 +388,7 @@ "name": "Fumigation", "type": "feature", "system": { - "description": "

Drop a smoke bomb that fills the air within Close range with smoke, Dizzying all targets in this area. Dizzied targets have disadvantage on their next action roll, then clear the condition.

", + "description": "

Drop a smoke bomb that fills the air within Close range with smoke, Dizzying all targets in this area. Dizzied targets have disadvantage on their next action roll, then clear the condition.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "sp7RfJRQJsEUm09m": { @@ -425,16 +416,7 @@ }, "name": "Drop Bomb", "img": "icons/magic/air/fog-gas-smoke-green.webp", - "range": "close", - "areas": [ - { - "name": "Fumigation", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "originItemType": null, @@ -457,15 +439,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [] + } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Dizzied targets have disadvantage on their next action roll, then clear the condition.

", "tint": "#ffffff", @@ -475,9 +460,6 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!h5RuhzGL17dW5FBT.lAmiK8wVxjyHwKlp.yP4ot8VqS56RnxnE" } ], diff --git a/src/packs/adversaries/adversary_Battle_Box_dgH3fW9FTYLaIDvS.json b/src/packs/adversaries/adversary_Battle_Box_dgH3fW9FTYLaIDvS.json index be47829b..96a1b752 100644 --- a/src/packs/adversaries/adversary_Battle_Box_dgH3fW9FTYLaIDvS.json +++ b/src/packs/adversaries/adversary_Battle_Box_dgH3fW9FTYLaIDvS.json @@ -80,8 +80,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - } + ] }, "range": "melee", "type": "attack", @@ -138,9 +138,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -191,7 +194,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -217,8 +220,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -307,7 +309,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -380,8 +382,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -407,7 +409,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -463,7 +465,7 @@ "name": "Fire Jets", "type": "feature", "system": { - "description": "

The @Lookup[@name] shoots into the air, spinning and releasing jets of flame. Make an attack against all targets within Close range. Targets the @Lookup[@name] succeeds against take 2d8 physical damage.

", + "description": "

The @Lookup[@name] shoots into the air, spinning and releasing jets of flame. Make an attack against all targets within Close range. Targets the @Lookup[@name] succeeds against take 2d8 physical damage.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "hRAKaOdzQXLYBNVV": { @@ -480,8 +482,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -507,9 +509,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -538,16 +539,7 @@ }, "name": "Attack", "img": "icons/magic/fire/explosion-embers-orange.webp", - "range": "close", - "areas": [ - { - "name": "Fire Jets", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "originItemType": null, @@ -573,7 +565,7 @@ "name": "Trample", "type": "feature", "system": { - "description": "

The @Lookup[@name] rockets around erratically. Make an attack against all PCs within Close range. Targets the @Lookup[@name] succeeds against take 1d6+5 physical damage and are Vulnerable until their next roll with Hope.

", + "description": "

The @Lookup[@name] rockets around erratically. Make an attack against all PCs within Close range. Targets the @Lookup[@name] succeeds against take 1d6+5 physical damage and are Vulnerable until their next roll with Hope.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "IOgPMu12Xnn33TfG": { @@ -590,8 +582,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -617,9 +609,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -653,16 +644,7 @@ }, "name": "Attack", "img": "icons/skills/movement/arrow-upward-yellow.webp", - "range": "close", - "areas": [ - { - "name": "Trample", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "originItemType": null, @@ -685,21 +667,20 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until their next roll with Hope.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

Vulnerable until your next roll with Hope.

", + "description": "

Vulnerable until your next roll with Hope.

", "tint": "#ffffff", "statuses": [ "vulnerable" @@ -709,16 +690,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!dgH3fW9FTYLaIDvS.XtnByqUr9AuYU9Ip.9NQcCXMhjyBReJRd" } ], @@ -738,7 +709,7 @@ "name": "Shocking Gas", "type": "feature", "system": { - "description": "

The @Lookup[@name] sprays out a silver gas sparking with lightning. All targets within Close range must succeed on a Finesse Reaction Roll or mark 3 Stress.

", + "description": "

The @Lookup[@name] sprays out a silver gas sparking with lightning. All targets within Close range must succeed on a Finesse Reaction Roll or mark 3 Stress.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "ky4OMl558J5wCbDp": { @@ -755,8 +726,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -781,9 +752,8 @@ }, "type": [] } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -812,16 +782,7 @@ }, "name": "Roll Save", "img": "icons/magic/lightning/bolt-strike-embers-teal.webp", - "range": "close", - "areas": [ - { - "name": "Shocking Gas", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "originItemType": null, @@ -847,7 +808,7 @@ "name": "Stunning Clap", "type": "feature", "system": { - "description": "

The @Lookup[@name] leaps and their sides clap, creating a small sonic boom. All targets within Very Close range must succeed on a Strength Reaction Roll or become Vulnerable until the cube is defeated.

", + "description": "

The @Lookup[@name] leaps and their sides clap, creating a small sonic boom. All targets within Very Close range must succeed on a Strength Reaction Roll or become Vulnerable until the cube is defeated.

@Template[type:emanation|range:vc]

", "resource": null, "actions": { "LQtopkrtSlCQ5MAr": { @@ -864,9 +825,8 @@ "recovery": null }, "damage": { - "parts": {}, - "includeBase": false, - "groupAttack": "" + "parts": [], + "includeBase": false }, "target": { "type": "any", @@ -900,16 +860,7 @@ }, "name": "Roll Save", "img": "icons/magic/sonic/explosion-impact-shock-wave.webp", - "range": "veryClose", - "areas": [ - { - "name": "Stunning Clap", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "veryClose" } }, "originItemType": null, @@ -932,21 +883,20 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until the cube is defeated.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

Vulnerable until the cube is defeated.

", + "description": "

Vulnerable until the cube is defeated.

", "tint": "#ffffff", "statuses": [ "vulnerable" @@ -956,16 +906,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!dgH3fW9FTYLaIDvS.ijIaKjroxq3xZd9Z.S7kJlhnV8Nexzi8l" } ], @@ -985,7 +925,7 @@ "name": "Psionic Whine", "type": "feature", "system": { - "description": "

The @Lookup[@name] releases a cluster of mechanical bees whose buzz rattles mortal minds. All targets within Close range must succeed on a Presence Reaction Roll or take 2d4+9 direct magic damage.

", + "description": "

The @Lookup[@name] releases a cluster of mechanical bees whose buzz rattles mortal minds. All targets within Close range must succeed on a Presence Reaction Roll or take 2d4+9 direct magic damage.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "3R3pGOUj4rHaUzPK": { @@ -1002,8 +942,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -1029,9 +969,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -1060,16 +999,7 @@ }, "name": "Bees!", "img": "icons/creatures/invertebrates/wasp-swarm-tan.webp", - "range": "close", - "areas": [ - { - "name": "Psionic Whine", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "originItemType": null, @@ -1119,8 +1049,8 @@ "recovery": null }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -1145,7 +1075,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -1196,7 +1126,7 @@ "name": "Death Quake", "type": "feature", "system": { - "description": "

When the @Lookup[@name] marks their last HP, the magic powering them ruptures in an explosion of force. All targets within Close range must succeed on an Instinct Reaction Roll or take 2d8+1 magic damage

", + "description": "

When the @Lookup[@name] marks their last HP, the magic powering them ruptures in an explosion of force. All targets within Close range must succeed on an Instinct Reaction Roll or take 2d8+1 magic damage

@Template[type:emanation|range:c]

", "resource": null, "actions": { "oCpv4zi9jtEpo0K1": { @@ -1213,8 +1143,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -1240,9 +1170,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -1271,16 +1200,7 @@ }, "name": "Roll Save", "img": "icons/magic/sonic/explosion-shock-wave-teal.webp", - "range": "close", - "areas": [ - { - "name": "Death Quake", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "originItemType": null, diff --git a/src/packs/adversaries/adversary_Bear_71qKDLKO3CsrNkdy.json b/src/packs/adversaries/adversary_Bear_71qKDLKO3CsrNkdy.json index cfc71120..da5de611 100644 --- a/src/packs/adversaries/adversary_Bear_71qKDLKO3CsrNkdy.json +++ b/src/packs/adversaries/adversary_Bear_71qKDLKO3CsrNkdy.json @@ -84,8 +84,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -111,7 +111,7 @@ }, "base": false } - } + ] }, "img": "icons/creatures/claws/claw-straight-brown.webp", "type": "attack", @@ -284,8 +284,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -311,7 +311,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -368,19 +368,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until you break free with a successful Strength Roll.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

You are Restrained until you break free with a successful Strength Roll.

", "tint": "#ffffff", @@ -392,16 +391,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!71qKDLKO3CsrNkdy.zgR0MEqyobKp2yXr.U50Ccm9emMqAxma6" } ], @@ -441,8 +430,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -468,7 +457,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Bladed_Guard_B4LZcGuBAHzyVdzy.json b/src/packs/adversaries/adversary_Bladed_Guard_B4LZcGuBAHzyVdzy.json index a315f91a..8ee7c56c 100644 --- a/src/packs/adversaries/adversary_Bladed_Guard_B4LZcGuBAHzyVdzy.json +++ b/src/packs/adversaries/adversary_Bladed_Guard_B4LZcGuBAHzyVdzy.json @@ -80,8 +80,8 @@ "name": "Longsword", "img": "icons/weapons/swords/sword-guard.webp", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -246,7 +246,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -319,7 +319,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -376,19 +376,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until you break free with a successful attack, Finesse Roll, or Strength Roll.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

You are Restrained until you break free with a successful attack, Finesse Roll, or Strength Roll.

", "tint": "#ffffff", @@ -400,16 +399,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!B4LZcGuBAHzyVdzy.9gizFt9ovKL05DXu.LmzztuktRkwOCy1a" } ], diff --git a/src/packs/adversaries/adversary_Brawny_Zombie_2UeZ0tEe7AzgSJNd.json b/src/packs/adversaries/adversary_Brawny_Zombie_2UeZ0tEe7AzgSJNd.json index 8863641d..c829c3f9 100644 --- a/src/packs/adversaries/adversary_Brawny_Zombie_2UeZ0tEe7AzgSJNd.json +++ b/src/packs/adversaries/adversary_Brawny_Zombie_2UeZ0tEe7AzgSJNd.json @@ -83,8 +83,8 @@ }, "range": "veryClose", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -110,7 +110,7 @@ }, "base": false } - } + ] }, "img": "icons/skills/melee/unarmed-punch-fist-yellow-red.webp", "type": "attack", @@ -280,8 +280,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -307,7 +307,7 @@ } } } - }, + ], "includeBase": false, "direct": true }, @@ -389,8 +389,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -415,7 +415,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -452,18 +452,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -475,16 +475,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!2UeZ0tEe7AzgSJNd.69reUZ5tv3splqyO.CjMrSdL6kgD8mKRQ" } ], diff --git a/src/packs/adversaries/adversary_Cave_Ogre_8Zkqk1jU09nKL2fy.json b/src/packs/adversaries/adversary_Cave_Ogre_8Zkqk1jU09nKL2fy.json index a1bf6bc9..5b2d2e41 100644 --- a/src/packs/adversaries/adversary_Cave_Ogre_8Zkqk1jU09nKL2fy.json +++ b/src/packs/adversaries/adversary_Cave_Ogre_8Zkqk1jU09nKL2fy.json @@ -79,8 +79,8 @@ }, "range": "veryClose", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -106,7 +106,7 @@ }, "base": false } - }, + ], "direct": true }, "name": "Club", @@ -139,9 +139,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -192,7 +195,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -218,8 +221,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -310,7 +312,7 @@ "_id": "zGvaBYJPOOnQVQEn", "img": "icons/magic/earth/projectile-stone-boulder-orange.webp", "system": { - "description": "

Mark a Stress to pick up heavy objects and throw them at all targets in front of the @Lookup[@name] within Far range. Make an attack against these targets. Targets the @Lookup[@name] succeeds against take 1d10+2 physical damage. If they succeed against more than one target, you gain a Fear.

", + "description": "

Mark a Stress to pick up heavy objects and throw them at all targets in front of the @Lookup[@name] within Far range. Make an attack against these targets. Targets the @Lookup[@name] succeeds against take 1d10+2 physical damage. If they succeed against more than one target, you gain a Fear.

@Template[type:inFront|range:f]

", "resource": null, "actions": { "3p1qfHy5uHe4H2hB": { @@ -334,8 +336,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false, @@ -363,10 +365,9 @@ } } } - }, + ], "includeBase": false, - "direct": true, - "groupAttack": "" + "direct": true }, "target": { "type": "any", @@ -395,16 +396,7 @@ }, "name": "Throw", "img": "icons/magic/earth/projectile-stone-boulder-orange.webp", - "range": "far", - "areas": [ - { - "name": "Hail of Boulders", - "type": "placed", - "shape": "inFront", - "size": "far", - "effects": [] - } - ] + "range": "far" }, "pmeromzI4eQOilbp": { "type": "healing", @@ -420,8 +412,8 @@ "recovery": null }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -446,7 +438,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -515,8 +507,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -542,7 +534,7 @@ } } } - }, + ], "includeBase": false, "direct": true }, diff --git a/src/packs/adversaries/adversary_Chaos_Skull_jDmHqGvzg5wjgmxE.json b/src/packs/adversaries/adversary_Chaos_Skull_jDmHqGvzg5wjgmxE.json index 876519cf..f548870a 100644 --- a/src/packs/adversaries/adversary_Chaos_Skull_jDmHqGvzg5wjgmxE.json +++ b/src/packs/adversaries/adversary_Chaos_Skull_jDmHqGvzg5wjgmxE.json @@ -74,8 +74,8 @@ }, "range": "close", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -101,7 +101,7 @@ }, "base": false } - } + ] }, "img": "icons/magic/light/beam-rays-magenta.webp", "type": "attack", @@ -132,9 +132,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -185,7 +188,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -211,8 +214,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -357,7 +359,7 @@ "name": "Magic Burst", "type": "feature", "system": { - "description": "

Mark a Stress to make an attack against all targets within Close range. Targets the @Lookup[@name] succeeds against take 2d6+4 magic damage.

", + "description": "

Mark a Stress to make an attack against all targets within Close range. Targets the @Lookup[@name] succeeds against take 2d6+4 magic damage.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "iF0PD1t3yovKMTfy": { @@ -381,8 +383,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -408,9 +410,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -439,16 +440,7 @@ }, "name": "Attack", "img": "icons/magic/lightning/bolt-strike-purple.webp", - "range": "close", - "areas": [ - { - "name": "Magic Burst", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "originItemType": null, @@ -491,8 +483,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -516,7 +508,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Conscript_99TqczuQipBmaB8i.json b/src/packs/adversaries/adversary_Conscript_99TqczuQipBmaB8i.json index 38e7ceab..35c43a3b 100644 --- a/src/packs/adversaries/adversary_Conscript_99TqczuQipBmaB8i.json +++ b/src/packs/adversaries/adversary_Conscript_99TqczuQipBmaB8i.json @@ -67,8 +67,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -95,7 +95,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -125,9 +125,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -178,7 +181,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -204,8 +207,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -240,95 +242,33 @@ "description": "

Spend a Fear to choose a target and spotlight all @Lookup[@name]s within Close range of them. Those Minions move into Melee range of the target and make one shared attack roll. On a success, they deal @Lookup[@system.attack.damageFormula] physical damage each. Combine this damage.

", "resource": null, "actions": { - "FCeTuf71gCzRiO5N": { - "type": "attack", - "_id": "FCeTuf71gCzRiO5N", + "cbAvPSIhwBMBTI3D": { + "type": "effect", + "_id": "cbAvPSIhwBMBTI3D", "systemPath": "actions", - "baseAction": false, "description": "", "chatDisplay": true, - "originItem": { - "type": "itemCollection" - }, "actionType": "action", - "triggers": [], "cost": [ { "scalable": false, "key": "fear", "value": 1, - "itemId": null, - "step": null, - "consumeOnSuccess": false + "step": null } ], "uses": { "value": null, "max": "", - "recovery": null, - "consumeOnSuccess": false - }, - "damage": { - "parts": { - "hitPoints": { - "applyTo": "hitPoints", - "resultBased": false, - "value": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": true, - "formula": "6" - } - }, - "valueAlt": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": false, - "formula": "" - } - }, - "base": false, - "type": [ - "physical" - ] - } - }, - "includeBase": false, - "direct": false, - "groupAttack": "close" + "recovery": null }, + "effects": [], "target": { "type": "any", "amount": null }, - "effects": [], - "roll": { - "type": "attack", - "trait": null, - "difficulty": null, - "bonus": null, - "advState": "neutral", - "diceRolling": { - "multiplier": "prof", - "flatMultiplier": 1, - "dice": "d6", - "compare": null, - "treshold": null - }, - "useDefault": false - }, - "save": { - "trait": null, - "difficulty": null, - "damageMod": "none" - }, "name": "Spend Fear", + "img": "icons/creatures/abilities/tail-strike-bone-orange.webp", "range": "" } }, diff --git a/src/packs/adversaries/adversary_Construct_uOP5oT9QzXPlnf3p.json b/src/packs/adversaries/adversary_Construct_uOP5oT9QzXPlnf3p.json index 3bd154ef..310eefce 100644 --- a/src/packs/adversaries/adversary_Construct_uOP5oT9QzXPlnf3p.json +++ b/src/packs/adversaries/adversary_Construct_uOP5oT9QzXPlnf3p.json @@ -72,8 +72,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -99,7 +99,7 @@ }, "base": false } - } + ] }, "name": "Fist Slam", "img": "icons/skills/melee/unarmed-punch-fist-yellow-red.webp", @@ -132,9 +132,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -185,7 +188,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -211,8 +214,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -330,8 +332,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -357,7 +359,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -532,8 +534,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -559,9 +561,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -590,16 +591,7 @@ }, "name": "Attack", "img": "icons/magic/sonic/explosion-shock-wave-teal.webp", - "range": "veryClose", - "areas": [ - { - "name": "Death Quake", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "veryClose" } }, "originItemType": null, diff --git a/src/packs/adversaries/adversary_Courtesan_ZxWaWPdzFIUPNC62.json b/src/packs/adversaries/adversary_Courtesan_ZxWaWPdzFIUPNC62.json index aba9ea46..668cd943 100644 --- a/src/packs/adversaries/adversary_Courtesan_ZxWaWPdzFIUPNC62.json +++ b/src/packs/adversaries/adversary_Courtesan_ZxWaWPdzFIUPNC62.json @@ -84,8 +84,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -111,7 +111,7 @@ }, "base": false } - } + ] }, "img": "icons/weapons/daggers/dagger-straight-cracked.webp", "type": "attack", @@ -256,8 +256,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -282,7 +282,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -320,19 +320,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until the scene ends or they succeed on a social action against the Courtesan.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Vulnerable until the scene ends or they succeed on a social action against the Courtesan.

", "tint": "#ffffff", @@ -344,16 +343,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!ZxWaWPdzFIUPNC62.rSMUPC5GhR982ifg.blcRqns0PHqiuPac" } ], diff --git a/src/packs/adversaries/adversary_Courtier_CBBuEXAlLKFMJdjg.json b/src/packs/adversaries/adversary_Courtier_CBBuEXAlLKFMJdjg.json index 8777ee06..6721666f 100644 --- a/src/packs/adversaries/adversary_Courtier_CBBuEXAlLKFMJdjg.json +++ b/src/packs/adversaries/adversary_Courtier_CBBuEXAlLKFMJdjg.json @@ -79,8 +79,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -106,7 +106,7 @@ }, "base": false } - } + ] }, "img": "icons/weapons/daggers/dagger-twin-green.webp", "type": "attack", @@ -253,8 +253,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -279,7 +279,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -336,18 +336,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "scene" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -359,16 +359,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!CBBuEXAlLKFMJdjg.LYNaKEYcYMgvF4Rf.YNMhgBZW8ndrCjIp" } ], diff --git a/src/packs/adversaries/adversary_Cult_Adept_0NxCSugvKQ4W8OYZ.json b/src/packs/adversaries/adversary_Cult_Adept_0NxCSugvKQ4W8OYZ.json index 27553d32..14eb579b 100644 --- a/src/packs/adversaries/adversary_Cult_Adept_0NxCSugvKQ4W8OYZ.json +++ b/src/packs/adversaries/adversary_Cult_Adept_0NxCSugvKQ4W8OYZ.json @@ -84,8 +84,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -111,7 +111,7 @@ }, "base": false } - } + ] }, "range": "far", "img": "icons/weapons/staves/staff-ornate-purple.webp", @@ -143,9 +143,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -196,7 +199,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -222,8 +225,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -254,8 +256,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -281,7 +283,7 @@ } } }, - "stress": { + { "value": { "custom": { "enabled": true, @@ -306,7 +308,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -420,32 +422,31 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.resistance.magical.resistance", - "value": 1, - "priority": null, - "type": "override" - }, - { - "key": "system.resistance.physical.resistance", - "value": 1, - "priority": null, - "type": "override" - } - ], - "duration": { - "type": "temporary", - "description": "

Until the Cult Adept marks their last HP.

" } }, + "changes": [ + { + "key": "system.resistance.magical.resistance", + "mode": 5, + "value": "1", + "priority": null + }, + { + "key": "system.resistance.physical.resistance", + "mode": 5, + "value": "1", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Resistance to all damage until the Adept marks their last HP

", "tint": "#ffffff", @@ -455,16 +456,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!0NxCSugvKQ4W8OYZ.IHWDn097sRgjlZXO.U9lWz1LgeAiK5L85" } ], @@ -484,7 +475,7 @@ "name": "Shadow Shackles", "type": "feature", "system": { - "description": "

Spend a Fear and choose a point within Far range. All targets within Close range of that point are Restrained in smoky chains until they break free with a successful Strength or Instinct Roll. A target Restrained by this feature must spend a Hope to make an action roll.

", + "description": "

Spend a Fear and choose a point within Far range. All targets within Close range of that point are Restrained in smoky chains until they break free with a successful Strength or Instinct Roll. A target Restrained by this feature must spend a Hope to make an action roll.

@Template[type:circle|range:c]

", "resource": null, "actions": { "g4RDHrY0AEYXjH52": { @@ -519,16 +510,7 @@ }, "name": "Spend Fear", "img": "icons/magic/air/fog-gas-smoke-dense-pink.webp", - "range": "far", - "areas": [ - { - "name": "Shadow Shackles", - "type": "placed", - "shape": "circle", - "size": "close", - "effects": [] - } - ] + "range": "far" } }, "originItemType": null, @@ -551,19 +533,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until you break free with a successful Strength or Instinct Roll.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

You are Restrained in smoky chains until you break free with a successful Strength or Instinct Roll. A target Restrained by this feature must spend a Hope to make an action roll.

", "tint": "#ffffff", @@ -575,16 +556,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!0NxCSugvKQ4W8OYZ.JpSrduK3vjd9h098.lNH6srSPyEprXZ4o" } ], @@ -621,8 +592,8 @@ "recovery": "scene" }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -647,7 +618,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Cult_Fang_tyBOpLfigAhI9bU3.json b/src/packs/adversaries/adversary_Cult_Fang_tyBOpLfigAhI9bU3.json index e65f3202..57e7a7c7 100644 --- a/src/packs/adversaries/adversary_Cult_Fang_tyBOpLfigAhI9bU3.json +++ b/src/packs/adversaries/adversary_Cult_Fang_tyBOpLfigAhI9bU3.json @@ -74,8 +74,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -101,7 +101,7 @@ }, "base": false } - } + ] }, "range": "melee", "type": "attack", @@ -300,8 +300,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -326,7 +326,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -384,18 +384,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -407,16 +407,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!tyBOpLfigAhI9bU3.ohASSruBxcvuItIK.LwWxRz7FTMA80VdA" } ], diff --git a/src/packs/adversaries/adversary_Cult_Initiate_zx99sOGTXicP4SSD.json b/src/packs/adversaries/adversary_Cult_Initiate_zx99sOGTXicP4SSD.json index db26605d..a0c0713d 100644 --- a/src/packs/adversaries/adversary_Cult_Initiate_zx99sOGTXicP4SSD.json +++ b/src/packs/adversaries/adversary_Cult_Initiate_zx99sOGTXicP4SSD.json @@ -66,8 +66,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -94,7 +94,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -125,9 +125,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -178,7 +181,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -204,8 +207,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -240,95 +242,33 @@ "description": "

Spend a Fear to choose a target and spotlight all Cult @Lookup[@name]s within Close range of them. Those Minions move into Melee range of the target and make one shared attack roll. On a success, they deal @Lookup[@system.attack.damageFormula] physical damage each. Combine this damage.

", "resource": null, "actions": { - "4M2MvVzEgIQEQHBS": { - "type": "attack", - "_id": "4M2MvVzEgIQEQHBS", + "EH1preaTWBD4rOvx": { + "type": "effect", + "_id": "EH1preaTWBD4rOvx", "systemPath": "actions", - "baseAction": false, "description": "", "chatDisplay": true, - "originItem": { - "type": "itemCollection" - }, "actionType": "action", - "triggers": [], "cost": [ { "scalable": false, "key": "fear", "value": 1, - "itemId": null, - "step": null, - "consumeOnSuccess": false + "step": null } ], "uses": { "value": null, "max": "", - "recovery": null, - "consumeOnSuccess": false - }, - "damage": { - "parts": { - "hitPoints": { - "applyTo": "hitPoints", - "resultBased": false, - "value": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": true, - "formula": "5" - } - }, - "valueAlt": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": false, - "formula": "" - } - }, - "base": false, - "type": [ - "physical" - ] - } - }, - "includeBase": false, - "direct": false, - "groupAttack": "close" - }, - "target": { - "type": "any", - "amount": null + "recovery": null }, "effects": [], - "roll": { - "type": null, - "trait": null, - "difficulty": null, - "bonus": null, - "advState": "neutral", - "diceRolling": { - "multiplier": "prof", - "flatMultiplier": 1, - "dice": "d6", - "compare": null, - "treshold": null - }, - "useDefault": false - }, - "save": { - "trait": null, - "difficulty": null, - "damageMod": "none" + "target": { + "type": "self", + "amount": null }, "name": "Spend Fear", + "img": "icons/creatures/abilities/tail-strike-bone-orange.webp", "range": "" } }, diff --git a/src/packs/adversaries/adversary_Deeproot_Defender_9x2xY9zwc3xzbXo5.json b/src/packs/adversaries/adversary_Deeproot_Defender_9x2xY9zwc3xzbXo5.json index 9ff0a161..cd745eb6 100644 --- a/src/packs/adversaries/adversary_Deeproot_Defender_9x2xY9zwc3xzbXo5.json +++ b/src/packs/adversaries/adversary_Deeproot_Defender_9x2xY9zwc3xzbXo5.json @@ -79,8 +79,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -106,7 +106,7 @@ }, "base": false } - } + ] }, "img": "icons/magic/nature/root-vines-grow-brown.webp", "type": "attack", @@ -137,9 +137,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -190,7 +193,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -216,8 +219,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -226,7 +228,7 @@ "_id": "0DSCzAFXy0hV4afJ", "img": "icons/magic/earth/barrier-stone-brown-green.webp", "system": { - "description": "

Slam the ground, knocking all targets within Very Close range back to Far range. Each target knocked back this way must mark a Stress.

", + "description": "

Slam the ground, knocking all targets within Very Close range back to Far range. Each target knocked back this way must mark a Stress.

@Template[type:emanation|range:vc]

", "resource": null, "actions": { "55hCZsJQhJNcZ0lX": { @@ -243,8 +245,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -269,9 +271,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -280,16 +281,7 @@ "effects": [], "name": "Stress Damage", "img": "icons/magic/earth/barrier-stone-brown-green.webp", - "range": "veryClose", - "areas": [ - { - "name": "Ground Slam", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "veryClose" } }, "originItemType": null, @@ -333,8 +325,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -358,7 +350,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -415,19 +407,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until the Deeproot Defender takes Severe damage.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

You are Restrained until the Defender takes Severe damage.

", "tint": "#ffffff", @@ -439,16 +430,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!9x2xY9zwc3xzbXo5.rreGFW5TbhUoZf2T.F3E7fiz01AbF2kr5" } ], diff --git a/src/packs/adversaries/adversary_Demon_of_Avarice_pnyjIGxxvurcWmTv.json b/src/packs/adversaries/adversary_Demon_of_Avarice_pnyjIGxxvurcWmTv.json index 1a3538da..e4ba41fb 100644 --- a/src/packs/adversaries/adversary_Demon_of_Avarice_pnyjIGxxvurcWmTv.json +++ b/src/packs/adversaries/adversary_Demon_of_Avarice_pnyjIGxxvurcWmTv.json @@ -80,8 +80,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", diff --git a/src/packs/adversaries/adversary_Demon_of_Despair_kE4dfhqmIQpNd44e.json b/src/packs/adversaries/adversary_Demon_of_Despair_kE4dfhqmIQpNd44e.json index 6468c1aa..830848c3 100644 --- a/src/packs/adversaries/adversary_Demon_of_Despair_kE4dfhqmIQpNd44e.json +++ b/src/packs/adversaries/adversary_Demon_of_Despair_kE4dfhqmIQpNd44e.json @@ -80,8 +80,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "far", @@ -138,9 +138,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -191,7 +194,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -217,8 +220,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -294,7 +296,7 @@ "name": "Your Struggle is Pointless", "type": "feature", "system": { - "description": "

Spend a Fear to weigh down the spirits of all PCs within Far range. All targets affected replace their Hope Die with a d8 until they roll a success with Hope or their next rest.

", + "description": "

Spend a Fear to weigh down the spirits of all PCs within Far range. All targets affected replace their Hope Die with a d8 until they roll a success with Hope or their next rest.

@Template[type:emanation|range:f]

", "resource": null, "actions": { "n0RYO05pROFU6ov3": { @@ -329,16 +331,7 @@ }, "name": "Spend Fear", "img": "icons/magic/death/skull-flames-white-blue.webp", - "range": "far", - "areas": [ - { - "name": "Your Struggle is Pointless", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "far" } }, "originItemType": null, @@ -361,25 +354,25 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.rules.dualityRoll.defaultHopeDice", - "value": "d8", - "priority": null, - "type": "override" - } - ], - "duration": { - "type": "shortRest" } }, + "changes": [ + { + "key": "system.rules.dualityRoll.defaultHopeDice", + "mode": 5, + "value": "d8", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

All targets affected replace their Hope Die with a d8 until they roll a success with Hope or their next rest.

", "tint": "#ffffff", @@ -389,16 +382,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!kE4dfhqmIQpNd44e.FC8PIf4BVkhmoJX8.6WSx03mFbpbPWnOI" } ], @@ -418,7 +401,7 @@ "name": "Your Friends Will Fail You", "type": "feature", "system": { - "description": "

When a PC fails with Fear, you can mark a Stress to cause all other PCs within Close range to lose a Hope.

", + "description": "

When a PC fails with Fear, you can mark a Stress to cause all other PCs within Close range to lose a Hope.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "urrp8SCFgqbmSTvm": { @@ -442,8 +425,8 @@ "recovery": null }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -468,9 +451,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -479,16 +461,7 @@ "effects": [], "name": "Lose Hope", "img": "icons/creatures/unholy/demon-fire-horned-mask.webp", - "range": "", - "areas": [ - { - "name": "Your Friends Will Fail You", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "" } }, "originItemType": null, @@ -532,8 +505,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -559,7 +532,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Demon_of_Hubris_2VN3BftageoTTIzu.json b/src/packs/adversaries/adversary_Demon_of_Hubris_2VN3BftageoTTIzu.json index 3a95c233..16bc1d1f 100644 --- a/src/packs/adversaries/adversary_Demon_of_Hubris_2VN3BftageoTTIzu.json +++ b/src/packs/adversaries/adversary_Demon_of_Hubris_2VN3BftageoTTIzu.json @@ -81,8 +81,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -108,7 +108,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -138,9 +138,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -191,7 +194,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -217,15 +220,14 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { "name": "Terrifying", "type": "feature", "system": { - "description": "

When the @Lookup[@name] makes a successful attack, all PCs within Far range must lose a Hope and you gain a Fear.

", + "description": "

When the @Lookup[@name] makes a successful attack, all PCs within Far range must lose a Hope and you gain a Fear.

@Template[type:emanation|range:f]

", "resource": null, "actions": { "v3XbljQeHEyfuSXz": { @@ -249,8 +251,8 @@ "recovery": null }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -275,9 +277,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -286,16 +287,7 @@ "effects": [], "name": "Lose Hope", "img": "icons/magic/death/skull-energy-light-purple.webp", - "range": "", - "areas": [ - { - "name": "Terrifying", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "" } }, "originItemType": null, @@ -337,8 +329,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -363,7 +355,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -422,8 +414,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -449,7 +441,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -541,7 +533,7 @@ "name": "You Pale in Comparison", "type": "feature", "system": { - "description": "

When a PC fails a roll within Close range of the @Lookup[@name], they must mark a Stress.

", + "description": "

When a PC fails a roll within Close range of the @Lookup[@name], they must mark a Stress.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "kuCPWb9cu3pZdAhh": { @@ -558,8 +550,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -584,9 +576,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -595,16 +586,7 @@ "effects": [], "name": "Mark Stress", "img": "icons/magic/control/fear-fright-shadow-monster-red.webp", - "range": "close", - "areas": [ - { - "name": "You Pale in Comparison", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "originItemType": null, diff --git a/src/packs/adversaries/adversary_Demon_of_Jealousy_SxSOkM4bcVOFyjbo.json b/src/packs/adversaries/adversary_Demon_of_Jealousy_SxSOkM4bcVOFyjbo.json index 0c743ac2..31f9b942 100644 --- a/src/packs/adversaries/adversary_Demon_of_Jealousy_SxSOkM4bcVOFyjbo.json +++ b/src/packs/adversaries/adversary_Demon_of_Jealousy_SxSOkM4bcVOFyjbo.json @@ -80,8 +80,8 @@ }, "range": "far", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - }, + ], "direct": true }, "img": "icons/magic/symbols/rune-sigil-rough-white-teal.webp", @@ -139,9 +139,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -192,7 +195,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -218,8 +221,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -277,7 +279,7 @@ "name": "Rivalry", "type": "feature", "system": { - "description": "

When a creature within Close range takes damage from a different adversary, you can mark a Stress to add a d4 to the damage roll.

", + "description": "

When a creature within Close range takes damage from a different adversary, you can mark a Stress to add a d4 to the damage roll.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "UU3H5aPQejOSoFZw": { @@ -307,16 +309,7 @@ }, "name": "Mark Stress", "img": "icons/magic/perception/eye-ringed-glow-angry-small-teal.webp", - "range": "", - "areas": [ - { - "name": "Rivalry", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "" } }, "originItemType": null, @@ -342,7 +335,7 @@ "name": "What's Yours Is Mine", "type": "feature", "system": { - "description": "

When a PC takes Severe damage within Very Close range of the @Lookup[@name], you can spend a Fear to cause the target to make a Finesse Reaction Roll. On a failure, the @Lookup[@name] seizes one item or consumable of their choice from the target’s inventory.

", + "description": "

When a PC takes Severe damage within Very Close range of the @Lookup[@name], you can spend a Fear to cause the target to make a Finesse Reaction Roll. On a failure, the @Lookup[@name] seizes one item or consumable of their choice from the target’s inventory.

@Template[type:emanation|range:vc]

", "resource": null, "actions": { "3cGZ2CofM9HUlELH": { @@ -359,9 +352,8 @@ "recovery": null }, "damage": { - "parts": {}, - "includeBase": false, - "groupAttack": "" + "parts": [], + "includeBase": false }, "target": { "type": "any", @@ -390,16 +382,7 @@ }, "name": "Roll Save", "img": "icons/magic/perception/hand-eye-black.webp", - "range": "veryClose", - "areas": [ - { - "name": "What's Yours Is Mine", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "veryClose" } }, "originItemType": null, diff --git a/src/packs/adversaries/adversary_Demon_of_Wrath_5lphJAgzoqZI3VoG.json b/src/packs/adversaries/adversary_Demon_of_Wrath_5lphJAgzoqZI3VoG.json index 0bc6bf2d..2341ee8a 100644 --- a/src/packs/adversaries/adversary_Demon_of_Wrath_5lphJAgzoqZI3VoG.json +++ b/src/packs/adversaries/adversary_Demon_of_Wrath_5lphJAgzoqZI3VoG.json @@ -81,8 +81,8 @@ }, "img": "icons/skills/melee/unarmed-punch-fist-yellow-red.webp", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -108,7 +108,7 @@ }, "base": false } - }, + ], "direct": true }, "type": "attack", @@ -139,9 +139,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -192,7 +195,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -218,8 +221,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -251,7 +253,7 @@ "name": "Battle Lust", "type": "feature", "system": { - "description": "

Spend a Fear to boil the blood of all PCs within Far range. They use a d20 as their Fear Die until the end of the scene.

", + "description": "

Spend a Fear to boil the blood of all PCs within Far range. They use a d20 as their Fear Die until the end of the scene.

@Template[type:emanation|range:f]

", "resource": null, "actions": { "jKvzbQT0vp66DDOH": { @@ -292,16 +294,7 @@ "amount": null }, "name": "Spend Fear", - "range": "far", - "areas": [ - { - "name": "Battle Lust", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "far" } }, "originItemType": null, @@ -324,25 +317,25 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.rules.dualityRoll.defaultFearDice", - "value": "d20", - "priority": null, - "type": "override" - } - ], - "duration": { - "type": "scene" } }, + "changes": [ + { + "key": "system.rules.dualityRoll.defaultFearDice", + "mode": 5, + "value": "d20", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

You use a d20 as your Fear Die until the end of the scene.

", "tint": "#ffffff", @@ -352,16 +345,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!5lphJAgzoqZI3VoG.a33PW8UkziliowlR.gFeHLGgeRoDdd3VG" } ], @@ -381,7 +364,7 @@ "name": "Retalliation", "type": "feature", "system": { - "description": "

When the @Lookup[@name] takes damage from an attack within Close range, you can mark a Stress to make a standard attack against the attacker.

", + "description": "

When the @Lookup[@name] takes damage from an attack within Close range, you can mark a Stress to make a standard attack against the attacker.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "hxrdtBm4dYN7KGZm": { @@ -405,8 +388,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -432,10 +415,9 @@ } } } - }, + ], "includeBase": false, - "direct": true, - "groupAttack": "" + "direct": true }, "target": { "type": "any", @@ -464,16 +446,7 @@ }, "name": "Attack", "img": "icons/skills/melee/blood-slash-foam-red.webp", - "range": "veryClose", - "areas": [ - { - "name": "Retalliation", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "veryClose" } }, "originItemType": null, diff --git a/src/packs/adversaries/adversary_Demonic_Hound_Pack_NoRZ1PqB8N5wcIw0.json b/src/packs/adversaries/adversary_Demonic_Hound_Pack_NoRZ1PqB8N5wcIw0.json index b534562b..7482c734 100644 --- a/src/packs/adversaries/adversary_Demonic_Hound_Pack_NoRZ1PqB8N5wcIw0.json +++ b/src/packs/adversaries/adversary_Demonic_Hound_Pack_NoRZ1PqB8N5wcIw0.json @@ -74,8 +74,8 @@ "motivesAndTactics": "Cause fear, consume fl esh, please masters", "attack": { "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -101,7 +101,7 @@ "resultBased": false, "base": false } - } + ] }, "name": "Claws and Fangs", "img": "icons/creatures/abilities/mouth-teeth-rows-red.webp", @@ -138,9 +138,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -191,7 +194,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -217,8 +220,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -250,7 +252,7 @@ "name": "Dreadhowl", "type": "feature", "system": { - "description": "

Mark a Stress to make all targets within Very Close range lose a Hope. If a target is not able to lose a Hope, they must instead mark 2 Stress.

", + "description": "

Mark a Stress to make all targets within Very Close range lose a Hope. If a target is not able to lose a Hope, they must instead mark 2 Stress.

@Template[type:emanation|range:vc]

", "resource": null, "actions": { "XyLlX9RWSxciZ7oV": { @@ -267,8 +269,8 @@ "recovery": null }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -293,9 +295,8 @@ }, "type": [] } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -304,16 +305,7 @@ "effects": [], "name": "Lose Hope", "img": "icons/creatures/unholy/demons-horned-glowing-pink.webp", - "range": "veryClose", - "areas": [ - { - "name": "Dreadhowl", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "veryClose" } }, "originItemType": null, @@ -357,8 +349,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -384,7 +376,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Dire_Bat_tBWHW00epmMnkawe.json b/src/packs/adversaries/adversary_Dire_Bat_tBWHW00epmMnkawe.json index a1107f7c..acfdb257 100644 --- a/src/packs/adversaries/adversary_Dire_Bat_tBWHW00epmMnkawe.json +++ b/src/packs/adversaries/adversary_Dire_Bat_tBWHW00epmMnkawe.json @@ -79,8 +79,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -106,7 +106,7 @@ }, "base": false } - } + ] }, "img": "icons/creatures/claws/claw-hooked-curved.webp", "type": "attack", @@ -138,9 +138,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -191,7 +194,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -217,8 +220,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -243,24 +245,27 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.difficulty", - "value": 3, - "priority": null, - "type": "add" - } - ] + } }, "_id": "qZfNiqw1iAIxeuYg", "img": "icons/commodities/biological/wing-lizard-brown.webp", + "changes": [ + { + "key": "system.difficulty", + "mode": 2, + "value": "3", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

While flying, the Bat gains a +3 bonus to their Difficulty.

", "origin": null, @@ -272,9 +277,6 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!tBWHW00epmMnkawe.gx22MpD8fWoi8klZ.qZfNiqw1iAIxeuYg" } ], @@ -294,7 +296,7 @@ "name": "Screech", "type": "feature", "system": { - "description": "

Mark a Stress to send a high-pitch screech out toward all targets in front of the @Lookup[@name] within Far range. Those targets must mark 1d4 Stress.

", + "description": "

Mark a Stress to send a high-pitch screech out toward all targets in front of the @Lookup[@name] within Far range. Those targets must mark 1d4 Stress.

@Template[type:inFront|range:f]

", "resource": null, "actions": { "2ILfoiBoMyBCtBsL": { @@ -311,8 +313,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -336,9 +338,8 @@ }, "type": [] } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -347,16 +348,7 @@ "effects": [], "name": "Mark Stress", "img": "icons/magic/sonic/projectile-sound-rings-wave.webp", - "range": "far", - "areas": [ - { - "name": "Screech", - "type": "placed", - "shape": "inFront", - "size": "far", - "effects": [] - } - ] + "range": "far" } }, "originItemType": null, @@ -406,8 +398,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -433,7 +425,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Dire_Wolf_wNzeuQLfLUMvgHlQ.json b/src/packs/adversaries/adversary_Dire_Wolf_wNzeuQLfLUMvgHlQ.json index 939a5307..e3ecda4e 100644 --- a/src/packs/adversaries/adversary_Dire_Wolf_wNzeuQLfLUMvgHlQ.json +++ b/src/packs/adversaries/adversary_Dire_Wolf_wNzeuQLfLUMvgHlQ.json @@ -79,8 +79,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -106,7 +106,7 @@ }, "base": false } - } + ] }, "img": "icons/creatures/claws/claw-straight-brown.webp", "type": "attack", @@ -247,8 +247,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -272,7 +272,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -352,8 +352,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -377,7 +377,7 @@ } } } - }, + ], "includeBase": false, "direct": true }, @@ -435,19 +435,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until they clear at least 1 HP.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -459,16 +458,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!wNzeuQLfLUMvgHlQ.85XrqDvLP30YOO43.YNKHEFQ4ucGr4Rmc" } ], diff --git a/src/packs/adversaries/adversary_Dryad_wR7cFKrHvRzbzhBT.json b/src/packs/adversaries/adversary_Dryad_wR7cFKrHvRzbzhBT.json index 62df584a..ca9ce647 100644 --- a/src/packs/adversaries/adversary_Dryad_wR7cFKrHvRzbzhBT.json +++ b/src/packs/adversaries/adversary_Dryad_wR7cFKrHvRzbzhBT.json @@ -81,8 +81,8 @@ }, "range": "far", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -108,7 +108,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -138,9 +138,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -191,7 +194,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -217,15 +220,14 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { "name": "Bramble Patch", "type": "feature", "system": { - "description": "

Mark a Stress to target a point within Far range. Create a patch of thorns that covers an area within Close range of that point. All targets within that area take 2d6+2 physical damage when they act. A target must succeed on a Finesse Roll or deal more than 20 damage to the @Lookup[@name] with an attack to leave the area.

", + "description": "

Mark a Stress to target a point within Far range. Create a patch of thorns that covers an area within Close range of that point. All targets within that area take 2d6+2 physical damage when they act. A target must succeed on a Finesse Roll or deal more than 20 damage to the @Lookup[@name] with an attack to leave the area.

@Template[type:circle|range:c]

", "resource": null, "actions": { "iCJdIs57hfh5Cb0u": { @@ -249,9 +251,8 @@ "recovery": null }, "damage": { - "parts": {}, - "includeBase": false, - "groupAttack": "" + "parts": [], + "includeBase": false }, "target": { "type": "any", @@ -280,16 +281,7 @@ }, "name": "Mark Stress", "img": "icons/magic/nature/root-vines-grow-brown.webp", - "range": "", - "areas": [ - { - "name": "Bramble Patch", - "type": "placed", - "shape": "circle", - "size": "close", - "effects": [] - } - ] + "range": "" }, "cpZ5c9d3opSA4BN9": { "type": "damage", @@ -305,8 +297,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -332,7 +324,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -422,7 +414,7 @@ "name": "We Are All One", "type": "feature", "system": { - "description": "

When an ally dies within Close range, you can spend a Fear to clear 2 HP and 2 Stress as the fallen ally’s life force is returned to the forest.

", + "description": "

When an ally dies within Close range, you can spend a Fear to clear 2 HP and 2 Stress as the fallen ally’s life force is returned to the forest.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "SrhuW3mfOuqg1ys6": { @@ -446,8 +438,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -472,7 +464,7 @@ }, "type": [] }, - "stress": { + { "value": { "custom": { "enabled": true, @@ -497,9 +489,8 @@ }, "type": [] } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "self", @@ -523,16 +514,7 @@ }, "name": "Spend Fear", "img": "icons/magic/unholy/orb-hands-pink.webp", - "range": "self", - "areas": [ - { - "name": "We Are All One", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "self" } }, "originItemType": null, diff --git a/src/packs/adversaries/adversary_Electric_Eels_TLzY1nDw0Bu9Ud40.json b/src/packs/adversaries/adversary_Electric_Eels_TLzY1nDw0Bu9Ud40.json index 1909a74a..9386944f 100644 --- a/src/packs/adversaries/adversary_Electric_Eels_TLzY1nDw0Bu9Ud40.json +++ b/src/packs/adversaries/adversary_Electric_Eels_TLzY1nDw0Bu9Ud40.json @@ -68,8 +68,8 @@ "motivesAndTactics": "Avoid larger predators, shock prey, tear apart", "attack": { "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -95,7 +95,7 @@ "resultBased": false, "base": false } - } + ] }, "name": "Shocking Bite", "img": "icons/creatures/abilities/mouth-teeth-sharp.webp", @@ -270,8 +270,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -297,7 +297,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Elemental_Spark_P7h54ZePFPHpYwvB.json b/src/packs/adversaries/adversary_Elemental_Spark_P7h54ZePFPHpYwvB.json index 5b8fa7b2..5c25f63e 100644 --- a/src/packs/adversaries/adversary_Elemental_Spark_P7h54ZePFPHpYwvB.json +++ b/src/packs/adversaries/adversary_Elemental_Spark_P7h54ZePFPHpYwvB.json @@ -67,8 +67,8 @@ }, "range": "close", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -95,7 +95,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -125,9 +125,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -178,7 +181,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -204,8 +207,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -240,95 +242,33 @@ "description": "

Spend a Fear to choose a target and spotlight all @Lookup[@name]s within Close range of them. Those Minions move into Melee range of the target and make one shared attack roll. On a success, they deal @Lookup[@system.attack.damageFormula] physical damage each. Combine this damage.

", "resource": null, "actions": { - "S3dYxRclyhYINRi8": { - "type": "attack", - "_id": "S3dYxRclyhYINRi8", + "vXHZVb0Y7Hqu3uso": { + "type": "effect", + "_id": "vXHZVb0Y7Hqu3uso", "systemPath": "actions", - "baseAction": false, "description": "", "chatDisplay": true, - "originItem": { - "type": "itemCollection" - }, "actionType": "action", - "triggers": [], "cost": [ { "scalable": false, "key": "fear", "value": 1, - "itemId": null, - "step": null, - "consumeOnSuccess": false + "step": null } ], "uses": { "value": null, "max": "", - "recovery": null, - "consumeOnSuccess": false - }, - "damage": { - "parts": { - "hitPoints": { - "applyTo": "hitPoints", - "resultBased": false, - "value": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": true, - "formula": "5" - } - }, - "valueAlt": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": false, - "formula": "" - } - }, - "base": false, - "type": [ - "physical" - ] - } - }, - "includeBase": false, - "direct": false, - "groupAttack": "close" - }, - "target": { - "type": "any", - "amount": null + "recovery": null }, "effects": [], - "roll": { - "type": "attack", - "trait": null, - "difficulty": null, - "bonus": null, - "advState": "neutral", - "diceRolling": { - "multiplier": "prof", - "flatMultiplier": 1, - "dice": "d6", - "compare": null, - "treshold": null - }, - "useDefault": false - }, - "save": { - "trait": null, - "difficulty": null, - "damageMod": "none" + "target": { + "type": "self", + "amount": null }, "name": "Spend Fear", + "img": "icons/magic/unholy/orb-hands-pink.webp", "range": "" } }, diff --git a/src/packs/adversaries/adversary_Elite_Soldier_bfhVWMBUh61b9J6n.json b/src/packs/adversaries/adversary_Elite_Soldier_bfhVWMBUh61b9J6n.json index df3e6d12..de5db0b2 100644 --- a/src/packs/adversaries/adversary_Elite_Soldier_bfhVWMBUh61b9J6n.json +++ b/src/packs/adversaries/adversary_Elite_Soldier_bfhVWMBUh61b9J6n.json @@ -98,8 +98,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -125,7 +125,7 @@ }, "base": false } - }, + ], "includeBase": false }, "target": { @@ -276,8 +276,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -303,7 +303,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Failed_Experiment_ChwwVqowFw8hJQwT.json b/src/packs/adversaries/adversary_Failed_Experiment_ChwwVqowFw8hJQwT.json index 70e56980..408d5102 100644 --- a/src/packs/adversaries/adversary_Failed_Experiment_ChwwVqowFw8hJQwT.json +++ b/src/packs/adversaries/adversary_Failed_Experiment_ChwwVqowFw8hJQwT.json @@ -79,8 +79,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -106,7 +106,7 @@ }, "base": false } - } + ] }, "img": "icons/creatures/claws/claw-hooked-barbed.webp", "range": "melee", diff --git a/src/packs/adversaries/adversary_Fallen_Shock_Troop_OsLG2BjaEdTZUJU9.json b/src/packs/adversaries/adversary_Fallen_Shock_Troop_OsLG2BjaEdTZUJU9.json index 484e161a..931e4c0a 100644 --- a/src/packs/adversaries/adversary_Fallen_Shock_Troop_OsLG2BjaEdTZUJU9.json +++ b/src/packs/adversaries/adversary_Fallen_Shock_Troop_OsLG2BjaEdTZUJU9.json @@ -67,8 +67,8 @@ "img": "icons/weapons/axes/axe-battle-skull-black.webp", "range": "veryClose", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -95,7 +95,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -125,9 +125,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -178,7 +181,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -204,8 +207,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -254,8 +256,8 @@ "recovery": null }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -280,7 +282,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -318,95 +320,33 @@ "description": "

Spend a Fear to choose a target and spotlight all @Lookup[@name]s within Close range of them. Those Minions move into Melee range of the target and make one shared attack roll. On a success, they deal @Lookup[@system.attack.damageFormula] physical damage each. Combine this damage.

", "resource": null, "actions": { - "G0DVft7h55pBnwJA": { - "type": "attack", - "_id": "G0DVft7h55pBnwJA", + "QHNRSEQmqOcaoXq4": { + "type": "effect", + "_id": "QHNRSEQmqOcaoXq4", "systemPath": "actions", - "baseAction": false, "description": "", "chatDisplay": true, - "originItem": { - "type": "itemCollection" - }, "actionType": "action", - "triggers": [], "cost": [ { "scalable": false, "key": "fear", "value": 1, - "itemId": null, - "step": null, - "consumeOnSuccess": false + "step": null } ], "uses": { "value": null, "max": "", - "recovery": null, - "consumeOnSuccess": false - }, - "damage": { - "parts": { - "hitPoints": { - "applyTo": "hitPoints", - "resultBased": false, - "value": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": true, - "formula": "12" - } - }, - "valueAlt": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": false, - "formula": "" - } - }, - "base": false, - "type": [ - "physical" - ] - } - }, - "includeBase": false, - "direct": false, - "groupAttack": "close" - }, - "target": { - "type": "any", - "amount": null + "recovery": null }, "effects": [], - "roll": { - "type": "attack", - "trait": null, - "difficulty": null, - "bonus": null, - "advState": "neutral", - "diceRolling": { - "multiplier": "prof", - "flatMultiplier": 1, - "dice": "d6", - "compare": null, - "treshold": null - }, - "useDefault": false - }, - "save": { - "trait": null, - "difficulty": null, - "damageMod": "none" + "target": { + "type": "self", + "amount": null }, "name": "Spend Fear", + "img": "icons/magic/unholy/orb-hands-pink.webp", "range": "" } }, diff --git a/src/packs/adversaries/adversary_Fallen_Sorcerer_PELRry1vqjBzSAlr.json b/src/packs/adversaries/adversary_Fallen_Sorcerer_PELRry1vqjBzSAlr.json index 975cf6aa..fc064958 100644 --- a/src/packs/adversaries/adversary_Fallen_Sorcerer_PELRry1vqjBzSAlr.json +++ b/src/packs/adversaries/adversary_Fallen_Sorcerer_PELRry1vqjBzSAlr.json @@ -80,8 +80,8 @@ }, "range": "far", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - } + ] }, "img": "icons/weapons/staves/staff-animal-skull-bull.webp", "type": "attack", @@ -138,9 +138,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -191,7 +194,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -217,15 +220,14 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { "name": "Conflagration", "type": "feature", "system": { - "description": "

Spend a Fear to unleash an all-consuming firestorm and make an attack against all targets within Close range. Targets the @Lookup[@name] succeeds against take 2d10+6 direct magic damage.

", + "description": "

Spend a Fear to unleash an all-consuming firestorm and make an attack against all targets within Close range. Targets the @Lookup[@name] succeeds against take 2d10+6 direct magic damage.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "v7zZo52Dnj1e1i2G": { @@ -249,8 +251,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -276,9 +278,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -307,16 +308,7 @@ }, "name": "Attack", "img": "icons/magic/fire/projectile-beams-salvo-red.webp", - "range": "close", - "areas": [ - { - "name": "Conflagration", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "originItemType": null, @@ -393,41 +385,30 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until youbreak free with a successful Instinct Roll.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Restrained and Vulnerable until you break free, ending both conditions, with a successful Instinct Roll.

", "tint": "#ffffff", "statuses": [ - "vulnerable", - "restrained" + "restrained", + "vulnerable" ], "sort": 0, "flags": {}, "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!PELRry1vqjBzSAlr.ecp9o8t1dQFXGsse.Q99saHj6NOY2PSXf" } ], @@ -473,14 +454,14 @@ "name": "Shackles of Guilt", "type": "feature", "system": { - "description": "

Countdown (Loop 2d6). When the @Lookup[@name] is in the spotlight for the first time, activate the countdown. When it triggers, all targets within Far range become Vulnerable and must mark a Stress as they relive their greatest regrets. A target can break free from their regret with a successful Presence or Strength Roll. When a PC fails to break free, they lose a Hope.

", + "description": "

Countdown (Loop 2d6). When the @Lookup[@name] is in the spotlight for the first time, activate the countdown. When it triggers, all targets within Far range become Vulnerable and must mark a Stress as they relive their greatest regrets. A target can break free from their regret with a successful Presence or Strength Roll. When a PC fails to break free, they lose a Hope.

@Template[type:emanation|range:f]

", "resource": null, "actions": { "7b0FkpAnWz9a5EWx": { "type": "damage", "_id": "7b0FkpAnWz9a5EWx", "systemPath": "actions", - "description": "

When it triggers, all targets within Far range become Vulnerable and must mark a Stress as they relive their greatest regrets. A target can break free from their regret with a successful Presence or Strength Roll. When a PC fails to break free, they lose a Hope.

", + "description": "

When the countdown triggers, all targets within Far range become Vulnerable and must mark a Stress as they relive their greatest regrets. A target can break free from their regret with a successful Presence or Strength Roll. When a PC fails to break free, they lose a Hope.

@Template[type:emanation|range:f]

", "chatDisplay": true, "actionType": "action", "cost": [], @@ -490,8 +471,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -516,9 +497,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -532,16 +512,7 @@ ], "name": "Mark Stress", "img": "icons/magic/unholy/strike-hand-glow-pink.webp", - "range": "", - "areas": [ - { - "name": "Shackles of Guilt", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "" }, "11PtfoxbgOXxNlkG": { "type": "countdown", @@ -601,19 +572,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

A target can break free from their regret with a successful Presence or Strength Roll.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Vulnerable until you break free from your regret with a successful Presence or Strength Roll. If you fail to break free, you lose a Hope.

", "tint": "#ffffff", @@ -625,16 +595,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!PELRry1vqjBzSAlr.gwSgBhkcekCGvXxz.pWDg0MADoohKu40O" } ], diff --git a/src/packs/adversaries/adversary_Fallen_Warlord__Realm_Breaker_hxZ0sgoFJubh5aj6.json b/src/packs/adversaries/adversary_Fallen_Warlord__Realm_Breaker_hxZ0sgoFJubh5aj6.json index 15663752..8f3865e9 100644 --- a/src/packs/adversaries/adversary_Fallen_Warlord__Realm_Breaker_hxZ0sgoFJubh5aj6.json +++ b/src/packs/adversaries/adversary_Fallen_Warlord__Realm_Breaker_hxZ0sgoFJubh5aj6.json @@ -67,8 +67,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -94,7 +94,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", @@ -173,9 +173,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -226,7 +229,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -252,8 +255,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -335,7 +337,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -390,7 +392,7 @@ "name": "Tormenting Lash", "type": "feature", "system": { - "description": "

Mark a Stress to make a standard attack against all targets within Very Close range. When a target uses armor to reduce damage from this attack, they must mark 2 Armor Slots.

", + "description": "

Mark a Stress to make a standard attack against all targets within Very Close range. When a target uses armor to reduce damage from this attack, they must mark 2 Armor Slots.

@Template[type:emanation|range:vc]

", "resource": null, "actions": { "zMVhUekP8pcyQGFR": { @@ -414,8 +416,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -441,9 +443,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -472,16 +473,7 @@ }, "name": "Attack", "img": "icons/skills/melee/blood-slash-foam-red.webp", - "range": "veryClose", - "areas": [ - { - "name": "Tormenting Lash", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "veryClose" } }, "originItemType": null, @@ -507,14 +499,14 @@ "name": "All-Consuming Rage", "type": "feature", "system": { - "description": "

Countdown (Decreasing 8). When the @Lookup[@name] is in the spotlight for the first time, activate the countdown. When it triggers, create a torrent of incarnate rage that rends flesh from bone. All targets within Far range must make a Presence Reaction Roll. Targets who fail take 2d6+10 direct magic damage. Targets who succeed take half damage. For each HP marked from this damage, summon a @UUID[Compendium.daggerheart.adversaries.Actor.OsLG2BjaEdTZUJU9]{Fallen Shock Troop} within Very Close range of the target who marked that HP. If the countdown ever decreases its maximum value to 0, the @Lookup[@name] marks their remaining HP and all targets within Far range must mark all remaining HP and make a death move.

", + "description": "

Countdown (Decreasing 8). When the @Lookup[@name] is in the spotlight for the first time, activate the countdown. When it triggers, create a torrent of incarnate rage that rends flesh from bone. All targets within Far range must make a Presence Reaction Roll. Targets who fail take 2d6+10 direct magic damage. Targets who succeed take half damage. For each HP marked from this damage, summon a @UUID[Compendium.daggerheart.adversaries.Actor.OsLG2BjaEdTZUJU9]{Fallen Shock Troop} within Very Close range of the target who marked that HP. If the countdown ever decreases its maximum value to 0, the @Lookup[@name] marks their remaining HP and all targets within Far range must mark all remaining HP and make a death move.

@Template[type:emanation|range:f]

", "resource": null, "actions": { "rgy5wXyXJWh6uWxC": { "type": "attack", "_id": "rgy5wXyXJWh6uWxC", "systemPath": "actions", - "description": "

When it triggers, create a torrent of incarnate rage that rends flesh from bone. All targets within Far range must make a Presence Reaction Roll. Targets who fail take 2d6+10 direct magic damage. Targets who succeed take half damage. For each HP marked from this damage, summon a @UUID[Compendium.daggerheart.adversaries.Actor.OsLG2BjaEdTZUJU9]{Fallen Shock Troop} within Very Close range of the target who marked that HP. If the countdown ever decreases its maximum value to 0, the @Lookup[@name] marks their remaining HP and all targets within Far range must mark all remaining HP and make a death move.

", + "description": "

When it triggers, create a torrent of incarnate rage that rends flesh from bone. All targets within Far range must make a Presence Reaction Roll. Targets who fail take 2d6+10 direct magic damage. Targets who succeed take half damage. For each HP marked from this damage, summon a @UUID[Compendium.daggerheart.adversaries.Actor.OsLG2BjaEdTZUJU9]{Fallen Shock Troop} within Very Close range of the target who marked that HP. If the countdown ever decreases its maximum value to 0, the @Lookup[@name] marks their remaining HP and all targets within Far range must mark all remaining HP and make a death move.

@Template[type:emanation|range:f]

", "chatDisplay": true, "actionType": "action", "cost": [], @@ -524,8 +516,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -551,9 +543,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -582,16 +573,7 @@ }, "name": "Roll Save", "img": "icons/magic/control/fear-fright-monster-grin-red-orange.webp", - "range": "far", - "areas": [ - { - "name": "All-Consuming Rage", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "far" }, "8e3BHmOFLvRwPbTW": { "type": "countdown", @@ -654,7 +636,7 @@ "name": "Doombringer", "type": "feature", "system": { - "description": "

When a target marks HP from an attack by the @Lookup[@name], all PCs within Far range of the target must lose a Hope.

", + "description": "

When a target marks HP from an attack by the @Lookup[@name], all PCs within Far range of the target must lose a Hope.

@Template[type:emanation|range:f]

", "resource": null, "actions": { "WEBPJCbXfBeyHFJ4": { @@ -671,8 +653,8 @@ "recovery": null }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -697,9 +679,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -708,16 +689,7 @@ "effects": [], "name": "Lose Hope", "img": "icons/magic/death/skull-energy-light-purple.webp", - "range": "", - "areas": [ - { - "name": "Doombringer", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "" } }, "originItemType": null, diff --git a/src/packs/adversaries/adversary_Fallen_Warlord__Undefeated_Champion_RXkZTwBRi4dJ3JE5.json b/src/packs/adversaries/adversary_Fallen_Warlord__Undefeated_Champion_RXkZTwBRi4dJ3JE5.json index 6cb1c0ce..89d61c1c 100644 --- a/src/packs/adversaries/adversary_Fallen_Warlord__Undefeated_Champion_RXkZTwBRi4dJ3JE5.json +++ b/src/packs/adversaries/adversary_Fallen_Warlord__Undefeated_Champion_RXkZTwBRi4dJ3JE5.json @@ -67,8 +67,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -94,7 +94,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", @@ -174,9 +174,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -227,7 +230,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -253,8 +256,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -336,7 +338,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -391,7 +393,7 @@ "name": "Shattering Strike", "type": "feature", "system": { - "description": "

Mark a Stress to make a standard attack against all targets within Very Close range. PCs the @Lookup[@name] succeeds against lose a number of Hope equal to the HP they marked from this attack.

", + "description": "

Mark a Stress to make a standard attack against all targets within Very Close range. PCs the @Lookup[@name] succeeds against lose a number of Hope equal to the HP they marked from this attack.

@Template[type:emanation|range:vc]

", "resource": null, "actions": { "t1GhGnEhNYyJ7p2U": { @@ -408,8 +410,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -435,9 +437,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -466,16 +467,7 @@ }, "name": "Attack", "img": "icons/skills/melee/sword-stuck-glowing-pink.webp", - "range": "veryClose", - "areas": [ - { - "name": "Shattering Strike", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "veryClose" } }, "originItemType": null, @@ -504,42 +496,34 @@ "description": "

Spend a Fear to summon a number of @UUID[Compendium.daggerheart.adversaries.Actor.OsLG2BjaEdTZUJU9]{Fallen Shock Troops} equal to twice the number of PCs. The Shock Troops appear at Far range.

", "resource": null, "actions": { - "SrU7qbh8LcOgfozT": { - "type": "summon", - "_id": "SrU7qbh8LcOgfozT", + "hGMzqw00JTlYfHYy": { + "type": "effect", + "_id": "hGMzqw00JTlYfHYy", "systemPath": "actions", - "baseAction": false, "description": "", "chatDisplay": true, - "originItem": { - "type": "itemCollection" - }, "actionType": "action", - "triggers": [], "cost": [ { "scalable": false, "key": "fear", "value": 1, - "itemId": null, - "step": null, - "consumeOnSuccess": false + "step": null } ], "uses": { "value": null, "max": "", - "recovery": null, - "consumeOnSuccess": false + "recovery": null + }, + "effects": [], + "target": { + "type": "self", + "amount": null }, - "summon": [ - { - "actorUUID": "Compendium.daggerheart.adversaries.Actor.OsLG2BjaEdTZUJU9", - "count": "@partySize*2" - } - ], "name": "Spend Fear", - "range": "far" + "img": "icons/magic/death/undead-skeleton-worn-blue.webp", + "range": "" } }, "originItemType": null, @@ -581,25 +565,19 @@ "max": "", "recovery": null }, - "effects": [], + "effects": [ + { + "_id": "eZp1PSCHZzdb47oM", + "onSave": false + } + ], "target": { "type": "any", "amount": null }, "name": "Circle", "img": "icons/magic/unholy/barrier-fire-pink.webp", - "range": "", - "areas": [ - { - "name": "Circle of Defilement", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [ - "KlTKlZXjdXQ9v6qB" - ] - } - ] + "range": "" }, "4x13WyksHU0u0j20": { "type": "countdown", @@ -647,58 +625,42 @@ "img": "icons/magic/unholy/barrier-fire-pink.webp", "effects": [ { - "name": "Circle Of Defilement", - "disabled": false, + "name": "Circle of Defilement", "img": "icons/magic/unholy/barrier-fire-pink.webp", - "description": "

You are Vulnerable until you leave the circle.

", + "origin": "Compendium.daggerheart.adversaries.Actor.RXkZTwBRi4dJ3JE5.Item.55P7ZijSbQeVHCw4", "transfer": false, - "statuses": [ - "vulnerable" - ], + "_id": "eZp1PSCHZzdb47oM", + "type": "base", "system": { "rangeDependence": { "enabled": false, "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "description": "", - "type": "" - }, - "stacking": null, - "targetDispositions": [ - 1, - 0 - ] - }, - "_id": "KlTKlZXjdXQ9v6qB", - "type": "base", - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null + } }, + "changes": [], + "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "origin": null, + "description": "

Vulnerable until you leave the circle. The circle can be removed by dealing Severe damage to the Undefeated Champion.

", "tint": "#ffffff", - "showIcon": 1, - "folder": null, + "statuses": [ + "vulnerable" + ], "sort": 0, "flags": {}, "_stats": { "compendiumSource": null }, - "_key": "!actors.items.effects!RXkZTwBRi4dJ3JE5.55P7ZijSbQeVHCw4.KlTKlZXjdXQ9v6qB" + "_key": "!actors.items.effects!RXkZTwBRi4dJ3JE5.55P7ZijSbQeVHCw4.eZp1PSCHZzdb47oM" } ], "folder": null, @@ -735,8 +697,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -762,7 +724,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -813,7 +775,7 @@ "name": "Doombringer", "type": "feature", "system": { - "description": "

When a target marks HP from an attack by the @Lookup[@name], all PCs within Far range of the target lose a Hope.

", + "description": "

When a target marks HP from an attack by the @Lookup[@name], all PCs within Far range of the target lose a Hope.

@Template[type:emanation|range:f]

", "resource": null, "actions": { "liwKSCTmQqZasAf6": { @@ -830,8 +792,8 @@ "recovery": null }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -856,9 +818,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -867,16 +828,7 @@ "effects": [], "name": "Lose Hope", "img": "icons/magic/death/skull-energy-light-purple.webp", - "range": "far", - "areas": [ - { - "name": "Doombringer", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "far" } }, "originItemType": null, diff --git a/src/packs/adversaries/adversary_Giant_Beastmaster_8VZIgU12cB3cvlyH.json b/src/packs/adversaries/adversary_Giant_Beastmaster_8VZIgU12cB3cvlyH.json index c6a482dd..6d09a490 100644 --- a/src/packs/adversaries/adversary_Giant_Beastmaster_8VZIgU12cB3cvlyH.json +++ b/src/packs/adversaries/adversary_Giant_Beastmaster_8VZIgU12cB3cvlyH.json @@ -81,8 +81,8 @@ }, "range": "far", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -108,7 +108,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -269,8 +269,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -294,7 +294,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -352,19 +352,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until you break free with a successful Finesse or Strength Roll.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

You are Restrained until you break free with a successful Finesse or Strength Roll.

", "tint": "#ffffff", @@ -376,16 +375,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!8VZIgU12cB3cvlyH.6ZrDjgnWufJohkp1.vb1sZCOLwDNLsr3j" } ], diff --git a/src/packs/adversaries/adversary_Giant_Brawler_YnObCleGjPT7yqEc.json b/src/packs/adversaries/adversary_Giant_Brawler_YnObCleGjPT7yqEc.json index acb9c219..4f76b706 100644 --- a/src/packs/adversaries/adversary_Giant_Brawler_YnObCleGjPT7yqEc.json +++ b/src/packs/adversaries/adversary_Giant_Brawler_YnObCleGjPT7yqEc.json @@ -81,8 +81,8 @@ }, "range": "veryClose", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -108,7 +108,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -138,9 +138,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -191,7 +194,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -217,15 +220,14 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { "name": "Battering Ram", "type": "feature", "system": { - "description": "

Mark a Stress to have the @Lookup[@name] charge at an inanimate object within Close range they could feasibly smash (such as a wall, cart, or market stand) and destroy it. All targets within Very Close range of the object must succeed on an Agility Reaction Roll or take 2d4+3 physical damage from the shrapnel.

", + "description": "

Mark a Stress to have the @Lookup[@name] charge at an inanimate object within Close range they could feasibly smash (such as a wall, cart, or market stand) and destroy it. All targets within Very Close range of the object must succeed on an Agility Reaction Roll or take 2d4+3 physical damage from the shrapnel.

@Template[type:circle|range:vc]

", "resource": null, "actions": { "zns57MqnZ6M1d4r0": { @@ -249,8 +251,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -276,7 +278,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -306,16 +308,7 @@ }, "name": "Roll Save", "img": "icons/skills/melee/shield-damaged-broken-orange.webp", - "range": "close", - "areas": [ - { - "name": "Battering Ram", - "type": "placed", - "shape": "circle", - "size": "veryClose", - "effects": [] - } - ] + "range": "close" } }, "originItemType": null, @@ -358,8 +351,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -385,7 +378,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -459,8 +452,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -486,7 +479,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Giant_Eagle_OMQ0v6PE8s1mSU0K.json b/src/packs/adversaries/adversary_Giant_Eagle_OMQ0v6PE8s1mSU0K.json index a8a33586..b0ba4170 100644 --- a/src/packs/adversaries/adversary_Giant_Eagle_OMQ0v6PE8s1mSU0K.json +++ b/src/packs/adversaries/adversary_Giant_Eagle_OMQ0v6PE8s1mSU0K.json @@ -98,8 +98,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -125,7 +125,7 @@ }, "base": false } - }, + ], "includeBase": false }, "target": { @@ -345,8 +345,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -372,7 +372,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -430,18 +430,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "act" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Vulnerable until the next time you act.

", "tint": "#ffffff", @@ -453,16 +453,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!OMQ0v6PE8s1mSU0K.MabIQE1Kjn60j08J.m6qqQZxukDPVcGdQ" } ], @@ -499,8 +489,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -526,7 +516,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -643,8 +633,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -670,7 +660,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Giant_Mosquitoes_IIWV4ysJPFPnTP7W.json b/src/packs/adversaries/adversary_Giant_Mosquitoes_IIWV4ysJPFPnTP7W.json index a74cb88d..fbb30d40 100644 --- a/src/packs/adversaries/adversary_Giant_Mosquitoes_IIWV4ysJPFPnTP7W.json +++ b/src/packs/adversaries/adversary_Giant_Mosquitoes_IIWV4ysJPFPnTP7W.json @@ -74,8 +74,8 @@ "motivesAndTactics": "Fly away, harass, steal blood", "attack": { "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -101,7 +101,7 @@ "resultBased": false, "base": false } - } + ] }, "name": "Proboscis", "img": "icons/skills/wounds/blood-cells-vessel-red.webp", diff --git a/src/packs/adversaries/adversary_Giant_Rat_4PfLnaCrOcMdb4dK.json b/src/packs/adversaries/adversary_Giant_Rat_4PfLnaCrOcMdb4dK.json index 746806d9..d1df6b57 100644 --- a/src/packs/adversaries/adversary_Giant_Rat_4PfLnaCrOcMdb4dK.json +++ b/src/packs/adversaries/adversary_Giant_Rat_4PfLnaCrOcMdb4dK.json @@ -72,8 +72,8 @@ "name": "Claws", "img": "icons/creatures/claws/claw-straight-brown.webp", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -100,7 +100,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -131,9 +131,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -184,7 +187,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -210,8 +213,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -270,38 +272,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { - "applyTo": "hitPoints", - "resultBased": false, - "value": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": true, - "formula": "1" - } - }, - "valueAlt": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": false, - "formula": "" - } - }, - "base": false, - "type": [ - "physical" - ] - } - }, - "includeBase": false, - "groupAttack": "close" + "parts": [], + "includeBase": false }, "target": { "type": "any", @@ -328,7 +300,7 @@ "difficulty": null, "damageMod": "none" }, - "name": "Spend Fear", + "name": "Attack", "img": "icons/creatures/abilities/tail-strike-bone-orange.webp", "range": "" } diff --git a/src/packs/adversaries/adversary_Giant_Recruit_5s8wSvpyC5rxY5aD.json b/src/packs/adversaries/adversary_Giant_Recruit_5s8wSvpyC5rxY5aD.json index 6611496f..adcdf015 100644 --- a/src/packs/adversaries/adversary_Giant_Recruit_5s8wSvpyC5rxY5aD.json +++ b/src/packs/adversaries/adversary_Giant_Recruit_5s8wSvpyC5rxY5aD.json @@ -62,8 +62,8 @@ "name": "Warhammer", "img": "icons/weapons/hammers/hammer-double-stone-worn.webp", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -90,7 +90,7 @@ }, "base": false } - } + ] }, "range": "veryClose", "roll": { @@ -125,9 +125,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -178,7 +181,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -204,8 +207,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -240,95 +242,35 @@ "description": "

Spend a Fear to choose a target and spotlight all @Lookup[@name]s within Close range of them. Those Minions move into Melee range of the target and make one shared attack roll. On a success, they deal @Lookup[@system.attack.damageFormula] physical damage each. Combine this damage.

", "resource": null, "actions": { - "wez1xgy9vScux9wi": { - "type": "attack", - "_id": "wez1xgy9vScux9wi", + "DjbPQowW1OdBD9Zn": { + "type": "effect", + "_id": "DjbPQowW1OdBD9Zn", "systemPath": "actions", - "baseAction": false, "description": "", "chatDisplay": true, - "originItem": { - "type": "itemCollection" - }, "actionType": "action", - "triggers": [], "cost": [ { - "consumeOnSuccess": false, "scalable": false, "key": "fear", "value": 1, - "itemId": null, - "step": null + "keyIsID": false, + "step": null, + "consumeOnSuccess": false } ], "uses": { "value": null, "max": "", - "recovery": null, - "consumeOnSuccess": false - }, - "damage": { - "parts": { - "hitPoints": { - "applyTo": "hitPoints", - "resultBased": false, - "value": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": true, - "formula": "5" - } - }, - "valueAlt": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": false, - "formula": "" - } - }, - "base": false, - "type": [ - "physical" - ] - } - }, - "includeBase": false, - "direct": false, - "groupAttack": "close" - }, - "target": { - "type": "any", - "amount": null + "recovery": null }, "effects": [], - "roll": { - "type": "attack", - "trait": null, - "difficulty": null, - "bonus": null, - "advState": "neutral", - "diceRolling": { - "multiplier": "prof", - "flatMultiplier": 1, - "dice": "d6", - "compare": null, - "treshold": null - }, - "useDefault": false - }, - "save": { - "trait": null, - "difficulty": null, - "damageMod": "none" + "target": { + "type": "self", + "amount": null }, "name": "Spend Fear", + "img": "icons/creatures/abilities/tail-strike-bone-orange.webp", "range": "" } }, diff --git a/src/packs/adversaries/adversary_Giant_Scorpion_fmfntuJ8mHRCAktP.json b/src/packs/adversaries/adversary_Giant_Scorpion_fmfntuJ8mHRCAktP.json index 03a0272d..99b5ed46 100644 --- a/src/packs/adversaries/adversary_Giant_Scorpion_fmfntuJ8mHRCAktP.json +++ b/src/packs/adversaries/adversary_Giant_Scorpion_fmfntuJ8mHRCAktP.json @@ -80,8 +80,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -253,8 +253,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -280,7 +280,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -354,8 +354,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -381,7 +381,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -438,18 +438,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "shortRest" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

You are Poisoned until your next rest or until you succeed on a Knowledge Roll (16). While Poisoned, you must roll a d6 before you make an action roll. On a result of 4 or lower, you must mark a Stress.

[[/dr trait=knowledge difficulty=16]]

", "tint": "#ffffff", @@ -459,16 +459,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!fmfntuJ8mHRCAktP.lANiDkxxth2sGacT.oILkLJlGNZl7KI1R" } ], @@ -508,8 +498,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -535,7 +525,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Glass_Snake_8KWVLWXFhlY2kYx0.json b/src/packs/adversaries/adversary_Glass_Snake_8KWVLWXFhlY2kYx0.json index f290875d..f02a1c52 100644 --- a/src/packs/adversaries/adversary_Glass_Snake_8KWVLWXFhlY2kYx0.json +++ b/src/packs/adversaries/adversary_Glass_Snake_8KWVLWXFhlY2kYx0.json @@ -75,8 +75,8 @@ }, "range": "veryClose", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -102,7 +102,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -132,9 +132,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -185,7 +188,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -211,8 +214,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -238,8 +240,8 @@ "recovery": null }, "damage": { - "parts": { - "armor": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -264,7 +266,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -324,8 +326,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -349,9 +351,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -380,16 +381,7 @@ }, "name": "Attack", "img": "icons/skills/melee/blood-slash-foam-red.webp", - "range": "veryClose", - "areas": [ - { - "name": "Spinning Serpent", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "veryClose" } }, "originItemType": null, @@ -416,7 +408,7 @@ "_id": "LR5XHauNtWcl18CY", "img": "icons/magic/acid/projectile-needles-salvo-green.webp", "system": { - "description": "

Spend a Fear to introduce a d6 Spitter Die. When the @Lookup[@name] is in the spotlight, roll this die. On a result of 5 or higher, all targets in front of the @Lookup[@name] within Far range must succeed on an Agility Reaction Roll or take 1d4 physical damage. The @Lookup[@name] can take the spotlight a second time this GM turn.

", + "description": "

Spend a Fear to introduce a d6 Spitter Die. When the @Lookup[@name] is in the spotlight, roll this die. On a result of 5 or higher, all targets in front of the @Lookup[@name] within Far range must succeed on an Agility Reaction Roll or take 1d4 physical damage. The @Lookup[@name] can take the spotlight a second time this GM turn.

@Template[type:inFront|range:f]

", "resource": null, "actions": { "yx5fjMLLwSnvSbqs": { @@ -457,7 +449,7 @@ "type": "attack", "_id": "Ds6KlQKZCOhh5OMT", "systemPath": "actions", - "description": "

All targets in front of the @Lookup[@name] within Far range must succeed on an Agility Reaction Roll or take 1d4 physical damage.

", + "description": "

All targets in front of the @Lookup[@name] within Far range must succeed on an Agility Reaction Roll or take 1d4 physical damage.

@Template[type:inFront|range:f]

", "chatDisplay": true, "actionType": "action", "cost": [], @@ -467,8 +459,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -494,9 +486,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -525,16 +516,7 @@ }, "name": "Spit Attack", "img": "icons/magic/acid/projectile-needles-salvo-green.webp", - "range": "far", - "areas": [ - { - "name": "Spitter", - "type": "placed", - "shape": "inFront", - "size": "far", - "effects": [] - } - ] + "range": "far" }, "xccwknU2xHUwQSdn": { "type": "attack", @@ -550,7 +532,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -602,15 +584,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [] + } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

You have a d6 Spitter Die. When the Snake is in the spotlight, roll this die. On a result of 5 or higher, all targets in front of the Snake within Far range must succeed on an Agility Reaction Roll or take 1d4 physical damage. The Snake can take the spotlight a second time this GM turn.

", "tint": "#ffffff", @@ -620,9 +605,6 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!8KWVLWXFhlY2kYx0.LR5XHauNtWcl18CY.Mchd23xNQ4nSWw9X" } ], diff --git a/src/packs/adversaries/adversary_Gorgon_8mJYMpbLTb8qIOrr.json b/src/packs/adversaries/adversary_Gorgon_8mJYMpbLTb8qIOrr.json index 1fcfcce4..deeafa37 100644 --- a/src/packs/adversaries/adversary_Gorgon_8mJYMpbLTb8qIOrr.json +++ b/src/packs/adversaries/adversary_Gorgon_8mJYMpbLTb8qIOrr.json @@ -80,8 +80,8 @@ }, "range": "far", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - } + ] }, "img": "icons/weapons/bows/shortbow-recurve-yellow.webp", "type": "attack", @@ -335,25 +335,25 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.rules.conditionImmunities.hidden", - "value": 1, - "priority": null, - "type": "override" - } - ], - "duration": { - "type": "scene" } }, + "changes": [ + { + "key": "system.rules.conditionImmunities.hidden", + "mode": 5, + "value": "1", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

You Glow until the end of the scene and can’t become Hidden. Attack rolls made against you have advantage.

", "tint": "#ffffff", @@ -363,16 +363,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!8mJYMpbLTb8qIOrr.NepVGKOo1lHYjA1F.bYBrgiSwHwYfQyjn" } ], @@ -409,8 +399,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -436,7 +426,7 @@ } } }, - "stress": { + { "value": { "custom": { "enabled": true, @@ -461,7 +451,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -541,7 +531,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -652,8 +642,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -679,7 +669,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Greater_Earth_Elemental_dsfB3YhoL5SudvS2.json b/src/packs/adversaries/adversary_Greater_Earth_Elemental_dsfB3YhoL5SudvS2.json index 72ad8ae2..48926d06 100644 --- a/src/packs/adversaries/adversary_Greater_Earth_Elemental_dsfB3YhoL5SudvS2.json +++ b/src/packs/adversaries/adversary_Greater_Earth_Elemental_dsfB3YhoL5SudvS2.json @@ -75,8 +75,8 @@ }, "range": "veryClose", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -102,7 +102,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -132,9 +132,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -185,7 +188,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -211,8 +214,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -266,8 +268,8 @@ "recovery": null }, "damage": { - "parts": { - "armor": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -292,7 +294,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -396,7 +398,7 @@ "name": "Rockslide", "type": "feature", "system": { - "description": "

Mark a Stress to create a rockslide that buries the land in front of @Lookup[@name] within Close range with rockfall. All targets in this area must make an Agility Reaction Roll (19). Targets who fail take 2d12+5 physical damage and become Vulnerable until their next roll with Hope. Targets who succeed take half damage.

", + "description": "

Mark a Stress to create a rockslide that buries the land in front of @Lookup[@name] within Close range with rockfall. All targets in this area must make an Agility Reaction Roll (19). Targets who fail take 2d12+5 physical damage and become Vulnerable until their next roll with Hope. Targets who succeed take half damage.

@Template[type:inFront|range:c]

", "resource": null, "actions": { "eLGIC3kVjLo8FEvy": { @@ -420,8 +422,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -447,9 +449,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -483,16 +484,7 @@ }, "name": "Roll Save", "img": "icons/magic/earth/barrier-stone-brown-green.webp", - "range": "", - "areas": [ - { - "name": "Rockslide", - "type": "placed", - "shape": "inFront", - "size": "close", - "effects": [] - } - ] + "range": "" } }, "originItemType": null, @@ -515,19 +507,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until your next roll with Hope.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Vulnerable until your next roll with Hope.

", "tint": "#ffffff", @@ -539,16 +530,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!dsfB3YhoL5SudvS2.q45DiEFlXqcXZ5hv.38MUzfbH64EMLVse" } ], @@ -586,8 +567,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -613,7 +594,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Greater_Water_Elemental_xIICT6tEdnA7dKDV.json b/src/packs/adversaries/adversary_Greater_Water_Elemental_xIICT6tEdnA7dKDV.json index db73a536..be037b10 100644 --- a/src/packs/adversaries/adversary_Greater_Water_Elemental_xIICT6tEdnA7dKDV.json +++ b/src/packs/adversaries/adversary_Greater_Water_Elemental_xIICT6tEdnA7dKDV.json @@ -75,8 +75,8 @@ }, "range": "veryClose", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -102,7 +102,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -132,9 +132,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -185,7 +188,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -211,8 +214,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -243,8 +245,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -270,7 +272,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -375,7 +377,7 @@ "name": "Drowning Embrace", "type": "feature", "system": { - "description": "

Spend a Fear to make an attack against all targets within Very Close range. Targets the @Lookup[@name] succeeds against become Restrained and Vulnerable as they begin drowning. A target can break free, ending both conditions, with a successful Strength or Instinct Roll.

", + "description": "

Spend a Fear to make an attack against all targets within Very Close range. Targets the @Lookup[@name] succeeds against become Restrained and Vulnerable as they begin drowning. A target can break free, ending both conditions, with a successful Strength or Instinct Roll.

@Template[type:emanation|range:vc]

", "resource": null, "actions": { "ooYbiLrYjoWXIfe9": { @@ -399,9 +401,8 @@ "recovery": null }, "damage": { - "parts": {}, - "includeBase": false, - "groupAttack": "" + "parts": [], + "includeBase": false }, "target": { "type": "any", @@ -435,16 +436,7 @@ }, "name": "Attack", "img": "icons/magic/water/vortex-water-whirlpool-blue.webp", - "range": "veryClose", - "areas": [ - { - "name": "Drowning Embrace", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "veryClose" } }, "originItemType": null, @@ -467,41 +459,30 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

You can break free with a successful Strength or Instinct Roll.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

You are Restrained and Vulnerable as you are drowning. You can break free, ending both conditions, with a successful Strength or Instinct Roll.

", "tint": "#ffffff", "statuses": [ - "vulnerable", - "restrained" + "restrained", + "vulnerable" ], "sort": 0, "flags": {}, "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!xIICT6tEdnA7dKDV.bcwFQeuU6ZfIGjau.X8NF2OB23mSpDvlx" } ], diff --git a/src/packs/adversaries/adversary_Green_Ooze_SHXedd9zZPVfUgUa.json b/src/packs/adversaries/adversary_Green_Ooze_SHXedd9zZPVfUgUa.json index a3a76d7a..b03b5495 100644 --- a/src/packs/adversaries/adversary_Green_Ooze_SHXedd9zZPVfUgUa.json +++ b/src/packs/adversaries/adversary_Green_Ooze_SHXedd9zZPVfUgUa.json @@ -79,8 +79,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -106,7 +106,7 @@ }, "base": false } - } + ] }, "img": "icons/creatures/slimes/slime-movement-dripping-pseudopods-green.webp", "type": "attack", @@ -277,8 +277,8 @@ "recovery": null }, "damage": { - "parts": { - "armor": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -303,7 +303,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -356,8 +356,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -383,7 +383,7 @@ } } }, - "stress": { + { "value": { "custom": { "enabled": true, @@ -408,7 +408,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -465,19 +465,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

If the Green Ooze takes Severe damage, the target is freed.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

You must mark an additional Stress when you make an action roll. If the Ooze takes Severe damage, you are freed.

", "tint": "#ffffff", @@ -487,16 +486,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!SHXedd9zZPVfUgUa.Sm9Sk4mSvcq6PkmR.yk5kR5OVLCgDWfgY" } ], diff --git a/src/packs/adversaries/adversary_Hallowed_Archer_kabueAo6BALApWqp.json b/src/packs/adversaries/adversary_Hallowed_Archer_kabueAo6BALApWqp.json index eb7eafc1..8cce1b94 100644 --- a/src/packs/adversaries/adversary_Hallowed_Archer_kabueAo6BALApWqp.json +++ b/src/packs/adversaries/adversary_Hallowed_Archer_kabueAo6BALApWqp.json @@ -75,8 +75,8 @@ "name": "Sanctified Longbow", "img": "icons/weapons/bows/shortbow-recurve-yellow.webp", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -102,7 +102,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -314,8 +314,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -341,7 +341,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Hallowed_Soldier_VENwg7xEFcYObjmT.json b/src/packs/adversaries/adversary_Hallowed_Soldier_VENwg7xEFcYObjmT.json index 3e1ab854..95a2ecd0 100644 --- a/src/packs/adversaries/adversary_Hallowed_Soldier_VENwg7xEFcYObjmT.json +++ b/src/packs/adversaries/adversary_Hallowed_Soldier_VENwg7xEFcYObjmT.json @@ -65,8 +65,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -93,7 +93,7 @@ }, "base": false } - } + ] }, "img": "icons/skills/melee/sword-shield-stylized-white.webp", "type": "attack", @@ -125,9 +125,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -178,7 +181,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -204,8 +207,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -295,95 +297,33 @@ "description": "

Spend a Fear to choose a target and spotlight all @Lookup[@name]s within Close range of them. Those Minions move into Melee range of the target and make one shared attack roll. On a success, they deal @Lookup[@system.attack.damageFormula] physical damage each. Combine this damage.

", "resource": null, "actions": { - "irZGPKPpGLA6sP2y": { - "type": "attack", - "_id": "irZGPKPpGLA6sP2y", + "eo7J0v1B5zPHul1M": { + "type": "effect", + "_id": "eo7J0v1B5zPHul1M", "systemPath": "actions", - "baseAction": false, "description": "", "chatDisplay": true, - "originItem": { - "type": "itemCollection" - }, "actionType": "action", - "triggers": [], "cost": [ { "scalable": false, "key": "fear", "value": 1, - "itemId": null, - "step": null, - "consumeOnSuccess": false + "step": null } ], "uses": { "value": null, "max": "", - "recovery": null, - "consumeOnSuccess": false - }, - "damage": { - "parts": { - "hitPoints": { - "applyTo": "hitPoints", - "resultBased": false, - "value": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": true, - "formula": "10" - } - }, - "valueAlt": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": false, - "formula": "" - } - }, - "base": false, - "type": [ - "physical" - ] - } - }, - "includeBase": false, - "direct": false, - "groupAttack": "close" - }, - "target": { - "type": "any", - "amount": null + "recovery": null }, "effects": [], - "roll": { - "type": "attack", - "trait": null, - "difficulty": null, - "bonus": null, - "advState": "neutral", - "diceRolling": { - "multiplier": "prof", - "flatMultiplier": 1, - "dice": "d6", - "compare": null, - "treshold": null - }, - "useDefault": false - }, - "save": { - "trait": null, - "difficulty": null, - "damageMod": "none" + "target": { + "type": "self", + "amount": null }, "name": "Spend Fear", + "img": "icons/creatures/abilities/tail-strike-bone-orange.webp", "range": "" } }, diff --git a/src/packs/adversaries/adversary_Harrier_uRtghKE9mHlII4rs.json b/src/packs/adversaries/adversary_Harrier_uRtghKE9mHlII4rs.json index 84034a7e..89d82a0b 100644 --- a/src/packs/adversaries/adversary_Harrier_uRtghKE9mHlII4rs.json +++ b/src/packs/adversaries/adversary_Harrier_uRtghKE9mHlII4rs.json @@ -79,8 +79,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -106,7 +106,7 @@ }, "base": false } - } + ] }, "img": "icons/weapons/polearms/spear-hooked-rounded.webp", "type": "attack", @@ -278,8 +278,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -305,7 +305,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Head_Guard_mK3A5FTx6k8iPU3F.json b/src/packs/adversaries/adversary_Head_Guard_mK3A5FTx6k8iPU3F.json index 9a6cc509..75afed49 100644 --- a/src/packs/adversaries/adversary_Head_Guard_mK3A5FTx6k8iPU3F.json +++ b/src/packs/adversaries/adversary_Head_Guard_mK3A5FTx6k8iPU3F.json @@ -85,8 +85,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -112,7 +112,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -143,9 +143,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -196,7 +199,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -222,8 +225,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -232,7 +234,7 @@ "_id": "SsgN2qSYpQLR43Cz", "img": "icons/skills/movement/arrows-up-trio-red.webp", "system": { - "description": "

Spend 2 Fear to spotlight the @Lookup[@name] and up to 2d4 allies within Far range.

", + "description": "

Spend 2 Fear to spotlight the @Lookup[@name] and up to 2d4 allies within Far range.

@Template[type:emanation|range:f]

", "resource": null, "actions": { "lI0lnRb3xrUjqIYX": { @@ -256,9 +258,8 @@ "recovery": null }, "damage": { - "parts": {}, - "includeBase": false, - "groupAttack": "" + "parts": [], + "includeBase": false }, "target": { "type": "any", @@ -287,16 +288,7 @@ }, "name": "Rally", "img": "icons/skills/movement/arrows-up-trio-red.webp", - "range": "", - "areas": [ - { - "name": "Rally Guards", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "" } }, "originItemType": null, @@ -323,7 +315,7 @@ "_id": "YeJ7eJVCKsRxG8mk", "img": "icons/skills/ranged/target-bullseye-arrow-blue.webp", "system": { - "description": "

Countdown (5). When the @Lookup[@name] is in the spotlight for the first time, activate the countdown. It ticks down when a PC makes an attack roll. When it triggers, all Archer Guards within Far range make a standard attack with advantage against the nearest target within their range. If any attacks succeed on the same target, combine their damage.

", + "description": "

Countdown (5). When the @Lookup[@name] is in the spotlight for the first time, activate the countdown. It ticks down when a PC makes an attack roll. When it triggers, all Archer Guards within Far range make a standard attack with advantage against the nearest target within their range. If any attacks succeed on the same target, combine their damage.

@Template[type:emanation|range:f]

", "resource": null, "actions": { "xyhaCmPGiVMsTViH": { @@ -361,16 +353,7 @@ ], "name": "Start Countdown", "img": "icons/skills/ranged/target-bullseye-arrow-blue.webp", - "range": "", - "areas": [ - { - "name": "On My Signal", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "" } }, "originItemType": null, @@ -415,8 +398,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -442,7 +425,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Head_Vampire_i2UNbRvgyoSs07M6.json b/src/packs/adversaries/adversary_Head_Vampire_i2UNbRvgyoSs07M6.json index b17c85bc..d5891359 100644 --- a/src/packs/adversaries/adversary_Head_Vampire_i2UNbRvgyoSs07M6.json +++ b/src/packs/adversaries/adversary_Head_Vampire_i2UNbRvgyoSs07M6.json @@ -80,8 +80,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -138,9 +138,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -191,7 +194,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -217,15 +220,14 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { "name": "Terrifying", "type": "feature", "system": { - "description": "

When the @Lookup[@name] makes a successful attack, all PCs within Far range lose a Hope and you gain a Fear.

", + "description": "

When the @Lookup[@name] makes a successful attack, all PCs within Far range lose a Hope and you gain a Fear.

@Template[type:emanation|range:f]

", "resource": null, "actions": { "Rf2ZL3EjCzudonRb": { @@ -242,8 +244,8 @@ "recovery": null }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -268,9 +270,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -279,16 +280,7 @@ "effects": [], "name": "Lose Hope", "img": "icons/magic/death/skull-energy-light-purple.webp", - "range": "far", - "areas": [ - { - "name": "Terrifying", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "far" } }, "originItemType": null, @@ -330,7 +322,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -402,8 +394,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -428,7 +420,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -533,7 +525,7 @@ "name": "Lifesuck", "type": "feature", "system": { - "description": "

When the @Lookup[@name] is spotlighted, roll a d8. On a result of 6 or higher, all targets within Very Close range must mark a HP.

", + "description": "

When the @Lookup[@name] is spotlighted, roll a d8. On a result of 6 or higher, all targets within Very Close range must mark a HP.

@Template[type:emanation|range:vc]

", "resource": null, "actions": { "DA8qT2omBcG4oryX": { @@ -550,8 +542,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -576,9 +568,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -607,16 +598,7 @@ }, "name": "Roll d8", "img": "icons/magic/unholy/strike-beam-blood-small-red-purple.webp", - "range": "veryClose", - "areas": [ - { - "name": "Lifesuck", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "veryClose" } }, "originItemType": null, diff --git a/src/packs/adversaries/adversary_High_Seraph_r1mbfSSwKWdcFdAU.json b/src/packs/adversaries/adversary_High_Seraph_r1mbfSSwKWdcFdAU.json index 3dc96fd5..0a952540 100644 --- a/src/packs/adversaries/adversary_High_Seraph_r1mbfSSwKWdcFdAU.json +++ b/src/packs/adversaries/adversary_High_Seraph_r1mbfSSwKWdcFdAU.json @@ -80,8 +80,8 @@ }, "range": "veryClose", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - } + ] }, "img": "icons/skills/melee/strike-blade-hooked-orange-blue.webp", "type": "attack", @@ -391,21 +391,20 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until the High Seraph is defeated.Β The High Seraph can only mark one target at a time.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

While Guilty, you don’t gain Hope on a result with Hope.

", + "description": "

While Guilty, you don’t gain Hope on a result with Hope.

", "tint": "#ffffff", "statuses": [], "sort": 0, @@ -413,16 +412,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!r1mbfSSwKWdcFdAU.FilEB21L5q9XxKE1.O8G0oOf9f3qzNOAT" } ], @@ -466,8 +455,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -493,7 +482,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Huge_Green_Ooze_6hbqmxDXFOzZJDk4.json b/src/packs/adversaries/adversary_Huge_Green_Ooze_6hbqmxDXFOzZJDk4.json index 183719f2..e04b4422 100644 --- a/src/packs/adversaries/adversary_Huge_Green_Ooze_6hbqmxDXFOzZJDk4.json +++ b/src/packs/adversaries/adversary_Huge_Green_Ooze_6hbqmxDXFOzZJDk4.json @@ -80,8 +80,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -138,9 +138,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -191,7 +194,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -217,8 +220,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -272,8 +274,8 @@ "recovery": null }, "damage": { - "parts": { - "armor": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -298,7 +300,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -350,8 +352,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -376,7 +378,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -434,19 +436,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

When the Huge Green Ooze takes Severe damage, all Enveloped targets are freed and the condition is cleared.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

While Enveloped, you must mark an additional Stress every time you make an action roll. When the Ooze takes Severe damage, all Enveloped targets are freed and the condition is cleared.

", "tint": "#ffffff", @@ -456,16 +457,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!6hbqmxDXFOzZJDk4.pfXYuH7rtsyVjSXh.EwZ8owroJxFpg81e" } ], diff --git a/src/packs/adversaries/adversary_Hydra_MI126iMOOobQ1Obn.json b/src/packs/adversaries/adversary_Hydra_MI126iMOOobQ1Obn.json index 9c53487a..4c6fd61f 100644 --- a/src/packs/adversaries/adversary_Hydra_MI126iMOOobQ1Obn.json +++ b/src/packs/adversaries/adversary_Hydra_MI126iMOOobQ1Obn.json @@ -75,8 +75,8 @@ }, "range": "close", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -102,7 +102,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -132,9 +132,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -185,7 +188,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -211,8 +214,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -298,8 +300,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -324,7 +326,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -375,7 +377,7 @@ "name": "Terrifying Chorus", "type": "feature", "system": { - "description": "

All PCs within Far range lose 2 Hope.

", + "description": "

All PCs within Far range lose 2 Hope.

@Template[type:emanation|range:f]

", "resource": null, "actions": { "nJxpFR4Ul0e2RrL4": { @@ -392,8 +394,8 @@ "recovery": null }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -418,9 +420,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -429,16 +430,7 @@ "effects": [], "name": "Lose Hope", "img": "icons/magic/death/skull-energy-light-white.webp", - "range": "far", - "areas": [ - { - "name": "Terrifying Chorus", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "far" } }, "originItemType": null, @@ -515,26 +507,25 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.resistance.magical.immunity", - "value": 1, - "priority": null, - "type": "override" - } - ], - "duration": { - "type": "temporary", - "description": "

Until the next roll with Fear.

" } }, + "changes": [ + { + "key": "system.resistance.magical.immunity", + "mode": 5, + "value": "1", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

While Dazed, they can’t use their Regeneration action but are immune to magic damage.

", "tint": "#ffffff", @@ -544,16 +535,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!MI126iMOOobQ1Obn.sJzjcRBgYRp5f53E.iBJ3YhEkVsGKEIVk" } ], diff --git a/src/packs/adversaries/adversary_Jagged_Knife_Bandit_5Lh1T0zaT8Pkr2U2.json b/src/packs/adversaries/adversary_Jagged_Knife_Bandit_5Lh1T0zaT8Pkr2U2.json index bfbff494..ae359eaf 100644 --- a/src/packs/adversaries/adversary_Jagged_Knife_Bandit_5Lh1T0zaT8Pkr2U2.json +++ b/src/packs/adversaries/adversary_Jagged_Knife_Bandit_5Lh1T0zaT8Pkr2U2.json @@ -79,8 +79,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -106,7 +106,7 @@ }, "base": false } - } + ] }, "img": "icons/weapons/daggers/dagger-twin-green.webp", "type": "attack", @@ -272,8 +272,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -299,7 +299,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Jagged_Knife_Hexer_MbBPIOxaxXYNApXz.json b/src/packs/adversaries/adversary_Jagged_Knife_Hexer_MbBPIOxaxXYNApXz.json index c6b2554e..6ca9749c 100644 --- a/src/packs/adversaries/adversary_Jagged_Knife_Hexer_MbBPIOxaxXYNApXz.json +++ b/src/packs/adversaries/adversary_Jagged_Knife_Hexer_MbBPIOxaxXYNApXz.json @@ -80,8 +80,8 @@ }, "img": "icons/weapons/staves/staff-blue-jewel.webp", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -278,18 +278,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Whenever you roll with Hope, the hexer can mark a stress to make the roll be with Fear instead.

", "tint": "#ffffff", @@ -299,16 +299,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!MbBPIOxaxXYNApXz.Bl8L0RCGOgVUzuXo.ihy3kvEGSOEKdNfT" } ], @@ -347,8 +337,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -374,7 +364,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Jagged_Knife_Kneebreaker_CBKixLH3yhivZZuL.json b/src/packs/adversaries/adversary_Jagged_Knife_Kneebreaker_CBKixLH3yhivZZuL.json index 3ce6a165..c38260e9 100644 --- a/src/packs/adversaries/adversary_Jagged_Knife_Kneebreaker_CBKixLH3yhivZZuL.json +++ b/src/packs/adversaries/adversary_Jagged_Knife_Kneebreaker_CBKixLH3yhivZZuL.json @@ -85,8 +85,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -112,7 +112,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -277,7 +277,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -334,26 +334,25 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.rules.attack.damage.hpDamageTakenMultiplier", - "value": 2, - "priority": null, - "type": "override" - } - ], - "duration": { - "type": "temporary", - "description": "

The target can break free, clearing both conditions, with a successful Strength Roll or is freed automatically if the Jagged Knife Kneebreaker takes Major or greater damage.

" } }, + "changes": [ + { + "key": "system.rules.attack.damage.hpDamageTakenMultiplier", + "mode": 5, + "value": "2", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -366,16 +365,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!CBKixLH3yhivZZuL.Sa4Nt0eoDjirBKGf.d7sB1Qa1kJMnglqu" } ], diff --git a/src/packs/adversaries/adversary_Jagged_Knife_Lackey_C0OMQqV7pN6t7ouR.json b/src/packs/adversaries/adversary_Jagged_Knife_Lackey_C0OMQqV7pN6t7ouR.json index 076318c6..a52ec1c9 100644 --- a/src/packs/adversaries/adversary_Jagged_Knife_Lackey_C0OMQqV7pN6t7ouR.json +++ b/src/packs/adversaries/adversary_Jagged_Knife_Lackey_C0OMQqV7pN6t7ouR.json @@ -64,8 +64,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -92,7 +92,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -131,9 +131,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -184,7 +187,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -210,8 +213,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -249,95 +251,33 @@ "description": "

Spend a Fear to choose a target and spotlight all @Lookup[@name] within Close range of them. Those Minions move into Melee range of the target and make one shared attack roll. On a success, they deal @Lookup[@system.attack.damageFormula] physical damage each. Combine this damage.

", "resource": null, "actions": { - "ferZO3BuiP9zU46m": { - "type": "attack", - "_id": "ferZO3BuiP9zU46m", + "aoQDb2m32NDxE6ZP": { + "type": "effect", + "_id": "aoQDb2m32NDxE6ZP", "systemPath": "actions", - "baseAction": false, "description": "", "chatDisplay": true, - "originItem": { - "type": "itemCollection" - }, "actionType": "action", - "triggers": [], "cost": [ { - "consumeOnSuccess": false, "scalable": false, "key": "fear", "value": 1, - "itemId": null, "step": null } ], "uses": { "value": null, "max": "", - "recovery": null, - "consumeOnSuccess": false - }, - "damage": { - "parts": { - "hitPoints": { - "applyTo": "hitPoints", - "resultBased": false, - "value": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": true, - "formula": "2" - } - }, - "valueAlt": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": false, - "formula": "" - } - }, - "base": false, - "type": [ - "physical" - ] - } - }, - "includeBase": false, - "direct": false, - "groupAttack": "close" + "recovery": null }, + "effects": [], "target": { "type": "any", "amount": null }, - "effects": [], - "roll": { - "type": "attack", - "trait": null, - "difficulty": null, - "bonus": null, - "advState": "neutral", - "diceRolling": { - "multiplier": "prof", - "flatMultiplier": 1, - "dice": "d6", - "compare": null, - "treshold": null - }, - "useDefault": false - }, - "save": { - "trait": null, - "difficulty": null, - "damageMod": "none" - }, "name": "Spend Fear", + "img": "icons/creatures/abilities/tail-strike-bone-orange.webp", "range": "" } }, diff --git a/src/packs/adversaries/adversary_Jagged_Knife_Lieutenant_aTljstqteGoLpCBq.json b/src/packs/adversaries/adversary_Jagged_Knife_Lieutenant_aTljstqteGoLpCBq.json index 771c6692..c139d76f 100644 --- a/src/packs/adversaries/adversary_Jagged_Knife_Lieutenant_aTljstqteGoLpCBq.json +++ b/src/packs/adversaries/adversary_Jagged_Knife_Lieutenant_aTljstqteGoLpCBq.json @@ -80,8 +80,8 @@ }, "range": "close", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -137,9 +137,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -190,7 +193,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -216,8 +219,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -256,16 +258,7 @@ }, "name": "Mark Stress", "img": "icons/skills/movement/arrows-up-trio-red.webp", - "range": "close", - "areas": [ - { - "name": "Tactician", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "originItemType": null, @@ -371,8 +364,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -398,7 +391,7 @@ } } }, - "stress": { + { "value": { "custom": { "enabled": true, @@ -423,7 +416,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -498,8 +491,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -525,7 +518,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Jagged_Knife_Shadow_XF4tYTq9nPJAy2ox.json b/src/packs/adversaries/adversary_Jagged_Knife_Shadow_XF4tYTq9nPJAy2ox.json index 81b95d8b..bca035c1 100644 --- a/src/packs/adversaries/adversary_Jagged_Knife_Shadow_XF4tYTq9nPJAy2ox.json +++ b/src/packs/adversaries/adversary_Jagged_Knife_Shadow_XF4tYTq9nPJAy2ox.json @@ -80,8 +80,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -246,8 +246,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -273,7 +273,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Jagged_Knife_Sniper_1zuyof1XuIfi3aMG.json b/src/packs/adversaries/adversary_Jagged_Knife_Sniper_1zuyof1XuIfi3aMG.json index 62253d69..6fd02cb5 100644 --- a/src/packs/adversaries/adversary_Jagged_Knife_Sniper_1zuyof1XuIfi3aMG.json +++ b/src/packs/adversaries/adversary_Jagged_Knife_Sniper_1zuyof1XuIfi3aMG.json @@ -81,8 +81,8 @@ }, "range": "far", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -108,7 +108,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -246,8 +246,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -273,7 +273,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Juvenile_Flickerfly_MYXmTx2FHcIjdfYZ.json b/src/packs/adversaries/adversary_Juvenile_Flickerfly_MYXmTx2FHcIjdfYZ.json index 24683a37..86d69c37 100644 --- a/src/packs/adversaries/adversary_Juvenile_Flickerfly_MYXmTx2FHcIjdfYZ.json +++ b/src/packs/adversaries/adversary_Juvenile_Flickerfly_MYXmTx2FHcIjdfYZ.json @@ -75,8 +75,8 @@ }, "range": "veryClose", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -102,7 +102,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -132,9 +132,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -185,7 +188,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -211,8 +214,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -294,7 +296,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -398,7 +400,7 @@ "name": "Mind Dance", "type": "feature", "system": { - "description": "

Mark a Stress to create a magically dazzling display that grapples the minds of nearby foes. All targets within Close range must make an Instinct Reaction Roll. For each target who failed, you gain a Fear and the @Lookup[@name] learns one of the target’s fears.

", + "description": "

Mark a Stress to create a magically dazzling display that grapples the minds of nearby foes. All targets within Close range must make an Instinct Reaction Roll. For each target who failed, you gain a Fear and the @Lookup[@name] learns one of the target’s fears.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "0wL3ieMrXEb2gcxe": { @@ -415,9 +417,8 @@ "recovery": null }, "damage": { - "parts": {}, - "includeBase": false, - "groupAttack": "" + "parts": [], + "includeBase": false }, "target": { "type": "any", @@ -446,16 +447,7 @@ }, "name": "Roll Save", "img": "icons/magic/light/explosion-glow-spiral-yellow.webp", - "range": "close", - "areas": [ - { - "name": "Mind Dance", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "originItemType": null, @@ -481,7 +473,7 @@ "name": "Hallucinatory Breath", "type": "feature", "system": { - "description": "

Countdown (Loop 1d6). When the @Lookup[@name] takes damage for the first time, activate the countdown. When it triggers, the @Lookup[@name] breathes hallucinatory gas on all targets in front of them up to Far range. Targets must succeed on an Instinct Reaction Roll or be tormented by fearful hallucinations. Targets whose fears are known to the @Lookup[@name] have disadvantage on this roll. Targets who fail must mark a Stress and lose a Hope.

", + "description": "

Countdown (Loop 1d6). When the @Lookup[@name] takes damage for the first time, activate the countdown. When it triggers, the @Lookup[@name] breathes hallucinatory gas on all targets in front of them up to Far range. Targets must succeed on an Instinct Reaction Roll or be tormented by fearful hallucinations. Targets whose fears are known to the @Lookup[@name] have disadvantage on this roll. Targets who fail must mark a Stress and lose a Hope.

@Template[type:inFront|range:f]

", "resource": null, "actions": { "USEkCakSzYcZbBwY": { @@ -498,8 +490,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -524,7 +516,7 @@ }, "type": [] }, - "hope": { + { "value": { "custom": { "enabled": true, @@ -549,9 +541,8 @@ }, "type": [] } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -580,16 +571,7 @@ }, "name": "Roll Save", "img": "icons/magic/air/fog-gas-smoke-purple.webp", - "range": "far", - "areas": [ - { - "name": "Hallucinatory Breath", - "type": "placed", - "shape": "inFront", - "size": "far", - "effects": [] - } - ] + "range": "far" }, "n8ZuLjwTf2FJ7V6n": { "type": "countdown", diff --git a/src/packs/adversaries/adversary_Knight_of_the_Realm_7ai2opemrclQe3VF.json b/src/packs/adversaries/adversary_Knight_of_the_Realm_7ai2opemrclQe3VF.json index 01435922..71cb7a8d 100644 --- a/src/packs/adversaries/adversary_Knight_of_the_Realm_7ai2opemrclQe3VF.json +++ b/src/packs/adversaries/adversary_Knight_of_the_Realm_7ai2opemrclQe3VF.json @@ -90,8 +90,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -117,7 +117,7 @@ }, "base": false } - } + ] }, "range": "melee", "type": "attack", @@ -392,8 +392,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -417,7 +417,7 @@ } } }, - "stress": { + { "value": { "custom": { "enabled": true, @@ -442,7 +442,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Kraken_4nqv3ZwJGjnmic8j.json b/src/packs/adversaries/adversary_Kraken_4nqv3ZwJGjnmic8j.json index 4bcdc15d..3b84774e 100644 --- a/src/packs/adversaries/adversary_Kraken_4nqv3ZwJGjnmic8j.json +++ b/src/packs/adversaries/adversary_Kraken_4nqv3ZwJGjnmic8j.json @@ -80,8 +80,8 @@ }, "range": "close", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - } + ] }, "img": "icons/creatures/tentacles/tentacles-octopus-black-pink.webp", "type": "attack", @@ -138,9 +138,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -191,7 +194,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -217,8 +220,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -325,7 +327,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -383,41 +385,30 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until you break free with a successful Strength Roll or the Kraken takes Major or greater damage.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

You are Restrained and Vulnerable until you break free with a successful Strength Roll or the Kraken takes Major or greater damage. While Restrained and Vulnerable in this way, you must mark a Stress when you make an action roll.

", "tint": "#ffffff", "statuses": [ - "vulnerable", - "restrained" + "restrained", + "vulnerable" ], "sort": 0, "flags": {}, "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!4nqv3ZwJGjnmic8j.vz2BWhispgR7mSWF.Xes6ZIE01CCN67KF" } ], @@ -437,7 +428,7 @@ "name": "Boiling Blast", "type": "feature", "system": { - "description": "

Spend a Fear to spew a line of boiling water at any number of targets in a line up to Far range. All targets must succeed on an Agility Reaction Roll or take 4d6+9 physical damage. If a target marks an Armor Slot to reduce the damage, they must also mark a Stress.

", + "description": "

Spend a Fear to spew a line of boiling water at any number of targets in a line up to Far range. All targets must succeed on an Agility Reaction Roll or take 4d6+9 physical damage. If a target marks an Armor Slot to reduce the damage, they must also mark a Stress.

@Template[type:ray|range:f]

", "resource": null, "actions": { "pHZUiZRSj4FuG0uK": { @@ -454,8 +445,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -481,9 +472,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -512,16 +502,7 @@ }, "name": "Attack", "img": "icons/magic/water/projectile-icecicle-glowing.webp", - "range": "", - "areas": [ - { - "name": "Boiling Blast", - "type": "placed", - "shape": "line", - "size": "far", - "effects": [] - } - ] + "range": "" } }, "originItemType": null, @@ -565,8 +546,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -592,7 +573,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Masked_Thief_niBpVU7yeo5ccskE.json b/src/packs/adversaries/adversary_Masked_Thief_niBpVU7yeo5ccskE.json index 77d48be3..528df6a9 100644 --- a/src/packs/adversaries/adversary_Masked_Thief_niBpVU7yeo5ccskE.json +++ b/src/packs/adversaries/adversary_Masked_Thief_niBpVU7yeo5ccskE.json @@ -80,8 +80,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - } + ] }, "range": "melee", "type": "attack", @@ -138,9 +138,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -191,7 +194,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -217,8 +220,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -242,8 +244,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -267,7 +269,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -323,7 +325,7 @@ "name": "Escape Plan", "type": "feature", "system": { - "description": "

Mark a Stress to reveal a snare trap set anywhere on the battlefield by the @Lookup[@name]. All targets within Very Close range of the trap must succeed on an Agility Reaction Roll (13) or be pulled off their feet and suspended upside down. A target is Restrained and Vulnerable until they break free, ending both conditions, with a successful Finesse or Strength Roll (13).

", + "description": "

Mark a Stress to reveal a snare trap set anywhere on the battlefield by the @Lookup[@name]. All targets within Very Close range of the trap must succeed on an Agility Reaction Roll (13) or be pulled off their feet and suspended upside down. A target is Restrained and Vulnerable until they break free, ending both conditions, with a successful Finesse or Strength Roll (13).

@Template[type:rect|range:c]

", "resource": null, "actions": { "sq0q1l2Go4GduR3B": { @@ -340,7 +342,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -375,16 +377,7 @@ }, "name": "Roll Save", "img": "icons/environment/traps/trap-jaw-tan.webp", - "range": "", - "areas": [ - { - "name": "Escape Plan", - "type": "placed", - "shape": "circle", - "size": "veryClose", - "effects": [] - } - ] + "range": "" } }, "originItemType": null, @@ -407,41 +400,30 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until you break free with a successful Finesse or Strength Roll (13).

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

You are Restrained and Vulnerable until you break free, ending both conditions, with a successful Finesse or Strength Roll (13).

[[/dr trait=finesse difficulty=13]]
[[/dr trait=strength difficulty=13]]

", "tint": "#ffffff", "statuses": [ - "vulnerable", - "restrained" + "restrained", + "vulnerable" ], "sort": 0, "flags": {}, "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!niBpVU7yeo5ccskE.tP2DD751nOLxFVps.zMut1PRphlwE0xOa" } ], diff --git a/src/packs/adversaries/adversary_Master_Assassin_dNta0cUzr96xcFhf.json b/src/packs/adversaries/adversary_Master_Assassin_dNta0cUzr96xcFhf.json index 2131023a..3cec6e0b 100644 --- a/src/packs/adversaries/adversary_Master_Assassin_dNta0cUzr96xcFhf.json +++ b/src/packs/adversaries/adversary_Master_Assassin_dNta0cUzr96xcFhf.json @@ -86,8 +86,8 @@ }, "range": "close", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -113,7 +113,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -254,8 +254,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false, @@ -283,7 +283,7 @@ } } } - }, + ], "includeBase": false, "direct": true }, @@ -469,8 +469,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -496,7 +496,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Merchant_Al3w2CgjfdT3p9ma.json b/src/packs/adversaries/adversary_Merchant_Al3w2CgjfdT3p9ma.json index 482ba727..880b1a6e 100644 --- a/src/packs/adversaries/adversary_Merchant_Al3w2CgjfdT3p9ma.json +++ b/src/packs/adversaries/adversary_Merchant_Al3w2CgjfdT3p9ma.json @@ -79,8 +79,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -106,7 +106,7 @@ }, "base": false } - } + ] }, "img": "icons/weapons/clubs/club-baton-blue.webp", "type": "attack", @@ -272,8 +272,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -298,7 +298,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Merchant_Baron_Vy02IhGhkJLuezu4.json b/src/packs/adversaries/adversary_Merchant_Baron_Vy02IhGhkJLuezu4.json index 7ace67ac..15c0aeb9 100644 --- a/src/packs/adversaries/adversary_Merchant_Baron_Vy02IhGhkJLuezu4.json +++ b/src/packs/adversaries/adversary_Merchant_Baron_Vy02IhGhkJLuezu4.json @@ -85,8 +85,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -112,7 +112,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -249,8 +249,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -275,7 +275,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Minor_Chaos_Elemental_sRn4bqerfARvhgSV.json b/src/packs/adversaries/adversary_Minor_Chaos_Elemental_sRn4bqerfARvhgSV.json index 9ddfb4f3..b1732c71 100644 --- a/src/packs/adversaries/adversary_Minor_Chaos_Elemental_sRn4bqerfARvhgSV.json +++ b/src/packs/adversaries/adversary_Minor_Chaos_Elemental_sRn4bqerfARvhgSV.json @@ -74,8 +74,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -101,7 +101,7 @@ }, "base": false } - } + ] }, "range": "close", "type": "attack", @@ -132,9 +132,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -185,7 +188,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -211,8 +214,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -291,7 +293,7 @@ "_id": "oAxhAawgcK7DAdpa", "img": "icons/magic/sonic/explosion-shock-sound-wave.webp", "system": { - "description": "

Mark a HP to force all targets within Close range to mark a Stress and become Vulnerable until their next rest or they clear a HP.

", + "description": "

Mark a HP to force all targets within Close range to mark a Stress and become Vulnerable until their next rest or they clear a HP.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "g4CVwjDeJgTJ2oCw": { @@ -315,8 +317,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -341,9 +343,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -357,16 +358,7 @@ ], "name": "Mark HP", "img": "icons/magic/sonic/explosion-shock-sound-wave.webp", - "range": "close", - "areas": [ - { - "name": "Sickening Flux", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "originItemType": null, @@ -388,18 +380,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "shortRest" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Vulnerable until your next rest or you clear a HP.

", "tint": "#ffffff", @@ -411,16 +403,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!sRn4bqerfARvhgSV.oAxhAawgcK7DAdpa.KIyV2eXDmmymXY5y" } ], @@ -442,7 +424,7 @@ "_id": "updQuIK8sybf4YmW", "img": "icons/magic/light/explosion-glow-spiral-teal.webp", "system": { - "description": "

Spend a Fear to transform the area within Very Close range into a different biome. All targets within this area take 2d6+3 direct magic damage.

", + "description": "

Spend a Fear to transform the area within Very Close range into a different biome. All targets within this area take 2d6+3 direct magic damage.

@Template[type:emanation|range:vc]

", "resource": null, "actions": { "QzuQIAtSrgz9Zd5V": { @@ -466,8 +448,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -493,9 +475,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -504,16 +485,7 @@ "effects": [], "name": "Spend Fear", "img": "icons/magic/light/explosion-glow-spiral-teal.webp", - "range": "veryClose", - "areas": [ - { - "name": "Remake Reality", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "veryClose" } }, "originItemType": null, @@ -585,8 +557,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -612,7 +584,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Minor_Demon_3tqCjDwJAQ7JKqMb.json b/src/packs/adversaries/adversary_Minor_Demon_3tqCjDwJAQ7JKqMb.json index 626b1597..0fceeba1 100644 --- a/src/packs/adversaries/adversary_Minor_Demon_3tqCjDwJAQ7JKqMb.json +++ b/src/packs/adversaries/adversary_Minor_Demon_3tqCjDwJAQ7JKqMb.json @@ -74,8 +74,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -101,7 +101,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -132,9 +132,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -185,7 +188,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -211,8 +214,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -280,7 +282,7 @@ "_id": "kD9kO92V7t3IqZu8", "img": "icons/magic/unholy/strike-hand-glow-pink.webp", "system": { - "description": "

When a PC rolls a failure with Fear while within Close range of the @Lookup[@name], they lose a Hope.

", + "description": "

When a PC rolls a failure with Fear while within Close range of the @Lookup[@name], they lose a Hope.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "XQ7QebA0iGvMti4A": { @@ -297,8 +299,8 @@ "recovery": null }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -323,9 +325,8 @@ }, "type": [] } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -334,16 +335,7 @@ "effects": [], "name": "Hope Damage", "img": "icons/magic/unholy/strike-hand-glow-pink.webp", - "range": "", - "areas": [ - { - "name": "All Must fall", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "" } }, "originItemType": null, @@ -369,7 +361,7 @@ "_id": "lA7vcvS7oGT9NTSy", "img": "icons/magic/fire/projectile-beams-salvo-red.webp", "system": { - "description": "

Spend a Fear to rain down hellfire within Far range. All targets within the area must make an Agility Reaction Roll. Targets who fail take 1d20+3 magic damage. Targets who succeed take half damage.

", + "description": "

Spend a Fear to rain down hellfire within Far range. All targets within the area must make an Agility Reaction Roll. Targets who fail take 1d20+3 magic damage. Targets who succeed take half damage.

@Template[type:emanation|range:f]

", "resource": null, "actions": { "nOzLQ0NJzeB3vKiV": { @@ -393,8 +385,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -420,9 +412,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -451,16 +442,7 @@ }, "name": "Spend Fear", "img": "icons/magic/fire/projectile-beams-salvo-red.webp", - "range": "far", - "areas": [ - { - "name": "Hellfire", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "far" } }, "originItemType": null, @@ -562,8 +544,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -589,7 +571,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Minor_Fire_Elemental_DscWkNVoHak6P4hh.json b/src/packs/adversaries/adversary_Minor_Fire_Elemental_DscWkNVoHak6P4hh.json index 859c207c..2980a141 100644 --- a/src/packs/adversaries/adversary_Minor_Fire_Elemental_DscWkNVoHak6P4hh.json +++ b/src/packs/adversaries/adversary_Minor_Fire_Elemental_DscWkNVoHak6P4hh.json @@ -75,8 +75,8 @@ }, "range": "far", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -102,7 +102,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -132,9 +132,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -185,7 +188,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -211,8 +214,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -271,7 +273,7 @@ "_id": "7AXE86WNd68OySkD", "img": "icons/magic/fire/explosion-flame-lightning-strike.webp", "system": { - "description": "

Mark a Stress to choose a point within Far range. The ground within Very Close range of that point immediately bursts into flames. All creatures within this area must make an Agility Reaction Roll. Targets who fail take 2d8 magic damage from the flames. Targets who succeed take half damage.

", + "description": "

Mark a Stress to choose a point within Far range. The ground within Very Close range of that point immediately bursts into flames. All creatures within this area must make an Agility Reaction Roll. Targets who fail take 2d8 magic damage from the flames. Targets who succeed take half damage.

@Template[type:circle|range:vc]

", "resource": null, "actions": { "x1VCkfcSYiPyg8fk": { @@ -295,8 +297,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -322,7 +324,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -352,16 +354,7 @@ }, "name": "Attack", "img": "icons/magic/fire/explosion-flame-lightning-strike.webp", - "range": "far", - "areas": [ - { - "name": "Scorched Earth", - "type": "placed", - "shape": "circle", - "size": "veryClose", - "effects": [] - } - ] + "range": "far" } }, "originItemType": null, @@ -388,14 +381,14 @@ "_id": "ESnu3I89BmUdBZEk", "img": "icons/magic/fire/explosion-fireball-large-red-orange.webp", "system": { - "description": "

Spend a Fear to erupt in a fi ery explosion. Make an attack against all targets within Close range. Targets the Elemental succeeds against take 1d8 magic damage and are knocked back to Far range.

", + "description": "

Spend a Fear to erupt in a fi ery explosion. Make an attack against all targets within Close range. Targets the Elemental succeeds against take 1d8 magic damage and are knocked back to Far range.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "JQgqyW8H7fugR7F0": { "type": "attack", "_id": "JQgqyW8H7fugR7F0", "systemPath": "actions", - "description": "", + "description": "

Spend a Fear to erupt in a fi ery explosion. Make an attack against all targets within Close range. Targets the Elemental succeeds against take 1d8 magic damage and are knocked back to Far range.

@Template[type:emanation|range:c]

", "chatDisplay": true, "actionType": "action", "cost": [ @@ -412,8 +405,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -439,9 +432,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -470,16 +462,7 @@ }, "name": "Attack", "img": "icons/magic/fire/explosion-fireball-large-red-orange.webp", - "range": "close", - "areas": [ - { - "name": "Explosion", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "originItemType": null, @@ -509,11 +492,9 @@ "description": "

Three times per scene, when the @Lookup[@name] moves onto objects that are highly flammable, consume them to clear a HP or a Stress.

", "resource": { "type": "simple", - "value": 3, + "value": 0, "max": "3", - "icon": "fa-solid fa-fire", - "progression": "decreasing", - "recovery": "scene" + "icon": "fa-solid fa-fire" }, "actions": { "CTWSVVisdgJgF7pd": { @@ -523,24 +504,15 @@ "description": "", "chatDisplay": true, "actionType": "action", - "cost": [ - { - "scalable": false, - "key": "resource", - "value": 1, - "itemId": "3u6wvKPJAS2v5nWV", - "step": null, - "consumeOnSuccess": false - } - ], + "cost": [], "uses": { "value": null, "max": "", "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -565,9 +537,8 @@ }, "type": [] } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "self", @@ -600,24 +571,15 @@ "description": "", "chatDisplay": true, "actionType": "action", - "cost": [ - { - "scalable": false, - "key": "resource", - "value": 1, - "itemId": "3u6wvKPJAS2v5nWV", - "step": null, - "consumeOnSuccess": false - } - ], + "cost": [], "uses": { "value": null, "max": "", "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -642,9 +604,8 @@ }, "type": [] } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "self", @@ -713,8 +674,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -740,7 +701,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Minor_Treant_G62k4oSkhkoXEs2D.json b/src/packs/adversaries/adversary_Minor_Treant_G62k4oSkhkoXEs2D.json index 163556e9..f05ba5fc 100644 --- a/src/packs/adversaries/adversary_Minor_Treant_G62k4oSkhkoXEs2D.json +++ b/src/packs/adversaries/adversary_Minor_Treant_G62k4oSkhkoXEs2D.json @@ -66,8 +66,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -94,7 +94,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -125,9 +125,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -178,7 +181,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -204,8 +207,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -243,95 +245,33 @@ "description": "

Spend a Fear to choose a target and spotlight all @Lookup[@name]s within Close range of them. Those Minions move into Melee range of the target and make one shared attack roll. On a success, they deal @Lookup[@system.attack.damageFormula] physical damage each. Combine this damage.

", "resource": null, "actions": { - "xFlhxnQWmVvDqQ55": { - "type": "attack", - "_id": "xFlhxnQWmVvDqQ55", + "xTMNAHcoErKuR6TZ": { + "type": "effect", + "_id": "xTMNAHcoErKuR6TZ", "systemPath": "actions", - "baseAction": false, "description": "", "chatDisplay": true, - "originItem": { - "type": "itemCollection" - }, "actionType": "action", - "triggers": [], "cost": [ { "scalable": false, "key": "fear", "value": 1, - "itemId": null, - "step": null, - "consumeOnSuccess": false + "step": null } ], "uses": { "value": null, "max": "", - "recovery": null, - "consumeOnSuccess": false - }, - "damage": { - "parts": { - "hitPoints": { - "applyTo": "hitPoints", - "resultBased": false, - "value": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": true, - "formula": "4" - } - }, - "valueAlt": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": false, - "formula": "" - } - }, - "base": false, - "type": [ - "physical" - ] - } - }, - "includeBase": false, - "direct": false, - "groupAttack": "close" - }, - "target": { - "type": "any", - "amount": null + "recovery": null }, "effects": [], - "roll": { - "type": "attack", - "trait": null, - "difficulty": null, - "bonus": null, - "advState": "neutral", - "diceRolling": { - "multiplier": "prof", - "flatMultiplier": 1, - "dice": "d6", - "compare": null, - "treshold": null - }, - "useDefault": false - }, - "save": { - "trait": null, - "difficulty": null, - "damageMod": "none" + "target": { + "type": "self", + "amount": null }, "name": "Spend Fear", + "img": "icons/creatures/abilities/tail-strike-bone-orange.webp", "range": "" } }, diff --git a/src/packs/adversaries/adversary_Minotaur_Wrecker_rM9qCIYeWg9I0B4l.json b/src/packs/adversaries/adversary_Minotaur_Wrecker_rM9qCIYeWg9I0B4l.json index b4734967..85981374 100644 --- a/src/packs/adversaries/adversary_Minotaur_Wrecker_rM9qCIYeWg9I0B4l.json +++ b/src/packs/adversaries/adversary_Minotaur_Wrecker_rM9qCIYeWg9I0B4l.json @@ -74,8 +74,8 @@ }, "range": "veryClose", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -101,7 +101,7 @@ }, "base": false } - } + ] }, "img": "icons/weapons/axes/axe-double.webp", "type": "attack", @@ -300,8 +300,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -327,7 +327,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -373,8 +373,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -401,7 +401,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -454,8 +454,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -479,7 +479,7 @@ } } } - }, + ], "includeBase": false, "direct": true }, diff --git a/src/packs/adversaries/adversary_Monarch_yx0vK2yfNVZKWUUi.json b/src/packs/adversaries/adversary_Monarch_yx0vK2yfNVZKWUUi.json index 8d5845a9..5320a0ed 100644 --- a/src/packs/adversaries/adversary_Monarch_yx0vK2yfNVZKWUUi.json +++ b/src/packs/adversaries/adversary_Monarch_yx0vK2yfNVZKWUUi.json @@ -85,8 +85,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -112,7 +112,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -381,8 +381,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": false, @@ -408,7 +408,7 @@ }, "type": [] } - }, + ], "includeBase": false, "direct": false }, diff --git a/src/packs/adversaries/adversary_Mortal_Hunter_mVV7a7KQAORoPMgZ.json b/src/packs/adversaries/adversary_Mortal_Hunter_mVV7a7KQAORoPMgZ.json index 33677263..8bc7fe10 100644 --- a/src/packs/adversaries/adversary_Mortal_Hunter_mVV7a7KQAORoPMgZ.json +++ b/src/packs/adversaries/adversary_Mortal_Hunter_mVV7a7KQAORoPMgZ.json @@ -81,8 +81,8 @@ }, "range": "veryClose", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -108,7 +108,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -138,9 +138,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -191,7 +194,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -217,15 +220,14 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { "name": "Terrifying", "type": "feature", "system": { - "description": "

When the @Lookup[@name] makes a successful attack, all PCs within Far range lose a Hope and you gain a Fear.

", + "description": "

When the @Lookup[@name] makes a successful attack, all PCs within Far range lose a Hope and you gain a Fear.

@Template[type:emanation|range:f]

", "resource": null, "actions": { "9T1g3FH38cnCRG8k": { @@ -242,8 +244,8 @@ "recovery": null }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -268,9 +270,8 @@ }, "type": [] } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -279,16 +280,7 @@ "effects": [], "name": "Lose Hope", "img": "icons/magic/death/skull-energy-light-purple.webp", - "range": "far", - "areas": [ - { - "name": "Terrifying", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "far" } }, "originItemType": null, @@ -369,8 +361,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false, @@ -398,7 +390,7 @@ } } } - }, + ], "includeBase": false, "direct": true }, @@ -452,18 +444,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "scene" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Attacks made by the Hunter against a Deathlocked target deal direct damage.

", "tint": "#ffffff", @@ -473,16 +465,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!mVV7a7KQAORoPMgZ.r1T70u9n3bRfUTX5.YznseQP43jNrk07h" } ], @@ -526,7 +508,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -582,7 +564,7 @@ "name": "Rampage", "type": "feature", "system": { - "description": "

Countdown (Loop 1d6). When the @Lookup[@name] is in the spotlight for the first time, activate the countdown. When it triggers, move the @Lookup[@name] in a straight line to a point within Far range and make an attack against all targets in their path. Targets the @Lookup[@name] succeeds against take 2d8+2 physical damage.

", + "description": "

Countdown (Loop 1d6). When the @Lookup[@name] is in the spotlight for the first time, activate the countdown. When it triggers, move the @Lookup[@name] in a straight line to a point within Far range and make an attack against all targets in their path. Targets the @Lookup[@name] succeeds against take 2d8+2 physical damage.

@Template[type:ray|range:f]

", "resource": null, "actions": { "VjiFxuzfAaq5N1jy": { @@ -599,8 +581,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -626,9 +608,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -657,16 +638,7 @@ }, "name": "Attack", "img": "icons/magic/movement/trail-streak-zigzag-yellow.webp", - "range": "far", - "areas": [ - { - "name": "Rampage", - "type": "placed", - "shape": "line", - "size": "far", - "effects": [] - } - ] + "range": "far" }, "BhA3vxCuMs4UbbQU": { "type": "countdown", diff --git a/src/packs/adversaries/adversary_Oak_Treant_XK78QUfY8c8Go8Uv.json b/src/packs/adversaries/adversary_Oak_Treant_XK78QUfY8c8Go8Uv.json index c5feed37..3c110024 100644 --- a/src/packs/adversaries/adversary_Oak_Treant_XK78QUfY8c8Go8Uv.json +++ b/src/packs/adversaries/adversary_Oak_Treant_XK78QUfY8c8Go8Uv.json @@ -73,8 +73,8 @@ }, "range": "veryClose", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "multiplier": "flat", "flatMultiplier": 3, @@ -100,7 +100,7 @@ }, "base": false } - } + ] }, "img": "icons/skills/melee/blood-slash-foam-red.webp", "type": "attack", @@ -273,8 +273,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false, @@ -302,7 +302,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -399,26 +399,25 @@ "type": "withinRange", "target": "any", "range": "self" - }, - "changes": [ - { - "key": "system.resistance.physical.resistance", - "value": 1, - "priority": null, - "type": "add" - } - ], - "duration": { - "type": "temporary", - "description": "

Can end this effect instead of moving while they are spotlighted.

" } }, + "changes": [ + { + "key": "system.resistance.physical.resistance", + "mode": 2, + "value": "1", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Mark a Stress to Root the Treant in place. The Treant is Restrained while Rooted and can end this effect instead of moving while they are spotlighted. While Rooted the Treant has resistance to physical damage.

", "tint": "#ffffff", @@ -428,16 +427,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!XK78QUfY8c8Go8Uv.sqkgw26P2KiQVtXT.3PY5KIG6d3dr3dty" } ], diff --git a/src/packs/adversaries/adversary_Oracle_of_Doom_befIqd5IYKg6eUz2.json b/src/packs/adversaries/adversary_Oracle_of_Doom_befIqd5IYKg6eUz2.json index a9b865ae..66fa5ba1 100644 --- a/src/packs/adversaries/adversary_Oracle_of_Doom_befIqd5IYKg6eUz2.json +++ b/src/packs/adversaries/adversary_Oracle_of_Doom_befIqd5IYKg6eUz2.json @@ -80,8 +80,8 @@ }, "range": "far", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - } + ] }, "img": "icons/magic/symbols/rune-sigil-rough-white-teal.webp", "type": "attack", @@ -138,9 +138,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -191,7 +194,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -217,15 +220,14 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { "name": "Terrifying", "type": "feature", "system": { - "description": "

When the @Lookup[@name] makes a successful attack, all PCs within Far range lose a Hope and you gain a Fear.

", + "description": "

When the @Lookup[@name] makes a successful attack, all PCs within Far range lose a Hope and you gain a Fear.

@Template[type:emanation|range:f]

", "resource": null, "actions": { "VjdSO1lAdTIAlofM": { @@ -242,8 +244,8 @@ "recovery": null }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -268,9 +270,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -279,16 +280,7 @@ "effects": [], "name": "Lose Hope", "img": "icons/magic/death/skull-energy-light-purple.webp", - "range": "far", - "areas": [ - { - "name": "Terrifying", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "far" } }, "originItemType": null, @@ -330,8 +322,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -356,7 +348,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -415,8 +407,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -442,7 +434,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -522,7 +514,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -628,8 +620,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -655,7 +647,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Outer_Realms_Abomination_A0SeeDzwjvqOsyof.json b/src/packs/adversaries/adversary_Outer_Realms_Abomination_A0SeeDzwjvqOsyof.json index 3e5bacf3..5b565b8c 100644 --- a/src/packs/adversaries/adversary_Outer_Realms_Abomination_A0SeeDzwjvqOsyof.json +++ b/src/packs/adversaries/adversary_Outer_Realms_Abomination_A0SeeDzwjvqOsyof.json @@ -74,8 +74,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -101,7 +101,7 @@ }, "base": false } - } + ] }, "img": "icons/creatures/tentacles/tentacle-earth-green.webp", "type": "attack", @@ -132,9 +132,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -185,7 +188,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -211,8 +214,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -261,7 +263,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -365,7 +367,7 @@ "name": "Reality Quake", "type": "feature", "system": { - "description": "

Spend a Fear to rattle the edges of reality within Far range of the @Lookup[@name]. All targets within that area must succeed on a Knowledge Reaction Roll or become Unstuck from reality until the end of the scene. When an Unstuck target spends Hope or marks Armor Slots, HP, or Stress, they must double the amount spent or marked.

", + "description": "

Spend a Fear to rattle the edges of reality within Far range of the @Lookup[@name]. All targets within that area must succeed on a Knowledge Reaction Roll or become Unstuck from reality until the end of the scene. When an Unstuck target spends Hope or marks Armor Slots, HP, or Stress, they must double the amount spent or marked.

@Template[type:emanation|range:f]

", "resource": null, "actions": { "7apNSLz8m7sxyLhU": { @@ -382,9 +384,8 @@ "recovery": null }, "damage": { - "parts": {}, - "includeBase": false, - "groupAttack": "" + "parts": [], + "includeBase": false }, "target": { "type": "any", @@ -418,16 +419,7 @@ }, "name": "Roll Save", "img": "icons/magic/sonic/explosion-shock-sound-wave.webp", - "range": "", - "areas": [ - { - "name": "Reality Quake", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "" } }, "originItemType": null, @@ -450,20 +442,20 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "scene" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

Unstuck from reality until the end of the scene. When you spend Hope or mark Armor Slots, HP, or Stress, you must double the amount spent or marked.

", + "description": "

Unstuck from reality until the end of the scene. When you spend Hope or mark Armor Slots, HP, or Stress, you must double the amount spent or marked.

", "tint": "#ffffff", "statuses": [], "sort": 0, @@ -471,16 +463,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!A0SeeDzwjvqOsyof.K3MQO1I42nmfM2F2.edEZER9ImWicMwRb" } ], @@ -517,7 +499,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Outer_Realms_Corrupter_ms6nuOl3NFkhPj1k.json b/src/packs/adversaries/adversary_Outer_Realms_Corrupter_ms6nuOl3NFkhPj1k.json index 9edf3f04..83fbf4fa 100644 --- a/src/packs/adversaries/adversary_Outer_Realms_Corrupter_ms6nuOl3NFkhPj1k.json +++ b/src/packs/adversaries/adversary_Outer_Realms_Corrupter_ms6nuOl3NFkhPj1k.json @@ -75,8 +75,8 @@ }, "img": "icons/creatures/tentacles/tentacles-thing-green.webp", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -102,7 +102,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -132,9 +132,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -185,7 +188,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -211,8 +214,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -236,8 +238,8 @@ "recovery": null }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -262,7 +264,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -297,7 +299,7 @@ "name": "Disgorge Realiy Flotsam", "type": "feature", "system": { - "description": "

Mark a Stress to spew partially digested portions of consumed realities at all targets within Close range. Targets must succeed on a Knowledge Reaction Roll or mark 2 Stress.

", + "description": "

Mark a Stress to spew partially digested portions of consumed realities at all targets within Close range. Targets must succeed on a Knowledge Reaction Roll or mark 2 Stress.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "6vX6VHpXX7OiGSWH": { @@ -314,8 +316,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -340,9 +342,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -371,16 +372,7 @@ }, "name": "Roll Save", "img": "icons/magic/unholy/barrier-shield-glowing-pink.webp", - "range": "close", - "areas": [ - { - "name": "Disgorge Realiy Flotsam", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "originItemType": null, diff --git a/src/packs/adversaries/adversary_Outer_Realms_Thrall_moJhHgKqTKPS2WYS.json b/src/packs/adversaries/adversary_Outer_Realms_Thrall_moJhHgKqTKPS2WYS.json index 0bb3a44c..5347bf49 100644 --- a/src/packs/adversaries/adversary_Outer_Realms_Thrall_moJhHgKqTKPS2WYS.json +++ b/src/packs/adversaries/adversary_Outer_Realms_Thrall_moJhHgKqTKPS2WYS.json @@ -60,8 +60,8 @@ }, "attack": { "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -88,7 +88,7 @@ }, "base": false } - } + ] }, "name": "Claws and Teeth", "roll": { @@ -125,9 +125,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -178,7 +181,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -204,8 +207,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -240,95 +242,33 @@ "description": "

Spend a Fear to choose a target and spotlight all @Lookup[@name]s within Close range of them. Those Minions move into Melee range of the target and make one shared attack roll. On a success, they deal @Lookup[@system.attack.damageFormula] physical damage each. Combine this damage.

", "resource": null, "actions": { - "6VKv71tPUIGGIfkZ": { - "type": "attack", - "_id": "6VKv71tPUIGGIfkZ", + "tvQetauskZoHDR5y": { + "type": "effect", + "_id": "tvQetauskZoHDR5y", "systemPath": "actions", - "baseAction": false, "description": "", "chatDisplay": true, - "originItem": { - "type": "itemCollection" - }, "actionType": "action", - "triggers": [], "cost": [ { - "consumeOnSuccess": false, "scalable": false, "key": "fear", "value": 1, - "itemId": null, "step": null } ], "uses": { "value": null, "max": "", - "recovery": null, - "consumeOnSuccess": false - }, - "damage": { - "parts": { - "hitPoints": { - "applyTo": "hitPoints", - "resultBased": false, - "value": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": true, - "formula": "11" - } - }, - "valueAlt": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": false, - "formula": "" - } - }, - "base": false, - "type": [ - "physical" - ] - } - }, - "includeBase": false, - "direct": false, - "groupAttack": "close" - }, - "target": { - "type": "any", - "amount": null + "recovery": null }, "effects": [], - "roll": { - "type": "attack", - "trait": null, - "difficulty": null, - "bonus": null, - "advState": "neutral", - "diceRolling": { - "multiplier": "prof", - "flatMultiplier": 1, - "dice": "d6", - "compare": null, - "treshold": null - }, - "useDefault": false - }, - "save": { - "trait": null, - "difficulty": null, - "damageMod": "none" + "target": { + "type": "self", + "amount": null }, "name": "Spend Fear", + "img": "icons/creatures/abilities/tail-strike-bone-orange.webp", "range": "" } }, diff --git a/src/packs/adversaries/adversary_Patchwork_Zombie_Hulk_EQTOAOUrkIvS2z88.json b/src/packs/adversaries/adversary_Patchwork_Zombie_Hulk_EQTOAOUrkIvS2z88.json index 8e82dcf7..b63e8cb7 100644 --- a/src/packs/adversaries/adversary_Patchwork_Zombie_Hulk_EQTOAOUrkIvS2z88.json +++ b/src/packs/adversaries/adversary_Patchwork_Zombie_Hulk_EQTOAOUrkIvS2z88.json @@ -85,8 +85,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -112,7 +112,7 @@ }, "base": false } - } + ] }, "img": "icons/commodities/biological/hand-clawed-blue.webp", "type": "attack", @@ -143,9 +143,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -196,7 +199,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -222,8 +225,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -250,8 +252,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -279,7 +281,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -315,46 +317,9 @@ "_id": "0fn7rVLwBnyCyvTA", "img": "icons/skills/melee/strike-slashes-orange.webp", "system": { - "description": "

When the @Lookup[@name] makes a standard attack, they can attack all targets within Very Close range.

", + "description": "

When the @Lookup[@name] makes a standard attack, they can attack all targets within Very Close range.

@Template[type:emanation|range:vc]

", "resource": null, - "actions": { - "ngl1xlJT4IOh3bkJ": { - "type": "effect", - "_id": "ngl1xlJT4IOh3bkJ", - "systemPath": "actions", - "baseAction": false, - "description": "", - "chatDisplay": true, - "originItem": { - "type": "itemCollection" - }, - "actionType": "action", - "triggers": [], - "areas": [ - { - "name": "Flailing Limbs", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ], - "cost": [], - "uses": { - "value": null, - "max": "", - "recovery": null, - "consumeOnSuccess": false - }, - "effects": [], - "target": { - "type": "any", - "amount": null - }, - "name": "", - "range": "" - } - }, + "actions": {}, "originItemType": null, "subType": null, "originId": null @@ -395,8 +360,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -421,7 +386,7 @@ }, "type": [] }, - "stress": { + { "value": { "custom": { "enabled": true, @@ -446,7 +411,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -498,7 +463,7 @@ "_id": "uTtQwNg46NAjgzuD", "img": "icons/magic/death/skeleton-skull-soul-blue.webp", "system": { - "description": "

Mark a Stress to cause all PCs within Far range to make a Presence Reaction Roll (13). Targets who fail lose a Hope and you gain a Fear for each. Targets who succeed must mark a Stress.

", + "description": "

Mark a Stress to cause all PCs within Far range to make a Presence Reaction Roll (13). Targets who fail lose a Hope and you gain a Fear for each. Targets who succeed must mark a Stress.

@Template[type:emanation|range:f]

", "resource": null, "actions": { "2NYC0D7wkBNrUAKl": { @@ -522,8 +487,8 @@ "recovery": null }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -548,9 +513,8 @@ }, "type": [] } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -579,16 +543,7 @@ }, "name": "Mark Stress", "img": "icons/magic/death/skeleton-skull-soul-blue.webp", - "range": "far", - "areas": [ - { - "name": "Tormented Screams", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "far" } }, "originItemType": null, diff --git a/src/packs/adversaries/adversary_Perfected_Zombie_CP6iRfHdyFWniTHY.json b/src/packs/adversaries/adversary_Perfected_Zombie_CP6iRfHdyFWniTHY.json index 06a18345..e3da56b6 100644 --- a/src/packs/adversaries/adversary_Perfected_Zombie_CP6iRfHdyFWniTHY.json +++ b/src/packs/adversaries/adversary_Perfected_Zombie_CP6iRfHdyFWniTHY.json @@ -75,8 +75,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -102,7 +102,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -132,9 +132,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -185,7 +188,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -211,15 +214,14 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { "name": "Terrifying", "type": "feature", "system": { - "description": "

When the @Lookup[@name] makes a successful attack, all PCs within Far range lose a Hope and you gain a Fear.

", + "description": "

When the @Lookup[@name] makes a successful attack, all PCs within Far range lose a Hope and you gain a Fear.

@Template[type:emanation|range:f]

", "resource": null, "actions": { "dquYnt5qiHZfnyD9": { @@ -236,8 +238,8 @@ "recovery": null }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -262,9 +264,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -273,16 +274,7 @@ "effects": [], "name": "Lose Hope", "img": "icons/magic/death/skull-energy-light-purple.webp", - "range": "far", - "areas": [ - { - "name": "Terrifying", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "far" } }, "originItemType": null, @@ -332,7 +324,7 @@ "name": "Perfect Strike", "type": "feature", "system": { - "description": "

Mark a Stress to make a standard attack against all targets within Very Close range. Targets the @Lookup[@name] succeeds against are Vulnerable until their next rest.

", + "description": "

Mark a Stress to make a standard attack against all targets within Very Close range. Targets the @Lookup[@name] succeeds against are Vulnerable until their next rest.

@Template[type:emanation|range:vc]

", "resource": null, "actions": { "un9btM1mN53JHIgV": { @@ -356,8 +348,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -383,9 +375,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -419,16 +410,7 @@ }, "name": "Attack", "img": "icons/skills/melee/strike-axe-energy-pink.webp", - "range": "veryClose", - "areas": [ - { - "name": "Perfect Strike", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "veryClose" } }, "originItemType": null, @@ -451,19 +433,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "shortRest", - "description": "" } }, + "changes": [], "disabled": true, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Vulnerable until your next rest.

", "tint": "#ffffff", @@ -475,16 +456,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!CP6iRfHdyFWniTHY.CKy2r6FguyTSO9Fm.Q5eeh0B6qaXFS1Ck" } ], diff --git a/src/packs/adversaries/adversary_Petty_Noble_wycLpvebWdUqRhpP.json b/src/packs/adversaries/adversary_Petty_Noble_wycLpvebWdUqRhpP.json index bee77686..db284f40 100644 --- a/src/packs/adversaries/adversary_Petty_Noble_wycLpvebWdUqRhpP.json +++ b/src/packs/adversaries/adversary_Petty_Noble_wycLpvebWdUqRhpP.json @@ -80,8 +80,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", diff --git a/src/packs/adversaries/adversary_Pirate_Captain_OROJbjsqagVh7ECV.json b/src/packs/adversaries/adversary_Pirate_Captain_OROJbjsqagVh7ECV.json index 428a9607..5b00ec60 100644 --- a/src/packs/adversaries/adversary_Pirate_Captain_OROJbjsqagVh7ECV.json +++ b/src/packs/adversaries/adversary_Pirate_Captain_OROJbjsqagVh7ECV.json @@ -85,8 +85,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -112,7 +112,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -251,8 +251,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -277,7 +277,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -401,8 +401,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -426,7 +426,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -501,8 +501,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -528,7 +528,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Pirate_Raiders_5YgEajn0wa4i85kC.json b/src/packs/adversaries/adversary_Pirate_Raiders_5YgEajn0wa4i85kC.json index 94137c2f..41f79b49 100644 --- a/src/packs/adversaries/adversary_Pirate_Raiders_5YgEajn0wa4i85kC.json +++ b/src/packs/adversaries/adversary_Pirate_Raiders_5YgEajn0wa4i85kC.json @@ -74,8 +74,8 @@ "description": "

Seafaring scoundrels moving in a ravaging pack.

", "attack": { "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -101,7 +101,7 @@ "resultBased": false, "base": false } - } + ] }, "name": "Cutlass", "img": "icons/weapons/swords/scimitar-worn-blue.webp", @@ -272,8 +272,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -298,7 +298,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Pirate_Tough_mhcVkVFrzIJ18FDm.json b/src/packs/adversaries/adversary_Pirate_Tough_mhcVkVFrzIJ18FDm.json index 2817b191..69b59211 100644 --- a/src/packs/adversaries/adversary_Pirate_Tough_mhcVkVFrzIJ18FDm.json +++ b/src/packs/adversaries/adversary_Pirate_Tough_mhcVkVFrzIJ18FDm.json @@ -67,8 +67,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -94,7 +94,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", @@ -269,8 +269,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -295,7 +295,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -347,8 +347,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -374,7 +374,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Red_Ooze_9rVlbJVrDNn1x7PS.json b/src/packs/adversaries/adversary_Red_Ooze_9rVlbJVrDNn1x7PS.json index f74da475..2c10ae3f 100644 --- a/src/packs/adversaries/adversary_Red_Ooze_9rVlbJVrDNn1x7PS.json +++ b/src/packs/adversaries/adversary_Red_Ooze_9rVlbJVrDNn1x7PS.json @@ -79,8 +79,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -106,7 +106,7 @@ }, "base": false } - } + ] }, "img": "icons/creatures/slimes/slime-movement-dripping-pseudopods-green.webp", "type": "attack", @@ -272,8 +272,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -299,7 +299,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -350,8 +350,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -377,7 +377,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -409,19 +409,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until they’re extinguished with a successful Finesse Roll (14)

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

You are Ignited until you are extinguished with a successful Finesse Roll (14). While Ignited, you take 1d4 magic damage whenever you make an action roll.

[[/dr trait=finesse difficulty=14]]

", "tint": "#ffffff", @@ -431,16 +430,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!9rVlbJVrDNn1x7PS.JU9uVwZSM0ItnZRq.9UBLk9M87VIUziAQ" } ], diff --git a/src/packs/adversaries/adversary_Rotted_Zombie_gP3fWTLzSFnpA8EJ.json b/src/packs/adversaries/adversary_Rotted_Zombie_gP3fWTLzSFnpA8EJ.json index f1c7f470..7672961c 100644 --- a/src/packs/adversaries/adversary_Rotted_Zombie_gP3fWTLzSFnpA8EJ.json +++ b/src/packs/adversaries/adversary_Rotted_Zombie_gP3fWTLzSFnpA8EJ.json @@ -57,8 +57,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -85,7 +85,7 @@ }, "base": false } - } + ] }, "img": "icons/creatures/abilities/mouth-teeth-sharp.webp", "type": "attack", @@ -125,9 +125,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -178,7 +181,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -204,8 +207,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -243,95 +245,33 @@ "description": "

Spend a Fear to choose a target and spotlight all @Lookup[@name]s within Close range of them. Those Minions move into Melee range of the target and make one shared attack roll. On a success, they deal @Lookup[@system.attack.damageFormula] physical damage each. Combine this damage.

", "resource": null, "actions": { - "8wRrAWHU0xHW4zuE": { - "type": "attack", - "_id": "8wRrAWHU0xHW4zuE", + "DJBNtd3hWjwsjPwq": { + "type": "effect", + "_id": "DJBNtd3hWjwsjPwq", "systemPath": "actions", - "baseAction": false, "description": "", "chatDisplay": true, - "originItem": { - "type": "itemCollection" - }, "actionType": "action", - "triggers": [], "cost": [ { "scalable": false, "key": "fear", "value": 1, - "itemId": null, - "step": null, - "consumeOnSuccess": false + "step": null } ], "uses": { "value": null, "max": "", - "recovery": null, - "consumeOnSuccess": false - }, - "damage": { - "parts": { - "hitPoints": { - "applyTo": "hitPoints", - "resultBased": false, - "value": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": true, - "formula": "2" - } - }, - "valueAlt": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": false, - "formula": "" - } - }, - "base": false, - "type": [ - "physical" - ] - } - }, - "includeBase": false, - "direct": false, - "groupAttack": "close" - }, - "target": { - "type": "any", - "amount": null + "recovery": null }, "effects": [], - "roll": { - "type": "attack", - "trait": null, - "difficulty": null, - "bonus": null, - "advState": "neutral", - "diceRolling": { - "multiplier": "prof", - "flatMultiplier": 1, - "dice": "d6", - "compare": null, - "treshold": null - }, - "useDefault": false - }, - "save": { - "trait": null, - "difficulty": null, - "damageMod": "none" + "target": { + "type": "self", + "amount": null }, "name": "Spend Fear", + "img": "icons/creatures/abilities/tail-strike-bone-orange.webp", "range": "" } }, diff --git a/src/packs/adversaries/adversary_Royal_Advisor_EtLJiTsilPPZvLUX.json b/src/packs/adversaries/adversary_Royal_Advisor_EtLJiTsilPPZvLUX.json index e215a444..8593ec01 100644 --- a/src/packs/adversaries/adversary_Royal_Advisor_EtLJiTsilPPZvLUX.json +++ b/src/packs/adversaries/adversary_Royal_Advisor_EtLJiTsilPPZvLUX.json @@ -86,8 +86,8 @@ }, "range": "far", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -113,7 +113,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -249,8 +249,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -275,7 +275,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Secret_Keeper_sLAccjvCWfeedbpI.json b/src/packs/adversaries/adversary_Secret_Keeper_sLAccjvCWfeedbpI.json index 93bfef2c..d17c3f86 100644 --- a/src/packs/adversaries/adversary_Secret_Keeper_sLAccjvCWfeedbpI.json +++ b/src/packs/adversaries/adversary_Secret_Keeper_sLAccjvCWfeedbpI.json @@ -85,8 +85,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -112,7 +112,7 @@ }, "base": false } - } + ] }, "img": "icons/weapons/staves/staff-ornate-purple.webp", "type": "attack", @@ -256,7 +256,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -336,8 +336,8 @@ "recovery": null }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -362,7 +362,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Sellsword_bgreCaQ6ap2DVpCr.json b/src/packs/adversaries/adversary_Sellsword_bgreCaQ6ap2DVpCr.json index 46bed122..514be8f5 100644 --- a/src/packs/adversaries/adversary_Sellsword_bgreCaQ6ap2DVpCr.json +++ b/src/packs/adversaries/adversary_Sellsword_bgreCaQ6ap2DVpCr.json @@ -61,8 +61,8 @@ "attack": { "name": "Longsword", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -89,7 +89,7 @@ }, "base": false } - } + ] }, "roll": { "bonus": 3, @@ -125,9 +125,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -178,7 +181,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -204,8 +207,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -243,95 +245,33 @@ "description": "

Spend a Fear to choose a target and spotlight all @Lookup[@name]s within Close range of them. Those Minions move into Melee range of the target and make one shared attack roll. On a success, they deal @Lookup[@system.attack.damageFormula] physical damage each. Combine this damage.

", "resource": null, "actions": { - "K3pF2DBnR9zJ90W8": { - "type": "attack", - "_id": "K3pF2DBnR9zJ90W8", + "ghgFZskDiizJDjcn": { + "type": "effect", + "_id": "ghgFZskDiizJDjcn", "systemPath": "actions", - "baseAction": false, "description": "", "chatDisplay": true, - "originItem": { - "type": "itemCollection" - }, "actionType": "action", - "triggers": [], "cost": [ { - "consumeOnSuccess": false, "scalable": false, "key": "fear", "value": 1, - "itemId": null, "step": null } ], "uses": { "value": null, "max": "", - "recovery": null, - "consumeOnSuccess": false - }, - "damage": { - "parts": { - "hitPoints": { - "applyTo": "hitPoints", - "resultBased": false, - "value": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": true, - "formula": "3" - } - }, - "valueAlt": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": false, - "formula": "" - } - }, - "base": false, - "type": [ - "physical" - ] - } - }, - "includeBase": false, - "direct": false, - "groupAttack": "close" - }, - "target": { - "type": "any", - "amount": null + "recovery": null }, "effects": [], - "roll": { - "type": "attack", - "trait": null, - "difficulty": null, - "bonus": null, - "advState": "neutral", - "diceRolling": { - "multiplier": "prof", - "flatMultiplier": 1, - "dice": "d6", - "compare": null, - "treshold": null - }, - "useDefault": false - }, - "save": { - "trait": null, - "difficulty": null, - "damageMod": "none" + "target": { + "type": "self", + "amount": null }, "name": "Spend Fear", + "img": "icons/creatures/abilities/tail-strike-bone-orange.webp", "range": "" } }, diff --git a/src/packs/adversaries/adversary_Shambling_Zombie_2nXz4ilAY4xuhKLm.json b/src/packs/adversaries/adversary_Shambling_Zombie_2nXz4ilAY4xuhKLm.json index 5161f8e2..7c3925ac 100644 --- a/src/packs/adversaries/adversary_Shambling_Zombie_2nXz4ilAY4xuhKLm.json +++ b/src/packs/adversaries/adversary_Shambling_Zombie_2nXz4ilAY4xuhKLm.json @@ -74,8 +74,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -101,7 +101,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -266,8 +266,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -292,7 +292,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Shark_YmVAkdNsyuXWTtYp.json b/src/packs/adversaries/adversary_Shark_YmVAkdNsyuXWTtYp.json index 0a6f27b0..e385a6c5 100644 --- a/src/packs/adversaries/adversary_Shark_YmVAkdNsyuXWTtYp.json +++ b/src/packs/adversaries/adversary_Shark_YmVAkdNsyuXWTtYp.json @@ -75,8 +75,8 @@ }, "range": "veryClose", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -102,7 +102,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -132,9 +132,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -185,7 +188,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -211,15 +214,14 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { "name": "Terrifying", "type": "feature", "system": { - "description": "

When the @Lookup[@name] makes a successful attack, all PCs within Far range lose a Hope and you gain a Fear.

", + "description": "

When the @Lookup[@name] makes a successful attack, all PCs within Far range lose a Hope and you gain a Fear.

@Template[type:emanation|range:f]

", "resource": null, "actions": { "NoEb6qR3ktIu9kRJ": { @@ -236,8 +238,8 @@ "recovery": null }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -262,9 +264,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -273,16 +274,7 @@ "effects": [], "name": "Lose Hope", "img": "icons/magic/death/skull-energy-light-purple.webp", - "range": "", - "areas": [ - { - "name": "Terrifying", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "" } }, "originItemType": null, @@ -324,8 +316,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -351,7 +343,7 @@ } } }, - "armor": { + { "value": { "custom": { "enabled": true, @@ -376,7 +368,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Siren_BK4jwyXSRx7IOQiO.json b/src/packs/adversaries/adversary_Siren_BK4jwyXSRx7IOQiO.json index 39f6a5b9..a72c6d46 100644 --- a/src/packs/adversaries/adversary_Siren_BK4jwyXSRx7IOQiO.json +++ b/src/packs/adversaries/adversary_Siren_BK4jwyXSRx7IOQiO.json @@ -79,8 +79,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -106,7 +106,7 @@ }, "base": false } - } + ] }, "img": "icons/creatures/abilities/mouth-teeth-sharp.webp", "range": "melee", @@ -138,9 +138,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -191,7 +194,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -217,8 +220,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -242,8 +244,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -269,7 +271,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -324,7 +326,7 @@ "name": "Enchanting Song", "type": "feature", "system": { - "description": "

Spend a Fear to sing a song that affects all targets within Close range. Targets must succeed on an Instinct Reaction Roll or become Entranced until they mark 2 Stress. Other @Lookup[@name]s within Close range of the target can mark a Stress to each add a +1 bonus to the Difficulty of the reaction roll. While Entranced, a target can’t act and is Vulnerable.

", + "description": "

Spend a Fear to sing a song that affects all targets within Close range. Targets must succeed on an Instinct Reaction Roll or become Entranced until they mark 2 Stress. Other @Lookup[@name]s within Close range of the target can mark a Stress to each add a +1 bonus to the Difficulty of the reaction roll. While Entranced, a target can’t act and is Vulnerable.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "FY8K8Nsg0TKAWok8": { @@ -348,9 +350,8 @@ "recovery": null }, "damage": { - "parts": {}, - "includeBase": false, - "groupAttack": "" + "parts": [], + "includeBase": false }, "target": { "type": "any", @@ -384,16 +385,7 @@ }, "name": "Roll Save", "img": "icons/magic/control/hypnosis-mesmerism-eye.webp", - "range": "close", - "areas": [ - { - "name": "Enchanting Song", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "originItemType": null, @@ -416,21 +408,20 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until you mark 2 Stress.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

While Entranced, you can’t act and are Vulnerable.

", + "description": "

While Entranced, you can’t act and are Vulnerable.

", "tint": "#ffffff", "statuses": [ "vulnerable" @@ -440,16 +431,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!BK4jwyXSRx7IOQiO.Ks3HpB4W1l5FqR7p.xrm5786ckKbMYHjn" } ], diff --git a/src/packs/adversaries/adversary_Skeleton_Archer_7X5q7a6ueeHs5oA9.json b/src/packs/adversaries/adversary_Skeleton_Archer_7X5q7a6ueeHs5oA9.json index f0dde9f0..9d837ac0 100644 --- a/src/packs/adversaries/adversary_Skeleton_Archer_7X5q7a6ueeHs5oA9.json +++ b/src/packs/adversaries/adversary_Skeleton_Archer_7X5q7a6ueeHs5oA9.json @@ -74,8 +74,8 @@ }, "range": "far", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -101,7 +101,7 @@ }, "base": false } - } + ] }, "img": "icons/weapons/bows/shortbow-leather.webp", "type": "attack", @@ -310,8 +310,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -337,7 +337,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Skeleton_Dredge_6l1a3Fazq8BoKIcc.json b/src/packs/adversaries/adversary_Skeleton_Dredge_6l1a3Fazq8BoKIcc.json index 1a82abb8..4013d7fe 100644 --- a/src/packs/adversaries/adversary_Skeleton_Dredge_6l1a3Fazq8BoKIcc.json +++ b/src/packs/adversaries/adversary_Skeleton_Dredge_6l1a3Fazq8BoKIcc.json @@ -58,8 +58,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -86,7 +86,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -125,9 +125,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -178,7 +181,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -204,8 +207,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -243,95 +245,33 @@ "description": "

Spend a Fear to choose a target and spotlight all @Lookup[@name]s within Close range of them. Those Minions move into Melee range of the target and make one shared attack roll. On a success, they deal @Lookup[@system.attack.damageFormula] physical damage each. Combine this damage.

", "resource": null, "actions": { - "6rdwJKwsSCO4R0Ty": { - "type": "attack", - "_id": "6rdwJKwsSCO4R0Ty", + "Sz55uB8xkoNytLwJ": { + "type": "effect", + "_id": "Sz55uB8xkoNytLwJ", "systemPath": "actions", - "baseAction": false, "description": "", "chatDisplay": true, - "originItem": { - "type": "itemCollection" - }, "actionType": "action", - "triggers": [], "cost": [ { "scalable": false, "key": "fear", "value": 1, - "itemId": null, - "step": null, - "consumeOnSuccess": false + "step": null } ], "uses": { "value": null, "max": "", - "recovery": null, - "consumeOnSuccess": false - }, - "damage": { - "parts": { - "hitPoints": { - "applyTo": "hitPoints", - "resultBased": false, - "value": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": true, - "formula": "1" - } - }, - "valueAlt": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": false, - "formula": "" - } - }, - "base": false, - "type": [ - "physical" - ] - } - }, - "includeBase": false, - "direct": false, - "groupAttack": "close" - }, - "target": { - "type": "any", - "amount": null + "recovery": null }, "effects": [], - "roll": { - "type": "attack", - "trait": null, - "difficulty": null, - "bonus": null, - "advState": "neutral", - "diceRolling": { - "multiplier": "prof", - "flatMultiplier": 1, - "dice": "d6", - "compare": null, - "treshold": null - }, - "useDefault": false - }, - "save": { - "trait": null, - "difficulty": null, - "damageMod": "none" + "target": { + "type": "self", + "amount": null }, "name": "Spend Fear", + "img": "icons/creatures/abilities/tail-strike-bone-orange.webp", "range": "" } }, diff --git a/src/packs/adversaries/adversary_Skeleton_Knight_Q9LaVTyXF9NF12C7.json b/src/packs/adversaries/adversary_Skeleton_Knight_Q9LaVTyXF9NF12C7.json index e6982135..3c26dd28 100644 --- a/src/packs/adversaries/adversary_Skeleton_Knight_Q9LaVTyXF9NF12C7.json +++ b/src/packs/adversaries/adversary_Skeleton_Knight_Q9LaVTyXF9NF12C7.json @@ -74,8 +74,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -101,7 +101,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -132,9 +132,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -185,7 +188,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -211,8 +214,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -238,8 +240,8 @@ "recovery": null }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -264,7 +266,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -300,7 +302,7 @@ "_id": "WdVLwy9RNkVlZnCL", "img": "icons/skills/melee/strike-sword-steel-yellow.webp", "system": { - "description": "

Mark a Stress to make an attack against all targets within Very Close range. Targets the @Lookup[@name] succeeds against take 1d8+2 physical damage and must mark a Stress.

", + "description": "

Mark a Stress to make an attack against all targets within Very Close range. Targets the @Lookup[@name] succeeds against take 1d8+2 physical damage and must mark a Stress.

@Template[type:emanation|range:vc]

", "resource": null, "actions": { "vMv4monku9LOSxUZ": { @@ -324,8 +326,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -351,7 +353,7 @@ } } }, - "stress": { + { "value": { "custom": { "enabled": true, @@ -376,9 +378,8 @@ }, "type": [] } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -407,16 +408,7 @@ }, "name": "Attack", "img": "icons/skills/melee/strike-sword-steel-yellow.webp", - "range": "veryClose", - "areas": [ - { - "name": "Cut to the Bone", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "veryClose" } }, "originItemType": null, @@ -460,8 +452,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -487,7 +479,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Skeleton_Warrior_10YIQl0lvCJXZLfX.json b/src/packs/adversaries/adversary_Skeleton_Warrior_10YIQl0lvCJXZLfX.json index 726b06e1..28003d5c 100644 --- a/src/packs/adversaries/adversary_Skeleton_Warrior_10YIQl0lvCJXZLfX.json +++ b/src/packs/adversaries/adversary_Skeleton_Warrior_10YIQl0lvCJXZLfX.json @@ -73,8 +73,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -100,7 +100,7 @@ }, "base": false } - } + ] }, "img": "icons/weapons/swords/sword-guard-brass-worn.webp", "type": "attack", @@ -310,7 +310,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Spectral_Archer_5tCkhnBByUIN5UdG.json b/src/packs/adversaries/adversary_Spectral_Archer_5tCkhnBByUIN5UdG.json index 5b9cbb65..e6cc30f7 100644 --- a/src/packs/adversaries/adversary_Spectral_Archer_5tCkhnBByUIN5UdG.json +++ b/src/packs/adversaries/adversary_Spectral_Archer_5tCkhnBByUIN5UdG.json @@ -80,8 +80,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - } + ] }, "range": "far", "type": "attack", @@ -343,8 +343,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -370,7 +370,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Spectral_Captain_65cSO3EQEh6ZH6Xk.json b/src/packs/adversaries/adversary_Spectral_Captain_65cSO3EQEh6ZH6Xk.json index 0572e018..b70a5d53 100644 --- a/src/packs/adversaries/adversary_Spectral_Captain_65cSO3EQEh6ZH6Xk.json +++ b/src/packs/adversaries/adversary_Spectral_Captain_65cSO3EQEh6ZH6Xk.json @@ -76,8 +76,8 @@ "name": "Longbow", "img": "icons/weapons/bows/longbow-recurve-skull-brown.webp", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -103,7 +103,7 @@ }, "base": false } - } + ] }, "roll": { "bonus": 3, @@ -456,8 +456,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -483,7 +483,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Spectral_Guardian_UFVGl1osOsJTneLf.json b/src/packs/adversaries/adversary_Spectral_Guardian_UFVGl1osOsJTneLf.json index 85893254..577a7d25 100644 --- a/src/packs/adversaries/adversary_Spectral_Guardian_UFVGl1osOsJTneLf.json +++ b/src/packs/adversaries/adversary_Spectral_Guardian_UFVGl1osOsJTneLf.json @@ -81,8 +81,8 @@ }, "range": "veryClose", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -108,7 +108,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -350,8 +350,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -377,7 +377,7 @@ } } }, - "stress": { + { "value": { "custom": { "enabled": true, @@ -402,7 +402,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Spellblade_ldbWEL7uZs84vyrR.json b/src/packs/adversaries/adversary_Spellblade_ldbWEL7uZs84vyrR.json index 5d72dfc7..13d6ed84 100644 --- a/src/packs/adversaries/adversary_Spellblade_ldbWEL7uZs84vyrR.json +++ b/src/packs/adversaries/adversary_Spellblade_ldbWEL7uZs84vyrR.json @@ -80,8 +80,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -108,7 +108,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -139,9 +139,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -192,7 +195,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -218,8 +221,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -254,7 +256,7 @@ "_id": "a76dNCrcoZOH1RRT", "img": "icons/magic/sonic/projectile-shock-wave-blue.webp", "system": { - "description": "

Mark a Stress and target a group within Far range. All targets must succeed on an Agility Reaction Roll or take 1d8+2 magic damage. You gain a Fear for each target who marked HP from this attack.

", + "description": "

Mark a Stress and target a group within Far range. All targets must succeed on an Agility Reaction Roll or take 1d8+2 magic damage. You gain a Fear for each target who marked HP from this attack.

@Template[type:emanation|range:f]

", "resource": null, "actions": { "K4VnxigKTiu7hhZx": { @@ -278,8 +280,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -305,9 +307,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -336,16 +337,7 @@ }, "name": "Attack", "img": "icons/magic/sonic/projectile-shock-wave-blue.webp", - "range": "far", - "areas": [ - { - "name": "Supressing Blast", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "far" } }, "originItemType": null, @@ -402,16 +394,7 @@ }, "name": "Spend Fear", "img": "icons/skills/movement/arrows-up-trio-red.webp", - "range": "", - "areas": [ - { - "name": "Move as a Unit", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "" } }, "originItemType": null, @@ -456,8 +439,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -483,7 +466,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Spy_8zlynOhnVA59KpKT.json b/src/packs/adversaries/adversary_Spy_8zlynOhnVA59KpKT.json index 0e160edb..5affdc44 100644 --- a/src/packs/adversaries/adversary_Spy_8zlynOhnVA59KpKT.json +++ b/src/packs/adversaries/adversary_Spy_8zlynOhnVA59KpKT.json @@ -79,8 +79,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -106,7 +106,7 @@ }, "base": false } - } + ] }, "img": "icons/weapons/daggers/dagger-curved-purple.webp", "range": "melee", @@ -329,8 +329,8 @@ "recovery": null }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -354,7 +354,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Stag_Knight_KGVwnLq85ywP9xvB.json b/src/packs/adversaries/adversary_Stag_Knight_KGVwnLq85ywP9xvB.json index 14e81a8c..603182cc 100644 --- a/src/packs/adversaries/adversary_Stag_Knight_KGVwnLq85ywP9xvB.json +++ b/src/packs/adversaries/adversary_Stag_Knight_KGVwnLq85ywP9xvB.json @@ -80,8 +80,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -138,9 +138,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -191,7 +194,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -217,8 +220,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -242,8 +244,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -269,7 +271,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -304,7 +306,7 @@ "name": "Blade of the Forest", "type": "feature", "system": { - "description": "

Spend a Fear to make an attack against all targets within Very Close range. Targets the @Lookup[@name] succeeds against take physical damage equal to [[/r 3d4]] + the target’s Major threshold.

", + "description": "

Spend a Fear to make an attack against all targets within Very Close range. Targets the @Lookup[@name] succeeds against take physical damage equal to [[/r 3d4]] + the target’s Major threshold.

@Template[type:emanation|range:vc]

", "resource": null, "actions": { "xPSVwVVOC5gc2KTi": { @@ -328,9 +330,8 @@ "recovery": null }, "damage": { - "parts": {}, - "includeBase": false, - "groupAttack": "" + "parts": [], + "includeBase": false }, "target": { "type": "any", @@ -359,16 +360,7 @@ }, "name": "Attack", "img": "icons/skills/melee/strike-blade-hooked-green-purple.webp", - "range": "veryClose", - "areas": [ - { - "name": "Blade of the Forest", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "veryClose" } }, "originItemType": null, @@ -418,8 +410,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -443,7 +435,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Stonewraith_3aAS2Qm3R6cgaYfE.json b/src/packs/adversaries/adversary_Stonewraith_3aAS2Qm3R6cgaYfE.json index 52869085..de3ef9f2 100644 --- a/src/packs/adversaries/adversary_Stonewraith_3aAS2Qm3R6cgaYfE.json +++ b/src/packs/adversaries/adversary_Stonewraith_3aAS2Qm3R6cgaYfE.json @@ -80,8 +80,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - } + ] }, "range": "melee", "type": "attack", @@ -138,9 +138,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -191,7 +194,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -217,8 +220,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -274,8 +276,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -299,7 +301,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -357,18 +359,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -380,16 +382,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!3aAS2Qm3R6cgaYfE.tQgxiSS48TJ3X1Dl.6UgMuuJ8ZygbCsDh" } ], @@ -409,7 +401,7 @@ "name": "Avalanche Roar", "type": "feature", "system": { - "description": "

Spend a Fear to roar while within a cave and cause a cave-in. All targets within Close range must succeed on an Agility Reaction Roll (14) or take 2d10 physical damage. The rubble can be cleared with a Progress Countdown (8).

", + "description": "

Spend a Fear to roar while within a cave and cause a cave-in. All targets within Close range must succeed on an Agility Reaction Roll (14) or take 2d10 physical damage. The rubble can be cleared with a Progress Countdown (8).

@Template[type:emanation|range:c]

", "resource": null, "actions": { "4UGEEuK9XY8leCBV": { @@ -433,8 +425,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -460,9 +452,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -491,16 +482,7 @@ }, "name": "Roll Save", "img": "icons/magic/sonic/projectile-sound-rings-wave.webp", - "range": "close", - "areas": [ - { - "name": "Avalanche Roar", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" }, "UurIzyyMRAJc2DUX": { "type": "countdown", @@ -581,8 +563,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -608,7 +590,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Swarm_of_Rats_qNgs3AbLyJrY19nt.json b/src/packs/adversaries/adversary_Swarm_of_Rats_qNgs3AbLyJrY19nt.json index 28d5dabe..014b3dc6 100644 --- a/src/packs/adversaries/adversary_Swarm_of_Rats_qNgs3AbLyJrY19nt.json +++ b/src/packs/adversaries/adversary_Swarm_of_Rats_qNgs3AbLyJrY19nt.json @@ -68,8 +68,8 @@ "description": "

A skittering mass of ordinary rodents moving as one like a ravenous wave.

", "attack": { "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -95,7 +95,7 @@ "resultBased": false, "base": false } - } + ] }, "name": "Claws", "img": "icons/creatures/claws/claw-straight-brown.webp", diff --git a/src/packs/adversaries/adversary_Sylvan_Soldier_VtFBt9XBE0WrGGxP.json b/src/packs/adversaries/adversary_Sylvan_Soldier_VtFBt9XBE0WrGGxP.json index f3ce03c3..2ec5e924 100644 --- a/src/packs/adversaries/adversary_Sylvan_Soldier_VtFBt9XBE0WrGGxP.json +++ b/src/packs/adversaries/adversary_Sylvan_Soldier_VtFBt9XBE0WrGGxP.json @@ -80,8 +80,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -246,8 +246,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -273,7 +273,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -353,8 +353,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -380,7 +380,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Tangle_Bramble_Swarm_PKSXFuaIHUCoH63A.json b/src/packs/adversaries/adversary_Tangle_Bramble_Swarm_PKSXFuaIHUCoH63A.json index f8f93cf2..40297eb6 100644 --- a/src/packs/adversaries/adversary_Tangle_Bramble_Swarm_PKSXFuaIHUCoH63A.json +++ b/src/packs/adversaries/adversary_Tangle_Bramble_Swarm_PKSXFuaIHUCoH63A.json @@ -99,8 +99,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -126,7 +126,7 @@ "resultBased": false, "base": false } - }, + ], "includeBase": false }, "description": "", @@ -309,8 +309,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false, @@ -338,7 +338,7 @@ } } } - }, + ], "includeBase": false, "direct": true }, diff --git a/src/packs/adversaries/adversary_Tangle_Bramble_XcAGOSmtCFLT1unN.json b/src/packs/adversaries/adversary_Tangle_Bramble_XcAGOSmtCFLT1unN.json index d635b2ca..33afaa3a 100644 --- a/src/packs/adversaries/adversary_Tangle_Bramble_XcAGOSmtCFLT1unN.json +++ b/src/packs/adversaries/adversary_Tangle_Bramble_XcAGOSmtCFLT1unN.json @@ -94,8 +94,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -122,7 +122,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", @@ -164,9 +164,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -217,7 +220,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -243,8 +246,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -282,95 +284,33 @@ "description": "

Spend a Fear to choose a target and spotlight all @Lookup[@name]s within Close range of them. Those Minions move into Melee range of the target and make one shared attack roll. On a success, they deal @Lookup[@system.attack.damageFormula] physical damage each. Combine this damage.

", "resource": null, "actions": { - "V58Ry90tvIjvfDTZ": { - "type": "attack", - "_id": "V58Ry90tvIjvfDTZ", + "ZC5pKIb9N82vgMWu": { + "type": "effect", + "_id": "ZC5pKIb9N82vgMWu", "systemPath": "actions", - "baseAction": false, "description": "", "chatDisplay": true, - "originItem": { - "type": "itemCollection" - }, "actionType": "action", - "triggers": [], "cost": [ { - "consumeOnSuccess": false, "scalable": false, "key": "fear", "value": 1, - "itemId": null, "step": null } ], "uses": { "value": null, "max": "", - "recovery": null, - "consumeOnSuccess": false - }, - "damage": { - "parts": { - "hitPoints": { - "applyTo": "hitPoints", - "resultBased": false, - "value": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": true, - "formula": "2" - } - }, - "valueAlt": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": false, - "formula": "" - } - }, - "base": false, - "type": [ - "physical" - ] - } - }, - "includeBase": false, - "direct": false, - "groupAttack": "close" - }, - "target": { - "type": "any", - "amount": null + "recovery": null }, "effects": [], - "roll": { - "type": "attack", - "trait": null, - "difficulty": null, - "bonus": null, - "advState": "neutral", - "diceRolling": { - "multiplier": "prof", - "flatMultiplier": 1, - "dice": "d6", - "compare": null, - "treshold": null - }, - "useDefault": false - }, - "save": { - "trait": null, - "difficulty": null, - "damageMod": "none" + "target": { + "type": "self", + "amount": null }, "name": "Spend Fear", + "img": "icons/creatures/abilities/tail-strike-bone-orange.webp", "range": "" } }, diff --git a/src/packs/adversaries/adversary_Tiny_Green_Ooze_aLkLFuVoKz2NLoBK.json b/src/packs/adversaries/adversary_Tiny_Green_Ooze_aLkLFuVoKz2NLoBK.json index 9470502c..6a984b3c 100644 --- a/src/packs/adversaries/adversary_Tiny_Green_Ooze_aLkLFuVoKz2NLoBK.json +++ b/src/packs/adversaries/adversary_Tiny_Green_Ooze_aLkLFuVoKz2NLoBK.json @@ -57,8 +57,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -84,7 +84,7 @@ }, "base": false } - } + ] }, "img": "icons/creatures/slimes/slime-movement-dripping-pseudopods-green.webp", "type": "attack", @@ -128,9 +128,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -181,7 +184,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -207,8 +210,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -217,7 +219,7 @@ "_id": "WpOh5kHHx7lcTvEY", "img": "icons/magic/acid/dissolve-drip-droplet-smoke.webp", "system": { - "description": "

When the @Lookup[@name] makes a successful attack, the target must mark an Armor Slot without receiving its benefits (they can still use armor to reduce the damage). If they can’t mark an Armor Slot, they must mark an additional HP.

", + "description": "

When the @Lookup[@name] makes a successful attack, the target must mark an Armor Slot without receiving its benefi ts (they can still use armor to reduce the damage). If they can’t mark an Armor Slot, they must mark an additional HP.

", "resource": null, "actions": { "HfK0u0c7NRppuF1Q": { @@ -234,8 +236,8 @@ "recovery": null }, "damage": { - "parts": { - "armor": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -260,7 +262,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Tiny_Red_Ooze_1fkLQXVtmILqfJ44.json b/src/packs/adversaries/adversary_Tiny_Red_Ooze_1fkLQXVtmILqfJ44.json index 28d6490e..116fffba 100644 --- a/src/packs/adversaries/adversary_Tiny_Red_Ooze_1fkLQXVtmILqfJ44.json +++ b/src/packs/adversaries/adversary_Tiny_Red_Ooze_1fkLQXVtmILqfJ44.json @@ -58,8 +58,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -85,7 +85,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -236,8 +236,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -263,7 +263,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Treant_Sapling_o63nS0k3wHu6EgKP.json b/src/packs/adversaries/adversary_Treant_Sapling_o63nS0k3wHu6EgKP.json index c03a1b52..ad9d8107 100644 --- a/src/packs/adversaries/adversary_Treant_Sapling_o63nS0k3wHu6EgKP.json +++ b/src/packs/adversaries/adversary_Treant_Sapling_o63nS0k3wHu6EgKP.json @@ -66,8 +66,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -94,7 +94,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -125,9 +125,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -178,7 +181,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -204,8 +207,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -240,95 +242,33 @@ "description": "

Spend a Fear to choose a target and spotlight all @Lookup[@name]s within Close range of them. Those Minions move into Melee range of the target and make one shared attack roll. On a success, they deal @Lookup[@system.attack.damageFormula] physical damage each. Combine this damage.

", "resource": null, "actions": { - "Itubbr63irPJcbXG": { - "type": "attack", - "_id": "Itubbr63irPJcbXG", + "euP8VA4wvfsCpwN1": { + "type": "effect", + "_id": "euP8VA4wvfsCpwN1", "systemPath": "actions", - "baseAction": false, "description": "", "chatDisplay": true, - "originItem": { - "type": "itemCollection" - }, "actionType": "action", - "triggers": [], "cost": [ { "scalable": false, "key": "fear", "value": 1, - "itemId": null, - "step": null, - "consumeOnSuccess": false + "step": null } ], "uses": { "value": null, "max": "", - "recovery": null, - "consumeOnSuccess": false - }, - "damage": { - "parts": { - "hitPoints": { - "applyTo": "hitPoints", - "resultBased": false, - "value": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": true, - "formula": "8" - } - }, - "valueAlt": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": false, - "formula": "" - } - }, - "base": false, - "type": [ - "physical" - ] - } - }, - "includeBase": false, - "direct": false, - "groupAttack": "close" - }, - "target": { - "type": "any", - "amount": null + "recovery": null }, "effects": [], - "roll": { - "type": "attack", - "trait": null, - "difficulty": null, - "bonus": null, - "advState": "neutral", - "diceRolling": { - "multiplier": "prof", - "flatMultiplier": 1, - "dice": "d6", - "compare": null, - "treshold": null - }, - "useDefault": false - }, - "save": { - "trait": null, - "difficulty": null, - "damageMod": "none" + "target": { + "type": "self", + "amount": null }, "name": "Spend Fear", + "img": "icons/magic/unholy/orb-hands-pink.webp", "range": "" } }, diff --git a/src/packs/adversaries/adversary_Vampire_WWyUp6Mxl1S3KYUG.json b/src/packs/adversaries/adversary_Vampire_WWyUp6Mxl1S3KYUG.json index 6ba4935a..4f51cd79 100644 --- a/src/packs/adversaries/adversary_Vampire_WWyUp6Mxl1S3KYUG.json +++ b/src/packs/adversaries/adversary_Vampire_WWyUp6Mxl1S3KYUG.json @@ -80,8 +80,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -244,8 +244,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -269,7 +269,7 @@ } } }, - "hope": { + { "value": { "custom": { "enabled": true, @@ -294,7 +294,7 @@ } } }, - "stress": { + { "value": { "custom": { "enabled": true, @@ -319,7 +319,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Vault_Guardian_Gaoler_JqYraOqNmmhHk4Yy.json b/src/packs/adversaries/adversary_Vault_Guardian_Gaoler_JqYraOqNmmhHk4Yy.json index 97c493a8..d1cca592 100644 --- a/src/packs/adversaries/adversary_Vault_Guardian_Gaoler_JqYraOqNmmhHk4Yy.json +++ b/src/packs/adversaries/adversary_Vault_Guardian_Gaoler_JqYraOqNmmhHk4Yy.json @@ -75,8 +75,8 @@ }, "range": "veryClose", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -102,7 +102,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -270,7 +270,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -328,21 +328,20 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until freed with a successful Strength Roll (18).

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

You are Restrained within the Gaoler until freed with a successful Strength Roll (18). While Restrained, you can only attack the Gaoler.

", + "description": "

You are Restrained within the Gaoler until freed with a successful Strength Roll (18). While Restrained, you can only attack the Gaoler.

", "tint": "#ffffff", "statuses": [ "restrained" @@ -352,16 +351,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!JqYraOqNmmhHk4Yy.VlHp8RjHy7MK8rqC.6TZlstmWJPbeoL7i" } ], diff --git a/src/packs/adversaries/adversary_Vault_Guardian_Sentinel_FVgYb28fhxlVcGwA.json b/src/packs/adversaries/adversary_Vault_Guardian_Sentinel_FVgYb28fhxlVcGwA.json index ba3f5c33..67139669 100644 --- a/src/packs/adversaries/adversary_Vault_Guardian_Sentinel_FVgYb28fhxlVcGwA.json +++ b/src/packs/adversaries/adversary_Vault_Guardian_Sentinel_FVgYb28fhxlVcGwA.json @@ -75,8 +75,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -102,7 +102,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -132,9 +132,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -185,7 +188,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -211,8 +214,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -244,7 +246,7 @@ "name": "Box In", "type": "feature", "system": { - "description": "

Mark a Stress to choose a target within Very Close range to focus on. That target has disadvantage on attack rolls when they’re within Very Close range of the @Lookup[@name]. The @Lookup[@name] can only focus on one target at a time.

", + "description": "

Mark a Stress to choose a target within Very Close range to focus on. That target has disadvantage on attack rolls when they’re within Very Close range of the @Lookup[@name]. The @Lookup[@name]Sentinel can only focus on one target at a time.

", "resource": null, "actions": { "4RQnBu4kcUs3PcPH": { @@ -349,7 +351,7 @@ "name": "Mana Bolt", "type": "feature", "system": { - "description": "

Spend a Fear to lob explosive magic at a point within Far range. All targets within Very Close range of that point must make an Agility Reaction Roll. Targets who fail take 2d8+20 magic damage and are knocked back to Close range. Targets who succeed take half damage and aren’t knocked back.

", + "description": "

Spend a Fear to lob explosive magic at a point within Far range. All targets within Very Close range of that point must make an Agility Reaction Roll. Targets who fail take 2d8+20 magic damage and are knocked back to Close range. Targets who succeed take half damage and aren’t knocked back.

@Template[type:circle|range:vc]

", "resource": null, "actions": { "mI9i9iwrM48NjzeE": { @@ -373,8 +375,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -400,7 +402,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -430,16 +432,7 @@ }, "name": "Roll Save", "img": "icons/magic/sonic/projectile-shock-wave-blue.webp", - "range": "far", - "areas": [ - { - "name": "Mana Bolt", - "type": "placed", - "shape": "circle", - "size": "veryClose", - "effects": [] - } - ] + "range": "far" } }, "originItemType": null, @@ -483,8 +476,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -510,7 +503,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Vault_Guardian_Turret_c5hGdvY5UnSjlHws.json b/src/packs/adversaries/adversary_Vault_Guardian_Turret_c5hGdvY5UnSjlHws.json index 018d5b58..ab683607 100644 --- a/src/packs/adversaries/adversary_Vault_Guardian_Turret_c5hGdvY5UnSjlHws.json +++ b/src/packs/adversaries/adversary_Vault_Guardian_Turret_c5hGdvY5UnSjlHws.json @@ -74,8 +74,8 @@ }, "range": "far", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -101,7 +101,7 @@ }, "base": false } - } + ] }, "img": "icons/commodities/tech/metal-joint.webp", "type": "attack", @@ -132,9 +132,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -185,7 +188,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -211,8 +214,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -410,7 +412,7 @@ "name": "Detonation", "type": "feature", "system": { - "description": "

When the @Lookup[@name] is destroyed, they explode. All targets within Close range must make an Agility Reaction Roll. Targets who fail take 3d20 physical damage. Targets who succeed take half damage.

", + "description": "

When the @Lookup[@name] is destroyed, they explode. All targets within Close range must make an Agility Reaction Roll. Targets who fail take 3d20 physical damage. Targets who succeed take half damage.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "i1PZ9ddYdOOs2xSb": { @@ -427,8 +429,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -454,9 +456,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -485,16 +486,7 @@ }, "name": "Roll Save", "img": "icons/magic/sonic/explosion-shock-wave-teal.webp", - "range": "close", - "areas": [ - { - "name": "Detonation", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "originItemType": null, diff --git a/src/packs/adversaries/adversary_Volcanic_Dragon__Ashen_Tyrant_pMuXGCSOQaxpi5tb.json b/src/packs/adversaries/adversary_Volcanic_Dragon__Ashen_Tyrant_pMuXGCSOQaxpi5tb.json index e360f0c8..82bdd810 100644 --- a/src/packs/adversaries/adversary_Volcanic_Dragon__Ashen_Tyrant_pMuXGCSOQaxpi5tb.json +++ b/src/packs/adversaries/adversary_Volcanic_Dragon__Ashen_Tyrant_pMuXGCSOQaxpi5tb.json @@ -67,8 +67,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -94,7 +94,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", @@ -163,9 +163,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -216,7 +219,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -242,8 +245,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -449,8 +451,8 @@ "recovery": null }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -475,9 +477,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -486,16 +487,7 @@ "effects": [], "name": "Lose Hope", "img": "icons/magic/fire/flame-burning-skull-orange.webp", - "range": "close", - "areas": [ - { - "name": "Ashes to Ashes", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "originItemType": null, @@ -520,7 +512,7 @@ "name": "Desperate Rampage", "type": "feature", "system": { - "description": "

Mark a Stress to make an attack against all targets within Close range. Targets the @Lookup[@name] succeeds against take 2d20+2 physical damage, are knocked back to Close range of where they were, and must mark a Stress.

", + "description": "

Mark a Stress to make an attack against all targets within Close range. Targets the @Lookup[@name] succeeds against take 2d20+2 physical damage, are knocked back to Close range of where they were, and must mark a Stress.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "3glUQAcsLBcCumnS": { @@ -537,8 +529,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -564,7 +556,7 @@ } } }, - "stress": { + { "value": { "custom": { "enabled": true, @@ -589,9 +581,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -620,16 +611,7 @@ }, "name": "Attack", "img": "icons/creatures/abilities/tail-swipe-green.webp", - "range": "close", - "areas": [ - { - "name": "Desperate Rampage", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "originItemType": null, @@ -655,7 +637,7 @@ "name": "Ashen Cloud", "type": "feature", "system": { - "description": "

Spend a Fear to smash the ground and kick up ash within Far range. While within the ash cloud, a target has disadvantage on action rolls. The ash cloud clears the next time an adversary is spotlighted.

", + "description": "

Spend a Fear to smash the ground and kick up ash within Far range. While within the ash cloud, a target has disadvantage on action rolls. The ash cloud clears the next time an adversary is spotlighted.

@Template[type:emanation|range:f]

", "resource": null, "actions": { "UrD4A68IBJgyfvvt": { @@ -685,16 +667,7 @@ }, "name": "Spend Fear", "img": "icons/magic/air/fog-gas-smoke-brown.webp", - "range": "", - "areas": [ - { - "name": "Ashen Cloud", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "" } }, "originItemType": null, @@ -720,14 +693,14 @@ "name": "Apocalyptic Thrasing", "type": "feature", "system": { - "description": "

Countdown (1d12). Spend a Fear to activate. It ticks down when a PC rolls with Fear. When it triggers, the @Lookup[@name] thrashes about, causing environmental damage (such as an earthquake, avalanche, or collapsing walls). All targets within Far range must make a Strength Reaction Roll. Targets who fail take 2d10+10 physical damage and are Restrained by the rubble until they break free with a successful Strength Roll. Targets who succeed take half damage. If the @Lookup[@name] is defeated while this countdown is active, trigger the countdown immediately as the destruction caused by their death throes.

", + "description": "

Countdown (1d12). Spend a Fear to activate. It ticks down when a PC rolls with Fear. When it triggers, the @Lookup[@name] thrashes about, causing environmental damage (such as an earthquake, avalanche, or collapsing walls). All targets within Far range must make a Strength Reaction Roll. Targets who fail take 2d10+10 physical damage and are Restrained by the rubble until they break free with a successful Strength Roll. Targets who succeed take half damage. If the @Lookup[@name] is defeated while this countdown is active, trigger the countdown immediately as the destruction caused by their death throes.

@Template[type:emanation|range:f]

", "resource": null, "actions": { "OznXxmwiPwzuFPQZ": { "type": "attack", "_id": "OznXxmwiPwzuFPQZ", "systemPath": "actions", - "description": "

When the countdown triggers, the @Lookup[@name] thrashes about, causing environmental damage (such as an earthquake, avalanche, or collapsing walls). All targets within Far range must make a Strength Reaction Roll. Targets who fail take 2d10+10 physical damage and are Restrained by the rubble until they break free with a successful Strength Roll. Targets who succeed take half damage. If the @Lookup[@name] is defeated while this countdown is active, trigger the countdown immediately as the destruction caused by their death throes.

", + "description": "

When the countdown triggers, the @Lookup[@name] thrashes about, causing environmental damage (such as an earthquake, avalanche, or collapsing walls). All targets within Far range must make a Strength Reaction Roll. Targets who fail take 2d10+10 physical damage and are Restrained by the rubble until they break free with a successful Strength Roll. Targets who succeed take half damage. If the @Lookup[@name] is defeated while this countdown is active, trigger the countdown immediately as the destruction caused by their death throes.

@Template[type:emanation|range:f]

", "chatDisplay": true, "actionType": "action", "cost": [], @@ -737,8 +710,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -764,9 +737,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -800,16 +772,7 @@ }, "name": "Roll Save", "img": "icons/creatures/abilities/mouth-teeth-fire-orange.webp", - "range": "", - "areas": [ - { - "name": "Apocalyptic Thrasing", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "" }, "rZ7IwBnDzw7VmBT6": { "type": "countdown", @@ -878,19 +841,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until you break free with a successful Strength Roll.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Restrained by the rubble until you break free with a successful Strength Roll.

", "tint": "#ffffff", @@ -902,16 +864,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!pMuXGCSOQaxpi5tb.uWiyaJPXcoW06pOM.YUjdwrEZ4zn7WR9X" } ], diff --git a/src/packs/adversaries/adversary_Volcanic_Dragon__Molten_Scourge_eArAPuB38CNR0ZIM.json b/src/packs/adversaries/adversary_Volcanic_Dragon__Molten_Scourge_eArAPuB38CNR0ZIM.json index d4babd71..7f9deb6c 100644 --- a/src/packs/adversaries/adversary_Volcanic_Dragon__Molten_Scourge_eArAPuB38CNR0ZIM.json +++ b/src/packs/adversaries/adversary_Volcanic_Dragon__Molten_Scourge_eArAPuB38CNR0ZIM.json @@ -67,8 +67,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -94,7 +94,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", @@ -163,9 +163,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -216,7 +219,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -242,8 +245,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -357,8 +359,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -384,7 +386,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -440,7 +442,7 @@ "name": "Eruption", "type": "feature", "system": { - "description": "

Spend a Fear to erupt lava from beneath the @Lookup[@name]’s scales, filling the area within Very Close range with molten lava. All targets in that area must succeed on an Agility Reaction Roll or take 4d6+6 physical damage and be knocked back to Close range. This area remains lava. When a creature other than the @Lookup[@name] enters that area or acts while inside of it, they must mark 6 HP.

", + "description": "

Spend a Fear to erupt lava from beneath the @Lookup[@name]’s scales, filling the area within Very Close range with molten lava. All targets in that area must succeed on an Agility Reaction Roll or take 4d6+6 physical damage and be knocked back to Close range. This area remains lava. When a creature other than the @Lookup[@name] enters that area or acts while inside of it, they must mark 6 HP.

@Template[type:emanation|range:vc]

", "resource": null, "actions": { "OpwKa8tQQoaEIZiS": { @@ -457,8 +459,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -484,9 +486,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -515,16 +516,7 @@ }, "name": "Roll Save", "img": "icons/magic/fire/blast-jet-stream-embers-red.webp", - "range": "veryClose", - "areas": [ - { - "name": "Eruption", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "veryClose" } }, "originItemType": null, @@ -550,7 +542,7 @@ "name": "Volcanic Breath", "type": "feature", "system": { - "description": "

When the @Lookup[@name] takes Major damage, roll a d10. On a result of 8 or higher, the @Lookup[@name] breathes a flow of lava in front of them within Far range. All targets in that area must make an Agility Reaction Roll. Targets who fail take 2d10+4 physical damage, mark 1d4 Stress, and are Vulnerable until they clear a Stress. Targets who succeed take half damage and must mark a Stress.

", + "description": "

When the @Lookup[@name] takes Major damage, roll a d10. On a result of 8 or higher, the @Lookup[@name] breathes a flow of lava in front of them within Far range. All targets in that area must make an Agility Reaction Roll. Targets who fail take 2d10+4 physical damage, mark 1d4 Stress, and are Vulnerable until they clear a Stress. Targets who succeed take half damage and must mark a Stress.

@Template[type:inFront|range:f]

", "resource": null, "actions": { "OhrssSQhmciZt1Rm": { @@ -574,7 +566,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -610,7 +602,7 @@ "type": "attack", "_id": "LBNvfABGWcrygpQM", "systemPath": "actions", - "description": "

The @Lookup[@name]Β breathes a flow of lava in front of them within Far range. All targets in that area must make an Agility Reaction Roll. Targets who fail take 2d10+4 physical damage, mark 1d4 Stress, and are Vulnerable until they clear a Stress. Targets who succeed take half damage and must mark a Stress.

", + "description": "

The @Lookup[@name] breathes a flow of lava in front of them within Far range. All targets in that area must make an Agility Reaction Roll. Targets who fail take 2d10+4 physical damage, mark 1d4 Stress, and are Vulnerable until they clear a Stress. Targets who succeed take half damage and must mark a Stress.

@Template[type:inFront|range:f]

", "chatDisplay": true, "actionType": "action", "cost": [], @@ -620,8 +612,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -647,7 +639,7 @@ } } }, - "stress": { + { "value": { "custom": { "enabled": false @@ -671,9 +663,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -707,16 +698,7 @@ }, "name": "Roll Save", "img": "icons/magic/fire/blast-jet-stream-embers-orange.webp", - "range": "far", - "areas": [ - { - "name": "Volcanic Breath", - "type": "placed", - "shape": "inFront", - "size": "far", - "effects": [] - } - ] + "range": "far" } }, "originItemType": null, @@ -739,19 +721,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until you clear a Stress.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Vulnerable until you clear a Stress.

", "tint": "#ffffff", @@ -763,16 +744,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!eArAPuB38CNR0ZIM.2mK8kxfp2WBUeBri.xmzA6NC9zrulhzQs" } ], @@ -809,8 +780,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -836,7 +807,7 @@ } } } - }, + ], "includeBase": false, "direct": true }, diff --git a/src/packs/adversaries/adversary_Volcanic_Dragon__Obsidian_Predator_ladm7wykhZczYzrQ.json b/src/packs/adversaries/adversary_Volcanic_Dragon__Obsidian_Predator_ladm7wykhZczYzrQ.json index 82daed6a..5f32aae5 100644 --- a/src/packs/adversaries/adversary_Volcanic_Dragon__Obsidian_Predator_ladm7wykhZczYzrQ.json +++ b/src/packs/adversaries/adversary_Volcanic_Dragon__Obsidian_Predator_ladm7wykhZczYzrQ.json @@ -67,8 +67,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -94,7 +94,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", @@ -163,9 +163,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -216,7 +219,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -242,8 +245,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -446,7 +448,7 @@ "name": "Avalanche Tail", "type": "feature", "system": { - "description": "

Mark a Stress to make an attack against all targets within Close range. Targets the @Lookup[@name] succeeds against take 4d6+4 physical damage and are knocked.

", + "description": "

Mark a Stress to make an attack against all targets within Close range. Targets the @Lookup[@name] succeeds against take 4d6+4 physical damage and are knocked.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "23y0BoufIgNq62j9": { @@ -463,8 +465,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -488,9 +490,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -524,16 +525,7 @@ }, "name": "Attack", "img": "icons/creatures/abilities/tail-swipe-green.webp", - "range": "close", - "areas": [ - { - "name": "Avalanche Tail", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "originItemType": null, @@ -556,15 +548,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [] + } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Vulnerable until your next roll with Hope.

", "tint": "#ffffff", @@ -576,9 +571,6 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!ladm7wykhZczYzrQ.8bMOItTuL7PfAYcJ.qtIaAZDW8QsjILgb" } ], @@ -598,7 +590,7 @@ "name": "Dive-Bomb", "type": "feature", "system": { - "description": "

If the @Lookup[@name] is flying, mark a Stress to choose a point within Far range. Move to that point and make an attack against all targets within Very Close range. Targets the @Lookup[@name] succeeds against take 2d10+6 physical damage and must mark a Stress and lose a Hope.

", + "description": "

If the @Lookup[@name] is flying, mark a Stress to choose a point within Far range. Move to that point and make an attack against all targets within Very Close range. Targets the @Lookup[@name] succeeds against take 2d10+6 physical damage and must mark a Stress and lose a Hope.

@Template[type:emanation|range:vc]

", "resource": null, "actions": { "OpAT9nxlbgvnhdBg": { @@ -615,8 +607,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -642,7 +634,7 @@ } } }, - "stress": { + { "value": { "custom": { "enabled": true, @@ -667,7 +659,7 @@ }, "type": [] }, - "hope": { + { "value": { "custom": { "enabled": true, @@ -692,9 +684,8 @@ }, "type": [] } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -723,16 +714,7 @@ }, "name": "Attack", "img": "icons/creatures/reptiles/dragon-winged-blue.webp", - "range": "far", - "areas": [ - { - "name": "Dive-Bomb", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "far" } }, "originItemType": null, diff --git a/src/packs/adversaries/adversary_War_Wizard_noDdT0tsN6FXSmC8.json b/src/packs/adversaries/adversary_War_Wizard_noDdT0tsN6FXSmC8.json index 0ba663ab..f087c63d 100644 --- a/src/packs/adversaries/adversary_War_Wizard_noDdT0tsN6FXSmC8.json +++ b/src/packs/adversaries/adversary_War_Wizard_noDdT0tsN6FXSmC8.json @@ -86,8 +86,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -113,7 +113,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -143,9 +143,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -196,7 +199,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -222,8 +225,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -341,7 +343,7 @@ "name": "Eruption", "type": "feature", "system": { - "description": "

Spend a Fear and choose a point within Far range. A Very Close area around that point erupts into impassable terrain. All targets within that area must make an Agility Reaction Roll (14). Targets who fail take 2d10 physical damage and are thrown out of the area. Targets who succeed take half damage and aren’t moved.

", + "description": "

Spend a Fear and choose a point within Far range. A Very Close area around that point erupts into impassable terrain. All targets within that area must make an Agility Reaction Roll (14). Targets who fail take 2d10 physical damage and are thrown out of the area. Targets who succeed take half damage and aren’t moved.

@Template[type:circle|range:vc]

", "resource": null, "actions": { "vnMq4NuQO6GYxWhM": { @@ -365,8 +367,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -392,7 +394,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -422,16 +424,7 @@ }, "name": "Roll Save", "img": "icons/magic/earth/barrier-stone-explosion-red.webp", - "range": "far", - "areas": [ - { - "name": "Eruption", - "type": "placed", - "shape": "circle", - "size": "veryClose", - "effects": [] - } - ] + "range": "far" } }, "originItemType": null, @@ -481,8 +474,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -508,7 +501,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -581,8 +574,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -608,7 +601,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Weaponmaster_ZNbQ2jg35LG4t9eH.json b/src/packs/adversaries/adversary_Weaponmaster_ZNbQ2jg35LG4t9eH.json index 8eaf56f9..2989468b 100644 --- a/src/packs/adversaries/adversary_Weaponmaster_ZNbQ2jg35LG4t9eH.json +++ b/src/packs/adversaries/adversary_Weaponmaster_ZNbQ2jg35LG4t9eH.json @@ -75,8 +75,8 @@ "img": "icons/weapons/swords/greatsword-guard-gold-worn.webp", "range": "veryClose", "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -102,7 +102,7 @@ }, "base": false } - } + ] }, "type": "attack", "chatDisplay": false @@ -240,8 +240,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -267,7 +267,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -324,19 +324,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until your next successful attack

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

The next time the Taunted target attacks, they have disadvantage against targets other than the Weaponmaster.

", "tint": "#ffffff", @@ -346,16 +345,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!ZNbQ2jg35LG4t9eH.tyGgOqQzDSIypoMz.j2jYmYbtWXvq32yX" } ], @@ -416,8 +405,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -442,7 +431,7 @@ }, "type": [] }, - "stress": { + { "value": { "custom": { "enabled": true, @@ -467,7 +456,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -537,8 +526,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -564,7 +553,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Young_Dryad_8yUj2Mzvnifhxegm.json b/src/packs/adversaries/adversary_Young_Dryad_8yUj2Mzvnifhxegm.json index 9d7f66d0..446a4af3 100644 --- a/src/packs/adversaries/adversary_Young_Dryad_8yUj2Mzvnifhxegm.json +++ b/src/packs/adversaries/adversary_Young_Dryad_8yUj2Mzvnifhxegm.json @@ -80,8 +80,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ }, "base": false } - } + ] }, "type": "attack", "range": "melee", @@ -253,7 +253,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -367,21 +367,20 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until they’re freed with a successful Strength Roll.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

You are Restrained until you're freed with a successful Strength Roll. When a creature makes an action roll against the cage, they must mark a Stress.

", + "description": "

You are Restrained until you're freed with a successful Strength Roll. When a creature makes an action roll against the cage, they must mark a Stress.

", "tint": "#ffffff", "statuses": [ "restrained" @@ -391,16 +390,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!8yUj2Mzvnifhxegm.i8NoUGUTNY2C5NhC.k8LzBWRZo6VPqvpH" } ], @@ -440,8 +429,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -467,7 +456,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Young_Ice_Dragon_UGPiPLJsPvMTSKEF.json b/src/packs/adversaries/adversary_Young_Ice_Dragon_UGPiPLJsPvMTSKEF.json index 6c55ba15..c55262e4 100644 --- a/src/packs/adversaries/adversary_Young_Ice_Dragon_UGPiPLJsPvMTSKEF.json +++ b/src/packs/adversaries/adversary_Young_Ice_Dragon_UGPiPLJsPvMTSKEF.json @@ -79,8 +79,8 @@ "type": "attack" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -106,7 +106,7 @@ }, "base": false } - } + ] }, "img": "icons/creatures/claws/claw-scaled-red.webp", "type": "attack", @@ -138,9 +138,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -191,7 +194,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -217,8 +220,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -300,8 +302,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -326,7 +328,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -386,7 +388,7 @@ "name": "Blizzard Breath", "type": "feature", "system": { - "description": "

Spend 2 Fear to release an icy whorl in front of the @Lookup[@name] within Close range. All targets in this area must make an Agility Reaction Roll. Targets who fail take 4d6+5 magic damage and are Restrained by ice until they break free with a successful Strength Roll. Targets who succeed must mark 2 Stress or take half damage.

", + "description": "

Spend 2 Fear to release an icy whorl in front of the @Lookup[@name] within Close range. All targets in this area must make an Agility Reaction Roll. Targets who fail take 4d6+5 magic damage and are Restrained by ice until they break free with a successful Strength Roll. Targets who succeed must mark 2 Stress or take half damage.

@Template[type:inFront|range:c]

", "resource": null, "actions": { "CBecTlgyUBFxgoi5": { @@ -410,8 +412,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -437,9 +439,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -473,16 +474,7 @@ }, "name": "Roll Save", "img": "icons/magic/water/projectiles-ice-faceted-shard-salvo-blue.webp", - "range": "close", - "areas": [ - { - "name": "Blizzard Breath", - "type": "placed", - "shape": "inFront", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "originItemType": null, @@ -505,15 +497,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [] + } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Restrained by ice until you break free with a successful Strength Roll.

", "tint": "#ffffff", @@ -525,9 +520,6 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!UGPiPLJsPvMTSKEF.QV2ytK4b1VWF71OS.g9bUvmw3jet6T99e" } ], @@ -547,7 +539,7 @@ "name": "Avalanche", "type": "feature", "system": { - "description": "

Spend a Fear to have the @Lookup[@name] unleash a huge downfall of snow and ice, covering all other creatures within Far range. All targets within this area must succeed on an Instinct Reaction Roll or be buried in snow and rocks, becoming Vulnerable until they dig themselves out from the debris. For each PC that fails the reaction roll, you gain a Fear.

", + "description": "

Spend a Fear to have the @Lookup[@name] unleash a huge downfall of snow and ice, covering all other creatures within Far range. All targets within this area must succeed on an Instinct Reaction Roll or be buried in snow and rocks, becoming Vulnerable until they dig themselves out from the debris. For each PC that fails the reaction roll, you gain a Fear.

@Template[type:emanation|range:f]

", "resource": null, "actions": { "G9LjoXShkCcgx8EC": { @@ -571,9 +563,8 @@ "recovery": null }, "damage": { - "parts": {}, - "includeBase": false, - "groupAttack": "" + "parts": [], + "includeBase": false }, "target": { "type": "any", @@ -607,16 +598,7 @@ }, "name": "Attack", "img": "icons/magic/water/barrier-ice-wall-snow.webp", - "range": "far", - "areas": [ - { - "name": "Avalanche", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "far" } }, "originItemType": null, @@ -639,19 +621,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until they dig themselves out from the debris.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Vulnerable until you dig yourself out from the debris.

", "tint": "#ffffff", @@ -663,16 +644,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!UGPiPLJsPvMTSKEF.CcRTxCDCJskiu3fI.40cFHuNdEvbUZ9rs" } ], @@ -709,8 +680,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -735,7 +706,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -773,26 +744,25 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.disadvantageSources", - "value": "On attack rolls.", - "priority": null, - "type": "add" - } - ], - "duration": { - "type": "temporary", - "description": "

Until your next rest or you clear a Stress.

" } }, + "changes": [ + { + "key": "system.disadvantageSources", + "mode": 2, + "value": "On attack rolls.", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Chilled until your next rest or you clear a Stress. While you are Chilled, you have disadvantage on attack rolls.

", "tint": "#ffffff", @@ -802,16 +772,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!UGPiPLJsPvMTSKEF.nXZHOfcYvjg3YMNU.1JlRxa07i8T1a9x6" } ], @@ -849,8 +809,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -876,7 +836,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/adversaries/adversary_Zombie_Legion_YhJrP7rTBiRdX5Fp.json b/src/packs/adversaries/adversary_Zombie_Legion_YhJrP7rTBiRdX5Fp.json index 2c3495ff..91bdab81 100644 --- a/src/packs/adversaries/adversary_Zombie_Legion_YhJrP7rTBiRdX5Fp.json +++ b/src/packs/adversaries/adversary_Zombie_Legion_YhJrP7rTBiRdX5Fp.json @@ -68,8 +68,8 @@ "motivesAndTactics": "Consume brain, shred fl esh, surround", "attack": { "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -95,7 +95,7 @@ "resultBased": false, "base": false } - } + ] }, "name": "Undead Hands", "roll": { diff --git a/src/packs/adversaries/adversary_Zombie_Pack_Nf0v43rtflV56V2T.json b/src/packs/adversaries/adversary_Zombie_Pack_Nf0v43rtflV56V2T.json index f418758a..017537ad 100644 --- a/src/packs/adversaries/adversary_Zombie_Pack_Nf0v43rtflV56V2T.json +++ b/src/packs/adversaries/adversary_Zombie_Pack_Nf0v43rtflV56V2T.json @@ -68,8 +68,8 @@ "description": "

A group of shambling corpses instinctively moving together.

", "attack": { "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -95,7 +95,7 @@ "resultBased": false, "base": false } - } + ] }, "name": "Bite", "roll": { diff --git a/src/packs/ancestries/feature_Charge_AA2CZlJSWW8GPhrR.json b/src/packs/ancestries/feature_Charge_AA2CZlJSWW8GPhrR.json index 0af2610a..f1f7ae35 100644 --- a/src/packs/ancestries/feature_Charge_AA2CZlJSWW8GPhrR.json +++ b/src/packs/ancestries/feature_Charge_AA2CZlJSWW8GPhrR.json @@ -29,8 +29,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -56,7 +56,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/ancestries/feature_Elemental_Breath_sRaE3CgkgjBF1UpV.json b/src/packs/ancestries/feature_Elemental_Breath_sRaE3CgkgjBF1UpV.json index fd313fcf..71ac4438 100644 --- a/src/packs/ancestries/feature_Elemental_Breath_sRaE3CgkgjBF1UpV.json +++ b/src/packs/ancestries/feature_Elemental_Breath_sRaE3CgkgjBF1UpV.json @@ -22,8 +22,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -47,7 +47,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -77,16 +77,7 @@ }, "name": "Attack", "img": "icons/creatures/abilities/dragon-fire-breath-orange.webp", - "range": "veryClose", - "areas": [ - { - "name": "Elemental Breath", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "veryClose" } }, "originItemType": null, diff --git a/src/packs/ancestries/feature_Fungril_Network_9tmeXm623hl4Qnws.json b/src/packs/ancestries/feature_Fungril_Network_9tmeXm623hl4Qnws.json index 87638f37..9d970a67 100644 --- a/src/packs/ancestries/feature_Fungril_Network_9tmeXm623hl4Qnws.json +++ b/src/packs/ancestries/feature_Fungril_Network_9tmeXm623hl4Qnws.json @@ -22,7 +22,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/ancestries/feature_Kick_gpW19TfJk0WWFh1S.json b/src/packs/ancestries/feature_Kick_gpW19TfJk0WWFh1S.json index b363b6c2..89546ded 100644 --- a/src/packs/ancestries/feature_Kick_gpW19TfJk0WWFh1S.json +++ b/src/packs/ancestries/feature_Kick_gpW19TfJk0WWFh1S.json @@ -31,8 +31,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false, @@ -58,7 +58,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/ancestries/feature_Long_Tongue_oWbdlh51ajn1Q5kL.json b/src/packs/ancestries/feature_Long_Tongue_oWbdlh51ajn1Q5kL.json index 1f1156d7..aee64a9a 100644 --- a/src/packs/ancestries/feature_Long_Tongue_oWbdlh51ajn1Q5kL.json +++ b/src/packs/ancestries/feature_Long_Tongue_oWbdlh51ajn1Q5kL.json @@ -29,8 +29,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -54,7 +54,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/ancestries/feature_Luckbringer_8O6SQQMxKWr430QA.json b/src/packs/ancestries/feature_Luckbringer_8O6SQQMxKWr430QA.json index 36fd73fb..3c31d62d 100644 --- a/src/packs/ancestries/feature_Luckbringer_8O6SQQMxKWr430QA.json +++ b/src/packs/ancestries/feature_Luckbringer_8O6SQQMxKWr430QA.json @@ -22,8 +22,8 @@ "recovery": "session" }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -48,7 +48,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/ancestries/feature_Retract_UFR67BUOhNGLFyg9.json b/src/packs/ancestries/feature_Retract_UFR67BUOhNGLFyg9.json index eb9696b2..9a1c434b 100644 --- a/src/packs/ancestries/feature_Retract_UFR67BUOhNGLFyg9.json +++ b/src/packs/ancestries/feature_Retract_UFR67BUOhNGLFyg9.json @@ -68,33 +68,31 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.resistance.physical.resistance", - "type": "override", - "value": 1, - "priority": null, - "phase": "initial" - }, - { - "key": "system.disadvantageSources", - "type": "add", - "value": "Action rolls", - "priority": null, - "phase": "initial" - } - ], - "duration": { - "type": "" } }, + "changes": [ + { + "key": "system.resistance.physical.resistance", + "mode": 5, + "value": "1", + "priority": null + }, + { + "key": "system.disadvantageSources", + "mode": 2, + "value": "Action Rolls", + "priority": null + } + ], "disabled": true, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

While in your shell, you have resistance to physical damage, you have disadvantage on action rolls, and you can’t move.

", "tint": "#ffffff", @@ -104,16 +102,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!UFR67BUOhNGLFyg9.3V4FPoyjJUnFP9WS" } ], diff --git a/src/packs/ancestries/feature_Retracting_Claws_Zj69cAeb3NjIa8Hn.json b/src/packs/ancestries/feature_Retracting_Claws_Zj69cAeb3NjIa8Hn.json index b9b000f4..8e408ec6 100644 --- a/src/packs/ancestries/feature_Retracting_Claws_Zj69cAeb3NjIa8Hn.json +++ b/src/packs/ancestries/feature_Retracting_Claws_Zj69cAeb3NjIa8Hn.json @@ -22,7 +22,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -83,18 +83,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -106,16 +106,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!Zj69cAeb3NjIa8Hn.pO76svFkmWmZ6LjC" } ], diff --git a/src/packs/ancestries/feature_Tusks_YhxD1ujZpftPu19w.json b/src/packs/ancestries/feature_Tusks_YhxD1ujZpftPu19w.json index 6038f2c6..5bd72773 100644 --- a/src/packs/ancestries/feature_Tusks_YhxD1ujZpftPu19w.json +++ b/src/packs/ancestries/feature_Tusks_YhxD1ujZpftPu19w.json @@ -31,8 +31,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false, @@ -58,7 +58,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/ancestries/feature_Unshakeable_G5pE8FW94V1W9jJx.json b/src/packs/ancestries/feature_Unshakeable_G5pE8FW94V1W9jJx.json index bf0a241b..195b10e8 100644 --- a/src/packs/ancestries/feature_Unshakeable_G5pE8FW94V1W9jJx.json +++ b/src/packs/ancestries/feature_Unshakeable_G5pE8FW94V1W9jJx.json @@ -22,7 +22,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/beastforms/beastform_Agile_Scout_a9UoCwtrbgKk02mK.json b/src/packs/beastforms/beastform_Agile_Scout_a9UoCwtrbgKk02mK.json index bd9bfffb..71018bc9 100644 --- a/src/packs/beastforms/beastform_Agile_Scout_a9UoCwtrbgKk02mK.json +++ b/src/packs/beastforms/beastform_Agile_Scout_a9UoCwtrbgKk02mK.json @@ -29,7 +29,8 @@ "Compendium.daggerheart.beastforms.Item.QFg1hNCEoKVDd9Zo" ], "evolved": { - "mainTraitBonus": 0 + "mainTraitBonus": 0, + "maximumTier": 1 }, "hybrid": { "beastformOptions": 2, diff --git a/src/packs/beastforms/feature_Demolish_DfBXO8jTchwFG8dZ.json b/src/packs/beastforms/feature_Demolish_DfBXO8jTchwFG8dZ.json index 36080868..b7d85ef1 100644 --- a/src/packs/beastforms/feature_Demolish_DfBXO8jTchwFG8dZ.json +++ b/src/packs/beastforms/feature_Demolish_DfBXO8jTchwFG8dZ.json @@ -3,7 +3,7 @@ "type": "feature", "img": "icons/magic/earth/barrier-stone-brown-green.webp", "system": { - "description": "

Spend a Hope to move up to Far range in a straight line and make an attack against all targets within Melee range of the line. Targets you succeed against take d8+10 physical damage using your Proficiency and are temporarily Vulnerable.

", + "description": "

Spend a Hope to move up to Far range in a straight line and make an attack against all targets within Melee range of the line. Targets you succeed against take d8+10 physical damage using your Proficiency and are temporarily Vulnerable.

@Template[type:ray|range:f]

", "resource": null, "actions": { "5SXMT39vrZoK7GBM": { @@ -23,12 +23,12 @@ ], "uses": { "value": null, - "max": "", + "max": null, "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -52,7 +52,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -87,16 +87,7 @@ }, "name": "Attack", "img": "icons/magic/earth/barrier-stone-brown-green.webp", - "range": "far", - "areas": [ - { - "name": "Demolish", - "type": "placed", - "shape": "line", - "size": "far", - "effects": [] - } - ] + "range": "far" } }, "originItemType": null, @@ -116,18 +107,17 @@ "transfer": false, "_id": "FXdFgEgqVl5gIWJS", "type": "base", - "system": { - "changes": [], - "duration": { - "type": "temporary" - } - }, + "system": {}, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -139,16 +129,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!DfBXO8jTchwFG8dZ.FXdFgEgqVl5gIWJS" } ], diff --git a/src/packs/beastforms/feature_Elusive_Prey_a7Qvmm14nx9BCysA.json b/src/packs/beastforms/feature_Elusive_Prey_a7Qvmm14nx9BCysA.json index a81eb8af..d99a6ab7 100644 --- a/src/packs/beastforms/feature_Elusive_Prey_a7Qvmm14nx9BCysA.json +++ b/src/packs/beastforms/feature_Elusive_Prey_a7Qvmm14nx9BCysA.json @@ -27,7 +27,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/beastforms/feature_Hobbling_Strike_8u0HkK3WgtU9lWYs.json b/src/packs/beastforms/feature_Hobbling_Strike_8u0HkK3WgtU9lWYs.json index a1d80e5d..6a16f864 100644 --- a/src/packs/beastforms/feature_Hobbling_Strike_8u0HkK3WgtU9lWYs.json +++ b/src/packs/beastforms/feature_Hobbling_Strike_8u0HkK3WgtU9lWYs.json @@ -58,18 +58,17 @@ "transfer": false, "_id": "2kKkV9zhfvqA2vlt", "type": "base", - "system": { - "changes": [], - "duration": { - "type": "temporary" - } - }, + "system": {}, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -81,16 +80,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!8u0HkK3WgtU9lWYs.2kKkV9zhfvqA2vlt" } ], diff --git a/src/packs/beastforms/feature_Ocean_Master_tGDdEH40wyOCsFmH.json b/src/packs/beastforms/feature_Ocean_Master_tGDdEH40wyOCsFmH.json index aa0baa31..a4431417 100644 --- a/src/packs/beastforms/feature_Ocean_Master_tGDdEH40wyOCsFmH.json +++ b/src/packs/beastforms/feature_Ocean_Master_tGDdEH40wyOCsFmH.json @@ -51,18 +51,17 @@ "transfer": false, "_id": "6GBczj8REkDmgX2Q", "type": "base", - "system": { - "changes": [], - "duration": { - "type": "temporary" - } - }, + "system": {}, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -74,16 +73,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!tGDdEH40wyOCsFmH.6GBczj8REkDmgX2Q" } ], diff --git a/src/packs/beastforms/feature_Snapping_Strike_Ky3rZD3sJMXYZOBC.json b/src/packs/beastforms/feature_Snapping_Strike_Ky3rZD3sJMXYZOBC.json index 581bdcf5..d79c9018 100644 --- a/src/packs/beastforms/feature_Snapping_Strike_Ky3rZD3sJMXYZOBC.json +++ b/src/packs/beastforms/feature_Snapping_Strike_Ky3rZD3sJMXYZOBC.json @@ -58,18 +58,17 @@ "transfer": false, "_id": "y3EsJuInxE7juNXT", "type": "base", - "system": { - "changes": [], - "duration": { - "type": "temporary" - } - }, + "system": {}, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -82,16 +81,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!Ky3rZD3sJMXYZOBC.y3EsJuInxE7juNXT" } ], diff --git a/src/packs/beastforms/feature_Takedown_0ey4kM9ssj2otHvb.json b/src/packs/beastforms/feature_Takedown_0ey4kM9ssj2otHvb.json index 531b30ea..4dc2c0f7 100644 --- a/src/packs/beastforms/feature_Takedown_0ey4kM9ssj2otHvb.json +++ b/src/packs/beastforms/feature_Takedown_0ey4kM9ssj2otHvb.json @@ -27,8 +27,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -54,7 +54,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/beastforms/feature_Trample_A0lgd6eVEfX6oqSB.json b/src/packs/beastforms/feature_Trample_A0lgd6eVEfX6oqSB.json index 90801cf6..e9878f02 100644 --- a/src/packs/beastforms/feature_Trample_A0lgd6eVEfX6oqSB.json +++ b/src/packs/beastforms/feature_Trample_A0lgd6eVEfX6oqSB.json @@ -3,7 +3,7 @@ "type": "feature", "img": "icons/environment/people/charge.webp", "system": { - "description": "

Mark a Stress to move up to Close range in a straight line and make an attack against all targets within Melee range of the line. Targets you succeed against take d8+1 physical damage using your Proficiency and are temporarily Vulnerable.

", + "description": "

Mark a Stress to move up to Close range in a straight line and make an attack against all targets within Melee range of the line. Targets you succeed against take d8+1 physical damage using your Proficiency and are temporarily Vulnerable.

@Template[type:ray|range:close]

", "resource": null, "actions": { "YCOTIv9IVEKpumbJ": { @@ -23,12 +23,12 @@ ], "uses": { "value": null, - "max": "", + "max": null, "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -52,11 +52,11 @@ } } } - }, + ], "includeBase": false }, "target": { - "type": "", + "type": null, "amount": null }, "effects": [ @@ -87,16 +87,7 @@ }, "name": "Attack", "img": "icons/environment/people/charge.webp", - "range": "close", - "areas": [ - { - "name": "Trample", - "type": "placed", - "shape": "line", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "originItemType": null, @@ -116,18 +107,17 @@ "transfer": false, "_id": "LkekG4IngVW9rFjI", "type": "base", - "system": { - "changes": [], - "duration": { - "type": "temporary" - } - }, + "system": {}, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -139,16 +129,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!A0lgd6eVEfX6oqSB.LkekG4IngVW9rFjI" } ], diff --git a/src/packs/beastforms/feature_Unyielding_vEAQ4cfsoPmOv2Gg.json b/src/packs/beastforms/feature_Unyielding_vEAQ4cfsoPmOv2Gg.json index 429b5a1a..6bfafa79 100644 --- a/src/packs/beastforms/feature_Unyielding_vEAQ4cfsoPmOv2Gg.json +++ b/src/packs/beastforms/feature_Unyielding_vEAQ4cfsoPmOv2Gg.json @@ -20,7 +20,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/beastforms/feature_Venomous_Bite_2KlTnfzO03vneVS8.json b/src/packs/beastforms/feature_Venomous_Bite_2KlTnfzO03vneVS8.json index 30ace68f..00870086 100644 --- a/src/packs/beastforms/feature_Venomous_Bite_2KlTnfzO03vneVS8.json +++ b/src/packs/beastforms/feature_Venomous_Bite_2KlTnfzO03vneVS8.json @@ -51,18 +51,17 @@ "transfer": false, "_id": "TTyAKKoUCoYXSMs4", "type": "base", - "system": { - "changes": [], - "duration": { - "type": "temporary" - } - }, + "system": {}, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

A Poisoned creature takes 1d10 direct physical damage each time they act.

", "tint": "#ffffff", @@ -72,16 +71,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!2KlTnfzO03vneVS8.TTyAKKoUCoYXSMs4" } ], diff --git a/src/packs/beastforms/feature_Venomous_Strike_uW3853pViM9VAfHb.json b/src/packs/beastforms/feature_Venomous_Strike_uW3853pViM9VAfHb.json index 923e43bd..57d5bb56 100644 --- a/src/packs/beastforms/feature_Venomous_Strike_uW3853pViM9VAfHb.json +++ b/src/packs/beastforms/feature_Venomous_Strike_uW3853pViM9VAfHb.json @@ -20,7 +20,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -75,18 +75,17 @@ "transfer": false, "_id": "1iQPj96LqUNkRaxE", "type": "base", - "system": { - "changes": [], - "duration": { - "type": "temporary" - } - }, + "system": {}, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

A Poisoned creature takes 1d10 physical direct damage each time they act.

", "tint": "#ffffff", @@ -96,16 +95,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!uW3853pViM9VAfHb.1iQPj96LqUNkRaxE" } ], diff --git a/src/packs/beastforms/feature_Vicious_Maul_jYUBi7yLHap5ljpa.json b/src/packs/beastforms/feature_Vicious_Maul_jYUBi7yLHap5ljpa.json index a3494ed0..2bdad760 100644 --- a/src/packs/beastforms/feature_Vicious_Maul_jYUBi7yLHap5ljpa.json +++ b/src/packs/beastforms/feature_Vicious_Maul_jYUBi7yLHap5ljpa.json @@ -27,8 +27,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -53,7 +53,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -88,18 +88,17 @@ "transfer": false, "_id": "MIAh9XNwDXGDktCm", "type": "base", - "system": { - "changes": [], - "duration": { - "type": "temporary" - } - }, + "system": {}, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -111,16 +110,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!jYUBi7yLHap5ljpa.MIAh9XNwDXGDktCm" } ], diff --git a/src/packs/beastforms/feature_Webslinger_D73fS1iM4SZPFimu.json b/src/packs/beastforms/feature_Webslinger_D73fS1iM4SZPFimu.json index 7cd48d25..40adb28b 100644 --- a/src/packs/beastforms/feature_Webslinger_D73fS1iM4SZPFimu.json +++ b/src/packs/beastforms/feature_Webslinger_D73fS1iM4SZPFimu.json @@ -20,7 +20,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -75,18 +75,17 @@ "transfer": false, "_id": "cBJueH89gNvvDKfQ", "type": "base", - "system": { - "changes": [], - "duration": { - "type": "temporary" - } - }, + "system": {}, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -98,16 +97,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!D73fS1iM4SZPFimu.cBJueH89gNvvDKfQ" } ], diff --git a/src/packs/classes/class_Bard_vegl3bFOq3pcFTWT.json b/src/packs/classes/class_Bard_vegl3bFOq3pcFTWT.json index 31288916..c4dd83a7 100644 --- a/src/packs/classes/class_Bard_vegl3bFOq3pcFTWT.json +++ b/src/packs/classes/class_Bard_vegl3bFOq3pcFTWT.json @@ -4,7 +4,7 @@ "type": "class", "img": "icons/tools/instruments/harp-red.webp", "system": { - "description": "

Bards are the most charismatic people in all the realms. Members of this class are masters of captivation and specialize in a variety of performance types, including singing, playing musical instruments, weaving tales, or telling jokes. Whether performing for an audience or speaking to an individual, bards thrive in social situations. Members of this profession bond and train at schools or guilds, but a current of egotism runs through those of the bardic persuasion. While they may be the most likely class to bring people together, a bard of ill temper can just as easily tear a party apart.

", + "description": "

Note: At level 5 use Rally (Level 5) instead of Rally under class feature. (Automation will be implemented in a later release)


Bards are the most charismatic people in all the realms. Members of this class are masters of captivation and specialize in a variety of performance types, including singing, playing musical instruments, weaving tales, or telling jokes. Whether performing for an audience or speaking to an individual, bards thrive in social situations. Members of this profession bond and train at schools or guilds, but a current of egotism runs through those of the bardic persuasion. While they may be the most likely class to bring people together, a bard of ill temper can just as easily tear a party apart.

", "domains": [ "grace", "codex" diff --git a/src/packs/classes/feature_Evolution_6rlxhrRwFaVgq9fe.json b/src/packs/classes/feature_Evolution_6rlxhrRwFaVgq9fe.json index 421063a4..46380fe8 100644 --- a/src/packs/classes/feature_Evolution_6rlxhrRwFaVgq9fe.json +++ b/src/packs/classes/feature_Evolution_6rlxhrRwFaVgq9fe.json @@ -5,7 +5,7 @@ "_id": "6rlxhrRwFaVgq9fe", "img": "icons/magic/nature/wolf-paw-glow-large-orange.webp", "system": { - "description": "

Spend 3 Hope to transform into a Beastform without marking a Stress. When you do, choose one trait to raise by +1 until you drop out of that Beastform.

", + "description": "

Spend 3 Hope to transform into a Beastform without marking a Stress. When you do, choose one trait to raise by +1 until you drop out of that Beastform.

Note: Toggle one of the Evolution Traits in the effects tab to raise a trait by 1, e.g. Evolution: Agility

", "resource": null, "actions": { "bj4m9E8ObFT0xDQ4": { @@ -31,13 +31,6 @@ "beastform": { "tierAccess": { "exact": null - }, - "modifications": { - "traitBonuses": [ - { - "bonus": 1 - } - ] } }, "name": "Beastform", @@ -53,7 +46,266 @@ "artist": "" } }, - "effects": [], + "effects": [ + { + "name": "Evolution: Agility", + "type": "base", + "system": { + "rangeDependence": { + "enabled": false, + "type": "withinRange", + "target": "hostile", + "range": "melee" + } + }, + "_id": "vQOqLZAxOltAzsVv", + "img": "icons/magic/nature/wolf-paw-glow-large-orange.webp", + "changes": [ + { + "key": "system.traits.agility.value", + "mode": 2, + "value": "1", + "priority": null + } + ], + "disabled": true, + "duration": { + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null + }, + "description": "

Toggle this for +1 to Agility when using Evolution. Turn it off when you leave Beastform.

", + "origin": null, + "tint": "#ffffff", + "transfer": true, + "statuses": [], + "sort": 0, + "flags": {}, + "_stats": { + "compendiumSource": null + }, + "_key": "!items.effects!6rlxhrRwFaVgq9fe.vQOqLZAxOltAzsVv" + }, + { + "name": "Evolution: Strength", + "type": "base", + "system": { + "rangeDependence": { + "enabled": false, + "type": "withinRange", + "target": "hostile", + "range": "melee" + } + }, + "_id": "cwEsO1NZpkQHuoTT", + "img": "icons/magic/nature/wolf-paw-glow-large-orange.webp", + "changes": [ + { + "key": "system.traits.strength.value", + "mode": 2, + "value": "1", + "priority": null + } + ], + "disabled": true, + "duration": { + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null + }, + "description": "

Toggle this for +1 to Strength when using Evolution. Turn it off when you leave Beastform.

", + "origin": null, + "tint": "#ffffff", + "transfer": true, + "statuses": [], + "sort": 0, + "flags": {}, + "_stats": { + "compendiumSource": null + }, + "_key": "!items.effects!6rlxhrRwFaVgq9fe.cwEsO1NZpkQHuoTT" + }, + { + "name": "Evolution: Finesse", + "type": "base", + "system": { + "rangeDependence": { + "enabled": false, + "type": "withinRange", + "target": "hostile", + "range": "melee" + } + }, + "_id": "8P0nwRHNsVnHVPjq", + "img": "icons/magic/nature/wolf-paw-glow-large-orange.webp", + "changes": [ + { + "key": "system.traits.finesse.value", + "mode": 2, + "value": "1", + "priority": null + } + ], + "disabled": true, + "duration": { + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null + }, + "description": "

Toggle this for +1 to Finesse when using Evolution. Turn it off when you leave Beastform.

", + "origin": null, + "tint": "#ffffff", + "transfer": true, + "statuses": [], + "sort": 0, + "flags": {}, + "_stats": { + "compendiumSource": null + }, + "_key": "!items.effects!6rlxhrRwFaVgq9fe.8P0nwRHNsVnHVPjq" + }, + { + "name": "Evolution: Instinct", + "type": "base", + "system": { + "rangeDependence": { + "enabled": false, + "type": "withinRange", + "target": "hostile", + "range": "melee" + } + }, + "_id": "i2GhNGo5TnGtLuA0", + "img": "icons/magic/nature/wolf-paw-glow-large-orange.webp", + "changes": [ + { + "key": "system.traits.instinct.value", + "mode": 2, + "value": "1", + "priority": null + } + ], + "disabled": true, + "duration": { + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null + }, + "description": "

Toggle this for +1 to Instinct when using Evolution. Turn it off when you leave Beastform.

", + "origin": null, + "tint": "#ffffff", + "transfer": true, + "statuses": [], + "sort": 0, + "flags": {}, + "_stats": { + "compendiumSource": null + }, + "_key": "!items.effects!6rlxhrRwFaVgq9fe.i2GhNGo5TnGtLuA0" + }, + { + "name": "Evolution: Presence", + "type": "base", + "system": { + "rangeDependence": { + "enabled": false, + "type": "withinRange", + "target": "hostile", + "range": "melee" + } + }, + "_id": "APQF1in1LXjBZh9n", + "img": "icons/magic/nature/wolf-paw-glow-large-orange.webp", + "changes": [ + { + "key": "system.traits.presence.value", + "mode": 2, + "value": "1", + "priority": null + } + ], + "disabled": true, + "duration": { + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null + }, + "description": "

Toggle this for +1 to Presence when using Evolution. Turn it off when you leave Beastform.

", + "origin": null, + "tint": "#ffffff", + "transfer": true, + "statuses": [], + "sort": 0, + "flags": {}, + "_stats": { + "compendiumSource": null + }, + "_key": "!items.effects!6rlxhrRwFaVgq9fe.APQF1in1LXjBZh9n" + }, + { + "name": "Evolution: Knowledge", + "type": "base", + "system": { + "rangeDependence": { + "enabled": false, + "type": "withinRange", + "target": "hostile", + "range": "melee" + } + }, + "_id": "WwOvGJYJb4d37cOy", + "img": "icons/magic/nature/wolf-paw-glow-large-orange.webp", + "changes": [ + { + "key": "system.traits.knowledge.value", + "mode": 2, + "value": "1", + "priority": null + } + ], + "disabled": true, + "duration": { + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null + }, + "description": "

Toggle this for +1 to Knowledge when using Evolution. Turn it off when you leave Beastform.

", + "origin": null, + "tint": "#ffffff", + "transfer": true, + "statuses": [], + "sort": 0, + "flags": {}, + "_stats": { + "compendiumSource": null + }, + "_key": "!items.effects!6rlxhrRwFaVgq9fe.WwOvGJYJb4d37cOy" + } + ], "sort": 100000, "ownership": { "default": 0, diff --git a/src/packs/classes/feature_Frontline_Tank_YS1g7YdWwOaS629x.json b/src/packs/classes/feature_Frontline_Tank_YS1g7YdWwOaS629x.json index 81fd08cc..7b7be61a 100644 --- a/src/packs/classes/feature_Frontline_Tank_YS1g7YdWwOaS629x.json +++ b/src/packs/classes/feature_Frontline_Tank_YS1g7YdWwOaS629x.json @@ -29,8 +29,8 @@ "recovery": null }, "damage": { - "parts": { - "armor": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -55,7 +55,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/classes/feature_Life_Support_lSlvSUHbOoX36q2j.json b/src/packs/classes/feature_Life_Support_lSlvSUHbOoX36q2j.json index b788f1f4..9c4fc450 100644 --- a/src/packs/classes/feature_Life_Support_lSlvSUHbOoX36q2j.json +++ b/src/packs/classes/feature_Life_Support_lSlvSUHbOoX36q2j.json @@ -31,8 +31,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -57,7 +57,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/classes/feature_Make_a_Scene_N9E5skDDK2VgvohR.json b/src/packs/classes/feature_Make_a_Scene_N9E5skDDK2VgvohR.json index 5f28c048..1a444728 100644 --- a/src/packs/classes/feature_Make_a_Scene_N9E5skDDK2VgvohR.json +++ b/src/packs/classes/feature_Make_a_Scene_N9E5skDDK2VgvohR.json @@ -53,7 +53,7 @@ "effects": [ { "name": "Make a Scene", - "img": "icons/magic/sonic/scream-wail-shout-teal.webp", + "img": "icons/svg/daze.svg", "origin": "Compendium.daggerheart.classes.Item.OxmucTHHfuBSv2dn", "transfer": false, "_id": "8G9zDv1gac6dEHmS", @@ -64,27 +64,27 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.difficulty", - "value": -2, - "priority": null, - "type": "add" - } - ], - "duration": { - "type": "temporary" } }, + "changes": [ + { + "key": "system.difficulty", + "mode": 2, + "value": "-2", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

Giving them a -2 penalty to their Difficulty.

", + "description": "", "tint": "#ffffff", "statuses": [], "sort": 0, @@ -92,16 +92,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!N9E5skDDK2VgvohR.8G9zDv1gac6dEHmS" } ], diff --git a/src/packs/classes/feature_Minor_Illusion_cshTYdtz9yoXYYB3.json b/src/packs/classes/feature_Minor_Illusion_cshTYdtz9yoXYYB3.json index 5f4d5fe7..fe18f68b 100644 --- a/src/packs/classes/feature_Minor_Illusion_cshTYdtz9yoXYYB3.json +++ b/src/packs/classes/feature_Minor_Illusion_cshTYdtz9yoXYYB3.json @@ -23,7 +23,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/classes/feature_No_Mercy_njj2C3tMDeCHHOoh.json b/src/packs/classes/feature_No_Mercy_njj2C3tMDeCHHOoh.json index 5b770e5d..4d10c3b9 100644 --- a/src/packs/classes/feature_No_Mercy_njj2C3tMDeCHHOoh.json +++ b/src/packs/classes/feature_No_Mercy_njj2C3tMDeCHHOoh.json @@ -67,29 +67,25 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.bonuses.roll.attack.bonus", - "type": "add", - "value": "@stacks", - "priority": null, - "phase": "initial" - } - ], - "duration": { - "type": "shortRest" - }, - "stacking": { - "max": null } }, + "changes": [ + { + "key": "system.bonuses.roll.attack.bonus", + "mode": 2, + "value": "1", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Gain a +1 bonus to your attack rolls until your next rest.

", "tint": "#ffffff", @@ -99,16 +95,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!njj2C3tMDeCHHOoh.XK4cCcz9sRGDJr0q" } ], diff --git a/src/packs/classes/feature_Rogue_s_Dodge_hVaaPIjxoextIgSL.json b/src/packs/classes/feature_Rogue_s_Dodge_hVaaPIjxoextIgSL.json index b886b079..231295fc 100644 --- a/src/packs/classes/feature_Rogue_s_Dodge_hVaaPIjxoextIgSL.json +++ b/src/packs/classes/feature_Rogue_s_Dodge_hVaaPIjxoextIgSL.json @@ -65,30 +65,25 @@ "type": "withinRange", "target": "any", "range": "self" - }, - "changes": [ - { - "key": "system.evasion", - "type": "add", - "value": "2 * @stacks", - "priority": null, - "phase": "initial" - } - ], - "duration": { - "type": "temporary", - "description": "

Until the next time an attack succeeds against you.

" - }, - "stacking": { - "max": null } }, + "changes": [ + { + "key": "system.evasion", + "mode": 2, + "value": "2", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Spend 3 Hope to gain a +2 bonus to your Evasion until the next time an attack succeeds against you. Otherwise, this bonus lasts until your next rest.

", "tint": "#ffffff", @@ -98,16 +93,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!hVaaPIjxoextIgSL.hhVjBro2osGDTT5g" } ], diff --git a/src/packs/classes/feature_Strange_Patterns_6YsfFjmCGuFYVhT4.json b/src/packs/classes/feature_Strange_Patterns_6YsfFjmCGuFYVhT4.json index 6939ff7f..953b3a2c 100644 --- a/src/packs/classes/feature_Strange_Patterns_6YsfFjmCGuFYVhT4.json +++ b/src/packs/classes/feature_Strange_Patterns_6YsfFjmCGuFYVhT4.json @@ -29,8 +29,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -55,7 +55,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -85,7 +85,7 @@ { "trigger": "dualityRoll", "triggeringActorType": "self", - "command": "/* Check if there's a Strange Pattern match */\nconst dice = [roll.dFear.total, roll.dHope.total];\nconst resource = this.parent.resource?.diceStates ? Object.values(this.parent.resource.diceStates).map(x => x.value)[0] : null;\nconst nrMatches = dice.filter(x => x === resource).length;\n\nif (!nrMatches) return;\n\n/* Create a dialog to choose Hope or Stress - or to cancel*/\nconst content = `\n
${game.i18n.format('DAGGERHEART.CONFIG.Triggers.triggerTexts.strangePatternsContentTitle', { nr: nrMatches })}
\n
${game.i18n.format('DAGGERHEART.CONFIG.Triggers.triggerTexts.strangePatternsContentSubTitle', { nr: nrMatches })}
\n
${game.i18n.localize('DAGGERHEART.CONFIG.Triggers.triggerTexts.strangePatternsActionExplanation')}
\n
\n \n \n
\n
`;\n\nconst result = await foundry.applications.api.DialogV2.input({\n classes: ['dh-style', 'two-big-buttons'],\n window: { title: this.item.name },\n content: content,\n render: (_, dialog) => {\n const hopeButton = dialog.element.querySelector('#hopeButton');\n const stressButton = dialog.element.querySelector('#stressButton');\ndialog.element.querySelector('button[type=\"submit\"]').disabled = true;\n \n const updateFunc = (event, selector, adding, clamp) => {\n const button = event.target.closest(`#${selector}Button`);\n const parent = event.target.closest('.flexrow');\n const hope = Number.parseInt(parent.querySelector('#hopeButton label').innerHTML);\n const stress = Number.parseInt(parent.querySelector('#stressButton label').innerHTML);\n const currentTotal = (Number.isNumeric(hope) ? hope : 0) + (Number.isNumeric(stress) ? stress : 0);\n if (adding && currentTotal === nrMatches) return;\n \n const current = Number.parseInt(button.querySelector('label').innerHTML);\n if (!adding && current === 0) return;\n \n const value = Number.isNumeric(current) ? adding ? current+1 : current-1 : 1;\n if (!dialog.data) dialog.data = {};\n dialog.data[selector] = clamp(value);\n button.querySelector('label').innerHTML = dialog.data[selector];\n\n event.target.closest('.dialog-form').querySelector('button[type=\"submit\"]').disabled = !adding || currentTotal < (nrMatches-1);\n \n };\n hopeButton.addEventListener('click', event => updateFunc(event, 'hope', true, x => Math.min(x, nrMatches)));\n hopeButton.addEventListener('contextmenu', event => updateFunc(event, 'hope', false, x => Math.max(x, 0)));\n stressButton.addEventListener('click', event => updateFunc(event, 'stress', true, x => Math.min(x, nrMatches)));\n stressButton.addEventListener('contextmenu', event => updateFunc(event, 'stress', false, x => Math.max(x, 0)));\n },\n ok: { callback: (_event, _result, dialog) => {\n const hope = dialog.data.hope ?? 0;\n const stress = dialog.data.stress ?? 0;\n if (!hope && !stress) return;\n\n /* Return resource update according to choices */\n const hopeUpdate = hope ? { key: 'hope', value: hope, total: -hope, enabled: true } : null;\n const stressUpdate = stress ? { key: 'stress', value: -stress, total: stress, enabled: true } : null;\n return { updates: [hopeUpdate, stressUpdate].filter(x => x) };\n }}\n});\n\nreturn result;" + "command": "/* Ignore if it's a TagTeam roll */\nconst tagTeam = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll);\nif (tagTeam.members[actor.id]) return;\n\n/* Check if there's a Strange Pattern match */\nconst dice = [roll.dFear.total, roll.dHope.total];\nconst resource = this.parent.resource?.diceStates ? Object.values(this.parent.resource.diceStates).map(x => x.value)[0] : null;\nconst nrMatches = dice.filter(x => x === resource).length;\n\nif (!nrMatches) return;\n\n/* Create a dialog to choose Hope or Stress - or to cancel*/\nconst content = `\n
${game.i18n.format('DAGGERHEART.CONFIG.Triggers.triggerTexts.strangePatternsContentTitle', { nr: nrMatches })}
\n
${game.i18n.format('DAGGERHEART.CONFIG.Triggers.triggerTexts.strangePatternsContentSubTitle', { nr: nrMatches })}
\n
${game.i18n.localize('DAGGERHEART.CONFIG.Triggers.triggerTexts.strangePatternsActionExplanation')}
\n
\n \n \n
\n
`;\n\nconst result = await foundry.applications.api.DialogV2.input({\n classes: ['dh-style', 'two-big-buttons'],\n window: { title: this.item.name },\n content: content,\n render: (_, dialog) => {\n const hopeButton = dialog.element.querySelector('#hopeButton');\n const stressButton = dialog.element.querySelector('#stressButton');\ndialog.element.querySelector('button[type=\"submit\"]').disabled = true;\n \n const updateFunc = (event, selector, adding, clamp) => {\n const button = event.target.closest(`#${selector}Button`);\n const parent = event.target.closest('.flexrow');\n const hope = Number.parseInt(parent.querySelector('#hopeButton label').innerHTML);\n const stress = Number.parseInt(parent.querySelector('#stressButton label').innerHTML);\n const currentTotal = (Number.isNumeric(hope) ? hope : 0) + (Number.isNumeric(stress) ? stress : 0);\n if (adding && currentTotal === nrMatches) return;\n \n const current = Number.parseInt(button.querySelector('label').innerHTML);\n if (!adding && current === 0) return;\n \n const value = Number.isNumeric(current) ? adding ? current+1 : current-1 : 1;\n if (!dialog.data) dialog.data = {};\n dialog.data[selector] = clamp(value);\n button.querySelector('label').innerHTML = dialog.data[selector];\n\n event.target.closest('.dialog-form').querySelector('button[type=\"submit\"]').disabled = !adding || currentTotal < (nrMatches-1);\n \n };\n hopeButton.addEventListener('click', event => updateFunc(event, 'hope', true, x => Math.min(x, nrMatches)));\n hopeButton.addEventListener('contextmenu', event => updateFunc(event, 'hope', false, x => Math.max(x, 0)));\n stressButton.addEventListener('click', event => updateFunc(event, 'stress', true, x => Math.min(x, nrMatches)));\n stressButton.addEventListener('contextmenu', event => updateFunc(event, 'stress', false, x => Math.max(x, 0)));\n },\n ok: { callback: (_event, _result, dialog) => {\n const hope = dialog.data.hope ?? 0;\n const stress = dialog.data.stress ?? 0;\n if (!hope && !stress) return;\n\n /* Return resource update according to choices */\n const hopeUpdate = hope ? { key: 'hope', value: hope, total: -hope, enabled: true } : null;\n const stressUpdate = stress ? { key: 'stress', value: -stress, total: stress, enabled: true } : null;\n return { updates: [hopeUpdate, stressUpdate].filter(x => x) };\n }}\n});\n\nreturn result;" } ] } diff --git a/src/packs/communities/feature_Low_Light_Living_aMla3xQuCHEwORGD.json b/src/packs/communities/feature_Low_Light_Living_aMla3xQuCHEwORGD.json index c95d9132..f40baa40 100644 --- a/src/packs/communities/feature_Low_Light_Living_aMla3xQuCHEwORGD.json +++ b/src/packs/communities/feature_Low_Light_Living_aMla3xQuCHEwORGD.json @@ -29,26 +29,25 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.advantageSources", - "type": "add", - "value": "Rolls to hide, investigate, or perceive details in low light", - "priority": null, - "phase": "initial" - } - ], - "duration": { - "type": "" } }, + "changes": [ + { + "key": "system.advantageSources", + "mode": 2, + "value": "Rolls to hide, investigate, or perceive details in low light", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

When you’re in an area with low light or heavy shadow, you have advantage on rolls to hide, investigate, or perceive details within that area.

", "origin": null, @@ -60,16 +59,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!aMla3xQuCHEwORGD.pCp32u7UwqxCI4WW" } ], diff --git a/src/packs/domains/domainCard_A_Soldier_s_Bond_Y08dLFuPXsgeRrHi.json b/src/packs/domains/domainCard_A_Soldier_s_Bond_Y08dLFuPXsgeRrHi.json index 09255a76..d3da85b6 100644 --- a/src/packs/domains/domainCard_A_Soldier_s_Bond_Y08dLFuPXsgeRrHi.json +++ b/src/packs/domains/domainCard_A_Soldier_s_Bond_Y08dLFuPXsgeRrHi.json @@ -25,8 +25,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -51,7 +51,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Arcane_Reflection_JzSvxy9Mu3RJp1jV.json b/src/packs/domains/domainCard_Arcane_Reflection_JzSvxy9Mu3RJp1jV.json index e557b8cd..e6d38e3f 100644 --- a/src/packs/domains/domainCard_Arcane_Reflection_JzSvxy9Mu3RJp1jV.json +++ b/src/packs/domains/domainCard_Arcane_Reflection_JzSvxy9Mu3RJp1jV.json @@ -33,7 +33,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Armorer_cy8GjBPGc9w9RaGO.json b/src/packs/domains/domainCard_Armorer_cy8GjBPGc9w9RaGO.json index cad6012e..aa9910dc 100644 --- a/src/packs/domains/domainCard_Armorer_cy8GjBPGc9w9RaGO.json +++ b/src/packs/domains/domainCard_Armorer_cy8GjBPGc9w9RaGO.json @@ -24,8 +24,8 @@ "recovery": null }, "damage": { - "parts": { - "armor": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -50,7 +50,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -92,28 +92,34 @@ "name": "Armorer", "type": "base", "system": { - "changes": [ - { - "type": "armor", - "phase": "initial", - "priority": 20, - "value": { - "max": "1", - "interaction": "active" - } - } - ] + "rangeDependence": { + "enabled": false, + "type": "withinRange", + "target": "hostile", + "range": "melee" + } }, - "_id": "tJw2JIPcT9hEMRXg", + "_id": "cED730OjuMW5haJR", "img": "icons/tools/hand/hammer-and-nail.webp", + "changes": [ + { + "key": "system.armorScore", + "mode": 2, + "value": "1", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

While you’re wearing armor, gain a +1 bonus to your Armor Score.

", + "description": "

While you’re wearing armor, gain a +1 bonus to your Armor Score.

", "origin": null, "tint": "#ffffff", "transfer": true, @@ -123,10 +129,7 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, - "_key": "!items.effects!cy8GjBPGc9w9RaGO.tJw2JIPcT9hEMRXg" + "_key": "!items.effects!cy8GjBPGc9w9RaGO.cED730OjuMW5haJR" } ], "ownership": { diff --git a/src/packs/domains/domainCard_Banish_AIbHfryMA2Rvs1ut.json b/src/packs/domains/domainCard_Banish_AIbHfryMA2Rvs1ut.json index e3c23dbf..b637a622 100644 --- a/src/packs/domains/domainCard_Banish_AIbHfryMA2Rvs1ut.json +++ b/src/packs/domains/domainCard_Banish_AIbHfryMA2Rvs1ut.json @@ -24,7 +24,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Bare_Bones_l5D9kq901JDESaXw.json b/src/packs/domains/domainCard_Bare_Bones_l5D9kq901JDESaXw.json index 7956d6eb..3b1ea76a 100644 --- a/src/packs/domains/domainCard_Bare_Bones_l5D9kq901JDESaXw.json +++ b/src/packs/domains/domainCard_Bare_Bones_l5D9kq901JDESaXw.json @@ -4,7 +4,7 @@ "type": "domainCard", "folder": "QpOL7jPbMBzH96qR", "system": { - "description": "

When you choose not to equip armor, you have a base Armor Score of 3 + your Strength and use the following as your base damage thresholds:

  • Tier 1: 9/19

  • Tier 2: 11/24

  • Tier 3: 13/31

  • Tier 4: 15/38

", + "description": "

When you choose not to equip armor, you have a base Armor Score of 3 + your Strength and use the following as your base damage thresholds:

  • Tier 1: 9/19
  • Tier 2: 11/24
  • Tier 3: 13/31
  • Tier 4: 15/38

Equip the below armor to use Bare Bones.

@UUID[Compendium.daggerheart.armors.Item.ITAjcigTcUw5pMCN]{Bare Bones}

", "domain": "valor", "recallCost": 0, "level": 1, @@ -19,63 +19,7 @@ } }, "flags": {}, - "effects": [ - { - "name": "Bare Bones", - "type": "base", - "system": { - "changes": [ - { - "type": "armor", - "phase": "initial", - "value": { - "current": 0, - "max": "3 + @system.traits.strength.value", - "interaction": "inactive", - "damageThresholds": { - "major": "9 + (@tier - 1) * 2", - "severe": "19 + (@tier - 1) * 5 + max(0, (@tier -2) * 2 )" - } - }, - "priority": 20 - } - ], - "duration": { - "type": "" - } - }, - "_id": "FCsgz7Tdsw6QUzBs", - "img": "icons/magic/control/buff-strength-muscle-damage-orange.webp", - "disabled": false, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false - }, - "description": "

You have a base Armor Score of 3 + your Strength.

", - "origin": null, - "tint": "#ffffff", - "transfer": true, - "statuses": [], - "showIcon": 1, - "folder": null, - "sort": 0, - "flags": {}, - "_stats": { - "compendiumSource": null - }, - "_key": "!items.effects!l5D9kq901JDESaXw.FCsgz7Tdsw6QUzBs" - } - ], + "effects": [], "ownership": { "default": 0, "MQSznptE5yLT7kj8": 3 diff --git a/src/packs/domains/domainCard_Battle_Cry_Ef1JsUG50LIoKx2F.json b/src/packs/domains/domainCard_Battle_Cry_Ef1JsUG50LIoKx2F.json index 1fde286d..6ca03c41 100644 --- a/src/packs/domains/domainCard_Battle_Cry_Ef1JsUG50LIoKx2F.json +++ b/src/packs/domains/domainCard_Battle_Cry_Ef1JsUG50LIoKx2F.json @@ -25,8 +25,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -51,7 +51,7 @@ }, "type": [] }, - "hope": { + { "value": { "custom": { "enabled": true, @@ -76,7 +76,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -132,27 +132,25 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.advantageSources", - "type": "add", - "value": "On Attacks", - "priority": null, - "phase": "initial" - } - ], - "duration": { - "type": "temporary", - "description": "

Until you or an ally rolls a failure with Fear.

" } }, + "changes": [ + { + "key": "system.advantageSources", + "mode": 2, + "value": "Attack Rolls", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

You gain advantage on attack rolls until you or an ally rolls a failure with Fear.

", "tint": "#ffffff", @@ -162,16 +160,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!Ef1JsUG50LIoKx2F.s7ma4TNgAvt0ZgEW" } ], diff --git a/src/packs/domains/domainCard_Battle_Hardened_NeEOghgfyDUBTwBG.json b/src/packs/domains/domainCard_Battle_Hardened_NeEOghgfyDUBTwBG.json index 852cd329..dfd0c68d 100644 --- a/src/packs/domains/domainCard_Battle_Hardened_NeEOghgfyDUBTwBG.json +++ b/src/packs/domains/domainCard_Battle_Hardened_NeEOghgfyDUBTwBG.json @@ -25,8 +25,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -51,7 +51,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Blink_Out_Qu0iA4s3Xov10Erd.json b/src/packs/domains/domainCard_Blink_Out_Qu0iA4s3Xov10Erd.json index 617bd27b..0b96d99c 100644 --- a/src/packs/domains/domainCard_Blink_Out_Qu0iA4s3Xov10Erd.json +++ b/src/packs/domains/domainCard_Blink_Out_Qu0iA4s3Xov10Erd.json @@ -33,7 +33,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Bolt_Beacon_BNevJyGk7hmN7XOY.json b/src/packs/domains/domainCard_Bolt_Beacon_BNevJyGk7hmN7XOY.json index df7d36a4..eb053b27 100644 --- a/src/packs/domains/domainCard_Bolt_Beacon_BNevJyGk7hmN7XOY.json +++ b/src/packs/domains/domainCard_Bolt_Beacon_BNevJyGk7hmN7XOY.json @@ -33,8 +33,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -58,7 +58,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -119,20 +119,20 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

Temporarily Vulnerable and glows brightly until this condition is cleared.

", + "description": "

Temporarily Vulnerable and glows brightly until this condition is cleared.

", "tint": "#ffffff", "statuses": [ "vulnerable" @@ -142,16 +142,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!BNevJyGk7hmN7XOY.veZpnhnF8NRRhKG4" } ], diff --git a/src/packs/domains/domainCard_Book_of_Ava_YtZzYBtR0yLPPA93.json b/src/packs/domains/domainCard_Book_of_Ava_YtZzYBtR0yLPPA93.json index fa247c89..4ed5bd63 100644 --- a/src/packs/domains/domainCard_Book_of_Ava_YtZzYBtR0yLPPA93.json +++ b/src/packs/domains/domainCard_Book_of_Ava_YtZzYBtR0yLPPA93.json @@ -24,8 +24,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -51,7 +51,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -105,7 +105,7 @@ }, "effects": [ { - "_id": "ptYT10JZ2WJHvFMd", + "_id": "LdcT1nrkd5ORCU4n", "onSave": false } ], @@ -131,7 +131,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -177,8 +177,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -204,7 +204,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -252,7 +252,7 @@ "img": "icons/magic/defensive/shield-barrier-glowing-triangle-blue.webp", "origin": "Compendium.daggerheart.domains.Item.YtZzYBtR0yLPPA93", "transfer": false, - "_id": "ptYT10JZ2WJHvFMd", + "_id": "LdcT1nrkd5ORCU4n", "type": "base", "system": { "rangeDependence": { @@ -260,27 +260,25 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "type": "armor", - "phase": "initial", - "priority": 20, - "value": { - "max": "1" - } - } - ], - "duration": { - "type": "shortRest" } }, + "changes": [ + { + "key": "system.armorScore", + "mode": 2, + "value": "1", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

+1 bonus to your Armor Score until your next rest, or the caster cast's Tava’s Armor again.

", "tint": "#ffffff", @@ -290,17 +288,7 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, - "_key": "!items.effects!YtZzYBtR0yLPPA93.ptYT10JZ2WJHvFMd" + "_key": "!items.effects!YtZzYBtR0yLPPA93.LdcT1nrkd5ORCU4n" } ], "ownership": { diff --git a/src/packs/domains/domainCard_Book_of_Exota_oVs2MSC6Uf5GbgEG.json b/src/packs/domains/domainCard_Book_of_Exota_oVs2MSC6Uf5GbgEG.json index d228d04b..032a2de2 100644 --- a/src/packs/domains/domainCard_Book_of_Exota_oVs2MSC6Uf5GbgEG.json +++ b/src/packs/domains/domainCard_Book_of_Exota_oVs2MSC6Uf5GbgEG.json @@ -25,7 +25,7 @@ "consumeOnSuccess": true }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -100,8 +100,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -127,7 +127,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Book_of_Grynn_R0LNheiZycZlZzV3.json b/src/packs/domains/domainCard_Book_of_Grynn_R0LNheiZycZlZzV3.json index c01cb756..05276707 100644 --- a/src/packs/domains/domainCard_Book_of_Grynn_R0LNheiZycZlZzV3.json +++ b/src/packs/domains/domainCard_Book_of_Grynn_R0LNheiZycZlZzV3.json @@ -66,7 +66,7 @@ "type": "attack", "_id": "K26kfjmTEH9zPMMO", "systemPath": "actions", - "description": "

Make a Spellcast Roll (15). On a success, create a temporary wall of magical flame between two points within Far range. All creatures in its path must choose a side to be on, and anything that subsequently passes through the wall takes 4d10+3 magic damage.

", + "description": "

Make a Spellcast Roll (15). On a success, create a temporary wall of magical flame between two points within Far range. All creatures in its path must choose a side to be on, and anything that subsequently passes through the wall takes 4d10+3 magic damage.

@Template[type:ray|range:f]

", "chatDisplay": true, "actionType": "action", "cost": [], @@ -76,8 +76,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -103,7 +103,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -133,16 +133,7 @@ }, "name": "Wall Of Flame", "img": "icons/magic/fire/barrier-wall-flame-ring-yellow.webp", - "range": "", - "areas": [ - { - "name": "Book of Grynn", - "type": "placed", - "shape": "line", - "size": "far", - "effects": [] - } - ] + "range": "" } }, "attribution": { diff --git a/src/packs/domains/domainCard_Book_of_Homet_gFMx08ogQ8hS2Obi.json b/src/packs/domains/domainCard_Book_of_Homet_gFMx08ogQ8hS2Obi.json index f6f048d1..a0102739 100644 --- a/src/packs/domains/domainCard_Book_of_Homet_gFMx08ogQ8hS2Obi.json +++ b/src/packs/domains/domainCard_Book_of_Homet_gFMx08ogQ8hS2Obi.json @@ -25,7 +25,7 @@ "consumeOnSuccess": true }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -72,7 +72,7 @@ "consumeOnSuccess": true }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Book_of_Illiat_df4iRqQzRntrF6Qw.json b/src/packs/domains/domainCard_Book_of_Illiat_df4iRqQzRntrF6Qw.json index b34fa000..5acec2fd 100644 --- a/src/packs/domains/domainCard_Book_of_Illiat_df4iRqQzRntrF6Qw.json +++ b/src/packs/domains/domainCard_Book_of_Illiat_df4iRqQzRntrF6Qw.json @@ -24,7 +24,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -82,8 +82,8 @@ "recovery": "shortRest" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -107,7 +107,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -177,18 +177,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "shortRest" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Lasts until your next rest or the caster casts Telepathy again.

", "tint": "#ffffff", @@ -198,16 +198,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!df4iRqQzRntrF6Qw.zAEaETYSOE2fmcyB" }, { @@ -223,19 +213,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until they take damage or the GM spends a Fear on their turn to clear this condition.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Asleep until they take damage or the GM spends a Fear on their turn to clear this condition.

", "tint": "#ffffff", @@ -245,16 +234,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!df4iRqQzRntrF6Qw.gfZTHSgwYSDKsePW" } ], diff --git a/src/packs/domains/domainCard_Book_of_Korvax_cWRFHJdxEZ0M1dAg.json b/src/packs/domains/domainCard_Book_of_Korvax_cWRFHJdxEZ0M1dAg.json index 3eb501e8..5bef4922 100644 --- a/src/packs/domains/domainCard_Book_of_Korvax_cWRFHJdxEZ0M1dAg.json +++ b/src/packs/domains/domainCard_Book_of_Korvax_cWRFHJdxEZ0M1dAg.json @@ -24,7 +24,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -77,7 +77,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -113,7 +113,7 @@ "type": "damage", "_id": "fb2HYD9J759nHKhV", "systemPath": "actions", - "description": "

Mark a Stress to create a temporary magical circle on the ground where you stand. All adversaries within Melee range, or who enter Melee range, take 2d12+4 magic damage and are knocked back to Very Close range.

", + "description": "

Mark a Stress to create a temporary magical circle on the ground where you stand. All adversaries within Melee range, or who enter Melee range, take 2d12+4 magic damage and are knocked back to Very Close range.

@Template[type:emanation|range:m]

", "chatDisplay": true, "actionType": "action", "cost": [ @@ -130,8 +130,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -157,7 +157,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -167,16 +167,7 @@ "effects": [], "name": "Rune Circle", "img": "icons/magic/symbols/runes-star-pentagon-blue.webp", - "range": "", - "areas": [ - { - "name": "Book of Korvax", - "type": "placed", - "shape": "emanation", - "size": "melee", - "effects": [] - } - ] + "range": "" } }, "attribution": { diff --git a/src/packs/domains/domainCard_Book_of_Norai_WtwSWXTRZa7QVvmo.json b/src/packs/domains/domainCard_Book_of_Norai_WtwSWXTRZa7QVvmo.json index 78028bab..6581cd52 100644 --- a/src/packs/domains/domainCard_Book_of_Norai_WtwSWXTRZa7QVvmo.json +++ b/src/packs/domains/domainCard_Book_of_Norai_WtwSWXTRZa7QVvmo.json @@ -24,8 +24,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -50,7 +50,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -91,7 +91,7 @@ "type": "attack", "_id": "GI2VkIcGDOjFRxpT", "systemPath": "actions", - "description": "

Make a Spellcast Roll against a target within Very Far range. On a success, hurl a sphere of fire toward them that explodes on impact.

", + "description": "

Make a Spellcast Roll against a target within Very Far range. On a success, hurl a sphere of fire toward them that explodes on impact. The target and all creatures within Very Close range of them must make a Reaction Roll (13). Targets who fail take d20+5 magic damage using your Proficiency. Targets who succeed take half damage.

@Template[type:emanation|range:vc]

", "chatDisplay": true, "actionType": "action", "cost": [], @@ -101,7 +101,34 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [ + { + "resultBased": false, + "value": { + "custom": { + "enabled": false + }, + "multiplier": "prof", + "dice": "d20", + "bonus": 5, + "flatMultiplier": 1 + }, + "applyTo": "hitPoints", + "type": [ + "magical" + ], + "base": false, + "valueAlt": { + "multiplier": "prof", + "flatMultiplier": 1, + "dice": "d6", + "bonus": null, + "custom": { + "enabled": false + } + } + } + ], "includeBase": false }, "target": { @@ -124,105 +151,14 @@ }, "useDefault": false }, - "save": { - "trait": null, - "difficulty": 13, - "damageMod": "half" - }, - "name": "Fireball - Cast", - "img": "icons/magic/fire/explosion-fireball-large-red-orange.webp", - "range": "veryFar" - }, - "HJ749c2a8WTjkSHY": { - "type": "attack", - "_id": "HJ749c2a8WTjkSHY", - "systemPath": "actions", - "baseAction": false, - "description": "

The target and all creatures within Very Close range of them must make a Reaction Roll (13). Targets who fail take d20+5 magic damage using your Proficiency. Targets who succeed take half damage.

", - "chatDisplay": true, - "originItem": { - "type": "itemCollection" - }, - "actionType": "action", - "triggers": [], - "areas": [ - { - "name": "Fireball", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ], - "cost": [], - "uses": { - "value": null, - "max": "", - "recovery": null, - "consumeOnSuccess": false - }, - "damage": { - "parts": { - "hitPoints": { - "applyTo": "hitPoints", - "resultBased": false, - "value": { - "multiplier": "prof", - "flatMultiplier": 1, - "dice": "d20", - "bonus": 5, - "custom": { - "enabled": false, - "formula": "" - } - }, - "valueAlt": { - "multiplier": "flat", - "flatMultiplier": 1, - "dice": "d6", - "bonus": null, - "custom": { - "enabled": false, - "formula": "" - } - }, - "base": false, - "type": [ - "magical" - ] - } - }, - "includeBase": false, - "direct": false - }, - "target": { - "type": "any", - "amount": null - }, - "effects": [], - "roll": { - "type": null, - "trait": null, - "difficulty": null, - "bonus": null, - "advState": "neutral", - "diceRolling": { - "multiplier": "prof", - "flatMultiplier": 1, - "dice": "d6", - "compare": null, - "treshold": null - }, - "useDefault": false - }, "save": { "trait": "agility", "difficulty": 13, "damageMod": "half" }, - "name": "Fireball - Explosion", - "range": "", - "img": "icons/magic/fire/explosion-fireball-large-red-orange.webp" + "name": "Fireball", + "img": "icons/magic/fire/explosion-fireball-large-red-orange.webp", + "range": "veryFar" } }, "attribution": { @@ -248,18 +184,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -271,16 +207,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!WtwSWXTRZa7QVvmo.iPnT02apql16Zhjf" } ], diff --git a/src/packs/domains/domainCard_Book_of_Ronin_SZMNR3uGNinJcN4N.json b/src/packs/domains/domainCard_Book_of_Ronin_SZMNR3uGNinJcN4N.json index 88bb759d..c809a8e0 100644 --- a/src/packs/domains/domainCard_Book_of_Ronin_SZMNR3uGNinJcN4N.json +++ b/src/packs/domains/domainCard_Book_of_Ronin_SZMNR3uGNinJcN4N.json @@ -24,7 +24,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -75,7 +75,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Book_of_Sitil_eq8VNqYMRHhF9xw9.json b/src/packs/domains/domainCard_Book_of_Sitil_eq8VNqYMRHhF9xw9.json index 16b7a63b..e88ccea9 100644 --- a/src/packs/domains/domainCard_Book_of_Sitil_eq8VNqYMRHhF9xw9.json +++ b/src/packs/domains/domainCard_Book_of_Sitil_eq8VNqYMRHhF9xw9.json @@ -85,7 +85,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Book_of_Tyfar_1VXzwRbvbBj5bd5V.json b/src/packs/domains/domainCard_Book_of_Tyfar_1VXzwRbvbBj5bd5V.json index 37b71b9c..4eabb038 100644 --- a/src/packs/domains/domainCard_Book_of_Tyfar_1VXzwRbvbBj5bd5V.json +++ b/src/packs/domains/domainCard_Book_of_Tyfar_1VXzwRbvbBj5bd5V.json @@ -24,8 +24,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -51,7 +51,7 @@ } } }, - "stress": { + { "value": { "custom": { "enabled": true, @@ -76,7 +76,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -144,7 +144,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Book_of_Vagras_aknDDYtN7EObv94t.json b/src/packs/domains/domainCard_Book_of_Vagras_aknDDYtN7EObv94t.json index a5764f48..eadd1550 100644 --- a/src/packs/domains/domainCard_Book_of_Vagras_aknDDYtN7EObv94t.json +++ b/src/packs/domains/domainCard_Book_of_Vagras_aknDDYtN7EObv94t.json @@ -25,7 +25,7 @@ "consumeOnSuccess": true }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -79,7 +79,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -125,7 +125,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Book_of_Vyola_VOIgm2j2Ijszwc5m.json b/src/packs/domains/domainCard_Book_of_Vyola_VOIgm2j2Ijszwc5m.json index 522a8f7c..b94cd702 100644 --- a/src/packs/domains/domainCard_Book_of_Vyola_VOIgm2j2Ijszwc5m.json +++ b/src/packs/domains/domainCard_Book_of_Vyola_VOIgm2j2Ijszwc5m.json @@ -24,7 +24,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Book_of_Yarrow_J1ovx2FpNDvPq1o6.json b/src/packs/domains/domainCard_Book_of_Yarrow_J1ovx2FpNDvPq1o6.json index 45fbc77f..2a48b31e 100644 --- a/src/packs/domains/domainCard_Book_of_Yarrow_J1ovx2FpNDvPq1o6.json +++ b/src/packs/domains/domainCard_Book_of_Yarrow_J1ovx2FpNDvPq1o6.json @@ -14,7 +14,7 @@ "type": "attack", "_id": "IxoglRervMx9YdVn", "systemPath": "actions", - "description": "

Make a Spellcast Roll (18). On a success, time temporarily slows to a halt for everyone within Far range except for you. It resumes the next time you make an action roll that targets another creature.

", + "description": "

Make a Spellcast Roll (18). On a success, time temporarily slows to a halt for everyone within Far range except for you. It resumes the next time you make an action roll that targets another creature.

@Template[type:emanation|range:f]

", "chatDisplay": true, "actionType": "action", "cost": [], @@ -24,7 +24,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -54,16 +54,7 @@ }, "name": "Timejammer", "img": "icons/magic/time/hourglass-tilted-glowing-gold.webp", - "range": "far", - "areas": [ - { - "name": "Book of Yarrow", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "far" }, "ZcQfbtGet0KQWjWS": { "type": "effect", @@ -123,25 +114,25 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.resistance.magical.immunity", - "value": 1, - "priority": null, - "type": "override" - } - ], - "duration": { - "type": "shortRest" } }, + "changes": [ + { + "key": "system.resistance.magical.immunity", + "mode": 5, + "value": "1", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Immune to magic damage until your next rest.

", "tint": "#ffffff", @@ -151,16 +142,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!J1ovx2FpNDvPq1o6.HWJYhSegVLeAa3dE" } ], diff --git a/src/packs/domains/domainCard_Chain_Lightning_0kAVO6rordCfZqYP.json b/src/packs/domains/domainCard_Chain_Lightning_0kAVO6rordCfZqYP.json index 6da2a76c..682357cc 100644 --- a/src/packs/domains/domainCard_Chain_Lightning_0kAVO6rordCfZqYP.json +++ b/src/packs/domains/domainCard_Chain_Lightning_0kAVO6rordCfZqYP.json @@ -33,8 +33,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -60,7 +60,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -90,16 +90,7 @@ }, "name": "Cast", "img": "icons/magic/lightning/bolts-forked-large-blue-yellow.webp", - "range": "close", - "areas": [ - { - "name": "Chain Lightning", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" }, "tRJNO3DVvVYwW3tt": { "type": "damage", @@ -116,8 +107,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -143,7 +134,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Champion_s_Edge_rnejRbUQsNGX1GMC.json b/src/packs/domains/domainCard_Champion_s_Edge_rnejRbUQsNGX1GMC.json index 304541e4..be639515 100644 --- a/src/packs/domains/domainCard_Champion_s_Edge_rnejRbUQsNGX1GMC.json +++ b/src/packs/domains/domainCard_Champion_s_Edge_rnejRbUQsNGX1GMC.json @@ -33,8 +33,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -59,7 +59,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -109,8 +109,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "armor": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -135,7 +135,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -185,8 +185,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -213,7 +213,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Chokehold_R5GYUalYXLLFRlNl.json b/src/packs/domains/domainCard_Chokehold_R5GYUalYXLLFRlNl.json index 73424902..587e7855 100644 --- a/src/packs/domains/domainCard_Chokehold_R5GYUalYXLLFRlNl.json +++ b/src/packs/domains/domainCard_Chokehold_R5GYUalYXLLFRlNl.json @@ -65,7 +65,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Cinder_Grasp_5EP2Lgf7ojfrc0Is.json b/src/packs/domains/domainCard_Cinder_Grasp_5EP2Lgf7ojfrc0Is.json index e3df986e..8ea51d7f 100644 --- a/src/packs/domains/domainCard_Cinder_Grasp_5EP2Lgf7ojfrc0Is.json +++ b/src/packs/domains/domainCard_Cinder_Grasp_5EP2Lgf7ojfrc0Is.json @@ -25,8 +25,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -52,7 +52,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -104,8 +104,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -131,7 +131,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -167,18 +167,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

When a creature acts while On Fire, they must take an extra 2d6 magic damage if they are still On Fire at the end of their action.

", "tint": "#ffffff", @@ -190,16 +190,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!5EP2Lgf7ojfrc0Is.HNKkaWi507whJuYN" } ], diff --git a/src/packs/domains/domainCard_Cloaking_Blast_Zhw7PtK8nMPlsOqD.json b/src/packs/domains/domainCard_Cloaking_Blast_Zhw7PtK8nMPlsOqD.json index a2a06889..67817fc1 100644 --- a/src/packs/domains/domainCard_Cloaking_Blast_Zhw7PtK8nMPlsOqD.json +++ b/src/packs/domains/domainCard_Cloaking_Blast_Zhw7PtK8nMPlsOqD.json @@ -70,19 +70,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

When you move into or within an adversary’s line of sight or make an attack, you are no longer Cloaked.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

While Cloaked, you remain unseen if you are stationary when an adversary moves to where they would normally see you. When you move into or within an adversary’s line of sight or make an attack, you are no longer Cloaked.

", "tint": "#ffffff", @@ -92,16 +91,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!Zhw7PtK8nMPlsOqD.twCBqXytmRkMz0kV" } ], diff --git a/src/packs/domains/domainCard_Confusing_Aura_R8NDiJXJWmC48WSr.json b/src/packs/domains/domainCard_Confusing_Aura_R8NDiJXJWmC48WSr.json index a261da89..859635f3 100644 --- a/src/packs/domains/domainCard_Confusing_Aura_R8NDiJXJWmC48WSr.json +++ b/src/packs/domains/domainCard_Confusing_Aura_R8NDiJXJWmC48WSr.json @@ -25,7 +25,7 @@ "consumeOnSuccess": true }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -80,7 +80,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Conjure_Swarm_rZPH0BY8Sznc9sFG.json b/src/packs/domains/domainCard_Conjure_Swarm_rZPH0BY8Sznc9sFG.json index d9e8da6d..ededde93 100644 --- a/src/packs/domains/domainCard_Conjure_Swarm_rZPH0BY8Sznc9sFG.json +++ b/src/packs/domains/domainCard_Conjure_Swarm_rZPH0BY8Sznc9sFG.json @@ -31,7 +31,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -119,8 +119,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -148,7 +148,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -178,16 +178,7 @@ }, "name": "Fire Flies: Cast", "img": "icons/creatures/invertebrates/wasp-swarm-movement.webp", - "range": "close", - "areas": [ - { - "name": "Conjure Swarm", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "attribution": { @@ -213,28 +204,31 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.rules.damageReduction.reduceSeverity.magical", - "value": 1, - "priority": null, - "type": "add" - }, - { - "key": "system.rules.damageReduction.reduceSeverity.physical", - "value": 1, - "priority": null, - "type": "add" - } - ] + } }, + "changes": [ + { + "key": "system.rules.damageReduction.reduceSeverity.magical", + "mode": 2, + "value": "1", + "priority": null + }, + { + "key": "system.rules.damageReduction.reduceSeverity.physical", + "mode": 2, + "value": "1", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -244,9 +238,6 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, "_key": "!items.effects!rZPH0BY8Sznc9sFG.dImnF8ZT2rVybiIP" } ], diff --git a/src/packs/domains/domainCard_Corrosive_Projectile_qJaSNTuDfbPVr8Lb.json b/src/packs/domains/domainCard_Corrosive_Projectile_qJaSNTuDfbPVr8Lb.json index 6a039bbf..09dff08a 100644 --- a/src/packs/domains/domainCard_Corrosive_Projectile_qJaSNTuDfbPVr8Lb.json +++ b/src/packs/domains/domainCard_Corrosive_Projectile_qJaSNTuDfbPVr8Lb.json @@ -24,8 +24,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -49,7 +49,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -127,7 +127,7 @@ "sort": 3400000, "effects": [ { - "name": "Corroded", + "name": "Corroded (1 stack)", "img": "icons/magic/acid/dissolve-bone-white.webp", "origin": "Compendium.daggerheart.domains.Item.qJaSNTuDfbPVr8Lb", "transfer": false, @@ -139,31 +139,27 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.difficulty", - "type": "add", - "value": "-@stack", - "priority": null, - "phase": "initial" - } - ], - "stacking": { - "max": null - }, - "duration": { - "type": "" } }, + "changes": [ + { + "key": "system.difficulty", + "mode": 2, + "value": "-1", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

While a target is Corroded, they gain a βˆ’1 penalty to their Difficulty for every 2 Stress you spent. This condition can stack.

", + "description": "

While a target is Corroded, they gain a βˆ’1 penalty to their Difficulty for every 2 Stress you spent. This condition can stack.

", "tint": "#ffffff", "statuses": [ "corrode" @@ -173,16 +169,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!qJaSNTuDfbPVr8Lb.zB95bjSSdVlApQnR" } ], diff --git a/src/packs/domains/domainCard_Counterspell_6dhqo1kzGxejCjHa.json b/src/packs/domains/domainCard_Counterspell_6dhqo1kzGxejCjHa.json index a8d403d8..7d3a74c9 100644 --- a/src/packs/domains/domainCard_Counterspell_6dhqo1kzGxejCjHa.json +++ b/src/packs/domains/domainCard_Counterspell_6dhqo1kzGxejCjHa.json @@ -25,7 +25,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Critical_Inspiration_ABp9pUfBS69NomTD.json b/src/packs/domains/domainCard_Critical_Inspiration_ABp9pUfBS69NomTD.json index 252878ea..c8013a14 100644 --- a/src/packs/domains/domainCard_Critical_Inspiration_ABp9pUfBS69NomTD.json +++ b/src/packs/domains/domainCard_Critical_Inspiration_ABp9pUfBS69NomTD.json @@ -24,7 +24,7 @@ "recovery": "longRest" }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Dark_Whispers_yL2qrSWmTwXVOySH.json b/src/packs/domains/domainCard_Dark_Whispers_yL2qrSWmTwXVOySH.json index 7d8ecf40..390a2526 100644 --- a/src/packs/domains/domainCard_Dark_Whispers_yL2qrSWmTwXVOySH.json +++ b/src/packs/domains/domainCard_Dark_Whispers_yL2qrSWmTwXVOySH.json @@ -31,7 +31,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Death_Grip_x0FVGE1YbfXalJiw.json b/src/packs/domains/domainCard_Death_Grip_x0FVGE1YbfXalJiw.json index d33b6bab..6e7c6b64 100644 --- a/src/packs/domains/domainCard_Death_Grip_x0FVGE1YbfXalJiw.json +++ b/src/packs/domains/domainCard_Death_Grip_x0FVGE1YbfXalJiw.json @@ -24,7 +24,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -75,8 +75,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -101,7 +101,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -152,8 +152,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -179,7 +179,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -214,16 +214,7 @@ }, "name": "Hit All Adversaries Between", "img": "icons/magic/nature/root-vine-beanstalk-moon.webp", - "range": "", - "areas": [ - { - "name": "Line To Target", - "type": "placed", - "shape": "line", - "size": "close", - "effects": [] - } - ] + "range": "" } }, "attribution": { @@ -249,15 +240,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [] + } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -269,9 +263,6 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, "_key": "!items.effects!x0FVGE1YbfXalJiw.wMXCIQxqLS9IbsEK" }, { @@ -287,15 +278,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [] + } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -307,9 +301,6 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, "_key": "!items.effects!x0FVGE1YbfXalJiw.bZ0xgZ6TT2099OYp" }, { @@ -325,15 +316,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [] + } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -345,9 +339,6 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, "_key": "!items.effects!x0FVGE1YbfXalJiw.Oe95zWWY41nH8y5l" } ], diff --git a/src/packs/domains/domainCard_Disintegration_Wave_kja5qvh4rdeDBB96.json b/src/packs/domains/domainCard_Disintegration_Wave_kja5qvh4rdeDBB96.json index 7d7ed27d..4e3c3083 100644 --- a/src/packs/domains/domainCard_Disintegration_Wave_kja5qvh4rdeDBB96.json +++ b/src/packs/domains/domainCard_Disintegration_Wave_kja5qvh4rdeDBB96.json @@ -25,7 +25,7 @@ "consumeOnSuccess": true }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Earthquake_C0qLOwSSvZ6PG3Ws.json b/src/packs/domains/domainCard_Earthquake_C0qLOwSSvZ6PG3Ws.json index 0a35c95f..57fc72db 100644 --- a/src/packs/domains/domainCard_Earthquake_C0qLOwSSvZ6PG3Ws.json +++ b/src/packs/domains/domainCard_Earthquake_C0qLOwSSvZ6PG3Ws.json @@ -34,8 +34,8 @@ "consumeOnSuccess": true }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -61,7 +61,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -123,20 +123,20 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

Temporarily Vulnerable.

", + "description": "

Temporarily Vulnerable.

", "tint": "#ffffff", "statuses": [], "sort": 0, @@ -144,16 +144,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!C0qLOwSSvZ6PG3Ws.Z31XqmGUKWYcZdMY" } ], diff --git a/src/packs/domains/domainCard_Eclipse_62Sj67PdPFzwWVe3.json b/src/packs/domains/domainCard_Eclipse_62Sj67PdPFzwWVe3.json index e2afaf66..bd080f0d 100644 --- a/src/packs/domains/domainCard_Eclipse_62Sj67PdPFzwWVe3.json +++ b/src/packs/domains/domainCard_Eclipse_62Sj67PdPFzwWVe3.json @@ -25,7 +25,7 @@ "consumeOnSuccess": true }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -60,16 +60,7 @@ }, "name": "Cast", "img": "icons/magic/nature/moon-crescent.webp", - "range": "far", - "areas": [ - { - "name": "Eclipse", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "far" }, "rvkNiqCr8N6t6KPo": { "type": "damage", @@ -85,8 +76,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -111,7 +102,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -147,22 +138,25 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.disadvantageSources", - "value": "Attacking you or an ally within this eclipse's shadow", - "priority": null, - "type": "add" - } - ] + } }, + "changes": [ + { + "key": "system.disadvantageSources", + "mode": 2, + "value": "Attacking you or an ally within this eclipse's shadow", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Attack rolls have disadvantage when targeting you or an ally within this shadow.

", "tint": "#ffffff", @@ -172,9 +166,6 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, "_key": "!items.effects!62Sj67PdPFzwWVe3.ARMcw2FtKfaYr902" } ], diff --git a/src/packs/domains/domainCard_Encore_klahWDFwihqqEhXP.json b/src/packs/domains/domainCard_Encore_klahWDFwihqqEhXP.json index fabc00e1..23358d47 100644 --- a/src/packs/domains/domainCard_Encore_klahWDFwihqqEhXP.json +++ b/src/packs/domains/domainCard_Encore_klahWDFwihqqEhXP.json @@ -24,7 +24,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Enrapture_a8lFiKX1o8T924ze.json b/src/packs/domains/domainCard_Enrapture_a8lFiKX1o8T924ze.json index 284682fa..fd27c8ce 100644 --- a/src/packs/domains/domainCard_Enrapture_a8lFiKX1o8T924ze.json +++ b/src/packs/domains/domainCard_Enrapture_a8lFiKX1o8T924ze.json @@ -24,7 +24,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -82,8 +82,8 @@ "recovery": "shortRest" }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -108,7 +108,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -144,18 +144,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

While Enraptured, a target’s attention is fixed on you, narrowing their field of view and drowning out any sound but your voice.

", "tint": "#ffffff", @@ -165,16 +165,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!a8lFiKX1o8T924ze.EYG5dLImk6GkmfRd" } ], diff --git a/src/packs/domains/domainCard_Falling_Sky_hZJp9mdkMnqKDROe.json b/src/packs/domains/domainCard_Falling_Sky_hZJp9mdkMnqKDROe.json index 2086deaa..ee36e25d 100644 --- a/src/packs/domains/domainCard_Falling_Sky_hZJp9mdkMnqKDROe.json +++ b/src/packs/domains/domainCard_Falling_Sky_hZJp9mdkMnqKDROe.json @@ -4,7 +4,7 @@ "type": "domainCard", "folder": "7Cs44YADBTmmtCw6", "system": { - "description": "

Make a Spellcast Roll against all adversaries within Far range. Mark any number of Stress to make shards of arcana rain down from above. Targets you succeed against take 1d20+2 magic damage for each Stress marked.

", + "description": "

Make a Spellcast Roll against all adversaries within Far range. Mark any number of Stress to make shards of arcana rain down from above. Targets you succeed against take 1d20+2 magic damage for each Stress marked.

@Template[type:emanation|range:f]

", "domain": "arcana", "recallCost": 1, "level": 10, @@ -14,7 +14,7 @@ "type": "attack", "_id": "xJfXJDVsBayGaqkr", "systemPath": "actions", - "description": "", + "description": "

Make a Spellcast Roll against all adversaries within Far range. Mark any number of Stress to make shards of arcana rain down from above. Targets you succeed against take 1d20+2 magic damage for each Stress marked.

@Template[type:emanation|range:f]

", "chatDisplay": true, "actionType": "action", "cost": [ @@ -33,8 +33,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -59,7 +59,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -89,16 +89,7 @@ }, "name": "Attack", "img": "icons/magic/light/projectiles-star-purple.webp", - "range": "", - "areas": [ - { - "name": "Falling Sky", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "" } }, "attribution": { diff --git a/src/packs/domains/domainCard_Final_Words_Nbw6Jnh1vRZzwHQI.json b/src/packs/domains/domainCard_Final_Words_Nbw6Jnh1vRZzwHQI.json index 65d7dd83..757a705a 100644 --- a/src/packs/domains/domainCard_Final_Words_Nbw6Jnh1vRZzwHQI.json +++ b/src/packs/domains/domainCard_Final_Words_Nbw6Jnh1vRZzwHQI.json @@ -25,7 +25,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Flight_54GUjNuBEy7xdzMz.json b/src/packs/domains/domainCard_Flight_54GUjNuBEy7xdzMz.json index 4d1355ee..bd8744f7 100644 --- a/src/packs/domains/domainCard_Flight_54GUjNuBEy7xdzMz.json +++ b/src/packs/domains/domainCard_Flight_54GUjNuBEy7xdzMz.json @@ -25,7 +25,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Forager_06UapZuaA5S6fAKl.json b/src/packs/domains/domainCard_Forager_06UapZuaA5S6fAKl.json index e8919d6b..292961b8 100644 --- a/src/packs/domains/domainCard_Forager_06UapZuaA5S6fAKl.json +++ b/src/packs/domains/domainCard_Forager_06UapZuaA5S6fAKl.json @@ -24,8 +24,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -50,7 +50,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -91,8 +91,8 @@ "recovery": null }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -117,7 +117,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -185,8 +185,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -211,7 +211,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Forceful_Push_z8FFPhDh2SdFkFfS.json b/src/packs/domains/domainCard_Forceful_Push_z8FFPhDh2SdFkFfS.json index 3d17ab5d..d77c8777 100644 --- a/src/packs/domains/domainCard_Forceful_Push_z8FFPhDh2SdFkFfS.json +++ b/src/packs/domains/domainCard_Forceful_Push_z8FFPhDh2SdFkFfS.json @@ -69,18 +69,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -92,16 +92,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!z8FFPhDh2SdFkFfS.95oX6QYPySdyyh2v" } ], diff --git a/src/packs/domains/domainCard_Forest_Sprites_JrkUMTzaFmQNBHVm.json b/src/packs/domains/domainCard_Forest_Sprites_JrkUMTzaFmQNBHVm.json index 4fa469a6..feb095a2 100644 --- a/src/packs/domains/domainCard_Forest_Sprites_JrkUMTzaFmQNBHVm.json +++ b/src/packs/domains/domainCard_Forest_Sprites_JrkUMTzaFmQNBHVm.json @@ -32,7 +32,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Frenzy_MMl7abdGRLl7TJLO.json b/src/packs/domains/domainCard_Frenzy_MMl7abdGRLl7TJLO.json index 6666bc28..2de4be7e 100644 --- a/src/packs/domains/domainCard_Frenzy_MMl7abdGRLl7TJLO.json +++ b/src/packs/domains/domainCard_Frenzy_MMl7abdGRLl7TJLO.json @@ -62,44 +62,43 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.bonuses.damage.physical.bonus", - "value": 10, - "priority": null, - "type": "add" - }, - { - "key": "system.bonuses.damage.magical.bonus", - "value": 10, - "priority": null, - "type": "add" - }, - { - "key": "system.damageThresholds.severe", - "value": 8, - "priority": null, - "type": "add" - }, - { - "key": "system.rules.damageReduction.disabledArmor", - "value": 1, - "priority": null, - "type": "override" - } - ], - "duration": { - "type": "temporary", - "description": "

Until there are no more adversaries within sight.

" } }, + "changes": [ + { + "key": "system.bonuses.damage.physical.bonus", + "mode": 2, + "value": "10", + "priority": null + }, + { + "key": "system.bonuses.damage.magical.bonus", + "mode": 2, + "value": "10", + "priority": null + }, + { + "key": "system.damageThresholds.severe", + "mode": 2, + "value": "8", + "priority": null + }, + { + "key": "system.rules.damageReduction.disabledArmor", + "mode": 5, + "value": "1", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Once per long rest, you can go into a Frenzy until there are no more adversaries within sight.

While Frenzied, you can’t use Armor Slots, and you gain a +10 bonus to your damage rolls and a +8 bonus to your Severe damage threshold.

", "tint": "#ffffff", @@ -109,16 +108,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!MMl7abdGRLl7TJLO.1POoAgObPOWDpUco" } ], diff --git a/src/packs/domains/domainCard_Full_Surge_SgvjJfMyubZowPxS.json b/src/packs/domains/domainCard_Full_Surge_SgvjJfMyubZowPxS.json index fb0bd16d..43b4baf4 100644 --- a/src/packs/domains/domainCard_Full_Surge_SgvjJfMyubZowPxS.json +++ b/src/packs/domains/domainCard_Full_Surge_SgvjJfMyubZowPxS.json @@ -68,57 +68,57 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.traits.strength.value", - "value": 2, - "priority": null, - "type": "add" - }, - { - "key": "system.traits.agility.value", - "value": 2, - "priority": null, - "type": "add" - }, - { - "key": "system.traits.finesse.value", - "value": 2, - "priority": null, - "type": "add" - }, - { - "key": "system.traits.instinct.value", - "value": 2, - "priority": null, - "type": "add" - }, - { - "key": "system.traits.presence.value", - "value": 2, - "priority": null, - "type": "add" - }, - { - "key": "system.traits.knowledge.value", - "value": 2, - "priority": null, - "type": "add" - } - ], - "duration": { - "type": "shortRest" } }, + "changes": [ + { + "key": "system.traits.strength.value", + "mode": 2, + "value": "2", + "priority": null + }, + { + "key": "system.traits.agility.value", + "mode": 2, + "value": "2", + "priority": null + }, + { + "key": "system.traits.finesse.value", + "mode": 2, + "value": "2", + "priority": null + }, + { + "key": "system.traits.instinct.value", + "mode": 2, + "value": "2", + "priority": null + }, + { + "key": "system.traits.presence.value", + "mode": 2, + "value": "2", + "priority": null + }, + { + "key": "system.traits.knowledge.value", + "mode": 2, + "value": "2", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

Gain a +2 bonus to all of your character traits until your next rest.

", + "description": "

Gain a +2 bonus to all of your character traits until your next rest.

", "tint": "#ffffff", "statuses": [], "sort": 0, @@ -126,16 +126,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!SgvjJfMyubZowPxS.H5q5iYImr69TfZcp" } ], diff --git a/src/packs/domains/domainCard_Glancing_Blow_nCNCqSH7UgW4O3To.json b/src/packs/domains/domainCard_Glancing_Blow_nCNCqSH7UgW4O3To.json index a0766c1c..70338c03 100644 --- a/src/packs/domains/domainCard_Glancing_Blow_nCNCqSH7UgW4O3To.json +++ b/src/packs/domains/domainCard_Glancing_Blow_nCNCqSH7UgW4O3To.json @@ -33,7 +33,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Glyph_of_Nightfall_B5HXqYRJiL3xMNKT.json b/src/packs/domains/domainCard_Glyph_of_Nightfall_B5HXqYRJiL3xMNKT.json index 35100187..ef2b6df9 100644 --- a/src/packs/domains/domainCard_Glyph_of_Nightfall_B5HXqYRJiL3xMNKT.json +++ b/src/packs/domains/domainCard_Glyph_of_Nightfall_B5HXqYRJiL3xMNKT.json @@ -32,7 +32,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -41,7 +41,7 @@ }, "effects": [ { - "_id": "9avDhppIdTqAR56f", + "_id": "X2w3kRHaETs8YWLO", "onSave": false } ], @@ -82,25 +82,12 @@ "effects": [ { "name": "Glyph of Nightfall", - "img": "systems/daggerheart/assets/icons/domains/domain-card/midnight.png", + "img": "icons/magic/symbols/runes-triangle-magenta.webp", "origin": "Compendium.daggerheart.domains.Item.B5HXqYRJiL3xMNKT", "transfer": false, - "_id": "9avDhppIdTqAR56f", + "_id": "st8Ji9ZNexvw64xM", "type": "base", "system": { - "changes": [ - { - "key": "system.difficulty", - "type": "add", - "value": "-max(ORIGIN.@system.traits.knowledge.value,1)", - "priority": null, - "phase": "initial" - } - ], - "duration": { - "description": "", - "type": "temporary" - }, "rangeDependence": { "enabled": false, "type": "withinRange", @@ -108,32 +95,76 @@ "range": "melee" } }, + "changes": [ + { + "key": "system.difficulty", + "mode": 2, + "value": "-max(ORIGIN.@system.traits.knowledge.value,1)", + "priority": null + } + ], "disabled": false, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

Conjure a dark glyph upon their body that exposes their weak points, temporarily reducing the target’s Difficulty by a value equal to your Knowledge (minimum 1).

", + "description": "

Conjure a dark glyph upon their body that exposes their weak points, temporarily reducing the target’s Difficulty by a value equal to your Knowledge (minimum 1).

", "tint": "#ffffff", "statuses": [], - "showIcon": 1, - "folder": null, "sort": 0, "flags": {}, "_stats": { "compendiumSource": null }, - "_key": "!items.effects!B5HXqYRJiL3xMNKT.9avDhppIdTqAR56f" + "_key": "!items.effects!B5HXqYRJiL3xMNKT.st8Ji9ZNexvw64xM" + }, + { + "name": "Glyph of Nightfall", + "img": "icons/magic/symbols/runes-triangle-magenta.webp", + "origin": "Compendium.daggerheart.domains.Item.B5HXqYRJiL3xMNKT", + "transfer": false, + "_id": "X2w3kRHaETs8YWLO", + "type": "base", + "system": { + "rangeDependence": { + "enabled": false, + "type": "withinRange", + "target": "hostile", + "range": "melee" + } + }, + "changes": [ + { + "key": "system.difficulty", + "mode": 2, + "value": "-max(ORIGIN.@system.traits.knowledge.value,1)", + "priority": null + } + ], + "disabled": false, + "duration": { + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null + }, + "description": "

Conjure a dark glyph upon their body that exposes their weak points, temporarily reducing the target’s Difficulty by a value equal to your Knowledge (minimum 1).

", + "tint": "#ffffff", + "statuses": [], + "sort": 0, + "flags": {}, + "_stats": { + "compendiumSource": null + }, + "_key": "!items.effects!B5HXqYRJiL3xMNKT.X2w3kRHaETs8YWLO" } ], "ownership": { diff --git a/src/packs/domains/domainCard_Goad_Them_On_HufF5KzuNfEb9RTi.json b/src/packs/domains/domainCard_Goad_Them_On_HufF5KzuNfEb9RTi.json index db28b8b5..190028ed 100644 --- a/src/packs/domains/domainCard_Goad_Them_On_HufF5KzuNfEb9RTi.json +++ b/src/packs/domains/domainCard_Goad_Them_On_HufF5KzuNfEb9RTi.json @@ -24,8 +24,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -50,7 +50,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Gore_and_Glory_3zvjgZ5Od343wHzx.json b/src/packs/domains/domainCard_Gore_and_Glory_3zvjgZ5Od343wHzx.json index ff648409..8151beaa 100644 --- a/src/packs/domains/domainCard_Gore_and_Glory_3zvjgZ5Od343wHzx.json +++ b/src/packs/domains/domainCard_Gore_and_Glory_3zvjgZ5Od343wHzx.json @@ -25,8 +25,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -51,7 +51,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -93,8 +93,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -119,7 +119,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Grace_Touched_KAuNb51AwhD8KEXk.json b/src/packs/domains/domainCard_Grace_Touched_KAuNb51AwhD8KEXk.json index 2e48f07b..346a81f2 100644 --- a/src/packs/domains/domainCard_Grace_Touched_KAuNb51AwhD8KEXk.json +++ b/src/packs/domains/domainCard_Grace_Touched_KAuNb51AwhD8KEXk.json @@ -53,8 +53,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -79,7 +79,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Ground_Pound_WnGldYhJPDhx8v9X.json b/src/packs/domains/domainCard_Ground_Pound_WnGldYhJPDhx8v9X.json index 452e8f76..56387c50 100644 --- a/src/packs/domains/domainCard_Ground_Pound_WnGldYhJPDhx8v9X.json +++ b/src/packs/domains/domainCard_Ground_Pound_WnGldYhJPDhx8v9X.json @@ -4,7 +4,7 @@ "type": "domainCard", "folder": "FUzQxkv4gFc46SIs", "system": { - "description": "

Spend 2 Hope to strike the ground where you stand and make a Strength Roll against all targets within Very Close range. Targets you succeed against are thrown back to Far range and must make a Reaction Roll (17). Targets who fail take 4d10+8 damage. Targets who succeed take half damage.

", + "description": "

Spend 2 Hope to strike the ground where you stand and make a Strength Roll against all targets within Very Close range. Targets you succeed against are thrown back to Far range and must make a Reaction Roll (17). Targets who fail take 4d10+8 damage. Targets who succeed take half damage.

@Template[type:emanation|range:vc]

", "domain": "valor", "recallCost": 2, "level": 8, @@ -14,7 +14,7 @@ "type": "attack", "_id": "FOrohOCnzfdBl4sM", "systemPath": "actions", - "description": "", + "description": "

Spend 2 Hope to strike the ground where you stand and make a Strength Roll against all targets within Very Close range. Targets you succeed against are thrown back to Far range and must make a Reaction Roll (17). Targets who fail take 4d10+8 damage. Targets who succeed take half damage.

@Template[type:emanation|range:vc]

", "chatDisplay": true, "actionType": "action", "cost": [ @@ -31,8 +31,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -58,7 +58,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -88,16 +88,7 @@ }, "name": "Strike Ground", "img": "icons/magic/earth/barrier-stone-brown-green.webp", - "range": "veryClose", - "areas": [ - { - "name": "Ground Pound", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "veryClose" } }, "attribution": { diff --git a/src/packs/domains/domainCard_Healing_Field_GlRm1Dxlc0Z1b04o.json b/src/packs/domains/domainCard_Healing_Field_GlRm1Dxlc0Z1b04o.json index 8ee53c81..0f60cc32 100644 --- a/src/packs/domains/domainCard_Healing_Field_GlRm1Dxlc0Z1b04o.json +++ b/src/packs/domains/domainCard_Healing_Field_GlRm1Dxlc0Z1b04o.json @@ -33,8 +33,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -59,7 +59,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -84,16 +84,7 @@ }, "name": "Heal 1 Hit Point", "img": "icons/commodities/gems/gem-faceted-diamond-green.webp", - "range": "close", - "areas": [ - { - "name": "Healing Field", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" }, "EqamWsxO86ZjY8WV": { "type": "healing", @@ -126,8 +117,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -152,7 +143,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -177,16 +168,7 @@ }, "name": "Heal 2 Hit Points", "img": "icons/commodities/gems/gem-faceted-diamond-green.webp", - "range": "close", - "areas": [ - { - "name": "Healing Field", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "resource": { diff --git a/src/packs/domains/domainCard_Healing_Hands_WTlhnQMajc1r8i50.json b/src/packs/domains/domainCard_Healing_Hands_WTlhnQMajc1r8i50.json index c771562c..1245fc4b 100644 --- a/src/packs/domains/domainCard_Healing_Hands_WTlhnQMajc1r8i50.json +++ b/src/packs/domains/domainCard_Healing_Hands_WTlhnQMajc1r8i50.json @@ -25,7 +25,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -85,8 +85,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -111,7 +111,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -161,8 +161,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -187,7 +187,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -237,8 +237,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -263,7 +263,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -313,8 +313,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -339,7 +339,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Healing_Strike_XtSc0jIJLOoMTMYS.json b/src/packs/domains/domainCard_Healing_Strike_XtSc0jIJLOoMTMYS.json index 22f7f2c9..26fab1a9 100644 --- a/src/packs/domains/domainCard_Healing_Strike_XtSc0jIJLOoMTMYS.json +++ b/src/packs/domains/domainCard_Healing_Strike_XtSc0jIJLOoMTMYS.json @@ -33,8 +33,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -59,7 +59,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Hold_the_Line_kdFoLo3KXwn4LqTG.json b/src/packs/domains/domainCard_Hold_the_Line_kdFoLo3KXwn4LqTG.json index 263220e4..5b3c95d3 100644 --- a/src/packs/domains/domainCard_Hold_the_Line_kdFoLo3KXwn4LqTG.json +++ b/src/packs/domains/domainCard_Hold_the_Line_kdFoLo3KXwn4LqTG.json @@ -132,18 +132,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

If an adversary moves within Very Close range, they’re pulled into Melee range and Restrained.

", "tint": "#ffffff", @@ -155,16 +155,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!kdFoLo3KXwn4LqTG.WTYg0b8nE1XbnMiA" } ], diff --git a/src/packs/domains/domainCard_Hush_gwmYasmfgXZ7tFS6.json b/src/packs/domains/domainCard_Hush_gwmYasmfgXZ7tFS6.json index 28c41c7e..f49c4a83 100644 --- a/src/packs/domains/domainCard_Hush_gwmYasmfgXZ7tFS6.json +++ b/src/packs/domains/domainCard_Hush_gwmYasmfgXZ7tFS6.json @@ -32,7 +32,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -82,7 +82,45 @@ "effects": [ { "name": "Silenced", - "img": "systems/daggerheart/assets/icons/domains/domain-card/midnight.png", + "img": "icons/svg/sound-off.svg", + "origin": "Compendium.daggerheart.domains.Item.gwmYasmfgXZ7tFS6", + "transfer": false, + "_id": "5hzzPTFccUSSNHgp", + "type": "base", + "system": { + "rangeDependence": { + "enabled": false, + "type": "withinRange", + "target": "hostile", + "range": "melee" + } + }, + "changes": [], + "disabled": false, + "duration": { + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null + }, + "description": "

Auppressive magic around the target that encompasses everything within Very Close range of them and follows them as they move.Β The target and anything within the area is Silenced until the GM spends a Fear on their turn to clear this condition, you cast Hush again, or you take Major damage. While Silenced, they can’t make noise and can’t cast spells.

", + "tint": "#ffffff", + "statuses": [ + "silence" + ], + "sort": 0, + "flags": {}, + "_stats": { + "compendiumSource": null + }, + "_key": "!items.effects!gwmYasmfgXZ7tFS6.5hzzPTFccUSSNHgp" + }, + { + "name": "Silenced", + "img": "icons/svg/sound-off.svg", "origin": "Compendium.daggerheart.domains.Item.gwmYasmfgXZ7tFS6", "transfer": false, "_id": "pZ5YpjKidaj48IYF", @@ -93,21 +131,20 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until the GM spends a Fear on their turn to clear this condition, you cast Hush again, or you take Major damage.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

Suppressive magic around the target that encompasses everything within Very Close range of them and follows them as they move.Β The target and anything within the area is Silenced until the GM spends a Fear on their turn to clear this condition, you cast Hush again, or you take Major damage. While Silenced, they can’t make noise and can’t cast spells.

", + "description": "

Suppressive magic around the target that encompasses everything within Very Close range of them and follows them as they move.Β The target and anything within the area is Silenced until the GM spends a Fear on their turn to clear this condition, you cast Hush again, or you take Major damage. While Silenced, they can’t make noise and can’t cast spells.

", "tint": "#ffffff", "statuses": [], "sort": 0, @@ -115,16 +152,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!gwmYasmfgXZ7tFS6.pZ5YpjKidaj48IYF" } ], diff --git a/src/packs/domains/domainCard_Hypnotic_Shimmer_2ZeuCGVatQdPOVC6.json b/src/packs/domains/domainCard_Hypnotic_Shimmer_2ZeuCGVatQdPOVC6.json index 08f0d3ee..67310781 100644 --- a/src/packs/domains/domainCard_Hypnotic_Shimmer_2ZeuCGVatQdPOVC6.json +++ b/src/packs/domains/domainCard_Hypnotic_Shimmer_2ZeuCGVatQdPOVC6.json @@ -14,7 +14,7 @@ "type": "attack", "_id": "kLMAuyZktmohOSXa", "systemPath": "actions", - "description": "

Make a Spellcast Roll against all adversaries in front of you within Close range. Once per rest on a success, create an illusion of flashing colors and lights that temporarily Stuns targets you succeed against and forces them to mark a Stress. While Stunned, they can’t use reactions and can’t take any other actions until they clear this condition.

", + "description": "

Make a Spellcast Roll against all adversaries in front of you within Close range. Once per rest on a success, create an illusion of flashing colors and lights that temporarily Stuns targets you succeed against and forces them to mark a Stress. While Stunned, they can’t use reactions and can’t take any other actions until they clear this condition.

@Template[type:infront|range:c]

", "chatDisplay": true, "actionType": "action", "cost": [], @@ -25,8 +25,8 @@ "consumeOnSuccess": true }, "damage": { - "parts": { - "stress": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -51,7 +51,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -86,16 +86,7 @@ }, "name": "Cast", "img": "icons/magic/control/hypnosis-mesmerism-swirl.webp", - "range": "close", - "areas": [ - { - "name": "Hypnotic Shimmer", - "type": "placed", - "shape": "inFront", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "attribution": { @@ -121,20 +112,20 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

An illusion of flashing colors and lights that temporarily Stuns targets. While Stunned, they can’t use reactions and can’t take any other actions until they clear this condition.

", + "description": "

An illusion of flashing colors and lights that temporarily Stuns targets. While Stunned, they can’t use reactions and can’t take any other actions until they clear this condition.

", "tint": "#ffffff", "statuses": [ "stun" @@ -144,16 +135,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!2ZeuCGVatQdPOVC6.xAG75UWUz3aDZH3m" } ], diff --git a/src/packs/domains/domainCard_I_See_It_Coming_Kp6RejHGimnuoBom.json b/src/packs/domains/domainCard_I_See_It_Coming_Kp6RejHGimnuoBom.json index 5fa005b6..8d5f6536 100644 --- a/src/packs/domains/domainCard_I_See_It_Coming_Kp6RejHGimnuoBom.json +++ b/src/packs/domains/domainCard_I_See_It_Coming_Kp6RejHGimnuoBom.json @@ -33,7 +33,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Inspirational_Words_cWu1o82ZF7GvnbXc.json b/src/packs/domains/domainCard_Inspirational_Words_cWu1o82ZF7GvnbXc.json index b1f15298..0c28d499 100644 --- a/src/packs/domains/domainCard_Inspirational_Words_cWu1o82ZF7GvnbXc.json +++ b/src/packs/domains/domainCard_Inspirational_Words_cWu1o82ZF7GvnbXc.json @@ -41,8 +41,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -67,7 +67,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -117,8 +117,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -143,7 +143,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -193,8 +193,8 @@ "recovery": null }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -219,7 +219,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Invigoration_X8OfkEoI5gLTRf1B.json b/src/packs/domains/domainCard_Invigoration_X8OfkEoI5gLTRf1B.json index e3c5436c..658e12fd 100644 --- a/src/packs/domains/domainCard_Invigoration_X8OfkEoI5gLTRf1B.json +++ b/src/packs/domains/domainCard_Invigoration_X8OfkEoI5gLTRf1B.json @@ -33,7 +33,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Invisibility_KHkzA4Zrw8EWN1CH.json b/src/packs/domains/domainCard_Invisibility_KHkzA4Zrw8EWN1CH.json index 5f67ff74..be46b1c3 100644 --- a/src/packs/domains/domainCard_Invisibility_KHkzA4Zrw8EWN1CH.json +++ b/src/packs/domains/domainCard_Invisibility_KHkzA4Zrw8EWN1CH.json @@ -32,7 +32,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Know_Thy_Enemy_O38MQMhJWdZnXi6b.json b/src/packs/domains/domainCard_Know_Thy_Enemy_O38MQMhJWdZnXi6b.json index 44885c23..12308e6b 100644 --- a/src/packs/domains/domainCard_Know_Thy_Enemy_O38MQMhJWdZnXi6b.json +++ b/src/packs/domains/domainCard_Know_Thy_Enemy_O38MQMhJWdZnXi6b.json @@ -33,7 +33,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Lean_on_Me_BdePs1ZWpZTZvY1Z.json b/src/packs/domains/domainCard_Lean_on_Me_BdePs1ZWpZTZvY1Z.json index ae8c5b82..883e2522 100644 --- a/src/packs/domains/domainCard_Lean_on_Me_BdePs1ZWpZTZvY1Z.json +++ b/src/packs/domains/domainCard_Lean_on_Me_BdePs1ZWpZTZvY1Z.json @@ -24,8 +24,8 @@ "recovery": "longRest" }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -50,7 +50,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Life_Ward_OszbCj0jTqq2ADx9.json b/src/packs/domains/domainCard_Life_Ward_OszbCj0jTqq2ADx9.json index de841ffe..19a6fda6 100644 --- a/src/packs/domains/domainCard_Life_Ward_OszbCj0jTqq2ADx9.json +++ b/src/packs/domains/domainCard_Life_Ward_OszbCj0jTqq2ADx9.json @@ -70,18 +70,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "longRest" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Marked with a glowing sigil of protection. When this ally would make a death move, they clear a Hit Point instead.

This effect ends when it saves the target from a death move, you cast Life Ward on another target, or you take a long rest.

", "tint": "#ffffff", @@ -91,16 +91,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!OszbCj0jTqq2ADx9.E7Ou4OMEy3TeK1Gf" } ], diff --git a/src/packs/domains/domainCard_Manifest_Wall_TtGOtWkbr23VhHfH.json b/src/packs/domains/domainCard_Manifest_Wall_TtGOtWkbr23VhHfH.json index cde6cdc8..6e4b4654 100644 --- a/src/packs/domains/domainCard_Manifest_Wall_TtGOtWkbr23VhHfH.json +++ b/src/packs/domains/domainCard_Manifest_Wall_TtGOtWkbr23VhHfH.json @@ -4,7 +4,7 @@ "type": "domainCard", "folder": "pDtffkb0SMv1O8pL", "system": { - "description": "

Make a Spellcast Roll (15). Once per rest on a success, spend a Hope to create a temporary magical wall between two points within Far range. It can be up to 50 feet high and form at any angle. Creatures or objects in its path are shunted to a side of your choice. The wall stays up until your next rest or you cast Manifest Wall again.

", + "description": "

Make a Spellcast Roll (15). Once per rest on a success, spend a Hope to create a temporary magical wall between two points within Far range. It can be up to 50 feet high and form at any angle. Creatures or objects in its path are shunted to a side of your choice. The wall stays up until your next rest or you cast Manifest Wall again.

@Template[type:ray|range:f]

", "domain": "codex", "recallCost": 2, "level": 5, @@ -14,7 +14,7 @@ "type": "attack", "_id": "nFzMCrW7wuXCCmJW", "systemPath": "actions", - "description": "", + "description": "

Make a Spellcast Roll (15). Once per rest on a success, spend a Hope to create a temporary magical wall between two points within Far range. It can be up to 50 feet high and form at any angle. Creatures or objects in its path are shunted to a side of your choice. The wall stays up until your next rest or you cast Manifest Wall again.

@Template[type:ray|range:f]

", "chatDisplay": true, "actionType": "action", "cost": [ @@ -33,7 +33,7 @@ "consumeOnSuccess": true }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -63,16 +63,7 @@ }, "name": "Spend Hope", "img": "icons/magic/symbols/ring-circle-smoke-blue.webp", - "range": "", - "areas": [ - { - "name": "Manifest Wall", - "type": "placed", - "shape": "line", - "size": "far", - "effects": [] - } - ] + "range": "" } }, "attribution": { diff --git a/src/packs/domains/domainCard_Mass_Enrapture_ubpixIgZrJXKyM3b.json b/src/packs/domains/domainCard_Mass_Enrapture_ubpixIgZrJXKyM3b.json index 8ada8d80..da64f16e 100644 --- a/src/packs/domains/domainCard_Mass_Enrapture_ubpixIgZrJXKyM3b.json +++ b/src/packs/domains/domainCard_Mass_Enrapture_ubpixIgZrJXKyM3b.json @@ -4,7 +4,7 @@ "type": "domainCard", "folder": "7O1tTswJMNdPgLsx", "system": { - "description": "

Make a Spellcast Roll against all targets within Far range. Targets you succeed against become temporarily Enraptured. While Enraptured, a target’s attention is fixed on you, narrowing their field of view and drowning out any sound but your voice. Mark a Stress to force all Enraptured targets to mark a Stress, ending this spell.

", + "description": "

Make a Spellcast Roll against all targets within Far range. Targets you succeed against become temporarily Enraptured. While Enraptured, a target’s attention is fixed on you, narrowing their field of view and drowning out any sound but your voice. Mark a Stress to force all Enraptured targets to mark a Stress, ending this spell.

@Template[type:emanation|range:f]

", "domain": "grace", "recallCost": 3, "level": 8, @@ -14,7 +14,7 @@ "type": "attack", "_id": "r5eA3tAH7EplOQCP", "systemPath": "actions", - "description": "", + "description": "

Make a Spellcast Roll against all targets within Far range. Targets you succeed against become temporarily Enraptured. While Enraptured, a target’s attention is fixed on you, narrowing their field of view and drowning out any sound but your voice. Mark a Stress to force all Enraptured targets to mark a Stress, ending this spell.

@Template[type:emanation|range:f]

", "chatDisplay": true, "actionType": "action", "cost": [], @@ -24,7 +24,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -59,16 +59,7 @@ }, "name": "Enrapture", "img": "icons/magic/control/hypnosis-mesmerism-eye.webp", - "range": "far", - "areas": [ - { - "name": "Mass Enrapture", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "far" }, "QhBaM0LU9tmSI3IO": { "type": "damage", @@ -91,8 +82,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -117,7 +108,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -153,20 +144,20 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

While Enraptured, a target’s attention is fixed on you, narrowing their field of view and drowning out any sound but your voice.

", + "description": "

While Enraptured, a target’s attention is fixed on you, narrowing their field of view and drowning out any sound but your voice.

", "tint": "#ffffff", "statuses": [], "sort": 0, @@ -174,16 +165,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!ubpixIgZrJXKyM3b.QNbnelRylVB0yCm0" } ], diff --git a/src/packs/domains/domainCard_Mending_Touch_TGjR4vJVNbQRV8zr.json b/src/packs/domains/domainCard_Mending_Touch_TGjR4vJVNbQRV8zr.json index 60367dcc..4cb8c2a2 100644 --- a/src/packs/domains/domainCard_Mending_Touch_TGjR4vJVNbQRV8zr.json +++ b/src/packs/domains/domainCard_Mending_Touch_TGjR4vJVNbQRV8zr.json @@ -33,8 +33,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -59,7 +59,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -109,8 +109,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -135,7 +135,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -194,8 +194,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -220,7 +220,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -279,8 +279,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -305,7 +305,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Midnight_Spirit_FXLsB3QbQvTtqX5B.json b/src/packs/domains/domainCard_Midnight_Spirit_FXLsB3QbQvTtqX5B.json index f951054e..f97fe53d 100644 --- a/src/packs/domains/domainCard_Midnight_Spirit_FXLsB3QbQvTtqX5B.json +++ b/src/packs/domains/domainCard_Midnight_Spirit_FXLsB3QbQvTtqX5B.json @@ -60,8 +60,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -87,7 +87,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Midnight_Touched_uSyGKVxOJcnp28po.json b/src/packs/domains/domainCard_Midnight_Touched_uSyGKVxOJcnp28po.json index b859aafb..10c42418 100644 --- a/src/packs/domains/domainCard_Midnight_Touched_uSyGKVxOJcnp28po.json +++ b/src/packs/domains/domainCard_Midnight_Touched_uSyGKVxOJcnp28po.json @@ -24,8 +24,8 @@ "recovery": "shortRest" }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -50,7 +50,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Natural_Familiar_Tag303LoRNC5zGgl.json b/src/packs/domains/domainCard_Natural_Familiar_Tag303LoRNC5zGgl.json index c14116d4..7aa85b0f 100644 --- a/src/packs/domains/domainCard_Natural_Familiar_Tag303LoRNC5zGgl.json +++ b/src/packs/domains/domainCard_Natural_Familiar_Tag303LoRNC5zGgl.json @@ -59,7 +59,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Nature_s_Tongue_atWLorlCOxcrq8WB.json b/src/packs/domains/domainCard_Nature_s_Tongue_atWLorlCOxcrq8WB.json index b6c9464a..c722954b 100644 --- a/src/packs/domains/domainCard_Nature_s_Tongue_atWLorlCOxcrq8WB.json +++ b/src/packs/domains/domainCard_Nature_s_Tongue_atWLorlCOxcrq8WB.json @@ -24,7 +24,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Night_Terror_zcldCuqOg3dphUVI.json b/src/packs/domains/domainCard_Night_Terror_zcldCuqOg3dphUVI.json index 8eefeec4..6ffddbe7 100644 --- a/src/packs/domains/domainCard_Night_Terror_zcldCuqOg3dphUVI.json +++ b/src/packs/domains/domainCard_Night_Terror_zcldCuqOg3dphUVI.json @@ -4,7 +4,7 @@ "type": "domainCard", "folder": "2rqOUxEglhhPKk2j", "system": { - "description": "

Once per long rest, choose any targets within Very Close range to perceive you as a nightmarish horror. The targets must succeed on a Reaction Roll (16) or become temporarily Horrified. While Horrified, they’re Vulnerable. Steal a number of Fear from the GM equal to the number of targets that are Horrified (up to the number of Fear in the GM’s pool). Roll a number of d6s equal to the number of stolen Fear and deal the total damage to each Horrified target. Discard the stolen Fear.

", + "description": "

Once per long rest, choose any targets within Very Close range to perceive you as a nightmarish horror. The targets must succeed on a Reaction Roll (16) or become temporarily Horrified. While Horrified, they’re Vulnerable. Steal a number of Fear from the GM equal to the number of targets that are Horrified (up to the number of Fear in the GM’s pool). Roll a number of d6s equal to the number of stolen Fear and deal the total damage to each Horrified target. Discard the stolen Fear.

@Template[type:emanation|range:vc]

", "domain": "midnight", "recallCost": 2, "level": 9, @@ -14,7 +14,7 @@ "type": "attack", "_id": "e4A6GQERsn08IBby", "systemPath": "actions", - "description": "", + "description": "

Once per long rest, choose any targets within Very Close range to perceive you as a nightmarish horror. The targets must succeed on a Reaction Roll (16) or become temporarily Horrified. While Horrified, they’re Vulnerable. Steal a number of Fear from the GM equal to the number of targets that are Horrified (up to the number of Fear in the GM’s pool). Roll a number of d6s equal to the number of stolen Fear and deal the total damage to each Horrified target. Discard the stolen Fear.

@Template[type:emanation|range:vc]

", "chatDisplay": true, "actionType": "action", "cost": [], @@ -24,7 +24,7 @@ "recovery": "longRest" }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -59,16 +59,7 @@ }, "name": "Horrify", "img": "icons/creatures/magical/spirit-fear-energy-pink.webp", - "range": "veryClose", - "areas": [ - { - "name": "Night Terror", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "veryClose" }, "ELzQvftGxZigPkBH": { "type": "damage", @@ -93,8 +84,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -118,7 +109,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -155,20 +146,20 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

While Horrified, they’re Vulnerable.

", + "description": "

While Horrified, they’re Vulnerable.

", "tint": "#ffffff", "statuses": [ "vulnerable" @@ -178,16 +169,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!zcldCuqOg3dphUVI.32j3ZeNMMCk1QLlM" } ], diff --git a/src/packs/domains/domainCard_Onslaught_I7pNsQ9Yx6mRJX4V.json b/src/packs/domains/domainCard_Onslaught_I7pNsQ9Yx6mRJX4V.json index 5122ec4b..d2d7361d 100644 --- a/src/packs/domains/domainCard_Onslaught_I7pNsQ9Yx6mRJX4V.json +++ b/src/packs/domains/domainCard_Onslaught_I7pNsQ9Yx6mRJX4V.json @@ -33,7 +33,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Overwhelming_Aura_iEBLySZD9z8CLdz7.json b/src/packs/domains/domainCard_Overwhelming_Aura_iEBLySZD9z8CLdz7.json index 9aa2f5b4..cc04c9c9 100644 --- a/src/packs/domains/domainCard_Overwhelming_Aura_iEBLySZD9z8CLdz7.json +++ b/src/packs/domains/domainCard_Overwhelming_Aura_iEBLySZD9z8CLdz7.json @@ -33,7 +33,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -94,25 +94,25 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.traits.presence.value", - "value": "@cast", - "priority": 51, - "type": "override" - } - ], - "duration": { - "type": "longRest" } }, + "changes": [ + { + "key": "system.traits.presence.value", + "mode": 5, + "value": "@cast", + "priority": 51 + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Your Presence is equal to your Spellcast trait until your next long rest.
While this spell is active, an adversary must mark a Stress when they target you with an attack.

", "tint": "#ffffff", @@ -122,16 +122,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!iEBLySZD9z8CLdz7.ba9GO4NtQHYkaRR9" } ], diff --git a/src/packs/domains/domainCard_Plant_Dominion_9a6xP5pxhVvdugk9.json b/src/packs/domains/domainCard_Plant_Dominion_9a6xP5pxhVvdugk9.json index 4b4767fa..64b1e1c2 100644 --- a/src/packs/domains/domainCard_Plant_Dominion_9a6xP5pxhVvdugk9.json +++ b/src/packs/domains/domainCard_Plant_Dominion_9a6xP5pxhVvdugk9.json @@ -25,7 +25,7 @@ "consumeOnSuccess": true }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Preservation_Blast_1p1cOmbnRd5CoKBp.json b/src/packs/domains/domainCard_Preservation_Blast_1p1cOmbnRd5CoKBp.json index 5470c340..46dc2bdb 100644 --- a/src/packs/domains/domainCard_Preservation_Blast_1p1cOmbnRd5CoKBp.json +++ b/src/packs/domains/domainCard_Preservation_Blast_1p1cOmbnRd5CoKBp.json @@ -25,8 +25,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -52,7 +52,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Rage_Up_GRL0cvs96vrTDckZ.json b/src/packs/domains/domainCard_Rage_Up_GRL0cvs96vrTDckZ.json index c3493aea..6f8b481d 100644 --- a/src/packs/domains/domainCard_Rage_Up_GRL0cvs96vrTDckZ.json +++ b/src/packs/domains/domainCard_Rage_Up_GRL0cvs96vrTDckZ.json @@ -42,8 +42,44 @@ "type": "self", "amount": null }, - "name": "Mark Stress", - "img": "icons/skills/wounds/injury-face-impact-orange.webp", + "name": "Mark 1 Stress", + "img": "icons/magic/control/silhouette-aura-energy.webp", + "range": "self" + }, + "fKY9NcYBwCFwMsgV": { + "type": "effect", + "_id": "fKY9NcYBwCFwMsgV", + "systemPath": "actions", + "description": "

You can mark a Stress to gain a bonus to your damage roll equal to twice your Strength.

", + "chatDisplay": true, + "actionType": "action", + "cost": [ + { + "scalable": false, + "key": "stress", + "value": 2, + "step": null, + "consumeOnSuccess": false + } + ], + "uses": { + "value": null, + "max": "", + "recovery": null, + "consumeOnSuccess": false + }, + "effects": [ + { + "_id": "t6SIjQxB6UBUJ98f", + "onSave": false + } + ], + "target": { + "type": "self", + "amount": null + }, + "name": "Mark 2 Stress", + "img": "icons/magic/control/silhouette-aura-energy.webp", "range": "self" } }, @@ -58,8 +94,8 @@ "sort": 3400000, "effects": [ { - "name": "Rage Up", - "img": "icons/skills/wounds/injury-face-impact-orange.webp", + "name": "Rage Up (1)", + "img": "systems/daggerheart/assets/icons/domains/domain-card/blade.png", "origin": "Compendium.daggerheart.domains.Item.GRL0cvs96vrTDckZ", "transfer": false, "_id": "bq1MhcmoP6Wo5CXF", @@ -70,38 +106,33 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.bonuses.damage.magical.bonus", - "type": "add", - "value": "2*@system.traits.strength.value*@stacks", - "priority": 21, - "phase": "initial" - }, - { - "key": "system.bonuses.damage.physical.bonus", - "type": "add", - "value": "2*@system.traits.strength.value*@stacks", - "priority": 21, - "phase": "initial" - } - ], - "stacking": { - "max": 2 - }, - "duration": { - "type": "" } }, + "changes": [ + { + "key": "system.bonuses.damage.magical.bonus", + "mode": 2, + "value": "2*@system.traits.strength.value", + "priority": 21 + }, + { + "key": "system.bonuses.damage.physical.bonus", + "mode": 2, + "value": "2*@system.traits.strength.value", + "priority": 21 + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

For your next attack you have a bonus to your damage roll equal to twice your Strength.

", + "description": "", "tint": "#ffffff", "statuses": [], "sort": 0, @@ -109,16 +140,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!GRL0cvs96vrTDckZ.bq1MhcmoP6Wo5CXF" }, { @@ -134,28 +155,31 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.bonuses.damage.magical.bonus", - "value": "4*@system.traits.strength.value", - "priority": 21, - "type": "add" - }, - { - "key": "system.bonuses.damage.physical.bonus", - "value": "4*@system.traits.strength.value", - "priority": 21, - "type": "add" - } - ] + } }, + "changes": [ + { + "key": "system.bonuses.damage.magical.bonus", + "mode": 2, + "value": "4*@system.traits.strength.value", + "priority": 21 + }, + { + "key": "system.bonuses.damage.physical.bonus", + "mode": 2, + "value": "4*@system.traits.strength.value", + "priority": 21 + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -165,9 +189,6 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, "_key": "!items.effects!GRL0cvs96vrTDckZ.t6SIjQxB6UBUJ98f" } ], diff --git a/src/packs/domains/domainCard_Rain_of_Blades_Ucenef6JpjQxwXni.json b/src/packs/domains/domainCard_Rain_of_Blades_Ucenef6JpjQxwXni.json index ad41f6ec..7a5ccb1b 100644 --- a/src/packs/domains/domainCard_Rain_of_Blades_Ucenef6JpjQxwXni.json +++ b/src/packs/domains/domainCard_Rain_of_Blades_Ucenef6JpjQxwXni.json @@ -14,7 +14,7 @@ "type": "attack", "_id": "WTnjKQs2uI1TuF9r", "systemPath": "actions", - "description": "

Spend a Hope to make a Spellcast Roll and conjure throwing blades that strike out at all targets within Very Close range. Targets you succeed against take d8+2 magic damage using your Proficiency.

", + "description": "

Spend a Hope to make a Spellcast Roll and conjure throwing blades that strike out at all targets within Very Close range.Β Targets you succeed against take d8+2 magic damage using your Proficiency.

@Template[type:emanation|range:vc]

", "chatDisplay": true, "actionType": "action", "cost": [ @@ -31,12 +31,13 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { - "enabled": false + "enabled": false, + "formula": "" }, "multiplier": "prof", "dice": "d8", @@ -54,11 +55,12 @@ "dice": "d6", "bonus": null, "custom": { - "enabled": false + "enabled": false, + "formula": "" } } } - }, + ], "includeBase": false }, "target": { @@ -88,16 +90,7 @@ }, "name": "Cast", "img": "icons/skills/melee/spear-tips-three-green.webp", - "range": "veryClose", - "areas": [ - { - "name": "Rain of Blades", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "veryClose" } }, "attribution": { diff --git a/src/packs/domains/domainCard_Reaper_s_Strike_MCgNRlh0s5XUPCfl.json b/src/packs/domains/domainCard_Reaper_s_Strike_MCgNRlh0s5XUPCfl.json index 3bb8accd..f4feebbb 100644 --- a/src/packs/domains/domainCard_Reaper_s_Strike_MCgNRlh0s5XUPCfl.json +++ b/src/packs/domains/domainCard_Reaper_s_Strike_MCgNRlh0s5XUPCfl.json @@ -33,7 +33,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Redirect_faU0XkJCbar69PiN.json b/src/packs/domains/domainCard_Redirect_faU0XkJCbar69PiN.json index aeb20f1d..4adb8240 100644 --- a/src/packs/domains/domainCard_Redirect_faU0XkJCbar69PiN.json +++ b/src/packs/domains/domainCard_Redirect_faU0XkJCbar69PiN.json @@ -50,7 +50,7 @@ }, "flags": {}, "_id": "faU0XkJCbar69PiN", - "sort": 3500000, + "sort": 3400000, "effects": [], "ownership": { "default": 0 diff --git a/src/packs/domains/domainCard_Rejuvenation_Barrier_HtWx5IIemCoorMj2.json b/src/packs/domains/domainCard_Rejuvenation_Barrier_HtWx5IIemCoorMj2.json index 6d8757f7..25c991c2 100644 --- a/src/packs/domains/domainCard_Rejuvenation_Barrier_HtWx5IIemCoorMj2.json +++ b/src/packs/domains/domainCard_Rejuvenation_Barrier_HtWx5IIemCoorMj2.json @@ -4,7 +4,7 @@ "type": "domainCard", "folder": "qY4Zqc1Ch6p317uK", "system": { - "description": "

Make a Spellcast Roll (15). Once per rest on a success, create a temporary barrier of protective energy around you at Very Close range. You and all allies within the barrier when this spell is cast clear 1d4 Hit Points. While the barrier is up, you and all allies within have resistance to physical damage from outside the barrier.

When you move, the barrier follows you.

", + "description": "

Make a Spellcast Roll (15). Once per rest on a success, create a temporary barrier of protective energy around you at Very Close range. You and all allies within the barrier when this spell is cast clear 1d4 Hit Points. While the barrier is up, you and all allies within have resistance to physical damage from outside the barrier.

When you move, the barrier follows you.

@Template[type:emanation|range:vc]

", "domain": "sage", "recallCost": 1, "level": 8, @@ -14,7 +14,7 @@ "type": "healing", "_id": "XdAwXl2uWNinInFe", "systemPath": "actions", - "description": "", + "description": "

Make a Spellcast Roll (15). Once per rest on a success, create a temporary barrier of protective energy around you at Very Close range. You and all allies within the barrier when this spell is cast clear 1d4 Hit Points. While the barrier is up, you and all allies within have resistance to physical damage from outside the barrier.

When you move, the barrier follows you.

@Template[type:emanation|range:vc]

", "chatDisplay": true, "actionType": "action", "cost": [], @@ -25,8 +25,8 @@ "consumeOnSuccess": true }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -50,7 +50,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -80,16 +80,7 @@ }, "name": "Cast", "img": "icons/magic/nature/leaf-hand-green.webp", - "range": "veryClose", - "areas": [ - { - "name": "Rejuvenation Barrier", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "veryClose" } }, "attribution": { @@ -115,22 +106,25 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.resistance.physical.resistance", - "value": true, - "priority": null, - "type": "override" - } - ] + } }, + "changes": [ + { + "key": "system.resistance.physical.resistance", + "mode": 5, + "value": "true", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

While the barrier is up, the caster and all allies within have resistance to physical damage from outside the barrier. When the caster moves, the barrier follows them.

", "tint": "#ffffff", @@ -140,9 +134,6 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, "_key": "!items.effects!HtWx5IIemCoorMj2.obul9k0P4CjFuxJD" } ], diff --git a/src/packs/domains/domainCard_Restoration_wUQFsRtww18naYaq.json b/src/packs/domains/domainCard_Restoration_wUQFsRtww18naYaq.json index a83044a0..8d4d7695 100644 --- a/src/packs/domains/domainCard_Restoration_wUQFsRtww18naYaq.json +++ b/src/packs/domains/domainCard_Restoration_wUQFsRtww18naYaq.json @@ -42,8 +42,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -68,7 +68,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -119,8 +119,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -145,7 +145,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Resurrection_z30ciOwQI7g3tHla.json b/src/packs/domains/domainCard_Resurrection_z30ciOwQI7g3tHla.json index b7faa7ae..82b1b4fa 100644 --- a/src/packs/domains/domainCard_Resurrection_z30ciOwQI7g3tHla.json +++ b/src/packs/domains/domainCard_Resurrection_z30ciOwQI7g3tHla.json @@ -25,7 +25,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -72,7 +72,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Rift_Walker_vd5STqX29RpYbGxa.json b/src/packs/domains/domainCard_Rift_Walker_vd5STqX29RpYbGxa.json index 163cd293..c112e373 100644 --- a/src/packs/domains/domainCard_Rift_Walker_vd5STqX29RpYbGxa.json +++ b/src/packs/domains/domainCard_Rift_Walker_vd5STqX29RpYbGxa.json @@ -25,7 +25,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Rise_Up_oDIZoC4l19Nli0Fj.json b/src/packs/domains/domainCard_Rise_Up_oDIZoC4l19Nli0Fj.json index 5d46562d..38c900b2 100644 --- a/src/packs/domains/domainCard_Rise_Up_oDIZoC4l19Nli0Fj.json +++ b/src/packs/domains/domainCard_Rise_Up_oDIZoC4l19Nli0Fj.json @@ -24,8 +24,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -50,7 +50,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Rune_Ward_GEhBUmv9Bj7oJfHk.json b/src/packs/domains/domainCard_Rune_Ward_GEhBUmv9Bj7oJfHk.json index 01515230..54b0edbb 100644 --- a/src/packs/domains/domainCard_Rune_Ward_GEhBUmv9Bj7oJfHk.json +++ b/src/packs/domains/domainCard_Rune_Ward_GEhBUmv9Bj7oJfHk.json @@ -31,7 +31,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Salvation_Beam_4uAFGp3LxiC07woC.json b/src/packs/domains/domainCard_Salvation_Beam_4uAFGp3LxiC07woC.json index 05a62281..c7aeb02f 100644 --- a/src/packs/domains/domainCard_Salvation_Beam_4uAFGp3LxiC07woC.json +++ b/src/packs/domains/domainCard_Salvation_Beam_4uAFGp3LxiC07woC.json @@ -14,7 +14,7 @@ "type": "healing", "_id": "dmnB4ZMSk8lsB8Lg", "systemPath": "actions", - "description": "", + "description": "

Make a Spellcast Roll (16). On a success, mark any number of Stress to target a line of allies within Far range. You can clear Hit Points on the targets equal to the number of Stress marked, divided among them however you’d like.

@Template[type:ray|range:f]

", "chatDisplay": true, "actionType": "action", "cost": [ @@ -33,8 +33,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -59,7 +59,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -84,16 +84,7 @@ }, "name": "Cast", "img": "icons/magic/light/beams-rays-orange-purple-large.webp", - "range": "far", - "areas": [ - { - "name": "Salvation Beam", - "type": "placed", - "shape": "line", - "size": "far", - "effects": [] - } - ] + "range": "far" } }, "attribution": { diff --git a/src/packs/domains/domainCard_Second_Wind_ffPbSEvLuFrFsMxl.json b/src/packs/domains/domainCard_Second_Wind_ffPbSEvLuFrFsMxl.json index 764a3c87..8dc535cc 100644 --- a/src/packs/domains/domainCard_Second_Wind_ffPbSEvLuFrFsMxl.json +++ b/src/packs/domains/domainCard_Second_Wind_ffPbSEvLuFrFsMxl.json @@ -34,8 +34,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -60,7 +60,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -111,8 +111,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -137,7 +137,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Sensory_Projection_gZOMzskSOfeiXn54.json b/src/packs/domains/domainCard_Sensory_Projection_gZOMzskSOfeiXn54.json index c0aea3df..2701b0ce 100644 --- a/src/packs/domains/domainCard_Sensory_Projection_gZOMzskSOfeiXn54.json +++ b/src/packs/domains/domainCard_Sensory_Projection_gZOMzskSOfeiXn54.json @@ -25,7 +25,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Shadowbind_kguhWlidhxe2GbT0.json b/src/packs/domains/domainCard_Shadowbind_kguhWlidhxe2GbT0.json index a90ec0f7..cd906eaa 100644 --- a/src/packs/domains/domainCard_Shadowbind_kguhWlidhxe2GbT0.json +++ b/src/packs/domains/domainCard_Shadowbind_kguhWlidhxe2GbT0.json @@ -4,7 +4,7 @@ "type": "domainCard", "folder": "Abn46nCQst6kpGeA", "system": { - "description": "

Make a Spellcast Roll against all adversaries within Very Close range. Targets you succeed against are temporarily Restrained as their shadow binds them in place.

", + "description": "

Make a Spellcast Roll against all adversaries within Very Close range. Targets you succeed against are temporarily Restrained as their shadow binds them in place.

@Template[type:emanation|range:vc]

", "domain": "midnight", "recallCost": 0, "level": 2, @@ -14,7 +14,7 @@ "type": "attack", "_id": "Llr9uIDUCrfsiZNn", "systemPath": "actions", - "description": "", + "description": "

Make a Spellcast Roll against all adversaries within Very Close range. Targets you succeed against are temporarily Restrained as their shadow binds them in place.

@Template[type:emanation|range:vc]

", "chatDisplay": true, "actionType": "action", "cost": [], @@ -24,7 +24,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -59,16 +59,7 @@ }, "name": "Cast", "img": "icons/magic/control/debuff-energy-snare-blue.webp", - "range": "veryClose", - "areas": [ - { - "name": "Shadowbind", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "veryClose" } }, "attribution": { @@ -94,18 +85,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -117,16 +108,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!kguhWlidhxe2GbT0.RFB4V0V4bDJ6vCL2" } ], diff --git a/src/packs/domains/domainCard_Shrug_It_Off_JwfhtgmmuRxg4zhI.json b/src/packs/domains/domainCard_Shrug_It_Off_JwfhtgmmuRxg4zhI.json index 3e757308..7cabf19d 100644 --- a/src/packs/domains/domainCard_Shrug_It_Off_JwfhtgmmuRxg4zhI.json +++ b/src/packs/domains/domainCard_Shrug_It_Off_JwfhtgmmuRxg4zhI.json @@ -32,7 +32,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Soothing_Speech_QED2PDYePOSTbLtC.json b/src/packs/domains/domainCard_Soothing_Speech_QED2PDYePOSTbLtC.json index b7ef626d..daecba3b 100644 --- a/src/packs/domains/domainCard_Soothing_Speech_QED2PDYePOSTbLtC.json +++ b/src/packs/domains/domainCard_Soothing_Speech_QED2PDYePOSTbLtC.json @@ -24,8 +24,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -50,7 +50,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -91,8 +91,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -117,7 +117,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Splintering_Strike_TYKfM3H9vBXyWiH4.json b/src/packs/domains/domainCard_Splintering_Strike_TYKfM3H9vBXyWiH4.json index a63fd477..e36c744c 100644 --- a/src/packs/domains/domainCard_Splintering_Strike_TYKfM3H9vBXyWiH4.json +++ b/src/packs/domains/domainCard_Splintering_Strike_TYKfM3H9vBXyWiH4.json @@ -33,7 +33,7 @@ "consumeOnSuccess": true }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Stunning_Sunlight_lRHo6ZkK1zybeEoG.json b/src/packs/domains/domainCard_Stunning_Sunlight_lRHo6ZkK1zybeEoG.json index e2d68a10..6fde5d18 100644 --- a/src/packs/domains/domainCard_Stunning_Sunlight_lRHo6ZkK1zybeEoG.json +++ b/src/packs/domains/domainCard_Stunning_Sunlight_lRHo6ZkK1zybeEoG.json @@ -33,8 +33,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -60,7 +60,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -95,16 +95,7 @@ }, "name": "Cast", "img": "icons/magic/light/beam-strike-village-yellow.webp", - "range": "far", - "areas": [ - { - "name": "Stunning Sunlight", - "type": "placed", - "shape": "inFront", - "size": "far", - "effects": [] - } - ] + "range": "far" }, "AI8sGbUXLw4gG8mW": { "type": "damage", @@ -121,8 +112,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -148,7 +139,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -184,20 +175,20 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

Temporarily Stunned. While Stunned, they can’t use reactions and can’t take any other actions until they clear this condition.

", + "description": "

Temporarily Stunned. While Stunned, they can’t use reactions and can’t take any other actions until they clear this condition.

", "tint": "#ffffff", "statuses": [ "stun" @@ -207,16 +198,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!lRHo6ZkK1zybeEoG.kSLuGSI6FLhOJaGp" } ], diff --git a/src/packs/domains/domainCard_Swift_Step_H6TqCJBaa1eWEQ1z.json b/src/packs/domains/domainCard_Swift_Step_H6TqCJBaa1eWEQ1z.json index 76e9e6e9..bd153045 100644 --- a/src/packs/domains/domainCard_Swift_Step_H6TqCJBaa1eWEQ1z.json +++ b/src/packs/domains/domainCard_Swift_Step_H6TqCJBaa1eWEQ1z.json @@ -25,8 +25,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -51,7 +51,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -93,8 +93,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -119,7 +119,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Telekinesis_FgzBppvLjXr0UbUI.json b/src/packs/domains/domainCard_Telekinesis_FgzBppvLjXr0UbUI.json index 0436b1aa..f80954e7 100644 --- a/src/packs/domains/domainCard_Telekinesis_FgzBppvLjXr0UbUI.json +++ b/src/packs/domains/domainCard_Telekinesis_FgzBppvLjXr0UbUI.json @@ -25,7 +25,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -72,8 +72,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -99,7 +99,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Teleport_HnPwVrWblYa9hwSt.json b/src/packs/domains/domainCard_Teleport_HnPwVrWblYa9hwSt.json index ff262d6f..b4563eac 100644 --- a/src/packs/domains/domainCard_Teleport_HnPwVrWblYa9hwSt.json +++ b/src/packs/domains/domainCard_Teleport_HnPwVrWblYa9hwSt.json @@ -24,7 +24,7 @@ "recovery": "longRest" }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Tell_No_Lies_HTv9QEPS466WsstP.json b/src/packs/domains/domainCard_Tell_No_Lies_HTv9QEPS466WsstP.json index 1efb1374..f1056dfc 100644 --- a/src/packs/domains/domainCard_Tell_No_Lies_HTv9QEPS466WsstP.json +++ b/src/packs/domains/domainCard_Tell_No_Lies_HTv9QEPS466WsstP.json @@ -24,8 +24,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -50,7 +50,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Tempest_X7YaZgFieBlqaPdZ.json b/src/packs/domains/domainCard_Tempest_X7YaZgFieBlqaPdZ.json index e027ca8f..d82dd9fa 100644 --- a/src/packs/domains/domainCard_Tempest_X7YaZgFieBlqaPdZ.json +++ b/src/packs/domains/domainCard_Tempest_X7YaZgFieBlqaPdZ.json @@ -24,8 +24,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -51,7 +51,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -86,16 +86,7 @@ }, "name": "Blizzard", "img": "icons/magic/water/projectiles-ice-faceted-shard-salvo-blue.webp", - "range": "far", - "areas": [ - { - "name": "Tempest", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "far" }, "FEPhujGa5lvu5fXr": { "type": "attack", @@ -111,8 +102,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -138,7 +129,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -173,16 +164,7 @@ }, "name": "Hurricane", "img": "icons/magic/air/wind-tornado-cyclone-purple-blue.webp", - "range": "far", - "areas": [ - { - "name": "Tempest", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "far" }, "CzMlqo91kuTgg1As": { "type": "attack", @@ -198,8 +180,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -225,7 +207,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -260,16 +242,7 @@ }, "name": "Sandstorm", "img": "icons/magic/air/air-wave-gust-smoke-yellow.webp", - "range": "far", - "areas": [ - { - "name": "Tempest", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "far" } }, "attribution": { @@ -295,18 +268,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -318,16 +291,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!X7YaZgFieBlqaPdZ.oqPY3I9oO9J6l5Aj" }, { @@ -343,15 +306,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [] + } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Targets can’t move against the wind.

", "tint": "#ffffff", @@ -361,9 +327,6 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, "_key": "!items.effects!X7YaZgFieBlqaPdZ.tB7AyDy0pbE9q5hM" }, { @@ -379,15 +342,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [] + } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Attacks made from beyond Melee range have disadvantage.

", "tint": "#ffffff", @@ -397,9 +363,6 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, "_key": "!items.effects!X7YaZgFieBlqaPdZ.S4Vpgf3FMmq8MGrb" } ], diff --git a/src/packs/domains/domainCard_Thought_Delver_B4choj481tqajWb9.json b/src/packs/domains/domainCard_Thought_Delver_B4choj481tqajWb9.json index 7c8d6235..0dbc078d 100644 --- a/src/packs/domains/domainCard_Thought_Delver_B4choj481tqajWb9.json +++ b/src/packs/domains/domainCard_Thought_Delver_B4choj481tqajWb9.json @@ -58,7 +58,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Through_Your_Eyes_7b0mzV5QMPjVPT4o.json b/src/packs/domains/domainCard_Through_Your_Eyes_7b0mzV5QMPjVPT4o.json index 529950b5..ed01392d 100644 --- a/src/packs/domains/domainCard_Through_Your_Eyes_7b0mzV5QMPjVPT4o.json +++ b/src/packs/domains/domainCard_Through_Your_Eyes_7b0mzV5QMPjVPT4o.json @@ -61,20 +61,20 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "shortRest" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

Can see through their eyes and hear through their ears.

", + "description": "

Can see through their eyes and hear through their ears.

", "tint": "#ffffff", "statuses": [], "sort": 0, @@ -82,16 +82,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!7b0mzV5QMPjVPT4o.TCOHV7tWpunCZDxn" } ], diff --git a/src/packs/domains/domainCard_Towering_Stalk_n0P3VS1WfxvmXbB6.json b/src/packs/domains/domainCard_Towering_Stalk_n0P3VS1WfxvmXbB6.json index 70a1fbda..d7d984d1 100644 --- a/src/packs/domains/domainCard_Towering_Stalk_n0P3VS1WfxvmXbB6.json +++ b/src/packs/domains/domainCard_Towering_Stalk_n0P3VS1WfxvmXbB6.json @@ -41,8 +41,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -68,7 +68,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -98,16 +98,7 @@ }, "name": "Use as attack", "img": "icons/magic/nature/root-vine-entangled-humanoid.webp", - "range": "close", - "areas": [ - { - "name": "Towering Stalk", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" }, "I6eSBTpuYDU1nEgr": { "type": "effect", diff --git a/src/packs/domains/domainCard_Transcendent_Union_kVkoCLBXLAIifqpz.json b/src/packs/domains/domainCard_Transcendent_Union_kVkoCLBXLAIifqpz.json index 4460a5db..7d8d9bbe 100644 --- a/src/packs/domains/domainCard_Transcendent_Union_kVkoCLBXLAIifqpz.json +++ b/src/packs/domains/domainCard_Transcendent_Union_kVkoCLBXLAIifqpz.json @@ -70,18 +70,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "shortRest" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Until your next rest, when a creature connected by this union would mark Stress or Hit Points, the connected creatures can choose who marks it.

", "tint": "#ffffff", @@ -91,16 +91,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!kVkoCLBXLAIifqpz.kMcvp2QKmBP4uinB" } ], diff --git a/src/packs/domains/domainCard_Troublemaker_JrdZedm1BFKeV7Yb.json b/src/packs/domains/domainCard_Troublemaker_JrdZedm1BFKeV7Yb.json index 161c499f..9d740283 100644 --- a/src/packs/domains/domainCard_Troublemaker_JrdZedm1BFKeV7Yb.json +++ b/src/packs/domains/domainCard_Troublemaker_JrdZedm1BFKeV7Yb.json @@ -25,8 +25,8 @@ "consumeOnSuccess": true }, "damage": { - "parts": { - "stress": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -51,7 +51,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Twilight_Toll_SDjjV61TC1NceV1m.json b/src/packs/domains/domainCard_Twilight_Toll_SDjjV61TC1NceV1m.json index cc7f45c7..a6a987dd 100644 --- a/src/packs/domains/domainCard_Twilight_Toll_SDjjV61TC1NceV1m.json +++ b/src/packs/domains/domainCard_Twilight_Toll_SDjjV61TC1NceV1m.json @@ -40,8 +40,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -65,7 +65,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Unbreakable_CUIQmrPjf9VCHmwJ.json b/src/packs/domains/domainCard_Unbreakable_CUIQmrPjf9VCHmwJ.json index b822b632..e4847ee4 100644 --- a/src/packs/domains/domainCard_Unbreakable_CUIQmrPjf9VCHmwJ.json +++ b/src/packs/domains/domainCard_Unbreakable_CUIQmrPjf9VCHmwJ.json @@ -24,7 +24,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Uncanny_Disguise_TV56wSysbU5xAlOa.json b/src/packs/domains/domainCard_Uncanny_Disguise_TV56wSysbU5xAlOa.json index 62953005..46d9c472 100644 --- a/src/packs/domains/domainCard_Uncanny_Disguise_TV56wSysbU5xAlOa.json +++ b/src/packs/domains/domainCard_Uncanny_Disguise_TV56wSysbU5xAlOa.json @@ -24,7 +24,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Unleash_Chaos_o62i0QdbUDIiAhSq.json b/src/packs/domains/domainCard_Unleash_Chaos_o62i0QdbUDIiAhSq.json index 69049d01..62bd00a0 100644 --- a/src/packs/domains/domainCard_Unleash_Chaos_o62i0QdbUDIiAhSq.json +++ b/src/packs/domains/domainCard_Unleash_Chaos_o62i0QdbUDIiAhSq.json @@ -42,8 +42,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -69,7 +69,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Valor_Touched_k1AtYd3lSchIymBr.json b/src/packs/domains/domainCard_Valor_Touched_k1AtYd3lSchIymBr.json index 61c7ace8..20fe18ea 100644 --- a/src/packs/domains/domainCard_Valor_Touched_k1AtYd3lSchIymBr.json +++ b/src/packs/domains/domainCard_Valor_Touched_k1AtYd3lSchIymBr.json @@ -24,8 +24,8 @@ "recovery": null }, "damage": { - "parts": { - "armor": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -50,7 +50,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -93,25 +93,32 @@ "name": "Valor-Touched", "type": "base", "system": { - "changes": [ - { - "type": "armor", - "phase": "initial", - "priority": 20, - "value": { - "max": "1" - } - } - ] + "rangeDependence": { + "enabled": false, + "type": "withinRange", + "target": "hostile", + "range": "melee" + } }, - "_id": "Ma8Zp005QYKPWIEN", + "_id": "H9lgIqqp1imSNOv9", "img": "icons/magic/control/control-influence-rally-purple.webp", + "changes": [ + { + "key": "system.armorScore", + "mode": 2, + "value": "1", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "
  • +1 bonus to your Armor Score

  • When you mark 1 or more Hit Points without marking an Armor Slot, clear an Armor Slot.

", "origin": null, @@ -123,10 +130,7 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, - "_key": "!items.effects!k1AtYd3lSchIymBr.Ma8Zp005QYKPWIEN" + "_key": "!items.effects!k1AtYd3lSchIymBr.H9lgIqqp1imSNOv9" } ], "ownership": { diff --git a/src/packs/domains/domainCard_Veil_of_Night_gV4L5ZZmfPrEbIDh.json b/src/packs/domains/domainCard_Veil_of_Night_gV4L5ZZmfPrEbIDh.json index cff0c185..a6263afe 100644 --- a/src/packs/domains/domainCard_Veil_of_Night_gV4L5ZZmfPrEbIDh.json +++ b/src/packs/domains/domainCard_Veil_of_Night_gV4L5ZZmfPrEbIDh.json @@ -24,7 +24,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -59,16 +59,7 @@ }, "name": "Cast", "img": "icons/magic/unholy/barrier-shield-glowing-pink.webp", - "range": "self", - "areas": [ - { - "name": "Veil of Night", - "type": "placed", - "shape": "line", - "size": "far", - "effects": [] - } - ] + "range": "self" } }, "attribution": { @@ -94,22 +85,25 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.advantageSources", - "value": "Attack rolls you make through the darkness", - "priority": null, - "type": "add" - } - ] + } }, + "changes": [ + { + "key": "system.advantageSources", + "mode": 2, + "value": "Attack rolls you make through the darkness", + "priority": null + } + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -121,9 +115,6 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, "_key": "!items.effects!gV4L5ZZmfPrEbIDh.eSfBBZ7IP8qirLu7" } ], diff --git a/src/packs/domains/domainCard_Vicious_Entangle_qvpvTnkAoRn9vYO4.json b/src/packs/domains/domainCard_Vicious_Entangle_qvpvTnkAoRn9vYO4.json index 3b7358bc..dae448e9 100644 --- a/src/packs/domains/domainCard_Vicious_Entangle_qvpvTnkAoRn9vYO4.json +++ b/src/packs/domains/domainCard_Vicious_Entangle_qvpvTnkAoRn9vYO4.json @@ -24,8 +24,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -51,7 +51,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -146,18 +146,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -169,16 +169,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!qvpvTnkAoRn9vYO4.Xh0wrgRUuYpwChBU" }, { @@ -194,18 +184,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -217,16 +207,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!qvpvTnkAoRn9vYO4.2xzOqTaPJQzGqFJv" } ], diff --git a/src/packs/domains/domainCard_Whirlwind_anO0arioUy7I5zBg.json b/src/packs/domains/domainCard_Whirlwind_anO0arioUy7I5zBg.json index 610ced15..237e5736 100644 --- a/src/packs/domains/domainCard_Whirlwind_anO0arioUy7I5zBg.json +++ b/src/packs/domains/domainCard_Whirlwind_anO0arioUy7I5zBg.json @@ -4,7 +4,7 @@ "type": "domainCard", "folder": "9Xc6KzNyjDtTGZkp", "system": { - "description": "

When you make a successful attack against a target within Very Close range, you can spend a Hope to use the attack against all other targets within Very Close range. All additional adversaries you succeed against with this ability take half damage.

", + "description": "

When you make a successful attack against a target within Very Close range, you can spend a Hope to use the attack against all other targets within Very Close range. All additional adversaries you succeed against with this ability take half damage.

@Template[type:emanation|range:vc]

", "domain": "blade", "recallCost": 0, "level": 1, @@ -14,7 +14,7 @@ "type": "effect", "_id": "g9X0wRuCtAYzF576", "systemPath": "actions", - "description": "", + "description": "

When you make a successful attack against a target within Very Close range, you can spend a Hope to use the attack against all other targets within Very Close range. All additional adversaries you succeed against with this ability take half damage.

@Template[type:emanation|range:vc]

", "chatDisplay": true, "actionType": "action", "cost": [ @@ -39,16 +39,7 @@ }, "name": "Spend a Hope", "img": "icons/magic/control/buff-flight-wings-runes-purple-orange.webp", - "range": "", - "areas": [ - { - "name": "Whirlwind", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "" } }, "attribution": { diff --git a/src/packs/domains/domainCard_Wild_Fortress_9dFvcM1i3bxG3BSA.json b/src/packs/domains/domainCard_Wild_Fortress_9dFvcM1i3bxG3BSA.json index d61f914b..655f0c2b 100644 --- a/src/packs/domains/domainCard_Wild_Fortress_9dFvcM1i3bxG3BSA.json +++ b/src/packs/domains/domainCard_Wild_Fortress_9dFvcM1i3bxG3BSA.json @@ -32,7 +32,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Words_of_Discord_ZjAdi1FSNCDDHI3X.json b/src/packs/domains/domainCard_Words_of_Discord_ZjAdi1FSNCDDHI3X.json index d743f5e1..fb3c6611 100644 --- a/src/packs/domains/domainCard_Words_of_Discord_ZjAdi1FSNCDDHI3X.json +++ b/src/packs/domains/domainCard_Words_of_Discord_ZjAdi1FSNCDDHI3X.json @@ -24,8 +24,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -50,7 +50,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/domains/domainCard_Wrangle_9DwSxHoUwl8Kxj3n.json b/src/packs/domains/domainCard_Wrangle_9DwSxHoUwl8Kxj3n.json index eec2e76e..16753e1e 100644 --- a/src/packs/domains/domainCard_Wrangle_9DwSxHoUwl8Kxj3n.json +++ b/src/packs/domains/domainCard_Wrangle_9DwSxHoUwl8Kxj3n.json @@ -4,7 +4,7 @@ "type": "domainCard", "folder": "n7pgTBYSItMzCX0s", "system": { - "description": "

Make an Agility Roll against all targets within Close range. Spend a Hope to move targets you succeed against, and any willing allies within Close range, to another point within Close range.

", + "description": "

Make an Agility Roll against all targets within Close range. Spend a Hope to move targets you succeed against, and any willing allies within Close range, to another point within Close range.

@Template[type:emanation|range:c]

", "domain": "bone", "recallCost": 1, "level": 8, @@ -25,7 +25,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -55,16 +55,7 @@ }, "name": "Agility Roll", "img": "icons/skills/melee/sword-engraved-glow-purple.webp", - "range": "close", - "areas": [ - { - "name": "Wrangle", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "attribution": { diff --git a/src/packs/domains/domainCard_Zone_of_Protection_lOZaRb4fCVgQsWB5.json b/src/packs/domains/domainCard_Zone_of_Protection_lOZaRb4fCVgQsWB5.json index b9090717..5669173d 100644 --- a/src/packs/domains/domainCard_Zone_of_Protection_lOZaRb4fCVgQsWB5.json +++ b/src/packs/domains/domainCard_Zone_of_Protection_lOZaRb4fCVgQsWB5.json @@ -4,7 +4,7 @@ "type": "domainCard", "folder": "OwsbTSWzKq2WJmQN", "system": { - "description": "

Make a Spellcast Roll (16). Once per long rest on a success, choose a point within Far range and create a visible zone of protection there for all allies within Very Close range of that point. When you do, place a d6 on this card with the 1 value facing up. When an ally in this zone takes damage, they reduce it by the die’s value. You then increase the die’s value by one. When the die’s value would exceed 6, this effect ends.

", + "description": "

Make a Spellcast Roll (16). Once per long rest on a success, choose a point within Far range and create a visible zone of protection there for all allies within Very Close range of that point. When you do, place a d6 on this card with the 1 value facing up. When an ally in this zone takes damage, they reduce it by the die’s value. You then increase the die’s value by one. When the die’s value would exceed 6, this effect ends.

@Template[type:emanation|range:vc]

", "domain": "splendor", "recallCost": 2, "level": 6, @@ -25,7 +25,7 @@ "consumeOnSuccess": true }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -55,16 +55,7 @@ }, "name": "Cast", "img": "icons/magic/control/buff-flight-wings-runes-purple-orange.webp", - "range": "far", - "areas": [ - { - "name": "Zone of Protection", - "type": "placed", - "shape": "emanation", - "size": "veryClose", - "effects": [] - } - ] + "range": "far" } }, "resource": null, diff --git a/src/packs/environments/environment_Abandoned_Grove_pGEdzdLkqYtBhxnG.json b/src/packs/environments/environment_Abandoned_Grove_pGEdzdLkqYtBhxnG.json index 25340e77..c1006da4 100644 --- a/src/packs/environments/environment_Abandoned_Grove_pGEdzdLkqYtBhxnG.json +++ b/src/packs/environments/environment_Abandoned_Grove_pGEdzdLkqYtBhxnG.json @@ -52,9 +52,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/forest.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -105,7 +108,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -131,8 +134,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -171,7 +173,7 @@ "type": "attack", "_id": "47fcdhe1FDdm9rQU", "systemPath": "actions", - "description": "", + "description": "

Pick a point within the grove. All targets within Very Close range of that point must succeed on an Agility Reaction Roll or take 1d8+3 physical damage and become Restrained by barbed vines. Restrained lasts until they’re freed with a successful Finesse or Strength roll or by dealing at least 6 damage to the vines.

@Template[type:rect|range:vc]

", "chatDisplay": true, "actionType": "action", "cost": [], @@ -181,8 +183,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -208,9 +210,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -244,16 +245,7 @@ }, "name": "Roll Save", "img": "icons/magic/nature/root-vine-spiral-thorns-teal.webp", - "range": "veryClose", - "areas": [ - { - "name": "Barbed Vines", - "type": "placed", - "shape": "circle", - "size": "veryClose", - "effects": [] - } - ] + "range": "veryClose" } }, "originItemType": null, @@ -276,19 +268,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until you’re freed with a successful Finesse or Strength roll or by dealing at least 6 damage to the vines.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Restrained lasts until you’re freed with a successful Finesse or Strength roll or by dealing at least 6 damage to the vines.

", "tint": "#ffffff", @@ -300,16 +291,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!pGEdzdLkqYtBhxnG.maK5OyfrOxcjCoPt.LSeftEwgBbXXkLw3" } ], @@ -331,42 +312,7 @@ "system": { "description": "

A @UUID[Compendium.daggerheart.adversaries.Actor.8yUj2Mzvnifhxegm]{Young Dryad}, two @UUID[Compendium.daggerheart.adversaries.Actor.VtFBt9XBE0WrGGxP]{Sylvan Soldiers}, and a number of @UUID[Compendium.daggerheart.adversaries.Actor.G62k4oSkhkoXEs2D]{Minor Treants} equal to the number of PCs appear to confront the party for their intrusion.

What are the grove guardians concealing? What threat to the forest could the PCs confront to appease the Dryad?

", "resource": null, - "actions": { - "TPm6rpKA4mbili82": { - "type": "summon", - "_id": "TPm6rpKA4mbili82", - "systemPath": "actions", - "baseAction": false, - "description": "", - "chatDisplay": true, - "originItem": { - "type": "itemCollection" - }, - "actionType": "action", - "triggers": [], - "cost": [], - "uses": { - "value": null, - "max": null, - "recovery": null, - "consumeOnSuccess": false - }, - "summon": [ - { - "actorUUID": "Compendium.daggerheart.adversaries.Actor.8yUj2Mzvnifhxegm", - "count": "1" - }, - { - "actorUUID": "Compendium.daggerheart.adversaries.Actor.VtFBt9XBE0WrGGxP", - "count": "2" - }, - { - "actorUUID": "Compendium.daggerheart.adversaries.Actor.G62k4oSkhkoXEs2D", - "count": "@partySize" - } - ] - } - }, + "actions": {}, "originItemType": null, "originId": null, "featureForm": "action" diff --git a/src/packs/environments/environment_Ambushed_uGEdNYERCTJBEjc5.json b/src/packs/environments/environment_Ambushed_uGEdNYERCTJBEjc5.json index ea1a158c..b0ccd435 100644 --- a/src/packs/environments/environment_Ambushed_uGEdNYERCTJBEjc5.json +++ b/src/packs/environments/environment_Ambushed_uGEdNYERCTJBEjc5.json @@ -166,8 +166,8 @@ "recovery": null }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -192,7 +192,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/environments/environment_Burning_Heart_of_the_Woods_oY69NN4rYxoRE4hl.json b/src/packs/environments/environment_Burning_Heart_of_the_Woods_oY69NN4rYxoRE4hl.json index 86d3eff4..ea4f1951 100644 --- a/src/packs/environments/environment_Burning_Heart_of_the_Woods_oY69NN4rYxoRE4hl.json +++ b/src/packs/environments/environment_Burning_Heart_of_the_Woods_oY69NN4rYxoRE4hl.json @@ -57,9 +57,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/forest.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -110,7 +113,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -136,8 +139,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -211,7 +213,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -269,41 +271,30 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until you break free with a successful Finesse or Strength Roll or by dealing 10 damage to the vines.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

Restrained and Vulnerable until you break free, clearing both conditions, with a successful Finesse or Strength Roll or by dealing 10 damage to the vines. When the target makes a roll to escape, they take 1d8+4 physical damage and lose a Hope.

What painful memories do the vines bring to the surface as they pierce flesh?

", + "description": "

Restrained and Vulnerable until you break free, clearing both conditions, with a successful Finesse or Strength Roll or by dealing 10 damage to the vines. When the target makes a roll to escape, they take 1d8+4 physical damage and lose a Hope.

What painful memories do the vines bring to the surface as they pierce flesh?

", "tint": "#ffffff", "statuses": [ - "vulnerable", - "restrained" + "restrained", + "vulnerable" ], "sort": 0, "flags": {}, "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!oY69NN4rYxoRE4hl.1aOeMMX0XuDtZbbB.gCkqvBUljsOsYacB" } ], @@ -323,14 +314,14 @@ "name": "Charcoal Constructs", "type": "feature", "system": { - "description": "

Warped animals wreathed in indigo flame trample through a point of your choice. All targets within Close range of that point must make an Agility Reaction Roll. Targets who fail take 3d12+3 physical damage. Targets who succeed take half damage instead.

Are these real animals consumed by the fl ame or merely constructs of the corrupting magic?

", + "description": "

Warped animals wreathed in indigo flame trample through a point of your choice. All targets within Close range of that point must make an Agility Reaction Roll. Targets who fail take 3d12+3 physical damage. Targets who succeed take half damage instead.

@Template[type:emanation|range:c]

Are these real animals consumed by the fl ame or merely constructs of the corrupting magic?

", "resource": null, "actions": { "gbXIaKr8em134IZC": { "type": "attack", "_id": "gbXIaKr8em134IZC", "systemPath": "actions", - "description": "", + "description": "

Warped animals wreathed in indigo f l ame trample through a point of your choice. All targets within Close range of that point must make an Agility Reaction Roll. Targets who fail take 3d12+3 physical damage. Targets who succeed take half damage instead.

@Template[type:emanation|range:c]

Are these real animals consumed by the fl ame or merely constructs of the corrupting magic?

", "chatDisplay": true, "actionType": "action", "cost": [], @@ -340,8 +331,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -367,9 +358,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -398,16 +388,7 @@ }, "name": "Roll Save", "img": "icons/creatures/magical/construct-face-stone-pink.webp", - "range": "close", - "areas": [ - { - "name": "Charcoal Constructs", - "type": "placed", - "shape": "circle", - "size": "close", - "effects": [] - } - ] + "range": "close" } }, "originItemType": null, @@ -450,8 +431,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -477,7 +458,7 @@ } } } - }, + ], "includeBase": false, "direct": true }, diff --git a/src/packs/environments/environment_Bustling_Marketplace_HZKA7hkej7JJY503.json b/src/packs/environments/environment_Bustling_Marketplace_HZKA7hkej7JJY503.json index e10fad1a..ad96108b 100644 --- a/src/packs/environments/environment_Bustling_Marketplace_HZKA7hkej7JJY503.json +++ b/src/packs/environments/environment_Bustling_Marketplace_HZKA7hkej7JJY503.json @@ -50,9 +50,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/forest.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -103,7 +106,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -129,15 +132,14 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { "name": "Tip the Scales", "type": "feature", "system": { - "description": "

PCs can gain advantage on a Presence Roll by offering a handful of gold as part of the interaction.

Will any coin be accepted or only local currency? How overt are the PCs in offering this bribe?

", + "description": "

PCs can gain advantage on a Presence Roll by off ering a handful of gold as part of the interaction.

Will any coin be accepted or only local currency? How overt are the PCs in offering this bribe?

", "resource": null, "actions": {}, "originItemType": null, @@ -205,7 +207,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/environments/environment_Castle_Siege_1eZ32Esq7rfZOjlu.json b/src/packs/environments/environment_Castle_Siege_1eZ32Esq7rfZOjlu.json index 190d78b1..411a10c7 100644 --- a/src/packs/environments/environment_Castle_Siege_1eZ32Esq7rfZOjlu.json +++ b/src/packs/environments/environment_Castle_Siege_1eZ32Esq7rfZOjlu.json @@ -54,9 +54,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/forest.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -107,7 +110,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -133,8 +136,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -183,8 +185,8 @@ "recovery": null }, "damage": { - "parts": { - "fear": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -209,7 +211,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -323,14 +325,14 @@ "name": "Collateral Damage", "type": "feature", "system": { - "description": "

When an adversary is defeated, you can spend a Fear to have a stray attack from a siege weapon hit a point on the battlefield. All targets within Very Close range of that point must make an Agility Reaction Roll.

  • Targets who fail take 3d8+3 physical or magic damage and must mark a Stress.

  • Targets who succeed must mark a Stress.

What debris is scattered by the attack? What is broken by the strike that can’t be easily mended?

", + "description": "

When an adversary is defeated, you can spend a Fear to have a stray attack from a siege weapon hit a point on the battlefield. All targets within Very Close range of that point must make an Agility Reaction Roll.

@Template[type:circle|range:vc]

  • Targets who fail take 3d8+3 physical or magic damage and must mark a Stress.

  • Targets who succeed must mark a Stress.

What debris is scattered by the attack? What is broken by the strike that can’t be easily mended?

", "resource": null, "actions": { "r5JN5oFYL5DC6Qqw": { "type": "attack", "_id": "r5JN5oFYL5DC6Qqw", "systemPath": "actions", - "description": "

When an adversary is defeated, you can spend a Fear to have a stray attack from a siege weapon hit a point on the battlefield. All targets within Very Close range of that point must make an Agility Reaction Roll.

  • Targets who fail take 3d8+3 physical or magic damage and must mark a Stress.

  • Targets who succeed must mark a Stress.

What debris is scattered by the attack? What is broken by the strike that can’t be easily mended?

", + "description": "

When an adversary is defeated, you can spend a Fear to have a stray attack from a siege weapon hit a point on the battlefield. All targets within Very Close range of that point must make an Agility Reaction Roll.

@Template[type:circle|range:vc]

  • Targets who fail take 3d8+3 physical or magic damage and must mark a Stress.

  • Targets who succeed must mark a Stress.

What debris is scattered by the attack? What is broken by the strike that can’t be easily mended?

", "chatDisplay": true, "actionType": "action", "cost": [], @@ -340,8 +342,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -367,9 +369,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -398,16 +399,7 @@ }, "name": "Roll Save", "img": "icons/magic/earth/projectile-stone-boulder-brown.webp", - "range": "", - "areas": [ - { - "name": "Collateral Damage", - "type": "placed", - "shape": "circle", - "size": "veryClose", - "effects": [] - } - ] + "range": "" } }, "originItemType": null, diff --git a/src/packs/environments/environment_Chaos_Realm_2Z1mKc65LxNk2PqR.json b/src/packs/environments/environment_Chaos_Realm_2Z1mKc65LxNk2PqR.json index e7c2c4e0..361b15bc 100644 --- a/src/packs/environments/environment_Chaos_Realm_2Z1mKc65LxNk2PqR.json +++ b/src/packs/environments/environment_Chaos_Realm_2Z1mKc65LxNk2PqR.json @@ -150,8 +150,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -176,7 +176,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -265,7 +265,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -381,8 +381,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -408,7 +408,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -552,8 +552,8 @@ "recovery": null }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -578,7 +578,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/environments/environment_Cliffside_Ascent_LPpfdlNKqiZIl04w.json b/src/packs/environments/environment_Cliffside_Ascent_LPpfdlNKqiZIl04w.json index ef367d67..548cf7c4 100644 --- a/src/packs/environments/environment_Cliffside_Ascent_LPpfdlNKqiZIl04w.json +++ b/src/packs/environments/environment_Cliffside_Ascent_LPpfdlNKqiZIl04w.json @@ -214,8 +214,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -240,7 +240,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -292,8 +292,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -317,7 +317,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -343,8 +343,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -368,7 +368,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -394,8 +394,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -419,7 +419,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/environments/environment_Divine_Usurpation_4DLYez7VbMCFDAuZ.json b/src/packs/environments/environment_Divine_Usurpation_4DLYez7VbMCFDAuZ.json index 637cdd41..d8e9cded 100644 --- a/src/packs/environments/environment_Divine_Usurpation_4DLYez7VbMCFDAuZ.json +++ b/src/packs/environments/environment_Divine_Usurpation_4DLYez7VbMCFDAuZ.json @@ -323,8 +323,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -349,7 +349,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -600,8 +600,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -625,7 +625,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/environments/environment_Hallowed_Temple_dsA6j69AnaJhUyqH.json b/src/packs/environments/environment_Hallowed_Temple_dsA6j69AnaJhUyqH.json index c510a87f..f005fa59 100644 --- a/src/packs/environments/environment_Hallowed_Temple_dsA6j69AnaJhUyqH.json +++ b/src/packs/environments/environment_Hallowed_Temple_dsA6j69AnaJhUyqH.json @@ -150,8 +150,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -176,7 +176,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -268,8 +268,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -294,7 +294,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/environments/environment_Imperial_Court_jr1xAoXzVwVblzxI.json b/src/packs/environments/environment_Imperial_Court_jr1xAoXzVwVblzxI.json index 5807d43c..4b49c341 100644 --- a/src/packs/environments/environment_Imperial_Court_jr1xAoXzVwVblzxI.json +++ b/src/packs/environments/environment_Imperial_Court_jr1xAoXzVwVblzxI.json @@ -209,8 +209,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -234,7 +234,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -307,7 +307,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -387,7 +387,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/environments/environment_Local_Tavern_cM4X81DOyvxNIi52.json b/src/packs/environments/environment_Local_Tavern_cM4X81DOyvxNIi52.json index da2d2830..105f230f 100644 --- a/src/packs/environments/environment_Local_Tavern_cM4X81DOyvxNIi52.json +++ b/src/packs/environments/environment_Local_Tavern_cM4X81DOyvxNIi52.json @@ -266,8 +266,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -291,7 +291,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/environments/environment_Mountain_Pass_acMu9wJrMZZzLSTJ.json b/src/packs/environments/environment_Mountain_Pass_acMu9wJrMZZzLSTJ.json index eaad99f7..9ba6a918 100644 --- a/src/packs/environments/environment_Mountain_Pass_acMu9wJrMZZzLSTJ.json +++ b/src/packs/environments/environment_Mountain_Pass_acMu9wJrMZZzLSTJ.json @@ -183,8 +183,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -208,7 +208,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -315,8 +315,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -341,7 +341,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/environments/environment_Necromancer_s_Ossuary_h3KyRL7AshhLAmcH.json b/src/packs/environments/environment_Necromancer_s_Ossuary_h3KyRL7AshhLAmcH.json index 299e8729..e96b9177 100644 --- a/src/packs/environments/environment_Necromancer_s_Ossuary_h3KyRL7AshhLAmcH.json +++ b/src/packs/environments/environment_Necromancer_s_Ossuary_h3KyRL7AshhLAmcH.json @@ -43,9 +43,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/forest.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -96,7 +99,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -122,8 +125,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -147,8 +149,8 @@ "recovery": null }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -173,7 +175,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -233,14 +235,14 @@ "name": "Skeletal Burst", "type": "feature", "system": { - "description": "

All targets within Close range of a point you choose in this environment must succeed on an Agility Reaction Roll or take 4d8+8 physical damage from skeletal shrapnel as part of the ossuary detonates around them.

What ancient skeletal architecture is destroyed? What bones stick in your armor?

", + "description": "

All targets within Close range of a point you choose in this environment must succeed on an Agility Reaction Roll or take 4d8+8 physical damage from skeletal shrapnel as part of the ossuary detonates around them.

@Template[type:circle|range:c]

What ancient skeletal architecture is destroyed? What bones stick in your armor?

", "resource": null, "actions": { "M1mOwi4Limw2hRwL": { "type": "attack", "_id": "M1mOwi4Limw2hRwL", "systemPath": "actions", - "description": "

All targets within Close range of a point you choose in this environment must succeed on an Agility Reaction Roll or take 4d8+8 physical damage from skeletal shrapnel as part of the ossuary detonates around them.

What ancient skeletal architecture is destroyed? What bones stick in your armor?

", + "description": "

All targets within Close range of a point you choose in this environment must succeed on an Agility Reaction Roll or take 4d8+8 physical damage from skeletal shrapnel as part of the ossuary detonates around them.

@Template[type:circle|range:c]

What ancient skeletal architecture is destroyed? What bones stick in your armor?

", "chatDisplay": true, "actionType": "action", "cost": [], @@ -250,8 +252,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -275,9 +277,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -306,16 +307,7 @@ }, "name": "Roll Save", "img": "icons/magic/death/bones-crossed-gray.webp", - "range": "", - "areas": [ - { - "name": "Skeletal Burst", - "type": "placed", - "shape": "circle", - "size": "close", - "effects": [] - } - ] + "range": "" } }, "originItemType": null, @@ -358,7 +350,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/environments/environment_Pitched_Battle_EWD3ZsLoK6VMVOf7.json b/src/packs/environments/environment_Pitched_Battle_EWD3ZsLoK6VMVOf7.json index 42fbd8f9..7be27924 100644 --- a/src/packs/environments/environment_Pitched_Battle_EWD3ZsLoK6VMVOf7.json +++ b/src/packs/environments/environment_Pitched_Battle_EWD3ZsLoK6VMVOf7.json @@ -54,9 +54,12 @@ "src": "systems/daggerheart/assets/icons/documents/actors/forest.svg", "anchorX": 0.5, "anchorY": 0.5, + "offsetX": 0, + "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, + "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -107,7 +110,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": {}, + "detectionModes": [], "occludable": { "radius": 0 }, @@ -133,8 +136,7 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false, - "depth": 1 + "prependAdjective": false }, "items": [ { @@ -192,14 +194,14 @@ "name": "War Magic", "type": "feature", "system": { - "description": "

Spend a Fear as a mage from one side uses large-scale destructive magic. Pick a point on the battlefield within Very Far range of the mage. All targets within Close range of that point must make an Agility Reaction Roll. Targets who fail take 3d12+8 magic damage and must mark a Stress.

What form does the attack takeβ€”fireball raining acid a storm of blades? What tactical objective is this attack meant to accomplish and what comes next?

", + "description": "

Spend a Fear as a mage from one side uses large-scale destructive magic. Pick a point on the battlefield within Very Far range of the mage. All targets within Close range of that point must make an Agility Reaction Roll. Targets who fail take 3d12+8 magic damage and must mark a Stress.

@Template[type:circle|range:c]

What form does the attack takeβ€”fireball raining acid a storm of blades? What tactical objective is this attack meant to accomplish and what comes next?

", "resource": null, "actions": { "1giAFbu3tGqXwi8g": { "type": "attack", "_id": "1giAFbu3tGqXwi8g", "systemPath": "actions", - "description": "

Spend a Fear as a mage from one side uses large-scale destructive magic. Pick a point on the battlefield within Very Far range of the mage. All targets within Close range of that point must make an Agility Reaction Roll. Targets who fail take 3d12+8 magic damage and must mark a Stress.

What form does the attack takeβ€”fireball raining acid a storm of blades? What tactical objective is this attack meant to accomplish and what comes next?

", + "description": "

Spend a Fear as a mage from one side uses large-scale destructive magic. Pick a point on the battlefield within Very Far range of the mage. All targets within Close range of that point must make an Agility Reaction Roll. Targets who fail take 3d12+8 magic damage and must mark a Stress.

@Template[type:circle|range:c]

What form does the attack takeβ€”fireball raining acid a storm of blades? What tactical objective is this attack meant to accomplish and what comes next?

", "chatDisplay": true, "actionType": "action", "cost": [ @@ -216,8 +218,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -243,9 +245,8 @@ } } } - }, - "includeBase": false, - "groupAttack": "" + ], + "includeBase": false }, "target": { "type": "any", @@ -274,16 +275,7 @@ }, "name": "Roll Save", "img": "icons/magic/fire/explosion-flame-lightning-strike.webp", - "range": "far", - "areas": [ - { - "name": "War Magic", - "type": "placed", - "shape": "circle", - "size": "close", - "effects": [] - } - ] + "range": "far" } }, "originItemType": null, diff --git a/src/packs/environments/environment_Raging_River_t4cdqTfzcqP3H1vJ.json b/src/packs/environments/environment_Raging_River_t4cdqTfzcqP3H1vJ.json index 6c87c446..6c34c296 100644 --- a/src/packs/environments/environment_Raging_River_t4cdqTfzcqP3H1vJ.json +++ b/src/packs/environments/environment_Raging_River_t4cdqTfzcqP3H1vJ.json @@ -230,8 +230,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -257,7 +257,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -315,19 +315,18 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until you get out of the river.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Vulnerable until you get out of the river.

", "tint": "#ffffff", @@ -339,16 +338,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!actors.items.effects!t4cdqTfzcqP3H1vJ.WsNoSwwtv0r80BMj.T0ouSQyR8cVpAn79" } ], diff --git a/src/packs/items/armors/armor_Advanced_Chainmail_Armor_LzLOJ9EVaHWAjoq9.json b/src/packs/items/armors/armor_Advanced_Chainmail_Armor_LzLOJ9EVaHWAjoq9.json index 4566396a..174f20c8 100644 --- a/src/packs/items/armors/armor_Advanced_Chainmail_Armor_LzLOJ9EVaHWAjoq9.json +++ b/src/packs/items/armors/armor_Advanced_Chainmail_Armor_LzLOJ9EVaHWAjoq9.json @@ -5,10 +5,6 @@ "_id": "LzLOJ9EVaHWAjoq9", "img": "icons/equipment/chest/breastplate-banded-steel-gold.webp", "system": { - "armor": { - "current": 0, - "max": 6 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Advanced_Full_Plate_Armor_crIbCb9NZ4K0VpoU.json b/src/packs/items/armors/armor_Advanced_Full_Plate_Armor_crIbCb9NZ4K0VpoU.json index 52adc7aa..dbc9d29f 100644 --- a/src/packs/items/armors/armor_Advanced_Full_Plate_Armor_crIbCb9NZ4K0VpoU.json +++ b/src/packs/items/armors/armor_Advanced_Full_Plate_Armor_crIbCb9NZ4K0VpoU.json @@ -5,10 +5,6 @@ "_id": "crIbCb9NZ4K0VpoU", "img": "icons/equipment/chest/breastplate-layered-steel-grey.webp", "system": { - "armor": { - "current": 0, - "max": 6 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Advanced_Gambeson_Armor_epkAmlZVk7HOfUUT.json b/src/packs/items/armors/armor_Advanced_Gambeson_Armor_epkAmlZVk7HOfUUT.json index 36edec39..c9ffc8a3 100644 --- a/src/packs/items/armors/armor_Advanced_Gambeson_Armor_epkAmlZVk7HOfUUT.json +++ b/src/packs/items/armors/armor_Advanced_Gambeson_Armor_epkAmlZVk7HOfUUT.json @@ -5,10 +5,6 @@ "_id": "epkAmlZVk7HOfUUT", "img": "icons/equipment/chest/breastplate-purple.webp", "system": { - "armor": { - "current": 0, - "max": 5 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Advanced_Leather_Armor_itSOp2GCyem0f7oM.json b/src/packs/items/armors/armor_Advanced_Leather_Armor_itSOp2GCyem0f7oM.json index 3e5dbd3b..4e1927e3 100644 --- a/src/packs/items/armors/armor_Advanced_Leather_Armor_itSOp2GCyem0f7oM.json +++ b/src/packs/items/armors/armor_Advanced_Leather_Armor_itSOp2GCyem0f7oM.json @@ -5,10 +5,6 @@ "_id": "itSOp2GCyem0f7oM", "img": "icons/equipment/chest/breastplate-layered-leather-blue.webp", "system": { - "armor": { - "current": 0, - "max": 5 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Bare_Bones_ITAjcigTcUw5pMCN.json b/src/packs/items/armors/armor_Bare_Bones_ITAjcigTcUw5pMCN.json new file mode 100644 index 00000000..5158b100 --- /dev/null +++ b/src/packs/items/armors/armor_Bare_Bones_ITAjcigTcUw5pMCN.json @@ -0,0 +1,75 @@ +{ + "folder": "tI3bfr6Sgi16Z7zm", + "name": "Bare Bones", + "type": "armor", + "_id": "ITAjcigTcUw5pMCN", + "img": "icons/magic/control/buff-strength-muscle-damage.webp", + "system": { + "description": "

When you choose not to equip armor, you have a base Armor Score of 3 + your Strength and use the following as your base damage thresholds:

  • Tier 1: 9/19
  • Tier 2: 11/24
  • Tier 3: 13/31
  • Tier 4: 15/38
", + "actions": {}, + "attached": [], + "tier": 1, + "equipped": false, + "baseScore": 3, + "armorFeatures": [], + "marks": { + "value": 0 + }, + "baseThresholds": { + "major": 9, + "severe": 19 + } + }, + "effects": [ + { + "name": "Bare Bones", + "type": "base", + "system": { + "rangeDependence": { + "enabled": false, + "type": "withinRange", + "target": "hostile", + "range": "melee" + } + }, + "_id": "8ze88zUwdkQSKKJq", + "img": "icons/magic/control/buff-strength-muscle-damage.webp", + "changes": [ + { + "key": "system.armorScore", + "mode": 2, + "value": "@system.traits.strength.value", + "priority": 21 + } + ], + "disabled": false, + "duration": { + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null + }, + "description": "

When you choose not to equip armor, you have a base Armor Score of 3 + your Strength and use the following as your base damage thresholds:

  • Tier 1: 9/19
  • Tier 2: 11/24
  • Tier 3: 13/31
  • Tier 4: 15/38
", + "origin": null, + "tint": "#ffffff", + "transfer": true, + "statuses": [], + "sort": 0, + "flags": {}, + "_stats": { + "compendiumSource": null + }, + "_key": "!items.effects!ITAjcigTcUw5pMCN.8ze88zUwdkQSKKJq" + } + ], + "sort": 0, + "ownership": { + "default": 0, + "MQSznptE5yLT7kj8": 3 + }, + "flags": {}, + "_key": "!items!ITAjcigTcUw5pMCN" +} diff --git a/src/packs/items/armors/armor_Bellamoi_Fine_Armor_WuoVwZA53XRAIt6d.json b/src/packs/items/armors/armor_Bellamoi_Fine_Armor_WuoVwZA53XRAIt6d.json index c470de87..ce4e35fd 100644 --- a/src/packs/items/armors/armor_Bellamoi_Fine_Armor_WuoVwZA53XRAIt6d.json +++ b/src/packs/items/armors/armor_Bellamoi_Fine_Armor_WuoVwZA53XRAIt6d.json @@ -5,10 +5,6 @@ "_id": "WuoVwZA53XRAIt6d", "img": "icons/equipment/chest/breastplate-layered-gold.webp", "system": { - "armor": { - "current": 0, - "max": 5 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Bladefare_Armor_mNN6pvcsS10ChrWF.json b/src/packs/items/armors/armor_Bladefare_Armor_mNN6pvcsS10ChrWF.json index 4ee73939..8b276d5f 100644 --- a/src/packs/items/armors/armor_Bladefare_Armor_mNN6pvcsS10ChrWF.json +++ b/src/packs/items/armors/armor_Bladefare_Armor_mNN6pvcsS10ChrWF.json @@ -5,10 +5,6 @@ "_id": "mNN6pvcsS10ChrWF", "img": "icons/equipment/chest/breastplate-collared-steel-grey.webp", "system": { - "armor": { - "current": 0, - "max": 6 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Chainmail_Armor_haULhuEg37zUUvhb.json b/src/packs/items/armors/armor_Chainmail_Armor_haULhuEg37zUUvhb.json index 4f0719a7..f7526e96 100644 --- a/src/packs/items/armors/armor_Chainmail_Armor_haULhuEg37zUUvhb.json +++ b/src/packs/items/armors/armor_Chainmail_Armor_haULhuEg37zUUvhb.json @@ -5,10 +5,6 @@ "_id": "haULhuEg37zUUvhb", "img": "icons/equipment/chest/breastplate-scale-grey.webp", "system": { - "armor": { - "current": 0, - "max": 4 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Channeling_Armor_vMJxEWz1srfwMsoj.json b/src/packs/items/armors/armor_Channeling_Armor_vMJxEWz1srfwMsoj.json index e805d5d1..a4bd0fea 100644 --- a/src/packs/items/armors/armor_Channeling_Armor_vMJxEWz1srfwMsoj.json +++ b/src/packs/items/armors/armor_Channeling_Armor_vMJxEWz1srfwMsoj.json @@ -5,10 +5,6 @@ "_id": "vMJxEWz1srfwMsoj", "img": "icons/equipment/chest/robe-collared-blue.webp", "system": { - "armor": { - "current": 0, - "max": 5 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Dragonscale_Armor_mdQ69eFHyAQUDmE7.json b/src/packs/items/armors/armor_Dragonscale_Armor_mdQ69eFHyAQUDmE7.json index 4b270234..5b39e41d 100644 --- a/src/packs/items/armors/armor_Dragonscale_Armor_mdQ69eFHyAQUDmE7.json +++ b/src/packs/items/armors/armor_Dragonscale_Armor_mdQ69eFHyAQUDmE7.json @@ -5,10 +5,6 @@ "_id": "mdQ69eFHyAQUDmE7", "img": "icons/equipment/chest/breastplate-rivited-red.webp", "system": { - "armor": { - "current": 0, - "max": 5 - }, "description": "", "actions": { "J1MCpcfXByKaSSgx": { diff --git a/src/packs/items/armors/armor_Dunamis_Silkchain_hAY6UgdGT7dj22Pr.json b/src/packs/items/armors/armor_Dunamis_Silkchain_hAY6UgdGT7dj22Pr.json index 6d223ada..df692143 100644 --- a/src/packs/items/armors/armor_Dunamis_Silkchain_hAY6UgdGT7dj22Pr.json +++ b/src/packs/items/armors/armor_Dunamis_Silkchain_hAY6UgdGT7dj22Pr.json @@ -5,10 +5,6 @@ "_id": "hAY6UgdGT7dj22Pr", "img": "icons/equipment/chest/robe-layered-red.webp", "system": { - "armor": { - "current": 0, - "max": 7 - }, "description": "", "actions": { "8PD5JQuS05IA6HJT": { @@ -52,7 +48,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/items/armors/armor_Elundrian_Chain_Armor_Q6LxmtFetDDkoZVZ.json b/src/packs/items/armors/armor_Elundrian_Chain_Armor_Q6LxmtFetDDkoZVZ.json index 1cf74e2e..d63ce4df 100644 --- a/src/packs/items/armors/armor_Elundrian_Chain_Armor_Q6LxmtFetDDkoZVZ.json +++ b/src/packs/items/armors/armor_Elundrian_Chain_Armor_Q6LxmtFetDDkoZVZ.json @@ -5,10 +5,6 @@ "_id": "Q6LxmtFetDDkoZVZ", "img": "icons/equipment/chest/breastplate-sculpted-green.webp", "system": { - "armor": { - "current": 0, - "max": 4 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Emberwoven_Armor_bcQUh4QG3qFX0Vx6.json b/src/packs/items/armors/armor_Emberwoven_Armor_bcQUh4QG3qFX0Vx6.json index 616bbadf..8ccc27e3 100644 --- a/src/packs/items/armors/armor_Emberwoven_Armor_bcQUh4QG3qFX0Vx6.json +++ b/src/packs/items/armors/armor_Emberwoven_Armor_bcQUh4QG3qFX0Vx6.json @@ -5,10 +5,6 @@ "_id": "bcQUh4QG3qFX0Vx6", "img": "icons/equipment/chest/breastplate-layered-gilded-orange.webp", "system": { - "armor": { - "current": 0, - "max": 6 - }, "description": "", "actions": { "L8mHf4A8SylyxsMH": { @@ -24,8 +20,8 @@ "amount": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "applyTo": "stress", "value": { "custom": { @@ -50,7 +46,7 @@ "base": false, "type": [] } - }, + ], "includeBase": false }, "_id": "L8mHf4A8SylyxsMH", diff --git a/src/packs/items/armors/armor_Full_Fortified_Armor_7emTSt6nhZuTlvt5.json b/src/packs/items/armors/armor_Full_Fortified_Armor_7emTSt6nhZuTlvt5.json index 9f2d7ece..8eb964cc 100644 --- a/src/packs/items/armors/armor_Full_Fortified_Armor_7emTSt6nhZuTlvt5.json +++ b/src/packs/items/armors/armor_Full_Fortified_Armor_7emTSt6nhZuTlvt5.json @@ -5,10 +5,6 @@ "_id": "7emTSt6nhZuTlvt5", "img": "icons/equipment/chest/breastplate-layered-steel.webp", "system": { - "armor": { - "current": 0, - "max": 4 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Full_Plate_Armor_UdUJNa31WxFW2noa.json b/src/packs/items/armors/armor_Full_Plate_Armor_UdUJNa31WxFW2noa.json index 7701d063..1ea120ed 100644 --- a/src/packs/items/armors/armor_Full_Plate_Armor_UdUJNa31WxFW2noa.json +++ b/src/packs/items/armors/armor_Full_Plate_Armor_UdUJNa31WxFW2noa.json @@ -5,10 +5,6 @@ "_id": "UdUJNa31WxFW2noa", "img": "icons/equipment/chest/breastplate-collared-steel.webp", "system": { - "armor": { - "current": 0, - "max": 4 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Gambeson_Armor_yJFp1bfpecDcStVK.json b/src/packs/items/armors/armor_Gambeson_Armor_yJFp1bfpecDcStVK.json index 0ede5b60..1c775402 100644 --- a/src/packs/items/armors/armor_Gambeson_Armor_yJFp1bfpecDcStVK.json +++ b/src/packs/items/armors/armor_Gambeson_Armor_yJFp1bfpecDcStVK.json @@ -5,10 +5,6 @@ "_id": "yJFp1bfpecDcStVK", "img": "icons/equipment/chest/vest-leather-tattered-white.webp", "system": { - "armor": { - "current": 0, - "max": 3 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Harrowbone_Armor_dvyQeUVRLc9y6rnt.json b/src/packs/items/armors/armor_Harrowbone_Armor_dvyQeUVRLc9y6rnt.json index 85ad1d6a..61d1fed7 100644 --- a/src/packs/items/armors/armor_Harrowbone_Armor_dvyQeUVRLc9y6rnt.json +++ b/src/packs/items/armors/armor_Harrowbone_Armor_dvyQeUVRLc9y6rnt.json @@ -5,10 +5,6 @@ "_id": "dvyQeUVRLc9y6rnt", "img": "icons/equipment/chest/breastplate-gorget-steel.webp", "system": { - "armor": { - "current": 0, - "max": 4 - }, "description": "", "actions": { "IzM88FIxQ35P5VB2": { @@ -43,7 +39,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/items/armors/armor_Improved_Chainmail_Armor_K5WkjS0NGqHYmhU3.json b/src/packs/items/armors/armor_Improved_Chainmail_Armor_K5WkjS0NGqHYmhU3.json index ef93ecdd..96e320d1 100644 --- a/src/packs/items/armors/armor_Improved_Chainmail_Armor_K5WkjS0NGqHYmhU3.json +++ b/src/packs/items/armors/armor_Improved_Chainmail_Armor_K5WkjS0NGqHYmhU3.json @@ -5,10 +5,6 @@ "_id": "K5WkjS0NGqHYmhU3", "img": "icons/equipment/chest/breastplate-metal-scaled-grey.webp", "system": { - "armor": { - "current": 0, - "max": 5 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Improved_Full_Plate_Armor_9f7RozpPTqrzJS1m.json b/src/packs/items/armors/armor_Improved_Full_Plate_Armor_9f7RozpPTqrzJS1m.json index 1723c53a..ee63a774 100644 --- a/src/packs/items/armors/armor_Improved_Full_Plate_Armor_9f7RozpPTqrzJS1m.json +++ b/src/packs/items/armors/armor_Improved_Full_Plate_Armor_9f7RozpPTqrzJS1m.json @@ -5,10 +5,6 @@ "_id": "9f7RozpPTqrzJS1m", "img": "icons/equipment/chest/breastplate-cuirass-steel-grey.webp", "system": { - "armor": { - "current": 0, - "max": 5 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Improved_Gambeson_Armor_jphnMZjnS2FkOH3s.json b/src/packs/items/armors/armor_Improved_Gambeson_Armor_jphnMZjnS2FkOH3s.json index a2ff6554..6f4ea1c3 100644 --- a/src/packs/items/armors/armor_Improved_Gambeson_Armor_jphnMZjnS2FkOH3s.json +++ b/src/packs/items/armors/armor_Improved_Gambeson_Armor_jphnMZjnS2FkOH3s.json @@ -5,10 +5,6 @@ "_id": "jphnMZjnS2FkOH3s", "img": "icons/equipment/chest/breastplate-quilted-brown.webp", "system": { - "armor": { - "current": 0, - "max": 4 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Improved_Leather_Armor_t91M61pSCMKStTNt.json b/src/packs/items/armors/armor_Improved_Leather_Armor_t91M61pSCMKStTNt.json index efa3643d..a4f38cc6 100644 --- a/src/packs/items/armors/armor_Improved_Leather_Armor_t91M61pSCMKStTNt.json +++ b/src/packs/items/armors/armor_Improved_Leather_Armor_t91M61pSCMKStTNt.json @@ -5,10 +5,6 @@ "_id": "t91M61pSCMKStTNt", "img": "icons/equipment/chest/breastplate-banded-simple-leather-brown.webp", "system": { - "armor": { - "current": 0, - "max": 4 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Irontree_Breastplate_Armor_tzZntboNtHL5C6VM.json b/src/packs/items/armors/armor_Irontree_Breastplate_Armor_tzZntboNtHL5C6VM.json index a664ad9c..a9e9eaca 100644 --- a/src/packs/items/armors/armor_Irontree_Breastplate_Armor_tzZntboNtHL5C6VM.json +++ b/src/packs/items/armors/armor_Irontree_Breastplate_Armor_tzZntboNtHL5C6VM.json @@ -5,10 +5,6 @@ "_id": "tzZntboNtHL5C6VM", "img": "icons/equipment/chest/breastplate-layered-leather-brown-silver.webp", "system": { - "armor": { - "current": 0, - "max": 4 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Leather_Armor_nibfdNtp2PtxvbVz.json b/src/packs/items/armors/armor_Leather_Armor_nibfdNtp2PtxvbVz.json index 93d8f0cc..37a13f2b 100644 --- a/src/packs/items/armors/armor_Leather_Armor_nibfdNtp2PtxvbVz.json +++ b/src/packs/items/armors/armor_Leather_Armor_nibfdNtp2PtxvbVz.json @@ -5,10 +5,6 @@ "_id": "nibfdNtp2PtxvbVz", "img": "icons/equipment/chest/breastplate-layered-leather-brown.webp", "system": { - "armor": { - "current": 0, - "max": 3 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Legendary_Chainmail_Armor_EsIN5OLKe9ZYFNXZ.json b/src/packs/items/armors/armor_Legendary_Chainmail_Armor_EsIN5OLKe9ZYFNXZ.json index 6c93cbe4..4bee5e4f 100644 --- a/src/packs/items/armors/armor_Legendary_Chainmail_Armor_EsIN5OLKe9ZYFNXZ.json +++ b/src/packs/items/armors/armor_Legendary_Chainmail_Armor_EsIN5OLKe9ZYFNXZ.json @@ -5,10 +5,6 @@ "_id": "EsIN5OLKe9ZYFNXZ", "img": "icons/equipment/chest/breastplate-banded-blue.webp", "system": { - "armor": { - "current": 0, - "max": 7 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Legendary_Full_Plate_Armor_SXWjUR2aUR6bYvdl.json b/src/packs/items/armors/armor_Legendary_Full_Plate_Armor_SXWjUR2aUR6bYvdl.json index f66e4c38..baf544c2 100644 --- a/src/packs/items/armors/armor_Legendary_Full_Plate_Armor_SXWjUR2aUR6bYvdl.json +++ b/src/packs/items/armors/armor_Legendary_Full_Plate_Armor_SXWjUR2aUR6bYvdl.json @@ -5,10 +5,6 @@ "_id": "SXWjUR2aUR6bYvdl", "img": "icons/equipment/chest/breastplate-layered-steel-blue-gold.webp", "system": { - "armor": { - "current": 0, - "max": 7 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Legendary_Gambeson_Armor_c6tMXz4rPf9ioQrf.json b/src/packs/items/armors/armor_Legendary_Gambeson_Armor_c6tMXz4rPf9ioQrf.json index 4cf1c856..338c85e8 100644 --- a/src/packs/items/armors/armor_Legendary_Gambeson_Armor_c6tMXz4rPf9ioQrf.json +++ b/src/packs/items/armors/armor_Legendary_Gambeson_Armor_c6tMXz4rPf9ioQrf.json @@ -5,10 +5,6 @@ "_id": "c6tMXz4rPf9ioQrf", "img": "icons/equipment/chest/breastplate-layered-leather-blue-gold.webp", "system": { - "armor": { - "current": 0, - "max": 6 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Legendary_Leather_Armor_Tptgl5WOj76TyFn7.json b/src/packs/items/armors/armor_Legendary_Leather_Armor_Tptgl5WOj76TyFn7.json index 3ddc5ed7..42334dc4 100644 --- a/src/packs/items/armors/armor_Legendary_Leather_Armor_Tptgl5WOj76TyFn7.json +++ b/src/packs/items/armors/armor_Legendary_Leather_Armor_Tptgl5WOj76TyFn7.json @@ -5,10 +5,6 @@ "_id": "Tptgl5WOj76TyFn7", "img": "icons/equipment/chest/breastplate-layered-gilded-black.webp", "system": { - "armor": { - "current": 0, - "max": 6 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Monett_s_Cloak_AQzU2RsqS5V5bd1v.json b/src/packs/items/armors/armor_Monett_s_Cloak_AQzU2RsqS5V5bd1v.json index 6bb479a4..9a8e1f22 100644 --- a/src/packs/items/armors/armor_Monett_s_Cloak_AQzU2RsqS5V5bd1v.json +++ b/src/packs/items/armors/armor_Monett_s_Cloak_AQzU2RsqS5V5bd1v.json @@ -5,10 +5,6 @@ "_id": "AQzU2RsqS5V5bd1v", "img": "icons/equipment/chest/coat-collared-red.webp", "system": { - "armor": { - "current": 0, - "max": 6 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Rosewild_Armor_tN8kAeBvNKM3EBFo.json b/src/packs/items/armors/armor_Rosewild_Armor_tN8kAeBvNKM3EBFo.json index e3cde9fb..0f0f6430 100644 --- a/src/packs/items/armors/armor_Rosewild_Armor_tN8kAeBvNKM3EBFo.json +++ b/src/packs/items/armors/armor_Rosewild_Armor_tN8kAeBvNKM3EBFo.json @@ -5,10 +5,6 @@ "_id": "tN8kAeBvNKM3EBFo", "img": "icons/equipment/chest/breastplate-banded-leather-purple.webp", "system": { - "armor": { - "current": 0, - "max": 5 - }, "description": "", "actions": { "QRTnCYxJfuJHdnyV": { diff --git a/src/packs/items/armors/armor_Runes_of_Fortification_P4qAEDJUoNLgVRsA.json b/src/packs/items/armors/armor_Runes_of_Fortification_P4qAEDJUoNLgVRsA.json index 2ccc80da..240a4f3e 100644 --- a/src/packs/items/armors/armor_Runes_of_Fortification_P4qAEDJUoNLgVRsA.json +++ b/src/packs/items/armors/armor_Runes_of_Fortification_P4qAEDJUoNLgVRsA.json @@ -5,10 +5,6 @@ "_id": "P4qAEDJUoNLgVRsA", "img": "icons/magic/symbols/rune-sigil-red-orange.webp", "system": { - "armor": { - "current": 0, - "max": 6 - }, "description": "", "actions": { "37KLF2bim9nRdPTU": { diff --git a/src/packs/items/armors/armor_Runetan_Floating_Armor_tHlBUDQC24YMZqd6.json b/src/packs/items/armors/armor_Runetan_Floating_Armor_tHlBUDQC24YMZqd6.json index 593bc8e0..8d4af425 100644 --- a/src/packs/items/armors/armor_Runetan_Floating_Armor_tHlBUDQC24YMZqd6.json +++ b/src/packs/items/armors/armor_Runetan_Floating_Armor_tHlBUDQC24YMZqd6.json @@ -5,10 +5,6 @@ "_id": "tHlBUDQC24YMZqd6", "img": "icons/equipment/chest/breastplate-layered-leather-black.webp", "system": { - "armor": { - "current": 0, - "max": 4 - }, "description": "", "actions": { "Nn33zCIcWe6LQMDH": { diff --git a/src/packs/items/armors/armor_Savior_Chainmail_8X16lJQ3xltTwynm.json b/src/packs/items/armors/armor_Savior_Chainmail_8X16lJQ3xltTwynm.json index 6826254a..714e8592 100644 --- a/src/packs/items/armors/armor_Savior_Chainmail_8X16lJQ3xltTwynm.json +++ b/src/packs/items/armors/armor_Savior_Chainmail_8X16lJQ3xltTwynm.json @@ -5,10 +5,6 @@ "_id": "8X16lJQ3xltTwynm", "img": "icons/equipment/chest/breastplate-layered-leather-green.webp", "system": { - "armor": { - "current": 0, - "max": 8 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Spiked_Plate_Armor_QjwsIhXKqnlvRBMv.json b/src/packs/items/armors/armor_Spiked_Plate_Armor_QjwsIhXKqnlvRBMv.json index ac9115a2..cb5fc720 100644 --- a/src/packs/items/armors/armor_Spiked_Plate_Armor_QjwsIhXKqnlvRBMv.json +++ b/src/packs/items/armors/armor_Spiked_Plate_Armor_QjwsIhXKqnlvRBMv.json @@ -5,10 +5,6 @@ "_id": "QjwsIhXKqnlvRBMv", "img": "icons/equipment/chest/breastplate-banded-steel-studded.webp", "system": { - "armor": { - "current": 0, - "max": 5 - }, "description": "", "actions": {}, "attached": [], diff --git a/src/packs/items/armors/armor_Tyris_Soft_Armor_PSW3BxCGmtLeWOxM.json b/src/packs/items/armors/armor_Tyris_Soft_Armor_PSW3BxCGmtLeWOxM.json index c6766018..da640830 100644 --- a/src/packs/items/armors/armor_Tyris_Soft_Armor_PSW3BxCGmtLeWOxM.json +++ b/src/packs/items/armors/armor_Tyris_Soft_Armor_PSW3BxCGmtLeWOxM.json @@ -5,10 +5,6 @@ "_id": "PSW3BxCGmtLeWOxM", "img": "icons/equipment/chest/robe-layered-purple.webp", "system": { - "armor": { - "current": 0, - "max": 5 - }, "description": "", "actions": { "Ch6IhuPewBeseGez": { diff --git a/src/packs/items/armors/armor_Veritas_Opal_Armor_OvzgUTYy2RCN85vV.json b/src/packs/items/armors/armor_Veritas_Opal_Armor_OvzgUTYy2RCN85vV.json index 403b79e8..08a1b573 100644 --- a/src/packs/items/armors/armor_Veritas_Opal_Armor_OvzgUTYy2RCN85vV.json +++ b/src/packs/items/armors/armor_Veritas_Opal_Armor_OvzgUTYy2RCN85vV.json @@ -5,10 +5,6 @@ "_id": "OvzgUTYy2RCN85vV", "img": "icons/equipment/chest/breastplate-collared-steel-green.webp", "system": { - "armor": { - "current": 0, - "max": 6 - }, "description": "", "actions": { "sY3W5JYspN5Du5ag": { diff --git a/src/packs/items/armors/folders_Special_tI3bfr6Sgi16Z7zm.json b/src/packs/items/armors/folders_Special_tI3bfr6Sgi16Z7zm.json new file mode 100644 index 00000000..65c4eca8 --- /dev/null +++ b/src/packs/items/armors/folders_Special_tI3bfr6Sgi16Z7zm.json @@ -0,0 +1,12 @@ +{ + "type": "Item", + "folder": null, + "name": "Special", + "color": null, + "sorting": "a", + "_id": "tI3bfr6Sgi16Z7zm", + "description": "", + "sort": 0, + "flags": {}, + "_key": "!folders!tI3bfr6Sgi16Z7zm" +} diff --git a/src/packs/items/consumables/consumable_Blinding_Orb_eAXHdzA5qNPldOpn.json b/src/packs/items/consumables/consumable_Blinding_Orb_eAXHdzA5qNPldOpn.json index 1282ceeb..3e237b65 100644 --- a/src/packs/items/consumables/consumable_Blinding_Orb_eAXHdzA5qNPldOpn.json +++ b/src/packs/items/consumables/consumable_Blinding_Orb_eAXHdzA5qNPldOpn.json @@ -59,21 +59,19 @@ "transfer": false, "_id": "nryJhrF26hyFQUxH", "type": "base", - "system": { - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until they mark HP.

" - } - }, + "system": {}, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

You are Vulnerable until you mark a Hit Point.

", + "description": "

You are Vulnerable until you mark a Hit Point.

", "tint": "#ffffff", "statuses": [ "vulnerable" @@ -83,16 +81,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!eAXHdzA5qNPldOpn.nryJhrF26hyFQUxH" } ], diff --git a/src/packs/items/consumables/consumable_Dragonbloom_Tea_wM18PWWW2Ami4fBG.json b/src/packs/items/consumables/consumable_Dragonbloom_Tea_wM18PWWW2Ami4fBG.json index 5e877f6d..0dc8764d 100644 --- a/src/packs/items/consumables/consumable_Dragonbloom_Tea_wM18PWWW2Ami4fBG.json +++ b/src/packs/items/consumables/consumable_Dragonbloom_Tea_wM18PWWW2Ami4fBG.json @@ -30,8 +30,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -55,7 +55,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/items/consumables/consumable_Dripfang_Poison_eU8VpbWB2NHIL47n.json b/src/packs/items/consumables/consumable_Dripfang_Poison_eU8VpbWB2NHIL47n.json index cb2c7997..3b0eb9e7 100644 --- a/src/packs/items/consumables/consumable_Dripfang_Poison_eU8VpbWB2NHIL47n.json +++ b/src/packs/items/consumables/consumable_Dripfang_Poison_eU8VpbWB2NHIL47n.json @@ -30,8 +30,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -57,7 +57,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/items/consumables/consumable_Feast_of_Xuria_aX6NyxkNzu0LcJpt.json b/src/packs/items/consumables/consumable_Feast_of_Xuria_aX6NyxkNzu0LcJpt.json index 159e0442..67f4b227 100644 --- a/src/packs/items/consumables/consumable_Feast_of_Xuria_aX6NyxkNzu0LcJpt.json +++ b/src/packs/items/consumables/consumable_Feast_of_Xuria_aX6NyxkNzu0LcJpt.json @@ -30,8 +30,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -56,7 +56,7 @@ }, "type": [] }, - "stress": { + { "value": { "custom": { "enabled": true, @@ -81,7 +81,7 @@ }, "type": [] }, - "hope": { + { "value": { "custom": { "enabled": false @@ -105,7 +105,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/items/consumables/consumable_Growing_Potion_fl2f3ees8RFMze9t.json b/src/packs/items/consumables/consumable_Growing_Potion_fl2f3ees8RFMze9t.json index 833e7055..933d70fa 100644 --- a/src/packs/items/consumables/consumable_Growing_Potion_fl2f3ees8RFMze9t.json +++ b/src/packs/items/consumables/consumable_Growing_Potion_fl2f3ees8RFMze9t.json @@ -59,31 +59,30 @@ "transfer": false, "_id": "YEGd74Lssj7rCmpF", "type": "base", - "system": { - "changes": [ - { - "key": "system.traits.strength.value", - "value": 2, - "priority": null, - "type": "add" - }, - { - "key": "system.proficiency", - "value": 1, - "priority": null, - "type": "add" - } - ], - "duration": { - "type": "shortRest" + "system": {}, + "changes": [ + { + "key": "system.traits.strength.value", + "mode": 2, + "value": "2", + "priority": null + }, + { + "key": "system.proficiency", + "mode": 2, + "value": "1", + "priority": null } - }, + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -93,16 +92,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!fl2f3ees8RFMze9t.YEGd74Lssj7rCmpF" } ], diff --git a/src/packs/items/consumables/consumable_Health_Potion_Aruc2NLutWuVIjP1.json b/src/packs/items/consumables/consumable_Health_Potion_Aruc2NLutWuVIjP1.json index 7365b375..eb9c4824 100644 --- a/src/packs/items/consumables/consumable_Health_Potion_Aruc2NLutWuVIjP1.json +++ b/src/packs/items/consumables/consumable_Health_Potion_Aruc2NLutWuVIjP1.json @@ -30,8 +30,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -55,7 +55,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/items/consumables/consumable_Improved_Arcane_Shard_nQTo6mNoPTEVBtkm.json b/src/packs/items/consumables/consumable_Improved_Arcane_Shard_nQTo6mNoPTEVBtkm.json index 707a395f..f1e88b96 100644 --- a/src/packs/items/consumables/consumable_Improved_Arcane_Shard_nQTo6mNoPTEVBtkm.json +++ b/src/packs/items/consumables/consumable_Improved_Arcane_Shard_nQTo6mNoPTEVBtkm.json @@ -30,8 +30,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -57,7 +57,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/items/consumables/consumable_Jar_of_Lost_Voices_yUol6M5b8jsbk9za.json b/src/packs/items/consumables/consumable_Jar_of_Lost_Voices_yUol6M5b8jsbk9za.json index c8e6e75b..38555821 100644 --- a/src/packs/items/consumables/consumable_Jar_of_Lost_Voices_yUol6M5b8jsbk9za.json +++ b/src/packs/items/consumables/consumable_Jar_of_Lost_Voices_yUol6M5b8jsbk9za.json @@ -30,8 +30,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -57,7 +57,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/items/consumables/consumable_Major_Arcane_Shard_AA7bmiwv00lshPrC.json b/src/packs/items/consumables/consumable_Major_Arcane_Shard_AA7bmiwv00lshPrC.json index 5e95fe66..76e67cf9 100644 --- a/src/packs/items/consumables/consumable_Major_Arcane_Shard_AA7bmiwv00lshPrC.json +++ b/src/packs/items/consumables/consumable_Major_Arcane_Shard_AA7bmiwv00lshPrC.json @@ -30,8 +30,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -55,7 +55,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/items/consumables/consumable_Major_Health_Potion_cM7pHe8bBAxSZ2xR.json b/src/packs/items/consumables/consumable_Major_Health_Potion_cM7pHe8bBAxSZ2xR.json index 67be0b08..a300aaf6 100644 --- a/src/packs/items/consumables/consumable_Major_Health_Potion_cM7pHe8bBAxSZ2xR.json +++ b/src/packs/items/consumables/consumable_Major_Health_Potion_cM7pHe8bBAxSZ2xR.json @@ -30,8 +30,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -55,7 +55,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/items/consumables/consumable_Major_Stamina_Potion_I4cQ03xbxnc81EGa.json b/src/packs/items/consumables/consumable_Major_Stamina_Potion_I4cQ03xbxnc81EGa.json index 703c2cbe..94e53a0c 100644 --- a/src/packs/items/consumables/consumable_Major_Stamina_Potion_I4cQ03xbxnc81EGa.json +++ b/src/packs/items/consumables/consumable_Major_Stamina_Potion_I4cQ03xbxnc81EGa.json @@ -30,8 +30,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -55,7 +55,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/items/consumables/consumable_Major_Stride_Potion_yK6eEDUrsPbZA8G0.json b/src/packs/items/consumables/consumable_Major_Stride_Potion_yK6eEDUrsPbZA8G0.json index dbfe2dcc..cf754770 100644 --- a/src/packs/items/consumables/consumable_Major_Stride_Potion_yK6eEDUrsPbZA8G0.json +++ b/src/packs/items/consumables/consumable_Major_Stride_Potion_yK6eEDUrsPbZA8G0.json @@ -59,25 +59,24 @@ "transfer": false, "_id": "L9dAw8pws1o02XkE", "type": "base", - "system": { - "changes": [ - { - "key": "system.traits.agility.value", - "value": 1, - "priority": null, - "type": "add" - } - ], - "duration": { - "type": "shortRest" + "system": {}, + "changes": [ + { + "key": "system.traits.agility.value", + "mode": 2, + "value": "1", + "priority": null } - }, + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -87,16 +86,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!yK6eEDUrsPbZA8G0.L9dAw8pws1o02XkE" } ], diff --git a/src/packs/items/consumables/consumable_Minor_Health_Potion_tPfKtKRRjv8qdSqy.json b/src/packs/items/consumables/consumable_Minor_Health_Potion_tPfKtKRRjv8qdSqy.json index fe86bf95..d0f90919 100644 --- a/src/packs/items/consumables/consumable_Minor_Health_Potion_tPfKtKRRjv8qdSqy.json +++ b/src/packs/items/consumables/consumable_Minor_Health_Potion_tPfKtKRRjv8qdSqy.json @@ -30,8 +30,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -55,7 +55,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/items/consumables/consumable_Minor_Stamina_Potion_b6vGSPFWOlzZZDLO.json b/src/packs/items/consumables/consumable_Minor_Stamina_Potion_b6vGSPFWOlzZZDLO.json index 625167e1..1ef4efbf 100644 --- a/src/packs/items/consumables/consumable_Minor_Stamina_Potion_b6vGSPFWOlzZZDLO.json +++ b/src/packs/items/consumables/consumable_Minor_Stamina_Potion_b6vGSPFWOlzZZDLO.json @@ -30,8 +30,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -55,7 +55,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/items/consumables/consumable_Morphing_Clay_f1NHVSIHJJCIOaBl.json b/src/packs/items/consumables/consumable_Morphing_Clay_f1NHVSIHJJCIOaBl.json index 90dd4fdc..54aa6ccc 100644 --- a/src/packs/items/consumables/consumable_Morphing_Clay_f1NHVSIHJJCIOaBl.json +++ b/src/packs/items/consumables/consumable_Morphing_Clay_f1NHVSIHJJCIOaBl.json @@ -65,20 +65,20 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "shortRest" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

Your face is unrecognizable until your next rest.

", + "description": "

Your face is unrecognizable until your next rest.

", "tint": "#ffffff", "statuses": [], "sort": 0, @@ -86,16 +86,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!f1NHVSIHJJCIOaBl.rMno0zO5Cbwlu4zn" } ], diff --git a/src/packs/items/consumables/consumable_Ogre_Musk_qr1bosjFcUfuwq4B.json b/src/packs/items/consumables/consumable_Ogre_Musk_qr1bosjFcUfuwq4B.json index 59e51e80..39c8800b 100644 --- a/src/packs/items/consumables/consumable_Ogre_Musk_qr1bosjFcUfuwq4B.json +++ b/src/packs/items/consumables/consumable_Ogre_Musk_qr1bosjFcUfuwq4B.json @@ -65,20 +65,20 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "shortRest" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

You cannot be tracked by mundane or magical means until your next rest.

", + "description": "

You cannot be tracked by mundane or magical means until your next rest.

", "tint": "#ffffff", "statuses": [], "sort": 0, @@ -86,16 +86,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!qr1bosjFcUfuwq4B.n73d0J4oMCBIPWHN" } ], diff --git a/src/packs/items/consumables/consumable_Shrinking_Potion_HGixKenQwhyRAYNk.json b/src/packs/items/consumables/consumable_Shrinking_Potion_HGixKenQwhyRAYNk.json index a31a13f1..74e82995 100644 --- a/src/packs/items/consumables/consumable_Shrinking_Potion_HGixKenQwhyRAYNk.json +++ b/src/packs/items/consumables/consumable_Shrinking_Potion_HGixKenQwhyRAYNk.json @@ -59,31 +59,30 @@ "transfer": false, "_id": "yaRLd7eHWYm2MHRM", "type": "base", - "system": { - "changes": [ - { - "key": "system.traits.agility.value", - "value": 2, - "priority": null, - "type": "add" - }, - { - "key": "system.proficiency", - "value": -1, - "priority": null, - "type": "add" - } - ], - "duration": { - "type": "shortRest" + "system": {}, + "changes": [ + { + "key": "system.traits.agility.value", + "mode": 2, + "value": "2", + "priority": null + }, + { + "key": "system.proficiency", + "mode": 2, + "value": "-1", + "priority": null } - }, + ], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "", "tint": "#ffffff", @@ -93,16 +92,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!HGixKenQwhyRAYNk.yaRLd7eHWYm2MHRM" } ], diff --git a/src/packs/items/consumables/consumable_Sleeping_Sap_XZavUVlHEvE2srEt.json b/src/packs/items/consumables/consumable_Sleeping_Sap_XZavUVlHEvE2srEt.json index d66ff42b..a6f70305 100644 --- a/src/packs/items/consumables/consumable_Sleeping_Sap_XZavUVlHEvE2srEt.json +++ b/src/packs/items/consumables/consumable_Sleeping_Sap_XZavUVlHEvE2srEt.json @@ -30,8 +30,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -56,7 +56,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/items/consumables/consumable_Snap_Powder_cg6VtQ0eVZjDdcK0.json b/src/packs/items/consumables/consumable_Snap_Powder_cg6VtQ0eVZjDdcK0.json index 506cb1cf..dd129914 100644 --- a/src/packs/items/consumables/consumable_Snap_Powder_cg6VtQ0eVZjDdcK0.json +++ b/src/packs/items/consumables/consumable_Snap_Powder_cg6VtQ0eVZjDdcK0.json @@ -30,8 +30,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -56,7 +56,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/items/consumables/consumable_Stamina_Potion_hf3k1POoVSooJyN2.json b/src/packs/items/consumables/consumable_Stamina_Potion_hf3k1POoVSooJyN2.json index f464ee61..6a4a3335 100644 --- a/src/packs/items/consumables/consumable_Stamina_Potion_hf3k1POoVSooJyN2.json +++ b/src/packs/items/consumables/consumable_Stamina_Potion_hf3k1POoVSooJyN2.json @@ -30,8 +30,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -55,7 +55,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/items/consumables/consumable_Stardrop_y4c1jrlHrf0wBWOq.json b/src/packs/items/consumables/consumable_Stardrop_y4c1jrlHrf0wBWOq.json index 3351c24f..7b244715 100644 --- a/src/packs/items/consumables/consumable_Stardrop_y4c1jrlHrf0wBWOq.json +++ b/src/packs/items/consumables/consumable_Stardrop_y4c1jrlHrf0wBWOq.json @@ -30,8 +30,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -57,7 +57,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/items/consumables/consumable_Sun_Tree_Sap_kwexUzdM9wm1Qums.json b/src/packs/items/consumables/consumable_Sun_Tree_Sap_kwexUzdM9wm1Qums.json index cfe0a63c..82f02518 100644 --- a/src/packs/items/consumables/consumable_Sun_Tree_Sap_kwexUzdM9wm1Qums.json +++ b/src/packs/items/consumables/consumable_Sun_Tree_Sap_kwexUzdM9wm1Qums.json @@ -30,7 +30,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/items/consumables/consumable_Sweet_Moss_GrDrRqWgv7gvl9vn.json b/src/packs/items/consumables/consumable_Sweet_Moss_GrDrRqWgv7gvl9vn.json index 84663fb4..5034e482 100644 --- a/src/packs/items/consumables/consumable_Sweet_Moss_GrDrRqWgv7gvl9vn.json +++ b/src/packs/items/consumables/consumable_Sweet_Moss_GrDrRqWgv7gvl9vn.json @@ -30,8 +30,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -55,7 +55,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -105,8 +105,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -130,7 +130,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/items/consumables/consumable_Unstable_Arcane_Shard_mUepnLbkvFk0ha4Z.json b/src/packs/items/consumables/consumable_Unstable_Arcane_Shard_mUepnLbkvFk0ha4Z.json index b6f18539..2fa73e49 100644 --- a/src/packs/items/consumables/consumable_Unstable_Arcane_Shard_mUepnLbkvFk0ha4Z.json +++ b/src/packs/items/consumables/consumable_Unstable_Arcane_Shard_mUepnLbkvFk0ha4Z.json @@ -30,8 +30,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -57,7 +57,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/items/consumables/consumable_Varik_Leaves_hvy5BkG3F6iOIXTx.json b/src/packs/items/consumables/consumable_Varik_Leaves_hvy5BkG3F6iOIXTx.json index 7e2f0c08..8588d8e6 100644 --- a/src/packs/items/consumables/consumable_Varik_Leaves_hvy5BkG3F6iOIXTx.json +++ b/src/packs/items/consumables/consumable_Varik_Leaves_hvy5BkG3F6iOIXTx.json @@ -30,8 +30,8 @@ "recovery": null }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -56,7 +56,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/items/consumables/consumable_Vial_of_Moondrip_VqEX5YwK5oL3r1t6.json b/src/packs/items/consumables/consumable_Vial_of_Moondrip_VqEX5YwK5oL3r1t6.json index 3fc572fd..31586ef8 100644 --- a/src/packs/items/consumables/consumable_Vial_of_Moondrip_VqEX5YwK5oL3r1t6.json +++ b/src/packs/items/consumables/consumable_Vial_of_Moondrip_VqEX5YwK5oL3r1t6.json @@ -65,20 +65,20 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "shortRest" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

You can see in total darkness until your next rest.

", + "description": "

You can see in total darkness until your next rest.

", "tint": "#ffffff", "statuses": [], "sort": 0, @@ -86,16 +86,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!VqEX5YwK5oL3r1t6.548KAUPcSbQLsivh" } ], diff --git a/src/packs/items/loot/loot_Bag_of_Ficklesand_v758j4FwNVAurhYK.json b/src/packs/items/loot/loot_Bag_of_Ficklesand_v758j4FwNVAurhYK.json index 2cb80d86..c083e7ca 100644 --- a/src/packs/items/loot/loot_Bag_of_Ficklesand_v758j4FwNVAurhYK.json +++ b/src/packs/items/loot/loot_Bag_of_Ficklesand_v758j4FwNVAurhYK.json @@ -21,7 +21,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/items/loot/loot_Box_of_Many_Goods_bZyT7Qw7iafswlTY.json b/src/packs/items/loot/loot_Box_of_Many_Goods_bZyT7Qw7iafswlTY.json index cb603dc7..1090323f 100644 --- a/src/packs/items/loot/loot_Box_of_Many_Goods_bZyT7Qw7iafswlTY.json +++ b/src/packs/items/loot/loot_Box_of_Many_Goods_bZyT7Qw7iafswlTY.json @@ -21,7 +21,7 @@ "recovery": "longRest" }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/items/loot/loot_Calming_Pendant_tgFFMxpuRSiRrrEB.json b/src/packs/items/loot/loot_Calming_Pendant_tgFFMxpuRSiRrrEB.json index ea5b50eb..3d5b9651 100644 --- a/src/packs/items/loot/loot_Calming_Pendant_tgFFMxpuRSiRrrEB.json +++ b/src/packs/items/loot/loot_Calming_Pendant_tgFFMxpuRSiRrrEB.json @@ -21,7 +21,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/items/loot/loot_Skeleton_Key_edkNgwy4xghZreBa.json b/src/packs/items/loot/loot_Skeleton_Key_edkNgwy4xghZreBa.json index b5769661..72a8d3e0 100644 --- a/src/packs/items/loot/loot_Skeleton_Key_edkNgwy4xghZreBa.json +++ b/src/packs/items/loot/loot_Skeleton_Key_edkNgwy4xghZreBa.json @@ -21,7 +21,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/items/loot/loot_Woven_Net_ARuv48PWUGJGBC4n.json b/src/packs/items/loot/loot_Woven_Net_ARuv48PWUGJGBC4n.json index 2732b61f..99d52ea9 100644 --- a/src/packs/items/loot/loot_Woven_Net_ARuv48PWUGJGBC4n.json +++ b/src/packs/items/loot/loot_Woven_Net_ARuv48PWUGJGBC4n.json @@ -21,7 +21,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/items/weapons/weapon_Aantari_Bow_ijodu5yNBoMxpkHV.json b/src/packs/items/weapons/weapon_Aantari_Bow_ijodu5yNBoMxpkHV.json index 7b51d436..93e6404c 100644 --- a/src/packs/items/weapons/weapon_Aantari_Bow_ijodu5yNBoMxpkHV.json +++ b/src/packs/items/weapons/weapon_Aantari_Bow_ijodu5yNBoMxpkHV.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 11, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Arcane_Frame_Wheelchair_la3sAWgnvadc4NvP.json b/src/packs/items/weapons/weapon_Advanced_Arcane_Frame_Wheelchair_la3sAWgnvadc4NvP.json index a727bcd5..36f1be3a 100644 --- a/src/packs/items/weapons/weapon_Advanced_Arcane_Frame_Wheelchair_la3sAWgnvadc4NvP.json +++ b/src/packs/items/weapons/weapon_Advanced_Arcane_Frame_Wheelchair_la3sAWgnvadc4NvP.json @@ -48,8 +48,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 6, @@ -75,7 +75,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Arcane_Gauntlets_hXR56fTKwZ6s1obs.json b/src/packs/items/weapons/weapon_Advanced_Arcane_Gauntlets_hXR56fTKwZ6s1obs.json index 67400768..183ac117 100644 --- a/src/packs/items/weapons/weapon_Advanced_Arcane_Gauntlets_hXR56fTKwZ6s1obs.json +++ b/src/packs/items/weapons/weapon_Advanced_Arcane_Gauntlets_hXR56fTKwZ6s1obs.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 9, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Battleaxe_FcbvY1ydbNVMjKvk.json b/src/packs/items/weapons/weapon_Advanced_Battleaxe_FcbvY1ydbNVMjKvk.json index e780eeed..6d2879d7 100644 --- a/src/packs/items/weapons/weapon_Advanced_Battleaxe_FcbvY1ydbNVMjKvk.json +++ b/src/packs/items/weapons/weapon_Advanced_Battleaxe_FcbvY1ydbNVMjKvk.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 9, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Broadsword_WtQAGz0TUgz8Xg70.json b/src/packs/items/weapons/weapon_Advanced_Broadsword_WtQAGz0TUgz8Xg70.json index 4581c52f..9e4a67b0 100644 --- a/src/packs/items/weapons/weapon_Advanced_Broadsword_WtQAGz0TUgz8Xg70.json +++ b/src/packs/items/weapons/weapon_Advanced_Broadsword_WtQAGz0TUgz8Xg70.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 6, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Crossbow_3HGs0AgVrdIBTaKG.json b/src/packs/items/weapons/weapon_Advanced_Crossbow_3HGs0AgVrdIBTaKG.json index 437423f5..44e47499 100644 --- a/src/packs/items/weapons/weapon_Advanced_Crossbow_3HGs0AgVrdIBTaKG.json +++ b/src/packs/items/weapons/weapon_Advanced_Crossbow_3HGs0AgVrdIBTaKG.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 7, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Cutlass_bw9WO9lxkM9bWZxQ.json b/src/packs/items/weapons/weapon_Advanced_Cutlass_bw9WO9lxkM9bWZxQ.json index 45d9a597..a20acb5b 100644 --- a/src/packs/items/weapons/weapon_Advanced_Cutlass_bw9WO9lxkM9bWZxQ.json +++ b/src/packs/items/weapons/weapon_Advanced_Cutlass_bw9WO9lxkM9bWZxQ.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 7, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Dagger_mrioysDjNQEIE8hN.json b/src/packs/items/weapons/weapon_Advanced_Dagger_mrioysDjNQEIE8hN.json index 03f27c99..a7004807 100644 --- a/src/packs/items/weapons/weapon_Advanced_Dagger_mrioysDjNQEIE8hN.json +++ b/src/packs/items/weapons/weapon_Advanced_Dagger_mrioysDjNQEIE8hN.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 7, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Dualstaff_X5x3sC7v2f3L9sjL.json b/src/packs/items/weapons/weapon_Advanced_Dualstaff_X5x3sC7v2f3L9sjL.json index 033b873c..3baed3d4 100644 --- a/src/packs/items/weapons/weapon_Advanced_Dualstaff_X5x3sC7v2f3L9sjL.json +++ b/src/packs/items/weapons/weapon_Advanced_Dualstaff_X5x3sC7v2f3L9sjL.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 9, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Glowing_Rings_InQoh8mZPnwarQkX.json b/src/packs/items/weapons/weapon_Advanced_Glowing_Rings_InQoh8mZPnwarQkX.json index 2ea7b20d..2bdfed49 100644 --- a/src/packs/items/weapons/weapon_Advanced_Glowing_Rings_InQoh8mZPnwarQkX.json +++ b/src/packs/items/weapons/weapon_Advanced_Glowing_Rings_InQoh8mZPnwarQkX.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 8, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Grappler_7vvhVl4TDJHtjpFK.json b/src/packs/items/weapons/weapon_Advanced_Grappler_7vvhVl4TDJHtjpFK.json index 390a0b9a..01bef9b2 100644 --- a/src/packs/items/weapons/weapon_Advanced_Grappler_7vvhVl4TDJHtjpFK.json +++ b/src/packs/items/weapons/weapon_Advanced_Grappler_7vvhVl4TDJHtjpFK.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 4, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Greatstaff_4UzxqfkwF8gDSdu7.json b/src/packs/items/weapons/weapon_Advanced_Greatstaff_4UzxqfkwF8gDSdu7.json index 3cc7b986..c66354c2 100644 --- a/src/packs/items/weapons/weapon_Advanced_Greatstaff_4UzxqfkwF8gDSdu7.json +++ b/src/packs/items/weapons/weapon_Advanced_Greatstaff_4UzxqfkwF8gDSdu7.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 6, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Greatsword_MAC6YWTo4lzSotQc.json b/src/packs/items/weapons/weapon_Advanced_Greatsword_MAC6YWTo4lzSotQc.json index 9e04bf7a..71226630 100644 --- a/src/packs/items/weapons/weapon_Advanced_Greatsword_MAC6YWTo4lzSotQc.json +++ b/src/packs/items/weapons/weapon_Advanced_Greatsword_MAC6YWTo4lzSotQc.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 9, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Halberd_C8gQn7onAc9wsrCs.json b/src/packs/items/weapons/weapon_Advanced_Halberd_C8gQn7onAc9wsrCs.json index 6c11724c..59d7437d 100644 --- a/src/packs/items/weapons/weapon_Advanced_Halberd_C8gQn7onAc9wsrCs.json +++ b/src/packs/items/weapons/weapon_Advanced_Halberd_C8gQn7onAc9wsrCs.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 8, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Hallowed_Axe_BiyXKX2Mo1TQbKgk.json b/src/packs/items/weapons/weapon_Advanced_Hallowed_Axe_BiyXKX2Mo1TQbKgk.json index ce89ccc2..e6403810 100644 --- a/src/packs/items/weapons/weapon_Advanced_Hallowed_Axe_BiyXKX2Mo1TQbKgk.json +++ b/src/packs/items/weapons/weapon_Advanced_Hallowed_Axe_BiyXKX2Mo1TQbKgk.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 7, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Hand_Crossbow_Lsvocst8aGqkBj7g.json b/src/packs/items/weapons/weapon_Advanced_Hand_Crossbow_Lsvocst8aGqkBj7g.json index 88ba7077..521ee38d 100644 --- a/src/packs/items/weapons/weapon_Advanced_Hand_Crossbow_Lsvocst8aGqkBj7g.json +++ b/src/packs/items/weapons/weapon_Advanced_Hand_Crossbow_Lsvocst8aGqkBj7g.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 5, @@ -70,7 +70,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Hand_Runes_PQACczSghZIVTdgZ.json b/src/packs/items/weapons/weapon_Advanced_Hand_Runes_PQACczSghZIVTdgZ.json index 60ffb789..23f33ba1 100644 --- a/src/packs/items/weapons/weapon_Advanced_Hand_Runes_PQACczSghZIVTdgZ.json +++ b/src/packs/items/weapons/weapon_Advanced_Hand_Runes_PQACczSghZIVTdgZ.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 6, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Heavy_Frame_Wheelchair_eT2Qwb0RdrLX2hH1.json b/src/packs/items/weapons/weapon_Advanced_Heavy_Frame_Wheelchair_eT2Qwb0RdrLX2hH1.json index 7f5bb9c7..39afe3e6 100644 --- a/src/packs/items/weapons/weapon_Advanced_Heavy_Frame_Wheelchair_eT2Qwb0RdrLX2hH1.json +++ b/src/packs/items/weapons/weapon_Advanced_Heavy_Frame_Wheelchair_eT2Qwb0RdrLX2hH1.json @@ -48,8 +48,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d12", "bonus": 9, @@ -75,7 +75,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Light_Frame_Wheelchair_BuMfupnCzHbziQ8o.json b/src/packs/items/weapons/weapon_Advanced_Light_Frame_Wheelchair_BuMfupnCzHbziQ8o.json index fca77911..4600088d 100644 --- a/src/packs/items/weapons/weapon_Advanced_Light_Frame_Wheelchair_BuMfupnCzHbziQ8o.json +++ b/src/packs/items/weapons/weapon_Advanced_Light_Frame_Wheelchair_BuMfupnCzHbziQ8o.json @@ -77,8 +77,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 6, @@ -104,7 +104,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Longbow_M5CywMAyPKGgebsJ.json b/src/packs/items/weapons/weapon_Advanced_Longbow_M5CywMAyPKGgebsJ.json index 14327a8c..ad8a5bc9 100644 --- a/src/packs/items/weapons/weapon_Advanced_Longbow_M5CywMAyPKGgebsJ.json +++ b/src/packs/items/weapons/weapon_Advanced_Longbow_M5CywMAyPKGgebsJ.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 9, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Longsword_9xkB3MWXahrsVP4N.json b/src/packs/items/weapons/weapon_Advanced_Longsword_9xkB3MWXahrsVP4N.json index 0b51f2ae..2cf2c43c 100644 --- a/src/packs/items/weapons/weapon_Advanced_Longsword_9xkB3MWXahrsVP4N.json +++ b/src/packs/items/weapons/weapon_Advanced_Longsword_9xkB3MWXahrsVP4N.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 9, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Mace_WreMYiH5uhVDaoVw.json b/src/packs/items/weapons/weapon_Advanced_Mace_WreMYiH5uhVDaoVw.json index e255da65..db8cde18 100644 --- a/src/packs/items/weapons/weapon_Advanced_Mace_WreMYiH5uhVDaoVw.json +++ b/src/packs/items/weapons/weapon_Advanced_Mace_WreMYiH5uhVDaoVw.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 7, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Quarterstaff_zJtm2f9ZFKZRtCRg.json b/src/packs/items/weapons/weapon_Advanced_Quarterstaff_zJtm2f9ZFKZRtCRg.json index 00f0b694..d6beafb2 100644 --- a/src/packs/items/weapons/weapon_Advanced_Quarterstaff_zJtm2f9ZFKZRtCRg.json +++ b/src/packs/items/weapons/weapon_Advanced_Quarterstaff_zJtm2f9ZFKZRtCRg.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 9, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Rapier_KxFne76d7cak15dO.json b/src/packs/items/weapons/weapon_Advanced_Rapier_KxFne76d7cak15dO.json index 28c508b8..315d8401 100644 --- a/src/packs/items/weapons/weapon_Advanced_Rapier_KxFne76d7cak15dO.json +++ b/src/packs/items/weapons/weapon_Advanced_Rapier_KxFne76d7cak15dO.json @@ -78,8 +78,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 6, @@ -105,7 +105,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Returning_Blade_sIGXA4KMeYBUjcEO.json b/src/packs/items/weapons/weapon_Advanced_Returning_Blade_sIGXA4KMeYBUjcEO.json index 0694a020..bbdce2d4 100644 --- a/src/packs/items/weapons/weapon_Advanced_Returning_Blade_sIGXA4KMeYBUjcEO.json +++ b/src/packs/items/weapons/weapon_Advanced_Returning_Blade_sIGXA4KMeYBUjcEO.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 6, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Round_Shield_hiEOGF2reabGLUoi.json b/src/packs/items/weapons/weapon_Advanced_Round_Shield_hiEOGF2reabGLUoi.json index 54800642..c1c4fba5 100644 --- a/src/packs/items/weapons/weapon_Advanced_Round_Shield_hiEOGF2reabGLUoi.json +++ b/src/packs/items/weapons/weapon_Advanced_Round_Shield_hiEOGF2reabGLUoi.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d4", "bonus": 4, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", @@ -113,26 +113,26 @@ "name": "Protective", "description": "

Add the item's Tier to your Armor Score

", "img": "icons/skills/melee/shield-block-gray-orange.webp", - "_id": "7285CRGdZfHCEtT2", + "changes": [ + { + "key": "system.armorScore", + "mode": 2, + "value": "ITEM.@system.tier", + "priority": null + } + ], + "_id": "i5HfkF5aKQuUCTEG", "type": "base", - "system": { - "changes": [ - { - "type": "armor", - "phase": "initial", - "priority": 20, - "value": { - "max": "ITEM.@system.tier" - } - } - ] - }, + "system": {}, "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "origin": null, "tint": "#ffffff", @@ -143,10 +143,7 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, - "_key": "!items.effects!hiEOGF2reabGLUoi.7285CRGdZfHCEtT2" + "_key": "!items.effects!hiEOGF2reabGLUoi.i5HfkF5aKQuUCTEG" } ], "sort": 0, diff --git a/src/packs/items/weapons/weapon_Advanced_Scepter_2Khzuj768yoWN9QK.json b/src/packs/items/weapons/weapon_Advanced_Scepter_2Khzuj768yoWN9QK.json index 6dff775a..cf619a89 100644 --- a/src/packs/items/weapons/weapon_Advanced_Scepter_2Khzuj768yoWN9QK.json +++ b/src/packs/items/weapons/weapon_Advanced_Scepter_2Khzuj768yoWN9QK.json @@ -11,8 +11,8 @@ "type": "attack", "damage": { "includeBase": false, - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -38,7 +38,7 @@ } } } - } + ] }, "range": "melee", "roll": { @@ -115,8 +115,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 6, @@ -142,7 +142,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Shortbow_JpSlJvDR0X8VFDns.json b/src/packs/items/weapons/weapon_Advanced_Shortbow_JpSlJvDR0X8VFDns.json index f5efc9a9..5693e814 100644 --- a/src/packs/items/weapons/weapon_Advanced_Shortbow_JpSlJvDR0X8VFDns.json +++ b/src/packs/items/weapons/weapon_Advanced_Shortbow_JpSlJvDR0X8VFDns.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 9, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Shortstaff_T5exRCqOXhrjSYnI.json b/src/packs/items/weapons/weapon_Advanced_Shortstaff_T5exRCqOXhrjSYnI.json index 0e3b3161..71d66d82 100644 --- a/src/packs/items/weapons/weapon_Advanced_Shortstaff_T5exRCqOXhrjSYnI.json +++ b/src/packs/items/weapons/weapon_Advanced_Shortstaff_T5exRCqOXhrjSYnI.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 7, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Shortsword_p3nz5CaGUoyuGVg0.json b/src/packs/items/weapons/weapon_Advanced_Shortsword_p3nz5CaGUoyuGVg0.json index dd48db21..397fa061 100644 --- a/src/packs/items/weapons/weapon_Advanced_Shortsword_p3nz5CaGUoyuGVg0.json +++ b/src/packs/items/weapons/weapon_Advanced_Shortsword_p3nz5CaGUoyuGVg0.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 4, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Small_Dagger_0thN0BpN05KT8Avx.json b/src/packs/items/weapons/weapon_Advanced_Small_Dagger_0thN0BpN05KT8Avx.json index a63789f3..7af59440 100644 --- a/src/packs/items/weapons/weapon_Advanced_Small_Dagger_0thN0BpN05KT8Avx.json +++ b/src/packs/items/weapons/weapon_Advanced_Small_Dagger_0thN0BpN05KT8Avx.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 4, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Spear_pK6dsNABKKp1CIGN.json b/src/packs/items/weapons/weapon_Advanced_Spear_pK6dsNABKKp1CIGN.json index 099761b4..e5f3f8ec 100644 --- a/src/packs/items/weapons/weapon_Advanced_Spear_pK6dsNABKKp1CIGN.json +++ b/src/packs/items/weapons/weapon_Advanced_Spear_pK6dsNABKKp1CIGN.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 9, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Tower_Shield_OfOzQbs4hg6QbfTG.json b/src/packs/items/weapons/weapon_Advanced_Tower_Shield_OfOzQbs4hg6QbfTG.json index a88749a8..b2fb16d8 100644 --- a/src/packs/items/weapons/weapon_Advanced_Tower_Shield_OfOzQbs4hg6QbfTG.json +++ b/src/packs/items/weapons/weapon_Advanced_Tower_Shield_OfOzQbs4hg6QbfTG.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 4, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", @@ -113,25 +113,25 @@ "name": "Barrier", "description": "Gain Weapon Tier + 1 to Armor Score; -1 to Evasion", "img": "icons/skills/melee/shield-block-bash-blue.webp", + "changes": [ + { + "key": "system.armorScore", + "mode": 2, + "value": "ITEM.@system.tier + 1" + }, + { + "key": "system.evasion", + "mode": 2, + "value": "-1" + } + ], "_id": "87gedjJZGdFY81Mt", "type": "base", - "system": { - "changes": [ - { - "key": "system.evasion", - "type": "add", - "value": -1, - "phase": "initial", - "priority": 0 - } - ] - }, + "system": {}, "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null }, "origin": null, "tint": "#ffffff", @@ -142,49 +142,7 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, "_key": "!items.effects!OfOzQbs4hg6QbfTG.87gedjJZGdFY81Mt" - }, - { - "name": "Barrier", - "description": "Gain Weapon Tier + 1 to Armor Score; -1 to Evasion", - "img": "icons/skills/melee/shield-block-bash-blue.webp", - "_id": "J0f7zqqOr61ADpdy", - "type": "base", - "system": { - "changes": [ - { - "type": "armor", - "phase": "initial", - "priority": 20, - "value": { - "max": "ITEM.@system.tier + 1" - } - } - ] - }, - "disabled": false, - "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false - }, - "origin": null, - "tint": "#ffffff", - "transfer": true, - "statuses": [], - "sort": 0, - "flags": {}, - "_stats": { - "compendiumSource": null - }, - "start": null, - "showIcon": 1, - "folder": null, - "_key": "!items.effects!OfOzQbs4hg6QbfTG.J0f7zqqOr61ADpdy" } ], "sort": 0, diff --git a/src/packs/items/weapons/weapon_Advanced_Wand_jU9jWIardjtdAQcs.json b/src/packs/items/weapons/weapon_Advanced_Wand_jU9jWIardjtdAQcs.json index 8043e360..4cb4e2b2 100644 --- a/src/packs/items/weapons/weapon_Advanced_Wand_jU9jWIardjtdAQcs.json +++ b/src/packs/items/weapons/weapon_Advanced_Wand_jU9jWIardjtdAQcs.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 7, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Warhammer_8Lipw3RRKDgBVP0p.json b/src/packs/items/weapons/weapon_Advanced_Warhammer_8Lipw3RRKDgBVP0p.json index bb142281..72983f6b 100644 --- a/src/packs/items/weapons/weapon_Advanced_Warhammer_8Lipw3RRKDgBVP0p.json +++ b/src/packs/items/weapons/weapon_Advanced_Warhammer_8Lipw3RRKDgBVP0p.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d12", "bonus": 9, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Advanced_Whip_01izMUSJcAUo79IX.json b/src/packs/items/weapons/weapon_Advanced_Whip_01izMUSJcAUo79IX.json index 142eb542..6e1753c8 100644 --- a/src/packs/items/weapons/weapon_Advanced_Whip_01izMUSJcAUo79IX.json +++ b/src/packs/items/weapons/weapon_Advanced_Whip_01izMUSJcAUo79IX.json @@ -78,8 +78,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 4, @@ -105,7 +105,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Arcane_Frame_Wheelchair_XRChepscgr75Uug7.json b/src/packs/items/weapons/weapon_Arcane_Frame_Wheelchair_XRChepscgr75Uug7.json index 6959fb30..58ef5f4b 100644 --- a/src/packs/items/weapons/weapon_Arcane_Frame_Wheelchair_XRChepscgr75Uug7.json +++ b/src/packs/items/weapons/weapon_Arcane_Frame_Wheelchair_XRChepscgr75Uug7.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": null, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Arcane_Gauntlets_PC5EyEIq7NWBV0n5.json b/src/packs/items/weapons/weapon_Arcane_Gauntlets_PC5EyEIq7NWBV0n5.json index 29afcc13..8d9e3c31 100644 --- a/src/packs/items/weapons/weapon_Arcane_Gauntlets_PC5EyEIq7NWBV0n5.json +++ b/src/packs/items/weapons/weapon_Arcane_Gauntlets_PC5EyEIq7NWBV0n5.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 3, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Axe_of_Fortunis_YcS1rHgfnSlla8Xf.json b/src/packs/items/weapons/weapon_Axe_of_Fortunis_YcS1rHgfnSlla8Xf.json index 8e4b00c5..6ce0ce68 100644 --- a/src/packs/items/weapons/weapon_Axe_of_Fortunis_YcS1rHgfnSlla8Xf.json +++ b/src/packs/items/weapons/weapon_Axe_of_Fortunis_YcS1rHgfnSlla8Xf.json @@ -78,8 +78,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 8, @@ -105,7 +105,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Battleaxe_fbDYUja3ll9vCtrB.json b/src/packs/items/weapons/weapon_Battleaxe_fbDYUja3ll9vCtrB.json index 9ab3321e..9b43f8dc 100644 --- a/src/packs/items/weapons/weapon_Battleaxe_fbDYUja3ll9vCtrB.json +++ b/src/packs/items/weapons/weapon_Battleaxe_fbDYUja3ll9vCtrB.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 3, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Black_Powder_Revolver_AokqTusPzn0hghkE.json b/src/packs/items/weapons/weapon_Black_Powder_Revolver_AokqTusPzn0hghkE.json index 34371c2b..845fee44 100644 --- a/src/packs/items/weapons/weapon_Black_Powder_Revolver_AokqTusPzn0hghkE.json +++ b/src/packs/items/weapons/weapon_Black_Powder_Revolver_AokqTusPzn0hghkE.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 8, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Bladed_Whip_5faflfNz20cFW1EM.json b/src/packs/items/weapons/weapon_Bladed_Whip_5faflfNz20cFW1EM.json index 2b2a5b9c..5238578f 100644 --- a/src/packs/items/weapons/weapon_Bladed_Whip_5faflfNz20cFW1EM.json +++ b/src/packs/items/weapons/weapon_Bladed_Whip_5faflfNz20cFW1EM.json @@ -78,8 +78,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 3, @@ -105,7 +105,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Blessed_Anlace_n1oPTk5czTIGTkVj.json b/src/packs/items/weapons/weapon_Blessed_Anlace_n1oPTk5czTIGTkVj.json index 14448edc..82140411 100644 --- a/src/packs/items/weapons/weapon_Blessed_Anlace_n1oPTk5czTIGTkVj.json +++ b/src/packs/items/weapons/weapon_Blessed_Anlace_n1oPTk5czTIGTkVj.json @@ -19,8 +19,8 @@ "amount": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "applyTo": "hitPoints", "value": { "custom": { @@ -45,7 +45,7 @@ "base": false, "type": [] } - }, + ], "includeBase": false }, "_id": "o18UvqLPWLe1A8XJ", @@ -117,8 +117,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 6, @@ -144,7 +144,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Bloodstaff_IoMVDz92WVvfGGdc.json b/src/packs/items/weapons/weapon_Bloodstaff_IoMVDz92WVvfGGdc.json index ab6bb15d..2450d69c 100644 --- a/src/packs/items/weapons/weapon_Bloodstaff_IoMVDz92WVvfGGdc.json +++ b/src/packs/items/weapons/weapon_Bloodstaff_IoMVDz92WVvfGGdc.json @@ -78,8 +78,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d20", "bonus": 7, @@ -105,7 +105,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Blunderbuss_SLFrK0WmldPo0shz.json b/src/packs/items/weapons/weapon_Blunderbuss_SLFrK0WmldPo0shz.json index 9b2f455a..1fba6130 100644 --- a/src/packs/items/weapons/weapon_Blunderbuss_SLFrK0WmldPo0shz.json +++ b/src/packs/items/weapons/weapon_Blunderbuss_SLFrK0WmldPo0shz.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 6, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Braveshield_QEvgVoz9xKBSKsGi.json b/src/packs/items/weapons/weapon_Braveshield_QEvgVoz9xKBSKsGi.json index 2f5ec85d..aef812a6 100644 --- a/src/packs/items/weapons/weapon_Braveshield_QEvgVoz9xKBSKsGi.json +++ b/src/packs/items/weapons/weapon_Braveshield_QEvgVoz9xKBSKsGi.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d4", "bonus": 6, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Bravesword_QZrWAkprA2tL2MOI.json b/src/packs/items/weapons/weapon_Bravesword_QZrWAkprA2tL2MOI.json index 412a7083..7c3e65f5 100644 --- a/src/packs/items/weapons/weapon_Bravesword_QZrWAkprA2tL2MOI.json +++ b/src/packs/items/weapons/weapon_Bravesword_QZrWAkprA2tL2MOI.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 7, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Broadsword_1cwWNt4sqlgA8gCT.json b/src/packs/items/weapons/weapon_Broadsword_1cwWNt4sqlgA8gCT.json index 87c6f7e8..0e9a557e 100644 --- a/src/packs/items/weapons/weapon_Broadsword_1cwWNt4sqlgA8gCT.json +++ b/src/packs/items/weapons/weapon_Broadsword_1cwWNt4sqlgA8gCT.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "type": [ "physical" ], @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Buckler_EmFTp9wzT6MHSaNz.json b/src/packs/items/weapons/weapon_Buckler_EmFTp9wzT6MHSaNz.json index be147888..4d815a6c 100644 --- a/src/packs/items/weapons/weapon_Buckler_EmFTp9wzT6MHSaNz.json +++ b/src/packs/items/weapons/weapon_Buckler_EmFTp9wzT6MHSaNz.json @@ -87,8 +87,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d4", "bonus": 4, @@ -114,7 +114,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Casting_Sword_2Fbf2cxLfbdGkU4I.json b/src/packs/items/weapons/weapon_Casting_Sword_2Fbf2cxLfbdGkU4I.json index c861e735..9af34d45 100644 --- a/src/packs/items/weapons/weapon_Casting_Sword_2Fbf2cxLfbdGkU4I.json +++ b/src/packs/items/weapons/weapon_Casting_Sword_2Fbf2cxLfbdGkU4I.json @@ -11,8 +11,8 @@ "type": "attack", "damage": { "includeBase": false, - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -36,7 +36,7 @@ } } } - } + ] }, "range": "far", "roll": { @@ -113,8 +113,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 4, @@ -140,7 +140,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Crossbow_cw7HG1Z7hp7OOLD0.json b/src/packs/items/weapons/weapon_Crossbow_cw7HG1Z7hp7OOLD0.json index 62ad7f3d..749ef4aa 100644 --- a/src/packs/items/weapons/weapon_Crossbow_cw7HG1Z7hp7OOLD0.json +++ b/src/packs/items/weapons/weapon_Crossbow_cw7HG1Z7hp7OOLD0.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 1, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Curved_Dagger_Fk69R40svV0kanZD.json b/src/packs/items/weapons/weapon_Curved_Dagger_Fk69R40svV0kanZD.json index 1af2c372..a98a56b1 100644 --- a/src/packs/items/weapons/weapon_Curved_Dagger_Fk69R40svV0kanZD.json +++ b/src/packs/items/weapons/weapon_Curved_Dagger_Fk69R40svV0kanZD.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 9, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Cutlass_CWrbnethuILXrEpA.json b/src/packs/items/weapons/weapon_Cutlass_CWrbnethuILXrEpA.json index 4750891f..7343b92c 100644 --- a/src/packs/items/weapons/weapon_Cutlass_CWrbnethuILXrEpA.json +++ b/src/packs/items/weapons/weapon_Cutlass_CWrbnethuILXrEpA.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 1, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Dagger_iStO0BbeMTTR0rQi.json b/src/packs/items/weapons/weapon_Dagger_iStO0BbeMTTR0rQi.json index 4818c79f..5ef12e05 100644 --- a/src/packs/items/weapons/weapon_Dagger_iStO0BbeMTTR0rQi.json +++ b/src/packs/items/weapons/weapon_Dagger_iStO0BbeMTTR0rQi.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 1, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Devouring_Dagger_C5wSGglR8e0euQnY.json b/src/packs/items/weapons/weapon_Devouring_Dagger_C5wSGglR8e0euQnY.json index 7775501d..e00d665c 100644 --- a/src/packs/items/weapons/weapon_Devouring_Dagger_C5wSGglR8e0euQnY.json +++ b/src/packs/items/weapons/weapon_Devouring_Dagger_C5wSGglR8e0euQnY.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 4, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Double_Flail_xm1yU7k58fMgXxRR.json b/src/packs/items/weapons/weapon_Double_Flail_xm1yU7k58fMgXxRR.json index e5b603c6..a118b399 100644 --- a/src/packs/items/weapons/weapon_Double_Flail_xm1yU7k58fMgXxRR.json +++ b/src/packs/items/weapons/weapon_Double_Flail_xm1yU7k58fMgXxRR.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 8, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Dual_Ended_Sword_nXjuBa215H1sTUK3.json b/src/packs/items/weapons/weapon_Dual_Ended_Sword_nXjuBa215H1sTUK3.json index df1c3e54..da15604c 100644 --- a/src/packs/items/weapons/weapon_Dual_Ended_Sword_nXjuBa215H1sTUK3.json +++ b/src/packs/items/weapons/weapon_Dual_Ended_Sword_nXjuBa215H1sTUK3.json @@ -78,8 +78,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 9, @@ -105,7 +105,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Dualstaff_j8cdNeIUYxxzFVji.json b/src/packs/items/weapons/weapon_Dualstaff_j8cdNeIUYxxzFVji.json index a3b44d76..e7c458c3 100644 --- a/src/packs/items/weapons/weapon_Dualstaff_j8cdNeIUYxxzFVji.json +++ b/src/packs/items/weapons/weapon_Dualstaff_j8cdNeIUYxxzFVji.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 3, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Ego_Blade_G7rH31KQ5eEZXcv0.json b/src/packs/items/weapons/weapon_Ego_Blade_G7rH31KQ5eEZXcv0.json index 17e24aea..36d3b0ba 100644 --- a/src/packs/items/weapons/weapon_Ego_Blade_G7rH31KQ5eEZXcv0.json +++ b/src/packs/items/weapons/weapon_Ego_Blade_G7rH31KQ5eEZXcv0.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d12", "bonus": 4, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Elder_Bow_JdWcn9W1edhAEInL.json b/src/packs/items/weapons/weapon_Elder_Bow_JdWcn9W1edhAEInL.json index 73bb5a46..35659402 100644 --- a/src/packs/items/weapons/weapon_Elder_Bow_JdWcn9W1edhAEInL.json +++ b/src/packs/items/weapons/weapon_Elder_Bow_JdWcn9W1edhAEInL.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 4, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Extended_Polearm_fJHKMxZokVP34MCi.json b/src/packs/items/weapons/weapon_Extended_Polearm_fJHKMxZokVP34MCi.json index 35829bd5..62bcb3e0 100644 --- a/src/packs/items/weapons/weapon_Extended_Polearm_fJHKMxZokVP34MCi.json +++ b/src/packs/items/weapons/weapon_Extended_Polearm_fJHKMxZokVP34MCi.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 10, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Finehair_Bow_ykF3jouxHZ6YR8Bg.json b/src/packs/items/weapons/weapon_Finehair_Bow_ykF3jouxHZ6YR8Bg.json index d1bd58b5..6dc27659 100644 --- a/src/packs/items/weapons/weapon_Finehair_Bow_ykF3jouxHZ6YR8Bg.json +++ b/src/packs/items/weapons/weapon_Finehair_Bow_ykF3jouxHZ6YR8Bg.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 5, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Firestaff_BtCm2RhWEfs00g38.json b/src/packs/items/weapons/weapon_Firestaff_BtCm2RhWEfs00g38.json index ba7350f4..983f98d1 100644 --- a/src/packs/items/weapons/weapon_Firestaff_BtCm2RhWEfs00g38.json +++ b/src/packs/items/weapons/weapon_Firestaff_BtCm2RhWEfs00g38.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 7, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Flickerfly_Blade_xLJ5RRpUoTRmAC3G.json b/src/packs/items/weapons/weapon_Flickerfly_Blade_xLJ5RRpUoTRmAC3G.json index acf0cfd6..5dd5f04e 100644 --- a/src/packs/items/weapons/weapon_Flickerfly_Blade_xLJ5RRpUoTRmAC3G.json +++ b/src/packs/items/weapons/weapon_Flickerfly_Blade_xLJ5RRpUoTRmAC3G.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 5, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Floating_Bladeshards_3vti3xfo0wJND7ew.json b/src/packs/items/weapons/weapon_Floating_Bladeshards_3vti3xfo0wJND7ew.json index 0460e12d..232f26e9 100644 --- a/src/packs/items/weapons/weapon_Floating_Bladeshards_3vti3xfo0wJND7ew.json +++ b/src/packs/items/weapons/weapon_Floating_Bladeshards_3vti3xfo0wJND7ew.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 9, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Fusion_Gloves_uK1RhtYAsDeoPNGx.json b/src/packs/items/weapons/weapon_Fusion_Gloves_uK1RhtYAsDeoPNGx.json index 034ad5cf..747bc046 100644 --- a/src/packs/items/weapons/weapon_Fusion_Gloves_uK1RhtYAsDeoPNGx.json +++ b/src/packs/items/weapons/weapon_Fusion_Gloves_uK1RhtYAsDeoPNGx.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 9, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Ghostblade_6gFvOFTE97QZ74Zr.json b/src/packs/items/weapons/weapon_Ghostblade_6gFvOFTE97QZ74Zr.json index 0e17e0c2..7784b43d 100644 --- a/src/packs/items/weapons/weapon_Ghostblade_6gFvOFTE97QZ74Zr.json +++ b/src/packs/items/weapons/weapon_Ghostblade_6gFvOFTE97QZ74Zr.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 7, @@ -69,7 +69,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Gilded_Bow_ctTgFfMbM3YtmsYU.json b/src/packs/items/weapons/weapon_Gilded_Bow_ctTgFfMbM3YtmsYU.json index 0147cfdb..88f5a163 100644 --- a/src/packs/items/weapons/weapon_Gilded_Bow_ctTgFfMbM3YtmsYU.json +++ b/src/packs/items/weapons/weapon_Gilded_Bow_ctTgFfMbM3YtmsYU.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 7, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Gilded_Falchion_VwcOgqnzjf9LBj2S.json b/src/packs/items/weapons/weapon_Gilded_Falchion_VwcOgqnzjf9LBj2S.json index fdf5835e..ee8afebc 100644 --- a/src/packs/items/weapons/weapon_Gilded_Falchion_VwcOgqnzjf9LBj2S.json +++ b/src/packs/items/weapons/weapon_Gilded_Falchion_VwcOgqnzjf9LBj2S.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 4, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Glowing_Rings_wG9f5NpCwSbaLy8t.json b/src/packs/items/weapons/weapon_Glowing_Rings_wG9f5NpCwSbaLy8t.json index 3879c599..59963b03 100644 --- a/src/packs/items/weapons/weapon_Glowing_Rings_wG9f5NpCwSbaLy8t.json +++ b/src/packs/items/weapons/weapon_Glowing_Rings_wG9f5NpCwSbaLy8t.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 2, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Grappler_iEzPscUc18GuFoB6.json b/src/packs/items/weapons/weapon_Grappler_iEzPscUc18GuFoB6.json index 9a9158c7..7f42998b 100644 --- a/src/packs/items/weapons/weapon_Grappler_iEzPscUc18GuFoB6.json +++ b/src/packs/items/weapons/weapon_Grappler_iEzPscUc18GuFoB6.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": null, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Greatbow_MXBpbqQsZFln4rZk.json b/src/packs/items/weapons/weapon_Greatbow_MXBpbqQsZFln4rZk.json index 87118bb8..f56e77c7 100644 --- a/src/packs/items/weapons/weapon_Greatbow_MXBpbqQsZFln4rZk.json +++ b/src/packs/items/weapons/weapon_Greatbow_MXBpbqQsZFln4rZk.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 6, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Greatstaff_Yk8pTEmyLLi4095S.json b/src/packs/items/weapons/weapon_Greatstaff_Yk8pTEmyLLi4095S.json index 798541d1..66c12e5e 100644 --- a/src/packs/items/weapons/weapon_Greatstaff_Yk8pTEmyLLi4095S.json +++ b/src/packs/items/weapons/weapon_Greatstaff_Yk8pTEmyLLi4095S.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": null, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Greatsword_70ysaFJDREwTgvZa.json b/src/packs/items/weapons/weapon_Greatsword_70ysaFJDREwTgvZa.json index f0e450a4..f60e438d 100644 --- a/src/packs/items/weapons/weapon_Greatsword_70ysaFJDREwTgvZa.json +++ b/src/packs/items/weapons/weapon_Greatsword_70ysaFJDREwTgvZa.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 3, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Halberd_qT7FfmauAumOjJoq.json b/src/packs/items/weapons/weapon_Halberd_qT7FfmauAumOjJoq.json index 5a990da3..6259e63e 100644 --- a/src/packs/items/weapons/weapon_Halberd_qT7FfmauAumOjJoq.json +++ b/src/packs/items/weapons/weapon_Halberd_qT7FfmauAumOjJoq.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 2, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Hallowed_Axe_Vayg7CnRTFBrunjM.json b/src/packs/items/weapons/weapon_Hallowed_Axe_Vayg7CnRTFBrunjM.json index 1fe37eba..9d8885b9 100644 --- a/src/packs/items/weapons/weapon_Hallowed_Axe_Vayg7CnRTFBrunjM.json +++ b/src/packs/items/weapons/weapon_Hallowed_Axe_Vayg7CnRTFBrunjM.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 1, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Hammer_of_Exota_0lAkBEUvbM9Osmqb.json b/src/packs/items/weapons/weapon_Hammer_of_Exota_0lAkBEUvbM9Osmqb.json index 15e00303..ba955850 100644 --- a/src/packs/items/weapons/weapon_Hammer_of_Exota_0lAkBEUvbM9Osmqb.json +++ b/src/packs/items/weapons/weapon_Hammer_of_Exota_0lAkBEUvbM9Osmqb.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 6, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Hammer_of_Wrath_1R4uzOpWD8bkYRUm.json b/src/packs/items/weapons/weapon_Hammer_of_Wrath_1R4uzOpWD8bkYRUm.json index fdab6f80..122c0769 100644 --- a/src/packs/items/weapons/weapon_Hammer_of_Wrath_1R4uzOpWD8bkYRUm.json +++ b/src/packs/items/weapons/weapon_Hammer_of_Wrath_1R4uzOpWD8bkYRUm.json @@ -78,8 +78,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 7, @@ -105,7 +105,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Hand_Cannon_MyGz8nd5sieRQ7zl.json b/src/packs/items/weapons/weapon_Hand_Cannon_MyGz8nd5sieRQ7zl.json index 4967c6e4..1396fb1d 100644 --- a/src/packs/items/weapons/weapon_Hand_Cannon_MyGz8nd5sieRQ7zl.json +++ b/src/packs/items/weapons/weapon_Hand_Cannon_MyGz8nd5sieRQ7zl.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 12, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Hand_Crossbow_zxKt6qXe7uZB6ljm.json b/src/packs/items/weapons/weapon_Hand_Crossbow_zxKt6qXe7uZB6ljm.json index 6501f5d4..9f69ffc9 100644 --- a/src/packs/items/weapons/weapon_Hand_Crossbow_zxKt6qXe7uZB6ljm.json +++ b/src/packs/items/weapons/weapon_Hand_Crossbow_zxKt6qXe7uZB6ljm.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 1, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Hand_Runes_3whiedn0jBMNRdIb.json b/src/packs/items/weapons/weapon_Hand_Runes_3whiedn0jBMNRdIb.json index 00cb6e9b..32761768 100644 --- a/src/packs/items/weapons/weapon_Hand_Runes_3whiedn0jBMNRdIb.json +++ b/src/packs/items/weapons/weapon_Hand_Runes_3whiedn0jBMNRdIb.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": null, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Hand_Sling_RAIaoMi6iO1PKIlK.json b/src/packs/items/weapons/weapon_Hand_Sling_RAIaoMi6iO1PKIlK.json index 5c110b70..82641ca1 100644 --- a/src/packs/items/weapons/weapon_Hand_Sling_RAIaoMi6iO1PKIlK.json +++ b/src/packs/items/weapons/weapon_Hand_Sling_RAIaoMi6iO1PKIlK.json @@ -11,8 +11,8 @@ "type": "attack", "damage": { "includeBase": false, - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -36,7 +36,7 @@ } } } - } + ] }, "range": "close", "roll": { @@ -113,8 +113,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 4, @@ -140,7 +140,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Heavy_Frame_Wheelchair_XjPQjhRCH08VUIbr.json b/src/packs/items/weapons/weapon_Heavy_Frame_Wheelchair_XjPQjhRCH08VUIbr.json index e74ff4aa..db20063d 100644 --- a/src/packs/items/weapons/weapon_Heavy_Frame_Wheelchair_XjPQjhRCH08VUIbr.json +++ b/src/packs/items/weapons/weapon_Heavy_Frame_Wheelchair_XjPQjhRCH08VUIbr.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d12", "bonus": 3, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Ilmari_s_Rifle_TMrUzVC3KvcHmdt8.json b/src/packs/items/weapons/weapon_Ilmari_s_Rifle_TMrUzVC3KvcHmdt8.json index cddd762a..8234ab3a 100644 --- a/src/packs/items/weapons/weapon_Ilmari_s_Rifle_TMrUzVC3KvcHmdt8.json +++ b/src/packs/items/weapons/weapon_Ilmari_s_Rifle_TMrUzVC3KvcHmdt8.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 6, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Impact_Gauntlet_Zg6IutksQVOqAg8K.json b/src/packs/items/weapons/weapon_Impact_Gauntlet_Zg6IutksQVOqAg8K.json index 5e9891f9..8c8cc81d 100644 --- a/src/packs/items/weapons/weapon_Impact_Gauntlet_Zg6IutksQVOqAg8K.json +++ b/src/packs/items/weapons/weapon_Impact_Gauntlet_Zg6IutksQVOqAg8K.json @@ -78,8 +78,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 11, @@ -105,7 +105,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Arcane_Frame_Wheelchair_N9P695V5KKlJbAY5.json b/src/packs/items/weapons/weapon_Improved_Arcane_Frame_Wheelchair_N9P695V5KKlJbAY5.json index 33f96030..fad45a2b 100644 --- a/src/packs/items/weapons/weapon_Improved_Arcane_Frame_Wheelchair_N9P695V5KKlJbAY5.json +++ b/src/packs/items/weapons/weapon_Improved_Arcane_Frame_Wheelchair_N9P695V5KKlJbAY5.json @@ -48,8 +48,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 3, @@ -75,7 +75,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Arcane_Gauntlets_kENTDpa1hr5LDhIT.json b/src/packs/items/weapons/weapon_Improved_Arcane_Gauntlets_kENTDpa1hr5LDhIT.json index 1880d45b..40b85dde 100644 --- a/src/packs/items/weapons/weapon_Improved_Arcane_Gauntlets_kENTDpa1hr5LDhIT.json +++ b/src/packs/items/weapons/weapon_Improved_Arcane_Gauntlets_kENTDpa1hr5LDhIT.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 6, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Battleaxe_nxGUpuHLmuKdKsDC.json b/src/packs/items/weapons/weapon_Improved_Battleaxe_nxGUpuHLmuKdKsDC.json index 4652d62d..23068751 100644 --- a/src/packs/items/weapons/weapon_Improved_Battleaxe_nxGUpuHLmuKdKsDC.json +++ b/src/packs/items/weapons/weapon_Improved_Battleaxe_nxGUpuHLmuKdKsDC.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 6, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Broadsword_OcKeLJxvmdT81VBc.json b/src/packs/items/weapons/weapon_Improved_Broadsword_OcKeLJxvmdT81VBc.json index 6d6f1921..a17caadf 100644 --- a/src/packs/items/weapons/weapon_Improved_Broadsword_OcKeLJxvmdT81VBc.json +++ b/src/packs/items/weapons/weapon_Improved_Broadsword_OcKeLJxvmdT81VBc.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 3, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Crossbow_55NwHIIZHUeKSE3M.json b/src/packs/items/weapons/weapon_Improved_Crossbow_55NwHIIZHUeKSE3M.json index 5bc082ef..185f8f11 100644 --- a/src/packs/items/weapons/weapon_Improved_Crossbow_55NwHIIZHUeKSE3M.json +++ b/src/packs/items/weapons/weapon_Improved_Crossbow_55NwHIIZHUeKSE3M.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 4, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Cutlass_ddRjXnp2vbohu7rJ.json b/src/packs/items/weapons/weapon_Improved_Cutlass_ddRjXnp2vbohu7rJ.json index 87dfbfae..520e5679 100644 --- a/src/packs/items/weapons/weapon_Improved_Cutlass_ddRjXnp2vbohu7rJ.json +++ b/src/packs/items/weapons/weapon_Improved_Cutlass_ddRjXnp2vbohu7rJ.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 4, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Dagger_ScjTkb9qrndhlk9S.json b/src/packs/items/weapons/weapon_Improved_Dagger_ScjTkb9qrndhlk9S.json index 194ec879..1db4504e 100644 --- a/src/packs/items/weapons/weapon_Improved_Dagger_ScjTkb9qrndhlk9S.json +++ b/src/packs/items/weapons/weapon_Improved_Dagger_ScjTkb9qrndhlk9S.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 4, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Dualstaff_f7hhHlZ5nL3AhYEM.json b/src/packs/items/weapons/weapon_Improved_Dualstaff_f7hhHlZ5nL3AhYEM.json index d614130e..84cc75ba 100644 --- a/src/packs/items/weapons/weapon_Improved_Dualstaff_f7hhHlZ5nL3AhYEM.json +++ b/src/packs/items/weapons/weapon_Improved_Dualstaff_f7hhHlZ5nL3AhYEM.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 6, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Glowing_Rings_N5amhkxR1xn3B7r2.json b/src/packs/items/weapons/weapon_Improved_Glowing_Rings_N5amhkxR1xn3B7r2.json index f8b29720..01439f5b 100644 --- a/src/packs/items/weapons/weapon_Improved_Glowing_Rings_N5amhkxR1xn3B7r2.json +++ b/src/packs/items/weapons/weapon_Improved_Glowing_Rings_N5amhkxR1xn3B7r2.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 5, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Grappler_3T3o9zfe61t22L1H.json b/src/packs/items/weapons/weapon_Improved_Grappler_3T3o9zfe61t22L1H.json index 31dfff22..74ee510a 100644 --- a/src/packs/items/weapons/weapon_Improved_Grappler_3T3o9zfe61t22L1H.json +++ b/src/packs/items/weapons/weapon_Improved_Grappler_3T3o9zfe61t22L1H.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 2, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Greatstaff_LCuTrYXi4lhg6LqW.json b/src/packs/items/weapons/weapon_Improved_Greatstaff_LCuTrYXi4lhg6LqW.json index 25be3393..cf1bdf63 100644 --- a/src/packs/items/weapons/weapon_Improved_Greatstaff_LCuTrYXi4lhg6LqW.json +++ b/src/packs/items/weapons/weapon_Improved_Greatstaff_LCuTrYXi4lhg6LqW.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 3, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Greatsword_FPX4ouDrxXiQ5MDf.json b/src/packs/items/weapons/weapon_Improved_Greatsword_FPX4ouDrxXiQ5MDf.json index 60e5dd53..f71e5ea6 100644 --- a/src/packs/items/weapons/weapon_Improved_Greatsword_FPX4ouDrxXiQ5MDf.json +++ b/src/packs/items/weapons/weapon_Improved_Greatsword_FPX4ouDrxXiQ5MDf.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 6, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Halberd_F9PETfCQGwczBPif.json b/src/packs/items/weapons/weapon_Improved_Halberd_F9PETfCQGwczBPif.json index fb5a1dcc..168d8953 100644 --- a/src/packs/items/weapons/weapon_Improved_Halberd_F9PETfCQGwczBPif.json +++ b/src/packs/items/weapons/weapon_Improved_Halberd_F9PETfCQGwczBPif.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 5, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Hallowed_Axe_wFOXMN2uiX4j6Gd9.json b/src/packs/items/weapons/weapon_Improved_Hallowed_Axe_wFOXMN2uiX4j6Gd9.json index 71b28bea..a79ad56d 100644 --- a/src/packs/items/weapons/weapon_Improved_Hallowed_Axe_wFOXMN2uiX4j6Gd9.json +++ b/src/packs/items/weapons/weapon_Improved_Hallowed_Axe_wFOXMN2uiX4j6Gd9.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 4, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Hand_Crossbow_XEDRkuw3BhMoVBn9.json b/src/packs/items/weapons/weapon_Improved_Hand_Crossbow_XEDRkuw3BhMoVBn9.json index 91641856..74e74f2c 100644 --- a/src/packs/items/weapons/weapon_Improved_Hand_Crossbow_XEDRkuw3BhMoVBn9.json +++ b/src/packs/items/weapons/weapon_Improved_Hand_Crossbow_XEDRkuw3BhMoVBn9.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 3, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Hand_Runes_jMEukC3VpNDz5AOD.json b/src/packs/items/weapons/weapon_Improved_Hand_Runes_jMEukC3VpNDz5AOD.json index dc7f2005..546e9762 100644 --- a/src/packs/items/weapons/weapon_Improved_Hand_Runes_jMEukC3VpNDz5AOD.json +++ b/src/packs/items/weapons/weapon_Improved_Hand_Runes_jMEukC3VpNDz5AOD.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 3, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Heavy_Frame_Wheelchair_L5KeCtrs768PmYWW.json b/src/packs/items/weapons/weapon_Improved_Heavy_Frame_Wheelchair_L5KeCtrs768PmYWW.json index e65cc221..3a386fa8 100644 --- a/src/packs/items/weapons/weapon_Improved_Heavy_Frame_Wheelchair_L5KeCtrs768PmYWW.json +++ b/src/packs/items/weapons/weapon_Improved_Heavy_Frame_Wheelchair_L5KeCtrs768PmYWW.json @@ -48,8 +48,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d12", "bonus": 6, @@ -75,7 +75,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Light_Frame_Wheelchair_ZJsetdHKV77ygtCE.json b/src/packs/items/weapons/weapon_Improved_Light_Frame_Wheelchair_ZJsetdHKV77ygtCE.json index 315ceaf3..6fbe3c9d 100644 --- a/src/packs/items/weapons/weapon_Improved_Light_Frame_Wheelchair_ZJsetdHKV77ygtCE.json +++ b/src/packs/items/weapons/weapon_Improved_Light_Frame_Wheelchair_ZJsetdHKV77ygtCE.json @@ -77,8 +77,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 3, @@ -104,7 +104,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Longbow_NacNonjbzyoVMNhI.json b/src/packs/items/weapons/weapon_Improved_Longbow_NacNonjbzyoVMNhI.json index c197f726..787d5a28 100644 --- a/src/packs/items/weapons/weapon_Improved_Longbow_NacNonjbzyoVMNhI.json +++ b/src/packs/items/weapons/weapon_Improved_Longbow_NacNonjbzyoVMNhI.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 6, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Longsword_QyBZ5NxM8F9nCL9s.json b/src/packs/items/weapons/weapon_Improved_Longsword_QyBZ5NxM8F9nCL9s.json index aaa38270..982ca3ac 100644 --- a/src/packs/items/weapons/weapon_Improved_Longsword_QyBZ5NxM8F9nCL9s.json +++ b/src/packs/items/weapons/weapon_Improved_Longsword_QyBZ5NxM8F9nCL9s.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 6, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Mace_zSLx52U4Yltqx8F1.json b/src/packs/items/weapons/weapon_Improved_Mace_zSLx52U4Yltqx8F1.json index 1ce84304..c1b626d5 100644 --- a/src/packs/items/weapons/weapon_Improved_Mace_zSLx52U4Yltqx8F1.json +++ b/src/packs/items/weapons/weapon_Improved_Mace_zSLx52U4Yltqx8F1.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 4, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Quarterstaff_BEmAR60PM3ZaiNXa.json b/src/packs/items/weapons/weapon_Improved_Quarterstaff_BEmAR60PM3ZaiNXa.json index 9dc81b98..888022ed 100644 --- a/src/packs/items/weapons/weapon_Improved_Quarterstaff_BEmAR60PM3ZaiNXa.json +++ b/src/packs/items/weapons/weapon_Improved_Quarterstaff_BEmAR60PM3ZaiNXa.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 6, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Rapier_LFPH8nD2f4Blv3AM.json b/src/packs/items/weapons/weapon_Improved_Rapier_LFPH8nD2f4Blv3AM.json index e9db95d1..cc6099da 100644 --- a/src/packs/items/weapons/weapon_Improved_Rapier_LFPH8nD2f4Blv3AM.json +++ b/src/packs/items/weapons/weapon_Improved_Rapier_LFPH8nD2f4Blv3AM.json @@ -78,8 +78,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 3, @@ -105,7 +105,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Returning_Blade_SKNwkW23eVQjN4Zy.json b/src/packs/items/weapons/weapon_Improved_Returning_Blade_SKNwkW23eVQjN4Zy.json index 1dff30a1..31688a23 100644 --- a/src/packs/items/weapons/weapon_Improved_Returning_Blade_SKNwkW23eVQjN4Zy.json +++ b/src/packs/items/weapons/weapon_Improved_Returning_Blade_SKNwkW23eVQjN4Zy.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 3, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Round_Shield_DlinEBGZfIlvreO3.json b/src/packs/items/weapons/weapon_Improved_Round_Shield_DlinEBGZfIlvreO3.json index 65868950..53a8e9b6 100644 --- a/src/packs/items/weapons/weapon_Improved_Round_Shield_DlinEBGZfIlvreO3.json +++ b/src/packs/items/weapons/weapon_Improved_Round_Shield_DlinEBGZfIlvreO3.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d4", "bonus": 2, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", @@ -113,26 +113,26 @@ "name": "Protective", "description": "

Add the item's Tier to your Armor Score

", "img": "icons/skills/melee/shield-block-gray-orange.webp", - "_id": "pZCrWd7zLTarvEQK", + "changes": [ + { + "key": "system.armorScore", + "mode": 2, + "value": "ITEM.@system.tier", + "priority": null + } + ], + "_id": "cXWSV50apzaNQkdA", "type": "base", - "system": { - "changes": [ - { - "type": "armor", - "phase": "initial", - "priority": 20, - "value": { - "max": "ITEM.@system.tier" - } - } - ] - }, + "system": {}, "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "origin": null, "tint": "#ffffff", @@ -143,10 +143,7 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, - "_key": "!items.effects!DlinEBGZfIlvreO3.pZCrWd7zLTarvEQK" + "_key": "!items.effects!DlinEBGZfIlvreO3.cXWSV50apzaNQkdA" } ], "sort": 0, diff --git a/src/packs/items/weapons/weapon_Improved_Scepter_tj26lbNkwy8bORF4.json b/src/packs/items/weapons/weapon_Improved_Scepter_tj26lbNkwy8bORF4.json index ac226b84..dc41692f 100644 --- a/src/packs/items/weapons/weapon_Improved_Scepter_tj26lbNkwy8bORF4.json +++ b/src/packs/items/weapons/weapon_Improved_Scepter_tj26lbNkwy8bORF4.json @@ -11,8 +11,8 @@ "type": "attack", "damage": { "includeBase": false, - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -38,7 +38,7 @@ } } } - } + ] }, "range": "melee", "roll": { @@ -115,8 +115,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 3, @@ -142,7 +142,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Shortbow_6ZWl6ARfvYBaAMwY.json b/src/packs/items/weapons/weapon_Improved_Shortbow_6ZWl6ARfvYBaAMwY.json index b0e101fb..421b8f8e 100644 --- a/src/packs/items/weapons/weapon_Improved_Shortbow_6ZWl6ARfvYBaAMwY.json +++ b/src/packs/items/weapons/weapon_Improved_Shortbow_6ZWl6ARfvYBaAMwY.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 6, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Shortstaff_Mn8ja5Oi1sXvvPSk.json b/src/packs/items/weapons/weapon_Improved_Shortstaff_Mn8ja5Oi1sXvvPSk.json index 7d90cf94..08bf9251 100644 --- a/src/packs/items/weapons/weapon_Improved_Shortstaff_Mn8ja5Oi1sXvvPSk.json +++ b/src/packs/items/weapons/weapon_Improved_Shortstaff_Mn8ja5Oi1sXvvPSk.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 4, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Shortsword_rSyBNRwemBVuTo3H.json b/src/packs/items/weapons/weapon_Improved_Shortsword_rSyBNRwemBVuTo3H.json index 96ecd37f..df2f324c 100644 --- a/src/packs/items/weapons/weapon_Improved_Shortsword_rSyBNRwemBVuTo3H.json +++ b/src/packs/items/weapons/weapon_Improved_Shortsword_rSyBNRwemBVuTo3H.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 2, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Small_Dagger_nMuF8ZDZ2aXZVTg6.json b/src/packs/items/weapons/weapon_Improved_Small_Dagger_nMuF8ZDZ2aXZVTg6.json index 1553d75d..b69332a5 100644 --- a/src/packs/items/weapons/weapon_Improved_Small_Dagger_nMuF8ZDZ2aXZVTg6.json +++ b/src/packs/items/weapons/weapon_Improved_Small_Dagger_nMuF8ZDZ2aXZVTg6.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 2, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Spear_j5Pt1thLfcvopBij.json b/src/packs/items/weapons/weapon_Improved_Spear_j5Pt1thLfcvopBij.json index 790f9e51..ae6b0987 100644 --- a/src/packs/items/weapons/weapon_Improved_Spear_j5Pt1thLfcvopBij.json +++ b/src/packs/items/weapons/weapon_Improved_Spear_j5Pt1thLfcvopBij.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 6, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Tower_Shield_bxt3NsbMqTSdI5ab.json b/src/packs/items/weapons/weapon_Improved_Tower_Shield_bxt3NsbMqTSdI5ab.json index 64555dfa..839d4352 100644 --- a/src/packs/items/weapons/weapon_Improved_Tower_Shield_bxt3NsbMqTSdI5ab.json +++ b/src/packs/items/weapons/weapon_Improved_Tower_Shield_bxt3NsbMqTSdI5ab.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 2, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", @@ -113,25 +113,25 @@ "name": "Barrier", "description": "Gain Weapon Tier + 1 to Armor Score; -1 to Evasion", "img": "icons/skills/melee/shield-block-bash-blue.webp", + "changes": [ + { + "key": "system.armorScore", + "mode": 2, + "value": "ITEM.@system.tier + 1" + }, + { + "key": "system.evasion", + "mode": 2, + "value": "-1" + } + ], "_id": "tkNEA1PO3jEFhKCa", "type": "base", - "system": { - "changes": [ - { - "key": "system.evasion", - "type": "add", - "value": -1, - "phase": "initial", - "priority": 0 - } - ] - }, + "system": {}, "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null }, "origin": null, "tint": "#ffffff", @@ -142,49 +142,7 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, "_key": "!items.effects!bxt3NsbMqTSdI5ab.tkNEA1PO3jEFhKCa" - }, - { - "name": "Barrier", - "description": "Gain Weapon Tier + 1 to Armor Score; -1 to Evasion", - "img": "icons/skills/melee/shield-block-bash-blue.webp", - "_id": "XugJeHJdnC6IymSa", - "type": "base", - "system": { - "changes": [ - { - "type": "armor", - "phase": "initial", - "priority": 20, - "value": { - "max": "ITEM.@system.tier + 1" - } - } - ] - }, - "disabled": false, - "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false - }, - "origin": null, - "tint": "#ffffff", - "transfer": true, - "statuses": [], - "sort": 0, - "flags": {}, - "_stats": { - "compendiumSource": null - }, - "start": null, - "showIcon": 1, - "folder": null, - "_key": "!items.effects!bxt3NsbMqTSdI5ab.XugJeHJdnC6IymSa" } ], "sort": 0, diff --git a/src/packs/items/weapons/weapon_Improved_Wand_6d9B2b5X2d2U56jt.json b/src/packs/items/weapons/weapon_Improved_Wand_6d9B2b5X2d2U56jt.json index 53ee6746..cecb818d 100644 --- a/src/packs/items/weapons/weapon_Improved_Wand_6d9B2b5X2d2U56jt.json +++ b/src/packs/items/weapons/weapon_Improved_Wand_6d9B2b5X2d2U56jt.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 4, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Warhammer_pxaN4ZK4eqKrjtWj.json b/src/packs/items/weapons/weapon_Improved_Warhammer_pxaN4ZK4eqKrjtWj.json index aa24c4ad..40a5faba 100644 --- a/src/packs/items/weapons/weapon_Improved_Warhammer_pxaN4ZK4eqKrjtWj.json +++ b/src/packs/items/weapons/weapon_Improved_Warhammer_pxaN4ZK4eqKrjtWj.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d12", "bonus": 6, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Improved_Whip_ftTp8VlsBQ1r4LFD.json b/src/packs/items/weapons/weapon_Improved_Whip_ftTp8VlsBQ1r4LFD.json index 4dd1dcb1..dff7fb25 100644 --- a/src/packs/items/weapons/weapon_Improved_Whip_ftTp8VlsBQ1r4LFD.json +++ b/src/packs/items/weapons/weapon_Improved_Whip_ftTp8VlsBQ1r4LFD.json @@ -78,8 +78,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 2, @@ -105,7 +105,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Keeper_s_Staff_q382JqMkqLaaFLIr.json b/src/packs/items/weapons/weapon_Keeper_s_Staff_q382JqMkqLaaFLIr.json index 21fe863b..27b8044b 100644 --- a/src/packs/items/weapons/weapon_Keeper_s_Staff_q382JqMkqLaaFLIr.json +++ b/src/packs/items/weapons/weapon_Keeper_s_Staff_q382JqMkqLaaFLIr.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 4, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Knuckle_Blades_U8gfyvxoHm024inM.json b/src/packs/items/weapons/weapon_Knuckle_Blades_U8gfyvxoHm024inM.json index ffe92071..a5d00ff4 100644 --- a/src/packs/items/weapons/weapon_Knuckle_Blades_U8gfyvxoHm024inM.json +++ b/src/packs/items/weapons/weapon_Knuckle_Blades_U8gfyvxoHm024inM.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 6, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Knuckle_Claws_SFqganS8Du4aEKjQ.json b/src/packs/items/weapons/weapon_Knuckle_Claws_SFqganS8Du4aEKjQ.json index a7629e7d..df995a3f 100644 --- a/src/packs/items/weapons/weapon_Knuckle_Claws_SFqganS8Du4aEKjQ.json +++ b/src/packs/items/weapons/weapon_Knuckle_Claws_SFqganS8Du4aEKjQ.json @@ -72,8 +72,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 8, @@ -99,7 +99,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Labrys_Axe_ijWppQzSOqVCb3rE.json b/src/packs/items/weapons/weapon_Labrys_Axe_ijWppQzSOqVCb3rE.json index d5af9b14..3c11528e 100644 --- a/src/packs/items/weapons/weapon_Labrys_Axe_ijWppQzSOqVCb3rE.json +++ b/src/packs/items/weapons/weapon_Labrys_Axe_ijWppQzSOqVCb3rE.json @@ -5,7 +5,7 @@ "_id": "ijWppQzSOqVCb3rE", "img": "icons/weapons/axes/axe-battle-jagged.webp", "system": { - "description": "Protective: +1 to Armor Score", + "description": "Protective: +1 to Armor Score", "actions": {}, "attached": [], "tier": 3, @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 7, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", @@ -105,26 +105,20 @@ "name": "Protective", "description": "+1 to Armor Score", "img": "icons/magic/defensive/shield-barrier-deflect-teal.webp", - "_id": "vnR4Zhnb0rOqwrFw", + "changes": [ + { + "key": "system.armorScore", + "mode": 2, + "value": "1" + } + ], + "_id": "qTxADRsQnKiYfOiQ", "type": "base", - "system": { - "changes": [ - { - "type": "armor", - "phase": "initial", - "priority": 20, - "value": { - "max": "1" - } - } - ] - }, + "system": {}, "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null }, "origin": null, "tint": "#ffffff", @@ -135,10 +129,7 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, - "_key": "!items.effects!ijWppQzSOqVCb3rE.vnR4Zhnb0rOqwrFw" + "_key": "!items.effects!ijWppQzSOqVCb3rE.qTxADRsQnKiYfOiQ" } ], "sort": 0, diff --git a/src/packs/items/weapons/weapon_Legendary_Arcane_Frame_Wheelchair_gA2tiET9VHGhwMoO.json b/src/packs/items/weapons/weapon_Legendary_Arcane_Frame_Wheelchair_gA2tiET9VHGhwMoO.json index f947acac..d8068f41 100644 --- a/src/packs/items/weapons/weapon_Legendary_Arcane_Frame_Wheelchair_gA2tiET9VHGhwMoO.json +++ b/src/packs/items/weapons/weapon_Legendary_Arcane_Frame_Wheelchair_gA2tiET9VHGhwMoO.json @@ -48,8 +48,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 9, @@ -75,7 +75,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Arcane_Gauntlets_umADDPYCaykXDc1v.json b/src/packs/items/weapons/weapon_Legendary_Arcane_Gauntlets_umADDPYCaykXDc1v.json index c7adc0f2..94da915c 100644 --- a/src/packs/items/weapons/weapon_Legendary_Arcane_Gauntlets_umADDPYCaykXDc1v.json +++ b/src/packs/items/weapons/weapon_Legendary_Arcane_Gauntlets_umADDPYCaykXDc1v.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 12, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Battleaxe_1nztpLzoHGfbKf5x.json b/src/packs/items/weapons/weapon_Legendary_Battleaxe_1nztpLzoHGfbKf5x.json index 3c22e3f2..06a8a85f 100644 --- a/src/packs/items/weapons/weapon_Legendary_Battleaxe_1nztpLzoHGfbKf5x.json +++ b/src/packs/items/weapons/weapon_Legendary_Battleaxe_1nztpLzoHGfbKf5x.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 12, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Broadsword_y3hfTPfZhMognyaJ.json b/src/packs/items/weapons/weapon_Legendary_Broadsword_y3hfTPfZhMognyaJ.json index 361d0353..786ba8b6 100644 --- a/src/packs/items/weapons/weapon_Legendary_Broadsword_y3hfTPfZhMognyaJ.json +++ b/src/packs/items/weapons/weapon_Legendary_Broadsword_y3hfTPfZhMognyaJ.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 9, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Crossbow_1G6xX2QL9O0Rsgz7.json b/src/packs/items/weapons/weapon_Legendary_Crossbow_1G6xX2QL9O0Rsgz7.json index 358cdd56..e263bcbe 100644 --- a/src/packs/items/weapons/weapon_Legendary_Crossbow_1G6xX2QL9O0Rsgz7.json +++ b/src/packs/items/weapons/weapon_Legendary_Crossbow_1G6xX2QL9O0Rsgz7.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 10, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Cutlass_Rpyz0jbFJ1SwqfyD.json b/src/packs/items/weapons/weapon_Legendary_Cutlass_Rpyz0jbFJ1SwqfyD.json index 9ce1b48a..2c284332 100644 --- a/src/packs/items/weapons/weapon_Legendary_Cutlass_Rpyz0jbFJ1SwqfyD.json +++ b/src/packs/items/weapons/weapon_Legendary_Cutlass_Rpyz0jbFJ1SwqfyD.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 10, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Dagger_GmTg3Fdne1UPNs8t.json b/src/packs/items/weapons/weapon_Legendary_Dagger_GmTg3Fdne1UPNs8t.json index a7bb2fc9..0e9e988d 100644 --- a/src/packs/items/weapons/weapon_Legendary_Dagger_GmTg3Fdne1UPNs8t.json +++ b/src/packs/items/weapons/weapon_Legendary_Dagger_GmTg3Fdne1UPNs8t.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 10, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Dualstaff_o3rsLvImcLAx5TvD.json b/src/packs/items/weapons/weapon_Legendary_Dualstaff_o3rsLvImcLAx5TvD.json index b06909e4..9c618ba5 100644 --- a/src/packs/items/weapons/weapon_Legendary_Dualstaff_o3rsLvImcLAx5TvD.json +++ b/src/packs/items/weapons/weapon_Legendary_Dualstaff_o3rsLvImcLAx5TvD.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 12, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Glowing_Rings_PReWrfuPjoNQuieo.json b/src/packs/items/weapons/weapon_Legendary_Glowing_Rings_PReWrfuPjoNQuieo.json index ca9937ee..1710084f 100644 --- a/src/packs/items/weapons/weapon_Legendary_Glowing_Rings_PReWrfuPjoNQuieo.json +++ b/src/packs/items/weapons/weapon_Legendary_Glowing_Rings_PReWrfuPjoNQuieo.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 11, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Grappler_IrtUj0UntBMNn49G.json b/src/packs/items/weapons/weapon_Legendary_Grappler_IrtUj0UntBMNn49G.json index f20425b2..83334710 100644 --- a/src/packs/items/weapons/weapon_Legendary_Grappler_IrtUj0UntBMNn49G.json +++ b/src/packs/items/weapons/weapon_Legendary_Grappler_IrtUj0UntBMNn49G.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 6, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Greatstaff_jDtvEabkHY1GFgfc.json b/src/packs/items/weapons/weapon_Legendary_Greatstaff_jDtvEabkHY1GFgfc.json index 09fd1f7a..a5ea82f9 100644 --- a/src/packs/items/weapons/weapon_Legendary_Greatstaff_jDtvEabkHY1GFgfc.json +++ b/src/packs/items/weapons/weapon_Legendary_Greatstaff_jDtvEabkHY1GFgfc.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 9, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Greatsword_zMZ46F9VR7zdTxb9.json b/src/packs/items/weapons/weapon_Legendary_Greatsword_zMZ46F9VR7zdTxb9.json index aa9d2ef0..840e7ec7 100644 --- a/src/packs/items/weapons/weapon_Legendary_Greatsword_zMZ46F9VR7zdTxb9.json +++ b/src/packs/items/weapons/weapon_Legendary_Greatsword_zMZ46F9VR7zdTxb9.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 12, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Halberd_1AuMNiJz96Ez9fur.json b/src/packs/items/weapons/weapon_Legendary_Halberd_1AuMNiJz96Ez9fur.json index af6b2a07..22e6af1b 100644 --- a/src/packs/items/weapons/weapon_Legendary_Halberd_1AuMNiJz96Ez9fur.json +++ b/src/packs/items/weapons/weapon_Legendary_Halberd_1AuMNiJz96Ez9fur.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 11, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Hallowed_Axe_0HmhnZnv1I6uX69c.json b/src/packs/items/weapons/weapon_Legendary_Hallowed_Axe_0HmhnZnv1I6uX69c.json index 70379d45..2bf11f05 100644 --- a/src/packs/items/weapons/weapon_Legendary_Hallowed_Axe_0HmhnZnv1I6uX69c.json +++ b/src/packs/items/weapons/weapon_Legendary_Hallowed_Axe_0HmhnZnv1I6uX69c.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 10, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Hand_Crossbow_32nYyMaeDWaakSxz.json b/src/packs/items/weapons/weapon_Legendary_Hand_Crossbow_32nYyMaeDWaakSxz.json index 930310a8..ff43c21b 100644 --- a/src/packs/items/weapons/weapon_Legendary_Hand_Crossbow_32nYyMaeDWaakSxz.json +++ b/src/packs/items/weapons/weapon_Legendary_Hand_Crossbow_32nYyMaeDWaakSxz.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 7, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Hand_Runes_DWLkswhluXuMy3bB.json b/src/packs/items/weapons/weapon_Legendary_Hand_Runes_DWLkswhluXuMy3bB.json index e909f460..2dcad490 100644 --- a/src/packs/items/weapons/weapon_Legendary_Hand_Runes_DWLkswhluXuMy3bB.json +++ b/src/packs/items/weapons/weapon_Legendary_Hand_Runes_DWLkswhluXuMy3bB.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 9, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Heavy_Frame_Wheelchair_S6nB0CNlzdU05o5U.json b/src/packs/items/weapons/weapon_Legendary_Heavy_Frame_Wheelchair_S6nB0CNlzdU05o5U.json index d8816fc9..7e561c26 100644 --- a/src/packs/items/weapons/weapon_Legendary_Heavy_Frame_Wheelchair_S6nB0CNlzdU05o5U.json +++ b/src/packs/items/weapons/weapon_Legendary_Heavy_Frame_Wheelchair_S6nB0CNlzdU05o5U.json @@ -48,8 +48,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d12", "bonus": 12, @@ -75,7 +75,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Light_Frame_Wheelchair_Xt8tVSn5Fu6ly6LF.json b/src/packs/items/weapons/weapon_Legendary_Light_Frame_Wheelchair_Xt8tVSn5Fu6ly6LF.json index 7afbd979..9f96601c 100644 --- a/src/packs/items/weapons/weapon_Legendary_Light_Frame_Wheelchair_Xt8tVSn5Fu6ly6LF.json +++ b/src/packs/items/weapons/weapon_Legendary_Light_Frame_Wheelchair_Xt8tVSn5Fu6ly6LF.json @@ -77,8 +77,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 9, @@ -104,7 +104,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Longbow_Utt1GpoH1fhaTOtN.json b/src/packs/items/weapons/weapon_Legendary_Longbow_Utt1GpoH1fhaTOtN.json index bd5ab13b..bb0b8ab3 100644 --- a/src/packs/items/weapons/weapon_Legendary_Longbow_Utt1GpoH1fhaTOtN.json +++ b/src/packs/items/weapons/weapon_Legendary_Longbow_Utt1GpoH1fhaTOtN.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 12, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Longsword_14abPqQcROJfDChR.json b/src/packs/items/weapons/weapon_Legendary_Longsword_14abPqQcROJfDChR.json index e6555b02..9399edd4 100644 --- a/src/packs/items/weapons/weapon_Legendary_Longsword_14abPqQcROJfDChR.json +++ b/src/packs/items/weapons/weapon_Legendary_Longsword_14abPqQcROJfDChR.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 12, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Mace_RsDsy7tIhrhaAQQc.json b/src/packs/items/weapons/weapon_Legendary_Mace_RsDsy7tIhrhaAQQc.json index 7f4a9dab..95de32f0 100644 --- a/src/packs/items/weapons/weapon_Legendary_Mace_RsDsy7tIhrhaAQQc.json +++ b/src/packs/items/weapons/weapon_Legendary_Mace_RsDsy7tIhrhaAQQc.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 10, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Quarterstaff_1ZciqG7vIKLYpKsP.json b/src/packs/items/weapons/weapon_Legendary_Quarterstaff_1ZciqG7vIKLYpKsP.json index 91bc8ac8..cf25daa7 100644 --- a/src/packs/items/weapons/weapon_Legendary_Quarterstaff_1ZciqG7vIKLYpKsP.json +++ b/src/packs/items/weapons/weapon_Legendary_Quarterstaff_1ZciqG7vIKLYpKsP.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 12, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Rapier_BakN97v4jTePcXiZ.json b/src/packs/items/weapons/weapon_Legendary_Rapier_BakN97v4jTePcXiZ.json index d5bac6d1..59a49063 100644 --- a/src/packs/items/weapons/weapon_Legendary_Rapier_BakN97v4jTePcXiZ.json +++ b/src/packs/items/weapons/weapon_Legendary_Rapier_BakN97v4jTePcXiZ.json @@ -78,8 +78,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 9, @@ -105,7 +105,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Returning_Blade_mcj3CPkcSSDdAcBB.json b/src/packs/items/weapons/weapon_Legendary_Returning_Blade_mcj3CPkcSSDdAcBB.json index b3f3fc3d..211c88c2 100644 --- a/src/packs/items/weapons/weapon_Legendary_Returning_Blade_mcj3CPkcSSDdAcBB.json +++ b/src/packs/items/weapons/weapon_Legendary_Returning_Blade_mcj3CPkcSSDdAcBB.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 9, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Round_Shield_A28WL9E2lJ3iLZHW.json b/src/packs/items/weapons/weapon_Legendary_Round_Shield_A28WL9E2lJ3iLZHW.json index 85134d21..c7b18355 100644 --- a/src/packs/items/weapons/weapon_Legendary_Round_Shield_A28WL9E2lJ3iLZHW.json +++ b/src/packs/items/weapons/weapon_Legendary_Round_Shield_A28WL9E2lJ3iLZHW.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d4", "bonus": 6, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", @@ -113,26 +113,26 @@ "name": "Protective", "description": "

Add the item's Tier to your Armor Score

", "img": "icons/skills/melee/shield-block-gray-orange.webp", - "_id": "EixxJrRHyc6kj3Wg", + "changes": [ + { + "key": "system.armorScore", + "mode": 2, + "value": "ITEM.@system.tier", + "priority": null + } + ], + "_id": "Z2p00q5h6x6seXys", "type": "base", - "system": { - "changes": [ - { - "type": "armor", - "phase": "initial", - "priority": 20, - "value": { - "max": "ITEM.@system.tier" - } - } - ] - }, + "system": {}, "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "origin": null, "tint": "#ffffff", @@ -143,10 +143,7 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, - "_key": "!items.effects!A28WL9E2lJ3iLZHW.EixxJrRHyc6kj3Wg" + "_key": "!items.effects!A28WL9E2lJ3iLZHW.Z2p00q5h6x6seXys" } ], "sort": 0, diff --git a/src/packs/items/weapons/weapon_Legendary_Scepter_IZ4CWNxfuM46JeCN.json b/src/packs/items/weapons/weapon_Legendary_Scepter_IZ4CWNxfuM46JeCN.json index 882ecfdf..9630fd69 100644 --- a/src/packs/items/weapons/weapon_Legendary_Scepter_IZ4CWNxfuM46JeCN.json +++ b/src/packs/items/weapons/weapon_Legendary_Scepter_IZ4CWNxfuM46JeCN.json @@ -11,8 +11,8 @@ "type": "attack", "damage": { "includeBase": false, - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -38,7 +38,7 @@ } } } - } + ] }, "range": "melee", "roll": { @@ -115,8 +115,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 9, @@ -142,7 +142,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Shortbow_j7kp36jaetfn5jb3.json b/src/packs/items/weapons/weapon_Legendary_Shortbow_j7kp36jaetfn5jb3.json index b3dbd210..7fad3f95 100644 --- a/src/packs/items/weapons/weapon_Legendary_Shortbow_j7kp36jaetfn5jb3.json +++ b/src/packs/items/weapons/weapon_Legendary_Shortbow_j7kp36jaetfn5jb3.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 12, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Shortstaff_D3SbNvNJZAFuzfhg.json b/src/packs/items/weapons/weapon_Legendary_Shortstaff_D3SbNvNJZAFuzfhg.json index 3d29bc25..59d53e44 100644 --- a/src/packs/items/weapons/weapon_Legendary_Shortstaff_D3SbNvNJZAFuzfhg.json +++ b/src/packs/items/weapons/weapon_Legendary_Shortstaff_D3SbNvNJZAFuzfhg.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 10, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Shortsword_dEumq3BIZBk5xYTk.json b/src/packs/items/weapons/weapon_Legendary_Shortsword_dEumq3BIZBk5xYTk.json index a2203a1d..d7f9632a 100644 --- a/src/packs/items/weapons/weapon_Legendary_Shortsword_dEumq3BIZBk5xYTk.json +++ b/src/packs/items/weapons/weapon_Legendary_Shortsword_dEumq3BIZBk5xYTk.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 6, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Small_Dagger_Px3Rh3kIvAqyISxJ.json b/src/packs/items/weapons/weapon_Legendary_Small_Dagger_Px3Rh3kIvAqyISxJ.json index cf63bde2..c6bf5437 100644 --- a/src/packs/items/weapons/weapon_Legendary_Small_Dagger_Px3Rh3kIvAqyISxJ.json +++ b/src/packs/items/weapons/weapon_Legendary_Small_Dagger_Px3Rh3kIvAqyISxJ.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 6, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Spear_4e5pWxi2qohuGsWh.json b/src/packs/items/weapons/weapon_Legendary_Spear_4e5pWxi2qohuGsWh.json index e0248f4b..114ea79e 100644 --- a/src/packs/items/weapons/weapon_Legendary_Spear_4e5pWxi2qohuGsWh.json +++ b/src/packs/items/weapons/weapon_Legendary_Spear_4e5pWxi2qohuGsWh.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 12, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Tower_Shield_MaJIROht7A9LxIZx.json b/src/packs/items/weapons/weapon_Legendary_Tower_Shield_MaJIROht7A9LxIZx.json index 772e9ca9..47e707d3 100644 --- a/src/packs/items/weapons/weapon_Legendary_Tower_Shield_MaJIROht7A9LxIZx.json +++ b/src/packs/items/weapons/weapon_Legendary_Tower_Shield_MaJIROht7A9LxIZx.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 6, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", @@ -113,25 +113,25 @@ "name": "Barrier", "description": "Gain Weapon Tier + 1 to Armor Score; -1 to Evasion", "img": "icons/skills/melee/shield-block-bash-blue.webp", + "changes": [ + { + "key": "system.armorScore", + "mode": 2, + "value": "ITEM.@system.tier + 1" + }, + { + "key": "system.evasion", + "mode": 2, + "value": "-1" + } + ], "_id": "lBJMzxdGO2nJdTQS", "type": "base", - "system": { - "changes": [ - { - "key": "system.evasion", - "type": "add", - "value": -1, - "phase": "initial", - "priority": 0 - } - ] - }, + "system": {}, "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null }, "origin": null, "tint": "#ffffff", @@ -142,49 +142,7 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, "_key": "!items.effects!MaJIROht7A9LxIZx.lBJMzxdGO2nJdTQS" - }, - { - "name": "Barrier", - "description": "Gain Weapon Tier + 1 to Armor Score; -1 to Evasion", - "img": "icons/skills/melee/shield-block-bash-blue.webp", - "_id": "1fgUIaXl6VQrhP7j", - "type": "base", - "system": { - "changes": [ - { - "type": "armor", - "phase": "initial", - "priority": 20, - "value": { - "max": "ITEM.@system.tier + 1" - } - } - ] - }, - "disabled": false, - "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false - }, - "origin": null, - "tint": "#ffffff", - "transfer": true, - "statuses": [], - "sort": 0, - "flags": {}, - "_stats": { - "compendiumSource": null - }, - "start": null, - "showIcon": 1, - "folder": null, - "_key": "!items.effects!MaJIROht7A9LxIZx.1fgUIaXl6VQrhP7j" } ], "sort": 0, diff --git a/src/packs/items/weapons/weapon_Legendary_Wand_wPjg0LufJH9vUfVM.json b/src/packs/items/weapons/weapon_Legendary_Wand_wPjg0LufJH9vUfVM.json index 65925525..4bb0acd9 100644 --- a/src/packs/items/weapons/weapon_Legendary_Wand_wPjg0LufJH9vUfVM.json +++ b/src/packs/items/weapons/weapon_Legendary_Wand_wPjg0LufJH9vUfVM.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 10, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Warhammer_W9ymfEDck2icfvla.json b/src/packs/items/weapons/weapon_Legendary_Warhammer_W9ymfEDck2icfvla.json index 562122d2..0918f8b1 100644 --- a/src/packs/items/weapons/weapon_Legendary_Warhammer_W9ymfEDck2icfvla.json +++ b/src/packs/items/weapons/weapon_Legendary_Warhammer_W9ymfEDck2icfvla.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d12", "bonus": 12, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Legendary_Whip_Wcdbf6yS3LEt7nsg.json b/src/packs/items/weapons/weapon_Legendary_Whip_Wcdbf6yS3LEt7nsg.json index baf6d369..83ac59c7 100644 --- a/src/packs/items/weapons/weapon_Legendary_Whip_Wcdbf6yS3LEt7nsg.json +++ b/src/packs/items/weapons/weapon_Legendary_Whip_Wcdbf6yS3LEt7nsg.json @@ -78,8 +78,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 6, @@ -105,7 +105,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Light_Frame_Wheelchair_iaGnlUkShBgdeMo0.json b/src/packs/items/weapons/weapon_Light_Frame_Wheelchair_iaGnlUkShBgdeMo0.json index 7fadde01..fdda2b56 100644 --- a/src/packs/items/weapons/weapon_Light_Frame_Wheelchair_iaGnlUkShBgdeMo0.json +++ b/src/packs/items/weapons/weapon_Light_Frame_Wheelchair_iaGnlUkShBgdeMo0.json @@ -78,8 +78,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "type": [ "physical" ], @@ -105,7 +105,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Longbow_YfVs6Se903az4Yet.json b/src/packs/items/weapons/weapon_Longbow_YfVs6Se903az4Yet.json index 43af46ab..c6e98bc4 100644 --- a/src/packs/items/weapons/weapon_Longbow_YfVs6Se903az4Yet.json +++ b/src/packs/items/weapons/weapon_Longbow_YfVs6Se903az4Yet.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 3, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Longsword_Iv8BZM1R24QMT72M.json b/src/packs/items/weapons/weapon_Longsword_Iv8BZM1R24QMT72M.json index 3961d7c3..cba1bac8 100644 --- a/src/packs/items/weapons/weapon_Longsword_Iv8BZM1R24QMT72M.json +++ b/src/packs/items/weapons/weapon_Longsword_Iv8BZM1R24QMT72M.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 3, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Mace_cKQCDyM2UopDL9zF.json b/src/packs/items/weapons/weapon_Mace_cKQCDyM2UopDL9zF.json index 7a7582cb..0e6670f4 100644 --- a/src/packs/items/weapons/weapon_Mace_cKQCDyM2UopDL9zF.json +++ b/src/packs/items/weapons/weapon_Mace_cKQCDyM2UopDL9zF.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 1, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Mage_Orb_XKBmBUEoGLdLcuqQ.json b/src/packs/items/weapons/weapon_Mage_Orb_XKBmBUEoGLdLcuqQ.json index dbd218f1..3b5983f5 100644 --- a/src/packs/items/weapons/weapon_Mage_Orb_XKBmBUEoGLdLcuqQ.json +++ b/src/packs/items/weapons/weapon_Mage_Orb_XKBmBUEoGLdLcuqQ.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 7, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Magus_Revolver_jGykNGQiKm63tCiE.json b/src/packs/items/weapons/weapon_Magus_Revolver_jGykNGQiKm63tCiE.json index 9dbbb1c1..42a65010 100644 --- a/src/packs/items/weapons/weapon_Magus_Revolver_jGykNGQiKm63tCiE.json +++ b/src/packs/items/weapons/weapon_Magus_Revolver_jGykNGQiKm63tCiE.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 13, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Meridian_Cutlass_Gi26Zk9VqlAAgx3E.json b/src/packs/items/weapons/weapon_Meridian_Cutlass_Gi26Zk9VqlAAgx3E.json index b83a18be..dcc236a0 100644 --- a/src/packs/items/weapons/weapon_Meridian_Cutlass_Gi26Zk9VqlAAgx3E.json +++ b/src/packs/items/weapons/weapon_Meridian_Cutlass_Gi26Zk9VqlAAgx3E.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 5, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Midas_Scythe_BdLfy5i488VZgkjP.json b/src/packs/items/weapons/weapon_Midas_Scythe_BdLfy5i488VZgkjP.json index 57fe2367..799413be 100644 --- a/src/packs/items/weapons/weapon_Midas_Scythe_BdLfy5i488VZgkjP.json +++ b/src/packs/items/weapons/weapon_Midas_Scythe_BdLfy5i488VZgkjP.json @@ -78,8 +78,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 9, @@ -105,7 +105,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Parrying_Dagger_taAZDkDCpeNgxhnn.json b/src/packs/items/weapons/weapon_Parrying_Dagger_taAZDkDCpeNgxhnn.json index b5844e89..482d813b 100644 --- a/src/packs/items/weapons/weapon_Parrying_Dagger_taAZDkDCpeNgxhnn.json +++ b/src/packs/items/weapons/weapon_Parrying_Dagger_taAZDkDCpeNgxhnn.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 2, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Powered_Gauntlet_bW3xw5S9DbaLCN3E.json b/src/packs/items/weapons/weapon_Powered_Gauntlet_bW3xw5S9DbaLCN3E.json index 3c4ebd1c..67922f8b 100644 --- a/src/packs/items/weapons/weapon_Powered_Gauntlet_bW3xw5S9DbaLCN3E.json +++ b/src/packs/items/weapons/weapon_Powered_Gauntlet_bW3xw5S9DbaLCN3E.json @@ -85,8 +85,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 4, @@ -112,7 +112,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Primer_Shard_SxcblanBvqaest3A.json b/src/packs/items/weapons/weapon_Primer_Shard_SxcblanBvqaest3A.json index 0cf59179..fb42af74 100644 --- a/src/packs/items/weapons/weapon_Primer_Shard_SxcblanBvqaest3A.json +++ b/src/packs/items/weapons/weapon_Primer_Shard_SxcblanBvqaest3A.json @@ -72,8 +72,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d4", "bonus": null, @@ -99,7 +99,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Quarterstaff_mlIj88p1wcQNjEDG.json b/src/packs/items/weapons/weapon_Quarterstaff_mlIj88p1wcQNjEDG.json index 00940b6c..37c56a21 100644 --- a/src/packs/items/weapons/weapon_Quarterstaff_mlIj88p1wcQNjEDG.json +++ b/src/packs/items/weapons/weapon_Quarterstaff_mlIj88p1wcQNjEDG.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 3, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Rapier_zkAgEW6zMkRZalEm.json b/src/packs/items/weapons/weapon_Rapier_zkAgEW6zMkRZalEm.json index 45642f14..b4de1c00 100644 --- a/src/packs/items/weapons/weapon_Rapier_zkAgEW6zMkRZalEm.json +++ b/src/packs/items/weapons/weapon_Rapier_zkAgEW6zMkRZalEm.json @@ -78,8 +78,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "type": [ "physical" ], @@ -105,7 +105,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Retractable_Saber_i8CqVTzqoRoCewNe.json b/src/packs/items/weapons/weapon_Retractable_Saber_i8CqVTzqoRoCewNe.json index 548de60f..c1b350a3 100644 --- a/src/packs/items/weapons/weapon_Retractable_Saber_i8CqVTzqoRoCewNe.json +++ b/src/packs/items/weapons/weapon_Retractable_Saber_i8CqVTzqoRoCewNe.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 7, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Returning_Axe_FtsQGwOg3r8uUCST.json b/src/packs/items/weapons/weapon_Returning_Axe_FtsQGwOg3r8uUCST.json index 9f3cca62..76a887ae 100644 --- a/src/packs/items/weapons/weapon_Returning_Axe_FtsQGwOg3r8uUCST.json +++ b/src/packs/items/weapons/weapon_Returning_Axe_FtsQGwOg3r8uUCST.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 4, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Returning_Blade_4fQpVfQ3NVwTHStA.json b/src/packs/items/weapons/weapon_Returning_Blade_4fQpVfQ3NVwTHStA.json index efd81e48..74be4227 100644 --- a/src/packs/items/weapons/weapon_Returning_Blade_4fQpVfQ3NVwTHStA.json +++ b/src/packs/items/weapons/weapon_Returning_Blade_4fQpVfQ3NVwTHStA.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": null, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Ricochet_Axes_E9QDh5o9eQ1Qx0kH.json b/src/packs/items/weapons/weapon_Ricochet_Axes_E9QDh5o9eQ1Qx0kH.json index 34f3b200..1067bb02 100644 --- a/src/packs/items/weapons/weapon_Ricochet_Axes_E9QDh5o9eQ1Qx0kH.json +++ b/src/packs/items/weapons/weapon_Ricochet_Axes_E9QDh5o9eQ1Qx0kH.json @@ -78,8 +78,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 11, @@ -105,7 +105,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Round_Shield_mxwWKDujgsRcZWPT.json b/src/packs/items/weapons/weapon_Round_Shield_mxwWKDujgsRcZWPT.json index 55e92f01..47b096af 100644 --- a/src/packs/items/weapons/weapon_Round_Shield_mxwWKDujgsRcZWPT.json +++ b/src/packs/items/weapons/weapon_Round_Shield_mxwWKDujgsRcZWPT.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d4", "bonus": null, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", @@ -113,26 +113,26 @@ "name": "Protective", "description": "

Add the item's Tier to your Armor Score

", "img": "icons/skills/melee/shield-block-gray-orange.webp", - "_id": "eV4lFIpQMiKERj4U", + "changes": [ + { + "key": "system.armorScore", + "mode": 2, + "value": "ITEM.@system.tier", + "priority": null + } + ], + "_id": "M70a81e0Mg66jHRL", "type": "base", - "system": { - "changes": [ - { - "type": "armor", - "phase": "initial", - "priority": 20, - "value": { - "max": "ITEM.@system.tier" - } - } - ] - }, + "system": {}, "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "origin": null, "tint": "#ffffff", @@ -143,10 +143,7 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, - "_key": "!items.effects!mxwWKDujgsRcZWPT.eV4lFIpQMiKERj4U" + "_key": "!items.effects!mxwWKDujgsRcZWPT.M70a81e0Mg66jHRL" } ], "sort": 0, diff --git a/src/packs/items/weapons/weapon_Runes_of_Ruination_EG6mZhr3ib56r974.json b/src/packs/items/weapons/weapon_Runes_of_Ruination_EG6mZhr3ib56r974.json index 3a966fe0..e0676ed2 100644 --- a/src/packs/items/weapons/weapon_Runes_of_Ruination_EG6mZhr3ib56r974.json +++ b/src/packs/items/weapons/weapon_Runes_of_Ruination_EG6mZhr3ib56r974.json @@ -78,8 +78,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d20", "bonus": 4, @@ -105,7 +105,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Scepter_GZh345N8fmuS4Jeh.json b/src/packs/items/weapons/weapon_Scepter_GZh345N8fmuS4Jeh.json index f1e85577..04ce4c4b 100644 --- a/src/packs/items/weapons/weapon_Scepter_GZh345N8fmuS4Jeh.json +++ b/src/packs/items/weapons/weapon_Scepter_GZh345N8fmuS4Jeh.json @@ -11,8 +11,8 @@ "type": "attack", "damage": { "includeBase": false, - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -38,7 +38,7 @@ } } } - } + ] }, "range": "melee", "roll": { @@ -115,8 +115,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": null, @@ -142,7 +142,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Scepter_of_Elias_acPGwIaUhx3R0mTq.json b/src/packs/items/weapons/weapon_Scepter_of_Elias_acPGwIaUhx3R0mTq.json index f2c13441..8c8e50af 100644 --- a/src/packs/items/weapons/weapon_Scepter_of_Elias_acPGwIaUhx3R0mTq.json +++ b/src/packs/items/weapons/weapon_Scepter_of_Elias_acPGwIaUhx3R0mTq.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 3, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Shortbow_p9tdjQr2AZP19RYm.json b/src/packs/items/weapons/weapon_Shortbow_p9tdjQr2AZP19RYm.json index 56a791ba..82216a2d 100644 --- a/src/packs/items/weapons/weapon_Shortbow_p9tdjQr2AZP19RYm.json +++ b/src/packs/items/weapons/weapon_Shortbow_p9tdjQr2AZP19RYm.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 3, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Shortstaff_vHDHG3STcxTEfYAM.json b/src/packs/items/weapons/weapon_Shortstaff_vHDHG3STcxTEfYAM.json index 3dc3a137..0d468da8 100644 --- a/src/packs/items/weapons/weapon_Shortstaff_vHDHG3STcxTEfYAM.json +++ b/src/packs/items/weapons/weapon_Shortstaff_vHDHG3STcxTEfYAM.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 1, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Shortsword_cjGZpXCoshEqi1FI.json b/src/packs/items/weapons/weapon_Shortsword_cjGZpXCoshEqi1FI.json index 0ea874f8..84ae1a2a 100644 --- a/src/packs/items/weapons/weapon_Shortsword_cjGZpXCoshEqi1FI.json +++ b/src/packs/items/weapons/weapon_Shortsword_cjGZpXCoshEqi1FI.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": null, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Siphoning_Gauntlets_1N1jggda5DfdzdMj.json b/src/packs/items/weapons/weapon_Siphoning_Gauntlets_1N1jggda5DfdzdMj.json index 205aa4e0..0eb65689 100644 --- a/src/packs/items/weapons/weapon_Siphoning_Gauntlets_1N1jggda5DfdzdMj.json +++ b/src/packs/items/weapons/weapon_Siphoning_Gauntlets_1N1jggda5DfdzdMj.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 9, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Sledge_Axe_OxsEmffWriiQmqJK.json b/src/packs/items/weapons/weapon_Sledge_Axe_OxsEmffWriiQmqJK.json index d0230362..b5ffe457 100644 --- a/src/packs/items/weapons/weapon_Sledge_Axe_OxsEmffWriiQmqJK.json +++ b/src/packs/items/weapons/weapon_Sledge_Axe_OxsEmffWriiQmqJK.json @@ -20,8 +20,8 @@ "amount": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "applyTo": "stress", "value": { "custom": { @@ -46,7 +46,7 @@ "base": false, "type": [] } - }, + ], "includeBase": false }, "_id": "0qVTvNMfapVST3sQ", @@ -104,8 +104,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d12", "bonus": 13, @@ -131,7 +131,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Small_Dagger_wKklDxs5nkzILNp4.json b/src/packs/items/weapons/weapon_Small_Dagger_wKklDxs5nkzILNp4.json index 058d138e..5b63acd7 100644 --- a/src/packs/items/weapons/weapon_Small_Dagger_wKklDxs5nkzILNp4.json +++ b/src/packs/items/weapons/weapon_Small_Dagger_wKklDxs5nkzILNp4.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "type": [ "physical" ], @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Spear_TF85tKJetUjLwh54.json b/src/packs/items/weapons/weapon_Spear_TF85tKJetUjLwh54.json index a0ebc4ec..ea217ad9 100644 --- a/src/packs/items/weapons/weapon_Spear_TF85tKJetUjLwh54.json +++ b/src/packs/items/weapons/weapon_Spear_TF85tKJetUjLwh54.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 3, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Spiked_Bow_O1w8KPYH85ZS8X64.json b/src/packs/items/weapons/weapon_Spiked_Bow_O1w8KPYH85ZS8X64.json index 5421fc10..99faed64 100644 --- a/src/packs/items/weapons/weapon_Spiked_Bow_O1w8KPYH85ZS8X64.json +++ b/src/packs/items/weapons/weapon_Spiked_Bow_O1w8KPYH85ZS8X64.json @@ -11,8 +11,8 @@ "type": "attack", "damage": { "includeBase": false, - "parts": { - "hitPoints": { + "parts": [ + { "resultBased": false, "value": { "custom": { @@ -36,7 +36,7 @@ } } } - } + ] }, "range": "melee", "roll": { @@ -113,8 +113,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 7, @@ -140,7 +140,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Spiked_Shield_vzyzFwLUniWZV1rt.json b/src/packs/items/weapons/weapon_Spiked_Shield_vzyzFwLUniWZV1rt.json index 39c18b08..edadecf9 100644 --- a/src/packs/items/weapons/weapon_Spiked_Shield_vzyzFwLUniWZV1rt.json +++ b/src/packs/items/weapons/weapon_Spiked_Shield_vzyzFwLUniWZV1rt.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 2, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", @@ -113,31 +113,32 @@ "name": "Double Duty", "description": "+1 to Armor Score; +1 to primary weapon damage within Melee range", "img": "icons/skills/melee/sword-shield-stylized-white.webp", + "changes": [ + { + "key": "system.armorScore", + "mode": 2, + "value": "1" + }, + { + "key": "system.bonuses.damage.primaryWeapon.bonus", + "mode": 2, + "value": "1" + } + ], "system": { "rangeDependence": { "enabled": true, "range": "melee", "target": "hostile", "type": "withinRange" - }, - "changes": [ - { - "key": "system.bonuses.damage.primaryWeapon.bonus", - "type": "add", - "value": 1, - "phase": "initial", - "priority": 0 - } - ] + } }, "_id": "d3TJtlpoHBCztbom", "type": "base", "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null }, "origin": null, "tint": "#ffffff", @@ -148,49 +149,7 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, "_key": "!items.effects!vzyzFwLUniWZV1rt.d3TJtlpoHBCztbom" - }, - { - "name": "Double Duty", - "description": "+1 to Armor Score; +1 to primary weapon damage within Melee range", - "img": "icons/skills/melee/sword-shield-stylized-white.webp", - "system": { - "changes": [ - { - "type": "armor", - "phase": "initial", - "priority": 20, - "value": { - "max": "1" - } - } - ] - }, - "_id": "mvUY9LGfwICak7cE", - "type": "base", - "disabled": false, - "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false - }, - "origin": null, - "tint": "#ffffff", - "transfer": true, - "statuses": [], - "sort": 0, - "flags": {}, - "_stats": { - "compendiumSource": null - }, - "start": null, - "showIcon": 1, - "folder": null, - "_key": "!items.effects!vzyzFwLUniWZV1rt.mvUY9LGfwICak7cE" } ], "sort": 0, diff --git a/src/packs/items/weapons/weapon_Steelforged_Halberd_6bkbw4Ap644KZGvJ.json b/src/packs/items/weapons/weapon_Steelforged_Halberd_6bkbw4Ap644KZGvJ.json index 1fccc471..c4730e94 100644 --- a/src/packs/items/weapons/weapon_Steelforged_Halberd_6bkbw4Ap644KZGvJ.json +++ b/src/packs/items/weapons/weapon_Steelforged_Halberd_6bkbw4Ap644KZGvJ.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 4, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Swinging_Ropeblade_1jOJHHKdtk3s2jaY.json b/src/packs/items/weapons/weapon_Swinging_Ropeblade_1jOJHHKdtk3s2jaY.json index cd9490f2..b8fe04b6 100644 --- a/src/packs/items/weapons/weapon_Swinging_Ropeblade_1jOJHHKdtk3s2jaY.json +++ b/src/packs/items/weapons/weapon_Swinging_Ropeblade_1jOJHHKdtk3s2jaY.json @@ -78,8 +78,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 9, @@ -105,7 +105,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Sword_of_Light___Flame_TVPCWnSELOVBv6G1.json b/src/packs/items/weapons/weapon_Sword_of_Light___Flame_TVPCWnSELOVBv6G1.json index 63112b3e..7a74cf3d 100644 --- a/src/packs/items/weapons/weapon_Sword_of_Light___Flame_TVPCWnSELOVBv6G1.json +++ b/src/packs/items/weapons/weapon_Sword_of_Light___Flame_TVPCWnSELOVBv6G1.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 11, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Talon_Blades_jlLtgK468rO5IssR.json b/src/packs/items/weapons/weapon_Talon_Blades_jlLtgK468rO5IssR.json index a7c96705..13542a63 100644 --- a/src/packs/items/weapons/weapon_Talon_Blades_jlLtgK468rO5IssR.json +++ b/src/packs/items/weapons/weapon_Talon_Blades_jlLtgK468rO5IssR.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 7, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Thistlebow_I1nDGpulg29GpWOW.json b/src/packs/items/weapons/weapon_Thistlebow_I1nDGpulg29GpWOW.json index 18f635eb..65fef12a 100644 --- a/src/packs/items/weapons/weapon_Thistlebow_I1nDGpulg29GpWOW.json +++ b/src/packs/items/weapons/weapon_Thistlebow_I1nDGpulg29GpWOW.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 13, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Tower_Shield_C9aWpK1shVMWP4m5.json b/src/packs/items/weapons/weapon_Tower_Shield_C9aWpK1shVMWP4m5.json index e584b63c..d49b7de7 100644 --- a/src/packs/items/weapons/weapon_Tower_Shield_C9aWpK1shVMWP4m5.json +++ b/src/packs/items/weapons/weapon_Tower_Shield_C9aWpK1shVMWP4m5.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": null, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", @@ -113,25 +113,25 @@ "name": "Barrier", "description": "Gain Weapon Tier + 1 to Armor Score; -1 to Evasion", "img": "icons/skills/melee/shield-block-bash-blue.webp", + "changes": [ + { + "key": "system.armorScore", + "mode": 2, + "value": "ITEM.@system.tier + 1" + }, + { + "key": "system.evasion", + "mode": 2, + "value": "-1" + } + ], "_id": "8r0TcKWXboFV0eqS", "type": "base", - "system": { - "changes": [ - { - "key": "system.evasion", - "type": "add", - "value": -1, - "phase": "initial", - "priority": 0 - } - ] - }, + "system": {}, "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null }, "origin": null, "tint": "#ffffff", @@ -142,49 +142,7 @@ "_stats": { "compendiumSource": null }, - "start": null, - "showIcon": 1, - "folder": null, "_key": "!items.effects!C9aWpK1shVMWP4m5.8r0TcKWXboFV0eqS" - }, - { - "name": "Barrier", - "description": "Gain Weapon Tier + 1 to Armor Score; -1 to Evasion", - "img": "icons/skills/melee/shield-block-bash-blue.webp", - "_id": "tLRc4UAnGuIq7er3", - "type": "base", - "system": { - "changes": [ - { - "type": "armor", - "phase": "initial", - "priority": 20, - "value": { - "max": "ITEM.@system.tier + 1" - } - } - ] - }, - "disabled": false, - "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false - }, - "origin": null, - "tint": "#ffffff", - "transfer": true, - "statuses": [], - "sort": 0, - "flags": {}, - "_stats": { - "compendiumSource": null - }, - "start": null, - "showIcon": 1, - "folder": null, - "_key": "!items.effects!C9aWpK1shVMWP4m5.tLRc4UAnGuIq7er3" } ], "sort": 0, diff --git a/src/packs/items/weapons/weapon_Urok_Broadsword_zGm6Wa1fGF6cECY5.json b/src/packs/items/weapons/weapon_Urok_Broadsword_zGm6Wa1fGF6cECY5.json index 6727c333..708e920f 100644 --- a/src/packs/items/weapons/weapon_Urok_Broadsword_zGm6Wa1fGF6cECY5.json +++ b/src/packs/items/weapons/weapon_Urok_Broadsword_zGm6Wa1fGF6cECY5.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 3, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Wand_ItWisJFNGMNWeaCV.json b/src/packs/items/weapons/weapon_Wand_ItWisJFNGMNWeaCV.json index 8084f261..35fc7866 100644 --- a/src/packs/items/weapons/weapon_Wand_ItWisJFNGMNWeaCV.json +++ b/src/packs/items/weapons/weapon_Wand_ItWisJFNGMNWeaCV.json @@ -41,8 +41,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 1, @@ -68,7 +68,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Wand_of_Enthrallment_tP6vmnrmTq2h5sj7.json b/src/packs/items/weapons/weapon_Wand_of_Enthrallment_tP6vmnrmTq2h5sj7.json index 84c7b3f2..f2b2f308 100644 --- a/src/packs/items/weapons/weapon_Wand_of_Enthrallment_tP6vmnrmTq2h5sj7.json +++ b/src/packs/items/weapons/weapon_Wand_of_Enthrallment_tP6vmnrmTq2h5sj7.json @@ -85,8 +85,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 4, @@ -112,7 +112,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Wand_of_Essek_ZrRGNjGCgZTTfgDG.json b/src/packs/items/weapons/weapon_Wand_of_Essek_ZrRGNjGCgZTTfgDG.json index d788d008..23fb1003 100644 --- a/src/packs/items/weapons/weapon_Wand_of_Essek_ZrRGNjGCgZTTfgDG.json +++ b/src/packs/items/weapons/weapon_Wand_of_Essek_ZrRGNjGCgZTTfgDG.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 13, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_War_Scythe_z6yEdFYQJ5IzgTX3.json b/src/packs/items/weapons/weapon_War_Scythe_z6yEdFYQJ5IzgTX3.json index 0c57dd50..e80ddfad 100644 --- a/src/packs/items/weapons/weapon_War_Scythe_z6yEdFYQJ5IzgTX3.json +++ b/src/packs/items/weapons/weapon_War_Scythe_z6yEdFYQJ5IzgTX3.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d8", "bonus": 5, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Warhammer_ZXh1GQahBiODfSTC.json b/src/packs/items/weapons/weapon_Warhammer_ZXh1GQahBiODfSTC.json index a94950c7..50b1a829 100644 --- a/src/packs/items/weapons/weapon_Warhammer_ZXh1GQahBiODfSTC.json +++ b/src/packs/items/weapons/weapon_Warhammer_ZXh1GQahBiODfSTC.json @@ -49,8 +49,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d12", "bonus": 3, @@ -76,7 +76,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Whip_CmtWqw6DwoePnX7W.json b/src/packs/items/weapons/weapon_Whip_CmtWqw6DwoePnX7W.json index 287d8afe..2e548ab6 100644 --- a/src/packs/items/weapons/weapon_Whip_CmtWqw6DwoePnX7W.json +++ b/src/packs/items/weapons/weapon_Whip_CmtWqw6DwoePnX7W.json @@ -78,8 +78,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": null, @@ -105,7 +105,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Widogast_Pendant_8Z5QrThfwkYPXNco.json b/src/packs/items/weapons/weapon_Widogast_Pendant_8Z5QrThfwkYPXNco.json index 44e4dfd6..a03efe6b 100644 --- a/src/packs/items/weapons/weapon_Widogast_Pendant_8Z5QrThfwkYPXNco.json +++ b/src/packs/items/weapons/weapon_Widogast_Pendant_8Z5QrThfwkYPXNco.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d10", "bonus": 5, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/items/weapons/weapon_Yutari_Bloodbow_0XpSBYXxtywvBFQi.json b/src/packs/items/weapons/weapon_Yutari_Bloodbow_0XpSBYXxtywvBFQi.json index 17e02976..d07a986e 100644 --- a/src/packs/items/weapons/weapon_Yutari_Bloodbow_0XpSBYXxtywvBFQi.json +++ b/src/packs/items/weapons/weapon_Yutari_Bloodbow_0XpSBYXxtywvBFQi.json @@ -71,8 +71,8 @@ "useDefault": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "dice": "d6", "bonus": 4, @@ -98,7 +98,7 @@ }, "base": false } - }, + ], "includeBase": false }, "description": "", diff --git a/src/packs/subclasses/feature_Act_of_Reprisal_k7vvMJtEcxMWUUrW.json b/src/packs/subclasses/feature_Act_of_Reprisal_k7vvMJtEcxMWUUrW.json index 5dee0c1c..304bd29c 100644 --- a/src/packs/subclasses/feature_Act_of_Reprisal_k7vvMJtEcxMWUUrW.json +++ b/src/packs/subclasses/feature_Act_of_Reprisal_k7vvMJtEcxMWUUrW.json @@ -59,19 +59,13 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [], - "duration": { - "type": "temporary", - "description": "

Until the next successful attack you make against that adversary.

" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null }, "description": "", "tint": "#ffffff", @@ -81,16 +75,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!k7vvMJtEcxMWUUrW.9Uo0yOYGn3vandPp" } ], diff --git a/src/packs/subclasses/feature_Battle_Bonded_hWsKyed1vfILg0I8.json b/src/packs/subclasses/feature_Battle_Bonded_hWsKyed1vfILg0I8.json index 578be0a3..106b0057 100644 --- a/src/packs/subclasses/feature_Battle_Bonded_hWsKyed1vfILg0I8.json +++ b/src/packs/subclasses/feature_Battle_Bonded_hWsKyed1vfILg0I8.json @@ -26,28 +26,27 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.evasion", - "value": 2, - "priority": null, - "type": "add" - } - ], - "duration": { - "type": "", - "description": "

Against the attack.

" } }, "_id": "IZhakv6EuG8DO4a3", "img": "icons/creatures/mammals/humanoid-wolf-dog-blue.webp", + "changes": [ + { + "key": "system.evasion", + "mode": 2, + "value": "2", + "priority": null + } + ], "disabled": true, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

When an adversary attacks you while they’re within your companion’s Melee range, you gain a +2 bonus to your Evasion against the attack.

", "origin": null, @@ -59,16 +58,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!hWsKyed1vfILg0I8.IZhakv6EuG8DO4a3" } ], diff --git a/src/packs/subclasses/feature_Battle_Ritual_qqb5acyUSl1sCpWW.json b/src/packs/subclasses/feature_Battle_Ritual_qqb5acyUSl1sCpWW.json index 2b012aee..6dee9f9d 100644 --- a/src/packs/subclasses/feature_Battle_Ritual_qqb5acyUSl1sCpWW.json +++ b/src/packs/subclasses/feature_Battle_Ritual_qqb5acyUSl1sCpWW.json @@ -23,8 +23,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -49,7 +49,7 @@ }, "type": [] }, - "hope": { + { "value": { "custom": { "enabled": true, @@ -74,7 +74,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/subclasses/feature_Clarity_of_Nature_etaQ01yGJhBLDUqZ.json b/src/packs/subclasses/feature_Clarity_of_Nature_etaQ01yGJhBLDUqZ.json index 886f0b61..09d6f953 100644 --- a/src/packs/subclasses/feature_Clarity_of_Nature_etaQ01yGJhBLDUqZ.json +++ b/src/packs/subclasses/feature_Clarity_of_Nature_etaQ01yGJhBLDUqZ.json @@ -22,8 +22,8 @@ "recovery": "longRest" }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -48,7 +48,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/subclasses/feature_Dark_Cloud_frBTtNMX9Y2gkuPz.json b/src/packs/subclasses/feature_Dark_Cloud_frBTtNMX9Y2gkuPz.json index 8ac6aef2..95534b9f 100644 --- a/src/packs/subclasses/feature_Dark_Cloud_frBTtNMX9Y2gkuPz.json +++ b/src/packs/subclasses/feature_Dark_Cloud_frBTtNMX9Y2gkuPz.json @@ -5,14 +5,14 @@ "_id": "frBTtNMX9Y2gkuPz", "img": "icons/magic/air/wind-vortex-swirl-purple.webp", "system": { - "description": "

Make a Spellcast Roll (15). On a success, create a temporary dark cloud that covers any area within Close range. Anyone in this cloud can’t see outside of it, and anyone outside of it can’t see in. You’re considered Cloaked from any adversary for whom the cloud blocks line of sight.

", + "description": "

Make a Spellcast Roll (15). On a success, create a temporary dark cloud that covers any area within Close range. Anyone in this cloud can’t see outside of it, and anyone outside of it can’t see in. You’re considered Cloaked from any adversary for whom the cloud blocks line of sight.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "nIgBwYfAVAJ98lzb": { "type": "attack", "_id": "nIgBwYfAVAJ98lzb", "systemPath": "actions", - "description": "", + "description": "

Make a Spellcast Roll (15). On a success, create a temporary dark cloud that covers any area within Close range. Anyone in this cloud can’t see outside of it, and anyone outside of it can’t see in. You’re considered Cloaked from any adversary for whom the cloud blocks line of sight.

@Template[type:emanation|range:c]

", "chatDisplay": true, "actionType": "action", "cost": [], @@ -22,7 +22,7 @@ "recovery": null }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { @@ -52,8 +52,7 @@ }, "name": "SpellCast: Dark Cloud", "img": "icons/magic/air/wind-vortex-swirl-purple.webp", - "range": "", - "areas": [] + "range": "" } }, "originItemType": null, diff --git a/src/packs/subclasses/feature_Elemental_Aura_2JH9NaOh69yN80Gw.json b/src/packs/subclasses/feature_Elemental_Aura_2JH9NaOh69yN80Gw.json index 7a3ebd91..7dbae2f6 100644 --- a/src/packs/subclasses/feature_Elemental_Aura_2JH9NaOh69yN80Gw.json +++ b/src/packs/subclasses/feature_Elemental_Aura_2JH9NaOh69yN80Gw.json @@ -22,8 +22,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -48,7 +48,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -134,7 +134,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/subclasses/feature_Elemental_Dominion_EFUJHrkTuyv8uA9l.json b/src/packs/subclasses/feature_Elemental_Dominion_EFUJHrkTuyv8uA9l.json index 2476046c..4297173f 100644 --- a/src/packs/subclasses/feature_Elemental_Dominion_EFUJHrkTuyv8uA9l.json +++ b/src/packs/subclasses/feature_Elemental_Dominion_EFUJHrkTuyv8uA9l.json @@ -189,18 +189,18 @@ "type": "withinRange", "target": "hostile", "range": "veryFar" - }, - "changes": [], - "duration": { - "type": "temporary" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

When an attack against you succeeds, you can mark a Stress to make the attacker temporarily Vulnerable.

", "tint": "#ffffff", @@ -212,16 +212,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!EFUJHrkTuyv8uA9l.bGwFZZT4juuaIRmZ" }, { diff --git a/src/packs/subclasses/feature_Elemental_Incarnation_f37TTgCc0Q3Ih1A1.json b/src/packs/subclasses/feature_Elemental_Incarnation_f37TTgCc0Q3Ih1A1.json index 45ffde60..30ffb50b 100644 --- a/src/packs/subclasses/feature_Elemental_Incarnation_f37TTgCc0Q3Ih1A1.json +++ b/src/packs/subclasses/feature_Elemental_Incarnation_f37TTgCc0Q3Ih1A1.json @@ -29,8 +29,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -56,7 +56,7 @@ } } } - }, + ], "includeBase": false }, "target": { @@ -148,8 +148,8 @@ "recovery": null }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -174,7 +174,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/subclasses/feature_Elusive_Predator_Cjtc43V3IzAmfIFG.json b/src/packs/subclasses/feature_Elusive_Predator_Cjtc43V3IzAmfIFG.json index 82cd55a0..18f80cdb 100644 --- a/src/packs/subclasses/feature_Elusive_Predator_Cjtc43V3IzAmfIFG.json +++ b/src/packs/subclasses/feature_Elusive_Predator_Cjtc43V3IzAmfIFG.json @@ -26,28 +26,27 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.evasion", - "value": 2, - "priority": null, - "type": "add" - } - ], - "duration": { - "type": "", - "description": "

Against the attack.

" } }, "_id": "X4llFOcAcdJLbear", "img": "icons/creatures/mammals/beast-horned-scaled-glowing-orange.webp", + "changes": [ + { + "key": "system.evasion", + "mode": 2, + "value": "2", + "priority": null + } + ], "disabled": true, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

When your Focus makes an attack against you, you gain a +2 bonus to your Evasion against the attack.

", "origin": null, @@ -59,16 +58,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!Cjtc43V3IzAmfIFG.X4llFOcAcdJLbear" } ], diff --git a/src/packs/subclasses/feature_Gifted_Performer_99U7YWNCxFZHCiT0.json b/src/packs/subclasses/feature_Gifted_Performer_99U7YWNCxFZHCiT0.json index f65cd041..f53f7c31 100644 --- a/src/packs/subclasses/feature_Gifted_Performer_99U7YWNCxFZHCiT0.json +++ b/src/packs/subclasses/feature_Gifted_Performer_99U7YWNCxFZHCiT0.json @@ -21,8 +21,8 @@ "recovery": "longRest" }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -47,7 +47,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -115,8 +115,8 @@ "recovery": "longRest" }, "damage": { - "parts": { - "hope": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -141,7 +141,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -180,7 +180,7 @@ "effects": [ { "name": "Epic Song", - "img": "icons/tools/instruments/harp-yellow-teal.webp", + "img": "icons/svg/ice-aura.svg", "origin": "Compendium.daggerheart.subclasses.Item.6j1RP4fz3BwSfoli", "transfer": false, "_id": "FK4IdbxluRErfYor", @@ -191,18 +191,18 @@ "type": "withinRange", "target": "hostile", "range": "close" - }, - "changes": [], - "duration": { - "type": "temporary" } }, + "changes": [], "disabled": false, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, "description": "

Make a target within Close range temporarily Vulnerable.

", "tint": "#ffffff", @@ -214,16 +214,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!99U7YWNCxFZHCiT0.FK4IdbxluRErfYor" } ], diff --git a/src/packs/subclasses/feature_Honed_Expertise_w1BwNKxbQOSizLmZ.json b/src/packs/subclasses/feature_Honed_Expertise_w1BwNKxbQOSizLmZ.json index 48973ad9..1fad2396 100644 --- a/src/packs/subclasses/feature_Honed_Expertise_w1BwNKxbQOSizLmZ.json +++ b/src/packs/subclasses/feature_Honed_Expertise_w1BwNKxbQOSizLmZ.json @@ -23,7 +23,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/subclasses/feature_Natural_Evasion_TnuLBtHQGbqyzn82.json b/src/packs/subclasses/feature_Natural_Evasion_TnuLBtHQGbqyzn82.json index 517e1fe1..628fabed 100644 --- a/src/packs/subclasses/feature_Natural_Evasion_TnuLBtHQGbqyzn82.json +++ b/src/packs/subclasses/feature_Natural_Evasion_TnuLBtHQGbqyzn82.json @@ -31,7 +31,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/subclasses/feature_Regeneration_KRyrbSLVGreIOTZe.json b/src/packs/subclasses/feature_Regeneration_KRyrbSLVGreIOTZe.json index ab748169..b7c39f2a 100644 --- a/src/packs/subclasses/feature_Regeneration_KRyrbSLVGreIOTZe.json +++ b/src/packs/subclasses/feature_Regeneration_KRyrbSLVGreIOTZe.json @@ -29,8 +29,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": false @@ -54,7 +54,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/subclasses/feature_Revenge_oNfA5F9cKwNR7joq.json b/src/packs/subclasses/feature_Revenge_oNfA5F9cKwNR7joq.json index b7e2e8b9..f663201d 100644 --- a/src/packs/subclasses/feature_Revenge_oNfA5F9cKwNR7joq.json +++ b/src/packs/subclasses/feature_Revenge_oNfA5F9cKwNR7joq.json @@ -29,8 +29,8 @@ "recovery": null }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -55,7 +55,7 @@ } } } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/subclasses/feature_Rousing_Speech_PCmYTX02JLzBpgml.json b/src/packs/subclasses/feature_Rousing_Speech_PCmYTX02JLzBpgml.json index b5ca1eba..f1596519 100644 --- a/src/packs/subclasses/feature_Rousing_Speech_PCmYTX02JLzBpgml.json +++ b/src/packs/subclasses/feature_Rousing_Speech_PCmYTX02JLzBpgml.json @@ -21,8 +21,8 @@ "recovery": "longRest" }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -47,7 +47,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -72,16 +72,7 @@ }, "name": "Talk to your allies!", "img": "icons/equipment/head/mask-plague-leather-brown.webp", - "range": "far", - "areas": [ - { - "name": "Rousing Speech", - "type": "placed", - "shape": "emanation", - "size": "far", - "effects": [] - } - ] + "range": "far" } }, "originItemType": null, diff --git a/src/packs/subclasses/feature_Sparing_Touch_GfOSgVJW8bS1OjNq.json b/src/packs/subclasses/feature_Sparing_Touch_GfOSgVJW8bS1OjNq.json index 86de0fe8..deb4af6b 100644 --- a/src/packs/subclasses/feature_Sparing_Touch_GfOSgVJW8bS1OjNq.json +++ b/src/packs/subclasses/feature_Sparing_Touch_GfOSgVJW8bS1OjNq.json @@ -39,8 +39,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -65,7 +65,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -116,8 +116,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "stress": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -142,7 +142,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { diff --git a/src/packs/subclasses/feature_Thrive_in_Chaos_1nmFmkNXY6OYyyju.json b/src/packs/subclasses/feature_Thrive_in_Chaos_1nmFmkNXY6OYyyju.json index b65184e9..bbdd8707 100644 --- a/src/packs/subclasses/feature_Thrive_in_Chaos_1nmFmkNXY6OYyyju.json +++ b/src/packs/subclasses/feature_Thrive_in_Chaos_1nmFmkNXY6OYyyju.json @@ -31,7 +31,7 @@ "consumeOnSuccess": false }, "damage": { - "parts": {}, + "parts": [], "includeBase": false }, "target": { diff --git a/src/packs/subclasses/feature_Transcendence_th6HZwEFnVBjUtqm.json b/src/packs/subclasses/feature_Transcendence_th6HZwEFnVBjUtqm.json index c03c10b5..5f2df7cb 100644 --- a/src/packs/subclasses/feature_Transcendence_th6HZwEFnVBjUtqm.json +++ b/src/packs/subclasses/feature_Transcendence_th6HZwEFnVBjUtqm.json @@ -58,29 +58,29 @@ "type": "withinRange", "target": "hostile", "range": "melee" - }, - "changes": [ - { - "key": "system.damageThresholds.severe", - "value": "+4", - "priority": null, - "type": "add" - } - ], - "duration": { - "type": "" } }, "_id": "zFOpzO3tBJPcZcRc", "img": "icons/magic/fire/elemental-fire-flying.webp", + "changes": [ + { + "key": "system.damageThresholds.severe", + "mode": 2, + "value": "+4", + "priority": null + } + ], "disabled": true, "duration": { - "value": null, - "units": "seconds", - "expiry": null, - "expired": false + "startTime": null, + "combat": null, + "seconds": null, + "rounds": null, + "turns": null, + "startRound": null, + "startTurn": null }, - "description": "

+4 bonus to your Severe threshold

", + "description": "

+4 bonus to your Severe threshold

", "origin": null, "tint": "#ffffff", "transfer": true, @@ -90,16 +90,6 @@ "_stats": { "compendiumSource": null }, - "start": { - "time": 0, - "combat": null, - "combatant": null, - "initiative": null, - "round": null, - "turn": null - }, - "showIcon": 1, - "folder": null, "_key": "!items.effects!th6HZwEFnVBjUtqm.zFOpzO3tBJPcZcRc" }, { diff --git a/src/packs/subclasses/feature_Warden_s_Protection_2F1bUFY80oce97C9.json b/src/packs/subclasses/feature_Warden_s_Protection_2F1bUFY80oce97C9.json index a6cb2d97..e80a770a 100644 --- a/src/packs/subclasses/feature_Warden_s_Protection_2F1bUFY80oce97C9.json +++ b/src/packs/subclasses/feature_Warden_s_Protection_2F1bUFY80oce97C9.json @@ -23,8 +23,8 @@ "consumeOnSuccess": false }, "damage": { - "parts": { - "hitPoints": { + "parts": [ + { "value": { "custom": { "enabled": true, @@ -49,7 +49,7 @@ }, "type": [] } - }, + ], "includeBase": false }, "target": { @@ -74,16 +74,7 @@ }, "name": "Healing", "img": "icons/commodities/currency/coin-embossed-ruby-gold.webp", - "range": "", - "areas": [ - { - "name": "Warden’s Protection", - "type": "placed", - "shape": "emanation", - "size": "close", - "effects": [] - } - ] + "range": "" } }, "originItemType": null, diff --git a/styles/daggerheart.less b/styles/daggerheart.less index 4da2e043..187402fb 100755 --- a/styles/daggerheart.less +++ b/styles/daggerheart.less @@ -1,11 +1,19 @@ @import './less/sheets/index.less'; @import './less/sheets-settings/index.less'; + @import './less/dialog/index.less'; -@import './less/hud/index.less'; -@import './less/utils/index.less'; + +@import './less//hud/index.less'; + +@import './less/utils/colors.less'; +@import './less/utils/fonts.less'; + @import './less/global/index.less'; + @import './less/ui/index.less'; + @import './less/ux/index.less'; @import '../build/tagify.css'; +@import './less/utils/mixin.less'; diff --git a/styles/less/dialog/actions/index.less b/styles/less/dialog/actions/index.less deleted file mode 100644 index e9cc0401..00000000 --- a/styles/less/dialog/actions/index.less +++ /dev/null @@ -1 +0,0 @@ -@import "./action-list.less"; \ No newline at end of file diff --git a/styles/less/dialog/attribution/index.less b/styles/less/dialog/attribution/index.less deleted file mode 100644 index 2f8eaf45..00000000 --- a/styles/less/dialog/attribution/index.less +++ /dev/null @@ -1 +0,0 @@ -@import "./sheet.less"; \ No newline at end of file diff --git a/styles/less/dialog/beastform/index.less b/styles/less/dialog/beastform/index.less deleted file mode 100644 index 2f8eaf45..00000000 --- a/styles/less/dialog/beastform/index.less +++ /dev/null @@ -1 +0,0 @@ -@import "./sheet.less"; \ No newline at end of file diff --git a/styles/less/dialog/beastform/sheet.less b/styles/less/dialog/beastform/sheet.less index 6d1a8a2a..9e87f53b 100644 --- a/styles/less/dialog/beastform/sheet.less +++ b/styles/less/dialog/beastform/sheet.less @@ -43,7 +43,7 @@ text-align: center; font-size: var(--font-size-16); margin: 0 4px; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; color: light-dark(@dark, @beige); background-image: url('../assets/parchments/dh-parchment-dark.png'); @@ -58,7 +58,7 @@ position: relative; display: flex; justify-content: center; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; cursor: pointer; width: 120px; @@ -164,7 +164,7 @@ .hybrid-data { padding: 0 2px; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; color: light-dark(@dark, @beige); background-image: url('../assets/parchments/dh-parchment-dark.png'); @@ -191,7 +191,7 @@ flex-direction: column; gap: 4px; padding: 0 4px; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; color: light-dark(@dark, @beige); background-image: url('../assets/parchments/dh-parchment-dark.png'); @@ -204,44 +204,6 @@ } } - .modifications-container { - display: flex; - flex-direction: column; - gap: 16px; - - .trait-bonuses-container { - display: flex; - flex-direction: column; - gap: 8px; - - .bonus-separator { - background: light-dark(@dark-blue, @golden); - mask-image: linear-gradient(270deg, transparent 0%, black 50%, transparent 100%); - height: 2px; - width: calc(100% - 10px); - } - - .trait-bonus-container { - display: flex; - gap: 4px; - - .trait-card { - border: 1px solid @color-border; - border-radius: 6px; - padding: 2px; - opacity: 0.4; - flex: 1; - white-space: nowrap; - text-align: center; - - &.selected { - opacity: 1; - } - } - } - } - } - footer { margin-top: 8px; display: flex; diff --git a/styles/less/dialog/character-creation/index.less b/styles/less/dialog/character-creation/index.less deleted file mode 100644 index adf8d57a..00000000 --- a/styles/less/dialog/character-creation/index.less +++ /dev/null @@ -1,4 +0,0 @@ -@import "./sheet.less"; -@import "./creation-action-footer.less"; -@import "./selections-container.less"; -@import "./tab-navigation.less"; \ No newline at end of file diff --git a/styles/less/dialog/character-creation/selections-container.less b/styles/less/dialog/character-creation/selections-container.less index ebf12eda..f774eb72 100644 --- a/styles/less/dialog/character-creation/selections-container.less +++ b/styles/less/dialog/character-creation/selections-container.less @@ -79,7 +79,7 @@ font-weight: bold; padding: 0 2px; background-image: url(../assets/parchments/dh-parchment-light.png); - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; color: light-dark(@beige, @dark); opacity: 0.4; @@ -114,6 +114,9 @@ .card-preview-container { flex: 1; + } + + .card-preview-container { border-color: light-dark(@dark-blue, @golden); } @@ -203,7 +206,7 @@ height: 16px; width: 110px; min-height: unset; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); color: light-dark(@beige, @beige); background-color: light-dark(var(--color-warm-3), var(--color-warm-3)); @@ -230,7 +233,7 @@ .suggested-trait-container { width: 56px; white-space: nowrap; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; color: light-dark(@beige, @dark); background-image: url('../assets/parchments/dh-parchment-light.png'); @@ -242,21 +245,12 @@ display: flex; align-items: center; justify-content: space-evenly; - gap: 2px; + gap: 8px; .trait-container { - span { - font-size: var(--font-size-10); - } - width: 65px; - height: 65px; + width: 60px; + height: 60px; background: url(../assets/svg/trait-shield.svg) no-repeat; - background-size: 100%; - padding-top: 3px; - display: flex; - flex-direction: column; - align-items: center; - row-gap: 3px; div { filter: drop-shadow(0 0 3px black); @@ -345,7 +339,7 @@ display: flex; justify-content: center; position: relative; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; .nav-section-text { @@ -383,7 +377,7 @@ width: 56px; text-align: center; line-height: 1; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; color: light-dark(@beige, @dark); background-image: url(../assets/parchments/dh-parchment-light.png); @@ -447,7 +441,7 @@ height: 100%; .simple-equipment { - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 8px; position: relative; display: flex; @@ -466,7 +460,7 @@ top: -8px; font-size: var(--font-size-12); white-space: nowrap; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; color: @dark; background-image: url('../assets/parchments/dh-parchment-light.png'); diff --git a/styles/less/dialog/character-creation/tab-navigation.less b/styles/less/dialog/character-creation/tab-navigation.less index 85541db7..36b89d5a 100644 --- a/styles/less/dialog/character-creation/tab-navigation.less +++ b/styles/less/dialog/character-creation/tab-navigation.less @@ -7,7 +7,7 @@ border-top: 0; a { - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); &[disabled] { opacity: 0.4; diff --git a/styles/less/dialog/character-reset/index.less b/styles/less/dialog/character-reset/index.less deleted file mode 100644 index 1c574e81..00000000 --- a/styles/less/dialog/character-reset/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './sheet.less'; \ No newline at end of file diff --git a/styles/less/dialog/compendiumBrowserPackDialog/index.less b/styles/less/dialog/compendiumBrowserPackDialog/index.less deleted file mode 100644 index 1c574e81..00000000 --- a/styles/less/dialog/compendiumBrowserPackDialog/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './sheet.less'; \ No newline at end of file diff --git a/styles/less/dialog/compendiumBrowserPackDialog/sheet.less b/styles/less/dialog/compendiumBrowserPackDialog/sheet.less index b16f1086..dfe375b5 100644 --- a/styles/less/dialog/compendiumBrowserPackDialog/sheet.less +++ b/styles/less/dialog/compendiumBrowserPackDialog/sheet.less @@ -67,6 +67,7 @@ i { font-size: 18px; + // color: light-dark(@dark-blue, @golden); } } } diff --git a/styles/less/dialog/damage-reduction/damage-reduction-container.less b/styles/less/dialog/damage-reduction/damage-reduction-container.less index 6f7ffb51..2f343fb3 100644 --- a/styles/less/dialog/damage-reduction/damage-reduction-container.less +++ b/styles/less/dialog/damage-reduction/damage-reduction-container.less @@ -35,10 +35,7 @@ display: flex; flex-direction: column; align-items: center; - - &.full-width { - width: 100%; - } + width: 100%; } .padded { @@ -48,7 +45,6 @@ .armor-title { margin: 0; white-space: nowrap; - width: 100%; } .resources-container { @@ -66,22 +62,17 @@ .mark-selection { display: flex; - flex-direction: column; + align-items: center; width: 100%; margin: 0; - h4 { - margin: 0; - } - .mark-selection-inner { display: flex; - justify-content: center; gap: 8px; .mark-container { cursor: pointer; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; height: 26px; padding: 0 1px; @@ -100,19 +91,6 @@ opacity: 0.2; } - &.spent { - ::after { - position: absolute; - content: '/'; - color: red; - font-weight: 700; - font-size: 1.8em; - left: -1px; - top: -7px; - rotate: 13deg; - } - } - .fa-shield { position: relative; right: 0.5px; @@ -126,7 +104,7 @@ width: 100%; .chip-inner-container { - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; height: 26px; padding: 0 4px; diff --git a/styles/less/dialog/damage-reduction/index.less b/styles/less/dialog/damage-reduction/index.less deleted file mode 100644 index 0b8e94a8..00000000 --- a/styles/less/dialog/damage-reduction/index.less +++ /dev/null @@ -1,2 +0,0 @@ -@import './sheets.less'; -@import './damage-reduction-container.less'; \ No newline at end of file diff --git a/styles/less/dialog/damage-selection/index.less b/styles/less/dialog/damage-selection/index.less deleted file mode 100644 index 1c574e81..00000000 --- a/styles/less/dialog/damage-selection/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './sheet.less'; \ No newline at end of file diff --git a/styles/less/dialog/damage-selection/sheet.less b/styles/less/dialog/damage-selection/sheet.less index 9f8cfc8a..461fb0b5 100644 --- a/styles/less/dialog/damage-selection/sheet.less +++ b/styles/less/dialog/damage-selection/sheet.less @@ -17,50 +17,6 @@ } } - .bonuses { - gap: 4px; - .critical-chip { - flex: 0; - - display: flex; - align-items: center; - border-radius: 5px; - width: fit-content; - gap: 5px; - cursor: pointer; - padding: 5px; - transition: all 0.3s ease; - - background: @green-10; - color: @green; - - &.selected { - color: @beige; - background: @gradient-green; - } - } - } - - .group-attack-container { - margin: 0; - - .group-attack-inner-container { - display: flex; - align-items: center; - gap: 16px; - - > * { - flex: 1; - } - - .group-attack-tools { - display: flex; - align-items: center; - gap: 4px; - } - } - } - .damage-section-controls { display: flex; align-items: center; diff --git a/styles/less/dialog/death-move/index.less b/styles/less/dialog/death-move/index.less deleted file mode 100644 index 8a8a16c4..00000000 --- a/styles/less/dialog/death-move/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './death-move-container.less'; \ No newline at end of file diff --git a/styles/less/dialog/dice-roll/index.less b/styles/less/dialog/dice-roll/index.less deleted file mode 100644 index 8e0af6e0..00000000 --- a/styles/less/dialog/dice-roll/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './roll-selection.less'; \ No newline at end of file diff --git a/styles/less/dialog/dice-roll/roll-selection.less b/styles/less/dialog/dice-roll/roll-selection.less index e3551902..7fdae77a 100644 --- a/styles/less/dialog/dice-roll/roll-selection.less +++ b/styles/less/dialog/dice-roll/roll-selection.less @@ -56,7 +56,30 @@ cursor: pointer; padding: 5px; background: light-dark(@dark-blue-10, @golden-10); - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); + + .label { + font-style: normal; + font-weight: 400; + font-size: var(--font-size-14); + line-height: 17px; + } + + &.selected { + background: light-dark(@dark-blue-40, @golden-40); + } + } + + .tag-team-controller { + display: flex; + align-items: center; + border-radius: 5px; + width: fit-content; + gap: 5px; + cursor: pointer; + padding: 5px; + background: light-dark(@dark-blue-10, @golden-10); + color: light-dark(@dark-blue, @golden); .label { font-style: normal; @@ -129,7 +152,7 @@ cursor: pointer; padding: 5px; background: light-dark(@dark-blue-10, @golden-10); - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); .label { font-style: normal; diff --git a/styles/less/dialog/downtime/downtime-container.less b/styles/less/dialog/downtime/downtime-container.less index 33d153fd..eb615ef0 100644 --- a/styles/less/dialog/downtime/downtime-container.less +++ b/styles/less/dialog/downtime/downtime-container.less @@ -37,7 +37,7 @@ .activity-marker { font-size: 0.5rem; flex: none; - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); margin-right: 4px; } @@ -55,7 +55,7 @@ .activity-selected-marker { font-size: var(--font-size-14); - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; color: light-dark(@dark, @beige); background-image: url(../assets/parchments/dh-parchment-dark.png); @@ -78,7 +78,7 @@ } .refreshable-container { - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; color: light-dark(@dark, @beige); background-image: url('../assets/parchments/dh-parchment-dark.png'); diff --git a/styles/less/dialog/downtime/index.less b/styles/less/dialog/downtime/index.less deleted file mode 100644 index 09cc2dfe..00000000 --- a/styles/less/dialog/downtime/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './downtime-container.less'; \ No newline at end of file diff --git a/styles/less/dialog/group-roll-dialog/index.less b/styles/less/dialog/group-roll-dialog/index.less deleted file mode 100644 index f90b57dc..00000000 --- a/styles/less/dialog/group-roll-dialog/index.less +++ /dev/null @@ -1,3 +0,0 @@ -@import './sheet.less'; -@import './initialization.less'; -@import './main.less'; diff --git a/styles/less/dialog/group-roll-dialog/initialization.less b/styles/less/dialog/group-roll-dialog/initialization.less deleted file mode 100644 index b32f4756..00000000 --- a/styles/less/dialog/group-roll-dialog/initialization.less +++ /dev/null @@ -1,76 +0,0 @@ -.daggerheart.dialog.dh-style.views.group-roll-dialog { - .initialization-container.active { - display: flex; - flex-direction: column; - overflow: hidden; - - .main-roll { - display: flex; - flex-direction: column; - text-align: center; - padding-bottom: 4px; - - &.inactive { - opacity: 0.4; - } - } - - .hint { - color: var(--color-form-hint); - line-height: 1; - padding: var(--spacer-8) 0; - font-family: var(--dh-font-body); - font-size: var(--font-size-12); - font-weight: 300; - } - - .members-container { - display: flex; - flex-direction: column; - gap: 8px; - overflow-y: auto; - - .member-container { - display: flex; - position: relative; - justify-content: center; - height: unset; - padding: 4px 8px; - gap: var(--spacer-8); - flex: 0 0 auto; - - &:not(.inactive) { - background: @golden-bg; - } - - .name { - flex: 1; - color: light-dark(@dark, @beige); - font-weight: 500; - text-align: left; - } - } - } - - footer { - margin-top: 12px; - display: flex; - gap: 8px; - - button { - flex: 1; - } - - .finish-tools { - flex: none; - display: flex; - align-items: center; - gap: 4px; - - &.inactive { - opacity: 0.4; - } - } - } - } -} diff --git a/styles/less/dialog/group-roll-dialog/main.less b/styles/less/dialog/group-roll-dialog/main.less deleted file mode 100644 index e30f4e29..00000000 --- a/styles/less/dialog/group-roll-dialog/main.less +++ /dev/null @@ -1,273 +0,0 @@ -.daggerheart.dialog.dh-style.views.group-roll-dialog { - .group-roll.active { - display: flex; - flex-direction: column; - overflow: hidden; - - a.roll-button { - &:hover { - text-shadow: none; - filter: drop-shadow(0 0 3px @golden-90); - } - } - - .aiding-members { - display: flex; - flex-direction: column; - gap: 6px; - overflow-y: auto; - } - - .item-tags { - gap: 6px; - .tag.failure, - .tag.success { - font-weight: 600; - justify-content: center; - min-width: 3ch; - } - - .tag.success { - border-color: @green; - background: @green-10; - color: @green; - } - - .tag.failure { - border-color: @red; - background: @red-10; - color: @red; - } - - .tag { - padding-top: 0; - padding-bottom: 0; - line-height: 1.1875rem; - } - } - - .with-result { - border-radius: 5px; - background: var(--duality-bg); - color: var(--color-light-2); - - &.hope { - --duality-text-color: @golden; - --duality-bg: url(../assets/parchments/dh-parchment-hope.png); - } - - &.fear { - --duality-text-color: @chat-blue; - --duality-bg: url(../assets/parchments/dh-parchment-fear.png); - } - - &.critical { - --duality-text-color: @chat-purple; - --duality-bg: url(../assets/parchments/dh-parchment-critical.png); - } - - .duality-label { - font-family: var(--dh-font-subtitle); - color: var(--duality-text-color); - font-weight: 700; - } - } - - .member-roll-container { - display: flex; - align-items: center; - justify-content: space-between; - gap: 8px; - min-height: 3.375rem; - - &.inactive { - pointer-events: none; - } - - .name-area { - display: flex; - flex-direction: column; - flex: 1; - justify-content: center; - .name { - font-weight: 500; - } - .trait { - display: flex; - align-items: center; - gap: 6px; - select { - --input-height: 2em; - width: auto; - } - } - .item-tags { - align-items: stretch; - } - } - - .buttons { - display: flex; - flex-direction: row; - button { - --button-text-color: @color-text-primary; - --button-size: 1.5em; - padding: 0 var(--spacer-4); - img { - width: 100%; - height: 100%; - object-fit: contain; - } - } - } - - a.roll-button.initial-roll { - width: 1.875rem; - height: 1.875rem; - margin-right: 2px; /** makes hover look a bit nicer */ - } - - .with-result { - display: flex; - justify-content: end; - align-items: center; - gap: 6px; - - .roll-data { - display: flex; - flex-direction: column; - align-items: end; - justify-content: center; - padding: 0 4px; - min-height: 3rem; - - .duality-label { - font-size: var(--font-size-15); - - .unused-damage { - text-decoration: line-through; - } - - .with { - font-size: var(--font-size-10); - } - } - - .roll-dice-container { - display: flex; - align-items: center; - justify-content: center; - flex-wrap: wrap; - gap: 2px; - - .roll-dice { - position: relative; - display: flex; - align-items: center; - justify-content: center; - - .dice-label { - position: absolute; - color: white; - font-size: 1rem; - paint-order: stroke fill; - -webkit-text-stroke: 2px black; - } - - img { - height: 1.3125rem; - } - } - - .roll-operator { - font-size: var(--font-size-18); - padding: 0 1px; - } - - .roll-value { - font-size: var(--font-size-16); - padding: 0 1px; - } - } - } - - .buttons { - flex-direction: column; - button { - color: var(--medium-red); - &[data-success=true] { - color: var(--green); - } - &.active { - text-shadow: 0 0 1px light-dark(@dark-80, @beige-80); - } - &.inactive { - opacity: 0.35; - } - } - } - } - } - } - - .group-roll-results { - display: flex; - flex-direction: column; - align-items: stretch; - gap: 4px; - font-size: var(--font-size-12); - padding: 6px 12px; - margin-top: 8px; - - &.empty { - color: light-dark(@dark-blue-90, @beige-80); - border-radius: 3px; - justify-content: center; - border: 1px dashed light-dark(@dark-blue-90, @beige-80); - text-align: center; - height: 3.25rem; - font-family: @font-body; - } - - .row { - display: flex; - align-items: center; - justify-content: space-between; - } - - .divider { - height: 1px; - background-image: linear-gradient(90deg, transparent 0%, var(--duality-text-color) 50%, transparent 100%); - margin-block: var(--spacer-4); - } - - .modifiers .item-tags { - min-height: calc(2px + 1.1875rem); - } - - .total { - .label { - font-size: var(--font-size-14); - } - .duality-label { - display: flex; - align-items: center; - gap: var(--spacer-4); - .value { - font-size: 20px; - } - } - } - } - - .finish-container { - margin-top: 16px; - gap: 16px; - display: grid; - grid-template-columns: 1fr 1fr 1fr; - - .finish-button { - grid-column: span 2; - } - } -} diff --git a/styles/less/dialog/group-roll-dialog/sheet.less b/styles/less/dialog/group-roll-dialog/sheet.less deleted file mode 100644 index 938710c9..00000000 --- a/styles/less/dialog/group-roll-dialog/sheet.less +++ /dev/null @@ -1,48 +0,0 @@ -.daggerheart.dialog.dh-style.views.group-roll-dialog { - .window-content { - h1 { - color: @color-text-emphatic; - font: 700 var(--font-size-24) var(--dh-font-subtitle); - text-align: center; - } - - header { - --bar-color: light-dark(@dark-blue, @golden); - color: light-dark(@dark, @beige); - display: flex; - justify-content: center; - align-items: center; - - &:not(:first-child) { - margin-top: var(--spacer-8); - } - - span { - padding: 0 10px; - } - - &:before { - content: ' '; - flex: 1; - height: 1px; - background: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, var(--bar-color) 100%); - } - - &:after { - content: ' '; - flex: 1; - height: 1px; - background: linear-gradient(90deg, var(--bar-color) 0%, rgba(0, 0, 0, 0) 100%); - } - } - - img.portrait { - border-radius: 50%; - border: none; - object-fit: cover; - object-position: center top; - width: 2.5rem; - height: 2.5rem; - } - } -} \ No newline at end of file diff --git a/styles/less/dialog/group-roll/group-roll.less b/styles/less/dialog/group-roll/group-roll.less new file mode 100644 index 00000000..f2895d31 --- /dev/null +++ b/styles/less/dialog/group-roll/group-roll.less @@ -0,0 +1,50 @@ +@import '../../utils/colors.less'; + +.application.daggerheart.group-roll { + fieldset.one-column { + min-width: 500px; + margin-bottom: 10px; + } + .actor-item { + display: flex; + align-items: center; + gap: 15px; + width: 100%; + + img { + height: 40px; + width: 40px; + border-radius: 50%; + object-fit: cover; + } + + .actor-info { + display: flex; + flex-direction: column; + gap: 10px; + + .actor-check-info { + display: flex; + gap: 10px; + + .form-fields { + display: flex; + gap: 5px; + align-items: center; + + input { + max-width: 40px; + text-align: center; + } + } + } + } + + .controls { + margin-left: auto; + } + } + .tooltip-container { + width: 100%; + } +} diff --git a/styles/less/dialog/image-select/index.less b/styles/less/dialog/image-select/index.less deleted file mode 100644 index 1c574e81..00000000 --- a/styles/less/dialog/image-select/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './sheet.less'; \ No newline at end of file diff --git a/styles/less/dialog/image-select/sheet.less b/styles/less/dialog/image-select/sheet.less index 7a3a8468..3ed4f583 100644 --- a/styles/less/dialog/image-select/sheet.less +++ b/styles/less/dialog/image-select/sheet.less @@ -12,7 +12,7 @@ img { width: 136px; height: 136px; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; opacity: 0.4; diff --git a/styles/less/dialog/index.less b/styles/less/dialog/index.less index 4ce4834e..0c70df9f 100644 --- a/styles/less/dialog/index.less +++ b/styles/less/dialog/index.less @@ -1,20 +1,47 @@ -@import './actions/index.less'; -@import './attribution/index.less'; -@import './beastform/index.less'; -@import './character-creation/index.less'; -@import './character-reset/index.less'; -@import './compendiumBrowserPackDialog/index.less'; -@import './damage-reduction/index.less'; -@import './damage-selection/index.less'; -@import './death-move/index.less'; -@import './dice-roll/index.less'; -@import './downtime/index.less'; -@import './group-roll-dialog/index.less'; -@import './level-up/index.less'; -@import './resource-dice/index.less'; -@import './multiclass-choice/index.less'; -@import './tag-team-dialog/index.less'; -@import './image-select/index.less'; -@import './item-transfer/index.less'; -@import './settings/index.less'; -@import './risk-it-all/index.less'; \ No newline at end of file +@import './attribution/sheet.less'; +@import './level-up/navigation-container.less'; +@import './level-up/selections-container.less'; +@import './level-up/sheet.less'; +@import './level-up/summary-container.less'; +@import './level-up/tiers-container.less'; +@import './level-up/footer.less'; + +@import './resource-dice/sheet.less'; + +@import './actions/action-list.less'; + +@import './damage-selection/sheet.less'; + +@import './downtime/downtime-container.less'; + +@import './death-move/death-move-container.less'; + +@import './beastform/sheet.less'; + +@import './character-creation/creation-action-footer.less'; +@import './character-creation/selections-container.less'; +@import './character-creation/sheet.less'; +@import './character-creation/tab-navigation.less'; + +@import './dice-roll/roll-selection.less'; +@import './damage-reduction/damage-reduction-container.less'; +@import './damage-reduction/sheets.less'; + +@import './multiclass-choice/sheet.less'; + +@import './reroll-dialog/sheet.less'; + +@import './group-roll/group-roll.less'; +@import './tag-team-dialog/sheet.less'; + +@import './image-select/sheet.less'; + +@import './item-transfer/sheet.less'; + +@import './settings/change-currency-icon.less'; + +@import './risk-it-all/sheet.less'; + +@import './character-reset/sheet.less'; + +@import './compendiumBrowserPackDialog/sheet.less'; diff --git a/styles/less/dialog/item-transfer/index.less b/styles/less/dialog/item-transfer/index.less deleted file mode 100644 index 1c574e81..00000000 --- a/styles/less/dialog/item-transfer/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './sheet.less'; \ No newline at end of file diff --git a/styles/less/dialog/level-up/index.less b/styles/less/dialog/level-up/index.less deleted file mode 100644 index 849a4d36..00000000 --- a/styles/less/dialog/level-up/index.less +++ /dev/null @@ -1,6 +0,0 @@ -@import './navigation-container.less'; -@import './selections-container.less'; -@import './summary-container.less'; -@import './tiers-container.less'; -@import './footer.less'; -@import './sheet.less'; diff --git a/styles/less/dialog/level-up/navigation-container.less b/styles/less/dialog/level-up/navigation-container.less index 6bf80d7c..282d683f 100644 --- a/styles/less/dialog/level-up/navigation-container.less +++ b/styles/less/dialog/level-up/navigation-container.less @@ -19,7 +19,7 @@ a, span { - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); } } } diff --git a/styles/less/dialog/level-up/selections-container.less b/styles/less/dialog/level-up/selections-container.less index 8c0dbaec..6a551865 100644 --- a/styles/less/dialog/level-up/selections-container.less +++ b/styles/less/dialog/level-up/selections-container.less @@ -3,7 +3,12 @@ .daggerheart.levelup { .levelup-selections-container { + overflow: auto; padding: 10px 0; + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; + max-height: 500px; + mask-image: linear-gradient(0deg, transparent 0%, black 5%, black 95%, transparent 100%); .achievement-experience-cards { display: flex; @@ -40,22 +45,20 @@ .levelup-card-selection { display: flex; + flex-wrap: wrap; justify-content: center; gap: 40px; height: 190px; - align-items: stretch; .card-preview-container { - height: 190px; + height: 100%; max-width: 200px; } .levelup-domains-selection-container { - display: grid; - grid-auto-flow: column; - grid-template-rows: repeat(2, minmax(0, 1fr)); - height: 100%; - gap: 4px; + display: flex; + flex-direction: column; + gap: 8px; .levelup-domain-selection-container { display: flex; @@ -63,8 +66,6 @@ align-items: center; position: relative; cursor: pointer; - overflow: hidden; - width: 93px; &.disabled { pointer-events: none; @@ -73,20 +74,16 @@ .levelup-domain-label { position: absolute; - left: 0; - right: 0; - bottom: 0; text-align: center; + top: 4px; background: grey; - padding: 2px 12px; + padding: 0 12px; + border-radius: 6px; z-index: 2; - line-height: 1; } img { - object-fit: cover; - width: auto; - height: auto; + height: 124px; &.svg { filter: @beige-filter; @@ -95,18 +92,17 @@ .levelup-domain-selected { position: absolute; - height: 40px; - width: 40px; + height: 54px; + width: 54px; border-radius: 50%; - border: 2px solid @golden; - font-size: var(--font-size-24); + border: 2px solid; + font-size: var(--font-size-48); display: flex; align-items: center; justify-content: center; - background: @dark-golden; - color: @golden; - top: 10px; - z-index: 2; + background-image: url(../assets/parchments/dh-parchment-light.png); + color: var(--color-dark-5); + top: calc(50% - 29px); i { position: relative; diff --git a/styles/less/dialog/level-up/sheet.less b/styles/less/dialog/level-up/sheet.less index 9ebd9331..ade7c8a9 100644 --- a/styles/less/dialog/level-up/sheet.less +++ b/styles/less/dialog/level-up/sheet.less @@ -11,10 +11,9 @@ }); .daggerheart.levelup { - .tab.active { - flex: 1; + .window-content { + max-height: 960px; overflow: auto; - .with-scroll-shadows(); } div[data-application-part='form'] { @@ -23,13 +22,15 @@ gap: 8px; } - .section-container { - display: flex; - flex-direction: row; - justify-content: center; - gap: 20px 8px; - margin-top: 8px; - flex-wrap: wrap; + section { + .section-container { + display: flex; + flex-direction: row; + justify-content: center; + gap: 20px 8px; + margin-top: 8px; + flex-wrap: wrap; + } } .levelup-footer { diff --git a/styles/less/dialog/level-up/summary-container.less b/styles/less/dialog/level-up/summary-container.less index de7c9f4a..d67abff6 100644 --- a/styles/less/dialog/level-up/summary-container.less +++ b/styles/less/dialog/level-up/summary-container.less @@ -17,8 +17,10 @@ .levelup-summary-container { overflow: auto; padding: 10px 0; + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; max-height: 700px; - .with-scroll-shadows(); + mask-image: linear-gradient(0deg, transparent 0%, black 5%, black 95%, transparent 100%); .level-achievements-container, .level-advancements-container { diff --git a/styles/less/dialog/multiclass-choice/index.less b/styles/less/dialog/multiclass-choice/index.less deleted file mode 100644 index 1c574e81..00000000 --- a/styles/less/dialog/multiclass-choice/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './sheet.less'; \ No newline at end of file diff --git a/styles/less/dialog/multiclass-choice/sheet.less b/styles/less/dialog/multiclass-choice/sheet.less index 0c487cbc..1f38449a 100644 --- a/styles/less/dialog/multiclass-choice/sheet.less +++ b/styles/less/dialog/multiclass-choice/sheet.less @@ -35,7 +35,7 @@ width: 120px; height: 120px; background: light-dark(@dark-blue-10, @golden-10); - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); &.selected { background: light-dark(@dark-blue-40, @golden-40); @@ -57,7 +57,7 @@ display: flex; flex-wrap: wrap; font-style: italic; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; padding: 4px 4px; } diff --git a/styles/less/dialog/reroll-dialog/sheet.less b/styles/less/dialog/reroll-dialog/sheet.less new file mode 100644 index 00000000..71c94d80 --- /dev/null +++ b/styles/less/dialog/reroll-dialog/sheet.less @@ -0,0 +1,125 @@ +.daggerheart.dialog.dh-style.views.reroll-dialog { + .window-content { + max-width: 648px; + } + + .reroll-outer-container { + h2 { + margin: 0; + } + + .dices-container { + display: flex; + flex-wrap: wrap; + gap: 8px; + } + + .dice-outer-container { + width: 300px; + + legend { + display: flex; + align-items: center; + gap: 4px; + + i { + margin-right: 4px; + } + } + + .dice-container { + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr; + + .result-container { + position: relative; + aspect-ratio: 1; + display: flex; + align-items: center; + justify-content: center; + font-size: 1.375rem; + opacity: 0.8; + + &.selected { + opacity: 1; + border: 1px solid; + border-radius: 6px; + border-color: light-dark(@dark-blue, @golden); + filter: drop-shadow(0 0 3px @golden); + } + + &:before { + content: ' '; + position: absolute; + width: 100%; + height: 100%; + z-index: -1; + mask: var(--svg-die) no-repeat center; + mask-size: contain; + background: linear-gradient(139.01deg, #efe6d8 3.51%, #372e1f 96.49%); + } + + &.d4:before { + --svg-die: url(../assets/icons/dice/default/d4.svg); + } + &.d6:before { + --svg-die: url(../assets/icons/dice/default/d6.svg); + } + &.d8:before { + --svg-die: url(../assets/icons/dice/default/d8.svg); + } + &.d10:before { + --svg-die: url(../assets/icons/dice/default/d10.svg); + } + &.d12:before { + --svg-die: url('../assets/icons/dice/default/d12.svg'); + } + &.d20:before { + --svg-die: url(../assets/icons/dice/default/d20.svg); + } + + .to-reroll-result { + position: absolute; + bottom: -7px; + gap: 2px; + border: 1px solid; + border-radius: 6px; + background-image: url(../assets/parchments/dh-parchment-dark.png); + display: flex; + align-items: center; + padding: 2px 6px; + + input { + margin: 0; + height: 12px; + line-height: 0px; + position: relative; + top: 1px; + + &:before, + &:after { + line-height: 12px; + font-size: var(--font-size-12); + } + } + + i { + font-size: var(--font-size-10); + } + } + } + } + } + } + + footer { + margin-top: 8px; + display: flex; + justify-content: space-between; + + .controls { + display: flex; + gap: 8px; + } + } +} diff --git a/styles/less/dialog/resource-dice/index.less b/styles/less/dialog/resource-dice/index.less deleted file mode 100644 index 1c574e81..00000000 --- a/styles/less/dialog/resource-dice/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './sheet.less'; \ No newline at end of file diff --git a/styles/less/dialog/risk-it-all/index.less b/styles/less/dialog/risk-it-all/index.less deleted file mode 100644 index 1c574e81..00000000 --- a/styles/less/dialog/risk-it-all/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './sheet.less'; \ No newline at end of file diff --git a/styles/less/dialog/settings/index.less b/styles/less/dialog/settings/index.less deleted file mode 100644 index 235f3b9c..00000000 --- a/styles/less/dialog/settings/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './change-currency-icon.less'; \ No newline at end of file diff --git a/styles/less/dialog/tag-team-dialog/index.less b/styles/less/dialog/tag-team-dialog/index.less deleted file mode 100644 index 8bf56824..00000000 --- a/styles/less/dialog/tag-team-dialog/index.less +++ /dev/null @@ -1,2 +0,0 @@ -@import './sheet.less'; -@import './initialization.less'; \ No newline at end of file diff --git a/styles/less/dialog/tag-team-dialog/initialization.less b/styles/less/dialog/tag-team-dialog/initialization.less deleted file mode 100644 index d6f7ad29..00000000 --- a/styles/less/dialog/tag-team-dialog/initialization.less +++ /dev/null @@ -1,117 +0,0 @@ -@import '../../utils/mixin.less'; - -.theme-light .daggerheart.dialog.dh-style.views.tag-team-dialog { - .initialization-container .members-container .member-container { - .member-name { - background-image: url('../assets/parchments/dh-parchment-light.png'); - } - } -} - -.daggerheart.dialog.dh-style.views.tag-team-dialog { - .initialization-container.active { - display: flex; - flex-direction: column; - gap: var(--spacer-4); - - h2 { - text-align: center; - } - - .members-container { - display: flex; - flex-wrap: wrap; - justify-content: center; - gap: 8px; - - // Force 3 columns for 5 -> 6 players - &:has(> :nth-child(5)):not(:has(> :nth-child(7))) { - padding-left: 10%; - padding-right: 10%; - } - - .member-container { - position: relative; - display: flex; - align-items: stretch; - justify-content: center; - border-radius: 6px; - border: 1px solid @color-border; - overflow: hidden; - height: 11.5rem; - width: 122px; - - &.inactive { - border-color: light-dark(@dark-blue-40, @golden-40); - img { - opacity: 0.4; - } - } - - .member-name { - --shadow-color: light-dark(white, black); - position: absolute; - bottom: 0; - left: 0; - right: 0; - - display: flex; - flex-direction: column; - justify-content: flex-end; - min-height: 4rem; - padding: 5rem 4px var(--spacer-8) 4px; - text-align: center; - - color: @color-text-primary; - text-shadow: 1px 1px 2px var(--shadow-color), 0 0 10px var(--shadow-color); - .smooth-gradient-ease-in-out(background-image, to bottom, var(--shadow-color), 100%); - } - - img { - object-fit: cover; - object-position: top center; - flex: 1; - } - - .leader-mark { - position: absolute; - top: 4px; - right: 4px; - text-shadow: var(--shadow-text-stroke), 0 0 20px black; - } - } - } - - .initiator-container { - margin-top: 8px; - display: grid; - grid-template-columns: 1fr 1fr; - gap: 8px; - - &.inactive { - opacity: 0.4; - } - } - - footer { - margin-top: 8px; - display: flex; - gap: 8px; - - button { - flex: 1; - } - - .finish-tools { - flex: none; - display: flex; - align-items: center; - gap: 4px; - - &.inactive { - opacity: 0.4; - } - } - } - } -} diff --git a/styles/less/dialog/tag-team-dialog/sheet.less b/styles/less/dialog/tag-team-dialog/sheet.less index 82bc0270..767c66ca 100644 --- a/styles/less/dialog/tag-team-dialog/sheet.less +++ b/styles/less/dialog/tag-team-dialog/sheet.less @@ -1,279 +1,178 @@ -.daggerheart.dialog.dh-style.views.tag-team-dialog .window-content { - h1 { - color: @color-text-emphatic; - font: 700 var(--font-size-24) var(--dh-font-subtitle); - text-align: center; - } - - .team-container { - display: flex; - gap: 16px; - margin-bottom: 16px; - - .team-member-container { - display: flex; - flex-direction: column; - justify-content: space-between; - gap: 8px; - flex: 1; - - &.select-padding { - padding-bottom: 64px; - } - - &.inactive { - opacity: 0.4; - pointer-events: none; - } - - .data-container { - display: flex; - flex-direction: column; - gap: 8px; - width: 100%; - } - - .member-info { - display: flex; - align-items: center; - justify-content: space-between; - width: 100%; - - img { - height: 64px; - border-radius: 6px; - border: 1px solid @color-border; - } - - .member-name { - flex: 1; - text-align: center; - font-size: var(--font-size-18); - } - } - - .roll-setup { - width: 100%; - } - - .roll-container { - display: flex; - flex-direction: column; - } - - .roll-title { - font-size: var(--font-size-20); - font-weight: bold; - color: @color-text-emphatic; - text-align: center; - display: flex; - align-items: center; - gap: 8px; - - &::before, - &::after { - color: @color-text-emphatic; - content: ''; - flex: 1; - height: 2px; - } - - &::before { - background: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, light-dark(@dark-blue, @golden) 100%); - } - - &::after { - background: linear-gradient(90deg, light-dark(@dark-blue, @golden) 0%, rgba(0, 0, 0, 0) 100%); - } - } - - .roll-tools { - display: flex; - gap: 4px; - align-items: center; - - img { - height: 16px; - } - - a { - display: flex; - font-size: 16px; - - &:hover { - text-shadow: none; - filter: drop-shadow(0 0 8px var(--golden)); - } - } - } - - .roll-data { - display: flex; - flex-direction: column; - align-items: center; - gap: 4px; - - &.hope { - --text-color: @golden; - --bg-color: @golden-40; - } - - &.fear { - --text-color: @chat-blue; - --bg-color: @chat-blue-40; - } - - &.critical { - --text-color: @chat-purple; - --bg-color: @chat-purple-40; - } - - .duality-label { - color: var(--text-color); - font-size: var(--font-size-20); - font-weight: bold; - text-align: center; - - .unused-damage { - text-decoration: line-through; - } - } - - .roll-dice-container { - display: flex; - align-items: center; - justify-content: center; - flex-wrap: wrap; - gap: 8px; - - .roll-dice { - position: relative; - display: flex; - align-items: center; - justify-content: center; - - .dice-label { - position: absolute; - color: white; - font-size: 1rem; - paint-order: stroke fill; - -webkit-text-stroke: 2px black; - } - - img { - height: 32px; - } - } - - .roll-operator { - font-size: var(--font-size-24); - } - - .roll-value { - font-size: 18px; - } - } - - .roll-total { - background: var(--bg-color); - color: var(--text-color); - border-radius: 4px; - padding: 3px; - } - } - } - } - - .roll-selection { - position: relative; - top: -80px; - - &.rendered { - margin-bottom: -56px; - } - - .roll-selection-container { - display: flex; - gap: 16px; - - .select-roll-button { - margin-top: 8px; - flex: 1; - display: flex; - justify-content: center; - - i { - color: @color-text-emphatic; - font-size: 48px; - - &.inactive { - opacity: 0.4; - } - } - } - } - } - - .tag-team-roll-container { +.daggerheart.dialog.dh-style.views.tag-team-dialog { + .tag-team-container { display: flex; flex-direction: column; gap: 16px; - &.inactive { - opacity: 0.4; - pointer-events: none; - } - - .results-container { + .tag-team-data-container { display: flex; - flex-direction: column; align-items: center; - gap: 4px; - border: 2px solid light-dark(@dark-blue, @golden); - border-radius: 6px; - padding: 8px 10px; + gap: 8px; - .result-container-label { - font-size: var(--font-size-24); - font-weight: bold; - } + .form-group { + flex: 0; - .results-inner-container { - display: flex; - justify-content: space-between; - gap: 8px; - width: 100%; - - .result-section-label { - font-size: var(--font-size-20); + label { + white-space: nowrap; } - .result-container { - width: 100%; - text-align: center; + &.flex-group { + flex: 1; + } + } + } - .result-info { + .title-row { + display: flex; + align-items: center; + gap: 8px; + + h2 { + text-align: start; + } + + select { + flex: 1; + } + } + + .participants-container { + margin-top: 8px; + display: flex; + flex-direction: column; + gap: 4px; + + .participant-outer-container { + padding: 8px; + display: flex; + flex-direction: column; + gap: 4px; + cursor: pointer; + border-radius: 6px; + + &.selected, + &:hover { + background-color: light-dark(@golden-40, @golden-40); + } + + .participant-container { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + + .participant-inner-container { + flex: 1; display: flex; + align-items: center; gap: 4px; + + img { + height: 48px; + width: 48px; + border-radius: 50%; + } + + .participant-labels { + display: flex; + flex-direction: column; + gap: 2px; + + .participant-label-title { + font-size: 18px; + } + + .participant-label-info { + display: flex; + gap: 4px; + + .participant-label-info-part { + border: 1px solid light-dark(white, white); + border-radius: 4px; + padding: 2px 4px; + background-color: light-dark(@beige-80, @soft-white-shadow); + color: white; + } + } + } + } + } + + .participant-empty-roll-container { + border: 1px dashed white; + padding: 8px 2px; + text-align: center; + font-style: italic; + } + + .participant-roll-outer-container { + display: flex; + flex-direction: column; + gap: 2px; + color: light-dark(@dark-blue, @golden); + + h4 { + text-align: center; + color: light-dark(@dark-blue, @golden); + } + + .participant-roll-container { + display: flex; align-items: center; justify-content: center; + white-space: nowrap; + + .participant-roll-text-container { + padding: 0 8px; + white-space: nowrap; + display: flex; + } + } + + .damage-values-container { + display: flex; + justify-content: space-around; + gap: 8px; + + .damage-container { + border: 1px solid light-dark(white, white); + border-radius: 6px; + padding: 0 4px; + display: flex; + gap: 4px; + } } } } } - .finish-container { - gap: 16px; - display: grid; - grid-template-columns: 1fr 1fr 1fr; + h2 { + text-align: center; + } - .finish-button { - grid-column: span 2; + .result-container { + display: grid; + grid-template-columns: 1fr 1fr; + align-items: center; + gap: 8px; + + .result-damages-container { + display: flex; + flex-wrap: wrap; + gap: 4px; + + .result-damage-container { + border: 1px solid light-dark(white, white); + border-radius: 6px; + padding: 0 4px; + } } } - } - .hint { - text-align: center; + .roll-leader-container { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 8px; + } } } diff --git a/styles/less/global/dialog.less b/styles/less/global/dialog.less index 1313d68b..a3400700 100644 --- a/styles/less/global/dialog.less +++ b/styles/less/global/dialog.less @@ -36,8 +36,8 @@ padding: 0; &:hover { - border: 1px solid @color-border; - color: @color-text-emphatic; + border: 1px solid light-dark(@dark-blue, @golden); + color: light-dark(@dark-blue, @golden); } } } @@ -81,7 +81,7 @@ cursor: pointer; padding: 5px; background: light-dark(@dark-blue-10, @golden-10); - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); .label { font-style: normal; diff --git a/styles/less/global/elements.less b/styles/less/global/elements.less index e57ba50d..beffefbb 100755 --- a/styles/less/global/elements.less +++ b/styles/less/global/elements.less @@ -2,22 +2,24 @@ @import '../utils/fonts.less'; .dh-style { + border: 1px solid light-dark(@dark-blue, @golden); + input[type='text'], input[type='number'], textarea, - file-picker, .input[contenteditable] { background: light-dark(transparent, transparent); border-radius: 6px; box-shadow: 0 4px 30px @soft-shadow; backdrop-filter: blur(9.5px); + -webkit-backdrop-filter: blur(9.5px); outline: 2px solid transparent; - color: @input-color-text; - border: 1px solid @input-color-border; + color: light-dark(@dark-blue, @golden); + border: 1px solid light-dark(@dark, @beige); transition: all 0.3s ease; &::placeholder { - color: @color-text-subtle; + color: light-dark(@dark-40, @beige-50); } &:hover, @@ -28,7 +30,7 @@ &:focus[type='number'] { background: light-dark(@soft-shadow, @semi-transparent-dark-blue); box-shadow: none; - outline: 2px solid @input-color-border; + outline: 2px solid light-dark(@dark, @beige); } &:disabled[type='text'], @@ -45,7 +47,7 @@ .input[contenteditable] { cursor: var(--cursor-text); &:empty:before { - color: @color-text-subtle; + color: light-dark(@dark-40, @beige-50); content: attr(placeholder); } } @@ -94,9 +96,11 @@ textarea { color: light-dark(@dark, @beige); + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; } - button:where(:not(.plain, color-picker *, file-picker *)) { + button { background: light-dark(transparent, @golden); border: 1px solid light-dark(@dark-blue, @dark-blue); color: light-dark(@dark-blue, @dark-blue); @@ -105,7 +109,7 @@ &:hover { background: light-dark(@light-black, @dark-blue); - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); } &.glow { @@ -126,7 +130,7 @@ &.reverted { background: light-dark(@dark-blue-10, @golden-10); - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); border: 1px solid light-dark(@dark, transparent); &:hover { background: light-dark(transparent, @golden); @@ -173,7 +177,7 @@ height: inherit; .tag { padding: 0.3rem 0.5rem; - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); background-color: light-dark(@dark-blue-10, @golden-40); border-radius: 3px; transition: 0.13s ease-out; @@ -247,23 +251,15 @@ a:hover, a.active { - text-shadow: 0 0 1px currentColor, 0 0 1px currentColor, 0 0 8px light-dark(@dark-blue, @golden); - } - - file-picker, color-picker { - > input[type=text] { - background: transparent; - border: none; - outline: none; - backdrop-filter: unset; - } + font-weight: bold; + text-shadow: 0 0 8px light-dark(@dark-blue, @golden); } fieldset { align-items: center; margin-top: 5px; border-radius: 6px; - border-color: @color-fieldset-border; + border-color: light-dark(@dark-blue, @golden); &.glassy { background-color: light-dark(@dark-blue-10, @golden-10); @@ -272,9 +268,8 @@ legend { padding: 2px 12px; border-radius: 3px; - background-color: @color-fieldset-border; + background-color: light-dark(@dark-blue, @golden); color: light-dark(@beige, @dark-blue); - margin-bottom: var(--spacer-4); } } @@ -283,7 +278,7 @@ } &.fit-height { - flex: 1; + height: 95%; } &.flex { @@ -298,20 +293,6 @@ } } - &.optional, - &.one-column.optional { - padding-top: 0; - padding-bottom: 4px; - min-height: auto; - row-gap: 0; - - legend { - display: flex; - align-items: center; - padding-left: 3px; - } - } - .list-w-img { padding: 5px; label { @@ -351,15 +332,18 @@ legend { font-weight: bold; - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); + } - &.with-icon { - display: flex; - align-items: center; + input[type='text'], + input[type='number'] { + color: light-dark(@dark, @beige); + transition: all 0.3s ease; + outline: 2px solid transparent; - i { - padding: 0 4px; - } + &:focus, + &:hover { + outline: 2px solid light-dark(@dark, @beige); } } @@ -412,19 +396,11 @@ width: fit-content; display: flex; align-items: center; - .form-fields { height: 32px; align-content: center; } } - - &.select { - width: fit-content; - display: flex; - align-items: center; - gap: 4px; - } } .scalable-input { @@ -484,10 +460,6 @@ &.even { grid-template-columns: 1fr 1fr; } - - &.full-width { - width: 100%; - } } .three-columns { @@ -500,7 +472,7 @@ display: block; height: 1px; width: 100%; - border-bottom: 1px solid @color-border; + border-bottom: 1px solid light-dark(@dark-blue, @golden); mask-image: linear-gradient(270deg, transparent 0%, black 50%, transparent 100%); } @@ -508,7 +480,7 @@ display: block; height: 1px; width: 100%; - border-bottom: 1px solid @color-border; + border-bottom: 1px solid light-dark(@dark-blue, @golden); mask-image: linear-gradient(270deg, transparent 0%, black 100%); &.invert { @@ -557,7 +529,7 @@ border: 0; &:hover { - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); } &:not(:first-child) { @@ -592,6 +564,59 @@ } } +.application.setting.dh-style { + h2, + h3, + h4 { + margin: 8px 0 4px; + text-align: center; + } + + footer { + margin-top: 8px; + display: flex; + gap: 8px; + + button { + flex: 1; + } + } + + .form-group { + display: flex; + justify-content: space-between; + align-items: center; + gap: 0.25rem 0.5rem; + flex-wrap: wrap; + + label { + font-size: var(--font-size-14); + font-weight: normal; + } + + .form-fields { + display: flex; + gap: 4px; + align-items: center; + } + + &.setting-two-values { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 0.25rem 0.5rem; + + .form-group { + justify-content: end; + flex-wrap: nowrap; + } + + .hint { + grid-column: 1 / -1; + } + } + } +} + .system-daggerheart { .tagify { background: light-dark(transparent, transparent); @@ -744,7 +769,6 @@ .preview-image-container { width: 100%; - min-height: 0; flex-grow: 1; object-fit: cover; border-radius: 4px 4px 0 0; diff --git a/styles/less/global/feature-section.less b/styles/less/global/feature-section.less index 2fd4e20f..13feb92c 100644 --- a/styles/less/global/feature-section.less +++ b/styles/less/global/feature-section.less @@ -5,6 +5,8 @@ .tab.features { padding: 0 10px; overflow-y: auto; + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; .feature-list { display: flex; flex-direction: column; @@ -17,36 +19,28 @@ &:last-child { margin-bottom: 0px; } - } - .feature-line { - display: grid; - align-items: center; - grid-template-columns: 1fr 4fr 1fr; - h4 { - font-weight: lighter; - color: light-dark(@dark, @beige); - } - .image { - height: 40px; - width: 40px; - object-fit: cover; - border-radius: 6px; - border: none; - } - .image-icon { - font-size: 26px; - width: 40px; - height: 40px; - display: flex; - justify-content: center; + .feature-line { + display: grid; align-items: center; - } - .controls { - display: flex; - justify-content: center; - gap: 10px; - a { - text-shadow: none; + grid-template-columns: 1fr 4fr 1fr; + h4 { + font-weight: lighter; + color: light-dark(@dark, @beige); + } + .image { + height: 40px; + width: 40px; + object-fit: cover; + border-radius: 6px; + border: none; + } + .controls { + display: flex; + justify-content: center; + gap: 10px; + a { + text-shadow: none; + } } } } diff --git a/styles/less/global/filter-menu.less b/styles/less/global/filter-menu.less index a0545950..65a184f8 100644 --- a/styles/less/global/filter-menu.less +++ b/styles/less/global/filter-menu.less @@ -13,7 +13,7 @@ legend { font-weight: bold; - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); font-size: var(--font-size-12); } @@ -25,7 +25,7 @@ button { background: light-dark(@light-black, @dark-blue); - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); outline: none; box-shadow: none; border: 1px solid light-dark(@dark-blue, @dark-blue); diff --git a/styles/less/global/global.less b/styles/less/global/global.less index c0e7f3fc..b9af67c0 100644 --- a/styles/less/global/global.less +++ b/styles/less/global/global.less @@ -12,11 +12,6 @@ } .daggerheart.dh-style { - * { - scrollbar-width: thin; - scrollbar-color: light-dark(@dark-blue, @golden) transparent; - } - .hint { flex: 0 0 100%; margin: 0; @@ -38,7 +33,7 @@ } &:before { - font-family: var(--font-awesome); + font-family: 'Font Awesome 6 Pro'; content: '\f110'; position: absolute; height: 100%; diff --git a/styles/less/global/inventory-item.less b/styles/less/global/inventory-item.less index 3a5a9321..4bd4d0bb 100644 --- a/styles/less/global/inventory-item.less +++ b/styles/less/global/inventory-item.less @@ -24,15 +24,6 @@ width: 100%; list-style-type: none; - &.bordered { - border: 1px solid; - border-radius: 6px; - - .inventory-item-header .img-portait img.item-img { - border-radius: 6px 0 0 6px; - } - } - &:not(.single-img) { .img-portait:has(.roll-img):hover { .roll-img { @@ -287,7 +278,7 @@ position: relative; height: 120px; width: 98px; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; cursor: pointer; diff --git a/styles/less/global/prose-mirror.less b/styles/less/global/prose-mirror.less index e4b1249f..fd699b66 100644 --- a/styles/less/global/prose-mirror.less +++ b/styles/less/global/prose-mirror.less @@ -4,12 +4,13 @@ .application.daggerheart { prose-mirror { height: 100% !important; - width: 100%; .editor-menu { background-color: transparent; } .editor-content { + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; h1 { font-size: var(--font-size-32); } @@ -40,11 +41,6 @@ ul { list-style: disc; } - } - // Fixes centering and makes it not render over scrollbar - &:hover button.toggle:enabled { - display: flex; - right: 12px; } } } diff --git a/styles/less/global/resource-bar.less b/styles/less/global/resource-bar.less index d06b43a8..be9bc68b 100644 --- a/styles/less/global/resource-bar.less +++ b/styles/less/global/resource-bar.less @@ -50,16 +50,16 @@ flex-wrap: wrap; gap: 5px; padding: 5px; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; z-index: 1; - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); width: fit-content; .slot { width: 15px; height: 10px; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); background: light-dark(@dark-blue-10, @golden-10); border-radius: 3px; transition: all 0.3s ease; @@ -148,7 +148,7 @@ appearance: none; width: 100px; height: 40px; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; z-index: 1; background: @dark-blue; diff --git a/styles/less/global/sheet.less b/styles/less/global/sheet.less index e3072da1..1e7bad0a 100755 --- a/styles/less/global/sheet.less +++ b/styles/less/global/sheet.less @@ -4,8 +4,8 @@ // Theme handling .appTheme({ - background: @dark-blue-c0; - backdrop-filter: blur(7px); + background: @dark-blue-90; + backdrop-filter: blur(8px); }, { background: url('../assets/parchments/dh-parchment-light.png') no-repeat center; }); @@ -14,7 +14,11 @@ body.game:is(.performance-low, .noblur) { .themed.theme-dark .application.daggerheart.sheet.dh-style, .themed.theme-dark.application.daggerheart.sheet.dh-style, &.theme-dark .application.daggerheart { - background: @dark-blue; + &.adversary, + &.character, + &.item { + background: @dark-blue; + } } } @@ -36,14 +40,14 @@ body.game:is(.performance-low, .noblur) { } button { - background: light-dark(#e8e6e3, @deep-black); + background: light-dark(transparent, @deep-black); color: light-dark(@dark-blue, @beige); border: 1px solid light-dark(@dark-blue, transparent); padding: 0; &:hover { border-color: light-dark(@dark-blue, @golden); - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); } } } diff --git a/styles/less/global/tab-navigation.less b/styles/less/global/tab-navigation.less index 3d143b4c..3f8844f2 100755 --- a/styles/less/global/tab-navigation.less +++ b/styles/less/global/tab-navigation.less @@ -3,7 +3,8 @@ .daggerheart.dh-style { .tab-navigation { - margin: 5px 0 10px 0; + margin: 5px 0; + height: 40px; width: 100%; .navigation-container { @@ -19,11 +20,7 @@ white-space: nowrap; a { - color: @color-text-emphatic; - - &.empty:not(.active) { - opacity: 0.4; - } + color: light-dark(@dark-blue, @golden); } } } diff --git a/styles/less/hud/index.less b/styles/less/hud/index.less index f1f4602e..459f8fd7 100644 --- a/styles/less/hud/index.less +++ b/styles/less/hud/index.less @@ -1 +1 @@ -@import './token-hud/index.less'; +@import './token-hud/token-hud.less'; diff --git a/styles/less/hud/token-hud/index.less b/styles/less/hud/token-hud/index.less deleted file mode 100644 index c86d0939..00000000 --- a/styles/less/hud/token-hud/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './token-hud.less'; \ No newline at end of file diff --git a/styles/less/hud/token-hud/token-hud.less b/styles/less/hud/token-hud/token-hud.less index 3b998f4e..e31ede4a 100644 --- a/styles/less/hud/token-hud/token-hud.less +++ b/styles/less/hud/token-hud/token-hud.less @@ -24,7 +24,7 @@ .palette-category-title { grid-column: span var(--effect-columns); font-weight: bold; - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); } } } @@ -38,9 +38,6 @@ } .status-effects { - // TODO: Remove when the issue https://github.com/foundryvtt/foundryvtt/issues/14410 is resolved and Foundry handles it cleanly themselves. - grid-template-rows: min-content; - .effect-control-container { position: relative; diff --git a/styles/less/sheets-settings/adversary-settings/features.less b/styles/less/sheets-settings/adversary-settings/features.less index 15b1fa18..4e0f6a8f 100644 --- a/styles/less/sheets-settings/adversary-settings/features.less +++ b/styles/less/sheets-settings/adversary-settings/features.less @@ -5,6 +5,8 @@ .tab.features { max-height: 450px; overflow-y: auto; + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; .add-feature-btn { width: 100%; diff --git a/styles/less/sheets-settings/adversary-settings/index.less b/styles/less/sheets-settings/adversary-settings/index.less deleted file mode 100644 index 5968577d..00000000 --- a/styles/less/sheets-settings/adversary-settings/index.less +++ /dev/null @@ -1,3 +0,0 @@ -@import './sheet.less'; -@import './experiences.less'; -@import './features.less'; \ No newline at end of file diff --git a/styles/less/sheets-settings/adversary-settings/sheet.less b/styles/less/sheets-settings/adversary-settings/sheet.less index e6eb8d0b..b4b0683b 100644 --- a/styles/less/sheets-settings/adversary-settings/sheet.less +++ b/styles/less/sheets-settings/adversary-settings/sheet.less @@ -7,7 +7,7 @@ &.attack.active { display: flex; flex-direction: column; - gap: 12px; + gap: 16px; } .fieldsets-section { diff --git a/styles/less/sheets-settings/character-settings/index.less b/styles/less/sheets-settings/character-settings/index.less deleted file mode 100644 index 1c574e81..00000000 --- a/styles/less/sheets-settings/character-settings/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './sheet.less'; \ No newline at end of file diff --git a/styles/less/sheets-settings/character-settings/sheet.less b/styles/less/sheets-settings/character-settings/sheet.less index 37906712..f0c7c94e 100644 --- a/styles/less/sheets-settings/character-settings/sheet.less +++ b/styles/less/sheets-settings/character-settings/sheet.less @@ -1,19 +1,17 @@ @import '../../utils/colors.less'; -.appTheme({}, { - &.dialog.character-settings { - .tab.details { - .traits-inner-container .trait-container { - background: url('../assets/svg/trait-shield-light.svg') no-repeat; +.theme-light .application.daggerheart.dh-style.dialog { + .tab.details { + .traits-inner-container .trait-container { + background: url('../assets/svg/trait-shield-light.svg') no-repeat; - div { - filter: drop-shadow(0 0 3px @beige); - text-shadow: 0 0 3px @beige; - } + div { + filter: drop-shadow(0 0 3px @beige); + text-shadow: 0 0 3px @beige; } } } -}); +} .application.daggerheart.dh-style.dialog { .tab.details { @@ -22,22 +20,15 @@ display: flex; align-items: center; justify-content: space-evenly; - gap: 2px; + gap: 8px; .trait-container { - width: 65px; - height: 65px; + width: 60px; + height: 60px; background: url(../assets/svg/trait-shield.svg) no-repeat; - background-size: 100%; - padding-top: 3px; display: flex; flex-direction: column; align-items: center; - row-gap: 3px; - - span { - font-size: var(--font-size-10); - } div { filter: drop-shadow(0 0 3px black); diff --git a/styles/less/sheets-settings/environment-settings/adversaries.less b/styles/less/sheets-settings/environment-settings/adversaries.less index 2ce4819a..1a27eaca 100644 --- a/styles/less/sheets-settings/environment-settings/adversaries.less +++ b/styles/less/sheets-settings/environment-settings/adversaries.less @@ -5,6 +5,8 @@ .tab.adversaries { max-height: 450px; overflow-y: auto; + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; .add-action-btn { width: 100%; diff --git a/styles/less/sheets-settings/environment-settings/features.less b/styles/less/sheets-settings/environment-settings/features.less index db6b544d..d907837a 100644 --- a/styles/less/sheets-settings/environment-settings/features.less +++ b/styles/less/sheets-settings/environment-settings/features.less @@ -5,6 +5,8 @@ .tab.features { max-height: 450px; overflow-y: auto; + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; .add-feature-btn { width: 100%; diff --git a/styles/less/sheets-settings/environment-settings/index.less b/styles/less/sheets-settings/environment-settings/index.less deleted file mode 100644 index 1e6ee34d..00000000 --- a/styles/less/sheets-settings/environment-settings/index.less +++ /dev/null @@ -1,2 +0,0 @@ -@import './adversaries.less'; -@import './features.less'; \ No newline at end of file diff --git a/styles/less/sheets-settings/header.less b/styles/less/sheets-settings/header.less index 04e2fa90..82f3c488 100644 --- a/styles/less/sheets-settings/header.less +++ b/styles/less/sheets-settings/header.less @@ -13,7 +13,7 @@ font-size: var(--font-size-24); margin: 0; text-align: center; - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); } } } diff --git a/styles/less/sheets-settings/index.less b/styles/less/sheets-settings/index.less index 53a03868..f575f848 100644 --- a/styles/less/sheets-settings/index.less +++ b/styles/less/sheets-settings/index.less @@ -1,4 +1,8 @@ @import './header.less'; -@import './adversary-settings/index.less'; -@import './character-settings/index.less'; -@import './environment-settings/index.less'; +@import './adversary-settings/sheet.less'; +@import './adversary-settings/experiences.less'; +@import './adversary-settings/features.less'; +@import './character-settings/sheet.less'; + +@import './environment-settings/features.less'; +@import './environment-settings/adversaries.less'; diff --git a/styles/less/sheets/actions/actions.less b/styles/less/sheets/actions/actions.less index 485f8e91..5c21dc60 100644 --- a/styles/less/sheets/actions/actions.less +++ b/styles/less/sheets/actions/actions.less @@ -133,24 +133,4 @@ height: 300px; } } - - .deletable-row { - display: flex; - align-items: end; - gap: 8px; - - input { - flex: 1; - } - - a { - padding-bottom: 7px; - } - } - - .sub-section-header { - display: flex; - align-items: center; - gap: 4px; - } } diff --git a/styles/less/sheets/actions/index.less b/styles/less/sheets/actions/index.less deleted file mode 100644 index 29ef8645..00000000 --- a/styles/less/sheets/actions/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './actions.less'; \ No newline at end of file diff --git a/styles/less/sheets/activeEffects/activeEffects.less b/styles/less/sheets/activeEffects/activeEffects.less deleted file mode 100644 index e4f5c541..00000000 --- a/styles/less/sheets/activeEffects/activeEffects.less +++ /dev/null @@ -1,90 +0,0 @@ -.application.sheet.daggerheart.dh-style.active-effect-config { - .custom-duration-section { - width: 100%; - display: flex; - flex-direction: column; - gap: 10px; - overflow: hidden; - height: 0; - transition: height ease-in-out 0.3s; - - &.visible { - height: auto; - } - } - - .duration-description { - height: 0; - overflow: hidden; - transition: height ease-in-out 0.3s; - - &.visible { - height: 100px; - } - } - - .tab.changes { - gap: 0; - - header { - div { - text-align: center; - } - } - - .armor-change-container { - header { - padding: 0; - left: -0.25rem; // TODO: Find why this header is offset 0.25rem to the right so this can be removed. - } - - header, - ol { - grid-template-columns: 5rem 7rem 12rem 4rem; - } - - .damage-thresholds-container { - width: 100%; - display: flex; - flex-direction: column; - gap: 4px; - - .damage-threshold-title { - display: flex; - align-items: center; - justify-content: center; - gap: 8px; - - &::before, - &::after { - content: ''; - flex: 1; - height: 2px; - } - - &::before { - background: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, light-dark(@dark-blue, @golden) 100%); - } - - &::after { - background: linear-gradient(90deg, light-dark(@dark-blue, @golden) 0%, rgba(0, 0, 0, 0) 100%); - } - - span { - font-size: var(--font-size-18); - } - } - - .form-group { - flex-direction: column; - gap: 0; - - label { - color: inherit; - line-height: 16px; - } - } - } - } - } -} diff --git a/styles/less/sheets/activeEffects/index.less b/styles/less/sheets/activeEffects/index.less deleted file mode 100644 index 19f8a3a7..00000000 --- a/styles/less/sheets/activeEffects/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './activeEffects.less'; \ No newline at end of file diff --git a/styles/less/sheets/actors/actor-sheet-shared.less b/styles/less/sheets/actors/actor-sheet-shared.less index b3eb0469..23db088a 100644 --- a/styles/less/sheets/actors/actor-sheet-shared.less +++ b/styles/less/sheets/actors/actor-sheet-shared.less @@ -34,61 +34,7 @@ .attribution-header-label { font-style: italic; font-family: @font-body; - color: @color-text-subtle; - } - - .tab.inventory { - .gold-section { - display: grid; - grid-template-columns: 1fr 1fr 1fr 1fr; - gap: 10px; - padding: 10px 10px 0; - - .input { - color: light-dark(@dark, @beige); - } - } - } - - .search-section { - display: flex; - gap: 10px; - align-items: center; - justify-content: space-between; - .search-bar { - position: relative; - color: light-dark(@dark-blue-50, @beige-50); - width: 100%; - padding-top: 5px; - - input { - border-radius: 50px; - background: light-dark(@dark-blue-10, @golden-10); - border: none; - outline: 2px solid transparent; - transition: all 0.3s ease; - padding: 0 20px; - - &:hover { - outline: 2px solid light-dark(@dark, @golden); - } - - &::-webkit-search-cancel-button { - -webkit-appearance: none; - display: none; - } - } - - .icon { - align-content: center; - height: 32px; - position: absolute; - right: 20px; - font-size: var(--font-size-16); - z-index: 1; - color: light-dark(@dark-blue-50, @beige-50); - } - } + color: light-dark(@chat-blue-bg, @beige-50); } &.limited { @@ -128,7 +74,7 @@ .title-name { text-align: start; font-size: var(--font-size-28); - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); text-align: center; } } @@ -181,9 +127,9 @@ display: flex; gap: 10px; background-color: light-dark(transparent, @dark-blue); - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); padding: 5px 10px; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; align-items: center; width: fit-content; @@ -195,7 +141,7 @@ font-size: var(--font-size-14); font-weight: bold; text-transform: uppercase; - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); } .domain { @@ -207,7 +153,7 @@ font-size: var(--font-size-14); font-weight: bold; text-transform: uppercase; - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); } img { @@ -231,7 +177,7 @@ padding: 10px; border-radius: 5px; min-width: 90px; - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); background-color: light-dark(@dark-blue-10, @golden-40); } } diff --git a/styles/less/sheets/actors/adversary/features.less b/styles/less/sheets/actors/adversary/actions.less similarity index 65% rename from styles/less/sheets/actors/adversary/features.less rename to styles/less/sheets/actors/adversary/actions.less index 447d050e..00395ebd 100644 --- a/styles/less/sheets/actors/adversary/features.less +++ b/styles/less/sheets/actors/adversary/actions.less @@ -1,6 +1,5 @@ @import '../../../utils/colors.less'; @import '../../../utils/fonts.less'; -@import '../../../utils/mixin.less'; .application.sheet.daggerheart.actor.dh-style.adversary { .tab.features { @@ -9,8 +8,11 @@ flex-direction: column; gap: 10px; overflow-y: auto; + mask-image: linear-gradient(0deg, transparent 0%, black 5%); padding-bottom: 20px; - .with-scroll-shadows(); + + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; } } } diff --git a/styles/less/sheets/actors/adversary/effects.less b/styles/less/sheets/actors/adversary/effects.less index 4aa44e51..4afe2454 100644 --- a/styles/less/sheets/actors/adversary/effects.less +++ b/styles/less/sheets/actors/adversary/effects.less @@ -1,5 +1,4 @@ @import '../../../utils/colors.less'; -@import '../../../utils/mixin.less'; .application.sheet.daggerheart.actor.dh-style.adversary { .tab.effects { @@ -8,8 +7,11 @@ flex-direction: column; gap: 10px; overflow-y: auto; + mask-image: linear-gradient(0deg, transparent 0%, black 5%); padding-bottom: 20px; - .with-scroll-shadows(); + + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; } } } diff --git a/styles/less/sheets/actors/adversary/header.less b/styles/less/sheets/actors/adversary/header.less index 1e5e4fa5..8bd3fcee 100644 --- a/styles/less/sheets/actors/adversary/header.less +++ b/styles/less/sheets/actors/adversary/header.less @@ -35,7 +35,7 @@ .tags { display: flex; gap: 10px; - padding-bottom: 8px; + padding-bottom: 16px; .tag { display: flex; @@ -67,5 +67,11 @@ gap: 12px; padding: 16px 0; } + + .adversary-navigation { + display: flex; + gap: 8px; + align-items: center; + } } } diff --git a/styles/less/sheets/actors/adversary/index.less b/styles/less/sheets/actors/adversary/index.less deleted file mode 100644 index 28ff9d22..00000000 --- a/styles/less/sheets/actors/adversary/index.less +++ /dev/null @@ -1,7 +0,0 @@ -@import './features.less'; -@import './header.less'; -@import './sheet.less'; -@import './sidebar.less'; -@import './effects.less'; -@import './notes.less'; - diff --git a/styles/less/sheets/actors/adversary/notes.less b/styles/less/sheets/actors/adversary/notes.less deleted file mode 100644 index a95d070e..00000000 --- a/styles/less/sheets/actors/adversary/notes.less +++ /dev/null @@ -1,3 +0,0 @@ -.application.sheet.daggerheart.actor.dh-style.adversary .tab.notes.active { - padding-bottom: 20px; -} diff --git a/styles/less/sheets/actors/adversary/sidebar.less b/styles/less/sheets/actors/adversary/sidebar.less index 5db9f5e9..4e7535c1 100644 --- a/styles/less/sheets/actors/adversary/sidebar.less +++ b/styles/less/sheets/actors/adversary/sidebar.less @@ -65,9 +65,9 @@ display: flex; gap: 10px; background-color: light-dark(transparent, @dark-blue); - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); padding: 5px 10px; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; align-items: center; width: fit-content; @@ -77,7 +77,7 @@ font-size: var(--font-size-14); font-weight: bold; text-transform: uppercase; - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); &.threshold-value { color: light-dark(@dark, @beige); @@ -191,7 +191,7 @@ appearance: none; width: 100px; height: 40px; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; z-index: 1; background: @dark-blue; @@ -237,7 +237,7 @@ display: flex; width: 50px; height: 30px; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-bottom: none; border-radius: 6px 6px 0 0; padding: 0 6px; @@ -286,11 +286,13 @@ overflow-y: hidden; padding-top: 10px; padding-bottom: 20px; + mask-image: linear-gradient(0deg, transparent 0%, black 5%, black 95%, transparent 100%); + scrollbar-width: thin; scrollbar-gutter: stable; - .with-scroll-shadows(); &:hover { overflow-y: auto; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; } } diff --git a/styles/less/sheets/actors/character/biography.less b/styles/less/sheets/actors/character/biography.less index 8548a2fb..12a662ff 100644 --- a/styles/less/sheets/actors/character/biography.less +++ b/styles/less/sheets/actors/character/biography.less @@ -1,6 +1,5 @@ @import '../../../utils/colors.less'; @import '../../../utils/fonts.less'; -@import '../../../utils/mixin.less'; .application.sheet.daggerheart.actor.dh-style.character { .tab.biography { @@ -10,15 +9,12 @@ gap: 10px; height: 100%; overflow-y: auto; - padding-top: 8px; - padding-bottom: 20px; + mask-image: linear-gradient(0deg, transparent 0%, black 10%, black 98%, transparent 100%); + padding-bottom: 10px; height: 100%; - .with-scroll-shadows(); - } - .characteristics-section { - gap: 20px; - padding: 0 10px; + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; } .biography-section { diff --git a/styles/less/sheets/actors/character/effects.less b/styles/less/sheets/actors/character/effects.less index 0ab1007d..ceadd05e 100644 --- a/styles/less/sheets/actors/character/effects.less +++ b/styles/less/sheets/actors/character/effects.less @@ -1,6 +1,5 @@ @import '../../../utils/colors.less'; @import '../../../utils/fonts.less'; -@import '../../../utils/mixin.less'; .application.sheet.daggerheart.actor.dh-style.character { .tab.effects { @@ -9,8 +8,11 @@ flex-direction: column; gap: 10px; overflow-y: auto; + mask-image: linear-gradient(0deg, transparent 0%, black 5%); padding-bottom: 20px; - .with-scroll-shadows(); + + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; } } } diff --git a/styles/less/sheets/actors/character/features.less b/styles/less/sheets/actors/character/features.less index 52b41826..6a6438ff 100644 --- a/styles/less/sheets/actors/character/features.less +++ b/styles/less/sheets/actors/character/features.less @@ -1,6 +1,5 @@ @import '../../../utils/colors.less'; @import '../../../utils/fonts.less'; -@import '../../../utils/mixin.less'; .application.sheet.daggerheart.actor.dh-style.character { .tab.features { @@ -9,8 +8,11 @@ flex-direction: column; gap: 10px; overflow-y: auto; + mask-image: linear-gradient(0deg, transparent 0%, black 5%); padding-bottom: 20px; - .with-scroll-shadows(); + + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; } } } diff --git a/styles/less/sheets/actors/character/header.less b/styles/less/sheets/actors/character/header.less index 91b3545a..31fd4256 100644 --- a/styles/less/sheets/actors/character/header.less +++ b/styles/less/sheets/actors/character/header.less @@ -5,12 +5,20 @@ // Theme header backgrounds .appTheme({ .character-header-sheet { + .trait { + background: url(../assets/svg/trait-shield.svg) no-repeat; + } + .character-row .domains-section img { filter: @golden-filter; } } }, { .character-header-sheet { + .trait { + background: url('../assets/svg/trait-shield-light.svg') no-repeat; + } + .character-row .domains-section img { filter: brightness(0) saturate(100%); } @@ -25,19 +33,13 @@ .name-row { display: flex; - gap: 6px; + gap: 5px; align-items: start; justify-content: space-between; padding: 0; padding-top: 5px; flex: 1; - [contenteditable], - input { - border: 1px solid @soft-shadow; - background-color: light-dark(@dark-15, @soft-white-shadow); - } - h1 { display: flex; flex: 1; @@ -63,16 +65,14 @@ .label { display: flex; - align-items: baseline; + align-items: center; gap: 4px; } input { - border: none; width: 40px; padding: 0; text-align: center; - font-weight: 600; } .level-button { @@ -101,9 +101,9 @@ display: flex; justify-content: space-between; padding: 5px 0; - margin-bottom: 8px; + margin-bottom: 10px; font-size: var(--font-size-12); - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); .missing-header-feature { opacity: 0.5; @@ -131,7 +131,7 @@ display: flex; align-items: center; padding: 0; - margin-bottom: 12px; + margin-bottom: 15px; .resource-section { display: flex; @@ -168,11 +168,11 @@ .domains-section { position: relative; display: flex; - gap: 4px; + gap: 10px; background-color: light-dark(transparent, @dark-blue); - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); padding: 5px 10px; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; align-items: center; width: fit-content; @@ -182,8 +182,7 @@ font-size: var(--font-size-14); font-weight: bold; text-transform: uppercase; - color: @color-text-emphatic; - margin-right: 4px; + color: light-dark(@dark-blue, @golden); } .domain { @@ -195,7 +194,7 @@ font-size: var(--font-size-14); font-weight: bold; text-transform: uppercase; - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); } img { @@ -218,110 +217,37 @@ .character-traits { display: flex; + justify-content: space-between; padding: 0; margin-bottom: 15px; - justify-content: space-between; - max-width: 38.5rem; - gap: 0.5rem; - padding-left: 0.5rem; .trait { + height: 60px; + width: 60px; cursor: pointer; - position: relative; - - display: flex; - align-items: center; - justify-content: center; - flex-direction: column; - min-width: 4.375rem; .trait-name { - position: relative; - background-color: @trait-color-bg; - border: 1px solid @trait-color-border; - border-radius: 3px; - color: @color-text-emphatic; - font-size: var(--font-size-12); - font-weight: 600; - height: 1rem; - line-height: 1rem; - white-space: nowrap; - width: 100%; - padding: 0 0.1876px 0 0.375rem; - margin-right: 0.125rem; /* makes it center SLIGHTLY */ - text-shadow: 1px 1px 3px @color-text-shadow-contrast; - display: flex; align-items: center; + padding-top: 5px; + color: light-dark(@dark-blue, @golden); + font-size: var(--font-size-14); + font-weight: 600; + align-items: center; justify-content: center; + gap: 3px; - .tier-mark { - position: absolute; - background-color: @dark-blue; - border: 1px solid @color-border; - border-radius: 50%; - width: 1rem; - height: 1rem; - right: calc(100% - 0.4375rem); - display: flex; - justify-content: center; - align-items: center; - &.marked::before { - content: ' '; - position: absolute; - width: 0.5rem; - height: 0.5rem; - border-radius: 50%; - background-color: @golden; - } + i { + line-height: 17px; + font-size: var(--font-size-10); } } - .trait-value-area { - --color-border: @trait-color-border; - --background: light-dark(#e8e6e3, @dark-blue); - display: flex; - position: relative; - .trait-value { - position: absolute; - inset: 0; - display: flex; - align-items: center; - - justify-content: center; - font-style: normal; - font-weight: 600; - font-size: var(--font-size-20); - text-align: center; - margin-bottom: 0.375rem; - } - - .spellcasting-mark { - position: absolute; - border: 1px solid @color-border; - color: @golden; - left: 0; - right: 0; - bottom: -0.375rem; - margin-inline: auto; - border-radius: 50%; - width: 1.125rem; - height: 1.125rem; - background: radial-gradient(190.63% 190.63% at 50% -80.63%, #18152E 70%, #4D4494 80%, #A0837E 90%, var(--color-border) 100%); - font-size: var(--font-size-9); - text-shadow: 0 0 2px @light-black; - - display: flex; - align-items: center; - justify-content: center; - } - } - - &:hover { - .trait-name { - color: light-dark(@dark, @beige); - text-shadow: 0 0 8px light-dark(@dark-80, @beige-80); - } + .trait-value { + font-style: normal; + font-weight: 400; + font-size: var(--font-size-20); + text-align: center; } } } diff --git a/styles/less/sheets/actors/character/index.less b/styles/less/sheets/actors/character/index.less deleted file mode 100644 index edefe0a1..00000000 --- a/styles/less/sheets/actors/character/index.less +++ /dev/null @@ -1,8 +0,0 @@ -@import './biography.less'; -@import './effects.less'; -@import './features.less'; -@import './header.less'; -@import './inventory.less'; -@import './loadout.less'; -@import './sheet.less'; -@import './sidebar.less'; diff --git a/styles/less/sheets/actors/character/inventory.less b/styles/less/sheets/actors/character/inventory.less index fcfbbee9..b555aa3d 100644 --- a/styles/less/sheets/actors/character/inventory.less +++ b/styles/less/sheets/actors/character/inventory.less @@ -1,17 +1,70 @@ @import '../../../utils/colors.less'; @import '../../../utils/fonts.less'; -@import '../../../utils/mixin.less'; .application.sheet.daggerheart.actor.dh-style.character { .tab.inventory { + .search-section { + display: flex; + gap: 10px; + align-items: center; + + .search-bar { + position: relative; + color: light-dark(@dark-blue-50, @beige-50); + width: 100%; + padding-top: 5px; + + input { + border-radius: 50px; + background: light-dark(@dark-blue-10, @golden-10); + border: none; + outline: 2px solid transparent; + transition: all 0.3s ease; + padding: 0 20px; + + &:hover { + outline: 2px solid light-dark(@dark, @golden); + } + + &::-webkit-search-cancel-button { + -webkit-appearance: none; + display: none; + } + } + + .icon { + align-content: center; + height: 32px; + position: absolute; + right: 20px; + font-size: var(--font-size-16); + z-index: 1; + color: light-dark(@dark-blue-50, @beige-50); + } + } + } + .items-section { display: flex; flex-direction: column; gap: 10px; overflow-y: auto; - margin-top: 20px; - padding-bottom: 20px; - .with-scroll-shadows(); + mask-image: linear-gradient(0deg, transparent 0%, black 5%, black 95%, transparent 100%); + padding: 20px 0; + + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; + } + + .currency-section { + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr; + gap: 10px; + padding: 10px 10px 0; + + .input { + color: light-dark(@dark, @beige); + } } } } diff --git a/styles/less/sheets/actors/character/loadout.less b/styles/less/sheets/actors/character/loadout.less index fa3e0176..eba55890 100644 --- a/styles/less/sheets/actors/character/loadout.less +++ b/styles/less/sheets/actors/character/loadout.less @@ -1,13 +1,51 @@ @import '../../../utils/colors.less'; @import '../../../utils/fonts.less'; -@import '../../../utils/mixin.less'; .application.sheet.daggerheart.actor.dh-style.character { .tab.loadout { .search-section { + display: flex; + align-items: center; + justify-content: space-between; + + .search-bar { + position: relative; + color: light-dark(@dark-blue-50, @beige-50); + width: 80%; + padding-top: 5px; + + input { + border-radius: 50px; + background: light-dark(@dark-blue-10, @golden-10); + border: none; + outline: 2px solid transparent; + transition: all 0.3s ease; + padding: 0 20px; + + &:hover { + outline: 2px solid light-dark(@dark, @golden); + } + + &::-webkit-search-cancel-button { + -webkit-appearance: none; + display: none; + } + } + + .icon { + align-content: center; + height: 32px; + position: absolute; + right: 20px; + font-size: var(--font-size-16); + z-index: 1; + color: light-dark(@dark-blue-50, @beige-50); + } + } + .btn-toggle-view { background: light-dark(@dark-blue-10, @dark-blue); - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 15px; padding: 0; gap: 0; @@ -16,7 +54,7 @@ span { margin: 1px; width: 26px; - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); &.list-icon { i { @@ -52,9 +90,11 @@ gap: 10px; height: 100%; overflow-y: auto; - margin-top: 20px; - padding-bottom: 20px; - .with-scroll-shadows(); + mask-image: linear-gradient(0deg, transparent 0%, black 10%, black 98%, transparent 100%); + padding: 20px 0; + + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; } } } diff --git a/styles/less/sheets/actors/character/sheet.less b/styles/less/sheets/actors/character/sheet.less index 68792c99..ee6580fd 100644 --- a/styles/less/sheets/actors/character/sheet.less +++ b/styles/less/sheets/actors/character/sheet.less @@ -11,6 +11,21 @@ padding-bottom: 0; overflow-x: auto; + &.viewMode { + button:not(.btn-toggle-view), + input:not(.search), + .controls, + .character-sidebar-sheet, + .img-portait, + .name-row, + .hope-section, + .downtime-section, + .character-traits, + .card-list { + pointer-events: none; + } + } + .character-sidebar-sheet { grid-row: 1 / span 2; grid-column: 1; diff --git a/styles/less/sheets/actors/character/sidebar.less b/styles/less/sheets/actors/character/sidebar.less index c76ee9ff..04baf2b9 100644 --- a/styles/less/sheets/actors/character/sidebar.less +++ b/styles/less/sheets/actors/character/sidebar.less @@ -40,7 +40,7 @@ .application.sheet.dh-style .character-sidebar-sheet { width: 275px; min-width: 275px; - border-right: 1px solid @color-border; + border-right: 1px solid light-dark(@dark-blue, @golden); .portrait { position: relative; @@ -74,6 +74,62 @@ .death-roll-btn { display: none; } + + .icons-list { + position: absolute; + display: flex; + flex-direction: column; + gap: 5px; + align-items: end; + justify-content: center; + top: 45px; + right: 10px; + + .spellcast-icon { + display: flex; + align-items: center; + justify-content: end; + text-align: center; + padding-right: 8px; + max-width: 50px; + height: 50px; + font-size: 1.2rem; + background: light-dark(@dark-blue-60, @dark-golden-80); + backdrop-filter: blur(8px); + border: 4px double light-dark(@beige, @golden); + color: light-dark(@beige, @golden); + border-radius: 999px; + transition: all 0.3s ease; + + .spellcast-label { + font-size: var(--font-size-14); + opacity: 0; + margin-right: 0.3rem; + transition: all 0.3s ease; + } + + i { + height: 24px; + width: 24px; + align-content: center; + margin-right: 3px; + } + + &:not(.no-label):hover { + max-width: 300px; + padding: 0 10px; + border-radius: 60px; + + .spellcast-label { + opacity: 1; + } + + i { + margin-right: 0px; + } + } + } + } } .info-section { @@ -168,7 +224,7 @@ appearance: none; width: 100px; height: 40px; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; z-index: 1; background: @dark-blue; @@ -220,23 +276,6 @@ } } - .slot-label { - .slot-value-container { - position: relative; - display: flex; - align-items: center; - justify-content: center; - width: 100%; - - i { - position: absolute; - right: 0; - font-size: 12px; - color: light-dark(@beige, @dark-blue); - } - } - } - .status-value { padding: 0 5px; } @@ -249,7 +288,6 @@ position: relative; width: 95px; height: 30px; - white-space: nowrap; .status-label { padding: 2px 2px; @@ -260,12 +298,6 @@ border-radius: 3px; background: light-dark(@dark-blue, @golden); clip-path: none; - display: flex; - align-items: center; - justify-content: center; - gap: 4px; - border: 1px solid transparent; - transition: all 0.3s ease; h4 { font-weight: bold; @@ -274,21 +306,6 @@ color: light-dark(@beige, @dark-blue); font-size: var(--font-size-12); } - - i { - font-size: 12px; - color: light-dark(@beige, @dark-blue); - } - - &:hover { - background: light-dark(@light-black, @dark-blue); - border: 1px solid @color-border; - - h4, - i { - color: @color-text-emphatic; - } - } } .slot-value { position: absolute; @@ -309,12 +326,12 @@ flex-wrap: wrap; gap: 4px; padding: 5px; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; z-index: 1; background: @dark-blue; justify-content: center; - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); .armor-slot { cursor: pointer; @@ -338,19 +355,6 @@ font-size: var(--font-size-12); flex-wrap: wrap; justify-content: center; - border: 1px solid transparent; - transition: all 0.3s ease; - - &:hover { - background: light-dark(@light-black, @dark-blue); - border: 1px solid @color-border; - - .label, - .value, - i { - color: @color-text-emphatic; - } - } .label { padding-right: 1px; @@ -375,7 +379,7 @@ text-align: center; z-index: 2; color: light-dark(@dark-blue, @beige); - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-bottom: none; border-radius: 6px 6px 0 0; @@ -411,7 +415,7 @@ appearance: none; width: 80px; height: 30px; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; z-index: 1; background: light-dark(transparent, @dark-blue); @@ -450,7 +454,7 @@ display: flex; width: 50px; height: 30px; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-bottom: none; border-radius: 6px 6px 0 0; padding: 0 6px; @@ -513,9 +517,9 @@ align-self: center; gap: 10px; background-color: light-dark(transparent, @dark-blue); - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); padding: 5px 10px; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; align-items: center; width: fit-content; @@ -525,7 +529,7 @@ font-size: var(--font-size-14); font-weight: bold; text-transform: uppercase; - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); &.threshold-value { color: light-dark(@dark, @beige); @@ -549,11 +553,13 @@ overflow-y: hidden; padding-top: 10px; padding-bottom: 20px; + mask-image: linear-gradient(0deg, transparent 0%, black 5%); scrollbar-gutter: stable; - .with-scroll-shadows(); - + scrollbar-width: thin; + &:hover { overflow-y: auto; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; } } diff --git a/styles/less/sheets/actors/companion/effects.less b/styles/less/sheets/actors/companion/effects.less index c0cac669..12e1d847 100644 --- a/styles/less/sheets/actors/companion/effects.less +++ b/styles/less/sheets/actors/companion/effects.less @@ -7,8 +7,11 @@ flex-direction: column; gap: 10px; overflow-y: auto; + mask-image: linear-gradient(0deg, transparent 0%, black 5%); padding-bottom: 20px; - .with-scroll-shadows(); + + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; } } } diff --git a/styles/less/sheets/actors/companion/header.less b/styles/less/sheets/actors/companion/header.less index aca789a6..2a162a25 100644 --- a/styles/less/sheets/actors/companion/header.less +++ b/styles/less/sheets/actors/companion/header.less @@ -11,7 +11,7 @@ .profile { height: 235px; cursor: pointer; - .smooth-gradient-ease-in-out(mask-image, to top, black, 2.25rem); + mask-image: linear-gradient(0deg, transparent 0%, black 10%); } .actor-name { @@ -24,20 +24,15 @@ margin-bottom: -30px; input[type='text'] { - backdrop-filter: none; - border: none; - font-family: @font-title; font-size: var(--font-size-24); - outline: 2px solid transparent; - box-shadow: unset; - text-shadow: 0 0 4px @color-text-shadow-contrast, 0 0 8px @color-text-shadow-contrast, 0 0 14px @color-text-shadow-contrast; - - height: 2rem; + height: 32px; text-align: center; + border: 1px solid transparent; + outline: 2px solid transparent; transition: all 0.3s ease; &:hover { - outline: 2px solid @color-border; + outline: 2px solid light-dark(@dark, @golden); } } } @@ -68,7 +63,7 @@ display: flex; width: 50px; height: 40px; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-bottom: none; border-radius: 6px 6px 0 0; padding: 0 6px; @@ -100,6 +95,104 @@ } } + // .status-bar { + // display: flex; + // justify-content: center; + // position: relative; + // width: 100px; + // height: 40px; + + // .status-label { + // position: relative; + // top: 40px; + // height: 22px; + // width: 79px; + // clip-path: path('M0 0H79L74 16.5L39 22L4 16.5L0 0Z'); + // background: light-dark(@dark-blue, @golden); + + // h4 { + // font-weight: bold; + // text-align: center; + // line-height: 18px; + // color: light-dark(@beige, @dark-blue); + // } + // } + // .status-value { + // position: absolute; + // display: flex; + // padding: 0 6px; + // font-size: 1.5rem; + // align-items: center; + // width: 100px; + // height: 40px; + // justify-content: center; + // text-align: center; + // z-index: 2; + // color: @beige; + + // input[type='number'] { + // background: transparent; + // font-size: 1.5rem; + // width: 40px; + // height: 30px; + // text-align: center; + // border: none; + // outline: 2px solid transparent; + // color: @beige; + + // &.bar-input { + // padding: 0; + // color: @beige; + // backdrop-filter: none; + // background: transparent; + // transition: all 0.3s ease; + + // &:hover, + // &:focus { + // background: @semi-transparent-dark-blue; + // backdrop-filter: blur(9.5px); + // } + // } + // } + + // .bar-label { + // width: 40px; + // } + // } + // .progress-bar { + // position: absolute; + // appearance: none; + // width: 100px; + // height: 40px; + // border: 1px solid light-dark(@dark-blue, @golden); + // border-radius: 6px; + // z-index: 1; + // background: @dark-blue; + + // &::-webkit-progress-bar { + // border: none; + // background: @dark-blue; + // border-radius: 6px; + // } + // &::-webkit-progress-value { + // background: @gradient-hp; + // border-radius: 6px; + // } + // &.stress-color::-webkit-progress-value { + // background: @gradient-stress; + // border-radius: 6px; + // } + // &::-moz-progress-bar { + // background: @gradient-hp; + // border-radius: 6px; + // } + // &.stress-color::-moz-progress-bar { + // background: @gradient-stress; + // border-radius: 6px; + // } + // } + // } + .level-div { white-space: nowrap; display: flex; @@ -148,8 +241,10 @@ } .companion-navigation { + display: flex; + gap: 8px; + align-items: center; width: 100%; - padding: 0 10px; } } } diff --git a/styles/less/sheets/actors/companion/index.less b/styles/less/sheets/actors/companion/index.less deleted file mode 100644 index c4931814..00000000 --- a/styles/less/sheets/actors/companion/index.less +++ /dev/null @@ -1,4 +0,0 @@ -@import './details.less'; -@import './header.less'; -@import './sheet.less'; -@import './effects.less'; diff --git a/styles/less/sheets/actors/companion/sheet.less b/styles/less/sheets/actors/companion/sheet.less index 8bf8a0b9..f31679ba 100644 --- a/styles/less/sheets/actors/companion/sheet.less +++ b/styles/less/sheets/actors/companion/sheet.less @@ -10,16 +10,3 @@ background: url('../assets/parchments/dh-parchment-light.png'); } }); - -.application.sheet.daggerheart.actor.dh-style.companion { - .window-content { - display: flex; - } - - .tab.active { - flex: 1; - overflow: hidden; - display: flex; - flex-direction: column; - } -} diff --git a/styles/less/sheets/actors/environment/features.less b/styles/less/sheets/actors/environment/actions.less similarity index 59% rename from styles/less/sheets/actors/environment/features.less rename to styles/less/sheets/actors/environment/actions.less index 84cf26f8..51385322 100644 --- a/styles/less/sheets/actors/environment/features.less +++ b/styles/less/sheets/actors/environment/actions.less @@ -1,6 +1,5 @@ @import '../../../utils/colors.less'; @import '../../../utils/fonts.less'; -@import '../../../utils/mixin.less'; .application.sheet.daggerheart.actor.dh-style.environment { .tab.features { @@ -9,8 +8,11 @@ flex-direction: column; gap: 10px; overflow-y: auto; - padding-bottom: 4px; - .with-scroll-shadows(); + mask-image: linear-gradient(0deg, transparent 0%, black 5%); + padding-bottom: 20px; + + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; } } } diff --git a/styles/less/sheets/actors/environment/header.less b/styles/less/sheets/actors/environment/header.less index da6954e0..670f6c92 100644 --- a/styles/less/sheets/actors/environment/header.less +++ b/styles/less/sheets/actors/environment/header.less @@ -1,6 +1,5 @@ @import '../../../utils/colors.less'; @import '../../../utils/fonts.less'; -@import '../../../utils/mixin.less'; .application.sheet.daggerheart.actor.dh-style.environment { .environment-header-sheet { @@ -11,82 +10,60 @@ .profile { height: 235px; + mask-image: linear-gradient(0deg, transparent 0%, black 10%); cursor: pointer; - .smooth-gradient-ease-in-out(mask-image, to top, black, 3.5rem); } .item-container { - display: grid; - grid-auto-flow: row; - grid-template-columns: 1fr min-content; - + display: flex; align-items: center; position: relative; - top: -36px; - gap: 0 var(--spacer-12); + top: -45px; + gap: 20px; padding: 0 20px; - margin-bottom: -26px; + margin-bottom: -30px; - .item-name input[type='text'] { - backdrop-filter: none; - border: none; - font-family: @font-title; - font-size: var(--font-size-32); - text-align: start; - transition: all 0.3s ease; - outline: 2px solid transparent; - box-shadow: none; - text-shadow: 0 0 4px @color-text-shadow-contrast, 0 0 8px @color-text-shadow-contrast, 0 0 14px @color-text-shadow-contrast; - padding-left: 0; - height: 2.625rem; - - &:hover[type='text'], - &:focus[type='text'] { - box-shadow: none; - outline: 2px solid @color-border; - } - } - - .flexrow { - align-items: baseline; - grid-column: span 2; - } - - .tags { + .item-info { display: flex; - gap: 10px; - padding-bottom: 0; - flex: 0; + flex-direction: column; + gap: 8px; - .tag { + .tags { display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - padding: 3px 5px; - font-size: var(--font-size-12); - font: @font-body; - white-space: nowrap; + gap: 10px; + padding-bottom: 0; - background: light-dark(@dark-15, @beige-15); - border: 1px solid light-dark(@dark, @beige); - border-radius: 3px; + .tag { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + padding: 3px 5px; + font-size: var(--font-size-12); + font: @font-body; + + background: light-dark(@dark-15, @beige-15); + border: 1px solid light-dark(@dark, @beige); + border-radius: 3px; + } + + .label { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + font-size: var(--font-size-12); + } } - .label { - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - font-size: var(--font-size-12); + .attribution-header-label { + text-align: left; + position: relative; + top: 4px; + margin-bottom: -6px; } } - .attribution-header-label { - text-align: right; - position: relative; - } - .status-number { display: flex; align-items: center; @@ -97,14 +74,14 @@ display: flex; width: 50px; height: 30px; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-bottom: none; border-radius: 6px 6px 0 0; padding: 0 6px; font-size: 1.2rem; align-items: center; justify-content: center; - background: light-dark(#e8e6e3, @dark-blue); + background: light-dark(transparent, @dark-blue); z-index: 2; &.armor-slots { @@ -116,7 +93,7 @@ .status-label { padding: 2px 10px; width: 100%; - border-radius: 0 0 3px 3px; + border-radius: 3px; background: light-dark(@dark-blue, @golden); h4 { @@ -128,21 +105,37 @@ } } } + + .item-name { + input[type='text'] { + font-size: var(--font-size-32); + height: 42px; + text-align: start; + transition: all 0.3s ease; + outline: 2px solid transparent; + border: 1px solid transparent; + + &:hover[type='text'], + &:focus[type='text'] { + box-shadow: none; + outline: 2px solid light-dark(@dark-blue, @golden); + } + } + } } .environment-info { display: flex; flex-direction: column; - gap: var(--spacer-8); + gap: 12px; padding: 10px 20px; } .environment-navigation { + display: flex; + gap: 20px; + align-items: center; padding: 0 20px; - - .tab-navigation { - margin-top: 0; - } } } } diff --git a/styles/less/sheets/actors/environment/index.less b/styles/less/sheets/actors/environment/index.less deleted file mode 100644 index 211c8e60..00000000 --- a/styles/less/sheets/actors/environment/index.less +++ /dev/null @@ -1,4 +0,0 @@ -@import './features.less'; -@import './header.less'; -@import './potentialAdversaries.less'; -@import './sheet.less'; diff --git a/styles/less/sheets/actors/environment/potentialAdversaries.less b/styles/less/sheets/actors/environment/potentialAdversaries.less index f112c0d2..274362a5 100644 --- a/styles/less/sheets/actors/environment/potentialAdversaries.less +++ b/styles/less/sheets/actors/environment/potentialAdversaries.less @@ -7,8 +7,11 @@ flex-direction: column; gap: 10px; overflow-y: auto; - padding-bottom: 4px; - .with-scroll-shadows(); + mask-image: linear-gradient(0deg, transparent 0%, black 5%); + padding-bottom: 20px; + + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; } } } diff --git a/styles/less/sheets/actors/environment/sheet.less b/styles/less/sheets/actors/environment/sheet.less index 2d9cc188..3ea14bc7 100644 --- a/styles/less/sheets/actors/environment/sheet.less +++ b/styles/less/sheets/actors/environment/sheet.less @@ -5,6 +5,10 @@ .appTheme({ &.environment { background-image: url('../assets/parchments/dh-parchment-dark.png'); + + .attribution-header-label { + background-image: url('../assets/parchments/dh-parchment-dark.png'); + } } }, { &.environment { @@ -16,6 +20,8 @@ .tab { flex: 1; overflow-y: auto; + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; &.active { overflow: hidden; diff --git a/styles/less/sheets/actors/index.less b/styles/less/sheets/actors/index.less deleted file mode 100644 index 959bc0f5..00000000 --- a/styles/less/sheets/actors/index.less +++ /dev/null @@ -1,7 +0,0 @@ -@import './actor-sheet-shared.less'; -@import './adversary/index.less'; -@import './character/index.less'; -@import './companion/index.less'; -@import './environment/index.less'; -@import './npc/index.less'; -@import './party/index.less'; \ No newline at end of file diff --git a/styles/less/sheets/actors/npc/features.less b/styles/less/sheets/actors/npc/features.less deleted file mode 100644 index a579d9f8..00000000 --- a/styles/less/sheets/actors/npc/features.less +++ /dev/null @@ -1,18 +0,0 @@ -.application.sheet.daggerheart.actor.dh-style.npc { - .tab.features { - &.active { - overflow: hidden; - display: flex; - flex-direction: column; - } - - .feature-section { - display: flex; - flex-direction: column; - gap: 10px; - overflow-y: auto; - padding-bottom: 4px; - .with-scroll-shadows(); - } - } -} diff --git a/styles/less/sheets/actors/npc/header.less b/styles/less/sheets/actors/npc/header.less deleted file mode 100644 index 086a254c..00000000 --- a/styles/less/sheets/actors/npc/header.less +++ /dev/null @@ -1,83 +0,0 @@ -.application.sheet.daggerheart.actor.dh-style.npc { - .npc-header-sheet { - width: 100%; - display: flex; - - .portrait { - cursor: pointer; - max-width: 275px; - - img { - height: 275px; - } - } - - .tags { - display: flex; - gap: 10px; - padding-bottom: 8px; - - .tag { - display: flex; - flex-direction: row; - gap: 4px; - justify-content: center; - align-items: center; - padding: 3px 5px; - font-size: var(--font-size-12); - font: @font-body; - - background: light-dark(@dark-15, @beige-15); - border: 1px solid light-dark(@dark, @beige); - border-radius: 3px; - } - - .label { - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - font-size: var(--font-size-12); - } - } - - .info-section { - flex: 1; - padding: 0 15px; - padding-top: var(--header-height); - display: flex; - flex-direction: column; - - .name-row { - display: flex; - gap: 5px; - align-items: center; - justify-content: space-between; - padding: 8px 0; - - h1 { - display: flex; - flex: 1; - padding: 6px 0 0 0; - font-size: var(--font-size-32); - text-align: start; - border: 1px solid transparent; - outline: 2px solid transparent; - transition: all 0.3s ease; - word-break: break-word; - - &:hover { - outline: 2px solid light-dark(@dark, @golden); - } - } - } - - .npc-info { - display: flex; - flex-direction: column; - gap: 12px; - padding: 16px 0; - } - } - } -} \ No newline at end of file diff --git a/styles/less/sheets/actors/npc/index.less b/styles/less/sheets/actors/npc/index.less deleted file mode 100644 index 2d7d54e3..00000000 --- a/styles/less/sheets/actors/npc/index.less +++ /dev/null @@ -1,3 +0,0 @@ -@import './sheet.less'; -@import './header.less'; -@import './features.less'; \ No newline at end of file diff --git a/styles/less/sheets/actors/npc/sheet.less b/styles/less/sheets/actors/npc/sheet.less deleted file mode 100644 index 8ba3b7a9..00000000 --- a/styles/less/sheets/actors/npc/sheet.less +++ /dev/null @@ -1,10 +0,0 @@ -.application.sheet.daggerheart.actor.dh-style.npc { - .window-content { - display: grid; - grid-template-rows: auto auto 1fr; - } - - .npc-navigation { - padding: 0 15px; - } -} \ No newline at end of file diff --git a/styles/less/sheets/actors/party/header.less b/styles/less/sheets/actors/party/header.less index 58e3bc31..9a2c7350 100644 --- a/styles/less/sheets/actors/party/header.less +++ b/styles/less/sheets/actors/party/header.less @@ -1,6 +1,5 @@ @import '../../../utils/colors.less'; @import '../../../utils/fonts.less'; -@import '../../../utils/mixin.less'; .party-header-sheet { display: flex; @@ -10,31 +9,26 @@ .profile { height: 235px; + mask-image: linear-gradient(0deg, transparent 0%, black 10%); cursor: pointer; - .smooth-gradient-ease-in-out(mask-image, to top, black, 3.5rem); } .item-container { - margin-top: -2rem; - z-index: 1; - input.item-name[type='text'] { - backdrop-filter: none; - border: none; - color: @color-text-emphatic; - font-family: @font-title; - font-size: var(--font-size-32); - outline: 2px solid transparent; - box-shadow: unset; - text-shadow: 0 0 4px @color-text-shadow-contrast, 0 0 8px @color-text-shadow-contrast, 0 0 14px @color-text-shadow-contrast; + .item-name { + padding: 0 20px; + input[type='text'] { + font-size: 32px; + height: 42px; + text-align: center; + transition: all 0.3s ease; + outline: 2px solid transparent; + border: 1px solid transparent; - text-align: center; - transition: all 0.3s ease; - width: calc(100% - 40px); - height: 2.625rem; - - &:hover[type='text'], - &:focus[type='text'] { - outline: 2px solid @color-border; + &:hover[type='text'], + &:focus[type='text'] { + box-shadow: none; + outline: 2px solid light-dark(@dark-blue, @golden); + } } } diff --git a/styles/less/sheets/actors/party/index.less b/styles/less/sheets/actors/party/index.less deleted file mode 100644 index 56f7a457..00000000 --- a/styles/less/sheets/actors/party/index.less +++ /dev/null @@ -1,4 +0,0 @@ -@import './header.less'; -@import './party-members.less'; -@import './sheet.less'; -@import './inventory.less'; diff --git a/styles/less/sheets/actors/party/inventory.less b/styles/less/sheets/actors/party/inventory.less index 444c6a57..2dcc97d8 100644 --- a/styles/less/sheets/actors/party/inventory.less +++ b/styles/less/sheets/actors/party/inventory.less @@ -1,17 +1,74 @@ @import '../../../utils/colors.less'; @import '../../../utils/fonts.less'; -@import '../../../utils/mixin.less'; .application.sheet.daggerheart.actor.dh-style.party { .tab.inventory { + .search-section { + display: flex; + gap: 10px; + align-items: center; + + .search-bar { + position: relative; + color: light-dark(@dark-blue-50, @beige-50); + width: 100%; + padding-top: 5px; + + input { + border-radius: 50px; + background: light-dark(@dark-blue-10, @golden-10); + border: none; + outline: 2px solid transparent; + transition: all 0.3s ease; + padding: 0 20px; + + &:hover { + outline: 2px solid light-dark(@dark, @golden); + } + + &:placeholder { + color: light-dark(@dark-blue-50, @beige-50); + } + + &::-webkit-search-cancel-button { + -webkit-appearance: none; + display: none; + } + } + + .icon { + align-content: center; + height: 32px; + position: absolute; + right: 20px; + font-size: 16px; + z-index: 1; + color: light-dark(@dark-blue-50, @beige-50); + } + } + } + .items-section { display: flex; flex-direction: column; gap: 10px; overflow-y: auto; - margin-top: 20px; - padding-bottom: 4px; - .with-scroll-shadows(); + mask-image: linear-gradient(0deg, transparent 0%, black 5%, black 95%, transparent 100%); + padding: 20px 0; + + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; + } + + .currency-section { + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr; + gap: 10px; + padding: 10px 10px 0; + + .input { + color: light-dark(@dark, @beige); + } } } } diff --git a/styles/less/sheets/actors/party/party-members.less b/styles/less/sheets/actors/party/party-members.less index dc464291..a433ae34 100644 --- a/styles/less/sheets/actors/party/party-members.less +++ b/styles/less/sheets/actors/party/party-members.less @@ -1,295 +1,28 @@ @import '../../../utils/colors.less'; @import '../../../utils/fonts.less'; -@import '../../../utils/mixin.less'; -.application.sheet.daggerheart.actor.dh-style.party .tab.partyMembers { - overflow: auto; +.application.sheet.daggerheart.actor.dh-style.party { + .tab.partyMembers { + max-height: 400px; + overflow: auto; - .actors-list { - display: flex; - flex-direction: column; - gap: 8px; - align-items: stretch; - width: 100%; - - .actor-resources { - display: grid; - grid-template: - "img header" min-content - "img body" 1fr - / 7.5rem 1fr; - gap: 6px; - column-gap: 12px; - padding: 6px; - background-color: light-dark(@dark-blue-10, @golden-10); - - .actor-img-frame { - grid-area: img; - width: 7.375rem; - height: 7.375rem; - position: relative; - - .actor-img { - object-fit: cover; - object-position: top center; - border-radius: 6px; - width: 100%; - height: 100%; - } - - .equipped-weapons { - position: absolute; - top: -2px; - left: -3px; - display: flex; - flex-direction: column; - gap: 1px; - img { - border-radius: 50%; - width: 24px; - height: 24px; - border: 1px solid @color-border; - object-fit: cover; - } - } - - .evasion { - position: absolute; - top: 1px; - right: 1px; - width: 1.75rem; - height: 1.75rem; - background: url('../assets/svg/trait-shield.svg') no-repeat; - background-size: 100%; - color: var(--color-light-1); - font-size: var(--font-size-14); - font-weight: 700; - display: flex; - align-items: center; - justify-content: center; - } - - .threshold-section { - position: absolute; - left: 0; - right: 0; - bottom: -2px; - margin: auto; - - display: flex; - gap: 4px; - background-color: light-dark(var(--color-light-1), @dark-blue); - color: @color-text-emphatic; - padding: 4px 6px; - border: 1px solid @color-border; - border-radius: 3px; - align-items: baseline; - width: fit-content; - - h4 { - font-weight: bold; - text-transform: uppercase; - white-space: nowrap; - - &.threshold-label { - font-size: var(--font-size-10); - color: @color-text-emphatic; - } - - &.threshold-value { - font-size: var(--font-size-11); - color: light-dark(@dark, @beige); - } - } - } - } - - header { - grid-area: header; - display: grid; - grid-template: - "name hope" min-content - "subtitle subtitle" min-content - / 1fr min-content; - - .actor-name { - width: 100%; - z-index: 1; - font-size: var(--font-size-20); - color: @color-text-emphatic; - font-weight: bold; - } - - .delete-icon { - font-size: 0.75em; - } - - .subtitle { - grid-area: subtitle; - font-size: var(--font-size-14); - } - - .hope-section { - display: flex; - background-color: light-dark(transparent, @dark-blue); - color: @color-text-emphatic; - padding: 3px 6px; - border: 1px solid @color-border; - border-radius: 3px; - align-items: center; - width: fit-content; - margin-left: auto; - - h4 { - font-size: var(--font-size-12); - font-weight: bold; - text-transform: uppercase; - color: @color-text-emphatic; - margin-right: 3px; - } - - .hope-value { - display: flex; - cursor: pointer; - font-size: var(--font-size-12); - margin-left: 1px; - } - } - } - - .body { - grid-area: body; - display: flex; - align-items: start; - justify-content: space-between; - } - - .resources { - display: flex; - flex-direction: column; - gap: 4px; - - .slot-section { - display: flex; - flex-direction: row; - align-items: stretch; - - .slot-label { - display: flex; - align-items: center; - color: light-dark(@beige, @dark-blue); - background: light-dark(@dark-blue, @golden); - padding: 0 4px; - width: fit-content; - font-weight: bold; - border-radius: 6px 0px 0px 6px; - font-size: var(--font-size-12); - white-space: nowrap; - - .label { - padding-right: 2px; - } - - .value { - font-variant-numeric: tabular-nums; - .current { - display: inline-block; - text-align: end; - width: 2ch; - } - .max { - display: inline-block; - text-align: start; - width: 2ch; - } - } - } - - .slot-bar { - display: flex; - align-items: center; - flex-wrap: wrap; - gap: 4px; - - background-color: light-dark(@dark-blue-10, @dark-blue); - color: @color-text-emphatic; - padding: 2px 5px; - border: 1px solid @color-border; - border-radius: 0 6px 6px 0; - width: fit-content; - min-height: 22px; - - .armor-slot { - cursor: pointer; - transition: all 0.3s ease; - font-size: var(--font-size-12); - - .fa-shield-halved { - color: light-dark(@dark-blue-40, @golden-40); - } - } - - .slot { - width: 16px; - height: 10px; - border: 1px solid @color-border; - background: light-dark(@dark-blue-10, @golden-10); - border-radius: 3px; - transition: all 0.3s ease; - cursor: pointer; - - &.filled { - background: light-dark(@dark-blue, @golden); - } - } - } - } - } - - .traits { - background-color: light-dark(@dark-blue-10, @dark-blue); - border: 1px solid @color-border; - border-radius: 6px; - display: grid; - grid-template-columns: 1fr 1fr; - font-size: var(--font-size-12); - padding: 3px 4px; - gap: 3px 7px; - .trait { - display: flex; - justify-content: space-between; - gap: 3px; - .label { - color: @color-text-emphatic; - } - .value { - font-weight: 600; - } - } - } + .actors-list { + display: flex; + flex-direction: column; + gap: 10px; + align-items: center; + width: 100%; } - } - - .actors-list.limited { - .actor-resources { + .actors-dragger { display: flex; align-items: center; + justify-content: center; + box-sizing: border-box; + width: 100%; + height: 40px; + border: 1px dashed light-dark(@dark-blue-50, @beige-50); + border-radius: 3px; + color: light-dark(@dark-blue-50, @beige-50); } - .actor-img-frame { - width: 3rem; - height: 3rem; - } - } - - .actors-dragger { - display: flex; - align-items: center; - justify-content: center; - box-sizing: border-box; - width: 100%; - height: 40px; - border: 1px dashed light-dark(@dark-blue-50, @beige-50); - border-radius: 3px; - color: light-dark(@dark-blue-50, @beige-50); } } diff --git a/styles/less/sheets/actors/party/resources.less b/styles/less/sheets/actors/party/resources.less new file mode 100644 index 00000000..4db254bf --- /dev/null +++ b/styles/less/sheets/actors/party/resources.less @@ -0,0 +1,196 @@ +@import '../../../utils/colors.less'; +@import '../../../utils/fonts.less'; +@import '../../../utils/mixin.less'; + +body.game:is(.performance-low, .noblur) { + .application.sheet.daggerheart.actor.dh-style.party .tab.resources .actors-list .actor-resources { + background: light-dark(@dark-blue, @dark-golden); + + .actor-name { + background: light-dark(@dark-blue, @dark-golden); + } + } +} + +.application.sheet.daggerheart.actor.dh-style.party { + .tab.resources { + overflow: auto; + + .actors-list { + display: flex; + flex-direction: row; + flex-wrap: wrap; + gap: 10px; + align-items: center; + width: 100%; + justify-content: center; + + .actor-resources { + display: flex; + flex-direction: column; + position: relative; + background: light-dark(@dark-blue-40, @dark-golden-40); + border-radius: 6px; + border: 1px solid light-dark(@dark-blue, @golden); + width: 230px; + height: -webkit-fill-available; + + .actor-name { + position: absolute; + top: 0px; + background: light-dark(@dark-blue-90, @dark-golden-80); + backdrop-filter: blur(6.5px); + border-radius: 6px 6px 0px 0px; + text-align: center; + width: 100%; + z-index: 1; + font-size: var(--font-size-20); + color: light-dark(@beige, @golden); + font-weight: bold; + padding: 5px 0; + } + + .actor-img { + height: 150px; + object-fit: cover; + object-position: top center; + border-radius: 6px 6px 0px 0px; + mask-image: linear-gradient(180deg, black 88%, transparent 100%); + } + + .resources { + display: flex; + flex-direction: column; + gap: 10px; + align-items: center; + margin: 10px; + + .slot-section { + display: flex; + flex-direction: column; + align-items: center; + + .slot-bar { + display: flex; + flex-wrap: wrap; + gap: 5px; + width: 239px; + + background-color: light-dark(@dark-blue-10, @dark-blue); + color: light-dark(@dark-blue, @golden); + padding: 5px; + border: 1px solid light-dark(@dark-blue, @golden); + border-radius: 6px; + width: fit-content; + + .armor-slot { + cursor: pointer; + transition: all 0.3s ease; + font-size: var(--font-size-12); + + .fa-shield-halved { + color: light-dark(@dark-blue-40, @golden-40); + } + } + + .slot { + width: 20px; + height: 10px; + border: 1px solid light-dark(@dark-blue, @golden); + background: light-dark(@dark-blue-10, @golden-10); + border-radius: 3px; + transition: all 0.3s ease; + cursor: pointer; + + &.filled { + background: light-dark(@dark-blue, @golden); + } + } + } + .slot-label { + display: flex; + align-items: center; + color: light-dark(@beige, @dark-blue); + background: light-dark(@dark-blue, @golden); + padding: 0 5px; + width: fit-content; + font-weight: bold; + border-radius: 0px 0px 5px 5px; + font-size: var(--font-size-12); + + .label { + padding-right: 5px; + } + + .value { + padding-left: 6px; + border-left: 1px solid light-dark(@beige, @dark-golden); + } + } + } + + .hope-section { + position: relative; + display: flex; + gap: 10px; + background-color: light-dark(transparent, @dark-blue); + color: light-dark(@dark-blue, @golden); + padding: 5px 10px; + border: 1px solid light-dark(@dark-blue, @golden); + border-radius: 3px; + align-items: center; + width: fit-content; + + h4 { + font-size: var(--font-size-12); + font-weight: bold; + text-transform: uppercase; + color: light-dark(@dark-blue, @golden); + } + + .hope-value { + display: flex; + cursor: pointer; + font-size: var(--font-size-12); + } + } + + .threshold-section { + display: flex; + align-self: center; + gap: 10px; + background-color: light-dark(transparent, @dark-blue); + color: light-dark(@dark-blue, @golden); + padding: 5px 10px; + border: 1px solid light-dark(@dark-blue, @golden); + border-radius: 3px; + align-items: center; + width: fit-content; + + h4 { + font-size: var(--font-size-12); + font-weight: bold; + text-transform: uppercase; + color: light-dark(@dark-blue, @golden); + + &.threshold-value { + color: light-dark(@dark, @beige); + } + } + } + } + } + } + .actors-dragger { + display: flex; + align-items: center; + justify-content: center; + box-sizing: border-box; + width: 100%; + height: 40px; + border: 1px dashed light-dark(@dark-blue-50, @beige-50); + border-radius: 3px; + color: light-dark(@dark-blue-50, @beige-50); + } + } +} diff --git a/styles/less/sheets/actors/party/sheet.less b/styles/less/sheets/actors/party/sheet.less index 852b6cfc..2d1344e8 100644 --- a/styles/less/sheets/actors/party/sheet.less +++ b/styles/less/sheets/actors/party/sheet.less @@ -7,12 +7,8 @@ background-image: url('../assets/parchments/dh-parchment-dark.png'); } }, { - &.sheet.actor.dh-style.party { + &.party { background: url('../assets/parchments/dh-parchment-light.png'); - - .tab .actions-section .active-action { - animation: glow-dark 0.75s infinite alternate; - } } }); @@ -20,6 +16,8 @@ .tab { flex: 1; overflow-y: auto; + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; scrollbar-gutter: stable; &.active { @@ -42,10 +40,6 @@ font-size: 12px; } } - - .active-action { - animation: glow 0.75s infinite alternate; - } } } } diff --git a/styles/less/sheets/index.less b/styles/less/sheets/index.less index 451ae03a..1bdb451a 100644 --- a/styles/less/sheets/index.less +++ b/styles/less/sheets/index.less @@ -1,5 +1,44 @@ -@import './activeEffects/index.less'; -@import './actions/index.less'; -@import './actors/index.less'; -@import './items/index.less'; -@import './rollTables/index.less'; \ No newline at end of file +@import './actions/actions.less'; + +@import './actors/actor-sheet-shared.less'; + +@import './actors/adversary/actions.less'; +@import './actors/adversary/header.less'; +@import './actors/adversary/sheet.less'; +@import './actors/adversary/sidebar.less'; +@import './actors/adversary/effects.less'; + +@import './actors/character/biography.less'; +@import './actors/character/effects.less'; +@import './actors/character/features.less'; +@import './actors/character/header.less'; +@import './actors/character/inventory.less'; +@import './actors/character/loadout.less'; +@import './actors/character/sheet.less'; +@import './actors/character/sidebar.less'; + +@import './actors/companion/details.less'; +@import './actors/companion/header.less'; +@import './actors/companion/sheet.less'; +@import './actors/companion/effects.less'; + +@import './actors/environment/actions.less'; +@import './actors/environment/header.less'; +@import './actors/environment/potentialAdversaries.less'; +@import './actors/environment/sheet.less'; + +@import './actors/party/header.less'; +@import './actors/party/party-members.less'; +@import './actors/party/sheet.less'; +@import './actors/party/inventory.less'; +@import './actors/party/resources.less'; + +@import './items/beastform.less'; +@import './items/class.less'; +@import './items/domain-card.less'; +@import './items/feature.less'; +@import './items/heritage.less'; +@import './items/item-sheet-shared.less'; + +@import './rollTables/sheet.less'; +@import './actions/actions.less'; diff --git a/styles/less/sheets/items/domain-card.less b/styles/less/sheets/items/domain-card.less index 54378fd0..a784b3a2 100644 --- a/styles/less/sheets/items/domain-card.less +++ b/styles/less/sheets/items/domain-card.less @@ -5,5 +5,7 @@ section.tab { height: 400px; overflow-y: auto; + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; } } diff --git a/styles/less/sheets/items/feature.less b/styles/less/sheets/items/feature.less index f3c7cd49..b7493f15 100644 --- a/styles/less/sheets/items/feature.less +++ b/styles/less/sheets/items/feature.less @@ -14,5 +14,7 @@ section.tab { height: 400px; overflow-y: auto; + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; } } diff --git a/styles/less/sheets/items/index.less b/styles/less/sheets/items/index.less deleted file mode 100644 index 7c40a2e3..00000000 --- a/styles/less/sheets/items/index.less +++ /dev/null @@ -1,6 +0,0 @@ -@import './beastform.less'; -@import './class.less'; -@import './domain-card.less'; -@import './feature.less'; -@import './heritage.less'; -@import './item-sheet-shared.less'; \ No newline at end of file diff --git a/styles/less/sheets/items/item-sheet-shared.less b/styles/less/sheets/items/item-sheet-shared.less index 5155ad70..d0a8cc48 100644 --- a/styles/less/sheets/items/item-sheet-shared.less +++ b/styles/less/sheets/items/item-sheet-shared.less @@ -10,8 +10,4 @@ font-family: @font-body; color: light-dark(@chat-blue-bg, @beige-50); } - - button.plain.inline-control { - flex: 0 0 auto; - } } diff --git a/styles/less/sheets/rollTables/index.less b/styles/less/sheets/rollTables/index.less deleted file mode 100644 index 1c574e81..00000000 --- a/styles/less/sheets/rollTables/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './sheet.less'; \ No newline at end of file diff --git a/styles/less/ui/chat/ability-use.less b/styles/less/ui/chat/ability-use.less index d028fa7a..b590911d 100644 --- a/styles/less/ui/chat/ability-use.less +++ b/styles/less/ui/chat/ability-use.less @@ -6,6 +6,12 @@ #interface.theme-light { .daggerheart.chat.domain-card { .domain-card-move .domain-card-header { + border-bottom: 1px solid @dark-blue; + + &:hover { + background: @dark-blue-10; + } + .domain-label { .title { color: @dark-blue; @@ -23,13 +29,6 @@ } } - &:has(.description) .domain-card-move .domain-card-header { - border-bottom: 1px solid @dark-blue; - &:hover { - background: @dark-blue-10; - } - } - .description { color: @dark; } @@ -44,7 +43,7 @@ .card-img { width: 100%; - height: 180px; + height: 200px; mask-image: linear-gradient(0deg, transparent 0%, black 10%, black 90%, transparent 100%); object-fit: cover; } @@ -69,12 +68,23 @@ flex-direction: row; align-items: center; margin: 8px; + padding-bottom: 5px; + width: -webkit-fill-available; gap: 5px; + border-bottom: 1px solid @golden; + + &:hover { + background: @golden-10; + cursor: pointer; + transition: all 0.3s ease; + } .domain-label { display: flex; flex-direction: column; width: 100%; + padding-bottom: 5px; + width: -webkit-fill-available; gap: 5px; .title { @@ -85,7 +95,7 @@ .tags { display: flex; - gap: 4px; + gap: 10px; flex-wrap: wrap; .tag { @@ -106,16 +116,6 @@ } } - &:has(.description) .domain-card-move .domain-card-header { - border-bottom: 1px solid @golden; - padding-bottom: 5px; - &:hover { - background: @golden-10; - cursor: pointer; - transition: all 0.3s ease; - } - } - .description { padding: 8px; } diff --git a/styles/less/ui/chat/chat.less b/styles/less/ui/chat/chat.less index 4d627e39..e9ef9147 100644 --- a/styles/less/ui/chat/chat.less +++ b/styles/less/ui/chat/chat.less @@ -384,15 +384,6 @@ justify-content: center; width: 15px; } - &.has-minus:before { - content: '-'; - font-size: var(--font-size-20); - grid-area: c; - display: flex; - align-items: center; - justify-content: center; - width: 15px; - } } } @@ -624,14 +615,9 @@ display: flex; gap: 5px; margin-top: 8px; - button { height: 32px; flex: 1; - - &.end-button { - flex: 0; - } } } @@ -703,11 +689,6 @@ } } - .action-roll-buttons { - width: 100%; - padding: 0 8px; - } - .description { padding: 8px; diff --git a/styles/less/ui/chat/group-roll.less b/styles/less/ui/chat/group-roll.less index 98f0cfac..9ed87220 100644 --- a/styles/less/ui/chat/group-roll.less +++ b/styles/less/ui/chat/group-roll.less @@ -31,7 +31,7 @@ } i { - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); } } } @@ -71,7 +71,7 @@ align-items: center; justify-content: center; gap: 10px; - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); .main-value { font-size: var(--font-size-24); @@ -153,7 +153,7 @@ cursor: pointer; padding: 5px; background: light-dark(@dark-blue-10, @golden-10); - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); &.finished { background-color: initial; diff --git a/styles/less/ui/chat/index.less b/styles/less/ui/chat/index.less deleted file mode 100644 index 9cadbd04..00000000 --- a/styles/less/ui/chat/index.less +++ /dev/null @@ -1,10 +0,0 @@ -@import './sheet.less'; -@import './ability-use.less'; -@import './action.less'; -@import './chat.less'; -@import './damage-summary.less'; -@import './deathmoves.less'; -@import './downtime.less'; -@import './effect-summary.less'; -@import './group-roll.less'; -@import './refresh-message.less'; \ No newline at end of file diff --git a/styles/less/ui/chat/sheet.less b/styles/less/ui/chat/sheet.less index bdf22364..66b539b4 100644 --- a/styles/less/ui/chat/sheet.less +++ b/styles/less/ui/chat/sheet.less @@ -93,7 +93,7 @@ } a[href] { - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); } a[href]:hover, @@ -195,7 +195,7 @@ fieldset.daggerheart.chat { &:before, &:after { content: '\f0d8'; - font-family: var(--font-awesome); + font-family: 'Font Awesome 6 Pro'; } } &.expanded { diff --git a/styles/less/ui/combat-sidebar/index.less b/styles/less/ui/combat-sidebar/index.less deleted file mode 100644 index 786815ef..00000000 --- a/styles/less/ui/combat-sidebar/index.less +++ /dev/null @@ -1,5 +0,0 @@ -@import './combat-sidebar.less'; -@import './combatant-controls.less'; -@import './encounter-controls.less'; -@import './spotlight-control.less'; -@import './token-actions.less'; \ No newline at end of file diff --git a/styles/less/ui/countdown/countdown-edit.less b/styles/less/ui/countdown/countdown-edit.less index 78ad3a06..d6c4da93 100644 --- a/styles/less/ui/countdown/countdown-edit.less +++ b/styles/less/ui/countdown/countdown-edit.less @@ -60,6 +60,8 @@ overflow-y: auto; overflow-x: hidden; max-height: 500px; + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; .countdown-edit-outer-container { display: flex; diff --git a/styles/less/ui/countdown/countdown.less b/styles/less/ui/countdown/countdown.less index 63e539ba..47f06eb7 100644 --- a/styles/less/ui/countdown/countdown.less +++ b/styles/less/ui/countdown/countdown.less @@ -1,47 +1,28 @@ @import '../../utils/colors.less'; @import '../../utils/fonts.less'; -#interface.theme-dark { +.theme-dark { .daggerheart.dh-style.countdowns { - --background: url(../assets/parchments/dh-parchment-dark.png); + background-image: url(../assets/parchments/dh-parchment-dark.png); + + .window-header { + background-image: url(../assets/parchments/dh-parchment-dark.png); + } } } -#interface.theme-light { - .daggerheart.dh-style.countdowns { - --background: url('../assets/parchments/dh-parchment-light.png') no-repeat center; - } -} - -.daggerheart.dh-style.countdowns { +.daggerheart.dh-style.countdowns { position: relative; border: 0; + border-radius: 4px; box-shadow: none; - color: @color-text-primary; - width: 18.75rem; + width: 300px; pointer-events: all; align-self: flex-end; transition: 0.3s right ease-in-out; - display: flex; - flex-direction: column; - - &::before { - content: ' '; - position: absolute; - inset: 0; - background: var(--background); - border-radius: 4px; - opacity: var(--ui-fade-opacity); - transition: opacity var(--ui-fade-duration); - } - - &:not(.performance-low, .noblur) { - backdrop-filter: blur(5px); - } - - &:hover::before { - opacity: 1; + .window-title { + font-family: @font-body; } #ui-right:has(#effects-display .effect-container) & { @@ -49,139 +30,127 @@ } &.icon-only { - width: 12rem; + width: 180px; + min-width: 180px; } - .countdowns-header, - .countdowns-container { - position: relative; // allow rendering over the background + .window-header { + cursor: default; + border-bottom: 0; } - .countdowns-header { - display: flex; - align-items: center; - gap: 0.25rem; - flex: 0 0 36px; - padding: 0 0.5rem; - overflow: hidden; - font-size: var(--font-size-13); - .window-title { - font-family: @font-body; - flex: 1; - } - .header-control + .header-control { - margin-left: 8px; - } - } - - .countdowns-container { - display: flex; - flex-direction: column; - gap: 8px; - padding: 4px var(--spacer-16) var(--spacer-16) var(--spacer-16); + .window-content { + padding-top: 4px; + padding-bottom: 16px; overflow: auto; max-height: 312px; - .countdown-container { + .countdowns-container { display: flex; - width: 100%; + flex-direction: column; + gap: 8px; - &.icon-only { - gap: 8px; + .countdown-container { + display: flex; + width: 100%; - .countdown-main-container { - .countdown-content { - justify-content: center; + &.icon-only { + gap: 8px; - .countdown-tools { - gap: 8px; + .countdown-main-container { + .countdown-content { + justify-content: center; + + .countdown-tools { + gap: 8px; + } } } } - } - .countdown-main-container { - width: 100%; - display: flex; - align-items: center; - gap: 16px; - - img { - width: 2.75rem; - height: 2.75rem; - border-radius: 6px; - } - - .countdown-content { - flex: 1; + .countdown-main-container { + width: 100%; display: flex; - flex-direction: column; - justify-content: space-between; + align-items: center; + gap: 16px; - .countdown-tools { + img { + width: 44px; + height: 44px; + border-radius: 6px; + } + + .countdown-content { + flex: 1; display: flex; - align-items: center; + flex-direction: column; justify-content: space-between; - .countdown-tool-controls { + .countdown-tools { display: flex; align-items: center; - gap: var(--spacer-12); - } + justify-content: space-between; - .progress-tag { - border: 1px solid; - border-radius: 4px; - padding: 2px 4px; - background-color: light-dark(@beige, @dark-blue); - } + .countdown-tool-controls { + display: flex; + align-items: center; + gap: 16px; + } - .countdown-tool-icons { - display: flex; - align-items: center; - gap: 8px; - - .looping-container { - position: relative; - border: 1px solid light-dark(@dark-blue, white); - border-radius: 6px; + .progress-tag { + border: 1px solid; + border-radius: 4px; padding: 2px 4px; + background-color: light-dark(@beige, @dark-blue); + } - &.should-loop { - background: light-dark(@golden, @golden); + .countdown-tool-icons { + display: flex; + align-items: center; + gap: 8px; - .loop-marker { - color: light-dark(@dark-blue, @dark-blue); + .looping-container { + position: relative; + border: 1px solid light-dark(@dark-blue, white); + border-radius: 6px; + padding: 2px 4px; + + &.should-loop { + background: light-dark(@golden, @golden); + + .loop-marker { + color: light-dark(@dark-blue, @dark-blue); + } } - } - .direction-marker { - position: absolute; - font-size: 10px; - filter: drop-shadow(0 0 3px black); - top: -3px; + .direction-marker { + position: absolute; + font-size: 10px; + filter: drop-shadow(0 0 3px black); + top: -3px; + } } } } } } - } - /* Keep incase we want to reintroduce the player pips */ - // .countdown-access-container { - // display: grid; - // grid-template-columns: 1fr 1fr 1fr; - // grid-auto-rows: min-content; - // width: 38px; - // gap: 4px; + /* Keep incase we want to reintroduce the player pips */ + // .countdown-access-container { + // display: grid; + // grid-template-columns: 1fr 1fr 1fr; + // grid-auto-rows: min-content; + // width: 38px; + // gap: 4px; - // .countdown-access { - // height: 10px; - // width: 10px; - // border-radius: 50%; - // border: 1px solid light-dark(@dark-blue, @beige-80); - // content: ''; - // } - // } + // .countdown-access { + // height: 10px; + // width: 10px; + // border-radius: 50%; + // border: 1px solid light-dark(@dark-blue, @beige-80); + // content: ''; + // } + // } + } } } } diff --git a/styles/less/ui/countdown/index.less b/styles/less/ui/countdown/index.less deleted file mode 100644 index 45ecda26..00000000 --- a/styles/less/ui/countdown/index.less +++ /dev/null @@ -1,3 +0,0 @@ -@import './sheet.less'; -@import './countdown-edit.less'; -@import './countdown.less'; \ No newline at end of file diff --git a/styles/less/ui/effects-display/index.less b/styles/less/ui/effects-display/index.less deleted file mode 100644 index 1c574e81..00000000 --- a/styles/less/ui/effects-display/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './sheet.less'; \ No newline at end of file diff --git a/styles/less/ui/effects-display/sheet.less b/styles/less/ui/effects-display/sheet.less index 80ad0d65..1331b094 100644 --- a/styles/less/ui/effects-display/sheet.less +++ b/styles/less/ui/effects-display/sheet.less @@ -20,7 +20,7 @@ .effect-container { position: relative; pointer-events: all; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 3px; img { @@ -35,21 +35,6 @@ color: @golden; filter: drop-shadow(0 0 3px black); } - - .stacking-value { - position: absolute; - top: 4px; - right: 4px; - font-size: 16px; - font-weight: bold; - font-variant-numeric: tabular-nums; - color: @golden; - background: black; - padding: 1px; - border-radius: 6px; - border: 1px solid @golden; - pointer-events: none; - } } } } diff --git a/styles/less/ui/index.less b/styles/less/ui/index.less index 53a71b9b..31ea8955 100644 --- a/styles/less/ui/index.less +++ b/styles/less/ui/index.less @@ -1,11 +1,40 @@ -@import './chat/index.less'; -@import './combat-sidebar/index.less'; -@import './countdown/index.less'; -@import './effects-display/index.less'; -@import './item-browser/index.less'; -@import './ownership-selection/index.less'; -@import './resources/index.less'; -@import './scene-config/index.less'; -@import './scene-navigation/index.less'; -@import './settings/index.less'; -@import './sidebar/index.less'; \ No newline at end of file +@import './chat/ability-use.less'; +@import './chat/action.less'; +@import './chat/chat.less'; +@import './chat/damage-summary.less'; +@import './chat/downtime.less'; +@import './chat/effect-summary.less'; +@import './chat/group-roll.less'; +@import './chat/refresh-message.less'; +@import './chat/deathmoves.less'; +@import './chat/sheet.less'; + +@import './combat-sidebar/combat-sidebar.less'; +@import './combat-sidebar/combatant-controls.less'; +@import './combat-sidebar/encounter-controls.less'; +@import './combat-sidebar/spotlight-control.less'; +@import './combat-sidebar/token-actions.less'; +@import './item-browser/item-browser.less'; + +@import './countdown/countdown.less'; +@import './countdown/countdown-edit.less'; +@import './countdown/sheet.less'; + +@import './ownership-selection/ownership-selection.less'; + +@import './resources/resources.less'; + +@import './settings/settings.less'; +@import './settings/homebrew-settings/domains.less'; +@import './settings/homebrew-settings/types.less'; +@import './settings/homebrew-settings/resources.less'; +@import './settings/appearance-settings/diceSoNice.less'; + +@import './sidebar/tabs.less'; +@import './sidebar/daggerheartMenu.less'; + +@import './scene-config/scene-config.less'; + +@import './effects-display/sheet.less'; + +@import './scene-navigation/scene-navigation.less'; diff --git a/styles/less/ui/item-browser/index.less b/styles/less/ui/item-browser/index.less deleted file mode 100644 index 842f716b..00000000 --- a/styles/less/ui/item-browser/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './item-browser.less'; \ No newline at end of file diff --git a/styles/less/ui/item-browser/item-browser.less b/styles/less/ui/item-browser/item-browser.less index aac63d7a..f558a0ba 100644 --- a/styles/less/ui/item-browser/item-browser.less +++ b/styles/less/ui/item-browser/item-browser.less @@ -1,6 +1,5 @@ @import '../../utils/colors.less'; @import '../../utils/fonts.less'; -@import '../../utils/mixin.less'; .application.daggerheart.dh-style.compendium-browser { border: initial; @@ -126,7 +125,6 @@ .form-group { white-space: nowrap; - gap: 0; } .filter-header { @@ -170,10 +168,6 @@ } } } - - .filter-content { - margin-top: 8px; - } } .folder-list { @@ -201,7 +195,7 @@ font-weight: bold; border-radius: 3px; background-color: light-dark(@dark-blue-40, @golden-40); - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); } .subfolder-list { @@ -219,7 +213,7 @@ font-weight: bold; border-radius: 3px; background-color: light-dark(@dark-blue-10, @golden-10); - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); } .wrapper { @@ -243,11 +237,12 @@ .compendium-sidebar > .folder-list { overflow-y: auto; scrollbar-gutter: stable; - .with-scroll-shadows(); + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; } .item-list-header, - .item-list .item-info[data-action] { + .item-list [data-action='expandContent'] { display: flex; > * { @@ -267,8 +262,8 @@ .item-list-header { align-items: center; background-color: light-dark(@dark-15, @dark-golden-80); - color: @color-text-emphatic; - border: 1px solid @color-border; + color: light-dark(@dark-blue, @golden); + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 3px; min-height: 30px; font-weight: bold; @@ -279,7 +274,7 @@ div[data-sort-key] { &:after { - font-family: var(--font-awesome); + font-family: 'Font Awesome 6 Pro'; margin-left: 5px; } diff --git a/styles/less/ui/ownership-selection/index.less b/styles/less/ui/ownership-selection/index.less deleted file mode 100644 index 9646670a..00000000 --- a/styles/less/ui/ownership-selection/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './ownership-selection.less'; \ No newline at end of file diff --git a/styles/less/ui/resources/index.less b/styles/less/ui/resources/index.less deleted file mode 100644 index a7d08785..00000000 --- a/styles/less/ui/resources/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './resources.less'; \ No newline at end of file diff --git a/styles/less/ui/scene-config/index.less b/styles/less/ui/scene-config/index.less deleted file mode 100644 index 4e3af363..00000000 --- a/styles/less/ui/scene-config/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './scene-config.less'; \ No newline at end of file diff --git a/styles/less/ui/scene-config/scene-config.less b/styles/less/ui/scene-config/scene-config.less index ba1afb0b..664e7526 100644 --- a/styles/less/ui/scene-config/scene-config.less +++ b/styles/less/ui/scene-config/scene-config.less @@ -13,8 +13,6 @@ .application.sheet.scene-config { .sheet-tabs.tabs { - font-size: 12px; - a[data-tab='dh'] { display: flex; align-items: center; diff --git a/styles/less/ui/scene-navigation/index.less b/styles/less/ui/scene-navigation/index.less deleted file mode 100644 index c0765ae7..00000000 --- a/styles/less/ui/scene-navigation/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './scene-navigation.less'; \ No newline at end of file diff --git a/styles/less/ui/settings/appearance-settings/diceSoNice.less b/styles/less/ui/settings/appearance-settings/diceSoNice.less index a4846596..079bebc5 100644 --- a/styles/less/ui/settings/appearance-settings/diceSoNice.less +++ b/styles/less/ui/settings/appearance-settings/diceSoNice.less @@ -68,29 +68,5 @@ text-align: center; white-space: nowrap; } - - color-picker { - gap: 4px; - background: inherit; - } - } - - .animation-container { - display: flex; - align-items: center; - justify-content: space-between; - - .animation-inner-container { - display: flex; - align-items: center; - justify-content: right; - gap: 8px; - - .animation-control { - display: flex; - align-items: center; - gap: 2px; - } - } } } diff --git a/styles/less/ui/settings/appearance-settings/index.less b/styles/less/ui/settings/appearance-settings/index.less deleted file mode 100644 index 8b1c109a..00000000 --- a/styles/less/ui/settings/appearance-settings/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './diceSoNice.less'; \ No newline at end of file diff --git a/styles/less/ui/settings/homebrew-settings/domains.less b/styles/less/ui/settings/homebrew-settings/domains.less index 6314cc66..da258fcd 100644 --- a/styles/less/ui/settings/homebrew-settings/domains.less +++ b/styles/less/ui/settings/homebrew-settings/domains.less @@ -55,12 +55,14 @@ gap: 8px; max-height: 184px; overflow: auto; + scrollbar-width: thin; + scrollbar-color: light-dark(#18162e, #f3c267) transparent; .domain-container { position: relative; display: flex; justify-content: center; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; &.selectable { @@ -76,7 +78,7 @@ .domain-label { position: absolute; top: 4px; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; padding: 0 2px; color: light-dark(@dark, @beige); diff --git a/styles/less/ui/settings/homebrew-settings/index.less b/styles/less/ui/settings/homebrew-settings/index.less deleted file mode 100644 index f0a8bfc1..00000000 --- a/styles/less/ui/settings/homebrew-settings/index.less +++ /dev/null @@ -1,3 +0,0 @@ -@import './domains.less'; -@import './resources.less'; -@import './types.less'; \ No newline at end of file diff --git a/styles/less/ui/settings/homebrew-settings/resources.less b/styles/less/ui/settings/homebrew-settings/resources.less index 9d562756..5333e54d 100644 --- a/styles/less/ui/settings/homebrew-settings/resources.less +++ b/styles/less/ui/settings/homebrew-settings/resources.less @@ -24,7 +24,7 @@ .resource-icons-container { display: flex; justify-content: space-between; - gap: 10px; + gap: 8px; width: 100%; .resource-icon-container { @@ -61,7 +61,7 @@ display: flex; align-items: center; gap: 4px; - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); i { font-size: 14px; diff --git a/styles/less/ui/settings/homebrew-settings/types.less b/styles/less/ui/settings/homebrew-settings/types.less index 1d568853..d09431f7 100644 --- a/styles/less/ui/settings/homebrew-settings/types.less +++ b/styles/less/ui/settings/homebrew-settings/types.less @@ -21,7 +21,7 @@ border: 1px solid; border-radius: 6px; padding: 0 8px; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); color: light-dark(@dark, @beige); background-image: url('../assets/parchments/dh-parchment-dark.png'); cursor: pointer; diff --git a/styles/less/ui/settings/index.less b/styles/less/ui/settings/index.less deleted file mode 100644 index 4e1aa798..00000000 --- a/styles/less/ui/settings/index.less +++ /dev/null @@ -1,3 +0,0 @@ -@import './settings.less'; -@import './appearance-settings/index.less'; -@import './homebrew-settings/index.less'; \ No newline at end of file diff --git a/styles/less/ui/settings/settings.less b/styles/less/ui/settings/settings.less index 35c48480..34f17d53 100644 --- a/styles/less/ui/settings/settings.less +++ b/styles/less/ui/settings/settings.less @@ -1,67 +1,6 @@ @import '../../utils/colors.less'; .daggerheart.dh-style.setting { - --color-form-label: @color-text-primary; - - h2, - h3, - h4 { - margin: 8px 0 4px; - text-align: center; - } - - footer { - margin-top: 8px; - display: flex; - gap: 8px; - - button { - flex: 1; - } - } - - .standard-form { - gap: var(--spacer-8); - .form-group .form-fields { - width: unset; - } - } - - .form-group { - display: flex; - justify-content: space-between; - align-items: center; - gap: 0.25rem 0.5rem; - flex-wrap: wrap; - - label { - font-size: var(--font-size-14); - font-weight: normal; - line-height: var(--input-height); - } - - .form-fields { - display: flex; - gap: 4px; - align-items: center; - } - - &.setting-two-values { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 0.25rem 0.5rem; - - .form-group { - justify-content: end; - flex-wrap: nowrap; - } - - .hint { - grid-column: 1 / -1; - } - } - } - fieldset { display: flex; flex-direction: column; @@ -80,10 +19,7 @@ &.three-columns { display: grid; grid-template-columns: 1fr 1fr 1fr; - gap: 4px; - .form-group label { - line-height: unset; - } + gap: 2px; } &.six-columns { diff --git a/styles/less/ui/sidebar/daggerheartMenu.less b/styles/less/ui/sidebar/daggerheartMenu.less index 280d5ad3..677214d7 100644 --- a/styles/less/ui/sidebar/daggerheartMenu.less +++ b/styles/less/ui/sidebar/daggerheartMenu.less @@ -15,17 +15,17 @@ font-weight: bold; } - .menu-options-container { + .menu-refresh-container { display: flex; flex-direction: column; gap: 8px; - .menu-options-inner-container { + .menu-refresh-inner-container { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; - .option-chip { + .experience-chip { display: flex; align-items: center; border-radius: 5px; @@ -34,7 +34,7 @@ cursor: pointer; padding: 5px; background: light-dark(@dark-blue-10, @golden-10); - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); .label { font-style: normal; diff --git a/styles/less/ui/sidebar/index.less b/styles/less/ui/sidebar/index.less deleted file mode 100644 index b4961b41..00000000 --- a/styles/less/ui/sidebar/index.less +++ /dev/null @@ -1,2 +0,0 @@ -@import './daggerheartMenu.less'; -@import './tabs.less'; \ No newline at end of file diff --git a/styles/less/utils/colors.less b/styles/less/utils/colors.less index bb219ebb..8f6418bf 100755 --- a/styles/less/utils/colors.less +++ b/styles/less/utils/colors.less @@ -5,7 +5,6 @@ --golden: #f3c267; --golden-10: #f3c26710; --golden-40: #f3c26740; - --golden-60: #f3c26760; --golden-90: #f3c26790; --golden-bg: #f3c2671a; --golden-secondary: #eaaf42; @@ -51,7 +50,6 @@ --dark-blue-50: #18162e50; --dark-blue-60: #18162e60; --dark-blue-90: #18162e90; - --dark-blue-c0: #18162ec0; --semi-transparent-dark-blue: rgba(24, 22, 46, 0.33); --dark: #222222; @@ -71,7 +69,6 @@ --beige-filter: brightness(0) saturate(100%) invert(87%) sepia(25%) saturate(164%) hue-rotate(339deg) brightness(106%) contrast(87%); --bright-beige-filter: brightness(0) saturate(100%) invert(87%) sepia(15%) saturate(343%) hue-rotate(333deg) brightness(110%) contrast(87%); - --light-white: rgba(255, 255, 255, 0.3); --soft-white-shadow: rgba(255, 255, 255, 0.05); --light-black: rgba(0, 0, 0, 0.3); @@ -86,54 +83,12 @@ --primary-color-fear: rgba(9, 71, 179, 0.75); } -/** - * Override core foundry color variables in theme scopes, and add some new theme specific variants. - * These are intended to be more representative of its use case, so avoid naming these after the color. - * Some foundry variables are heavily scoped and we need to redefine them (https://github.com/foundryvtt/foundryvtt/issues/12893) - * Convention for the redefined ones is --dh-{element}-color-{thing} - */ -@scope (.theme-light) to (.themed) { - .dh-style :scope, - :scope.dh-style, - .dh-style, - .duality { - --color-border: @dark-blue; - --color-fieldset-border: @dark-blue; - --color-text-emphatic: @dark-blue; - --color-text-subtle: #555; - - --dh-color-text-shadow-contrast: #ffffffa0; - --dh-input-color-border: @dark; - --dh-input-color-text: @dark; - --dh-trait-color-bg: #b1afb6; - --dh-trait-color-border: #8e8d96; - } -} -@scope (.theme-dark) to (.themed) { - .dh-style :scope, - :scope.dh-style, - .dh-style, - .duality { - --color-border: @golden; - --color-fieldset-border: @golden; - --color-text-emphatic: @golden; - --color-text-subtle: #a29086; - - --dh-color-text-shadow-contrast: @dark-80; - --dh-input-color-border: @beige; - --dh-input-color-text: @beige; - --dh-trait-color-bg: #50433F; - --dh-trait-color-border: #927952; - } -} - @primary-blue: var(--primary-blue, #1488cc); @secondary-blue: var(--secondary-blue, #2b32b2); @golden: var(--golden, #f3c267); @golden-10: var(--golden-10, #f3c26710); @golden-40: var(--golden-40, #f3c26740); -@golden-60: var(--golden-60, #f3c26760); @golden-90: var(--golden-90, #f3c26790); @golden-bg: var(--golden-bg, #f3c2671a); @golden-secondary: var(--golden-secondary, #eaaf42); @@ -179,7 +134,6 @@ @dark-blue-50: var(--dark-blue-50, #18162e50); @dark-blue-60: var(--dark-blue-60, #18162e60); @dark-blue-90: var(--dark-blue-90, #18162e90); -@dark-blue-c0: var(--dark-blue-c0, #18162ec0); @semi-transparent-dark-blue: var(--semi-transparent-dark-blue, rgba(24, 22, 46, 0.33)); @dark: var(--dark, #222222); @@ -201,7 +155,6 @@ @soft-white-shadow: var(--soft-white-shadow, rgba(255, 255, 255, 0.05)); -@light-white: var(--light-white, rgba(255, 255, 255, 0.3)); @light-black: var(--light-black, rgba(0, 0, 0, 0.3)); @soft-shadow: var(--soft-shadow, rgba(0, 0, 0, 0.05)); @@ -233,15 +186,3 @@ box-shadow: 0 0 2px 2px @dark-blue; } } - -// LESS variable versions of core foundry color variables -@color-border: var(--color-border); -@color-fieldset-border: var(--color-fieldset-border); -@color-text-emphatic: var(--color-text-emphatic); -@color-text-primary: var(--color-text-primary); -@color-text-subtle: var(--color-text-subtle); -@color-text-shadow-contrast: var(--dh-color-text-shadow-contrast); -@input-color-border: var(--dh-input-color-border); -@input-color-text: var(--dh-input-color-text); -@trait-color-bg: var(--dh-trait-color-bg); -@trait-color-border: var(--dh-trait-color-border); \ No newline at end of file diff --git a/styles/less/utils/fonts.less b/styles/less/utils/fonts.less index 201ea356..5c1e597a 100755 --- a/styles/less/utils/fonts.less +++ b/styles/less/utils/fonts.less @@ -5,11 +5,6 @@ --dh-font-title: 'Cinzel Decorative'; --dh-font-subtitle: 'Cinzel'; --dh-font-body: 'Montserrat'; - - /* Include missing font sizes */ - --font-size-8: 0.5rem; - --font-size-9: 0.5625rem; - --font-size-22: 1.375rem; } @font-title: ~"var(--dh-font-title, 'Cinzel Decorative'), serif"; diff --git a/styles/less/utils/index.less b/styles/less/utils/index.less deleted file mode 100644 index 37b096d3..00000000 --- a/styles/less/utils/index.less +++ /dev/null @@ -1,4 +0,0 @@ -@import './colors.less'; -@import './fonts.less'; -@import './mixin.less'; -@import './spacing.less'; \ No newline at end of file diff --git a/styles/less/utils/mixin.less b/styles/less/utils/mixin.less index 18b1f9a6..49e97a1f 100644 --- a/styles/less/utils/mixin.less +++ b/styles/less/utils/mixin.less @@ -5,16 +5,16 @@ */ .appTheme(@darkRules, @lightRules) { // Dark theme selectors - .themed.theme-dark .application.daggerheart.dh-style, - .themed.theme-dark.application.daggerheart.dh-style, + .themed.theme-dark .application.daggerheart.sheet.dh-style, + .themed.theme-dark.application.daggerheart.sheet.dh-style, body.theme-dark .application.daggerheart, body.theme-dark.application.daggerheart { @darkRules(); } // Light theme selectors - .themed.theme-light .application.daggerheart.dh-style, - .themed.theme-light.application.daggerheart.dh-style, + .themed.theme-light .application.daggerheart.sheet.dh-style, + .themed.theme-light.application.daggerheart.sheet.dh-style, body.theme-light .application.daggerheart, body.theme-light.application.daggerheart { @lightRules(); @@ -50,15 +50,14 @@ */ .dh-typography() { h1 { - --dh-input-color-text: @color-text-emphatic; font-family: @font-title; margin: 0; border: none; font-weight: normal; - input[type='text'], - .input[contenteditable] { - font-family: @font-title; - } + } + + h1 input[type='text'] { + font-family: @font-title; } h2, @@ -115,92 +114,3 @@ font-family: @font-body; } } - - -// A simple ease-out mask -.smooth-gradient-ease-out(@param, @to, @destination, @length) { - @{param}+: linear-gradient( - @to, - transparent 0%, - rgb(from @destination r g b / ~"calc(alpha * 0.013)") calc(0.008 * @length), - rgb(from @destination r g b / ~"calc(alpha * 0.049)") calc(0.029 * @length), - rgb(from @destination r g b / ~"calc(alpha * 0.104)") calc(0.064 * @length), - rgb(from @destination r g b / ~"calc(alpha * 0.259)") calc(0.166 * @length), - rgb(from @destination r g b / ~"calc(alpha * 0.45)") calc(0.304 * @length), - rgb(from @destination r g b / ~"calc(alpha * 0.741)") calc(0.554 * @length), - rgb(from @destination r g b / ~"calc(alpha * 0.825)") calc(0.644 * @length), - rgb(from @destination r g b / ~"calc(alpha * 0.896)") calc(0.735 * @length), - rgb(from @destination r g b / ~"calc(alpha * 0.951)") calc(0.825 * @length), - rgb(from @destination r g b / ~"calc(alpha * 0.987)") calc(0.914 * @length), - @destination @length - ); -} - -/** - * A simple ease in and out mask. - * @param - the parameter to add to - * @param - direction, such as "to top" - * @destination - the color at the destination. The origin is always transparent - * @length - the value at the destination - */ -.smooth-gradient-ease-in-out(@param, @to, @destination, @length: 100%) { - @{param}+: linear-gradient( - @to, - transparent 0%, - rgb(from @destination r g b / ~"calc(alpha * 0.013)") calc(0.081 * @length), - rgb(from @destination r g b / ~"calc(alpha * 0.049)") calc(0.155 * @length), - rgb(from @destination r g b / ~"calc(alpha * 0.104)") calc(0.225 * @length), - rgb(from @destination r g b / ~"calc(alpha * 0.259)") calc(0.353 * @length), - rgb(from @destination r g b / ~"calc(alpha * 0.45)") calc(0.471 * @length), - rgb(from @destination r g b / ~"calc(alpha * 0.741)") calc(0.647 * @length), - rgb(from @destination r g b / ~"calc(alpha * 0.825)") calc(0.71 * @length), - rgb(from @destination r g b / ~"calc(alpha * 0.896)") calc(0.775 * @length), - rgb(from @destination r g b / ~"calc(alpha * 0.951)") calc(0.845 * @length), - rgb(from @destination r g b / ~"calc(alpha * 0.987)") calc(0.914 * @length), - @destination @length - ); -} - -// Scroll shadows, but only if the browser supports. At the time of writing, this doesn't work on firefox -@supports ((animation-timeline: scroll()) and (animation-range: 0% 100%)) { - @property --fade-start { - syntax: ""; - inherits: false; - initial-value: 0; - } - - @property --fade-end { - syntax: ""; - inherits: false; - initial-value: 0; - } - - @keyframes scrollfade { - 0% { - --fade-start: 0; - } - 10%, 100% { - --fade-start: 12px; - } - 0%, 90% { - --fade-end: 12px; - } - 100% { - --fade-end: 0; - } - } -} - -.with-scroll-shadows() { - animation: scrollfade; - animation-timeline: --scrollfade; - animation-range: entry 0% exit 100%; - scroll-timeline: --scrollfade y; - mask-image: linear-gradient( - 0deg, - transparent 0%, - black var(--fade-end), - black calc(100% - var(--fade-start)), - transparent 100% - ); -} diff --git a/styles/less/ux/autocomplete/autocomplete.less b/styles/less/ux/autocomplete/autocomplete.less index e778f0da..7f799449 100644 --- a/styles/less/ux/autocomplete/autocomplete.less +++ b/styles/less/ux/autocomplete/autocomplete.less @@ -21,6 +21,8 @@ flex-direction: column; gap: 2px; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; + .group { font-weight: bold; font-size: var(--font-size-14); diff --git a/styles/less/ux/autocomplete/index.less b/styles/less/ux/autocomplete/index.less deleted file mode 100644 index 91007146..00000000 --- a/styles/less/ux/autocomplete/index.less +++ /dev/null @@ -1 +0,0 @@ -@import './autocomplete.less'; \ No newline at end of file diff --git a/styles/less/ux/index.less b/styles/less/ux/index.less index b6c9a2e7..c6c40f78 100644 --- a/styles/less/ux/index.less +++ b/styles/less/ux/index.less @@ -1,2 +1,8 @@ -@import './autocomplete/index.less'; -@import './tooltip/index.less'; \ No newline at end of file +@import './tooltip/tooltip.less'; +@import './tooltip/battlepoints.less'; +@import './tooltip/bordered-tooltip.less'; +@import './tooltip/domain-cards.less'; + +@import './autocomplete/autocomplete.less'; + +@import './tooltip/resource-management.less'; diff --git a/styles/less/ux/tooltip/armorManagement.less b/styles/less/ux/tooltip/armorManagement.less deleted file mode 100644 index 497df4f5..00000000 --- a/styles/less/ux/tooltip/armorManagement.less +++ /dev/null @@ -1,141 +0,0 @@ -@import '../../utils/fonts.less'; -@import '../../utils/colors.less'; - -.bordered-tooltip.locked-tooltip .daggerheart.armor-management-container { - display: flex; - flex-direction: column; - gap: 10px; - padding-bottom: 10px; - - h3 { - font-family: @font-subtitle; - margin: 0; - border: none; - font-weight: normal; - font-size: var(--font-size-20); - } - - .armor-source-container { - display: flex; - flex-direction: column; - align-items: center; - gap: 4px; - - .armor-source-label { - font-family: @font-body; - margin: 0; - } - - .status-bar { - display: flex; - justify-content: center; - position: relative; - width: 100%; - height: 30px; - - .status-value { - position: absolute; - display: flex; - padding: 0 5px; - font-size: 1rem; - align-items: center; - width: 100%; - height: 30px; - justify-content: center; - text-align: center; - z-index: 2; - color: @beige; - - input[type='number'] { - background: transparent; - font-size: 1.2rem; - width: 30px; - text-align: center; - border: none; - outline: 2px solid transparent; - color: @beige; - font-family: @font-body; - - &.bar-input { - padding: 0; - color: @beige; - backdrop-filter: none; - background: transparent; - transition: all 0.3s ease; - height: 25px; - - &:hover, - &:focus { - background: @semi-transparent-dark-blue; - backdrop-filter: blur(9.5px); - } - } - } - - .bar-label { - font-family: @font-body; - width: 40px; - font-size: 1.2rem; - } - } - .progress-bar { - position: absolute; - appearance: none; - width: 100%; - height: 30px; - border: 1px solid @color-border; - border-radius: 6px; - z-index: 1; - background: @dark-blue; - - &::-webkit-progress-bar { - border: none; - background: @dark-blue; - border-radius: 6px; - } - &::-webkit-progress-value { - background: @gradient-hp; - border-radius: 6px; - } - &.stress-color::-webkit-progress-value { - background: @gradient-stress; - border-radius: 6px; - } - &::-moz-progress-bar { - background: @gradient-hp; - border-radius: 6px; - } - &.stress-color::-moz-progress-bar { - background: @gradient-stress; - border-radius: 6px; - } - } - } - } - - .slot-bar { - display: flex; - flex-wrap: wrap; - gap: 4px; - padding: 5px; - border: 1px solid @color-border; - border-radius: 6px; - z-index: 1; - background: @dark-blue; - align-items: center; - justify-content: center; - color: @color-text-emphatic; - min-height: 30px; - width: 100%; - - .armor-slot { - cursor: pointer; - transition: all 0.3s ease; - font-size: var(--font-size-12); - - .fa-shield-halved { - color: light-dark(@dark-blue-40, @golden-40); - } - } - } -} diff --git a/styles/less/ux/tooltip/bordered-tooltip.less b/styles/less/ux/tooltip/bordered-tooltip.less index d72f635e..78622377 100644 --- a/styles/less/ux/tooltip/bordered-tooltip.less +++ b/styles/less/ux/tooltip/bordered-tooltip.less @@ -6,7 +6,6 @@ .daggerheart.dh-style.tooltip { display: flex; flex-direction: column; - align-items: start; text-align: start; width: 100%; gap: 5px; @@ -14,11 +13,10 @@ border-radius: 3px; .tooltip-header { - width: 100%; display: flex; flex-direction: column; align-items: center; - text-align: center; + text-align: start; padding: 5px; gap: 0px; @@ -37,80 +35,12 @@ } } - .effect-stacks-outer-container { - display: flex; - flex-direction: column; - gap: 4px; - width: 100%; - - .effect-stacks-title { - font-size: var(--font-size-20); - font-weight: bold; - text-align: center; - } - - .effect-stacks-container { - display: flex; - justify-content: space-between; - - .effect-stacks-inner-container { - display: flex; - flex-direction: column; - gap: 2px; - - .effect-stack-title { - font-weight: bold; - } - } - } - } - - .close-hints { - margin-top: 0.5rem; - display: flex; - flex-direction: column; - gap: 4px; - - .close-hint { - border-radius: 3px; - padding: 3px; - background: @rustic-brown-80; - color: @golden; - font-size: 12px; - margin: 0; - } - } - - .duration-container { - display: flex; - flex-direction: column; - text-align: center; - margin-top: 0.5rem; - width: 100%; - - &::before, - &::after { - content: ''; - background: var(--golden, #f3c267); - mask-image: linear-gradient(270deg, transparent 0%, black 50%, transparent 100%); - height: 2px; - width: calc(100% - 10px); - } - - &::before { - margin-bottom: 8px; - } - - &::after { - margin-top: 8px; - } - - .duration-inner-container { - display: flex; - justify-content: center; - gap: 2px; - width: 100%; - } + .close-hint { + border-radius: 3px; + padding: 3px; + background: @rustic-brown-80; + color: @golden; + font-size: 12px; } } } diff --git a/styles/less/ux/tooltip/index.less b/styles/less/ux/tooltip/index.less deleted file mode 100644 index eeec9354..00000000 --- a/styles/less/ux/tooltip/index.less +++ /dev/null @@ -1,7 +0,0 @@ -@import './sheet.less'; -@import './armorManagement.less'; -@import './battlepoints.less'; -@import './bordered-tooltip.less'; -@import './domain-cards.less'; -@import './resource-management.less'; -@import './tooltip.less'; \ No newline at end of file diff --git a/styles/less/ux/tooltip/resource-management.less b/styles/less/ux/tooltip/resource-management.less index 6e7e7851..ff1f4dd2 100644 --- a/styles/less/ux/tooltip/resource-management.less +++ b/styles/less/ux/tooltip/resource-management.less @@ -9,9 +9,9 @@ display: flex; gap: 10px; background-color: light-dark(transparent, @dark-blue); - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); padding: 5px 10px; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; align-items: center; width: fit-content; @@ -22,7 +22,7 @@ font-size: var(--font-size-14); font-weight: bold; text-transform: uppercase; - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); margin: 0; } diff --git a/styles/less/ux/tooltip/sheet.less b/styles/less/ux/tooltip/sheet.less deleted file mode 100644 index cc4166da..00000000 --- a/styles/less/ux/tooltip/sheet.less +++ /dev/null @@ -1,126 +0,0 @@ -#tooltip:has(div.daggerheart.dh-style.tooltip.card-style), -aside[role='tooltip']:has(div.daggerheart.dh-style.tooltip), -#tooltip.bordered-tooltip { - .tooltip-title { - font-size: var(--font-size-20); - color: @color-text-emphatic; - font-weight: 700; - } - - .tooltip-description { - font-style: inherit; - text-align: inherit; - width: 100%; - padding: 5px 10px; - position: relative; - margin-top: 5px; - - &::before { - content: ''; - background: @golden; - mask-image: linear-gradient(270deg, transparent 0%, black 50%, transparent 100%); - height: 2px; - width: calc(100% - 10px); - } - - &::before { - position: absolute; - top: -5px; - } - } - - .tooltip-separator { - background: @golden; - mask-image: linear-gradient(270deg, transparent 0%, black 50%, transparent 100%); - height: 2px; - width: calc(100% - 10px); - margin-bottom: 2px; - } - - .tooltip-tags { - display: flex; - flex-direction: column; - gap: 10px; - width: 100%; - padding: 5px 10px; - position: relative; - max-height: 150px; - overflow-y: auto; - position: relative; - - .tooltip-tag { - display: flex; - gap: 10px; - flex-direction: column; - - .tooltip-tag-label-container { - display: flex; - align-items: center; - gap: 5px; - - img { - width: 40px; - height: 40px; - border-radius: 3px; - } - } - } - } - - .tags { - display: flex; - gap: 5px 10px; - padding-bottom: 16px; - flex-wrap: wrap; - justify-content: center; - - &.advantages { - width: 100%; - padding: 5px 10px; - padding-bottom: 16px; - position: relative; - margin-top: 5px; - - &::before { - content: ''; - background: @golden; - mask-image: linear-gradient(270deg, transparent 0%, black 50%, transparent 100%); - height: 2px; - width: calc(100% - 10px); - } - - &::before { - position: absolute; - top: -5px; - } - - .tag { - background: @green-10; - color: @green; - border-color: @green; - } - } - - .tag { - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - padding: 3px 5px; - font-size: var(--font-size-12); - font: @font-body; - - background: light-dark(@dark-15, @beige-15); - border: 1px solid light-dark(@dark, @beige); - border-radius: 3px; - } - - .label { - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - font-size: var(--font-size-12); - } - } -} diff --git a/styles/less/ux/tooltip/tooltip.less b/styles/less/ux/tooltip/tooltip.less index f02499e2..8e6f638d 100644 --- a/styles/less/ux/tooltip/tooltip.less +++ b/styles/less/ux/tooltip/tooltip.less @@ -13,6 +13,13 @@ aside[role='tooltip']:has(div.daggerheart.dh-style.tooltip.card-style) { outline: 1px solid light-dark(@dark-80, @beige-80); box-shadow: 0 0 25px rgba(0, 0, 0, 0.8); + .tooltip-title { + font-size: var(--font-size-20); + color: light-dark(@dark-blue, @golden); + font-weight: 700; + margin-bottom: 5px; + } + .tooltip-subtitle { margin: 0; } @@ -46,13 +53,20 @@ aside[role='tooltip']:has(div.daggerheart.dh-style.tooltip.card-style) { } } - .tooltip-duration { - font-style: italic; - text-align: start; - position: relative; + .tooltip-tags { + display: flex; + flex-direction: column; + gap: 10px; width: 100%; padding: 5px 10px; - margin: 5px 0px; + position: relative; + padding-top: 10px; + max-height: 150px; + overflow-y: auto; + position: relative; + + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; &::before { content: ''; @@ -60,16 +74,86 @@ aside[role='tooltip']:has(div.daggerheart.dh-style.tooltip.card-style) { mask-image: linear-gradient(270deg, transparent 0%, black 50%, transparent 100%); height: 2px; width: calc(100% - 10px); - position: absolute; - top: -5px; - font-size: 14px; } - .duration-inner-container { + &::before { + position: absolute; + top: 0px; + } + + .tooltip-tag { display: flex; - justify-content: center; - gap: 2px; + gap: 10px; + flex-direction: column; + + .tooltip-tag-label-container { + display: flex; + align-items: center; + gap: 5px; + + img { + width: 40px; + height: 40px; + border-radius: 3px; + } + } + } + } + + .tags { + display: flex; + gap: 5px 10px; + padding-bottom: 16px; + flex-wrap: wrap; + justify-content: center; + + &.advantages { width: 100%; + padding: 5px 10px; + padding-bottom: 16px; + position: relative; + margin-top: 5px; + + &::before { + content: ''; + background: @golden; + mask-image: linear-gradient(270deg, transparent 0%, black 50%, transparent 100%); + height: 2px; + width: calc(100% - 10px); + } + + &::before { + position: absolute; + top: -5px; + } + + .tag { + background: @green-10; + color: @green; + border-color: @green; + } + } + + .tag { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + padding: 3px 5px; + font-size: var(--font-size-12); + font: @font-body; + + background: light-dark(@dark-15, @beige-15); + border: 1px solid light-dark(@dark, @beige); + border-radius: 3px; + } + + .label { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + font-size: var(--font-size-12); } } @@ -132,7 +216,7 @@ aside[role='tooltip']:has(div.daggerheart.dh-style.tooltip.card-style) { border-radius: 3px; padding: 3px; background: light-dark(@dark-blue-60, @rustic-brown-80); - color: @color-text-emphatic; + color: light-dark(@dark-blue, @golden); font-size: 12px; margin-bottom: 10px; } @@ -238,7 +322,7 @@ aside[role='tooltip'].locked-tooltip:has(div.daggerheart.dh-style.tooltip.card-s .tooltip-chip { font-size: var(--font-size-18); padding: 2px 4px; - border: 1px solid @color-border; + border: 1px solid light-dark(@dark-blue, @golden); border-radius: 6px; color: light-dark(@dark, @beige); background-image: url(../assets/parchments/dh-parchment-dark.png); diff --git a/system.json b/system.json index ed14a17b..a5ec4af1 100644 --- a/system.json +++ b/system.json @@ -2,24 +2,19 @@ "id": "daggerheart", "title": "Daggerheart", "description": "An unofficial implementation of the Daggerheart system", - "version": "2.3.2", + "version": "1.9.12", "compatibility": { - "minimum": "14.361", - "verified": "14.363", - "maximum": "14" + "minimum": "13.346", + "verified": "13.351", + "maximum": "13" }, "url": "https://github.com/Foundryborne/daggerheart", - "manifest": "https://raw.githubusercontent.com/Foundryborne/daggerheart/v14/system.json", - "download": "https://github.com/Foundryborne/daggerheart/releases/download/2.3.2/system.zip", + "manifest": "https://raw.githubusercontent.com/Foundryborne/daggerheart/V13/system.json", + "download": "https://github.com/Foundryborne/daggerheart/releases/download/1.9.12/system.zip", "authors": [ { "name": "WBHarry" }, - { - "name": "Supe", - "url": "https://github.com/CarlosFdez", - "discord": "supe" - }, { "name": "cptn-cosmo", "url": "https://github.com/cptn-cosmo", @@ -244,14 +239,11 @@ "adversary": { "htmlFields": ["notes", "description"] }, - "npc": { - "htmlFields": ["notes"] - }, "environment": { "htmlFields": ["notes", "description"] }, "party": { - "htmlFields": ["notes", "description"] + "htmlFields": ["notes"] } }, "Item": { @@ -301,16 +293,11 @@ "damageRoll": {}, "abilityUse": {}, "tagTeam": {}, + "groupRoll": {}, "systemMessage": {} } }, "background": "systems/daggerheart/assets/logos/FoundrybornBackgroundLogo.png", "primaryTokenAttribute": "resources.hitPoints", - "secondaryTokenAttribute": "resources.stress", - "flags": { - "hotReload": { - "extensions": ["css", "hbs", "json"], - "paths": ["styles/daggerheart.css", "templates", "lang"] - } - } + "secondaryTokenAttribute": "resources.stress" } diff --git a/templates/actionTypes/areas.hbs b/templates/actionTypes/areas.hbs deleted file mode 100644 index 2e010c72..00000000 --- a/templates/actionTypes/areas.hbs +++ /dev/null @@ -1,46 +0,0 @@ -
- - {{localize "DAGGERHEART.ACTIONS.Config.area.sectionTitle"}} - - - - {{#each source as |area index|}} - {{#unless @first}}{{/unless}} -
- {{formField ../fields.name value=area.name name=(concat "areas." index ".name") localize=true}} - -
-
- {{formField ../fields.type value=area.type name=(concat "areas." index ".type") localize=true}} - {{formField ../fields.shape value=area.shape name=(concat "areas." index ".shape") localize=true}} - {{formField ../fields.size value=area.size name=(concat "areas." index ".size") localize=true}} -
- -
- {{localize "DAGGERHEART.GENERAL.Effect.plural"}} - -
-
- {{#each area.effects as |effectId index|}} - - -
-
- {{#with (@root.getEffectDetails effectId) as | details |}} -
- -
-
-
{{name}}
-
- {{/with}} -
- -
-
-
- {{/each}} -
- {{/each}} - -
\ No newline at end of file diff --git a/templates/actionTypes/beastform.hbs b/templates/actionTypes/beastform.hbs index 885038a1..3dcdb006 100644 --- a/templates/actionTypes/beastform.hbs +++ b/templates/actionTypes/beastform.hbs @@ -1,16 +1,4 @@ -{{formGroup fields.tierAccess.fields.exact value=source.tierAccess.exact name="beastform.tierAccess.exact" labelAttr="label" valueAttr="key" localize=true blank=""}} -
- {{localize "DAGGERHEART.ACTIONS.Config.beastform.modifications.traitBonuses.label.plural"}} - - {{#if source.modifications.traitBonuses.length}} - {{#each source.modifications.traitBonuses as |traitBonus index|}} -
- {{formGroup ../fields.modifications.fields.traitBonuses.element.fields.bonus value=traitBonus.bonus name=(concat "beastform.modifications.traitBonuses." index ".bonus") localize=true}} - -
- {{/each}} - {{else}} - {{localize "DAGGERHEART.ACTIONS.Config.beastform.modifications.traitBonuses.hint"}} - {{/if}} + {{localize "DAGGERHEART.ACTIONS.TYPES.beastform.name"}} + {{formGroup fields.tierAccess.fields.exact value=source.tierAccess.exact name="beastform.tierAccess.exact" labelAttr="label" valueAttr="key" localize=true blank=""}}
\ No newline at end of file diff --git a/templates/actionTypes/damage.hbs b/templates/actionTypes/damage.hbs index 03300840..96bb361c 100644 --- a/templates/actionTypes/damage.hbs +++ b/templates/actionTypes/damage.hbs @@ -1,92 +1,90 @@
- + {{#if (eq @root.source.type 'healing')}} {{localize "DAGGERHEART.GENERAL.healing"}} {{else}} {{localize "DAGGERHEART.GENERAL.damage"}} {{/if}} - {{#unless (eq path 'system.attack.')}}{{/unless}} + {{#unless (eq path 'system.attack.')}}{{/unless}} -
+
{{#if @root.hasBaseDamage}} {{formField @root.fields.damage.fields.includeBase value=@root.source.damage.includeBase name="damage.includeBase" classes="checkbox" localize=true }} {{/if}} {{#unless (eq @root.source.type 'healing')}} - {{formField baseFields.direct value=source.direct name=(concat path "damage.direct") localize=true classes="checkbox"}} + {{formField directField value=source.direct name=(concat path "damage.direct") localize=true classes="checkbox"}} {{/unless}} - {{#if (and @root.isNPC (not (eq path 'system.attack.')))}} - {{formField baseFields.groupAttack value=source.groupAttack name=(concat path "damage.groupAttack") localize=true classes="select"}} - {{/if}}
- - {{!-- Handlebars uses Symbol.Iterator to produce index|key. This isn't compatible with our parts object, so we instead use applyTo, which is the same value --}} - {{#each source.parts as |dmg key|}} + {{#each source.parts as |dmg index|}} + {{#if (and @root.hasBaseDamage @root.source.damage.includeBase)}} + {{setVar 'realIndex' (add index -1)}} + {{else}} + {{setVar 'realIndex' index}} + {{/if}}
- - {{localize (concat "DAGGERHEART.CONFIG.HealingType." dmg.applyTo ".name")}} - {{#unless (or dmg.base ../path)}} - - {{/unless}} - - {{#if (and (not @root.isNPC) @root.hasRoll (not dmg.base))}} - {{formField ../fields.resultBased value=dmg.resultBased name=(concat "damage.parts." dmg.applyTo ".resultBased") localize=true classes="checkbox"}} + {{formField ../fields.resultBased value=dmg.resultBased name=(concat "damage.parts." realIndex ".resultBased") localize=true classes="checkbox"}} {{/if}} {{#if (and (not @root.isNPC) @root.hasRoll (not dmg.base) dmg.resultBased)}}
{{localize "DAGGERHEART.GENERAL.withThing" thing=(localize "DAGGERHEART.GENERAL.hope")}} - {{> formula fields=../fields.value.fields type=../fields.type dmg=dmg source=dmg.value target="value" key=dmg.applyTo path=../path}} + {{> formula fields=../fields.value.fields type=../fields.type dmg=dmg source=dmg.value target="value" realIndex=realIndex path=../path}}
{{localize "DAGGERHEART.GENERAL.withThing" thing=(localize "DAGGERHEART.GENERAL.fear")}} - {{> formula fields=../fields.valueAlt.fields type=../fields.type dmg=dmg source=dmg.valueAlt target="valueAlt" key=dmg.applyTo path=../path}} + {{> formula fields=../fields.valueAlt.fields type=../fields.type dmg=dmg source=dmg.valueAlt target="valueAlt" realIndex=realIndex path=../path}}
{{else}} - {{> formula fields=../fields.value.fields type=../fields.type dmg=dmg source=dmg.value target="value" key=dmg.applyTo path=../path}} + + {{localize "DAGGERHEART.GENERAL.formula"}} + {{> formula fields=../fields.value.fields type=../fields.type dmg=dmg source=dmg.value target="value" realIndex=realIndex path=../path}} +
{{/if}} - - {{#if (and (eq dmg.applyTo 'hitPoints') (ne @root.source.type 'healing'))}} - {{formField ../fields.type value=dmg.type name=(concat ../path "damage.parts." dmg.applyTo ".type") localize=true}} - {{/if}} - +
+ {{formField ../fields.applyTo value=dmg.applyTo name=(concat ../path "damage.parts." realIndex ".applyTo") localize=true}} + {{#if (and (eq dmg.applyTo 'hitPoints') (ne @root.source.type 'healing'))}} + {{formField ../fields.type value=dmg.type name=(concat ../path "damage.parts." realIndex ".type") localize=true}} + {{/if}} +
{{#if ../horde}}
{{localize "DAGGERHEART.ACTORS.Adversary.hordeDamage"}}
- - {{formField ../fields.valueAlt.fields.flatMultiplier value=dmg.valueAlt.flatMultiplier name=(concat ../path "damage.parts." dmg.applyTo ".valueAlt.flatMultiplier") label="DAGGERHEART.ACTIONS.Settings.multiplier" classes="inline-child" localize=true }} - {{formField ../fields.valueAlt.fields.dice value=dmg.valueAlt.dice name=(concat ../path "damage.parts." dmg.applyTo ".valueAlt.dice") classes="inline-child" localize=true}} - {{formField ../fields.valueAlt.fields.bonus value=dmg.valueAlt.bonus name=(concat ../path "damage.parts." dmg.applyTo ".valueAlt.bonus") localize=true classes="inline-child"}} + + {{formField ../fields.valueAlt.fields.flatMultiplier value=dmg.valueAlt.flatMultiplier name=(concat ../path "damage.parts." realIndex ".valueAlt.flatMultiplier") label="DAGGERHEART.ACTIONS.Settings.multiplier" classes="inline-child" localize=true }} + {{formField ../fields.valueAlt.fields.dice value=dmg.valueAlt.dice name=(concat ../path "damage.parts." realIndex ".valueAlt.dice") classes="inline-child" localize=true}} + {{formField ../fields.valueAlt.fields.bonus value=dmg.valueAlt.bonus name=(concat ../path "damage.parts." realIndex ".valueAlt.bonus") localize=true classes="inline-child"}}
{{/if}} - + + {{#unless (or dmg.base ../path)}}
{{/unless}} {{/each}} {{#*inline "formula"}} {{#unless dmg.base}} - {{formField fields.custom.fields.enabled value=source.custom.enabled name=(concat path "damage.parts." key "." target ".custom.enabled") classes="checkbox" localize=true}} + {{formField fields.custom.fields.enabled value=source.custom.enabled name=(concat path "damage.parts." realIndex "." target ".custom.enabled") classes="checkbox" localize=true}} {{/unless}} {{#if source.custom.enabled}} - {{formField fields.custom.fields.formula value=source.custom.formula name=(concat path "damage.parts." key "." target ".custom.formula") localize=true}} + {{formField fields.custom.fields.formula value=source.custom.formula name=(concat path "damage.parts." realIndex "." target ".custom.formula") localize=true}} {{else}}
{{#unless @root.isNPC}} - {{formField fields.multiplier value=source.multiplier name=(concat path "damage.parts." key "." target ".multiplier") localize=true}} + {{formField fields.multiplier value=source.multiplier name=(concat path "damage.parts." realIndex "." target ".multiplier") localize=true}} {{/unless}} - {{#if (eq source.multiplier 'flat')}}{{formField fields.flatMultiplier value=source.flatMultiplier name=(concat path "damage.parts." key "." target ".flatMultiplier") localize=true }}{{/if}} - {{formField fields.dice value=source.dice name=(concat path "damage.parts." key "." target ".dice") localize=true}} - {{formField fields.bonus value=source.bonus name=(concat path "damage.parts." key "." target ".bonus") localize=true}} + {{#if (eq source.multiplier 'flat')}}{{formField fields.flatMultiplier value=source.flatMultiplier name=(concat path "damage.parts." realIndex "." target ".flatMultiplier") localize=true }}{{/if}} + {{formField fields.dice value=source.dice name=(concat path "damage.parts." realIndex "." target ".dice") localize=true}} + {{formField fields.bonus value=source.bonus name=(concat path "damage.parts." realIndex "." target ".bonus") localize=true}}
{{/if}} {{#if @root.isNPC}} - + {{/if}} {{/inline}} \ No newline at end of file diff --git a/templates/actionTypes/effect.hbs b/templates/actionTypes/effect.hbs index 8c5e6e68..dd6a7974 100644 --- a/templates/actionTypes/effect.hbs +++ b/templates/actionTypes/effect.hbs @@ -4,6 +4,21 @@
    + {{!-- {{#each source as | effect index |}} +
    + {{#with (@root.getEffectDetails effect._id) as | details |}} + +
    + {{name}} +
    + {{/with}} + + {{#if @root.source.save.trait}}{{formInput ../fields.onSave value=effect.onSave name=(concat "effects." index ".onSave") dataset=(object tooltip=(localize "DAGGERHEART.UI.Tooltip.appliedEvenIfSuccessful") tooltipDirection="UP")}}{{/if}} +
    + +
    +
    + {{/each}} --}} {{#each source as | effect index |}}
    diff --git a/templates/actionTypes/range-target.hbs b/templates/actionTypes/range-target.hbs index ec595df4..143acdf8 100644 --- a/templates/actionTypes/range-target.hbs +++ b/templates/actionTypes/range-target.hbs @@ -1,14 +1,12 @@
    {{localize "DAGGERHEART.GENERAL.range"}}{{#if fields.target}} & {{localize "DAGGERHEART.GENERAL.Target.single"}}{{/if}} + {{formField fields.range value=source.range label="DAGGERHEART.GENERAL.range" name=(concat path "range") localize=true}} {{#if fields.target}} -
    - {{formField fields.range value=source.range label=(localize "DAGGERHEART.GENERAL.range") name=(concat path "range") localize=true}} - {{#if (and source.target.type (not (eq source.target.type 'self')))}} - {{ formField fields.target.amount value=source.target.amount label=(localize "DAGGERHEART.GENERAL.amount") name=(concat path "target.amount") localize=true}} - {{/if}} - {{ formField fields.target.type value=source.target.type label=(localize "DAGGERHEART.GENERAL.Target.single") name=(concat path "target.type") localize=true }} -
    - {{else}} - {{formField fields.range value=source.range label=(localize "DAGGERHEART.GENERAL.range") name=(concat path "range") localize=true}} +
    + {{#if (and source.target.type (not (eq source.target.type 'self')))}} + {{ formField fields.target.amount value=source.target.amount label="DAGGERHEART.GENERAL.amount" name=(concat path "target.amount") localize=true}} + {{/if}} + {{ formField fields.target.type value=source.target.type label="DAGGERHEART.GENERAL.Target.single" name=(concat path "target.type") localize=true }} +
    {{/if}}
    \ No newline at end of file diff --git a/templates/actionTypes/roll.hbs b/templates/actionTypes/roll.hbs index 41f88ba2..3e25b9c8 100644 --- a/templates/actionTypes/roll.hbs +++ b/templates/actionTypes/roll.hbs @@ -1,10 +1,10 @@
    - {{localize "DAGGERHEART.GENERAL.roll"}} - {{#if @root.hasBaseDamage}}{{formInput fields.useDefault name="roll.useDefault" value=source.useDefault dataset=(object tooltip=(localize "DAGGERHEART.ACTIONS.Config.useDefaultItemValues") tooltipDirection="UP")}}{{/if}} + Roll + {{#if @root.hasBaseDamage}}{{formInput fields.useDefault name="roll.useDefault" value=source.useDefault dataset=(object tooltip="Use default Item values" tooltipDirection="UP")}}{{/if}} - {{formField fields.type label="DAGGERHEART.GENERAL.type" name="roll.type" value=source.type localize=true choices=@root.getRollTypeOptions localize=true}} + {{formField fields.type label="Type" name="roll.type" value=source.type localize=true choices=@root.getRollTypeOptions}} {{#if (eq source.type "diceSet")}}
    {{formField fields.diceRolling.fields.multiplier name="roll.diceRolling.multiplier" value=source.diceRolling.multiplier localize=true}} @@ -17,13 +17,13 @@
    {{#unless (eq source.type 'spellcast')}} {{#if @root.isNPC}} - {{formField fields.bonus label="DAGGERHEART.GENERAL.Modifier.single" name="roll.bonus" value=source.bonus placeholder=@root.baseAttackBonus disabled=(not source.type) localize=true}} + {{formField fields.bonus label="Bonus" name="roll.bonus" value=source.bonus placeholder=@root.baseAttackBonus disabled=(not source.type)}} {{else}} - {{formField fields.trait label="DAGGERHEART.GENERAL.Trait.single" name="roll.trait" value=source.trait localize=true disabled=(not source.type)}} + {{formField fields.trait label="Trait" name="roll.trait" value=source.trait localize=true disabled=(not source.type)}} {{/if}} {{/unless}} - {{formField fields.difficulty label="DAGGERHEART.GENERAL.difficulty" name="roll.difficulty" value=source.difficulty localize=true disabled=(not source.type)}} - {{formField fields.advState label="DAGGERHEART.ACTIONS.Config.advantageState" name="roll.advState" value=source.advState localize=true localize=true disabled=(not source.type)}} + {{formField fields.difficulty label="Difficulty" name="roll.difficulty" value=source.difficulty disabled=(not source.type)}} + {{formField fields.advState label= "Advantage State" name="roll.advState" value=source.advState localize=true disabled=(not source.type)}}
    {{/if}}
    \ No newline at end of file diff --git a/templates/actionTypes/save.hbs b/templates/actionTypes/save.hbs index 865991c7..85536c87 100644 --- a/templates/actionTypes/save.hbs +++ b/templates/actionTypes/save.hbs @@ -2,8 +2,8 @@ {{localize "DAGGERHEART.GENERAL.Roll.reaction"}}

    {{localize "DAGGERHEART.ACTIONS.Settings.saveHint"}}

    - {{formField fields.trait label="DAGGERHEART.GENERAL.Trait.single" name="save.trait" value=source.trait localize=true}} - {{formField fields.difficulty label="DAGGERHEART.GENERAL.difficulty" name="save.difficulty" value=source.difficulty disabled=(not source.trait) placeholder=@root.baseSaveDifficulty localize=true}} - {{formField fields.damageMod label="DAGGERHEART.ACTIONS.Config.damageOnSave" name="save.damageMod" value=source.damageMod localize=true localize=true disabled=(not source.trait)}} + {{formField fields.trait label="Trait" name="save.trait" value=source.trait localize=true}} + {{formField fields.difficulty label="Difficulty" name="save.difficulty" value=source.difficulty disabled=(not source.trait) placeholder=@root.baseSaveDifficulty}} + {{formField fields.damageMod label="Damage on Save" name="save.damageMod" value=source.damageMod localize=true disabled=(not source.trait)}}
    \ No newline at end of file diff --git a/templates/characterCreation/footer.hbs b/templates/characterCreation/footer.hbs index 51eef110..369af2d3 100644 --- a/templates/characterCreation/footer.hbs +++ b/templates/characterCreation/footer.hbs @@ -1,5 +1,5 @@
    - +
    \ No newline at end of file diff --git a/templates/dialogs/compendiumBrowserSettingsDialog/packs.hbs b/templates/dialogs/compendiumBrowserSettingsDialog/packs.hbs index ca2739b2..dcda8108 100644 --- a/templates/dialogs/compendiumBrowserSettingsDialog/packs.hbs +++ b/templates/dialogs/compendiumBrowserSettingsDialog/packs.hbs @@ -22,7 +22,7 @@
    {{#each source.packs as |pack|}}
    - +
    {{/each}} diff --git a/templates/dialogs/damageReduction.hbs b/templates/dialogs/damageReduction.hbs index 50fe3422..57d7ee61 100644 --- a/templates/dialogs/damageReduction.hbs +++ b/templates/dialogs/damageReduction.hbs @@ -7,57 +7,53 @@
    -

    {{localize "DAGGERHEART.APPLICATIONS.DamageReduction.maxUseableArmor"}}

    -
    {{availableArmor}}
    +

    {{localize "DAGGERHEART.APPLICATIONS.DamageReduction.armorMarks"}}

    +
    {{armorMarks}}/{{armorScore}}
    + {{#if this.stress}} +
    +

    {{localize "DAGGERHEART.APPLICATIONS.DamageReduction.stress"}}

    +
    {{this.stress.value}}/{{this.stress.max}}
    +
    + {{/if}}
    -
    - {{#each marks.armor as |source|}} -
    -

    {{source.label}}

    -
    - {{#each source.marks}} - - - - {{/each}} -
    -
    - {{/each}} - {{#if usesStressArmor}} -
    -

    {{localize "Stress"}}

    -
    +
    +

    +
    + {{#each marks.armor}} +
    + +
    + {{/each}} {{#each marks.stress}}
    {{/each}} -

    - {{/if}} + +
    {{localize "DAGGERHEART.APPLICATIONS.DamageReduction.usedMarks"}}
    {{#if availableStressReductions}}
    -

    {{localize "DAGGERHEART.APPLICATIONS.DamageReduction.stressReduction"}}

    +

    {{localize "DAGGERHEART.APPLICATIONS.DamageReduction.stressReduction"}}

    {{/if}} {{#each availableStressReductions}}
    -

    +

    {{#if this.any}} {{localize "DAGGERHEART.GENERAL.any"}} @@ -78,7 +74,7 @@ {{#if reduceSeverity}}
    -

    {{localize "DAGGERHEART.APPLICATIONS.DamageReduction.reduceSeverity" nr=reduceSeverity}}

    +

    {{localize "DAGGERHEART.APPLICATIONS.DamageReduction.reduceSeverity" nr=reduceSeverity}}

    {{/if}} @@ -86,7 +82,7 @@ {{#if thresholdImmunities}}
    -

    {{localize "DAGGERHEART.APPLICATIONS.DamageReduction.thresholdImmunities"}}

    +

    {{localize "DAGGERHEART.APPLICATIONS.DamageReduction.thresholdImmunities"}}

    {{/if}} diff --git a/templates/dialogs/deathMove.hbs b/templates/dialogs/deathMove.hbs index 97900022..341659df 100644 --- a/templates/dialogs/deathMove.hbs +++ b/templates/dialogs/deathMove.hbs @@ -17,7 +17,7 @@

    -
    +
    -
    {{/each}} - - {{#if damageOptions.groupAttack}} -
    - {{localize "DAGGERHEART.ACTIONS.Settings.groupAttack.label"}} - -
    - - -
    - - -
    -
    -
    - {{/if}} - {{#unless (empty @root.modifiers)}}
    {{localize "DAGGERHEART.GENERAL.Modifier.plural"}} @@ -78,8 +56,8 @@ {{/unless}}
    {{#if directDamage}} - + {{selectOptions rollModes selected=selectedRollMode valueAttr="action" labelAttr="label" localize=true}} {{/if}}
    {{/if}}
    + {{#if (and @root.hasRoll @root.activeTagTeamRoll)}} +
    + + {{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.title"}} +
    + {{/if}} \ No newline at end of file diff --git a/templates/dialogs/dice-roll/rollSelection.hbs b/templates/dialogs/dice-roll/rollSelection.hbs index 2c1a21b6..569f5e16 100644 --- a/templates/dialogs/dice-roll/rollSelection.hbs +++ b/templates/dialogs/dice-roll/rollSelection.hbs @@ -53,14 +53,14 @@ {{#if @root.advantage}} {{#if (eq @root.advantage 1)}}
    - +
    {{localize "DAGGERHEART.GENERAL.Advantage.full"}}
    {{else if (eq @root.advantage -1)}}
    - +
    {{localize "DAGGERHEART.GENERAL.Disadvantage.full"}}
    @@ -157,8 +157,8 @@ {{/times}} - + {{selectOptions diceOptions selected=@root.roll.dAdvantage.denomination}}
    {{#if abilities}} @@ -189,8 +189,8 @@ {{/if}}
    - + {{selectOptions rollModes selected=selectedRollMode valueAttr="action" labelAttr="label" localize=true}} +
    \ No newline at end of file diff --git a/templates/dialogs/group-roll/group-roll.hbs b/templates/dialogs/group-roll/group-roll.hbs new file mode 100644 index 00000000..9b23c0a5 --- /dev/null +++ b/templates/dialogs/group-roll/group-roll.hbs @@ -0,0 +1,84 @@ +
    +
    +

    {{localize "DAGGERHEART.UI.Chat.groupRoll.title"}}

    +
    + +
    + {{localize "DAGGERHEART.UI.Chat.groupRoll.leader"}} + {{#unless leader.actor}} + +
    + {{localize "DAGGERHEART.UI.Chat.groupRoll.selectLeader"}} +
    + {{else}} +
    + {{leader.actor.name}} +
    + {{leader.actor.name}} +
    +
    + + +
    + {{!-- Not used yet --}} + {{!--
    + + +
    --}} +
    +
    +
    + + + +
    +
    + {{/unless}} +
    + +
    + {{localize "DAGGERHEART.UI.Chat.groupRoll.partyTeam"}} + + + + {{#if (gt this.members.length 0)}} + {{#each members as |member index|}} +
    + {{member.actor.name}} +
    + {{member.actor.name}} +
    +
    + + +
    + {{!-- Not used yet --}} + {{!--
    + + +
    --}} +
    +
    +
    + + + +
    +
    + {{/each}} + {{/if}} + {{#unless allSelected}} +
    + {{localize "DAGGERHEART.UI.Chat.groupRoll.selectMember"}} +
    + {{/unless}} +
    + +
    \ No newline at end of file diff --git a/templates/dialogs/groupRollDialog/initialization.hbs b/templates/dialogs/groupRollDialog/initialization.hbs deleted file mode 100644 index a01a00bb..00000000 --- a/templates/dialogs/groupRollDialog/initialization.hbs +++ /dev/null @@ -1,43 +0,0 @@ -
    -

    {{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.initializationTitle"}}

    -
    {{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.leader"}}
    -
    -
    {{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.selectLeaderHint"}}
    - -
    - -
    {{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.members"}}
    -
    {{"DAGGERHEART.APPLICATIONS.GroupRollSelect.selectParticipantsHint"}}
    -
    - {{#each memberSelection as |member|}} - - {{/each}} -
    - -
    -
    - {{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.openDialogForAll"}} - -
    - -
    -
    \ No newline at end of file diff --git a/templates/dialogs/groupRollDialog/main.hbs b/templates/dialogs/groupRollDialog/main.hbs deleted file mode 100644 index 6807a7e4..00000000 --- a/templates/dialogs/groupRollDialog/main.hbs +++ /dev/null @@ -1,15 +0,0 @@ -
    -

    {{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.title"}}

    -
    {{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.members"}}
    -
    - {{#each aidKeys as |key|}} -
    - {{/each}} -
    - -
    {{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.leader"}}
    -
    -
    {{localize "DAGGERHEART.GENERAL.result.single"}}
    -
    -
    -
    \ No newline at end of file diff --git a/templates/dialogs/groupRollDialog/parts/footer.hbs b/templates/dialogs/groupRollDialog/parts/footer.hbs deleted file mode 100644 index 34b4efa1..00000000 --- a/templates/dialogs/groupRollDialog/parts/footer.hbs +++ /dev/null @@ -1,9 +0,0 @@ -
    -
    - - -
    -
    \ No newline at end of file diff --git a/templates/dialogs/groupRollDialog/parts/member.hbs b/templates/dialogs/groupRollDialog/parts/member.hbs deleted file mode 100644 index ee857794..00000000 --- a/templates/dialogs/groupRollDialog/parts/member.hbs +++ /dev/null @@ -1,95 +0,0 @@ -{{#with (ifThen (eq partId "leader") leader (lookup members partId))}} -
    - -
    - {{name}} - {{#if hasRolled}} -
    -
    {{rollChoiceLabel}}
    - {{#if modifier}} - - {{numberFormat modifier sign=true}} - - {{/if}} - {{#if isEditable}} -
    - - -
    - {{/if}} -
    - {{else if readyToRoll}} -
    - {{localize "DAGGERHEART.CONFIG.RollTypes.trait.name" }} - -
    - {{/if}} -
    - {{#if roll}} -
    -
    -
    - {{roll.total}} - {{withLabelShort}} -
    -
    - - {{roll.dHope.total}} - - - - {{roll.dFear.total}} - - - {{#if roll.hasAdvantage}} - + - - {{roll.dAdvantage.total}} - - - {{/if}} - {{#if roll.hasDisadvantage}} - - - - {{roll.dDisadvantage.total}} - - - {{/if}} - {{#if (gte roll.modifierTotal 0)}}+{{else}}-{{/if}} - {{positive roll.modifierTotal}} -
    -
    - {{#if (and @root.isGM (ne ../partId "leader"))}} -
    - - -
    - {{/if}} -
    - {{else if (and readyToRoll isEditable)}} - - 2d12 - - {{/if}} -
    -{{/with}} \ No newline at end of file diff --git a/templates/dialogs/groupRollDialog/parts/result.hbs b/templates/dialogs/groupRollDialog/parts/result.hbs deleted file mode 100644 index d90dfb5c..00000000 --- a/templates/dialogs/groupRollDialog/parts/result.hbs +++ /dev/null @@ -1,30 +0,0 @@ -{{#if (and hasRolled leader.roll)}} -
    -
    - {{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.leaderRoll"}} - - {{leader.roll.total}} - {{localize "DAGGERHEART.GENERAL.withThing" thing=leader.roll.totalLabel}} - -
    -
    - {{localize "DAGGERHEART.GENERAL.Modifier.plural"}} -
    - {{#each groupRoll.modifiers as |modifier|}} - - {{numberFormat modifier sign=true}} - - {{/each}} -
    -
    -
    -
    - {{localize "DAGGERHEART.GENERAL.total"}} - {{groupRoll.total}} {{groupRoll.totalLabel}} -
    -
    -{{else}} -
    - {{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.resultsHint"}} -
    -{{/if}} \ No newline at end of file diff --git a/templates/dialogs/image-select/footer.hbs b/templates/dialogs/image-select/footer.hbs index 58a60cc4..cd7d3d1a 100644 --- a/templates/dialogs/image-select/footer.hbs +++ b/templates/dialogs/image-select/footer.hbs @@ -1,4 +1,4 @@ \ No newline at end of file diff --git a/templates/dialogs/item-transfer.hbs b/templates/dialogs/item-transfer.hbs index 63972ed8..0e7df3dc 100644 --- a/templates/dialogs/item-transfer.hbs +++ b/templates/dialogs/item-transfer.hbs @@ -14,7 +14,7 @@
    - +
    diff --git a/templates/dialogs/multiclassChoice.hbs b/templates/dialogs/multiclassChoice.hbs index 55365939..3c89ff1a 100644 --- a/templates/dialogs/multiclassChoice.hbs +++ b/templates/dialogs/multiclassChoice.hbs @@ -16,7 +16,7 @@
    - +
    diff --git a/templates/dialogs/rerollDialog/damage/main.hbs b/templates/dialogs/rerollDialog/damage/main.hbs new file mode 100644 index 00000000..5b994bf6 --- /dev/null +++ b/templates/dialogs/rerollDialog/damage/main.hbs @@ -0,0 +1,35 @@ +
    + {{#each damage}} +

    {{localize (concat 'DAGGERHEART.CONFIG.HealingType.' @key '.name')}}

    + {{#each this}} +
    + {{#each this}} +
    + + + + {{this.selectedResults}}/{{this.maxSelected}} Selected + + +
    + {{#each this.results}} +
    + {{this.result}} + {{#if this.active}} + + + + + {{/if}} +
    + {{/each}} +
    +
    + {{/each}} +
    + {{/each}} + {{/each}} +
    \ No newline at end of file diff --git a/templates/dialogs/rerollDialog/footer.hbs b/templates/dialogs/rerollDialog/footer.hbs new file mode 100644 index 00000000..5d4ae2b2 --- /dev/null +++ b/templates/dialogs/rerollDialog/footer.hbs @@ -0,0 +1,4 @@ +
    + + +
    \ No newline at end of file diff --git a/templates/dialogs/rerollDialog/main.hbs b/templates/dialogs/rerollDialog/main.hbs new file mode 100644 index 00000000..6f10ce33 --- /dev/null +++ b/templates/dialogs/rerollDialog/main.hbs @@ -0,0 +1,35 @@ +
    + {{#each damage}} +

    {{localize (concat 'DAGGERHEART.CONFIG.HealingType.' @key '.name')}}

    + {{#each this}} +
    + {{#each this}} +
    + + + + {{this.selectedResults}}/{{this.results.length}} Selected + + +
    + {{#each this.results}} +
    + {{this.result}} + {{#if this.active}} + + + + + {{/if}} +
    + {{/each}} +
    +
    + {{/each}} +
    + {{/each}} + {{/each}} +
    \ No newline at end of file diff --git a/templates/dialogs/tagTeamDialog.hbs b/templates/dialogs/tagTeamDialog.hbs new file mode 100644 index 00000000..3c96a573 --- /dev/null +++ b/templates/dialogs/tagTeamDialog.hbs @@ -0,0 +1,110 @@ +
    +
    +
    + {{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.partyTeam"}} + +
    + + +
    + +
    + +
    + {{#each members as |member|}} +
    +
    +
    + +
    +
    {{member.character.name}}
    +
    + {{#if member.character.system.class.value}} +
    {{member.character.system.class.value.name}}
    + {{/if}} + {{#if member.system.multiclass.value}} +
    {{member.character.system.multiclass.value.name}}
    + {{/if}} +
    +
    +
    + +
    + {{#if member.roll}} +
    +
    +

    + + {{member.roll.system.title}} +

    +
    +
    + +
    + {{member.roll.system.roll.total}} + {{localize "DAGGERHEART.GENERAL.withThing" thing=member.roll.system.roll.result.label}} +
    + +
    + {{#if member.roll.system.hasDamage}} +

    {{localize "DAGGERHEART.GENERAL.damage"}}

    +
    + {{#if member.damageValues}} + {{#each member.damageValues as |damage|}} +
    +
    {{damage.name}}
    +
    {{damage.total}}
    +
    + {{/each}} + {{else}} + {{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.damageNotRolled"}} + {{/if}} +
    + {{/if}} +
    + {{else}} +
    + {{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.linkMessageHint"}} +
    + {{/if}} +
    + {{/each}} +
    +
    + +
    +

    + {{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.initiatingCharacter"}} + +

    +

    + {{localize "DAGGERHEART.GENERAL.Cost.single"}} + +

    +
    + {{#if showResult}} + {{#if selectedData.result}} +
    +

    {{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.title"}}: {{selectedData.result}}

    + {{#if usesDamage}} +
    + + {{#each selectedData.damageValues as |damage|}} +
    + {{damage.name}} + {{damage.total}} +
    + {{/each}} +
    + {{/if}} +
    + {{/if}} + {{/if}} + + +
    +
    \ No newline at end of file diff --git a/templates/dialogs/tagTeamDialog/initialization.hbs b/templates/dialogs/tagTeamDialog/initialization.hbs deleted file mode 100644 index 0b92e68e..00000000 --- a/templates/dialogs/tagTeamDialog/initialization.hbs +++ /dev/null @@ -1,47 +0,0 @@ -
    -

    {{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.selectParticipants"}}

    - - -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    -
    - {{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.openDialogForAll"}} - -
    - -
    -
    \ No newline at end of file diff --git a/templates/dialogs/tagTeamDialog/parts/tagTeamDamageParts.hbs b/templates/dialogs/tagTeamDialog/parts/tagTeamDamageParts.hbs deleted file mode 100644 index 2a366269..00000000 --- a/templates/dialogs/tagTeamDialog/parts/tagTeamDamageParts.hbs +++ /dev/null @@ -1,25 +0,0 @@ -{{#each damage as |damage key|}} -
    -
    - {{localize (concat "DAGGERHEART.CONFIG.HealingType." key ".name")}}: - {{damage.total}} -
    - {{#each damage.parts as |part|}} -
    - {{#each part.dice as |dice index|}} - - {{dice.total}} - - - {{#unless @last}} - + - {{/unless}} - {{/each}} - {{#if part.modifierTotal}} - {{#if part.dice.length}}{{#if (gte part.modifierTotal 0)}}+{{else}}-{{/if}}{{/if}} - {{positive part.modifierTotal}} - {{/if}} -
    - {{/each}} -
    -{{/each}} \ No newline at end of file diff --git a/templates/dialogs/tagTeamDialog/result.hbs b/templates/dialogs/tagTeamDialog/result.hbs deleted file mode 100644 index 151c8c87..00000000 --- a/templates/dialogs/tagTeamDialog/result.hbs +++ /dev/null @@ -1,41 +0,0 @@ -
    -
    -
    - {{localize "DAGGERHEART.GENERAL.result.plural"}} -
    - {{#if hintText}} -
    {{localize hintText}}
    - {{else}} - {{#if joinedRoll.roll}} -
    - -
    -
    {{joinedRoll.roll.total}}
    -
    {{localize "DAGGERHEART.GENERAL.withThing" thing=joinedRoll.roll.totalLabel}}
    -
    -
    - {{/if}} - {{#if joinedRoll.rollData.options.hasDamage}} -
    - - {{#each joinedRoll.rollData.options.damage as |damage key|}} -
    -
    {{localize (concat "DAGGERHEART.CONFIG.HealingType." key ".name")}}
    -
    {{damage.total}}
    -
    - {{/each}} -
    - {{/if}} - {{/if}} -
    -
    - -
    - - -
    -
    -
    \ No newline at end of file diff --git a/templates/dialogs/tagTeamDialog/rollSelection.hbs b/templates/dialogs/tagTeamDialog/rollSelection.hbs deleted file mode 100644 index a40d3d39..00000000 --- a/templates/dialogs/tagTeamDialog/rollSelection.hbs +++ /dev/null @@ -1,11 +0,0 @@ -
    - {{#if allHaveRolled}} -
    - {{#each members as |member key|}} - - - - {{/each}} -
    - {{/if}} -
    \ No newline at end of file diff --git a/templates/dialogs/tagTeamDialog/tagTeamMember.hbs b/templates/dialogs/tagTeamDialog/tagTeamMember.hbs deleted file mode 100644 index 7510422f..00000000 --- a/templates/dialogs/tagTeamDialog/tagTeamMember.hbs +++ /dev/null @@ -1,124 +0,0 @@ - - {{#with (lookup members partId)}} -
    -
    -
    - - {{name}} -
    -
    -
    -
    - - -
    -
    - {{#if (or (not rollType) (eq rollType 'trait'))}} -
    -
    - - -
    -
    - {{else if (eq rollType 'damageAbility')}} -
    -
    - - -
    -
    - {{else}} -
    -
    - - -
    -
    - {{/if}} -
    - - {{#if readyToRoll}} -
    - - {{localize "DAGGERHEART.GENERAL.roll"}} -
    - - - - - {{#if hasRolled}} - - - - {{/if}} -
    -
    - - {{#if roll}} -
    -
    {{roll.total}} {{localize "DAGGERHEART.GENERAL.withThing" thing=roll.totalLabel}}
    -
    - - {{roll.dHope.total}} - - - + - - {{roll.dFear.total}} - - - {{#if roll.advantage.type}} - {{#if (eq roll.advantage.type 1)}}+{{else}}-{{/if}} - - {{roll.advantage.value}} - - - {{/if}} - {{#if (gte roll.modifierTotal 0)}}+{{else}}-{{/if}} - {{positive roll.modifierTotal}} -
    -
    - {{else}} - {{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.makeYourRoll"}} - {{/if}} -
    - {{/if}} - - {{#if rollData.options.hasDamage}} -
    - - {{localize "DAGGERHEART.GENERAL.damage"}} -
    - - - - - {{#if damage}} - - - - {{/if}} -
    -
    - {{#if damage}} - {{#if useCritDamage}} - {{> "systems/daggerheart/templates/dialogs/tagTeamDialog/parts/tagTeamDamageParts.hbs" damage=critDamage isCritical=true }} - {{else}} - {{> "systems/daggerheart/templates/dialogs/tagTeamDialog/parts/tagTeamDamageParts.hbs" damage=damage }} - {{/if}} - {{else}} - {{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.makeYourRoll"}} - {{/if}} -
    - {{/if}} -
    -
    - {{/with}} \ No newline at end of file diff --git a/templates/dialogs/tagTeamDialog/tagTeamRoll.hbs b/templates/dialogs/tagTeamDialog/tagTeamRoll.hbs deleted file mode 100644 index 1a4b974b..00000000 --- a/templates/dialogs/tagTeamDialog/tagTeamRoll.hbs +++ /dev/null @@ -1,9 +0,0 @@ -
    -
    - {{#each memberKeys as |key|}} -
    - {{/each}} -
    -
    -
    -
    diff --git a/templates/hud/tokenHUD.hbs b/templates/hud/tokenHUD.hbs index cf43e15d..1ba29621 100644 --- a/templates/hud/tokenHUD.hbs +++ b/templates/hud/tokenHUD.hbs @@ -4,37 +4,21 @@ - {{#if canChangeLevel}} - -
    - {{#each levels as |level|}} - {{level.name}} - {{/each}} -
    - {{/if}} - - + {{#if hasCompanion}} {{/if}} - {{#if isGM}} - - {{/if}} - {{#if canConfigure}} - {{/if}} @@ -56,9 +40,8 @@
    {{#if isGM}} - {{/if}} @@ -127,15 +110,13 @@ {{/each}}
    - {{#if canToggleCombat}} - {{/if}} diff --git a/templates/levelup/tabs/footer.hbs b/templates/levelup/tabs/footer.hbs index d487e657..2ee7a316 100644 --- a/templates/levelup/tabs/footer.hbs +++ b/templates/levelup/tabs/footer.hbs @@ -20,7 +20,7 @@ {{/if}} {{#unless levelupAuto}} {{/unless}} diff --git a/templates/levelup/tabs/selections.hbs b/templates/levelup/tabs/selections.hbs index deb7f6c0..7ebe32bb 100644 --- a/templates/levelup/tabs/selections.hbs +++ b/templates/levelup/tabs/selections.hbs @@ -43,6 +43,45 @@ {{/if}} + {{#if (gt this.domainCards.length 0)}} +
    +
    + +

    {{localize "DAGGERHEART.APPLICATIONS.Levelup.summary.domainCards"}}

    + +
    +
    + +
    + +
    + {{#each this.domainCards}} + {{#> "systems/daggerheart/templates/components/card-preview.hbs" this }} + {{#each this.emptySubtexts}} +
    {{this}}
    + {{/each}} + {{/"systems/daggerheart/templates/components/card-preview.hbs"}} + {{/each}} +
    +
    + {{/if}} + + {{#if (gt this.subclassCards.length 0)}} +
    +
    + +

    {{localize "DAGGERHEART.APPLICATIONS.Levelup.summary.subclass"}}

    + +
    + +
    + {{#each this.subclassCards}} + {{> "systems/daggerheart/templates/levelup/parts/selectable-card-preview.hbs" img=this.img header=this.featureLabel name=this.name path=this.path selected=this.selected uuid=this.uuid isMulticlass=this.isMulticlass featureState=this.featureState disabled=this.disabled }} + {{/each}} +
    +
    + {{/if}} + {{#if this.multiclass}}
    @@ -89,45 +128,6 @@
    {{/if}} - {{#if (gt this.domainCards.length 0)}} -
    -
    - -

    {{localize "DAGGERHEART.APPLICATIONS.Levelup.summary.domainCards"}}

    - -
    -
    - -
    - -
    - {{#each this.domainCards}} - {{#> "systems/daggerheart/templates/components/card-preview.hbs" this }} - {{#each this.emptySubtexts}} -
    {{this}}
    - {{/each}} - {{/"systems/daggerheart/templates/components/card-preview.hbs"}} - {{/each}} -
    -
    - {{/if}} - - {{#if (gt this.subclassCards.length 0)}} -
    -
    - -

    {{localize "DAGGERHEART.APPLICATIONS.Levelup.summary.subclass"}}

    - -
    - -
    - {{#each this.subclassCards}} - {{> "systems/daggerheart/templates/levelup/parts/selectable-card-preview.hbs" img=this.img header=this.featureLabel name=this.name path=this.path selected=this.selected uuid=this.uuid isMulticlass=this.isMulticlass featureState=this.featureState disabled=this.disabled }} - {{/each}} -
    -
    - {{/if}} - {{#if this.vicious}}

    {{localize "DAGGERHEART.APPLICATIONS.Levelup.summary.vicious"}}

    diff --git a/templates/settings/appearance-settings/diceSoNice.hbs b/templates/settings/appearance-settings/diceSoNice.hbs index 6cd4e52e..afe7dd5a 100644 --- a/templates/settings/appearance-settings/diceSoNice.hbs +++ b/templates/settings/appearance-settings/diceSoNice.hbs @@ -9,16 +9,9 @@ {{/if}}
    -
    -
    - {{formInput fields.diceSoNice.fields.sfx.fields.critical.fields.class value=setting.diceSoNice.sfx.critical.class blank="" localize=true}} -
    - -
    - {{formInput fields.diceSoNice.fields.sfx.fields.critical.fields.options.fields.muteSound value=setting.diceSoNice.sfx.critical.options.muteSound localize=true}} -
    -
    + {{formInput fields.diceSoNice.fields.sfx.fields.critical.fields.class value=setting.diceSoNice.sfx.critical.class blank="" localize=true}} +
    diff --git a/templates/settings/appearance-settings/diceSoNiceTab.hbs b/templates/settings/appearance-settings/diceSoNiceTab.hbs index 89b587af..a15b63ec 100644 --- a/templates/settings/appearance-settings/diceSoNiceTab.hbs +++ b/templates/settings/appearance-settings/diceSoNiceTab.hbs @@ -42,15 +42,9 @@ {{#if animations}}

    {{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.animations"}}

    -
    +
    -
    - {{formInput fields.sfx.fields.higher.fields.class value=values.sfx.higher.class blank="" localize=true}} -
    - - {{formInput fields.sfx.fields.higher.fields.options.fields.muteSound value=values.sfx.higher.options.muteSound localize=true}} -
    -
    + {{formInput fields.sfx.fields.higher.fields.class value=values.sfx.higher.class blank="" localize=true}}
    {{/if}} diff --git a/templates/settings/automation-settings/footer.hbs b/templates/settings/automation-settings/footer.hbs index 14ff5bb5..d30c23b7 100644 --- a/templates/settings/automation-settings/footer.hbs +++ b/templates/settings/automation-settings/footer.hbs @@ -1,7 +1,7 @@
    {{formGroup settingFields.schema.fields.vulnerableAutomation value=settingFields._source.vulnerableAutomation localize=true}} - {{formGroup settingFields.schema.fields.autoExpireActiveEffects value=settingFields._source.autoExpireActiveEffects localize=true}} {{formGroup settingFields.schema.fields.countdownAutomation value=settingFields._source.countdownAutomation localize=true}} {{formGroup settingFields.schema.fields.actionPoints value=settingFields._source.actionPoints localize=true}} {{formGroup settingFields.schema.fields.hordeDamage value=settingFields._source.hordeDamage localize=true}} diff --git a/templates/settings/downtime-config/actions.hbs b/templates/settings/downtime-config/actions.hbs index feb05302..d197f983 100644 --- a/templates/settings/downtime-config/actions.hbs +++ b/templates/settings/downtime-config/actions.hbs @@ -8,7 +8,7 @@
    {{#each move.actions as |action|}} - {{> "systems/daggerheart/templates/settings/components/settings-item-line.hbs" id=action.id type="action" }} + {{> "systems/daggerheart/templates/settings/components/settings-item-line.hbs" id=action.id }} {{/each}}
    diff --git a/templates/settings/downtime-config/footer.hbs b/templates/settings/downtime-config/footer.hbs index 199aea15..5e5f31dd 100644 --- a/templates/settings/downtime-config/footer.hbs +++ b/templates/settings/downtime-config/footer.hbs @@ -1,4 +1,4 @@ \ No newline at end of file diff --git a/templates/settings/homebrew-settings/footer.hbs b/templates/settings/homebrew-settings/footer.hbs index fc84fde7..92c0ef15 100644 --- a/templates/settings/homebrew-settings/footer.hbs +++ b/templates/settings/homebrew-settings/footer.hbs @@ -1,7 +1,7 @@
    \ No newline at end of file diff --git a/templates/sheets-settings/action-settings/effect.hbs b/templates/sheets-settings/action-settings/effect.hbs index 567cb81c..1bdd0304 100644 --- a/templates/sheets-settings/action-settings/effect.hbs +++ b/templates/sheets-settings/action-settings/effect.hbs @@ -5,7 +5,7 @@ > {{#if fields.roll}}{{> 'systems/daggerheart/templates/actionTypes/roll.hbs' fields=fields.roll.fields source=source.roll}}{{/if}} {{#if fields.save}}{{> 'systems/daggerheart/templates/actionTypes/save.hbs' fields=fields.save.fields source=source.save}}{{/if}} - {{#if fields.damage}}{{> 'systems/daggerheart/templates/actionTypes/damage.hbs' fields=fields.damage.fields.parts.element.fields source=source.damage baseFields=fields.damage.fields }}{{/if}} + {{#if fields.damage}}{{> 'systems/daggerheart/templates/actionTypes/damage.hbs' fields=fields.damage.fields.parts.element.fields source=source.damage directField=fields.damage.fields.direct }}{{/if}} {{#if fields.macro}}{{> 'systems/daggerheart/templates/actionTypes/macro.hbs' fields=fields.macro source=source.macro}}{{/if}} {{#if fields.effects}}{{> 'systems/daggerheart/templates/actionTypes/effect.hbs' fields=fields.effects.element.fields source=source.effects}}{{/if}} {{#if fields.beastform}}{{> 'systems/daggerheart/templates/actionTypes/beastform.hbs' fields=fields.beastform.fields source=source.beastform}}{{/if}} diff --git a/templates/sheets-settings/adversary-settings/attack.hbs b/templates/sheets-settings/adversary-settings/attack.hbs index 41960032..c3ee21f6 100644 --- a/templates/sheets-settings/adversary-settings/attack.hbs +++ b/templates/sheets-settings/adversary-settings/attack.hbs @@ -11,7 +11,7 @@
    {{localize "DAGGERHEART.GENERAL.attack"}}
    - {{formField systemFields.attack.fields.roll.fields.bonus value=document._source.system.attack.roll.bonus label="DAGGERHEART.ACTIONS.Settings.attackModifier" name="system.attack.roll.bonus" localize=true}} + {{formField systemFields.attack.fields.roll.fields.bonus value=document._source.system.attack.roll.bonus label="DAGGERHEART.ACTIONS.Settings.attackBonus" name="system.attack.roll.bonus" localize=true}} {{formField systemFields.attack.fields.range value=document._source.system.attack.range label="DAGGERHEART.GENERAL.range" name="system.attack.range" localize=true}} {{#if systemFields.attack.fields.target.fields}} {{ formField systemFields.attack.fields.target.fields.type value=document._source.system.attack.target.type label="DAGGERHEART.GENERAL.Target.single" name="system.attack.target.type" localize=true }} @@ -22,5 +22,5 @@
    {{formGroup systemFields.criticalThreshold value=document._source.system.criticalThreshold label="DAGGERHEART.ACTIONS.Settings.criticalThreshold" name="system.criticalThreshold" localize=true}}
    - {{> 'systems/daggerheart/templates/actionTypes/damage.hbs' fields=systemFields.attack.fields.damage.fields.parts.element.fields source=document.system.attack.damage path="system.attack." baseFields=systemFields.attack.fields.damage.fields horde=(eq document._source.system.type 'horde')}} + {{> 'systems/daggerheart/templates/actionTypes/damage.hbs' fields=systemFields.attack.fields.damage.fields.parts.element.fields source=document.system.attack.damage path="system.attack." directField=systemFields.attack.fields.damage.fields.direct horde=(eq document._source.system.type 'horde')}} \ No newline at end of file diff --git a/templates/sheets-settings/adversary-settings/details.hbs b/templates/sheets-settings/adversary-settings/details.hbs index 3160fbb9..dc2fd386 100644 --- a/templates/sheets-settings/adversary-settings/details.hbs +++ b/templates/sheets-settings/adversary-settings/details.hbs @@ -18,12 +18,6 @@ {{formField systemFields.motivesAndTactics value=document._source.system.motivesAndTactics label=(localize "DAGGERHEART.ACTORS.Adversary.FIELDS.motivesAndTactics.label")}} -
    - {{localize "DAGGERHEART.GENERAL.DamageThresholds.title"}} - {{formGroup systemFields.damageThresholds.fields.major value=document._source.system.damageThresholds.major label=(localize "DAGGERHEART.GENERAL.DamageThresholds.majorThreshold")}} - {{formGroup systemFields.damageThresholds.fields.severe value=document._source.system.damageThresholds.severe label=(localize "DAGGERHEART.GENERAL.DamageThresholds.severeThreshold")}} -
    -
    {{localize "DAGGERHEART.GENERAL.Resource.plural"}} @@ -32,4 +26,10 @@ {{/each}}
    + +
    + {{localize "DAGGERHEART.GENERAL.DamageThresholds.title"}} + {{formGroup systemFields.damageThresholds.fields.major value=document._source.system.damageThresholds.major label=(localize "DAGGERHEART.GENERAL.DamageThresholds.majorThreshold")}} + {{formGroup systemFields.damageThresholds.fields.severe value=document._source.system.damageThresholds.severe label=(localize "DAGGERHEART.GENERAL.DamageThresholds.severeThreshold")}} +
    diff --git a/templates/sheets-settings/companion-settings/attack.hbs b/templates/sheets-settings/companion-settings/attack.hbs index 41451ef0..f99f7d8c 100644 --- a/templates/sheets-settings/companion-settings/attack.hbs +++ b/templates/sheets-settings/companion-settings/attack.hbs @@ -18,5 +18,5 @@ {{/if}} {{/if}} - {{> 'systems/daggerheart/templates/actionTypes/damage.hbs' fields=systemFields.attack.fields.damage.fields.parts.element.fields source=document.system.attack.damage path="system.attack." baseFields=systemFields.attack.fields.damage.fields}} + {{> 'systems/daggerheart/templates/actionTypes/damage.hbs' fields=systemFields.attack.fields.damage.fields.parts.element.fields source=document.system.attack.damage path="system.attack." directField=systemFields.attack.fields.damage.fields.direct}} \ No newline at end of file diff --git a/templates/sheets-settings/npc-settings/details.hbs b/templates/sheets-settings/npc-settings/details.hbs deleted file mode 100644 index 0e18b488..00000000 --- a/templates/sheets-settings/npc-settings/details.hbs +++ /dev/null @@ -1,13 +0,0 @@ -
    -
    - {{localize "DAGGERHEART.GENERAL.description"}} - {{formInput systemFields.description value=document._source.system.description}} -
    - - {{formGroup systemFields.motives value=document._source.system.motives}} - {{formGroup systemFields.difficulty value=document._source.system.difficulty localize=true}} -
    diff --git a/templates/sheets-settings/npc-settings/features.hbs b/templates/sheets-settings/npc-settings/features.hbs deleted file mode 100644 index 2f2f5f47..00000000 --- a/templates/sheets-settings/npc-settings/features.hbs +++ /dev/null @@ -1,29 +0,0 @@ -
    - -
    - {{localize tabs.features.label}} -
      - {{#each @root.features as |feature|}} -
    • - -
      - {{feature.name}} -
      -
      - - -
      -
    • - {{/each}} -
    -
    - {{localize "DAGGERHEART.GENERAL.dropFeaturesHere"}} -
    -
    -
    \ No newline at end of file diff --git a/templates/sheets-settings/npc-settings/header.hbs b/templates/sheets-settings/npc-settings/header.hbs deleted file mode 100644 index c9cb60fe..00000000 --- a/templates/sheets-settings/npc-settings/header.hbs +++ /dev/null @@ -1,3 +0,0 @@ -
    -

    {{document.name}}

    -
    \ No newline at end of file diff --git a/templates/sheets-settings/token-config/appearance.hbs b/templates/sheets-settings/token-config/appearance.hbs index 76ba255d..abdb49c2 100644 --- a/templates/sheets-settings/token-config/appearance.hbs +++ b/templates/sheets-settings/token-config/appearance.hbs @@ -1,43 +1,20 @@
    -
    - {{formGroup fields.texture.fields.src value=source.texture.src rootId=rootId}} - {{#if randomImgEnabled}} - {{formGroup fields.randomImg value=source.randomImg classes="slim" rootId=rootId}} - {{else if hasAlternates}} -
    - - -
    - {{/if}} - - {{#if imagePreview}} -
    - {{#if imagePreview.isVideo}} - - {{else}} - {{localize - {{/if}} -
    - - {{imagePreview.current}} / {{imagePreview.total}} - -
    -
    - {{/if}} + {{formGroup fields.texture.fields.src value=source.texture.src rootId=rootId}} + {{#if randomImgEnabled}} + {{formGroup fields.randomImg value=source.randomImg classes="slim" rootId=rootId}} + {{else if hasAlternates}} +
    + +
    - + {{/if}}
    - {{localize "DAGGERHEART.APPLICATIONS.TokenConfig.tokenSize"}} + {{localize "Token Size"}} {{#if usesActorSize}} -
    - +
    + -
    -
    - -
    -
    - {{formInput fields.value name=change.valuePath value=change.value elementType="input"}} -
    -
    - {{formInput fields.priority name=change.priorityPath value=change.priority placeholder=defaultPriority}} -
    -
    - -
    - diff --git a/templates/sheets/activeEffect/changes.hbs b/templates/sheets/activeEffect/changes.hbs index 37feb845..75f49e4a 100644 --- a/templates/sheets/activeEffect/changes.hbs +++ b/templates/sheets/activeEffect/changes.hbs @@ -1,27 +1,31 @@
    -
    {{localize "EFFECT.FIELDS.changes.element.key.label"}}
    -
    {{localize "EFFECT.FIELDS.changes.element.type.label"}}
    -
    {{localize "EFFECT.FIELDS.changes.element.value.label"}}
    -
    {{localize "EFFECT.FIELDS.changes.element.priority.label"}}
    -
    - -
    +
    {{localize "EFFECT.ChangeKey"}}
    +
    {{localize "EFFECT.ChangeMode"}}
    +
    {{localize "EFFECT.ChangeValue"}}
    +
    {{localize "EFFECT.ChangePriority"}}
    +
      - {{#each changes as |change|}} - {{{change}}} + {{#each source.changes as |change i|}} + {{#with ../fields.changes.element.fields as |changeFields|}} +
    1. +
      + +
      +
      + {{formInput changeFields.mode name=(concat "changes." i ".mode") value=change.mode choices=@root.modes}} +
      +
      + {{formInput changeFields.value name=(concat "changes." i ".value") value=change.value}} +
      +
      + {{formInput changeFields.priority name=(concat "changes." i ".priority") value=change.priority + placeholder=(lookup ../../priorities change.mode)}} +
      +
      +
    2. + {{/with}} {{/each}}
    - -
    - - {{localize "DAGGERHEART.GENERAL.armor"}} - - - - {{#if typedChanges.armor}} - {{> "systems/daggerheart/templates/sheets/activeEffect/typeChanges/armorChange.hbs" typedChanges.armor fields=@root.systemFields.changes.element.types.armor.fields}} - {{/if}} -
    -
    + \ No newline at end of file diff --git a/templates/sheets/activeEffect/details.hbs b/templates/sheets/activeEffect/details.hbs index 8ab4b5cf..22c95a1e 100644 --- a/templates/sheets/activeEffect/details.hbs +++ b/templates/sheets/activeEffect/details.hbs @@ -2,14 +2,14 @@ {{formGroup fields.tint value=source.tint rootId=rootId placeholder="#ffffff"}} {{formGroup fields.description value=source.description rootId=rootId}} {{formGroup fields.disabled value=source.disabled rootId=rootId}} - {{formGroup systemFields.targetDispositions value=source.system.targetDispositions name=(concat "system.targetDispositions") localize=true}} {{#if isActorEffect}} {{formGroup fields.origin value=source.origin rootId=rootId disabled=true}} - {{else if isItemEffect}} - {{formGroup fields.transfer value=source.transfer rootId=rootId}} + {{/if}} + + {{#if isItemEffect}} + {{formGroup fields.transfer value=source.transfer rootId=rootId label=legacyTransfer.label hint=(localize "DAGGERHEART.EFFECTS.Attachments.transferHint")}} {{/if}} {{formGroup fields.statuses value=source.statuses options=statuses rootId=rootId classes="statuses"}} - {{formGroup fields.showIcon value=source.showIcon options=showIconOptions rootId=rootId}} - \ No newline at end of file + diff --git a/templates/sheets/activeEffect/settings.hbs b/templates/sheets/activeEffect/settings.hbs index 09b78856..cf98c786 100644 --- a/templates/sheets/activeEffect/settings.hbs +++ b/templates/sheets/activeEffect/settings.hbs @@ -1,18 +1,4 @@
    -
    - - {{localize "DAGGERHEART.ACTIVEEFFECT.Config.stacking.title"}} - - - - {{#if source.system.stacking}} -
    - {{formGroup systemFields.stacking.fields.value value=source.system.stacking.value localize=true }} - {{formGroup systemFields.stacking.fields.max value=source.system.stacking.max localize=true }} -
    - {{/if}} -
    -
    {{localize "DAGGERHEART.ACTIVEEFFECT.Config.rangeDependence.title"}} @@ -21,31 +7,34 @@ {{formGroup systemFields.rangeDependence.fields.target value=source.system.rangeDependence.target localize=true }} {{formGroup systemFields.rangeDependence.fields.range value=source.system.rangeDependence.range localize=true }}
    +
    - {{localize "EFFECT.DURATION.Label"}} + {{formGroup fields.duration.fields.seconds value=source.duration.seconds rootId=rootId}} + {{formGroup fields.duration.fields.startTime value=source.duration.startTime rootId=rootId}} +
    - {{formGroup systemFields.duration.fields.type value=source.system.duration.type localize=true }} - -
    +
    +
    +
    - {{formInput systemFields.duration.fields.description value=source.system.duration.description localize=true }} + + {{formInput fields.duration.fields.rounds value=source.duration.rounds + id=(concat rootId "-duration.rounds")}} + + {{formInput fields.duration.fields.turns value=source.duration.turns + id=(concat rootId "-duration.turns")}}
    - -
    - {{formGroup fields.start.fields.time value=source.start.time localize=true }} -
    - -
    - {{formInput fields.duration.fields.value value=source.duration.value id=(concat rootId "-duration.value") - aria=(object label=(localize "EFFECT.FIELDS.duration.value.label"))}} - {{formInput fields.duration.fields.units value=source.duration.units id=(concat rootId "-duration.units") - options=durationUnits aria=(object label=(localize "EFFECT.FIELDS.duration.units.label")) localize=true }} -
    +
    + +
    + + {{formInput fields.duration.fields.startRound value=source.duration.startRound + id=(concat rootId "-duration.startRound")}} + + {{formInput fields.duration.fields.startTurn value=source.duration.startTurn + id=(concat rootId "-duration.startTurn")}}
    -
    \ No newline at end of file + diff --git a/templates/sheets/activeEffect/typeChanges/armorChange.hbs b/templates/sheets/activeEffect/typeChanges/armorChange.hbs deleted file mode 100644 index 662a1294..00000000 --- a/templates/sheets/activeEffect/typeChanges/armorChange.hbs +++ /dev/null @@ -1,28 +0,0 @@ -
    -
    {{localize "EFFECT.FIELDS.changes.element.value.label"}}
    -
    {{localize "DAGGERHEART.GENERAL.max"}}
    -
    {{localize "DAGGERHEART.EFFECTS.ChangeTypes.armor.FIELDS.interaction.label"}}
    -
    {{localize "EFFECT.FIELDS.changes.element.priority.label"}}
    -
    -
      -
    1. - - - {{formInput fields.value.fields.current name=(concat "system.changes." index ".value.current") value=value.current data-dtype="Number"}} - {{formInput fields.value.fields.max name=(concat "system.changes." index ".value.max") value=value.max data-dtype="Number"}} - {{formInput fields.value.fields.interaction name=(concat "system.changes." index ".value.interaction") value=value.interaction localize=true}} - {{formInput fields.priority name=(concat "system.changes." index ".priority") value=priority}} -
    2. -
    -
    -
    - {{localize "DAGGERHEART.GENERAL.DamageThresholds.title"}} - -
    - {{#if value.damageThresholds}} -
    - {{formGroup fields.value.fields.damageThresholds.fields.major name=(concat "system.changes." index ".value.damageThresholds.major") value=value.damageThresholds.major localize=true }} - {{formGroup fields.value.fields.damageThresholds.fields.severe name=(concat "system.changes." index ".value.damageThresholds.severe") value=value.damageThresholds.severe localize=true }} -
    - {{/if}} -
    \ No newline at end of file diff --git a/templates/sheets/actors/adversary/effects.hbs b/templates/sheets/actors/adversary/effects.hbs index 087e8b30..cefb6e57 100644 --- a/templates/sheets/actors/adversary/effects.hbs +++ b/templates/sheets/actors/adversary/effects.hbs @@ -6,7 +6,7 @@ type='effect' isGlassy=true collection=effects.actives - canCreate=@root.editable + canCreate=true hideResources=true }} @@ -15,7 +15,7 @@ type='effect' isGlassy=true collection=effects.inactives - canCreate=@root.editable + canCreate=true hideResources=true }}
    diff --git a/templates/sheets/actors/adversary/features.hbs b/templates/sheets/actors/adversary/features.hbs index 3b495e74..a24342fc 100644 --- a/templates/sheets/actors/adversary/features.hbs +++ b/templates/sheets/actors/adversary/features.hbs @@ -6,9 +6,8 @@ type='feature' collection=@root.features hideContextMenu=true - hideModifyControls=true - canCreate=@root.editable - showActions=@root.editable + canCreate=true + showActions=true }}
    \ No newline at end of file diff --git a/templates/sheets/actors/adversary/header.hbs b/templates/sheets/actors/adversary/header.hbs index 5adc235a..5bdfa421 100644 --- a/templates/sheets/actors/adversary/header.hbs +++ b/templates/sheets/actors/adversary/header.hbs @@ -1,14 +1,7 @@
    -

    {{source.name}}

    +

    {{source.name}}

    @@ -44,9 +37,10 @@
    - {{#> 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs'}} +
    + {{> 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs'}} - {{/ 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs'}} +
    \ No newline at end of file diff --git a/templates/sheets/actors/character/biography.hbs b/templates/sheets/actors/character/biography.hbs index 7da920e0..6f2fe8c1 100644 --- a/templates/sheets/actors/character/biography.hbs +++ b/templates/sheets/actors/character/biography.hbs @@ -4,7 +4,9 @@ data-group='{{tabs.biography.group}}' >
    -
    +
    + {{localize 'DAGGERHEART.ACTORS.Character.story.characteristics'}} +
    {{localize 'DAGGERHEART.ACTORS.Character.pronouns'}} {{formInput systemFields.biography.fields.characteristics.fields.pronouns value=source.system.biography.characteristics.pronouns enriched=source.system.biography.characteristics.pronouns localize=true toggled=true}} @@ -19,14 +21,14 @@ {{localize 'DAGGERHEART.ACTORS.Character.faith'}} {{formInput systemFields.biography.fields.characteristics.fields.faith value=source.system.biography.characteristics.faith enriched=source.system.biography.characteristics.faith localize=true toggled=true}}
    -
    + -
    +
    {{localize 'DAGGERHEART.ACTORS.Character.story.backgroundTitle'}} {{formInput background.field value=background.value enriched=background.enriched toggled=true}}
    -
    +
    {{localize 'DAGGERHEART.ACTORS.Character.story.connectionsTitle'}} {{formInput connections.field value=connections.value enriched=connections.enriched toggled=true}}
    diff --git a/templates/sheets/actors/character/effects.hbs b/templates/sheets/actors/character/effects.hbs index a2e5a420..30fb31f4 100644 --- a/templates/sheets/actors/character/effects.hbs +++ b/templates/sheets/actors/character/effects.hbs @@ -7,7 +7,7 @@ type='effect' isGlassy=true collection=effects.actives - canCreate=@root.editable + canCreate=true hideResources=true }} @@ -16,9 +16,8 @@ type='effect' isGlassy=true collection=effects.inactives - canCreate=@root.editable + canCreate=true hideResources=true - disabled=true }}
    \ No newline at end of file diff --git a/templates/sheets/actors/character/features.hbs b/templates/sheets/actors/character/features.hbs index b2760900..3e942468 100644 --- a/templates/sheets/actors/character/features.hbs +++ b/templates/sheets/actors/character/features.hbs @@ -2,25 +2,26 @@ data-group='{{tabs.features.group}}'>
    {{#each document.system.sheetLists as |category|}} - {{#if (eq category.type 'feature' )}} - {{> 'daggerheart.inventory-items' - title=category.title - type='feature' - actorType='character' - collection=category.values - canCreate=@root.editable - showActions=@root.editable - }} - {{else if category.values}} - {{> 'daggerheart.inventory-items' - title=category.title - type='feature' - actorType='character' - collection=category.values - canCreate=false - showActions=@root.editable - }} - {{/if}} + {{#if (eq category.type 'feature' )}} + {{> 'daggerheart.inventory-items' + title=category.title + type='feature' + actorType='character' + collection=category.values + canCreate=true + showActions=true + }} + {{else if category.values}} + {{> 'daggerheart.inventory-items' + title=category.title + type='feature' + actorType='character' + collection=category.values + canCreate=false + showActions=true + }} + + {{/if}} {{/each}}
    \ No newline at end of file diff --git a/templates/sheets/actors/character/header.hbs b/templates/sheets/actors/character/header.hbs index 459911af..06f464fa 100644 --- a/templates/sheets/actors/character/header.hbs +++ b/templates/sheets/actors/character/header.hbs @@ -1,39 +1,20 @@
    -

    {{source.name}}

    +

    {{source.name}}

    - {{#if @root.editable}} - {{#if document.system.needsCharacterSetup}} - - {{else if document.system.levelData.canLevelUp}} - - {{/if}} + {{#if (or document.system.needsCharacterSetup document.system.levelData.canLevelUp)}} + {{/if}} - {{#unless document.system.needsCharacterSetup}} - {{localize 'DAGGERHEART.GENERAL.level'}} - - {{/unless}} + {{localize 'DAGGERHEART.GENERAL.level'}} +

    @@ -64,7 +45,7 @@ {{/if}}
    - {{#if (or document.system.multiclass.value document.system.multiclass.subclass)}} + {{#if document.system.multiclass.value}}
    {{#if document.system.multiclass.value}} {{document.system.multiclass.value.name}} @@ -119,40 +100,31 @@ {{/if}} - {{#if @root.editable}} - - - {{/if}} + +
    {{#each this.attributes as |attribute key|}} -
    -
    -
    - {{attribute.label}} +
    +
    + {{localize (concat 'DAGGERHEART.CONFIG.Traits.' key '.short')}} + {{#if attribute.tierMarked}} + + {{else}} + + {{/if}}
    -
    - - - - -
    - {{#if (gt attribute.value 0)}} - +{{attribute.value}} - {{else}} - {{attribute.value}} - {{/if}} -
    - {{#if isSpellcasting}} -
    - -
    +
    + {{#if (gt attribute.value 0)}} + +{{attribute.value}} + {{else}} + {{attribute.value}} {{/if}}
    diff --git a/templates/sheets/actors/character/inventory.hbs b/templates/sheets/actors/character/inventory.hbs index c3ddb0ad..711d0c9f 100644 --- a/templates/sheets/actors/character/inventory.hbs +++ b/templates/sheets/actors/character/inventory.hbs @@ -13,7 +13,18 @@
    {{#if this.inventory.hasCurrency}} - {{> "systems/daggerheart/templates/sheets/global/partials/gold.hbs" currencies=inventory.currencies}} +
    + {{#each this.inventory.currencies as |currency key|}} + {{#if currency.enabled}} +
    + + {{localize currency.label}} + + +
    + {{/if}} + {{/each}} +
    {{/if}}
    @@ -22,7 +33,7 @@ type='weapon' collection=@root.inventory.weapons isGlassy=true - canCreate=@root.editable + canCreate=true hideResources=true }} {{> 'daggerheart.inventory-items' @@ -30,7 +41,7 @@ type='armor' collection=@root.inventory.armor isGlassy=true - canCreate=@root.editable + canCreate=true hideResources=true }} {{> 'daggerheart.inventory-items' @@ -38,17 +49,15 @@ type='consumable' collection=@root.inventory.consumables isGlassy=true - canCreate=@root.editable - isQuantifiable=true + canCreate=true }} {{> 'daggerheart.inventory-items' title='TYPES.Item.loot' type='loot' collection=@root.inventory.loot isGlassy=true - canCreate=@root.editable - showActions=@root.editable - isQuantifiable=true + canCreate=true + showActions=true }}
    \ No newline at end of file diff --git a/templates/sheets/actors/character/loadout.hbs b/templates/sheets/actors/character/loadout.hbs index 9ba3fb04..5e4c9f54 100644 --- a/templates/sheets/actors/character/loadout.hbs +++ b/templates/sheets/actors/character/loadout.hbs @@ -27,7 +27,7 @@ isGlassy=true cardView=cardView collection=document.system.domainCards.loadout - canCreate=@root.editable + canCreate=true }} {{> 'daggerheart.inventory-items' title='DAGGERHEART.GENERAL.Tabs.vault' @@ -35,7 +35,7 @@ isGlassy=true cardView=cardView collection=document.system.domainCards.vault - canCreate=@root.editable + canCreate=true inVault=true }}
    diff --git a/templates/sheets/actors/character/sidebar.hbs b/templates/sheets/actors/character/sidebar.hbs index 313c81f9..b2757b55 100644 --- a/templates/sheets/actors/character/sidebar.hbs +++ b/templates/sheets/actors/character/sidebar.hbs @@ -1,6 +1,17 @@
    - {{#if document.system.armorScore.max}} + {{#if document.system.armor.system.marks}} {{else}} @@ -97,16 +104,18 @@
      {{#if document.system.usedUnarmed}} - {{> 'daggerheart.inventory-item-compact' - item=document.system.usedUnarmed - type='attack' - }} + {{> 'daggerheart.inventory-item-compact' + item=document.system.usedUnarmed + type='attack' + }} + {{/if}} + {{#each document.items as |item|}} + {{#if item.system.equipped}} + {{> 'daggerheart.inventory-item-compact' + item=item + type=item.type + }} {{/if}} - {{#each equippedItems as |item|}} - {{> 'daggerheart.inventory-item-compact' - item=item - type=item.type - }} {{/each}}
    diff --git a/templates/sheets/actors/companion/effects.hbs b/templates/sheets/actors/companion/effects.hbs index 087e8b30..cefb6e57 100644 --- a/templates/sheets/actors/companion/effects.hbs +++ b/templates/sheets/actors/companion/effects.hbs @@ -6,7 +6,7 @@ type='effect' isGlassy=true collection=effects.actives - canCreate=@root.editable + canCreate=true hideResources=true }} @@ -15,7 +15,7 @@ type='effect' isGlassy=true collection=effects.inactives - canCreate=@root.editable + canCreate=true hideResources=true }} diff --git a/templates/sheets/actors/companion/header.hbs b/templates/sheets/actors/companion/header.hbs index 9c324709..8b63e396 100644 --- a/templates/sheets/actors/companion/header.hbs +++ b/templates/sheets/actors/companion/header.hbs @@ -6,8 +6,6 @@ name='name' value='{{document.name}}' placeholder='{{localize "DAGGERHEART.GENERAL.actorName"}}' - autocomplete="off" - spellcheck="false" /> {{#if useResourcePips}} @@ -50,10 +48,9 @@
    - {{#> 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs'}} - - {{/ 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs'}} + {{> 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs'}} +
    \ No newline at end of file diff --git a/templates/sheets/actors/environment/features.hbs b/templates/sheets/actors/environment/features.hbs index 35fcb038..3ad36023 100644 --- a/templates/sheets/actors/environment/features.hbs +++ b/templates/sheets/actors/environment/features.hbs @@ -9,9 +9,8 @@ type='feature' collection=@root.features hideContextMenu=true - hideModifyControls=true - canCreate=@root.editable - showActions=@root.editable + canCreate=true + showActions=true }} \ No newline at end of file diff --git a/templates/sheets/actors/environment/header.hbs b/templates/sheets/actors/environment/header.hbs index 1b4073c7..b7eab3db 100644 --- a/templates/sheets/actors/environment/header.hbs +++ b/templates/sheets/actors/environment/header.hbs @@ -1,7 +1,28 @@
    -

    +
    +

    +
    +
    +
    + + {{localize (concat 'DAGGERHEART.GENERAL.Tiers.' source.system.tier)}} + +
    + {{#if source.system.type}} +
    + + {{localize (concat 'DAGGERHEART.CONFIG.EnvironmentType.' source.system.type '.label')}} + +
    + {{/if}} +
    + {{#if (and showAttribution document.system.attributionLabel)}} + + {{/if}} +
    +
    {{#if source.system.difficulty}} @@ -14,25 +35,6 @@

    {{localize "DAGGERHEART.GENERAL.difficulty"}}

    -
    -
    -
    - - {{localize (concat 'DAGGERHEART.GENERAL.Tiers.' source.system.tier)}} - -
    - {{#if source.system.type}} -
    - - {{localize (concat 'DAGGERHEART.CONFIG.EnvironmentType.' source.system.type '.label')}} - -
    - {{/if}} -
    - {{#if (and showAttribution document.system.attributionLabel)}} - - {{/if}} -
    @@ -44,10 +46,9 @@
    - {{#> 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs'}} - - {{/ 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs'}} + {{> 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs'}} +
    \ No newline at end of file diff --git a/templates/sheets/actors/npc/features.hbs b/templates/sheets/actors/npc/features.hbs deleted file mode 100644 index 3b495e74..00000000 --- a/templates/sheets/actors/npc/features.hbs +++ /dev/null @@ -1,14 +0,0 @@ -
    -
    - {{> 'daggerheart.inventory-items' - title=tabs.features.label - type='feature' - collection=@root.features - hideContextMenu=true - hideModifyControls=true - canCreate=@root.editable - showActions=@root.editable - }} -
    -
    \ No newline at end of file diff --git a/templates/sheets/actors/npc/header.hbs b/templates/sheets/actors/npc/header.hbs deleted file mode 100644 index fce300da..00000000 --- a/templates/sheets/actors/npc/header.hbs +++ /dev/null @@ -1,42 +0,0 @@ -
    -
    - {{source.name}} -
    -
    - - -
    -

    {{source.name}}

    -
    - - {{#if source.system.difficulty}} -
    -
    - {{localize "DAGGERHEART.GENERAL.difficulty"}} - {{source.system.difficulty}} -
    -
    - {{/if}} - - - -
    - - {{{description}}} - - {{#if source.system.motives}} -
    - {{localize 'DAGGERHEART.ACTORS.NPC.FIELDS.motives.label'}}: - {{source.system.motives}} -
    - {{/if}} -
    -
    -
    \ No newline at end of file diff --git a/templates/sheets/actors/npc/navigation.hbs b/templates/sheets/actors/npc/navigation.hbs deleted file mode 100644 index ae684f0d..00000000 --- a/templates/sheets/actors/npc/navigation.hbs +++ /dev/null @@ -1,7 +0,0 @@ -
    - {{#> 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs'}} - - {{/'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs'}} -
    \ No newline at end of file diff --git a/templates/sheets/actors/npc/notes.hbs b/templates/sheets/actors/npc/notes.hbs deleted file mode 100644 index bc9ac3cf..00000000 --- a/templates/sheets/actors/npc/notes.hbs +++ /dev/null @@ -1,11 +0,0 @@ -
    - {{formInput notes.field value=notes.value enriched=notes.enriched toggled=true}} - - {{#if (and showAttribution document.system.attribution.artist)}} - - {{/if}} -
    \ No newline at end of file diff --git a/templates/sheets/actors/party/header.hbs b/templates/sheets/actors/party/header.hbs index efa6e5b8..f39f683f 100644 --- a/templates/sheets/actors/party/header.hbs +++ b/templates/sheets/actors/party/header.hbs @@ -2,7 +2,8 @@
    - +

    +

    Party

    \ No newline at end of file diff --git a/templates/sheets/actors/party/inventory.hbs b/templates/sheets/actors/party/inventory.hbs index cf056608..186e2e99 100644 --- a/templates/sheets/actors/party/inventory.hbs +++ b/templates/sheets/actors/party/inventory.hbs @@ -16,7 +16,18 @@ {{#if inventory.hasCurrency}} - {{> "systems/daggerheart/templates/sheets/global/partials/gold.hbs" currencies=inventory.currencies}} +
    + {{#each this.inventory.currencies as |currency key|}} + {{#if currency.enabled}} +
    + + {{localize currency.label}} + + +
    + {{/if}} + {{/each}} +
    {{/if}}
    @@ -26,10 +37,9 @@ actorType='party' collection=@root.inventory.weapons isGlassy=true - canCreate=@root.editable + canCreate=true hideResources=true hideContextMenu=true - isQuantifiable=true }} {{> 'daggerheart.inventory-items' title='TYPES.Item.armor' @@ -37,10 +47,9 @@ actorType='party' collection=@root.inventory.armor isGlassy=true - canCreate=@root.editable + canCreate=true hideResources=true hideContextMenu=true - isQuantifiable=true }} {{> 'daggerheart.inventory-items' title='TYPES.Item.consumable' @@ -48,9 +57,8 @@ actorType='party' collection=@root.inventory.consumables isGlassy=true - canCreate=@root.editable + canCreate=true hideContextMenu=true - isQuantifiable=true }} {{> 'daggerheart.inventory-items' title='TYPES.Item.loot' @@ -58,9 +66,8 @@ actorType='party' collection=@root.inventory.loot isGlassy=true - canCreate=@root.editable + canCreate=true hideContextMenu=true - isQuantifiable=true }}
    \ No newline at end of file diff --git a/templates/sheets/actors/party/party-members.hbs b/templates/sheets/actors/party/party-members.hbs index 55cacb79..84e0cddf 100644 --- a/templates/sheets/actors/party/party-members.hbs +++ b/templates/sheets/actors/party/party-members.hbs @@ -5,187 +5,37 @@ >
    - - - - + {{!-- NOT YET IMPLEMENTED --}} + {{!-- --}}
    - {{#if @root.showStats}} +
    + {{localize tabs.partyMembers.label}}
      - {{#each partyMembers as |member id|}} -
    • -
      - - {{#if member.weapons}} -
      - {{#each member.weapons as |weapon|}} - - {{/each}} -
      - {{/if}} - {{#if member.evasion includeZero=true}} -
      {{member.evasion}}
      - {{/if}} - {{#if member.difficulty includeZero=true}} -
      {{member.difficulty}}
      - {{/if}} - {{#unless (or (eq member.type 'companion') (eq member.type 'npc'))}} -
      -

      {{localize "DAGGERHEART.ACTORS.Party.Thresholds.minor"}}

      -

      {{member.damageThresholds.major}}

      -

      {{localize "DAGGERHEART.ACTORS.Party.Thresholds.major"}}

      -

      {{member.damageThresholds.severe}}

      -

      {{localize "DAGGERHEART.ACTORS.Party.Thresholds.severe"}}

      -
      - {{/unless}} -
      -
      -

      - {{member.name}} - -

      -
      - {{#unless (or (eq member.type 'companion') (eq member.type 'adversary') (eq member.type 'npc')) }} -
      -

      {{localize "DAGGERHEART.GENERAL.hope"}}

      - {{#times member.resources.hope.max}} - - {{#if (gte member.resources.hope.value (add this 1))}} - - {{else}} - - {{/if}} - - {{/times}} -
      - {{/unless}} -
      - {{#if member.subtitle}} - {{member.subtitle}} - {{/if}} -
      -
      -
      - {{#unless (or (eq member.type 'companion') (eq member.type 'npc')) }} -
      -
      - - - - - {{member.resources.hitPoints.value}} - / - {{member.resources.hitPoints.max}} - -
      -
      - {{#times member.resources.hitPoints.max}} - - - {{/times}} -
      -
      - {{/unless}} - - {{#unless (eq member.type 'npc')}} -
      -
      - - - - - {{member.resources.stress.value}} - / - {{member.resources.stress.max}} - -
      -
      - {{#times member.resources.stress.max}} - - - {{/times}} -
      -
      - {{/unless}} - - {{#if member.armorScore.max}} -
      -
      - - - - - {{member.armorScore.value}} - / - {{member.armorScore.max}} - -
      - -
      - {{/if}} -
      - {{#if member.traits}} -
      - {{#each member.traits as |trait|}} - - {{trait.label}} - {{trait.value}} - - {{/each}} -
      - {{/if}} -
      -
    • + {{#each document.system.partyMembers as |actor id|}} + {{> 'daggerheart.inventory-item' + item=actor + type='character' + isActor=true + hideContextMenu=true + }} {{/each}}
    - {{else}} -
      - {{#each partyMembers as |member id|}} -
    • -
      - -
      -
      -

      - {{member.name}} - -

      - {{#if member.subtitle}} - {{member.subtitle}} - {{/if}} -
      -
    • - {{/each}} -
    - {{/if}} - {{#unless document.system.partyMembers.length}} -
    - {{localize "DAGGERHEART.GENERAL.dropActorsHere"}} -
    - {{/unless}} - + {{#unless document.system.partyMembers.length}} +
    + {{localize "DAGGERHEART.GENERAL.dropActorsHere"}} +
    + {{/unless}} +
    + \ No newline at end of file diff --git a/templates/sheets/actors/party/resources.hbs b/templates/sheets/actors/party/resources.hbs new file mode 100644 index 00000000..74f94806 --- /dev/null +++ b/templates/sheets/actors/party/resources.hbs @@ -0,0 +1,105 @@ +
    +
    + + +
    + +
    + {{localize tabs.resources.label}} +
      + {{#each document.system.partyMembers as |actor id|}} +
    • +

      {{actor.name}}

      + +
      + {{#unless (eq actor.type 'companion') }} +
      +
      + {{#times actor.system.resources.hitPoints.max}} + + + {{/times}} +
      +
      + {{localize "DAGGERHEART.GENERAL.HitPoints.short"}} + {{actor.system.resources.hitPoints.value}} / {{actor.system.resources.hitPoints.max}} +
      +
      + {{/unless}} + +
      +
      + {{#times actor.system.resources.stress.max}} + + + {{/times}} +
      +
      + {{localize "DAGGERHEART.GENERAL.stress"}} + {{actor.system.resources.stress.value}} / {{actor.system.resources.stress.max}} +
      +
      + + {{#if actor.system.armor.system.marks}} +
      + +
      + {{localize "DAGGERHEART.GENERAL.armorSlots"}} + {{actor.system.armor.system.marks.value}} / {{actor.system.armorScore}} +
      +
      + {{/if}} + + {{#unless (or (eq actor.type 'companion') (eq actor.type 'adversary')) }} +
      +

      {{localize "DAGGERHEART.GENERAL.hope"}}

      + {{#times actor.system.resources.hope.max}} + + {{#if (gte actor.system.resources.hope.value (add this 1))}} + + {{else}} + + {{/if}} + + {{/times}} +
      + {{/unless}} + + {{#unless (eq actor.type 'companion')}} +
      +

      {{localize "DAGGERHEART.GENERAL.DamageThresholds.minor"}}

      +

      {{actor.system.damageThresholds.major}}

      +

      {{localize "DAGGERHEART.GENERAL.DamageThresholds.major"}}

      +

      {{actor.system.damageThresholds.severe}}

      +

      {{localize "DAGGERHEART.GENERAL.DamageThresholds.severe"}}

      +
      + {{/unless}} +
      +
    • + {{/each}} +
    +
    +
    \ No newline at end of file diff --git a/templates/sheets/global/partials/gold.hbs b/templates/sheets/global/partials/gold.hbs deleted file mode 100644 index 7aba2815..00000000 --- a/templates/sheets/global/partials/gold.hbs +++ /dev/null @@ -1,12 +0,0 @@ -
    - {{#each currencies as |currency key|}} - {{#if currency.enabled}} -
    - - {{localize currency.label}} - - -
    - {{/if}} - {{/each}} -
    \ No newline at end of file diff --git a/templates/sheets/global/partials/inventory-fieldset-items-V2.hbs b/templates/sheets/global/partials/inventory-fieldset-items-V2.hbs index db2fb6b7..31c8f7f5 100644 --- a/templates/sheets/global/partials/inventory-fieldset-items-V2.hbs +++ b/templates/sheets/global/partials/inventory-fieldset-items-V2.hbs @@ -19,8 +19,6 @@ Parameters: - showLabels {boolean} : If true, show label-tags else show simple tags. - hideTooltip {boolean} : If true, disables the tooltip on the item image. - hideControls {boolean} : If true, hides the controls inside inventory-item partials. -- hideContextMenu {boolean}: If true, hides the context menu dropdown button -- hideModifyControls {boolean}: If true, hides the edit and delete options - hideDescription {boolean} : If true, hides the item's description. - hideResources {boolean} : If true, hides the item's resources. - showActions {boolean} : If true show feature's actions. @@ -54,21 +52,20 @@ Parameters: {{else}}
      {{#each collection as |item|}} + {{> 'daggerheart.inventory-item' item=item type=../type disabledEffect=../disabledEffect - actorType=(ifThen ../actorType ../actorType @root.document.type) + actorType=../actorType hideControls=../hideControls hideContextMenu=../hideContextMenu - hideModifyControls=../hideModifyControls isActor=../isActor categoryAdversary=../categoryAdversary hideTooltip=../hideTooltip showLabels=../showLabels isAction=../isAction hideResources=../hideResources - isQuantifiable=../isQuantifiable showActions=../showActions }} diff --git a/templates/sheets/global/partials/inventory-item-V2.hbs b/templates/sheets/global/partials/inventory-item-V2.hbs index 523e9304..a758a28f 100644 --- a/templates/sheets/global/partials/inventory-item-V2.hbs +++ b/templates/sheets/global/partials/inventory-item-V2.hbs @@ -12,14 +12,12 @@ Parameters: - hideTags {boolean} : If true, hide simple-tags else show simple-tags. - hideTooltip {boolean} : If true, disables the tooltip on the item image. - hideControls {boolean} : If true, hides the controls inside inventory-item partials. -- hideContextMenu {boolean}: If true, hides the context menu dropdown button -- hideModifyControls {boolean}: If true, hides the edit and delete options (todo: swap to show, only party cares to show this) - hideDescription {boolean} : If true, hides the item's description. - hideResources {boolean} : If true, hides the item's resources. - showActions {boolean} : If true show feature's actions. --}} -
    • {{!-- Image --}} -
      - {{#if item.usable}} + {{#if (or item.system.actionsList.size item.system.actionsList.length item.actionType)}} {{#if @root.isNPC}} d20 {{else}} @@ -65,71 +63,74 @@ Parameters: {{#if (and (not hideResources) (not (eq item.system.resource.type 'diceValue')))}} {{> "systems/daggerheart/templates/sheets/global/partials/item-resource.hbs"}} {{/if}} - {{#if (or isQuantifiable (or (eq item.system.quantity 0) (gt item.system.quantity 1)))}} -
      - -
      + {{#if (and (not hideResources) (gte item.system.quantity 0))}} +
      + +
      {{/if}} {{!-- Controls --}} {{#unless hideControls}} -
      - {{!-- Toggle/Equip buttons --}} - {{#if @root.editable}} - {{#if (and (eq actorType 'character') (eq type 'weapon'))}} - - - - {{/if}} - {{#if (and (eq actorType 'character') (eq type 'armor'))}} - - - - {{/if}} - {{#if (and (eq type 'domainCard'))}} - - - - {{/if}} - {{#if (and (and (eq type 'effect') (not (eq item.type 'beastform'))))}} - - - - {{/if}} - {{/if}} - - {{!-- Send to Chat --}} - {{#if (hasProperty item "toChat")}} - - - - {{/if}} - - {{!-- Document management buttons or context menu --}} - {{#if (and (not isActor) (not hideContextMenu))}} - - - - {{else if (and @root.editable (not hideModifyControls))}} - - - - {{#if (not isActor)}} - - - - {{else if (eq type 'adversary')}} - - - - {{/if}} - {{/if}} -
      - {{/unless}} +
      + {{#if isActor}} + + + + {{#if (eq type 'adversary')}} + + + + {{/if}} + {{#if (eq type 'character')}} + + + + {{/if}} + {{else}} + {{#unless (eq actorType 'party')}} + {{#if (eq type 'weapon')}} + + + + {{else if (eq type 'armor')}} + + + + {{/if}} + {{#if (eq type 'domainCard')}} + + + + {{else if (and (eq type 'effect') (not (eq item.type 'beastform')))}} + + + + {{/if}} + {{#if (hasProperty item "toChat")}} + + + + {{/if}} + {{else}} + + + + + + + {{/unless}} + {{#unless hideContextMenu}} + + + + {{/unless}} + {{/if}} +
      + {{/unless}}
      {{!-- Description --}} diff --git a/templates/sheets/global/partials/inventory-item-compact.hbs b/templates/sheets/global/partials/inventory-item-compact.hbs index 78eaf087..bbdf9116 100644 --- a/templates/sheets/global/partials/inventory-item-compact.hbs +++ b/templates/sheets/global/partials/inventory-item-compact.hbs @@ -5,7 +5,7 @@ (hasProperty item "toChat" ) "toChat" "editDoc" ) }}' {{#unless hideTooltip}} {{#if (eq type 'attack' )}} data-tooltip="#attack#{{item.actor.uuid}}" {{else}} data-tooltip="#item#{{item.uuid}}" {{/if}} {{/unless}}> - {{#if item.usable}} + {{#if (or item.system.actionsList.size item.system.actionsList.length item.actionType)}} {{#if @root.isNPC}} d20 {{else}} @@ -48,28 +48,26 @@ {{/if}} {{else}} - {{#if @root.editable}} - {{#if (eq type 'weapon')}} - - - - {{else if (eq type 'armor')}} - - - - {{else if (eq type 'domainCard')}} - - - - {{else if (eq type 'effect')}} - - - - {{/if}} + {{#if (eq type 'weapon')}} + + + + {{else if (eq type 'armor')}} + + + + {{else if (eq type 'domainCard')}} + + + + {{else if (eq type 'effect')}} + + + {{/if}} {{#if (hasProperty item "toChat")}} diff --git a/templates/sheets/global/tabs/tab-actions.hbs b/templates/sheets/global/tabs/tab-actions.hbs index 8799f4d0..584cf782 100644 --- a/templates/sheets/global/tabs/tab-actions.hbs +++ b/templates/sheets/global/tabs/tab-actions.hbs @@ -8,6 +8,6 @@ title='DAGGERHEART.GENERAL.Action.plural' collection=document.system.actions type='action' - canCreate=@root.editable + canCreate=true }} \ No newline at end of file diff --git a/templates/sheets/global/tabs/tab-effects.hbs b/templates/sheets/global/tabs/tab-effects.hbs index 2dd540ef..1f0967b8 100644 --- a/templates/sheets/global/tabs/tab-effects.hbs +++ b/templates/sheets/global/tabs/tab-effects.hbs @@ -6,7 +6,7 @@ type='effect' isGlassy=true collection=effects.actives - canCreate=@root.editable + canCreate=true hideResources=true }} @@ -16,7 +16,7 @@ disabledEffect=true isGlassy=true collection=effects.inactives - canCreate=@root.editable + canCreate=true hideResources=true }} \ No newline at end of file diff --git a/templates/sheets/global/tabs/tab-navigation.hbs b/templates/sheets/global/tabs/tab-navigation.hbs index 8af1f140..f9a31d3e 100755 --- a/templates/sheets/global/tabs/tab-navigation.hbs +++ b/templates/sheets/global/tabs/tab-navigation.hbs @@ -4,7 +4,7 @@ {{/if}} - {{!-- Encounter Name --}} - {{#if combat.name}} -

      {{ combat.name }}

      - {{/if}} -
      {{!-- Combat Status --}} diff --git a/templates/ui/combatTracker/combatTrackerSection.hbs b/templates/ui/combatTracker/combatTrackerSection.hbs index ac759dfe..cf3ca422 100644 --- a/templates/ui/combatTracker/combatTrackerSection.hbs +++ b/templates/ui/combatTracker/combatTrackerSection.hbs @@ -13,20 +13,20 @@
      {{#if @root.user.isGM}} + data-action="toggleHidden" data-tooltip aria-label="{{ localize "COMBAT.ToggleVis" }}"> + aria-label="{{ localize "COMBAT.ToggleDead" }}"> {{/if}} {{#if canPing}} + aria-label="{{ localize "COMBAT.PingCombatant" }}"> {{/if}} {{#unless @root.user.isGM}} + aria-label="{{ localize "COMBAT.PanToCombatant" }}"> {{/unless}}
      diff --git a/templates/ui/countdowns.hbs b/templates/ui/countdowns.hbs index faaffdc5..18694e49 100644 --- a/templates/ui/countdowns.hbs +++ b/templates/ui/countdowns.hbs @@ -1,30 +1,18 @@
      -
      - - {{localize "DAGGERHEART.UI.Countdowns.title"}} - - - - - - -
      {{#each countdowns as | countdown id |}} -
      +
      - {{#unless ../iconOnly}} -
      {{countdown.name}}
      - {{/unless}} + {{#unless ../iconOnly}}{{/unless}}
      - {{#if countdown.editable}}{{/if}} + {{#if countdown.editable}}{{/if}}
      {{countdown.progress.current}}/{{countdown.progress.start}}
      - {{#if countdown.editable}}{{/if}} + {{#if countdown.editable}}{{/if}}
      {{#if (not ../iconOnly)}} @@ -33,7 +21,7 @@ {{/if}} {{#unless (eq countdown.progress.looping "noLooping")}} - + {{#if (eq countdown.progress.looping "increasing")}} diff --git a/templates/ui/effects-display.hbs b/templates/ui/effects-display.hbs index 67c783a6..95c6023c 100644 --- a/templates/ui/effects-display.hbs +++ b/templates/ui/effects-display.hbs @@ -8,9 +8,6 @@ - {{#if (gt effect.system.stacking.value 1)}} - {{effect.system.stacking.value}} - {{/if}} {{#if effect.condition}}{{/if}} {{/each}} diff --git a/templates/ui/itemBrowser/itemContainer.hbs b/templates/ui/itemBrowser/itemContainer.hbs index a5f067e8..8dd75156 100644 --- a/templates/ui/itemBrowser/itemContainer.hbs +++ b/templates/ui/itemBrowser/itemContainer.hbs @@ -1,7 +1,7 @@ {{#each items}}
      -
      +
      {{name}} {{#each ../menu.data.columns}} @@ -9,13 +9,11 @@ {{/each}}
      - {{#unless viewSheet}} -
      - - {{{system.enrichedTags}}} - {{{system.enrichedDescription}}} - -
      - {{/unless}} +
      + + {{{system.enrichedTags}}} + {{{system.enrichedDescription}}} + +
      {{/each}} \ No newline at end of file diff --git a/templates/ui/sceneNavigation/scene-navigation.hbs b/templates/ui/sceneNavigation/scene-navigation.hbs index 1b65c289..0bd59465 100644 --- a/templates/ui/sceneNavigation/scene-navigation.hbs +++ b/templates/ui/sceneNavigation/scene-navigation.hbs @@ -1,65 +1,40 @@ - - - -{{#*inline ".scene"}} -
    • -
      - {{ name }} - {{#if users}} -
        - {{#each users}} -
      • {{ letter }}
      • - {{/each}} -
      - {{/if}} -
      - {{#if hasEnvironments}} - - {{/if}} -
    • -{{/inline}} - diff --git a/templates/ui/sidebar/actor-document-partial.hbs b/templates/ui/sidebar/actor-document-partial.hbs index 1bd3ff9a..ec261f85 100644 --- a/templates/ui/sidebar/actor-document-partial.hbs +++ b/templates/ui/sidebar/actor-document-partial.hbs @@ -6,8 +6,6 @@ {{name}} {{#if (or (eq type "adversary") (eq type "environment"))}} {{localize "DAGGERHEART.UI.Sidebar.actorDirectory.tier" tier=system.tier type=(@root.getTypeLabel this)}} - {{else if (eq type "npc")}} - {{localize "TYPES.Actor.npc"}} {{else if (eq type "character")}} {{localize "DAGGERHEART.UI.Sidebar.actorDirectory.character" level=system.levelData.level.current}} {{else if (eq type "companion")}} @@ -16,10 +14,6 @@ {{else}} {{localize "DAGGERHEART.UI.Sidebar.actorDirectory.companionNoPartner"}} {{/if}} - {{else if (eq type "party")}} - {{#if system.active}} - {{localize "DAGGERHEART.UI.Sidebar.actorDirectory.partyIsActive"}} - {{/if}} {{/if}} diff --git a/templates/ui/tooltip/armorManagement.hbs b/templates/ui/tooltip/armorManagement.hbs deleted file mode 100644 index 963959c5..00000000 --- a/templates/ui/tooltip/armorManagement.hbs +++ /dev/null @@ -1,19 +0,0 @@ -
      -

      {{localize "DAGGERHEART.GENERAL.armorSlots"}}

      - {{#each sources as |source|}} -
      -

      {{source.name}}

      - -
      - {{/each}} -
      \ No newline at end of file diff --git a/templates/ui/tooltip/beastform.hbs b/templates/ui/tooltip/beastform.hbs index 3d07f78f..1b04ac82 100644 --- a/templates/ui/tooltip/beastform.hbs +++ b/templates/ui/tooltip/beastform.hbs @@ -3,7 +3,37 @@

      {{item.name}}

      {{item.system.examples}}

      - {{> "systems/daggerheart/templates/ui/tooltip/parts/beastformData.hbs" }} + {{#if description}} +
      {{{description}}}
      + {{/if}} + +
      + {{#with item.system.beastformAttackData}} +
      + {{localize "DAGGERHEART.ITEMS.Beastform.mainTrait"}} {{this.trait}} +
      +
      + {{localize "DAGGERHEART.ITEMS.Beastform.traitBonus"}} {{this.traitBonus}} +
      +
      + {{localize "DAGGERHEART.GENERAL.evasion"}} {{this.evasionBonus}} +
      +
      + {{localize "DAGGERHEART.GENERAL.damage"}} {{concat this.damageDice ' ' this.damageBonus}} +
      + {{/with}} +
      + +

      {{localize "DAGGERHEART.ITEMS.Beastform.FIELDS.advantageOn.label"}}

      +
      + {{#each item.system.advantageOn as | chip |}} +
      + {{ifThen chip.value chip.value chip}} +
      + {{/each}} +
      + + {{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.system.features label=(localize "DAGGERHEART.GENERAL.features")}}

      {{localize "DAGGERHEART.UI.Tooltip.middleClick"}} diff --git a/templates/ui/tooltip/effect-display.hbs b/templates/ui/tooltip/effect-display.hbs index f1db03c5..5ca4fec2 100644 --- a/templates/ui/tooltip/effect-display.hbs +++ b/templates/ui/tooltip/effect-display.hbs @@ -16,57 +16,9 @@ {{/if}} - {{#if effect.system.duration.type}} -

      -
      - {{localize "EFFECT.DURATION.Label"}}: - {{localize (concat "DAGGERHEART.CONFIG.ActiveEffectDuration." effect.system.duration.type )}} -
      -
      - {{/if}} - - {{#if effect.system.stacking}} -
      -
      {{localize "Stacks"}}
      -
      -
      - {{localize "Current"}} - {{effect.system.stacking.value}} -
      -
      - {{localize "Max"}} - {{effect.system.stacking.max}} -
      -
      -
      - {{/if}} - - -
      - {{#if (eq effect.type 'beastform')}} -

      - {{localize "DAGGERHEART.UI.Tooltip.middleClick"}} -

      - {{/if}} - {{#unless effect.isLockedCondition}} - {{#if effect.system.stacking}} -

      - {{localize "DAGGERHEART.UI.EffectsDisplay.increaseStacks"}} -

      - {{#if (gt effect.system.stacking.value 1)}} -

      - {{localize "DAGGERHEART.UI.EffectsDisplay.decreaseStacks"}} -

      - {{else}} -

      - {{localize "DAGGERHEART.UI.EffectsDisplay.removeThing" thing=(localize "DAGGERHEART.GENERAL.Effect.single")}} -

      - {{/if}} - {{else}} -

      - {{localize "DAGGERHEART.UI.EffectsDisplay.removeThing" thing=(localize "DAGGERHEART.GENERAL.Effect.single")}} -

      - {{/if}} - {{/unless}} -
      + {{#unless effect.isLockedCondition}} +

      + {{localize "DAGGERHEART.UI.EffectsDisplay.removeThing" thing=(localize "DAGGERHEART.GENERAL.Effect.single")}} +

      + {{/unless}} \ No newline at end of file diff --git a/templates/ui/tooltip/effect.hbs b/templates/ui/tooltip/effect.hbs index c5004a86..4430b91d 100644 --- a/templates/ui/tooltip/effect.hbs +++ b/templates/ui/tooltip/effect.hbs @@ -4,12 +4,4 @@ {{#if description}}
      {{{description}}}
      {{/if}} - {{#if item.system.duration.type}} -
      -
      - {{localize "EFFECT.DURATION.Label"}}: - {{localize (concat "DAGGERHEART.CONFIG.ActiveEffectDuration." item.system.duration.type )}} -
      -
      - {{/if}} \ No newline at end of file diff --git a/templates/ui/tooltip/parts/beastformData.hbs b/templates/ui/tooltip/parts/beastformData.hbs deleted file mode 100644 index 0473df40..00000000 --- a/templates/ui/tooltip/parts/beastformData.hbs +++ /dev/null @@ -1,31 +0,0 @@ -{{#if description}} -
      {{{description}}}
      -{{/if}} - -
      - {{#with item.system.beastformAttackData}} -
      - {{localize "DAGGERHEART.ITEMS.Beastform.mainTrait"}} {{this.trait}} -
      -
      - {{localize "DAGGERHEART.ITEMS.Beastform.traitBonus"}} {{this.traitBonus}} -
      -
      - {{localize "DAGGERHEART.GENERAL.evasion"}} {{this.evasionBonus}} -
      -
      - {{localize "DAGGERHEART.GENERAL.damage"}} {{concat this.damageDice ' ' this.damageBonus}} -
      - {{/with}} -
      - -

      {{localize "DAGGERHEART.ITEMS.Beastform.FIELDS.advantageOn.label"}}

      -
      - {{#each item.system.advantageOn as | chip |}} -
      - {{ifThen chip.value chip.value chip}} -
      - {{/each}} -
      - -{{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.system.features label=(localize "DAGGERHEART.GENERAL.features")}} \ No newline at end of file diff --git a/templates/ui/tooltip/parts/tooltipTags.hbs b/templates/ui/tooltip/parts/tooltipTags.hbs index da32723f..6a6d126d 100644 --- a/templates/ui/tooltip/parts/tooltipTags.hbs +++ b/templates/ui/tooltip/parts/tooltipTags.hbs @@ -1,5 +1,4 @@ {{#if (gt features.length 0)}}

      {{label}}

      {{/if}} -
      {{#each features as | feature |}} {{#with (ifThen ../isAction feature (ifThen feature.item feature.item feature))}} diff --git a/tools/analyze-damage.mjs b/tools/analyze-damage.mjs index 31c254ce..6d5da3de 100644 --- a/tools/analyze-damage.mjs +++ b/tools/analyze-damage.mjs @@ -5,41 +5,38 @@ * Maybe if future book monsters can be part of what we release, we can analyze those too. */ -import fs from 'fs/promises'; -import path from 'path'; +import fs from "fs/promises"; +import path from "path"; const allData = []; // Read adversary pack data for average damage for attacks -const adversariesDirectory = path.join('src/packs/adversaries'); +const adversariesDirectory = path.join("src/packs/adversaries"); for (const basefile of await fs.readdir(adversariesDirectory)) { - if (!basefile.endsWith('.json')) continue; + if (!basefile.endsWith(".json")) continue; const filepath = path.join(adversariesDirectory, basefile); - const data = JSON.parse(await fs.readFile(filepath, 'utf8')); - if (data?.type !== 'adversary' || data.system.type === 'social') continue; + const data = JSON.parse(await fs.readFile(filepath, "utf8")); + if (data?.type !== "adversary" || data.system.type === "social") continue; allData.push({ name: data.name, tier: data.system.tier, adversaryType: data.system.type, - damage: parseDamage(data.system.attack.damage) + damage: parseDamage(data.system.attack.damage), }); } const adversaryTypes = new Set(allData.map(a => a.adversaryType)); for (const type of [...adversaryTypes].toSorted()) { - const perTier = Object.groupBy( - allData.filter(a => a.adversaryType === type), - a => a.tier - ); - console.log(`${type} per Tier: ${[1, 2, 3, 4].map(t => perTier[t]?.length ?? 0).join(' ')}`); + const perTier = Object.groupBy(allData.filter(a => a.adversaryType === type), a => a.tier); + console.log(`${type} per Tier: ${[1, 2, 3, 4].map(t => perTier[t]?.length ?? 0).join(" ")}`) } const result = { - basic: compileData(allData.filter(d => d.adversaryType !== 'minion')), - solos_and_bruisers: compileData(allData.filter(d => ['solo', 'bruiser'].includes(d.adversaryType))), - leader_and_ranged: compileData(allData.filter(d => ['leader', 'ranged'].includes(d.adversaryType))), - minion: compileData(allData.filter(d => d.adversaryType === 'minion')) + basic: compileData(allData.filter(d => d.adversaryType !== "minion")), + solos_and_bruisers: compileData(allData.filter(d => ["solo", "bruiser"].includes(d.adversaryType))), + leader_and_ranged: compileData(allData.filter(d => ["leader", "ranged"].includes(d.adversaryType))), + minion: compileData(allData.filter(d => d.adversaryType === "minion")), }; console.log(result); @@ -55,7 +52,7 @@ function compileData(entries) { if (tier === 4) console.log(allDamage); results[tier] = { mean, - deviation: getStandardDeviation(allDamage, { mean }) + deviation: getStandardDeviation(allDamage, { mean }), }; } @@ -67,7 +64,7 @@ function removeOutliers(data) { const startIdx = Math.floor(data.length * 0.25); const endIdx = Math.ceil(data.length * 0.75); const iqrBound = (data[endIdx] - data[startIdx]) * 1.25; - return data.filter(d => d >= data[startIdx] - iqrBound && d <= data[endIdx] + iqrBound); + return data.filter((d) => d >= data[startIdx] - iqrBound && d <= data[endIdx] + iqrBound); } function getMedian(numbers) { @@ -82,12 +79,12 @@ function getMean(numbers) { } function getMedianAverageDeviation(numbers, { median }) { - const residuals = numbers.map(d => Math.abs(d - median)); + const residuals = allDamage.map(d => Math.abs(d - median)); return getMedian(residuals); } function getStandardDeviation(numbers, { mean }) { - const deviations = numbers.map(r => r - mean); + const deviations = numbers.map((r) => r - mean); return Math.sqrt(deviations.reduce((r, d) => r + d * d, 0) / (numbers.length - 1)); } @@ -98,8 +95,8 @@ function parseDamage(damage) { p.value.custom.enabled ? p.value.custom.formula : [p.value.flatMultiplier ? `${p.value.flatMultiplier}${p.value.dice}` : 0, p.value.bonus ?? 0] - .filter(p => !!p) - .join('+') + .filter(p => !!p) + .join('+') ) .join('+'); return getExpectedDamage(formula); @@ -110,23 +107,19 @@ function parseDamage(damage) { * All subtracted terms become negative terms. */ function getExpectedDamage(formula) { - const terms = formula - .replace('+', ' + ') - .replace('-', ' - ') - .split(' ') - .map(t => t.trim()); + const terms = formula.replace("+", " + ").replace("-", " - ").split(" ").map(t => t.trim()); let multiplier = 1; return terms.reduce((total, term) => { - if (term === '-') { + if (term === "-") { multiplier = -1; return total; - } else if (term === '+') { + } else if (term === "+") { return total; } const currentMultiplier = multiplier; multiplier = 1; - + const number = Number(term); if (!Number.isNaN(number)) { return total + currentMultiplier * number; diff --git a/tools/create-symlink.mjs b/tools/create-symlink.mjs index 4e14d5df..fd828c73 100644 --- a/tools/create-symlink.mjs +++ b/tools/create-symlink.mjs @@ -2,8 +2,6 @@ import fs from 'fs'; import path from 'path'; import readline from 'readline'; -console.log('Creates a foundry symlink in the base folder for type purposes\n'); - const askQuestion = question => { const rl = readline.createInterface({ input: process.stdin, diff --git a/tools/eslint.config.mjs b/tools/eslint.config.mjs deleted file mode 100644 index 36a5174a..00000000 --- a/tools/eslint.config.mjs +++ /dev/null @@ -1,20 +0,0 @@ -import globals from 'globals'; -import { defineConfig, globalIgnores } from 'eslint/config'; -import { stylisticRules } from '../eslint.config.mjs'; -import stylistic from '@stylistic/eslint-plugin'; - -export default defineConfig([ - globalIgnores(['foundry/**/*']), - { - files: ['**/*.{js,mjs,cjs}'], - plugins: { - '@stylistic': stylistic - }, - languageOptions: { globals: globals.node }, - rules: { - 'no-undef': 'error', - 'no-unused-vars': 0, - ...stylisticRules - } - } -]); diff --git a/tools/pullYMLtoLDB.mjs b/tools/pullYMLtoLDB.mjs index 52b7db94..2326d94a 100644 --- a/tools/pullYMLtoLDB.mjs +++ b/tools/pullYMLtoLDB.mjs @@ -1,12 +1,12 @@ import { compilePack } from '@foundryvtt/foundryvtt-cli'; import readline from 'node:readline/promises'; import { promises as fs } from 'fs'; -import systemJSON from '../system.json' with { type: 'json' }; +import systemJSON from "../system.json" with { type: "json" }; const MODULE_ID = process.cwd(); const answer = await (async () => { - if (process.argv.includes('--build')) return 'overwrite'; + if (process.argv.includes("--build")) return "overwrite"; const rl = readline.createInterface({ input: process.stdin, @@ -42,8 +42,8 @@ async function pullToLDB() { function transformEntry(entry) { const stats = { coreVersion: systemJSON.compatibility.minimum, - systemId: 'daggerheart', - systemVersion: systemJSON.version + systemId: "daggerheart", + systemVersion: systemJSON.version, }; entry._stats = { ...stats }; diff --git a/tools/pushLDBtoYML.mjs b/tools/pushLDBtoYML.mjs index 99f84fd7..a113caec 100644 --- a/tools/pushLDBtoYML.mjs +++ b/tools/pushLDBtoYML.mjs @@ -23,7 +23,7 @@ for (const pack of packs) { await extractPack(`${MODULE_ID}/${pack}`, `${MODULE_ID}/src/${pack}`, { yaml, transformName, - transformEntry + transformEntry, }); } /** @@ -45,12 +45,12 @@ function transformEntry(entry) { delete entry._stats; for (const effect of entry.effects ?? []) { - effect._stats = prune(effect._stats); + effect._stats = prune(effect._stats) } for (const item of entry.items ?? []) { item._stats = prune(item._stats); for (const effect of item.effects ?? []) { - effect._stats = prune(effect._stats); + effect._stats = prune(effect._stats) } } }