From aa4021d1a2e9dde546ba24eb45fcb594ebe0eec1 Mon Sep 17 00:00:00 2001 From: WBHarry Date: Thu, 22 May 2025 16:53:39 +0200 Subject: [PATCH] Initial commit --- .github/workflows/deploy.yml | 51 + .gitignore | 4 + LICENSE | 21 + assets/AttributeShield.svg | 24 + assets/DaggerheartLogo.webp | Bin 0 -> 27136 bytes assets/backgrounds/MidnightBackground.webp | Bin 0 -> 46494 bytes daggerheart.mjs | 140 + gulpfile.js | 21 + lang/en.json | 1062 +++ module/applications/_module.mjs | 14 + .../applications/ancestrySelectionDialog.mjs | 229 + module/applications/chatMessage.mjs | 9 + module/applications/config/Action.mjs | 74 + module/applications/daggerheart-sheet.mjs | 48 + module/applications/damageSelectionDialog.mjs | 180 + module/applications/deathMove.mjs | 63 + module/applications/downtime.mjs | 82 + module/applications/levelup.mjs | 277 + module/applications/multiclassDialog.mjs | 98 + .../applications/npcRollSelectionDialog.mjs | 76 + module/applications/rollSelectionDialog.mjs | 276 + module/applications/settings.mjs | 282 + module/applications/sheets/adversary.mjs | 377 + module/applications/sheets/ancestry.mjs | 117 + module/applications/sheets/armor.mjs | 65 + module/applications/sheets/class.mjs | 419 ++ module/applications/sheets/community.mjs | 117 + module/applications/sheets/consumable.mjs | 57 + .../applications/sheets/daggerheart-sheet.mjs | 73 + module/applications/sheets/domainCard.mjs | 110 + module/applications/sheets/environment.mjs | 129 + module/applications/sheets/feature.mjs | 116 + module/applications/sheets/miscellaneous.mjs | 57 + module/applications/sheets/pc.mjs | 2029 ++++++ module/applications/sheets/subclass.mjs | 168 + module/applications/sheets/weapon.mjs | 65 + module/config/actionConfig.mjs | 17 + module/config/actorConfig.mjs | 355 + module/config/domainConfig.mjs | 101 + module/config/effectConfig.mjs | 64 + module/config/generalConfig.mjs | 268 + module/config/itemConfig.mjs | 351 + module/config/settingsConfig.mjs | 28 + module/config/system.mjs | 20 + module/data/_module.mjs | 18 + module/data/abilityUse.mjs | 30 + module/data/action.mjs | 38 + module/data/adversary.mjs | 48 + module/data/adversaryRoll.mjs | 50 + module/data/ancestry.mjs | 11 + module/data/armor.mjs | 40 + module/data/class.mjs | 93 + module/data/combat.mjs | 9 + module/data/combatant.mjs | 8 + module/data/community.mjs | 11 + module/data/consumable.mjs | 10 + module/data/domainCard.mjs | 17 + module/data/dualityRoll.mjs | 150 + module/data/environment.mjs | 20 + module/data/feature.mjs | 77 + module/data/fields.mjs | 109 + module/data/interface/effects.mjs | 75 + module/data/interface/featuresSchema.mjs | 10 + module/data/miscellaneous.mjs | 9 + module/data/pc.mjs | 497 ++ module/data/subclass.mjs | 34 + module/data/weapon.mjs | 47 + module/dialogs/selectDialog.mjs | 94 + module/documents/_module.mjs | 3 + module/documents/actor.mjs | 349 + module/documents/combat.mjs | 41 + module/documents/item.mjs | 72 + module/helpers/handlebarsHelper.mjs | 105 + module/helpers/socket.mjs | 20 + module/helpers/utils.mjs | 82 + module/ui/chatLog.mjs | 103 + module/ui/combatTracker.mjs | 200 + module/ui/players.mjs | 53 + module/ui/ruler.mjs | 29 + package-lock.json | 6291 +++++++++++++++++ package.json | 22 + postcss.config.js | 6 + rollup.config.mjs | 29 + .../class_Test_Class_h9wTtM4iczXHqvf8.json | 70 + styles/application.less | 562 ++ styles/chat.less | 212 + styles/class.less | 5 + styles/components.less | 45 + styles/daggerheart.css | 2613 +++++++ styles/daggerheart.less | 132 + styles/dialog.less | 12 + styles/item.less | 60 + styles/pc.less | 1506 ++++ styles/sheets/adversary.less | 281 + styles/sheets/class.less | 119 + styles/sheets/heritage.less | 6 + styles/sheets/sheets.less | 186 + styles/ui.less | 72 + styles/variables/colors.less | 24 + styles/variables/values.less | 26 + styles/variables/variables.less | 2 + system.json | 458 ++ template.json | 33 + templates/chat/ability-use.hbs | 15 + templates/chat/adversary-attack-roll.hbs | 35 + templates/chat/adversary-roll.hbs | 22 + templates/chat/attack-roll.hbs | 49 + templates/chat/damage-roll.hbs | 19 + templates/chat/deathMove.hbs | 8 + templates/chat/downtime.hbs | 16 + templates/chat/duality-roll.hbs | 68 + templates/chat/healing-roll.hbs | 19 + templates/components/slider.hbs | 5 + templates/dialog/item-select.hbs | 5 + templates/sheets/adversary.hbs | 243 + templates/sheets/ancestry.hbs | 11 + templates/sheets/armor.hbs | 37 + templates/sheets/class.hbs | 300 + templates/sheets/community.hbs | 11 + templates/sheets/consumable.hbs | 36 + templates/sheets/domainCard.hbs | 101 + templates/sheets/environment.hbs | 111 + templates/sheets/feature.hbs | 80 + templates/sheets/miscellaneous.hbs | 29 + templates/sheets/parts/armor.hbs | 19 + templates/sheets/parts/attributes.hbs | 39 + templates/sheets/parts/defense.hbs | 31 + templates/sheets/parts/domainCard.hbs | 26 + templates/sheets/parts/effects.hbs | 69 + templates/sheets/parts/experience.hbs | 15 + templates/sheets/parts/features.hbs | 48 + templates/sheets/parts/gold.hbs | 88 + templates/sheets/parts/health.hbs | 58 + templates/sheets/parts/heritage.hbs | 20 + templates/sheets/parts/hope.hbs | 15 + templates/sheets/parts/inventory.hbs | 47 + templates/sheets/parts/subclassFeature.hbs | 25 + templates/sheets/parts/weapons.hbs | 57 + templates/sheets/pc/parts/advancementCard.hbs | 27 + templates/sheets/pc/parts/heritageCard.hbs | 18 + templates/sheets/pc/pc.hbs | 155 + templates/sheets/pc/sections/inventory.hbs | 32 + templates/sheets/pc/sections/loadout.hbs | 134 + templates/sheets/subclass.hbs | 45 + templates/sheets/weapon.hbs | 86 + templates/sidebar/documentCreate.hbs | 45 + templates/ui/combatTracker.hbs | 160 + templates/ui/players.hbs | 35 + templates/views/action.hbs | 64 + templates/views/ancestrySelection.hbs | 72 + templates/views/automation-settings.hbs | 19 + templates/views/damageSelection.hbs | 29 + templates/views/deathMove.hbs | 19 + templates/views/downtime.hbs | 28 + templates/views/homebrew-settings.hbs | 13 + templates/views/levelup.hbs | 20 + templates/views/multiclass.hbs | 37 + templates/views/npcRollSelection.hbs | 30 + templates/views/parts/level.hbs | 40 + templates/views/range-settings.hbs | 44 + templates/views/rollSelection.hbs | 75 + tools/pullYMLtoLDB.mjs | 16 + tools/pushLDBtoYML.mjs | 42 + 163 files changed, 26530 insertions(+) create mode 100644 .github/workflows/deploy.yml create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 assets/AttributeShield.svg create mode 100644 assets/DaggerheartLogo.webp create mode 100644 assets/backgrounds/MidnightBackground.webp create mode 100644 daggerheart.mjs create mode 100644 gulpfile.js create mode 100644 lang/en.json create mode 100644 module/applications/_module.mjs create mode 100644 module/applications/ancestrySelectionDialog.mjs create mode 100644 module/applications/chatMessage.mjs create mode 100644 module/applications/config/Action.mjs create mode 100644 module/applications/daggerheart-sheet.mjs create mode 100644 module/applications/damageSelectionDialog.mjs create mode 100644 module/applications/deathMove.mjs create mode 100644 module/applications/downtime.mjs create mode 100644 module/applications/levelup.mjs create mode 100644 module/applications/multiclassDialog.mjs create mode 100644 module/applications/npcRollSelectionDialog.mjs create mode 100644 module/applications/rollSelectionDialog.mjs create mode 100644 module/applications/settings.mjs create mode 100644 module/applications/sheets/adversary.mjs create mode 100644 module/applications/sheets/ancestry.mjs create mode 100644 module/applications/sheets/armor.mjs create mode 100644 module/applications/sheets/class.mjs create mode 100644 module/applications/sheets/community.mjs create mode 100644 module/applications/sheets/consumable.mjs create mode 100644 module/applications/sheets/daggerheart-sheet.mjs create mode 100644 module/applications/sheets/domainCard.mjs create mode 100644 module/applications/sheets/environment.mjs create mode 100644 module/applications/sheets/feature.mjs create mode 100644 module/applications/sheets/miscellaneous.mjs create mode 100644 module/applications/sheets/pc.mjs create mode 100644 module/applications/sheets/subclass.mjs create mode 100644 module/applications/sheets/weapon.mjs create mode 100644 module/config/actionConfig.mjs create mode 100644 module/config/actorConfig.mjs create mode 100644 module/config/domainConfig.mjs create mode 100644 module/config/effectConfig.mjs create mode 100644 module/config/generalConfig.mjs create mode 100644 module/config/itemConfig.mjs create mode 100644 module/config/settingsConfig.mjs create mode 100644 module/config/system.mjs create mode 100644 module/data/_module.mjs create mode 100644 module/data/abilityUse.mjs create mode 100644 module/data/action.mjs create mode 100644 module/data/adversary.mjs create mode 100644 module/data/adversaryRoll.mjs create mode 100644 module/data/ancestry.mjs create mode 100644 module/data/armor.mjs create mode 100644 module/data/class.mjs create mode 100644 module/data/combat.mjs create mode 100644 module/data/combatant.mjs create mode 100644 module/data/community.mjs create mode 100644 module/data/consumable.mjs create mode 100644 module/data/domainCard.mjs create mode 100644 module/data/dualityRoll.mjs create mode 100644 module/data/environment.mjs create mode 100644 module/data/feature.mjs create mode 100644 module/data/fields.mjs create mode 100644 module/data/interface/effects.mjs create mode 100644 module/data/interface/featuresSchema.mjs create mode 100644 module/data/miscellaneous.mjs create mode 100644 module/data/pc.mjs create mode 100644 module/data/subclass.mjs create mode 100644 module/data/weapon.mjs create mode 100644 module/dialogs/selectDialog.mjs create mode 100644 module/documents/_module.mjs create mode 100644 module/documents/actor.mjs create mode 100644 module/documents/combat.mjs create mode 100644 module/documents/item.mjs create mode 100644 module/helpers/handlebarsHelper.mjs create mode 100644 module/helpers/socket.mjs create mode 100644 module/helpers/utils.mjs create mode 100644 module/ui/chatLog.mjs create mode 100644 module/ui/combatTracker.mjs create mode 100644 module/ui/players.mjs create mode 100644 module/ui/ruler.mjs create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 postcss.config.js create mode 100644 rollup.config.mjs create mode 100644 src/packs/classes/class_Test_Class_h9wTtM4iczXHqvf8.json create mode 100644 styles/application.less create mode 100644 styles/chat.less create mode 100644 styles/class.less create mode 100644 styles/components.less create mode 100644 styles/daggerheart.css create mode 100644 styles/daggerheart.less create mode 100644 styles/dialog.less create mode 100644 styles/item.less create mode 100644 styles/pc.less create mode 100644 styles/sheets/adversary.less create mode 100644 styles/sheets/class.less create mode 100644 styles/sheets/heritage.less create mode 100644 styles/sheets/sheets.less create mode 100644 styles/ui.less create mode 100644 styles/variables/colors.less create mode 100644 styles/variables/values.less create mode 100644 styles/variables/variables.less create mode 100644 system.json create mode 100644 template.json create mode 100644 templates/chat/ability-use.hbs create mode 100644 templates/chat/adversary-attack-roll.hbs create mode 100644 templates/chat/adversary-roll.hbs create mode 100644 templates/chat/attack-roll.hbs create mode 100644 templates/chat/damage-roll.hbs create mode 100644 templates/chat/deathMove.hbs create mode 100644 templates/chat/downtime.hbs create mode 100644 templates/chat/duality-roll.hbs create mode 100644 templates/chat/healing-roll.hbs create mode 100644 templates/components/slider.hbs create mode 100644 templates/dialog/item-select.hbs create mode 100644 templates/sheets/adversary.hbs create mode 100644 templates/sheets/ancestry.hbs create mode 100644 templates/sheets/armor.hbs create mode 100644 templates/sheets/class.hbs create mode 100644 templates/sheets/community.hbs create mode 100644 templates/sheets/consumable.hbs create mode 100644 templates/sheets/domainCard.hbs create mode 100644 templates/sheets/environment.hbs create mode 100644 templates/sheets/feature.hbs create mode 100644 templates/sheets/miscellaneous.hbs create mode 100644 templates/sheets/parts/armor.hbs create mode 100644 templates/sheets/parts/attributes.hbs create mode 100644 templates/sheets/parts/defense.hbs create mode 100644 templates/sheets/parts/domainCard.hbs create mode 100644 templates/sheets/parts/effects.hbs create mode 100644 templates/sheets/parts/experience.hbs create mode 100644 templates/sheets/parts/features.hbs create mode 100644 templates/sheets/parts/gold.hbs create mode 100644 templates/sheets/parts/health.hbs create mode 100644 templates/sheets/parts/heritage.hbs create mode 100644 templates/sheets/parts/hope.hbs create mode 100644 templates/sheets/parts/inventory.hbs create mode 100644 templates/sheets/parts/subclassFeature.hbs create mode 100644 templates/sheets/parts/weapons.hbs create mode 100644 templates/sheets/pc/parts/advancementCard.hbs create mode 100644 templates/sheets/pc/parts/heritageCard.hbs create mode 100644 templates/sheets/pc/pc.hbs create mode 100644 templates/sheets/pc/sections/inventory.hbs create mode 100644 templates/sheets/pc/sections/loadout.hbs create mode 100644 templates/sheets/subclass.hbs create mode 100644 templates/sheets/weapon.hbs create mode 100644 templates/sidebar/documentCreate.hbs create mode 100644 templates/ui/combatTracker.hbs create mode 100644 templates/ui/players.hbs create mode 100644 templates/views/action.hbs create mode 100644 templates/views/ancestrySelection.hbs create mode 100644 templates/views/automation-settings.hbs create mode 100644 templates/views/damageSelection.hbs create mode 100644 templates/views/deathMove.hbs create mode 100644 templates/views/downtime.hbs create mode 100644 templates/views/homebrew-settings.hbs create mode 100644 templates/views/levelup.hbs create mode 100644 templates/views/multiclass.hbs create mode 100644 templates/views/npcRollSelection.hbs create mode 100644 templates/views/parts/level.hbs create mode 100644 templates/views/range-settings.hbs create mode 100644 templates/views/rollSelection.hbs create mode 100644 tools/pullYMLtoLDB.mjs create mode 100644 tools/pushLDBtoYML.mjs diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 00000000..b088f65d --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,51 @@ +name: Release Creation + +on: + release: + types: [published] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Install Dependencies + run: npm ci + + - name: Build Packs + run: npm run pullYMLtoLDB + + # get part of the tag after the `v` + - name: Extract tag version number + id: get_version + uses: battila7/get-version-action@v2 + + # Substitute the Manifest and Download URLs in the module.json + - name: Substitute Manifest and Download Links For Versioned Ones + id: sub_manifest_link_version + uses: microsoft/variable-substitution@v1 + with: + files: 'system.json' + env: + version: ${{steps.get_version.outputs.version-without-v}} + url: https://github.com/${{github.repository}} + manifest: https://github.com/${{github.repository}}/releases/latest/download/system.json + download: https://github.com/${{github.repository}}/releases/download/${{github.event.release.tag_name}}/system.zip + + # 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 daggerheart.mjs templates/ styles/daggerheart.css packs/ lang/ + + # Create a release for this specific version + - name: Update Release with Files + id: create_version_release + uses: ncipollo/release-action@v1 + with: + allowUpdates: true # Set this to false if you want to prevent updating existing releases + name: ${{ github.event.release.name }} + draft: ${{ github.event.release.unpublished }} + prerelease: ${{ github.event.release.prerelease }} + token: ${{ secrets.GITHUB_TOKEN }} + artifacts: './module.json, ./module.zip' + tag: ${{ github.event.release.tag_name }} + body: ${{ github.event.release.body }} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..d5c12e03 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.vscode +node_modules +/packs +Build \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..9052d30a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 WBHarry + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/assets/AttributeShield.svg b/assets/AttributeShield.svg new file mode 100644 index 00000000..8bd83a28 --- /dev/null +++ b/assets/AttributeShield.svg @@ -0,0 +1,24 @@ + + + + + + + + + \ No newline at end of file diff --git a/assets/DaggerheartLogo.webp b/assets/DaggerheartLogo.webp new file mode 100644 index 0000000000000000000000000000000000000000..a5f9c331480ccf4c7db3abd89974b8d92d54d3c5 GIT binary patch literal 27136 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 azrNlYhkRxOxQzClzgwti+kgNJQ7{0Ox=|$n literal 0 HcmV?d00001 diff --git a/daggerheart.mjs b/daggerheart.mjs new file mode 100644 index 00000000..bf567a79 --- /dev/null +++ b/daggerheart.mjs @@ -0,0 +1,140 @@ +import { SYSTEM } from './module/config/system.mjs'; +import * as applications from './module/applications/_module.mjs'; +import * as models from './module/data/_module.mjs'; +import * as documents from './module/documents/_module.mjs'; +import RegisterHandlebarsHelpers from './module/helpers/handlebarsHelper.mjs'; +import DhpCombatTracker from './module/ui/combatTracker.mjs'; +import { GMUpdateEvent, handleSocketEvent, socketEvent } from './module/helpers/socket.mjs'; +import { registerDHPSettings } from './module/applications/settings.mjs'; +import DhpChatLog from './module/ui/chatLog.mjs'; +import DhpPlayers from './module/ui/players.mjs'; +import DhpRuler from './module/ui/ruler.mjs'; + +globalThis.SYSTEM = SYSTEM; + +Hooks.once('init', () => { + CONFIG.daggerheart = SYSTEM; + game.system.api = { + applications, + models, + documents, + } + + CONFIG.statusEffects = Object.values(SYSTEM.GENERAL.conditions).map(x => ({ ...x, name: game.i18n.localize(x.name) })); + + CONFIG.Item.documentClass = documents.DhpItem; + CONFIG.Item.dataModels = { + ancestry: models.DhpAncestry, + community: models.DhpCommunity, + class: models.DhpClass, + subclass: models.DhpSubclass, + feature: models.DhpFeature, + domainCard: models.DhpDomainCard, + miscellaneous: models.DhpMiscellaneous, + consumable: models.DhpConsumable, + weapon: models.DhpWeapon, + armor: models.DhpArmor, + }; + + const { Items, Actors } = foundry.documents.collections; + Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet); + Items.registerSheet(SYSTEM.id, applications.DhpAncestry, {types: ["ancestry"], makeDefault: true}); + Items.registerSheet(SYSTEM.id, applications.DhpCommunity, {types: ["community"], makeDefault: true}); + Items.registerSheet(SYSTEM.id, applications.DhpClassSheet, {types: ["class"], makeDefault: true}); + Items.registerSheet(SYSTEM.id, applications.DhpSubclass, {types: ["subclass"], makeDefault: true}); + Items.registerSheet(SYSTEM.id, applications.DhpFeatureSheet, {types: ["feature"], makeDefault: true}); + Items.registerSheet(SYSTEM.id, applications.DhpDomainCardSheet, {types: ["domainCard"], makeDefault: true}); + Items.registerSheet(SYSTEM.id, applications.DhpMiscellaneous, {types: ["miscellaneous"], makeDefault: true}); + Items.registerSheet(SYSTEM.id, applications.DhpConsumable, {types: ["consumable"], makeDefault: true}); + Items.registerSheet(SYSTEM.id, applications.DhpWeapon, {types: ["weapon"], makeDefault: true}); + Items.registerSheet(SYSTEM.id, applications.DhpArmor, {types: ["armor"], makeDefault: true}); + + CONFIG.Actor.documentClass = documents.DhpActor; + CONFIG.Actor.dataModels = { + pc: models.DhpPC, + adversary: models.DhpAdversary, + environment: models.DhpEnvironment, + }; + Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet); + Actors.registerSheet(SYSTEM.id, applications.DhpPCSheet, {types: ["pc"], makeDefault: true}); + Actors.registerSheet(SYSTEM.id, applications.DhpAdversarySheet, {types: ["adversary"], makeDefault: true}); + Actors.registerSheet(SYSTEM.id, applications.DhpEnvironment, {types: ["environment"], makeDefault: true}); + + CONFIG.Combat.dataModels = { + base: models.DhpCombat, + }; + + CONFIG.Combatant.dataModels = { + base: models.DhpCombatant, + }; + + CONFIG.ChatMessage.dataModels ={ + dualityRoll: models.DhpDualityRoll, + adversaryRoll: models.DhpAdversaryRoll, + abilityUse: models.DhpAbilityUse, + }; + CONFIG.ChatMessage.documentClass = applications.DhpChatMessage; + + CONFIG.Canvas.rulerClass = DhpRuler; + CONFIG.Combat.documentClass = documents.DhpCombat; + CONFIG.ui.combat = DhpCombatTracker; + CONFIG.ui.chat = DhpChatLog; + CONFIG.ui.players = DhpPlayers; + + game.socket.on(`system.${SYSTEM.id}`, handleSocketEvent); + + registerDHPSettings(); + + RegisterHandlebarsHelpers.registerHelpers(); + + return preloadHandlebarsTemplates(); +}); + +Hooks.once('dicesoniceready', () => { + +}); + +Hooks.on(socketEvent.GMUpdate, async (action, uuid, update) => { + if(game.user.isGM){ + const document = uuid ? await fromUuid(uuid) : null; + switch(action){ + case GMUpdateEvent.UpdateDocument: + if(document && update){ + await document.update(update); + } + break; + case GMUpdateEvent.UpdateFear: + if(game.user.isGM){ + await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear, Math.max(Math.min(update, 6), 0)); + Hooks.callAll(socketEvent.DhpFearUpdate); + await game.socket.emit(`system.${SYSTEM.id}`, { action: socketEvent.DhpFearUpdate }); + } + break; + } + } +}); + +const preloadHandlebarsTemplates = async function() { + return foundry.applications.handlebars.loadTemplates([ + "systems/daggerheart/templates/sheets/parts/attributes.hbs", + "systems/daggerheart/templates/sheets/parts/defense.hbs", + "systems/daggerheart/templates/sheets/parts/armor.hbs", + "systems/daggerheart/templates/sheets/parts/experience.hbs", + "systems/daggerheart/templates/sheets/parts/features.hbs", + "systems/daggerheart/templates/sheets/parts/gold.hbs", + "systems/daggerheart/templates/sheets/parts/health.hbs", + "systems/daggerheart/templates/sheets/parts/hope.hbs", + "systems/daggerheart/templates/sheets/parts/inventory.hbs", + "systems/daggerheart/templates/sheets/parts/weapons.hbs", + "systems/daggerheart/templates/sheets/parts/domainCard.hbs", + "systems/daggerheart/templates/sheets/parts/heritage.hbs", + "systems/daggerheart/templates/sheets/parts/subclassFeature.hbs", + "systems/daggerheart/templates/sheets/parts/effects.hbs", + "systems/daggerheart/templates/sheets/pc/sections/inventory.hbs", + "systems/daggerheart/templates/sheets/pc/sections/loadout.hbs", + "systems/daggerheart/templates/sheets/pc/parts/heritageCard.hbs", + "systems/daggerheart/templates/sheets/pc/parts/advancementCard.hbs", + "systems/daggerheart/templates/views/parts/level.hbs", + "systems/daggerheart/templates/components/slider.hbs", + ]); + }; \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 00000000..a5e1c7ad --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,21 @@ +// Less configuration +var gulp = require('gulp'); +var less = require('gulp-less'); + +gulp.task('less', function(cb) { + gulp + .src('styles/daggerheart.less') + .pipe(less()) + .pipe( + gulp.dest("styles") + ); + cb(); +}); + +gulp.task( + 'default', + gulp.series('less', function(cb) { + gulp.watch('styles/**/*.less', gulp.series('less')); + cb(); + }) +); \ No newline at end of file diff --git a/lang/en.json b/lang/en.json new file mode 100644 index 00000000..7708e08b --- /dev/null +++ b/lang/en.json @@ -0,0 +1,1062 @@ +{ + "TYPES": { + "Item": { + "ancestry": "Ancestry", + "community": "Community", + "class": "Class", + "subclass": "Subclass", + "feature": "Feature", + "domainCard": "Domain Card", + "consumable": "Consumable", + "miscellaneous": "Miscellaneous", + "weapon": "Weapon", + "armor": "Armor" + }, + "Actor": { + "pc": "PC", + "npc": "NPC", + "adversary": "Adversary", + "environment": "Environment" + } + }, + "DAGGERHEART": { + "Settings": { + "Menu": { + "Automation": { + "Name": "Automation Settings", + "Label": "Configure Automation", + "Hint": "Various settings automating resource management and more", + "HopeLabel": "Hope", + "FearLabel": "Fear", + "ActionPointsLabel": "Action Points" + }, + "Homebrew": { + "Name": "Homebrew Settings", + "Label": "Configure Homebrew", + "Hint": "Various settings allowing extensions to types or altered game rules", + "AbilityArrayLabel": "Ability Array" + }, + "Range": { + "Name": "Range Settings", + "Label": "Configure Range Handling", + "Hint": "System ruler setup for displaying ranges in Daggerheart", + "EnabledLabel": "Enabled", + "MeleeLabel": "Melee", + "VeryCloseLabel": "Very Close", + "CloseLabel": "Close", + "FarLabel": "Far", + "VeryFarLabel": "Very Far" + } + }, + "Automation": { + "Hope": { + "Name": "Hope", + "Hint": "Automatically increase a character's hope on a hope duality roll result." + }, + "Fear": { + "Name": "Fear", + "Hint": "Automatically increase the GM's fear pool on a fear duality roll result." + }, + "ActionPoints": { + "Name": "Action Points", + "Hint": "Automatically give and take Action Points as combatants take their turns." + } + }, + "Resources": { + "Fear": { + "Name": "Fear", + "Hint": "The Fear pool of the GM." + } + }, + "General": { + "AbilityArray": { + "Name": "Ability Score Array", + "Hint": "The starting distribution of Ability Scores for a character." + }, + "RangeMeasurement": { + "Name": "Enable Range Measurement", + "Hint": "Enable measuring of ranges with the ruler according to set distances." + } + } + }, + "Notification": { + "Info": { + "ClassCanOnlyHaveTwoDomains": "A class can only have 2 domains!", + "NoTargetsSelected": "No targets are selected.", + "SecondaryEquipWhileTwohanded": "A secondary weapon can't be equipped together with a Two-Handed weapon.", + "TwohandedEquipWhileSecondary": "Can't equip a Two-Handed weapon together with a secondary weapon.", + "SelectClassBeforeSubclass": "Select a Class before selecting a Subclass.", + "SubclassNotOfClass": "This Subclass doesn't belong to your current Class." + }, + "Error": { + "NoClassSelected": "Your character has no class selected!", + "LacksDomain": "Your character doesn't have the domain of the card!", + "MaxLoadoutReached": "You can't have any more domain cards at this level!", + "DuplicateDomainCard": "You already have a domain card with that name!", + "ActionRequiresTarget": "The action requires at least one target" + } + }, + "General": { + "OpenBetaDisclaimer": "Daggerheart Open Beta {version}", + "Hope": "Hope", + "Fear": "Fear", + "CriticalSuccess": "Critical Success", + "Advantage": "Advantage", + "Disadvantage": "Disadvantage", + "OK": "OK", + "Cancel": "Cancel", + "Or": "Or", + "Description": "Description", + "Features": "Features", + "RefreshType": { + "Session": "Session", + "Shortrest": "Short Rest", + "Longrest": "Long Rest" + } + }, + "ActionType": { + "Passive": "Passive", + "Action": "Action", + "Reaction": "Reaction" + }, + "Abilities": { + "Agility": { + "Name": "Agility", + "Verb": { + "Sprint": "Sprint", + "Leap": "Leap", + "Maneuver": "Maneuver" + } + }, + "Strength": { + "Name": "Strength", + "Verb": { + "Lift": "Lift", + "Smash": "Smash", + "Grapple": "Grapple" + } + }, + "Finesse": { + "Name": "Finesse", + "Verb": { + "Control": "Control", + "Hide": "Hide", + "Tinker": "Tinker" + } + }, + "Instinct": { + "Name": "Instinct", + "Verb": { + "Perceive": "Perceive", + "Sense": "Sense", + "Navigate": "Navigate" + } + }, + "Presence": { + "Name": "Presence", + "Verb": { + "Charm": "Charm", + "Perform": "Perform", + "Deceive": "Deceive" + } + }, + "Knowledge": { + "Name": "Knowledge", + "Verb": { + "Recall": "Recall", + "Analyze": "Analyze", + "Comprehend": "Comprehend" + } + } + }, + "FeatureProperty": { + "SpellcastingTrait": "Spellcasting Trait" + }, + "Condition": { + "Vulnerable": { + "Name": "Vulnerable", + "Description": "While a creature is Vulnerable, all rolls targeting them have advantage.\nA creature who is already Vulnerable can’t be made to take the condition again." + }, + "Hidden": { + "Name": "Hidden", + "Description": "While Hidden, attacks cannot be made directly targeting them nd any rolls against them are at disadvantage.\nWhen a Hidden creature moves or attacks, they are no longer Hidden. However, if a creature is Hidden when they begin making an attack, the roll has advantage; the Hidden condition isn’t cleared until after the attack is resolved." + }, + "Restrained": { + "Name": "Restrained", + "Description": "When an effect makes a creature Restrained, it means they cannot move until this condition is cleared.\nThey can still take actions from their current position." + } + }, + "Adversary": { + "Bruiser": { + "Name": "Bruiser", + "Description": "Tough adversaries with powerful attacks." + }, + "Horde": { + "Name": "Horde", + "Description": "A Horde represents a number of foes working in a group." + }, + "Leader": { + "Name": "Leader", + "Description": "Adversaries that command and summon other adversaries." + }, + "Minion": { + "Name": "Minion", + "Description": "Basic enemies that are easily dispatched but dangerous in numbers." + }, + "Ranged": { + "Name": "Ranged", + "Description": "Adversaries that attack from a distance." + }, + "Skulker": { + "Name": "Skulker", + "Description": "Adversaries that maneuver and exploit opportunities to ambush their opponents." + }, + "Social": { + "Name": "Social", + "Description": "Adversaries that are primarily interpersonal threats or challenges." + }, + "Solo": { + "Name": "Solo", + "Description": "Designed to present a challenge to a whole party." + }, + "Standard": { + "Name": "Standard", + "Description": "Rank and File adversaries." + }, + "Support": { + "Name": "Support", + "Description": "Enemies that enhance their allies and/or disrupt their opponents." + }, + "Trait": { + "Relentless": { + "Name": "Relentless", + "Description": "A foe with Relentless can activate up to X times during a GM move so long as there are enough action tokens.", + "Tip": "The Relentless move is useful if you want an adversary you can activate more than once during a single GM move. This is often best for exceedingly fast or dangerous foes, or for adversaries who are likely to be battling the party on their own." + }, + "Slow": { + "Name": "Slow", + "Description": "A foe with Slow costs X action tokens to activate.", + "Tip": "The Slow move is useful if you want an adversary who narratively takes longer to act than others, like a slug creature or a massive ogre. This is usually most effective when that creature is very powerful when it does act, but eats up lots of action tokens to do it." + }, + "Minion": { + "Name": "Minion", + "Description": "For every X damage a PC deals to this adversary, they also deal 1 HP to an additional minion within their attack’s range.", + "Tip": "The Minion move is useful when you want to drop lots of small enemies into the battlefield, knowing the party can swing through them very easily. This move means that if a PC hits one minion and they do enough damage, they also hit a number of others that are in range for them. Because of this, it’s often best to have minions crowd a PC–it will feel overwhelming and dangerous until they’re able to make an attack against them. If you want that cinematic feeling of the PCs taking out waves of enemies with a single attack roll, minions are a great tool to make that happen." + } + } + }, + "Domains": { + "Arcana": { + "Description": "This is the domain of the innate or instinctual use of magic. Those who walk this path tap into the raw, enigmatic forces of the realms to manipulate both the elements and their own energy. Arcana offers wielders a volatile power, but it is incredibly potent when correctly channeled." + }, + "Blade": { + "Description": "This is the domain of those who dedicate their lives to the mastery of weapons. Whether by blade, bow, or perhaps a more specialized arm, those who follow this path have the skill to cut short the lives of others. Blade requires study and dedication from its followers, in exchange for inexorable power over death." + }, + "Bone": { + "Description": "This is the domain of mastery of swiftness and tactical mastery. Practitioners of this domain have an uncanny control over their own physical abilities, and an eye for predicting the behaviors of others in combat. Bone grants its adherents unparalleled understanding of bodies and their movements in exchange for diligent training." + }, + "Codex": { + "Description": "This is the domain of intensive magical study. Those who seek magical knowledge turn to the recipes of power recorded in books, on scrolls, etched into walls, or tattooed on bodies. Codex offers a commanding and versatile understanding of magic to those devotees who are willing to seek beyond the common knowledge." + }, + "Grace": { + "Description": "This is the domain of charisma. Through rapturous storytelling, clever charm, or a shroud of lies, those who channel this power define the realities of their adversaries, bending perception to their will. Grace offers its wielders raw magnetism and mastery over language." + }, + "Midnight": { + "Description": "This is the domain of shadows and secrecy. Whether by clever tricks, or cloak of night those who channel these forces are practiced in that art of obscurity and there is nothing hidden they cannot reach. Midnight offers practitioners the incredible power to control and create enigmas." + }, + "Sage": { + "Description": "This is the domain of the natural world. Those who walk this path tap into the unfettered power of the earth and its creatures to unleash raw magic. Sage grants its adherents the vitality of a blooming flower and ferocity of a hungry predator." + }, + "Splendor": { + "Description": "This is the domain of life. Through this magic, followers gain the ability to heal, though such power also grants the wielder some control over death. Splendor offers its disciples the magnificent ability to both give and end life." + }, + "Valor": { + "Description": "This is the domain of protection. Whether through attack or defense, those who choose this discipline channel formidable strength to protect their allies in battle. Valor offers great power to those who raise their shield in defense of others." + } + }, + "Domain": { + "CardTypes": { + "Ability": "Ability", + "Spell": "Spell", + "Grimoire": "Grimoire" + } + }, + "LevelUp": { + "Tier1": { + "Label": "Level 2-4", + "InfoLabel": "At Level 2, take an additional Experience.", + "Pretext": "When you level up, record it on your character sheet, then choose two available options from the list below and mark them.", + "Posttext": "Then increase your Severe Damage Threshold by +2 and choose a new Domain Deck card at your Level or lower." + }, + "Tier2": { + "Label": "Level 5-7", + "InfoLabel": "At Level 5, take an additional Experience and clear all marks on Character Traits.", + "Pretext": "When you level up, record it on your character sheet, then choose two from the list below or any unmarked from the previous tier.", + "Posttext": "Then, increase your Damage Thresholds: Major by +1 and Severe by +3. Then choose a new Domain Deck card at your Level or lower. If your loadout is full, you may choose a card to swap." + }, + "Tier3": { + "Label": "Level 8-10", + "InfoLabel": "At Level 8, take an additional Experience and clear all marks on Character Traits.", + "Pretext": "When you level up, record it on your character sheet, then choose two from the list below or any unmarked from the previous tier.", + "Posttext": "Then, increase your Damage Thresholds: Minor by +1, Major by +2, and Severe by +4. Then choose a new Domain Deck card at your Level or lower. If your loadout is full, you may choose a card to swap." + }, + "ChoiceDescriptions": { + "Attributes": "Increase two unmarked Character Traits by +1 and mark them.", + "HitPointSlots": "Permanently add one Hit Point Slot.", + "StressSlots": "Permanently add one Stress Slot.", + "Experiences": "Increase two Experiences by +1.", + "Proficiency": "Increase your Proficiency by +1", + "ArmorOrEvasionSlot": "Permanently add one Armor Slot or take +1 to your Evasion.", + "MajorDamageThreshold2": "Increase your Major Damage Threshold by +2.", + "SevereDamageThreshold2": "Increase your Severe Damage Threshold by +2.", + "MinorDamageThreshold2": "Increase your Minor Damage Threshold by +2.", + "SevereDamageThreshold3": "Increase your Severe Damage Threshold by +3.", + "Major2OrSevere4DamageThreshold": "Increase your Major Damage Threshold by +2 or Severe Damage Threshold by +4", + "Minor1OrMajor1DamageThreshold": "Increase your Minor or Major Damage Threshold by +1.", + "SevereDamageThreshold4": "Increase your Severe Damage Threshold by +4.", + "MajorDamageThreshold1": "Increase your Major Damage Threshold by +1.", + "Subclass": "Take an upgraded subclass card. Then cross out the multiclass option for this tier.", + "Multiclass": "Multiclass: Choose an additional class for your character, then cross out an unused “Take an upgraded subclass card” and the other multiclass option on this sheet." + } + }, + "Downtime": { + "TendToWounds": { + "Name": "Tend to Wounds", + "Description": "Describe how you patch yourself up and remove all marked Hit Points. You may also do this on an ally instead." + }, + "ClearStress": { + "Name": "Clear Stress", + "Description": "Describe how you blow off steam or pull yourself together, and clear all marked Stress." + }, + "RepairArmor": { + "Name": "Repair Armor", + "Description": "Describe how you spend time repairing your armor and clear all of its Armor Slots. You may also do this to an ally’s armor instead." + }, + "Prepare": { + "Name": "Prepare", + "Description": "Describe how you are preparing for the next day’s adventure, then gain a Hope. If you choose to Prepare with one or more members of your party, you may each take two Hope." + }, + "WorkOnAProject": { + "Name": "Work on a Project", + "Description": "Establish or continue work on a project. The GM might ask for a roll to determine how much to tick down on the completion track." + }, + "Custom": { + "NamePlaceholder": "Custom Activity...", + "Placeholder": "A custom downtime activity description..." + } + }, + "DeathMoves": { + "AvoidDeath": { + "Name": "Avoid Death", + "Description": "You drop unconscious temporarily and work with the GM to describe how the situation gets much worse because of it. Then roll your Fear die; if its value is equal to or under your Level, take a Scar." + }, + "RiskItAll": { + "Name": "Risk It All", + "Description": "Roll your Duality Dice. If Hope is higher, you stay on your feet and clear an amount of Hit Points and/or Stress equal to the value of the Hope die (divide the Hope die value up between these however you’d prefer). If your Fear die is higher, you cross through the veil of death. If the Duality Dice are tied, you stay on your feet and clear all Hit Points and Stress." + }, + "BlazeOfGlory": { + "Name": "Blaze Of Glory", + "Description": "With Blaze of Glory, the player is accepting death for the character. Take one action (at GM discretion), which becomes an automatic critical success, then cross through the veil of death." + } + }, + "Burden": { + "OneHanded": "One-Handed", + "TwoHanded": "Two-Handed" + }, + "Range": { + "Melee": { + "Name": "Melee", + "Description": "means a character is within touching distance of the target. PCs can generally touch targets up to a few feet away from them, but melee range may be greater for especially large NPCs." + }, + "VeryClose": { + "Name": "Very Close", + "Description": "means a distance where one can see fine details of a target- within moments of reaching, if need be. This is usually anywhere from about 5-10 feet away. While in danger, a PC can usually get to anything that’s very close as part of any other action they take. Anything on a battle map that is within the shortest length of a game card (~2-3 inches) can usually be considered very close." + }, + "Close": { + "Name": "Close", + "Description": "means a distance where one can see prominent details of a target-- across a room or to a neighboring market stall, generally about 10-30 feet away. While in danger, a PC can usually get to anything that’s close as part of any other action they take. Anything on a battle map that is within the length of a standard pen or pencil (~5-6 inches) can usually be considered close." + }, + "Far": { + "Name": "Far", + "Description": "means a distance where one can see the appearance of a person or object, but probably not in great detail-- across a small battlefield or down a large corridor. This is usually about 30-100 feet away. While under danger, a PC will likely have to make an Agility check to get here safely. Anything on a battle map that is within the length of a standard piece of paper (~10-11 inches) can usually be considered far." + }, + "VeryFar": { + "Name": "Very Far", + "Description": "means a distance where you can see the shape of a person or object, but probably not make outany details-- across a large battlefield or down a long street, generally about 100-300 feet away. While under danger, a PC likely has to make an Agility check to get here safely. Anything on a battle map that is beyond far distance, but still within sight of the characters can usually be considered very far." + } + }, + "DamageType": { + "Physical": { + "Name": "Physical", + "Abbreviation": "Phy" + }, + "Magical": { + "Name": "Magical", + "Abbreviation": "Mag" + } + }, + "HealingType": { + "HitPoints": { + "Name": "Hit Points", + "Abbreviation": "HP" + }, + "Stress": { + "Name": "Stress", + "Stress": "STR" + } + }, + "ArmorFeature": { + "Light": { + "Name": "Light", + "Description": "+1 to Evasion." + }, + "Heavy": { + "Name": "Heavy", + "Description": "-1 to Evasion." + }, + "VeryHeavy": { + "Name": "Very Heavy", + "Description": "-2 to Evasion and -1 to Agility." + }, + "Reinforced": { + "Name": "Reinforced", + "Description": "Increase your armor score by the number of unmarked armor slots you have." + }, + "Sturdy": { + "Name": "Sturdy", + "Description": "Before you mark your last armor slot, roll your armor die. On a 6, you use the armor without marking the slot." + }, + "Warded": { + "Name": "Warded", + "Description": "Each armor slot is worth an extra 2d4 against magic damage." + }, + "Resistant": { + "Name": "Resistant", + "Description": "Mark 2 armor slots to make yourself resistant to the incoming damage instead of reducing it by your armor score." + }, + "Quiet": { + "Name": "Quiet", + "Description": "+2 to any rolls you make to move without being heard." + }, + "Hopeful": { + "Name": "Hopeful", + "Description": "Anytime you need to spend Hope, you may mark an Armor Slot instead." + }, + "Impenetrable": { + "Name": "Impenetrable", + "Description": "When you mark an armor slot, you cannot fill your last hit point as the result of physical damage." + }, + "Painful": { + "Name": "Painful", + "Description": "Mark stress every time you use one or more armor slots on an attack." + }, + "Gilded": { + "Name": "Gilded", + "Description": "When you mark an armor slot, you may spend any amount of Hope to also reduce the incoming damage by an amount equal to your proficiency per Hope spent." + }, + "Physical": { + "Name": "Physical", + "Description": "You cannot use this armor against Magic damage." + }, + "Magic": { + "Name": "Magic", + "Description": "You cannot use this armor against Physical damage." + }, + "Sharp": { + "Name": "Sharp", + "Description": "Add 1d4 to any damage rolls you make on a successful Melee attack." + }, + "Burning": { + "Name": "Burning", + "Description": "When an enemy strikes you in Melee, they immediately mark a stress." + }, + "Timeslowing": { + "Name": "Timeslowing", + "Description": "On any incoming attacks, roll 1d4 and add its value to your Evasion score." + }, + "Truthseeking": { + "Name": "Truthseeking", + "Description": "This armor glows when anyone within close range tells a lie." + }, + "Channeling": { + "Name": "Channeling", + "Description": "While this armor is equipped, take +1 to all Spellcast rolls." + }, + "Difficult": { + "Name": "Difficult", + "Description": "-1 to all Character Traits." + }, + "Variable": { + "Name": "Variable", + "Description": "Add +1 to your armor score for every range beyond Melee the damage is coming from." + } + }, + "WeaponFeature": { + "Light": { + "Name": "Light", + "Description": "+1 to Agility." + }, + "Heavy": { + "Name": "Heavy", + "Description": "-1 to Agility." + }, + "Massive": { + "Name": "Massive", + "Description": "-1 Agility, roll one extra Damage die and drop the lowest." + }, + "Reliable": { + "Name": "Reliable", + "Description": "+1 to attack rolls with this weapon." + }, + "Quick": { + "Name": "Quick", + "Description": "Mark stress to attack an additional target in range." + }, + "Cumbersome": { + "Name": "Cumbersome", + "Description": "-1 to Evasion." + }, + "Versatile": { + "Name": "Versatile", + "Description": "Presence Melee - d10" + }, + "Powerful": { + "Name": "Powerful", + "Description": "Roll one extra damage die and drop the lowest." + }, + "Scary": { + "Name": "Scary", + "Description": "Successful attacks also deal +1 stress." + }, + "Brutal": { + "Name": "Brutal", + "Description": "For every 8 rolled on a damage die, roll an additional d8 of damage." + }, + "Reloading": { + "Name": "Reloading", + "Description": "If any of your damage dice land on a 10, you must mark stress to reload this weapon before it can be shot again." + }, + "Eruptive": { + "Name": "Eruptive", + "Description": "When you hit a creature in Melee, each Very Close enemy must make a React (5) roll or take half damage as well." + }, + "Persuasive": { + "Name": "Persuasive", + "Description": "Mark stress before rolling Presence to add +2 to the result." + }, + "Pompous": { + "Name": "Pompous", + "Description": "Must have a Presence score of 0 or less to use this weapon." + }, + "Invigorating": { + "Name": "Invigorating", + "Description": "When you make a successful attack, roll a d4. On a 4, clear a stress." + }, + "Dense": { + "Name": "Dense", + "Description": "-1 to Agility & +3 to Severe Damage Threshold." + }, + "Soulswift": { + "Name": "Soulswift", + "Description": "You may re-roll any damage die that rolls a value lower than your Agility. You must use the new result" + }, + "Protective": { + "Name": "Protective", + "Description": "Add +1 to your Armor score." + }, + "Devastating": { + "Name": "Devastating", + "Description": "Mark stress before your attack roll to use d20s as your damage dice instead." + }, + "Retractable": { + "Name": "Retractable", + "Description": "Blade can be hidden in hilt to avoid recognition as a weapon." + }, + "Burn": { + "Name": "Burn", + "Description": "For every damage dice that rolls an 8, deal stress." + }, + "Painful": { + "Name": "Painful", + "Description": "Mark stress every time you roll damage on an attack with this weapon." + }, + "Otherwordly": { + "Name": "Otherwordly", + "Description": "You can choose whether to do Physical or Magic damage." + }, + "Lucky": { + "Name": "Lucky", + "Description": "Spend stress on a failure to reroll your attack and take the new result." + }, + "SelfCorrecting": { + "Name": "Self Correcting", + "Description": "Any 1’s rolled on the damage dice may be treated as 8’s instead." + }, + "Healing": { + "Name": "Healing", + "Description": "During downtime, automatically heal 1 hit point." + }, + "Timebender": { + "Name": "Timebender", + "Description": "You may choose the target of your attack after making your attack roll." + }, + "Enchanted": { + "Name": "Enchanted", + "Description": "This weapon returns to its owner’s hand after being thrown." + }, + "Serrated": { + "Name": "Serrated", + "Description": "Any 1’s rolled on the damage dice count as 11 points of damage." + }, + "Grappling": { + "Name": "Grappling", + "Description": "Spend Hope on a successful attack to temporarily keep the target in place, or pull them into Melee with you." + }, + "Long": { + "Name": "Long", + "Description": "Can target all enemies in a line within range with your attack." + }, + "Destructive": { + "Name": "Destructive", + "Description": "−1 to Agility, all Very Close enemies mark stress on a successful attack." + }, + "Concussive": { + "Name": "Concussive", + "Description": "Spend Hope on a successful attack to launch the target into far range." + }, + "Bouncing": { + "Name": "Bouncing", + "Description": "Spend any amount of stress to hit that many targets in range with the attack." + }, + "Penetrating": { + "Name": "Penetrating", + "Description": "Cuts through solid material." + }, + "Lifestealing": { + "Name": "Lifestealing", + "Description": "On a successful hit, roll a d6. On a 6, heal a hit point or clear a stress." + }, + "Greedy": { + "Name": "Greedy", + "Description": "You may spend one handful of gold to increase your proficiency by +1 on a damage roll." + }, + "Bonded": { + "Name": "Bonded", + "Description": "Add your Level to the damage result." + }, + "Barrier": { + "Name": "Barrier", + "Description": "Add +4 to your armor score, -2 to Evasion." + }, + "Paired": { + "Name": "Paired", + "Description": "+2 to Primary Weapon damage in Melee." + }, + "Whipcrack": { + "Name": "Whipcrack", + "Description": "Mark stress to scatter enemies in Melee into close range." + }, + "Hook": { + "Name": "Hook", + "Description": "On a successful attack, you may also pull the target into Melee with you." + }, + "DoubleDuty": { + "Name": "Double Duty", + "Description": "+2 to Armor score, +1 to Primary Weapon damage in Melee." + }, + "Parry": { + "Name": "Parry", + "Description": "On an attack against you, roll this weapon’s damage dice. If any match the attacker’s, they are removed before damage is totalled." + }, + "Retrieve": { + "Name": "Retrieve", + "Description": "Must be retrieved once thrown before using again." + }, + "Deflecting": { + "Name": "Deflecting", + "Description": "On an incoming attack, you may spend an armor slot to boost your Evasion score by your Armor score." + }, + "ChargedAttack": { + "Name": "Charged Attack", + "Description": "Mark stress to increase proficiency by +1 on Primary Weapon attack." + }, + "Sheltering": { + "Name": "Sheltering", + "Description": "Using an armor slot reduces damage for you and all allies in Melee with you." + }, + "DoubledUp": { + "Name": "Doubled Up", + "Description": "When you make an attack with your Primary Weapon, you also apply that roll to another enemy in range of this weapon." + }, + "LockedOn": { + "Name": "Locked On", + "Description": "On a successful attack with this weapon against a target, the next hit with your Primary Weapon automatically hits that target." + } + }, + "Feature": { + "Type": { + "Ancestry": "Ancestry", + "Community": "Community", + "Class": "Class", + "Subclass": "Subclass" + }, + "ValueType": { + "Normal": "Normal", + "Input": "Input", + "Dice": "Dice" + }, + "Max": "Max" + }, + "FeatureType": { + "Normal": "Normal", + "Input": "Input", + "Ticks": "Ticks" + }, + "Application": { + "Downtime": { + "TakeDowntime": "Take Downtime" + }, + "LevelUp": { + "AdvanceLevel": "Continue To Level {level}", + "TakeLevelUp": "Finish Level Up" + }, + "DeathMove": { + "Title": "{actor} - Death Move", + "TakeMove": "Take Death Move" + }, + "Settings": { + "Title": "Daggerheart Settings" + }, + "Multiclass": { + "ClassSection": { + "Title": "Select Class" + }, + "SubclassSection": { + "Title": "Select Subclass" + }, + "DomainSection": { + "Title": "Select Domain" + }, + "AlreadyOwnedDomain": "You already have this domain!", + "Finish": "Finish Multiclass", + "Close": "Cancel" + }, + "Cancel": "Cancel" + }, + "Chat": { + "DualityRoll": { + "AdvantageChooseTitle": "Select Hope Dice" + }, + "DamageRoll": { + "DealDamage": "Deal Damage" + }, + "HealingRoll": { + "Heal": "Heal" + }, + "DeathMove": { + "Title": "Death Move" + }, + "DomainCard": { + "Title": "Domain Card" + }, + "FoundationCard": { + "AncestryTitle": "Ancestry Card", + "CommunityTitle": "Community Card", + "SubclassFeatureTitle": "Subclass Feature" + }, + "FeatureTitle": "Class Feature", + "EnvironmentTitle": "Environment {actionType}", + "Downtime": { + "Title": "Downtime" + } + }, + "Sheets": { + "PC": { + "Name": "Name", + "Pronouns": "Pronouns", + "ShortRest": "Take a Short Rest", + "LongRest": "Take a Long Rest", + "Level": "Level", + "LevelUp": "Level Up!", + "Tabs": { + "Features": "Features", + "Inventory": "Inventory", + "Foundation": "Foundation", + "Loadout": "Loadout", + "Vault": "Vault", + "Heritage": "Heritage", + "Story": "Story" + }, + "Armor": { + "Title": "Active Armor" + }, + "Attributes": { + "AttributeBaseMenuTitle": "Edit starting attribute values" + }, + "Defense": { + "Evasion": "EVASION", + "Armor": "ARMOR" + }, + "DomainCard": { + "Recall": "Recall", + "ToVault": "To Vault", + "AvailableDomainSlot": "Available Loadout Slot", + "UnavailableDomainSlot": "Available at level {level}", + "FoundationTitle": "Foundation", + "SpecializationTitle": "Specialization", + "MasteryTitle": "Mastery" + }, + "Experience": { + "Title": "Experience" + }, + "Features": { + "Title": "Class Features" + }, + "Gold": { + "Title": "Gold", + "Coins": "Coins", + "Handfulls": "Handfulls", + "Bags": "Bags", + "Chests": "Chests" + }, + "Health":{ + "Title": "HIT POINTS & STRESS", + "Minor": "Minor", + "Major": "Major", + "Severe": "Severe", + "DeathMoveTooltip": "Make a Death Move", + "HealthTitle": "HP", + "StressTitle": "STRESS" + }, + "Heritage": { + "EmptyAncestry": "Ancestry Card", + "EmptyAncestryTip": "(Select an Ancestry)", + "EmptyCommunity": "Community Card", + "EmptyCommunityTip": "(Select a Community)", + "SubclassFoundation": "Subclass Foundation", + "SubclassFoundationTip": "(Select a Subclass)", + "Subclass": "Subclass Upgrade", + "Multiclass": "Multiclass" + }, + "Hope": { + "Title": "Hope", + "Description": "Spend Hope to use an experience or help an ally." + }, + "Inventory": { + "Title": "Inventory", + "InventoryArmor": "Inventory Armor", + "InventoryWeapon": "Inventory Weapon" + }, + "InventoryTab": { + "EquipmentTitle": "Equipment", + "ConsumableTitle": "Consumables", + "MiscellaneousTitle": "Miscellaneous", + "QuantityTitle": "Quantity" + }, + "Weapons": { + "Title": "Active Weapons", + "ProficiencyTitle": "Proficiency", + "PrimaryTitle": "PRIMARY", + "SecondaryTitle": "SECONDARY" + }, + "Story": { + "BackgroundTitle": "Background", + "AppearanceTitle": "Appearance", + "ConnectionsTitle": "Connections", + "Scars": { + "Title": "Scars" + } + }, + "NewItem": "New Item", + "NewScar": "New Scar", + "DeleteConfirmation": "Are you sure you want to delete the item - {item}?" + }, + "Adversary": { + "Description": "Description", + "MotivesAndTactics": "Motives & Tactics", + "Tier": "Tier", + "Type": "Type", + "Attack": { + "Title": "Attack", + "Modifier": "Attack Modifier", + "Name": "Name", + "Range": "Range", + "Damage": { + "Title": "Damage", + "Value": "Value", + "Type": "Type" + } + }, + "Difficulty": "Difficulty", + "Reaction": "Reaction Roll", + "DamageThresholds": { + "Title": "Damage Thresholds", + "Minor": "Minor", + "Major": "Major", + "Severe": "Severe" + }, + "HP": "HP", + "Stress": "Stress", + "Experience": "Experience", + "Experiences": "Experiences", + "Moves": "Moves", + "NewMove": "New Move" + }, + "Environment": { + "ToneAndFeel": "Tone And feel", + "PotentialAdversaries": "Potential Adversaries", + "NewFeature": "New Feature" + }, + "Armor": { + "BaseScore": "Base Score", + "Feature": "Feature", + "Description": "Description" + }, + "Class": { + "Tabs": { + "Features": "Features", + "Guide": "Character Guide", + "Items": "Items", + "Appearance": "Appearance" + }, + "Domains": "Domains", + "DamageThresholds": { + "Title": "Damage Thresholds", + "Minor": "Minor", + "Major": "Major", + "Severe": "Severe" + }, + "Evasion": "Evasion", + "ClassFeatures": "Class Features", + "Subclasses": "Subclasses", + "Guide": { + "Suggestions": { + "Title": "Suggested", + "Traits": { + "Title": "Traits" + } + }, + "SuggestedPrimaryWeaponTitle": "Suggested Primary Weapon", + "SuggestedSecondaryWeaponTitle": "Suggested Secondary Weapon", + "SuggestedArmorTitle": "Suggested Armor", + "Inventory": { + "Title": "Inventory", + "Take": "Take", + "ThenChoose": "Then Choose Between", + "AndEither": "And Either" + }, + "Description": { + "Title": "Character Description", + "Explanation": "Choose one (or more) from each line, or make your own", + "Clothes": "Clothes", + "Eyes": "Eyes", + "Body": "Body", + "Color": "Color", + "Attitude": "Attitude" + }, + "Extra": { + "Title": "Extra", + "Subtitle": "Title" + }, + "BackgroundQuestions": { + "Title": "Background Questions", + "Question": "Question" + }, + "Connections": { + "Title": "Connections", + "Question": "Question" + } + } + }, + "Heritage": { + "Title": "Abilities" + }, + "DomainCard": { + "Type": "Type", + "Category": "Category", + "Foundation": "Foundation", + "Domain": "Domain", + "Costs": "Costs", + "Level": "Level", + "RecallCost": "Recall Cost", + "Description": "Description" + }, + "Feature": { + "FeatureType": "Type", + "ActionType": "Action Type", + "RefreshType": "Refresh Type", + "ValueType": { + "Title": "Feature Type", + "Type": "Type", + "Property": "Property", + "Dice": "Dice", + "Icon": "Icon" + }, + "Tabs": { + "Features": "Features", + "Effects": "Effects", + "Actions": "Actions" + }, + "Description": "Description" + }, + "Consumable": { + "Quantity": "Quantity", + "ConsumeOnUse": "Consume On Use" + }, + "Miscellaneous": { + "Quantity": "Quantity" + }, + "Subclass": { + "Tabs": { + "General": "General", + "Foundation": "Foundation", + "Specialization": "Specialization", + "Mastery": "Mastery" + }, + "SpellcastingTrait": "Spellcasting Trait", + "Description": "Description", + "SubclassFeature": { + "Description": "Description", + "Abilities": "Abilities" + } + }, + "Weapon": { + "SecondaryWeapon": "Secondary Weapon", + "Trait": "Trait", + "Range": "Range", + "Damage": { + "Title": "Damage", + "Value": "Value", + "Type": "Type" + }, + "Burden": "Burden", + "Feature": "Feature", + "Description": "Description" + } + }, + "Effects": { + "Types": { + "Health": { + "Name": "Health" + }, + "Stress": { + "Name": "Stress" + }, + "Reach": { + "Name": "Reach" + }, + "Damage": { + "Name": "Damage" + } + }, + "ApplyLocations": { + "AttackRoll": { + "Name": "Attack Roll" + }, + "DamageRoll": { + "Name": "Damage Roll" + } + } + } + } +} \ No newline at end of file diff --git a/module/applications/_module.mjs b/module/applications/_module.mjs new file mode 100644 index 00000000..ba817c03 --- /dev/null +++ b/module/applications/_module.mjs @@ -0,0 +1,14 @@ +export { default as DhpPCSheet } from './sheets/pc.mjs'; +export { default as DhpAdversarySheet } from './sheets/adversary.mjs'; +export { default as DhpClassSheet } from './sheets/class.mjs'; +export { default as DhpSubclass } from './sheets/subclass.mjs'; +export { default as DhpFeatureSheet } from './sheets/feature.mjs'; +export { default as DhpDomainCardSheet } from './sheets/domainCard.mjs'; +export { default as DhpAncestry } from './sheets/ancestry.mjs'; +export { default as DhpCommunity } from './sheets/community.mjs'; +export { default as DhpMiscellaneous } from './sheets/miscellaneous.mjs'; +export { default as DhpConsumable } from './sheets/consumable.mjs'; +export { default as DhpWeapon } from './sheets/weapon.mjs'; +export { default as DhpArmor } from './sheets/armor.mjs'; +export { default as DhpChatMessage } from './chatMessage.mjs'; +export { default as DhpEnvironment } from './sheets/environment.mjs'; \ No newline at end of file diff --git a/module/applications/ancestrySelectionDialog.mjs b/module/applications/ancestrySelectionDialog.mjs new file mode 100644 index 00000000..0ea04b9f --- /dev/null +++ b/module/applications/ancestrySelectionDialog.mjs @@ -0,0 +1,229 @@ +const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; + +export default class AncestrySelectionDialog extends HandlebarsApplicationMixin(ApplicationV2) { + + constructor(resolve){ + super({}); + + this.resolve = resolve; + this.data = { + ancestries: [], + features: [], + ancestryInfo: { + name: '', + img: null, + customImg: 'icons/svg/mystery-man.svg', + description: '', + }, + }; + } + + static DEFAULT_OPTIONS = { + tag: 'form', + classes: ["daggerheart", "views", "ancestry-selection"], + position: { + width: 800, + height: "auto" + }, + actions: { + selectAncestry: this.selectAncestry, + selectFeature: this.selectFeature, + viewItem: this.viewItem, + selectImage: this.selectImage, + editImage: this._onEditImage, + saveAncestry: this.saveAncestry, + }, + form: { + submitOnChange: true, + closeOnSubmit: false, + } + }; + + /** @override */ + static PARTS = { + damageSelection: { + id: "ancestrySelection", + template: "systems/daggerheart/templates/views/ancestrySelection.hbs" + } + } + + /* -------------------------------------------- */ + + /** @inheritDoc */ + get title() { + return `Ancestry Selection`; + } + + _attachPartListeners(partId, htmlElement, options) { + super._attachPartListeners(partId, htmlElement, options); + + const ancestryNameInput = $(htmlElement).find(".ancestry-name"); + if(ancestryNameInput.length > 0){ + ancestryNameInput.on("change", this.setName.bind(this)); + $(htmlElement).find(".ancestry-description").on("change", this.setDescription.bind(this)); + } + // $(htmlElement).find(".ancestry-image").on("change", this.selectImage.bind(this)); + } + + async _prepareContext(_options) { + const systemAncestries = Array.from((await game.packs.get('daggerheart.playtest-ancestries')).index).map(x => ({ + ...x, + selected: this.data.ancestries.some(selected => selected.uuid === x.uuid), + })); + + const customAncestries = game.items.reduce((acc, x) => { + if(x.type === 'ancestry'){ + acc.push({ ...x, uuid: x.uuid, selected: this.data.ancestries.some(selected => selected.uuid === x.uuid) }); + } + + return acc; + }, []); + + const ancestryFeatures = this.data.ancestries.flatMap(x => + x.system.abilities.map(x => ({ ...x, selected: this.data.features.some(selected => selected.uuid === x.uuid) })) + ); + + return { + systemAncestries, + customAncestries, + ancestryFeatures, + selectedAncestries: this.data.ancestries, + selectedFeatures: this.data.features, + ancestryInfo: this.data.ancestryInfo, + }; + } + + static async selectAncestry(_, button) { + const newAncestries = [...this.data.ancestries]; + if(!newAncestries.findSplice(x => x.uuid === button.dataset.uuid) && this.data.ancestries.length < 2){ + const ancestry = await fromUuid(button.dataset.uuid); + newAncestries.push(ancestry); + } + + this.data.ancestries = newAncestries; + this.data.features = newAncestries.length === 1 ? newAncestries[0].system.abilities : []; + + this.render(true); + } + + static async selectFeature(_, button) { + const newFeatures = [...this.data.features]; + if(!newFeatures.findSplice(x => x.uuid === button.dataset.uuid) && this.data.features.length < 2){ + const feature = await fromUuid(button.dataset.uuid); + newFeatures.push(feature); + } + + this.data.features = newFeatures; + this.render(true); + } + + static async viewItem(_, button) { + (await fromUuid(button.dataset.uuid)).sheet.render(true); + } + + setName(event) { + this.data.ancestryInfo.name = event.currentTarget.value; + this.render(true); + } + + setDescription(event) { + this.data.ancestryInfo.description = event.currentTarget.value; + this.render(true); + } + + static selectImage(_, button) { + this.data.ancestryInfo.img = button.dataset.img; + this.render(true); + } + + static _onEditImage() { + const fp = new FilePicker({ + current: this.data.ancestryInfo.img, + type: "image", + redirectToRoot: ['icons/svg/mystery-man.svg'], + callback: async path => this._updateImage.bind(this)(path), + top: this.position.top + 40, + left: this.position.left + 10 + }); + return fp.browse(); + } + + _updateImage(path){ + this.data.ancestryInfo.customImg = path; + this.data.ancestryInfo.img = path; + this.render(true); + } + + static async saveAncestry(_, button) { + if(this.data.ancestries.length === 2){ + const { name, img, description } = this.data.ancestryInfo; + + this.resolve({ data: { name: name, img: img, type: "ancestry", system: { description: description, abilities: this.data.features.map(x => ({ name: x.name, img: x.img, uuid: x.uuid, subclassLevel: '' })) }}}); + } else { + this.resolve({ data: this.data.ancestries[0].toObject() }); + } + + this.close(); + } +} + +// export default class DamageSelectionDialog extends FormApplication { +// constructor(rollString, bonusDamage, resolve){ +// super({}, {}); + +// this.data = { +// rollString, +// bonusDamage: bonusDamage.map(x => ({ +// ...x, +// hopeUses: 0 +// })), +// } +// this.resolve = resolve; +// } + +// get title (){ +// return 'Damage Options'; +// } + +// static get defaultOptions() { +// const defaults = super.defaultOptions; +// const overrides = { +// height: 'auto', +// width: 400, +// id: 'damage-selection', +// template: 'systems/daggerheart/templates/views/damageSelection.hbs', +// closeOnSubmit: false, +// classes: ["daggerheart", "views", "damage-selection"], +// }; + +// const mergedOptions = foundry.utils.mergeObject(defaults, overrides); + +// return mergedOptions; +// } + +// async getData(){ +// const context = super.getData(); +// context.rollString = this.data.rollString; +// context.bonusDamage = this.data.bonusDamage; + +// return context; +// } + +// activateListeners(html) { +// super.activateListeners(html); + +// html.find('.roll-button').click(this.finish.bind(this)); +// html.find('.').change(); +// } + +// // async _updateObject(_, formData) { +// // const data = foundry.utils.expandObject(formData); +// // this.data = foundry.utils.mergeObject(this.data, data); +// // this.render(true); +// // } + +// finish(){ +// this.resolve(this.data); +// this.close(); +// } +// } \ No newline at end of file diff --git a/module/applications/chatMessage.mjs b/module/applications/chatMessage.mjs new file mode 100644 index 00000000..f16f6fc5 --- /dev/null +++ b/module/applications/chatMessage.mjs @@ -0,0 +1,9 @@ +export default class DhpChatMesssage extends ChatMessage { + async renderHTML() { + if(this.type === 'dualityRoll' || this.type === 'adversaryRoll' || this.type === 'abilityUse'){ + this.content = await renderTemplate(this.content, this.system); + } + + return super.renderHTML(); + } +} \ No newline at end of file diff --git a/module/applications/config/Action.mjs b/module/applications/config/Action.mjs new file mode 100644 index 00000000..ed27e0c1 --- /dev/null +++ b/module/applications/config/Action.mjs @@ -0,0 +1,74 @@ +import DaggerheartSheet from '../sheets/daggerheart-sheet.mjs'; + +const {ApplicationV2} = foundry.applications.api; +export default class DaggerheartActionConfig extends DaggerheartSheet(ApplicationV2) { + constructor(action){ + super({}); + + this.action = action; + this.openSection = null; + } + + // get title(){ + // return `Action - ${this.action.name}`; + // } + + static DEFAULT_OPTIONS = { + tag: 'form', + id: "daggerheart-action", + classes: ["daggerheart", "views", "action"], + position: { width: 600, height: 'auto' }, + actions: { + toggleSection: this.toggleSection, + }, + form: { + handler: this.updateForm, + closeOnSubmit: true, + }, + }; + + static PARTS = { + form: { + id: "action", + template: "systems/daggerheart/templates/views/action.hbs" + } + } + + _getTabs() { + const tabs = { + effects: { active: true, cssClass: '', group: 'primary', id: 'effects', icon: null, label: 'Effects' }, + useage: { active: false, cssClass: '', group: 'primary', id: 'useage', icon: null, label: 'Useage' }, + conditions: { active: false, cssClass: '', group: 'primary', id: 'conditions', icon: null, label: 'Conditions' }, + } + + for ( const v of Object.values(tabs) ) { + v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active; + v.cssClass = v.active ? "active" : ""; + } + + return tabs; + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options, 'action'); + context.openSection = this.openSection; + context.tabs = this._getTabs(); + + return context; + } + + static toggleSection(_, button) { + this.openSection = button.dataset.section === this.openSection ? null : button.dataset.section; + this.render(true); + } + + static async updateForm(event, _, formData) { + const data = foundry.utils.expandObject(foundry.utils.mergeObject(this.action.toObject(), formData.object)); + const newActions = this.action.parent.actions.map(x => x.toObject()); + if(!newActions.findSplice(x => x.id === data.id, data)){ + newActions.push(data); + } + + await this.action.parent.parent.update({ "system.actions": newActions }); + } +} \ No newline at end of file diff --git a/module/applications/daggerheart-sheet.mjs b/module/applications/daggerheart-sheet.mjs new file mode 100644 index 00000000..ee06d762 --- /dev/null +++ b/module/applications/daggerheart-sheet.mjs @@ -0,0 +1,48 @@ +export default function DhpApplicationMixin(Base) { + return class DhpSheet extends Base { + static applicationType = "sheets"; + static documentType = ""; + + static get defaultOptions() { + return Object.assign(super.defaultOptions, { + classes: ["daggerheart", "sheet", this.documentType], + template: `systems/${SYSTEM.id}/templates/${this.applicationType}/${this.documentType}.hbs`, + height: "auto", + submitOnChange: true, + submitOnClose: false, + width: 450 + }); + } + + /** @override */ + get title() { + const {documentName, type, name} = this.object; + // const typeLabel = game.i18n.localize(CONFIG[documentName].typeLabels[type]); + const typeLabel = documentName; + return `[${typeLabel}] ${name}`; + } + + // async _renderOuter() { + // const html = await super._renderOuter(); + // // const overlaySrc = "systems/amia/assets/ThePrimordial.png"; + // const overlay = `
` + // $(html).find('.window-header').prepend(overlay); + // return html; + // } + + activateListeners(html) { + super.activateListeners(html); + html.on("click", "[data-action]", this.#onClickAction.bind(this)); + } + + async #onClickAction(event) { + event.preventDefault(); + const button = event.currentTarget; + const action = button.dataset.action; + + return this._handleAction(action, event, button); + } + + async _handleAction(action, event, button) {} + } +} \ No newline at end of file diff --git a/module/applications/damageSelectionDialog.mjs b/module/applications/damageSelectionDialog.mjs new file mode 100644 index 00000000..cb7c3133 --- /dev/null +++ b/module/applications/damageSelectionDialog.mjs @@ -0,0 +1,180 @@ +const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; + +export default class DamageSelectionDialog extends HandlebarsApplicationMixin(ApplicationV2) { + + constructor(rollString, bonusDamage, hope, resolve){ + super({}); + + this.data = { + rollString, + bonusDamage: bonusDamage.reduce((acc, x) => { + if(x.appliesOn === SYSTEM.EFFECTS.applyLocations.damageRoll.id){ + acc.push(({ + ...x, + hopeUses: 0 + })); + } + + return acc; + }, []), + hope, + } + this.resolve = resolve; + } + + static DEFAULT_OPTIONS = { + tag: 'form', + classes: ["daggerheart", "views", "damage-selection"], + position: { + width: 400, + height: "auto" + }, + actions: { + decreaseHopeUse: this.decreaseHopeUse, + increaseHopeUse: this.increaseHopeUse, + rollDamage: this.rollDamage, + }, + form: { + handler: this.updateSelection, + submitOnChange: true, + closeOnSubmit: false, + } + }; + + /** @override */ + static PARTS = { + damageSelection: { + id: "damageSelection", + template: "systems/daggerheart/templates/views/damageSelection.hbs" + } + } + + /* -------------------------------------------- */ + + /** @inheritDoc */ + get title() { + return `Damage Options`; + } + + async _prepareContext(_options) { + return { + rollString: this.getRollString(), + bonusDamage: this.data.bonusDamage, + hope: this.data.hope+1, + hopeUsed: this.getHopeUsed(), + } + } + + static updateSelection(event, _, formData){ + const { bonusDamage, ...rest } = foundry.utils.expandObject(formData.object); + + for(var index in bonusDamage){ + this.data.bonusDamage[index].initiallySelected = bonusDamage[index].initiallySelected; + if(bonusDamage[index].hopeUses){ + const value = Number.parseInt(bonusDamage[index].hopeUses); + if(!Number.isNaN(value)) this.data.bonusDamage[index].hopeUses = value; + } + } + + this.data = foundry.utils.mergeObject(this.data, rest); + this.render(true); + } + + getRollString(){ + return this.data.rollString.concat(this.data.bonusDamage.reduce((acc, x) => { + if(x.initiallySelected){ + const nr = 1+x.hopeUses; + const baseDamage = x.value; + return acc.concat(` + ${nr}${baseDamage}`); + } + + return acc; + }, "")); + } + + getHopeUsed(){ + return this.data.bonusDamage.reduce((acc, x) => acc+x.hopeUses, 0); + } + + static decreaseHopeUse(_, button){ + const index = Number.parseInt(button.dataset.index); + if(this.data.bonusDamage[index].hopeUses - 1 >= 0) { + this.data.bonusDamage[index].hopeUses -= 1; + this.render(true); + } + } + + static increaseHopeUse(_, button){ + const index = Number.parseInt(button.dataset.index); + if(this.data.bonusDamage[index].hopeUses <= this.data.hope+1) { + this.data.bonusDamage[index].hopeUses += 1; + this.render(true); + } + } + + static rollDamage(){ + this.resolve({ rollString: this.getRollString(), bonusDamage: this.data.bonusDamage, hopeUsed: this.getHopeUsed() }); + this.close(); + } +} + +// export default class DamageSelectionDialog extends FormApplication { +// constructor(rollString, bonusDamage, resolve){ +// super({}, {}); + +// this.data = { +// rollString, +// bonusDamage: bonusDamage.map(x => ({ +// ...x, +// hopeUses: 0 +// })), +// } +// this.resolve = resolve; +// } + +// get title (){ +// return 'Damage Options'; +// } + +// static get defaultOptions() { +// const defaults = super.defaultOptions; +// const overrides = { +// height: 'auto', +// width: 400, +// id: 'damage-selection', +// template: 'systems/daggerheart/templates/views/damageSelection.hbs', +// closeOnSubmit: false, +// classes: ["daggerheart", "views", "damage-selection"], +// }; + +// const mergedOptions = foundry.utils.mergeObject(defaults, overrides); + +// return mergedOptions; +// } + +// async getData(){ +// const context = super.getData(); +// context.rollString = this.data.rollString; +// context.bonusDamage = this.data.bonusDamage; + +// return context; +// } + +// activateListeners(html) { +// super.activateListeners(html); + +// html.find('.roll-button').click(this.finish.bind(this)); +// html.find('.').change(); +// } + +// // async _updateObject(_, formData) { +// // const data = foundry.utils.expandObject(formData); +// // this.data = foundry.utils.mergeObject(this.data, data); +// // this.render(true); +// // } + +// finish(){ +// this.resolve(this.data); +// this.close(); +// } +// } \ No newline at end of file diff --git a/module/applications/deathMove.mjs b/module/applications/deathMove.mjs new file mode 100644 index 00000000..d5559489 --- /dev/null +++ b/module/applications/deathMove.mjs @@ -0,0 +1,63 @@ +const {HandlebarsApplicationMixin, ApplicationV2} = foundry.applications.api; + +export default class DhpDeathMove extends HandlebarsApplicationMixin(ApplicationV2) { + constructor(actor){ + super({}); + + this.actor = actor; + this.selectedMove = null; + } + + get title(){ + return game.i18n.format("DAGGERHEART.Application.DeathMove.Title", { actor: this.actor.name }); + } + + static DEFAULT_OPTIONS = { + classes: ["daggerheart", "views", "death-move"], + position: { width: 800, height: 'auto' }, + actions: { + selectMove: this.selectMove, + takeMove: this.takeMove, + }, + }; + + static PARTS = { + application: { + id: "death-move", + template: "systems/daggerheart/templates/views/deathMove.hbs" + } + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.selectedMove = this.selectedMove; + context.options = SYSTEM.GENERAL.deathMoves; + + return context; + } + + + static selectMove(_, button){ + const move = button.dataset.move; + this.selectedMove = SYSTEM.GENERAL.deathMoves[move]; + + this.render(); + } + + static async takeMove(){ + const cls = getDocumentClass("ChatMessage"); + const msg = new cls({ + user: game.user.id, + content: await renderTemplate("systems/daggerheart/templates/chat/deathMove.hbs", { + player: game.user.character.name, + title: game.i18n.localize(this.selectedMove.name), + img: this.selectedMove.img, + description: game.i18n.localize(this.selectedMove.description), + }), + }); + + cls.create(msg.toObject()); + + this.close(); + } +} \ No newline at end of file diff --git a/module/applications/downtime.mjs b/module/applications/downtime.mjs new file mode 100644 index 00000000..8a8cdf25 --- /dev/null +++ b/module/applications/downtime.mjs @@ -0,0 +1,82 @@ +const {HandlebarsApplicationMixin, ApplicationV2} = foundry.applications.api; + +export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV2) { + constructor(actor, shortrest){ + super({}); + + this.actor = actor; + this.selectedActivity = null; + this.shortrest = shortrest; + + this.customActivity = SYSTEM.GENERAL.downtime.custom; + } + + get title(){ + return `${this.actor.name} - ${this.shortrest ? 'Short Rest': 'Long Rest'}`; + } + + static DEFAULT_OPTIONS = { + tag: 'form', + classes: ["daggerheart", "views", "downtime"], + position: { width: 800, height: 'auto' }, + actions: { + selectActivity: this.selectActivity, + takeDowntime: this.takeDowntime, + }, + form: { handler: this.updateData, submitOnChange: true } + }; + + static PARTS = { + application: { + id: "downtime", + template: "systems/daggerheart/templates/views/downtime.hbs" + } + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.selectedActivity = this.selectedActivity; + context.options = this.shortrest ? SYSTEM.GENERAL.downtime.shortRest : SYSTEM.GENERAL.downtime.longRest; + context.customActivity = this.customActivity; + + context.disabledDowntime = !this.selectedActivity || (this.selectedActivity.id === this.customActivity.id && (!this.customActivity.name || !this.customActivity.description)); + + return context; + } + + + static selectActivity(_, button){ + const activity = button.dataset.activity; + this.selectedActivity = activity === this.customActivity.id ? this.customActivity : this.shortrest ? SYSTEM.GENERAL.downtime.shortRest[activity] : SYSTEM.GENERAL.downtime.longRest[activity]; + + this.render(); + } + + static async takeDowntime(){ + const refreshedFeatures = this.shortrest ? this.actor.system.refreshableFeatures.shortRest : [...this.actor.system.refreshableFeatures.shortRest, ...this.actor.system.refreshableFeatures.longRest]; + for(var feature of refreshedFeatures){ + await feature.system.refresh(); + } + + const cls = getDocumentClass("ChatMessage"); + const msg = new cls({ + user: game.user.id, + content: await renderTemplate("systems/daggerheart/templates/chat/downtime.hbs", { + player: game.user.character.name, + title: game.i18n.localize(this.selectedActivity.name), + img: this.selectedActivity.img, + description: game.i18n.localize(this.selectedActivity.description), + refreshedFeatures: refreshedFeatures, + }), + }); + + cls.create(msg.toObject()); + + this.close(); + } + + static async updateData(event, element, formData){ + this.customActivity = foundry.utils.mergeObject(this.customActivity, formData.object); + this.render(); + } +} \ No newline at end of file diff --git a/module/applications/levelup.mjs b/module/applications/levelup.mjs new file mode 100644 index 00000000..8408ae38 --- /dev/null +++ b/module/applications/levelup.mjs @@ -0,0 +1,277 @@ +import SelectDialog from "../dialogs/selectDialog.mjs"; +import { getTier } from "../helpers/utils.mjs"; +import DhpMulticlassDialog from "./multiclassDialog.mjs"; + +const {HandlebarsApplicationMixin, ApplicationV2} = foundry.applications.api; + +export default class DhpLevelup extends HandlebarsApplicationMixin(ApplicationV2) { + constructor(actor){ + super({}); + + this.actor = actor; + this.data = foundry.utils.deepClone(actor.system.levelData); + this.activeLevel = actor.system.levelData.currentLevel+1; + } + + get title(){ + return `${this.actor.name} - Level Up`; + } + + static DEFAULT_OPTIONS = { + id: "daggerheart-levelup", + classes: ["daggerheart", "views", "levelup"], + position: { width: 1200, height: 'auto' }, + actions: { + toggleBox: this.toggleBox, + advanceLevel: this.advanceLevel, + finishLevelup: this.finishLevelup, + }, + }; + + static PARTS = { + form: { + id: "levelup", + template: "systems/daggerheart/templates/views/levelup.hbs" + } + } + + async _prepareContext(_options) { + let selectedChoices = 0, multiclassing = {}, subclassing = {}; + const leveledTiers = Object.keys(this.data.levelups).reduce((acc, levelKey) => { + const levelData = this.data.levelups[levelKey]; + ['tier1','tier2','tier3'].forEach(tierKey => { + let tierUpdate = {}; + const tierData = levelData[tierKey]; + if(tierData){ + tierUpdate = Object.keys(tierData).reduce((acc, propertyKey) => { + const values = tierData[propertyKey]; + const level = Number.parseInt(levelKey); + + acc[propertyKey] = Object.values(values).map(value => { + if(value && level === this.activeLevel) selectedChoices++; + if(propertyKey === 'multiclass') multiclassing[levelKey] = true; + if(propertyKey === 'subclass') subclassing[tierKey] = true; + + return { level: level, value: value }; + }); + + return acc; + }, {}); + } + + Object.keys(tierUpdate).forEach(propertyKey => { + const property = tierUpdate[propertyKey]; + const propertyValues = foundry.utils.getProperty(acc, `${tierKey}.${propertyKey}`)??[]; + foundry.utils.setProperty(acc, `${tierKey}.${propertyKey}`, [...propertyValues, ...property]); + }); + }); + + return acc; + }, { tier1: {}, tier2: {}, tier3: {} }); + + const activeTier = getTier(this.activeLevel); + const data = Object.keys(SYSTEM.ACTOR.levelupData).reduce((acc, tierKey) => { + const tier = SYSTEM.ACTOR.levelupData[tierKey]; + acc[tierKey] = { + label: game.i18n.localize(tier.label), + info: game.i18n.localize(tier.info), + pretext: game.i18n.localize(tier.pretext), + postext: game.i18n.localize(tier.posttext), + active: tierKey <= activeTier, + choices: Object.keys(tier.choices).reduce((acc, propertyKey) => { + const property = tier.choices[propertyKey]; + acc[propertyKey] = { description: property.description, cost: property.cost ?? 1, values: [] }; + for(var i = 0; i < property.maxChoices; i++){ + const leveledValue = leveledTiers[tierKey][propertyKey]?.[i]; + const subclassLock = propertyKey === 'subclass' && Object.keys(multiclassing).find(x => getTier(Number.parseInt(x)) === tierKey); + const subclassMulticlassLock = propertyKey === 'multiclass' && subclassing[tierKey]; + const multiclassLock = propertyKey === 'multiclass' && Object.keys(multiclassing).length > 0 && !(leveledValue && Object.keys(multiclassing).find(x => Number.parseInt(x) === leveledValue.level)); + const locked = leveledValue && leveledValue.level !== this.activeLevel || subclassLock || subclassMulticlassLock || multiclassLock; + const disabled = tierKey > activeTier || (selectedChoices === 2 && !(leveledValue && leveledValue.level === this.activeLevel)) || locked; + + + acc[propertyKey].values.push({ + selected: leveledValue?.value !== undefined, + path: `levelups.${this.activeLevel}.${tierKey}.${propertyKey}.${i}`, + description: game.i18n.localize(property.description), + disabled: disabled, + locked: locked, + }); + } + + return acc; + }, {}) + }; + + return acc; + }, {}); + + return { + data: data, + activeLevel: this.activeLevel, + changedLevel: this.actor.system.levelData.changedLevel, + completedSelection: selectedChoices === 2, + } + } + + static async toggleBox(_, button){ + const path = button.dataset.path; + if(foundry.utils.getProperty(this.data, path)){ + const pathParts = path.split('.'); + const arrayPart = pathParts.slice(0, pathParts.length-1).join('.'); + let array = foundry.utils.getProperty(this.data, arrayPart); + if(button.dataset.levelAttribute === 'multiclass'){ + array = []; + } + else { + delete array[Number.parseInt(pathParts[pathParts.length-1])]; + } + foundry.utils.setProperty(this.data, arrayPart, array); + } else { + const updates = [{ path: path, value: { level: this.activeLevel } }]; + const levelChoices = SYSTEM.ACTOR.levelChoices[button.dataset.levelAttribute]; + if(button.dataset.levelAttribute === 'subclass'){ + if(!this.actor.system.multiclassSubclass){ + updates[0].value.value = { multiclass: false, feature: this.actor.system.subclass.system.specializationFeature.unlocked ? 'mastery' : 'specialization' }; + } + else { + const choices = [{name: this.actor.system.subclass.name, value: this.actor.system.subclass.uuid}, {name: this.actor.system.multiclassSubclass.name, value: this.actor.system.multiclassSubclass.uuid}]; + const indexes = await SelectDialog.selectItem({ actor: this.actor, choices: choices, title: levelChoices.title, nrChoices: 1 }); + if(indexes.length === 0) { + this.render(); + return; + } + const multiclassSubclass = choices[indexes[0]].name === this.actor.system.multiclassSubclass.name; + updates[0].value.value = { multiclass: multiclassSubclass, feature: this.actor.system.multiclassSubclass.system.specializationFeature.unlocked ? 'mastery' : 'specialization' }; + } + } + else if (button.dataset.levelAttribute === 'multiclass'){ + const multiclassAwait = new Promise((resolve) => { + new DhpMulticlassDialog(this.actor.name, this.actor.system.class, resolve).render(true); + }); + const multiclassData = await multiclassAwait; + if(!multiclassData) { + this.render(); + return; + } + + const pathParts = path.split('.'); + const arrayPart = pathParts.slice(0, pathParts.length-1).join('.'); + updates[0] = { path: [arrayPart, '0'].join('.'), value: { level: this.activeLevel, value: { class: multiclassData.class, subclass: multiclassData.subclass, domain: multiclassData.domain, level: this.activeLevel } } }; + updates[1] = { path: [arrayPart, '1'].join('.'), value: { level: this.activeLevel, value: { class: multiclassData.class, subclass: multiclassData.subclass, domain: multiclassData.domain, level: this.activeLevel } } }; + } + else { + if(levelChoices.choices.length > 0){ + if(typeof levelChoices.choices === 'string'){ + const choices = foundry.utils.getProperty(this.actor, levelChoices.choices).map(x => ({ name: x.description, value: x.id })); + const indexes = await SelectDialog.selectItem({ actor: this.actor, choices: choices, title: levelChoices.title, nrChoices: levelChoices.nrChoices }); + if(indexes.length === 0) { + this.render(); + return; + } + updates[0].value.value = choices.filter((_, index) => indexes.includes(index)).map(x => x.value); + } + else { + const indexes = await SelectDialog.selectItem({ actor: this.actor, choices: levelChoices.choices, title: levelChoices.title, nrChoices: levelChoices.nrChoices }); + if(indexes.length === 0) { + this.render(); + return; + } + updates[0].value.value = levelChoices.choices[indexes[0]].path; + } + } + } + + const update = updates.reduce((acc, x) => { + acc[x.path] = x.value; + + return acc; + }, {}); + + this.data = foundry.utils.mergeObject(this.data, update); + } + + this.render(); + } + + static advanceLevel(){ + this.activeLevel += 1; + this.render(); + } + + static async finishLevelup(){ + this.data.currentLevel = this.data.changedLevel; + let multiclass = null; + for(var level in this.data.levelups){ + for(var tier in this.data.levelups[level]){ + for(var category in this.data.levelups[level][tier]) { + for (var value in this.data.levelups[level][tier][category]){ + if(category === 'multiclass'){ + multiclass = this.data.levelups[level][tier][category][value].value; + this.data.levelups[level][tier][category][value] = true; + } else { + this.data.levelups[level][tier][category][value] = this.data.levelups[level][tier][category][value].value ?? true; + } + } + } + } + } + + const tiersMoved = getTier(this.actor.system.levelData.changedLevel, true) - getTier(this.actor.system.levelData.currentLevel, true); + const experiences = Array.from(Array(tiersMoved), (_,index) => ({ id: foundry.utils.randomID(), level: this.actor.system.experiences.length+index*3, description: '', value: 1 })); + + await this.actor.update({ system: { + levelData: this.data, + experiences: [...this.actor.system.experiences, ...experiences], + }}, { diff: false }); + + if(!this.actor.multiclass && multiclass){ + const multiclassClass = (await fromUuid(multiclass.class.uuid)).toObject(); + multiclassClass.system.domains = [multiclass.domain.id]; + multiclassClass.system.multiclass = multiclass.level; + + const multiclassFeatures = []; + for(var i = 0; i < multiclassClass.system.features.length; i++){ + const feature = (await fromUuid(multiclassClass.system.features[i].uuid)).toObject(); + feature.system.multiclass = multiclass.level; + multiclassFeatures.push(feature); + } + + const multiclassSubclass = (await fromUuid(multiclass.subclass.uuid)).toObject(); + multiclassSubclass.system.multiclass = multiclass.level; + + const multiclassSubclassFeatures = {}; + const features = [multiclassSubclass.system.foundationFeature, multiclassSubclass.system.specializationFeature, multiclassSubclass.system.masteryFeature]; + for(var i = 0; i < features.length; i++){ + const path = i === 0 ? 'foundationFeature' : i === 1 ? 'specializationFeature' : 'masteryFeature'; + const feature = features[i]; + for(var ability of feature.abilities){ + const data = (await fromUuid(ability.uuid)).toObject(); + if(i > 0 ) data.system.disabled = true; + data.system.multiclass = multiclass.level; + if(!multiclassSubclassFeatures[path]) multiclassSubclassFeatures[path] = [data]; + else multiclassSubclassFeatures[path].push(data); + // data.uuid = feature.uuid; + + // const abilityData = await this._onDropItemCreate(data); + // ability.uuid = abilityData[0].uuid; + + // createdItems.push(abilityData); + } + } + + for(let subclassFeaturesKey in multiclassSubclassFeatures){ + const values = multiclassSubclassFeatures[subclassFeaturesKey]; + const abilityResults = await this.actor.createEmbeddedDocuments('Item', values); + for(var i = 0; i < abilityResults.length; i++){ + multiclassSubclass.system[subclassFeaturesKey].abilities[i].uuid = abilityResults[i].uuid; + } + } + + await this.actor.createEmbeddedDocuments('Item', [multiclassClass, ...multiclassFeatures, multiclassSubclass]); + } + + + this.close(); + } +} \ No newline at end of file diff --git a/module/applications/multiclassDialog.mjs b/module/applications/multiclassDialog.mjs new file mode 100644 index 00000000..8fd1b251 --- /dev/null +++ b/module/applications/multiclassDialog.mjs @@ -0,0 +1,98 @@ +const {HandlebarsApplicationMixin, ApplicationV2} = foundry.applications.api; + +export default class DhpMulticlassDialog extends HandlebarsApplicationMixin(ApplicationV2) { + constructor(actorName, actorClass, resolve){ + super({}); + + this.actorName = actorName; + this.actorClass = actorClass; + this.resolve = resolve; + + this.classChoices = Array.from(game.items.reduce((acc, x) => { + if(x.type === 'class' && x.name !== actorClass.name){ + acc.add(x); + } + + return acc; + }, new Set())); + this.subclassChoices = []; + this.domainChoices = []; + + this.data = { + class: null, + subclass: null, + domain: null, + }; + } + + get title(){ + return `${this.actorName} - Multiclass`; + } + + static DEFAULT_OPTIONS = { + classes: ["daggerheart", "views", "multiclass"], + position: { width: 600, height: 'auto' }, + actions: { + selectClass: this.selectClass, + selectSubclass: this.selectSubclass, + selectDomain: this.selectDomain, + finish: this.finish, + }, + }; + + static PARTS = { + form: { + id: "levelup", + template: "systems/daggerheart/templates/views/multiclass.hbs" + } + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.classChoices = this.classChoices; + context.subclassChoices = this.subclassChoices; + context.domainChoices = this.domainChoices; + context.disabledFinish = !this.data.class || !this.data.subclass || !this.data.domain; + context.data = this.data; + + return context; + } + + static async selectClass(_, button) { + const oldClass = this.data.class; + this.data.class = this.data.class?.uuid === button.dataset.class ? null : await fromUuid(button.dataset.class); + if(oldClass !== button.dataset.class){ + this.data.subclass = null; + this.data.domain = null; + this.subclassChoices = this.data.class ? this.data.class.system.subclasses : []; + this.domainChoices = this.data.class ? this.data.class.system.domains.map(x => { + const config = SYSTEM.DOMAIN.domains[x]; + return { name: game.i18n.localize(config.name), id: config.id, img: config.src, disabled: this.actorClass.system.domains.includes(config.id) }; + }) : []; + } + + this.render(true); + } + + static async selectSubclass(_, button) { + this.data.subclass = this.data.subclass?.uuid === button.dataset.subclass ? null : this.subclassChoices.find(x => x.uuid === button.dataset.subclass); + this.render(true); + } + + static async selectDomain(_, button) { + const domain = this.data.domain?.id === button.dataset.domain ? null : this.domainChoices.find(x => x.id === button.dataset.domain);; + if(domain?.disabled) return; + + this.data.domain = domain; + this.render(true); + } + + static finish(){ + this.close({}, this.data); + } + + async close(options={}, data=null) { + this.resolve(data); + super.close(options); + } +} \ No newline at end of file diff --git a/module/applications/npcRollSelectionDialog.mjs b/module/applications/npcRollSelectionDialog.mjs new file mode 100644 index 00000000..8f0aa06b --- /dev/null +++ b/module/applications/npcRollSelectionDialog.mjs @@ -0,0 +1,76 @@ +export default class NpcRollSelectionDialog extends FormApplication { + constructor(experiences, resolve, isNpc){ + super({}, {}); + + this.experiences = experiences; + this.resolve = resolve; + this.selectedExperiences = []; + this.data = { + nrDice: 1, + advantage: null, + }; + } + + get title (){ + return 'Roll Options'; + } + + static get defaultOptions() { + const defaults = super.defaultOptions; + const overrides = { + height: 'auto', + width: 400, + id: 'roll-selection', + template: 'systems/daggerheart/templates/views/npcRollSelection.hbs', + closeOnSubmit: false, + submitOnChange: true, + classes: ["daggerheart", "views", "npc-roll-selection"], + }; + + const mergedOptions = foundry.utils.mergeObject(defaults, overrides); + + return mergedOptions; + } + + async getData(){ + const context = super.getData(); + context.nrDice = this.data.nrDice; + context.advantage = this.data.advantage; + context.experiences = this.experiences.map(x => ({ ...x, selected: this.selectedExperiences.find(selected => selected.id === x.id) })); + + return context; + } + + activateListeners(html) { + super.activateListeners(html); + + html.find('.increase').click(_ => this.updateNrDice(1)); + html.find('.decrease').click(_ => this.updateNrDice(-1)); + html.find('.advantage').click(_ => this.updateIsAdvantage(true)); + html.find('.disadvantage').click(_ => this.updateIsAdvantage(false)); + html.find('.roll-button').click(this.finish.bind(this)); + html.find('.roll-dialog-chip').click(this.selectExperience.bind(this)); + } + + updateNrDice(value){ + this.data.nrDice += value; + this.render(); + } + + updateIsAdvantage(advantage) { + this.data.advantage = this.data.advantage === advantage ? null : advantage; + this.render(); + } + + selectExperience(event){ + const experience = this.experiences[event.currentTarget.dataset.key]; + this.selectedExperiences = this.selectedExperiences.find(x => x.name === experience.name) ? this.selectedExperiences.filter(x => x.name !== experience.name) : [...this.selectedExperiences, experience]; + + this.render(); + } + + finish(){ + this.resolve({ ...this.data, experiences: this.selectedExperiences }); + this.close(); + } +} \ No newline at end of file diff --git a/module/applications/rollSelectionDialog.mjs b/module/applications/rollSelectionDialog.mjs new file mode 100644 index 00000000..ff6da549 --- /dev/null +++ b/module/applications/rollSelectionDialog.mjs @@ -0,0 +1,276 @@ +const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; + +export default class RollSelectionDialog extends HandlebarsApplicationMixin(ApplicationV2) { + constructor(experiences, bonusDamage, hopeResource, resolve, isNpc){ + super({}, {}); + + this.experiences = experiences; + this.resolve = resolve; + this.isNpc; + this.selectedExperiences = []; + this.data = { + diceOptions: [{ name: 'd12', value: 'd12' }, { name: 'd20', value: 'd20' }], + hope: ['d12'], + fear: ['d12'], + advantage: null, + disadvantage: null, + bonusDamage: bonusDamage.reduce((acc, x) => { + if(x.appliesOn === SYSTEM.EFFECTS.applyLocations.attackRoll.id){ + acc.push(({ + ...x, + hopeUses: 0 + })); + } + + return acc; + }, []), + hopeResource: hopeResource, + }; + } + + static DEFAULT_OPTIONS = { + tag: 'form', + classes: ["daggerheart", "views", "roll-selection"], + position: { + width: 400, + height: "auto" + }, + actions: { + selectExperience: this.selectExperience, + decreaseHopeUse: this.decreaseHopeUse, + increaseHopeUse: this.increaseHopeUse, + setAdvantage: this.setAdvantage, + setDisadvantage: this.setDisadvantage, + finish: this.finish, + }, + form: { + handler: this.updateSelection, + submitOnChange: true, + submitOnClose: false, + } + }; + + /** @override */ + static PARTS = { + damageSelection: { + id: "damageSelection", + template: "systems/daggerheart/templates/views/rollSelection.hbs" + } + } + + get title() { + return `Roll Options`; + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.isNpc = this.isNpc; + context.diceOptions = this.data.diceOptions; + context.hope = this.data.hope; + context.fear = this.data.fear; + context.advantage = this.data.advantage; + context.disadvantage = this.data.disadvantage; + context.experiences = this.experiences.map(x => ({ ...x, selected: this.selectedExperiences.find(selected => selected.id === x.id) })); + context.bonusDamage = this.data.bonusDamage; + context.hopeResource = this.data.hopeResource+1; + context.hopeUsed = this.getHopeUsed(); + + return context; + } + + static updateSelection(event, _, formData){ + const { bonusDamage, ...rest } = foundry.utils.expandObject(formData.object); + + for(var index in bonusDamage){ + this.data.bonusDamage[index].initiallySelected = bonusDamage[index].initiallySelected; + if(bonusDamage[index].hopeUses){ + const value = Number.parseInt(bonusDamage[index].hopeUses); + if(!Number.isNaN(value)) this.data.bonusDamage[index].hopeUses = value; + } + } + + this.data = foundry.utils.mergeObject(this.data, rest); + this.render(); + } + + static selectExperience(_, button){ + if(this.selectedExperiences.find(x => x.id === button.dataset.key)){ + this.selectedExperiences = this.selectedExperiences.filter(x => x.id !== button.dataset.key); + } else { + this.selectedExperiences = [...this.selectedExperiences, this.experiences.find(x => x.id === button.dataset.key)]; + } + + this.render(); + } + + getHopeUsed(){ + return this.data.bonusDamage.reduce((acc, x) => acc+x.hopeUses, 0); + } + + static decreaseHopeUse(_, button){ + const index = Number.parseInt(button.dataset.index); + if(this.data.bonusDamage[index].hopeUses - 1 >= 0) { + this.data.bonusDamage[index].hopeUses -= 1; + this.render(true); + } + } + + static increaseHopeUse(_, button){ + const index = Number.parseInt(button.dataset.index); + if(this.data.bonusDamage[index].hopeUses <= this.data.hopeResource+1) { + this.data.bonusDamage[index].hopeUses += 1; + this.render(true); + } + } + + static setAdvantage(){ + this.data.advantage = this.data.advantage ? null : 'd6'; + this.data.disadvantage = null; + + this.render(true); + } + + static setDisadvantage(){ + this.data.advantage = null; + this.data.disadvantage = this.data.disadvantage ? null : 'd6'; + + this.render(true); + } + + static async finish(){ + const { diceOptions, ...rest } = this.data; + this.resolve({ ...rest, experiences: this.selectedExperiences, hopeUsed: this.getHopeUsed(), bonusDamage: this.data.bonusDamage.reduce((acc, x) => acc.concat(` + ${1+x.hopeUses}${x.value}`), "") }); + this.close(); + } +} + +// V1.3 +// const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; + +// export default class RollSelectionDialog extends HandlebarsApplicationMixin(ApplicationV2) { +// constructor(experiences, bonusDamage, hopeResource, resolve, isNpc){ +// super({}, {}); + +// this.experiences = experiences; +// this.resolve = resolve; +// this.isNpc; +// this.selectedExperiences = []; +// this.data = { +// diceOptions: [{ name: 'd12', value: 'd12' }, { name: 'd20', value: 'd20' }], +// hope: ['d12'], +// fear: ['d12'], +// advantage: null, +// disadvantage: null, +// bonusDamage: bonusDamage.reduce((acc, x) => { +// if(x.appliesOn === SYSTEM.EFFECTS.applyLocations.attackRoll.id){ +// acc.push(({ +// ...x, +// hopeUses: 0 +// })); +// } + +// return acc; +// }, []), +// hopeResource: hopeResource, +// }; +// } + +// static DEFAULT_OPTIONS = { +// tag: 'form', +// classes: ["daggerheart", "views", "roll-selection"], +// position: { +// width: 400, +// height: "auto" +// }, +// actions: { +// selectExperience: this.selectExperience, +// decreaseHopeUse: this.decreaseHopeUse, +// increaseHopeUse: this.increaseHopeUse, +// finish: this.finish, +// }, +// form: { +// handler: this.updateSelection, +// submitOnChange: true, +// closeOnSubmit: false, +// } +// }; + +// /** @override */ +// static PARTS = { +// damageSelection: { +// id: "damageSelection", +// template: "systems/daggerheart/templates/views/rollSelection.hbs" +// } +// } + +// get title() { +// return `Roll Options`; +// } + +// async _prepareContext(_options) { +// const context = await super._prepareContext(_options); +// context.isNpc = this.isNpc; +// context.diceOptions = this.data.diceOptions; +// context.hope = this.data.hope; +// context.fear = this.data.fear; +// context.advantage = this.data.advantage; +// context.disadvantage = this.data.disadvantage; +// context.experiences = this.experiences.map(x => ({ ...x, selected: this.selectedExperiences.find(selected => selected.id === x.id) })); +// context.bonusDamage = this.data.bonusDamage; +// context.hopeResource = this.data.hopeResource+1; +// context.hopeUsed = this.getHopeUsed(); + +// return context; +// } + +// static updateSelection(event, _, formData){ +// const { bonusDamage, ...rest } = foundry.utils.expandObject(formData.object); + +// for(var index in bonusDamage){ +// this.data.bonusDamage[index].initiallySelected = bonusDamage[index].initiallySelected; +// if(bonusDamage[index].hopeUses){ +// const value = Number.parseInt(bonusDamage[index].hopeUses); +// if(!Number.isNaN(value)) this.data.bonusDamage[index].hopeUses = value; +// } +// } + +// this.data = foundry.utils.mergeObject(this.data, rest); +// this.render(true); +// } + +// static selectExperience(_, button){ +// if(this.selectedExperiences.find(x => x.id === button.dataset.key)){ +// this.selectedExperiences = this.selectedExperiences.filter(x => x.id !== button.dataset.key); +// } else { +// this.selectedExperiences = [...this.selectedExperiences, this.experiences.find(x => x.id === button.dataset.key)]; +// } + +// this.render(); +// } + +// getHopeUsed(){ +// return this.data.bonusDamage.reduce((acc, x) => acc+x.hopeUses, 0); +// } + +// static decreaseHopeUse(_, button){ +// const index = Number.parseInt(button.dataset.index); +// if(this.data.bonusDamage[index].hopeUses - 1 >= 0) { +// this.data.bonusDamage[index].hopeUses -= 1; +// this.render(true); +// } +// } + +// static increaseHopeUse(_, button){ +// const index = Number.parseInt(button.dataset.index); +// if(this.data.bonusDamage[index].hopeUses <= this.data.hopeResource+1) { +// this.data.bonusDamage[index].hopeUses += 1; +// this.render(true); +// } +// } + +// static finish(){ +// const { diceOptions, ...rest } = this.data; +// this.resolve({ ...rest, experiences: this.selectedExperiences, hopeUsed: this.getHopeUsed(), bonusDamage: this.data.bonusDamage.reduce((acc, x) => acc.concat(` + ${1+x.hopeUses}${x.value}`), "") }); +// this.close(); +// } +// } \ No newline at end of file diff --git a/module/applications/settings.mjs b/module/applications/settings.mjs new file mode 100644 index 00000000..94fd651f --- /dev/null +++ b/module/applications/settings.mjs @@ -0,0 +1,282 @@ +class DhpAutomationSettings extends FormApplication { + constructor(object={}, options={}){ + super(object, options); + } + + static get defaultOptions() { + const defaults = super.defaultOptions; + const overrides = { + height: 'auto', + width: 400, + id: 'daggerheart-automation-settings', + template: 'systems/daggerheart/templates/views/automation-settings.hbs', + closeOnSubmit: true, + submitOnChange: false, + classes: ["daggerheart", "views", "settings"], + }; + + const mergedOptions = foundry.utils.mergeObject(defaults, overrides); + + return mergedOptions; + } + + async getData(){ + const context = super.getData(); + context.settings = SYSTEM.SETTINGS.gameSettings.Automation; + context.hope = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.Hope); + context.actionPoints = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.ActionPoints); + + return context; + } + + activateListeners(html) { + super.activateListeners(html); + } + + async _updateObject(_, formData) { + const data = foundry.utils.expandObject(formData); + const updateSettingsKeys = Object.keys(data); + for(var i = 0; i < updateSettingsKeys.length; i++){ + await game.settings.set(SYSTEM.id, updateSettingsKeys[i], data[updateSettingsKeys[i]]); + } + } +} + +class DhpHomebrewSettings extends FormApplication { + constructor(object={}, options={}){ + super(object, options); + } + + static get defaultOptions() { + const defaults = super.defaultOptions; + const overrides = { + height: 'auto', + width: 400, + id: 'daggerheart-homebrew-settings', + template: 'systems/daggerheart/templates/views/homebrew-settings.hbs', + closeOnSubmit: true, + submitOnChange: false, + classes: ["daggerheart", "views", "settings"], + }; + + const mergedOptions = foundry.utils.mergeObject(defaults, overrides); + + return mergedOptions; + } + + async getData(){ + const context = super.getData(); + context.settings = SYSTEM.SETTINGS.gameSettings.General; + context.abilityArray = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.General.AbilityArray); + + return context; + } + + activateListeners(html) { + super.activateListeners(html); + } + + async _updateObject(_, formData) { + const data = foundry.utils.expandObject(formData); + const updateSettingsKeys = Object.keys(data); + for(var i = 0; i < updateSettingsKeys.length; i++){ + await game.settings.set(SYSTEM.id, updateSettingsKeys[i], data[updateSettingsKeys[i]]); + } + } +} + +class DhpRangeSettings extends FormApplication { + constructor(object={}, options={}){ + super(object, options); + + this.range = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.General.RangeMeasurement); + } + + static get defaultOptions() { + const defaults = super.defaultOptions; + const overrides = { + height: 'auto', + width: 400, + id: 'daggerheart-range-settings', + template: 'systems/daggerheart/templates/views/range-settings.hbs', + closeOnSubmit: false, + submitOnChange: true, + classes: ["daggerheart", "views", "settings"], + }; + + const mergedOptions = foundry.utils.mergeObject(defaults, overrides); + + return mergedOptions; + } + + async getData(){ + const context = super.getData(); + context.settings = SYSTEM.SETTINGS.gameSettings.General; + context.range = this.range; + context.disabled = context.range.enabled && [context.range.melee, context.range.veryClose, context.range.close, context.range.far, context.range.veryFar].some(x => x === null || x === false); + + return context; + } + + activateListeners(html) { + super.activateListeners(html); + + html.find(".range-reset").click(this.reset.bind(this)); + html.find(".save").click(this.save.bind(this)); + html.find(".close").click(this.close.bind(this)); + } + + async _updateObject(_, formData) { + const data = foundry.utils.expandObject(formData, { disabled: true }); + this.range = foundry.utils.mergeObject(this.range, data); + this.render(true); + } + + reset(){ + this.range = { + enabled: false, + melee: 5, + veryClose: 15, + close: 30, + far: 60, + veryFar: 120 + }; + this.render(true); + } + + async save(){ + await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.General.RangeMeasurement, this.range); + this.close(); + } +} + +export const registerDHPSettings = () => { + // const debouncedReload = foundry.utils.debounce(() => window.location.reload(), 100); + + game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.General.AbilityArray, { + name: game.i18n.localize("DAGGERHEART.Settings.General.AbilityArray.Name"), + hint: game.i18n.localize("DAGGERHEART.Settings.General.AbilityArray.Hint"), + scope: 'world', + config: false, + type: String, + default: '[2,1,1,0,0,-1]', + }); + + game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear, { + name: game.i18n.localize("DAGGERHEART.Settings.Resources.Fear.Name"), + hint: game.i18n.localize("DAGGERHEART.Settings.Resources.Fear.Hint"), + scope: 'world', + config: false, + type: Number, + default: 0, + }); + + game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.Hope, { + name: game.i18n.localize("DAGGERHEART.Settings.Automation.Hope.Name"), + hint: game.i18n.localize("DAGGERHEART.Settings.Automation.Hope.Hint"), + scope: 'world', + config: false, + type: Boolean, + default: false, + }); + + game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.ActionPoints, { + name: game.i18n.localize("DAGGERHEART.Settings.Automation.ActionPoints.Name"), + hint: game.i18n.localize("DAGGERHEART.Settings.Automation.ActionPoints.Hint"), + scope: 'world', + config: false, + type: Boolean, + default: true, + }); + + game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.General.RangeMeasurement, { + name: game.i18n.localize("DAGGERHEART.Settings.General.RangeMeasurement.Name"), + hint: game.i18n.localize("DAGGERHEART.Settings.General.RangeMeasurement.Hint"), + scope: 'world', + config: false, + type: Object, + default: { + enabled: false, + melee: 5, + veryClose: 15, + close: 30, + far: 60, + veryFar: 120 + }, + }); + + game.settings.registerMenu(SYSTEM.id, SYSTEM.SETTINGS.menu.Automation.Name, { + name: game.i18n.localize("DAGGERHEART.Settings.Menu.Automation.Name"), + label: game.i18n.localize("DAGGERHEART.Settings.Menu.Automation.Label"), + hint: game.i18n.localize("DAGGERHEART.Settings.Menu.Automation.Hint"), + icon: SYSTEM.SETTINGS.menu.Automation.Icon, + type: DhpAutomationSettings, + restricted: true + }); + game.settings.registerMenu(SYSTEM.id, SYSTEM.SETTINGS.menu.Homebrew.Name, { + name: game.i18n.localize("DAGGERHEART.Settings.Menu.Homebrew.Name"), + label: game.i18n.localize("DAGGERHEART.Settings.Menu.Homebrew.Label"), + hint: game.i18n.localize("DAGGERHEART.Settings.Menu.Homebrew.Hint"), + icon: SYSTEM.SETTINGS.menu.Homebrew.Icon, + type: DhpHomebrewSettings, + restricted: true + }); + game.settings.registerMenu(SYSTEM.id, SYSTEM.SETTINGS.menu.Range.Name, { + name: game.i18n.localize("DAGGERHEART.Settings.Menu.Range.Name"), + label: game.i18n.localize("DAGGERHEART.Settings.Menu.Range.Label"), + hint: game.i18n.localize("DAGGERHEART.Settings.Menu.Range.Hint"), + icon: SYSTEM.SETTINGS.menu.Range.Icon, + type: DhpRangeSettings, + restricted: true + }); +} + + +// const {HandlebarsApplicationMixin, ApplicationV2} = foundry.applications.api; + +// export default class DhpSettings extends HandlebarsApplicationMixin(ApplicationV2) { +// constructor(actor, shortrest){ +// super({}); + +// this.actor = actor; +// this.selectedActivity = null; +// this.shortrest = shortrest; + +// this.customActivity = SYSTEM.GENERAL.downtime.custom; +// } + +// get title(){ +// return game.i18n.localize("DAGGERHEART.Application.Settings.Title"); +// } + +// static DEFAULT_OPTIONS = { +// tag: 'form', +// classes: ["daggerheart", "application", "settings"], +// position: { width: 800, height: 'auto' }, +// actions: { +// selectActivity: this.selectActivity, +// }, +// form: { handler: this.updateData } +// }; + +// static PARTS = { +// application: { +// id: "settings", +// template: "systems/daggerheart/templates/application/settings.hbs" +// } +// } + +// async _prepareContext(_options) { +// const context = await super._prepareContext(_options); + +// return context; +// } + +// static async updateData(event, element, formData){ +// this.render(); +// } + +// static close(){ +// super.close(); +// } +// } \ No newline at end of file diff --git a/module/applications/sheets/adversary.mjs b/module/applications/sheets/adversary.mjs new file mode 100644 index 00000000..f13480f2 --- /dev/null +++ b/module/applications/sheets/adversary.mjs @@ -0,0 +1,377 @@ + +// import DhpApplicationMixin from '../daggerheart-sheet.mjs'; + +// export class Teest extends DhpApplicationMixin(ActorSheet) { +// static documentType = "adversary"; + +// constructor(options){ +// super(options); + +// this.editMode = false; +// } + +// /** @override */ +// static get defaultOptions() { +// return foundry.utils.mergeObject(super.defaultOptions, { +// classes: ["daggerheart", "sheet", "adversary"], +// width: 600, +// height: 'auto', +// resizable: false, +// }); +// } + +// async getData() { +// const context = super.getData(); +// context.config = SYSTEM; +// context.editMode = this.editMode; +// context.title = `${this.actor.name} - ${game.i18n.localize(SYSTEM.ACTOR.adversaryTypes[this.actor.system.type].name)}`; + +// context.data = { +// description: this.object.system.description, +// motivesAndTactics: this.object.system.motivesAndTactics.join(', '), +// tier: this.object.system.tier, +// type: game.i18n.localize(SYSTEM.ACTOR.adversaryTypes[this.object.system.type].name), +// attack: { +// name: this.object.system.attack.name, +// attackModifier: this.object.system.attackModifier, +// range: this.object.system.attack.range ? game.i18n.localize(SYSTEM.GENERAL.range[this.object.system.attack.range].name) : null, +// damage: { +// value: this.object.system.attack.damage.value, +// type: this.object.system.attack.damage.type, +// typeName: this.object.system.attack.damage.type ? game.i18n.localize(SYSTEM.GENERAL.damageTypes[this.object.system.attack.damage.type].abbreviation).toLowerCase() : null, +// }, +// }, +// damageThresholds: this.object.system.damageThresholds, +// difficulty: this.object.system.difficulty, +// hp: { ...this.object.system.resources.health, lastRowIndex: Math.floor(this.object.system.resources.health.max/5)*5 }, +// stress: { ...this.object.system.resources.stress, lastRowIndex: Math.floor(this.object.system.resources.stress.max/5)*5 }, +// moves: this.object.system.moves, +// }; + +// return context; +// } + +// async _handleAction(action, event, button) { +// switch(action){ +// case 'viewMove': +// await this.viewMove(button); +// break; +// case 'addMove': +// this.addMove(); +// break; +// case 'removeMove': +// await this.removeMove(button); +// break; +// case 'toggleSlider': +// this.toggleEditMode(); +// break; +// case 'addMotive': +// await this.addMotive(); +// break; +// case 'removeMotive': +// await this.removeMotive(button); +// break; +// case 'reactionRoll': +// await this.reactionRoll(event); +// break; +// case 'attackRoll': +// await this.attackRoll(event); +// break; +// case 'addExperience': +// await this.addExperience(); +// break; +// case 'removeExperience': +// await this.removeExperience(button); +// break; +// case 'toggleHP': +// await this.toggleHP(button); +// break; +// case 'toggleStress': +// await this.toggleStress(button); +// break; +// } +// } + +// async viewMove(button){ +// const move = await fromUuid(button.dataset.move); +// move.sheet.render(true); +// } + +// async addMove(){ +// const result = await this.object.createEmbeddedDocuments("Item", [{ +// name: game.i18n.localize('DAGGERHEART.Sheets.Adversary.NewMove'), +// type: 'feature', +// }]); + +// await result[0].sheet.render(true); +// } + +// async removeMove(button){ +// await this.object.items.find(x => x.uuid === button.dataset.move).delete(); +// } + +// toggleEditMode(){ +// this.editMode = !this.editMode; +// this.render(); +// } + +// async addMotive(){ +// await this.object.update({ "system.motivesAndTactics": [...this.object.system.motivesAndTactics, ''] }); +// } + +// async removeMotive(button){ +// await this.object.update({ "system.motivesAndTactics": this.object.system.motivesAndTactics.filter((_, index) => index !== Number.parseInt(button.dataset.motive) )}); +// } + +// async reactionRoll(event){ +// const { roll, diceResults, modifiers } = await this.actor.diceRoll({ title: `${this.actor.name} - Reaction Roll`, value: 0 }, event.shiftKey); + +// const cls = getDocumentClass("ChatMessage"); +// const msg = new cls({ +// type: 'adversaryRoll', +// system: { +// roll: roll._formula, +// total: roll._total, +// modifiers: modifiers, +// diceResults: diceResults, +// }, +// content: "systems/daggerheart/templates/chat/adversary-roll.hbs", +// rolls: [roll] +// }); + +// cls.create(msg.toObject()); +// } + +// async attackRoll(event){ +// const modifier = Number.parseInt(event.currentTarget.dataset.value); + +// const { roll, diceResults, modifiers } = await this.actor.diceRoll({ title: `${this.actor.name} - Attack Roll`, value: modifier }, event.shiftKey); + +// const targets = Array.from(game.user.targets).map(x => ({ +// id: x.id, +// name: x.actor.name, +// img: x.actor.img, +// difficulty: x.actor.system.difficulty, +// evasion: x.actor.system.evasion, +// })); + +// const cls = getDocumentClass("ChatMessage"); +// const msg = new cls({ +// type: 'adversaryRoll', +// system: { +// roll: roll._formula, +// total: roll._total, +// modifiers: modifiers, +// diceResults: diceResults, +// targets: targets, +// damage: { value: event.currentTarget.dataset.damage, type: event.currentTarget.dataset.damageType }, +// }, +// content: "systems/daggerheart/templates/chat/adversary-attack-roll.hbs", +// rolls: [roll] +// }); + +// cls.create(msg.toObject()); +// } + +// async addExperience(){ +// await this.object.update({ "system.experiences": [...this.object.system.experiences, { name: 'Experience', value: 1 }] }); +// } + +// async removeExperience(button){ +// await this.object.update({ "system.experiences": this.object.system.experiences.filter((_, index) => index !== Number.parseInt(button.dataset.experience) )}); +// } + +// async toggleHP(button){ +// const index = Number.parseInt(button.dataset.index); +// const newHP = index < this.object.system.resources.health.value ? index : index+1; +// await this.object.update({ "system.resources.health.value": newHP }); +// } + +// async toggleStress(button){ +// const index = Number.parseInt(button.dataset.index); +// const newStress = index < this.object.system.resources.stress.value ? index : index+1; +// await this.object.update({ "system.resources.stress.value": newStress }); +// } +// } + +import DaggerheartSheet from './daggerheart-sheet.mjs'; + +const { ActorSheetV2 } = foundry.applications.sheets; +export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) { + constructor(options={}){ + super(options); + + this.editMode = false; + } + + static DEFAULT_OPTIONS = { + tag: 'form', + id: "daggerheart-adversary", + classes: ["daggerheart", "sheet", "adversary"], + position: { width: 600 }, + actions: { + viewMove: this.viewMove, + addMove: this.addMove, + removeMove: this.removeMove, + toggleSlider: this.toggleEditMode, + addMotive: this.addMotive, + removeMotive: this.removeMotive, + reactionRoll: this.reactionRoll, + attackRoll: this.attackRoll, + addExperience: this.addExperience, + removeExperience: this.removeExperience, + toggleHP: this.toggleHP, + toggleStress: this.toggleStress, + }, + form: { + handler: this.updateForm, + submitOnChange: true, + closeOnSubmit: false, + }, + }; + + static PARTS = { + form: { + id: "feature", + template: "systems/daggerheart/templates/sheets/adversary.hbs" + } + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.document = this.document; + context.config = SYSTEM; + context.editMode = this.editMode; + context.title = `${this.actor.name} - ${game.i18n.localize(SYSTEM.ACTOR.adversaryTypes[this.actor.system.type].name)}`; + + context.data = { + description: this.document.system.description, + motivesAndTactics: this.document.system.motivesAndTactics.join(', '), + tier: this.document.system.tier, + type: game.i18n.localize(SYSTEM.ACTOR.adversaryTypes[this.document.system.type].name), + attack: { + name: this.document.system.attack.name, + attackModifier: this.document.system.attackModifier, + range: this.document.system.attack.range ? game.i18n.localize(SYSTEM.GENERAL.range[this.document.system.attack.range].name) : null, + damage: { + value: this.document.system.attack.damage.value, + type: this.document.system.attack.damage.type, + typeName: this.document.system.attack.damage.type ? game.i18n.localize(SYSTEM.GENERAL.damageTypes[this.document.system.attack.damage.type].abbreviation).toLowerCase() : null, + }, + }, + damageThresholds: this.document.system.damageThresholds, + difficulty: this.document.system.difficulty, + hp: { ...this.document.system.resources.health, lastRowIndex: Math.floor(this.document.system.resources.health.max/5)*5 }, + stress: { ...this.document.system.resources.stress, lastRowIndex: Math.floor(this.document.system.resources.stress.max/5)*5 }, + moves: this.document.system.moves, + }; + + return context; + } + + static async updateForm(event, _, formData) { + await this.document.update(formData.object) + this.render(); + } + + static async viewMove(_, button){ + const move = await fromUuid(button.dataset.move); + move.sheet.render(true); + } + + static async addMove(){ + const result = await this.document.createEmbeddedDocuments("Item", [{ + name: game.i18n.localize('DAGGERHEART.Sheets.Adversary.NewMove'), + type: 'feature', + }]); + + await result[0].sheet.render(true); + } + + static async removeMove(_, button){ + await this.document.items.find(x => x.uuid === button.dataset.move).delete(); + } + + static toggleEditMode(){ + this.editMode = !this.editMode; + this.render(); + } + + static async addMotive(){ + await this.document.update({ "system.motivesAndTactics": [...this.document.system.motivesAndTactics, ''] }); + } + + static async removeMotive(button){ + await this.document.update({ "system.motivesAndTactics": this.document.system.motivesAndTactics.filter((_, index) => index !== Number.parseInt(button.dataset.motive) )}); + } + + static async reactionRoll(event){ + const { roll, diceResults, modifiers } = await this.actor.diceRoll({ title: `${this.actor.name} - Reaction Roll`, value: 0 }, event.shiftKey); + + const cls = getDocumentClass("ChatMessage"); + const msg = new cls({ + type: 'adversaryRoll', + system: { + roll: roll._formula, + total: roll._total, + modifiers: modifiers, + diceResults: diceResults, + }, + content: "systems/daggerheart/templates/chat/adversary-roll.hbs", + rolls: [roll] + }); + + cls.create(msg.toObject()); + } + + static async attackRoll(event, button){ + const modifier = Number.parseInt(button.dataset.value); + + const { roll, diceResults, modifiers } = await this.actor.diceRoll({ title: `${this.actor.name} - Attack Roll`, value: modifier }, event.shiftKey); + + const targets = Array.from(game.user.targets).map(x => ({ + id: x.id, + name: x.actor.name, + img: x.actor.img, + difficulty: x.actor.system.difficulty, + evasion: x.actor.system.evasion, + })); + + const cls = getDocumentClass("ChatMessage"); + const msg = new cls({ + type: 'adversaryRoll', + system: { + roll: roll._formula, + total: roll._total, + modifiers: modifiers, + diceResults: diceResults, + targets: targets, + damage: { value: button.dataset.damage, type: button.dataset.damageType }, + }, + content: "systems/daggerheart/templates/chat/adversary-attack-roll.hbs", + rolls: [roll] + }); + + cls.create(msg.toObject()); + } + + static async addExperience(){ + await this.document.update({ "system.experiences": [...this.document.system.experiences, { name: 'Experience', value: 1 }] }); + } + + static async removeExperience(_, button){ + await this.document.update({ "system.experiences": this.document.system.experiences.filter((_, index) => index !== Number.parseInt(button.dataset.experience) )}); + } + + static async toggleHP(_, button){ + const index = Number.parseInt(button.dataset.index); + const newHP = index < this.document.system.resources.health.value ? index : index+1; + await this.document.update({ "system.resources.health.value": newHP }); + } + + static async toggleStress(_, button){ + const index = Number.parseInt(button.dataset.index); + const newStress = index < this.document.system.resources.stress.value ? index : index+1; + await this.document.update({ "system.resources.stress.value": newStress }); + } +} \ No newline at end of file diff --git a/module/applications/sheets/ancestry.mjs b/module/applications/sheets/ancestry.mjs new file mode 100644 index 00000000..b71b1508 --- /dev/null +++ b/module/applications/sheets/ancestry.mjs @@ -0,0 +1,117 @@ +// import DhpApplicationMixin from '../daggerheart-sheet.mjs'; + +// export default class AncestrySheet extends DhpApplicationMixin(ItemSheet) { +// static documentType = "ancestry"; + +// constructor(options){ +// super(options); +// } + +// /** @override */ +// static get defaultOptions() { +// return foundry.utils.mergeObject(super.defaultOptions, { +// classes: ["daggerheart", "sheet", "heritage"], +// width: 600, +// height: 'auto', +// dragDrop: [{ dragSelector: null, dropSelector: null }], +// }); +// } + +// /** @override */ +// getData() { +// const context = super.getData(); + +// return context; +// } + + +// async _handleAction(action, event, button) { +// switch(action){ +// case 'editAbility': +// this.editAbility(button); +// break; +// case 'deleteAbility': +// this.deleteAbility(event); +// break; +// } +// } + +// async editAbility(button){ +// const feature = await fromUuid(button.dataset.ability); +// feature.sheet.render(true); +// } + +// async deleteAbility(event){ +// event.preventDefault(); +// event.stopPropagation(); +// await this.item.update({ "system.abilities": this.item.system.abilities.filter(x => x.uuid !== event.currentTarget.dataset.ability) }) +// } + +// async _onDrop(event) { +// const data = TextEditor.getDragEventData(event); +// const item = await fromUuid(data.uuid); +// if(item.type === 'feature' && item.system.type === SYSTEM.ITEM.featureTypes.ancestry.id) { +// await this.object.update({ "system.abilities": [...this.item.system.abilities, { img: item.img, name: item.name, uuid: item.uuid }] }); +// } +// } +// } + +import DaggerheartSheet from './daggerheart-sheet.mjs'; + +const { ItemSheetV2 } = foundry.applications.sheets; +export default class AncestrySheet extends DaggerheartSheet(ItemSheetV2) { + static DEFAULT_OPTIONS = { + tag: 'form', + id: "daggerheart-ancestry", + classes: ["daggerheart", "sheet", "heritage"], + position: { width: 600 }, + actions: { + editAbility: this.editAbility, + deleteAbility: this.deleteAbility, + }, + form: { + handler: this.updateForm, + submitOnChange: true, + closeOnSubmit: false, + }, + dragDrop: [{ dragSelector: null, dropSelector: null }], + }; + + static PARTS = { + form: { + id: "feature", + template: "systems/daggerheart/templates/sheets/ancestry.hbs" + } + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.document = this.document; + + return context; + } + + static async updateForm(event, _, formData) { + await this.document.update(formData.object) + this.render(); + } + + static async editAbility(_, button){ + const feature = await fromUuid(button.dataset.ability); + feature.sheet.render(true); + } + + static async deleteAbility(event, button){ + event.preventDefault(); + event.stopPropagation(); + await this.item.update({ "system.abilities": this.item.system.abilities.filter(x => x.uuid !== button.dataset.ability) }) + } + + async _onDrop(event) { + const data = TextEditor.getDragEventData(event); + const item = await fromUuid(data.uuid); + if(item.type === 'feature' && item.system.type === SYSTEM.ITEM.featureTypes.ancestry.id) { + await this.document.update({ "system.abilities": [...this.document.system.abilities, { img: item.img, name: item.name, uuid: item.uuid }] }); + } + } +} \ No newline at end of file diff --git a/module/applications/sheets/armor.mjs b/module/applications/sheets/armor.mjs new file mode 100644 index 00000000..2be493dd --- /dev/null +++ b/module/applications/sheets/armor.mjs @@ -0,0 +1,65 @@ +// import DhpApplicationMixin from '../daggerheart-sheet.mjs'; + +// export default class ArmorSheet extends DhpApplicationMixin(ItemSheet) { +// static documentType = "armor"; + +// /** @override */ +// static get defaultOptions() { +// return foundry.utils.mergeObject(super.defaultOptions, { +// classes: ["daggerheart", "sheet", "armor"], +// width: 400, +// height: 'auto', +// }); +// } + +// /** @override */ +// getData() { +// const context = super.getData(); +// context.config = CONFIG.daggerheart; + +// return context; +// } + + +// async _handleAction(action, event, button) { +// switch(action){ +// } +// } +// } +import DaggerheartSheet from './daggerheart-sheet.mjs'; + +const { ItemSheetV2 } = foundry.applications.sheets; +export default class ArmorSheet extends DaggerheartSheet(ItemSheetV2) { + static DEFAULT_OPTIONS = { + tag: 'form', + id: "daggerheart-armor", + classes: ["daggerheart", "sheet", "armor"], + position: { width: 400 }, + form: { + handler: this.updateForm, + submitOnChange: true, + closeOnSubmit: false, + }, + dragDrop: [{ dragSelector: null, dropSelector: null }], + }; + + static PARTS = { + form: { + id: "feature", + template: "systems/daggerheart/templates/sheets/armor.hbs" + } + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.document = this.document; + context.config = CONFIG.daggerheart; + + return context; + } + + static async updateForm(event, _, formData) { + await this.document.update(formData.object) + this.render(); + } +} \ No newline at end of file diff --git a/module/applications/sheets/class.mjs b/module/applications/sheets/class.mjs new file mode 100644 index 00000000..d75e2dac --- /dev/null +++ b/module/applications/sheets/class.mjs @@ -0,0 +1,419 @@ +// import DhpApplicationMixin from '../daggerheart-sheet.mjs'; +// import Tagify from '@yaireo/tagify'; + +// export default class ClassSheet extends DhpApplicationMixin(ItemSheet) { +// static documentType = "class"; + +// /** @override */ +// static get defaultOptions() { +// return foundry.utils.mergeObject(super.defaultOptions, { +// classes: ["daggerheart", "sheet", "class"], +// width: 600, +// height: 'auto', +// resizable: false, +// tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "features" }], +// dragDrop: [ +// { dragSelector: '.suggested-item', dropSelector: null }, +// { dragSelector: null, dropSelector: '.take-section' }, +// { dragSelector: null, dropSelector: '.choice-a-section' }, +// { dragSelector: null, dropSelector: '.choice-b-section' }, +// { dragSelector: null, dropSelector: '.primary-weapon-section' }, +// { dragSelector: null, dropSelector: '.secondary-weapon-section' }, +// { dragSelector: null, dropSelector: '.armor-section' }, +// { dragSelector: null, dropSelector: null }, +// ] +// }); +// } + +// /** @override */ +// async getData() { +// const context = super.getData(); +// context.domains = this.object.system.domains.map(x => SYSTEM.DOMAIN.domains[x].name) + +// return context; +// } + +// activateListeners(html){ +// super.activateListeners(html); + +// const domainInput = $(html).find('.domain-input')[0]; +// const domainTagify = new Tagify(domainInput, { +// tagTextProp: "name", +// enforceWhitelist: true, +// whitelist : Object.keys(SYSTEM.DOMAIN.domains).map(key => { +// const domain = SYSTEM.DOMAIN.domains[key]; +// return { value: key, name: game.i18n.localize(domain.name), src: domain.src, background: domain.background }; +// }), +// maxTags: 2, +// callbacks : { invalid: this.onAddTag }, +// dropdown : { +// mapValueTo: 'name', +// searchKeys: ['name'], +// enabled: 0, +// maxItems: 20, +// closeOnSelect : true, +// highlightFirst: false, +// }, +// templates: { +// tag(tagData){ //z-index: unset; background-image: ${tagData.background}; Maybe a domain specific background for the chips? +// return ` +// +//
+// `; +// }} +// }); + +// domainTagify.on('change', this.onDomainSelect.bind(this)); +// } + +// onAddTag(e){ +// if( e.detail.index ===2 ){ +// ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.ClassCanOnlyHaveTwoDomains")); +// } +// } + +// async onDomainSelect(event) { +// const domains = event.detail?.value ? JSON.parse(event.detail.value) : []; +// await this.object.update({ "system.domains": domains.map(x => x.value) }); +// this.render(true); +// } + +// async _handleAction(action, event, button) { +// switch(action){ +// case 'removeSubclass': +// await this.removeSubclass(button); +// break; +// case 'viewSubclass': +// await this.viewSubclass(button); +// break; +// case 'removeFeature': +// await this.removeFeature(button); +// break; +// case 'viewFeature': +// await this.viewFeature(button); +// break; +// case 'removeItem': +// await this.removeItem(event); +// break; +// case 'viewItem': +// await this.viewItem(button); +// break; +// case 'removePrimaryWeapon': +// await this.removePrimaryWeapon(event); +// break; +// case 'removeSecondaryWeapon': +// await this.removeSecondaryWeapon(event); +// break; +// case 'removeArmor': +// await this.removeArmor(event); +// break; +// } +// } + +// async removeSubclass(button){ +// await this.object.update({ "system.subclasses": this.object.system.subclasses.filter(x => x.uuid !== button.dataset.subclass)}); +// } + +// async viewSubclass(button){ +// const subclass = await fromUuid(button.dataset.subclass); +// subclass.sheet.render(true); +// } + +// async removeFeature(button){ +// await this.object.update({ "system.features": this.object.system.features.filter(x => x.uuid !== button.dataset.feature)}); +// } + +// async viewFeature(button){ +// const feature = await fromUuid(button.dataset.feature); +// feature.sheet.render(true); +// } + +// async removeItem(event){ +// event.stopPropagation(); +// const type = event.currentTarget.dataset.type; +// const path = `system.inventory.${type}`; +// await this.object.update({ [path]: this.object.system.inventory[type].filter(x => x.uuid !== event.currentTarget.dataset.item)}); +// } + +// async viewItem(button){ +// const item = await fromUuid(button.dataset.item); +// item.sheet.render(true); +// } + +// async removePrimaryWeapon(event){ +// event.stopPropagation(); +// await this.object.update({ "system.characterGuide.suggestedPrimaryWeapon": null }, { diff: false }); +// } + +// async removeSecondaryWeapon(event){ +// event.stopPropagation(); +// await this.object.update({ "system.characterGuide.suggestedSecondaryWeapon": null }, { diff: false }); +// } + +// async removeArmor(event){ +// event.stopPropagation(); +// await this.object.update({ "system.characterGuide.suggestedArmor": null }, { diff: false }); +// } + +// async _onDragStart(event){ +// if(event.currentTarget.classList.contains('suggested-item')){ +// event.dataTransfer.setData("text/plain", JSON.stringify({ type: 'Item', uuid: event.currentTarget.dataset.item })); +// } + +// super._onDragStart(event); +// } + +// async _onDrop(event) { +// const data = TextEditor.getDragEventData(event); +// const item = await fromUuid(data.uuid); +// if(item.type === 'subclass') { +// await this.object.update({ "system.subclasses": [...this.object.system.subclasses, { img: item.img, name: item.name, uuid: item.uuid }] }); +// } +// else if(item.type === 'feature') { + +// await this.object.update({ "system.features": [...this.object.system.features, { img: item.img, name: item.name, uuid: item.uuid }] }); +// } +// else if(item.type === 'weapon'){ +// if(event.currentTarget.classList.contains('primary-weapon-section')){ +// if(!this.object.system.characterGuide.suggestedPrimaryWeapon && !item.system.secondary) await this.object.update({ "system.characterGuide.suggestedPrimaryWeapon": { img: item.img, name: item.name, uuid: item.uuid } }); +// } else if(event.currentTarget.classList.contains('secondary-weapon-section')){ +// if(!this.object.system.characterGuide.suggestedSecondaryWeapon && item.system.secondary) await this.object.update({ "system.characterGuide.suggestedSecondaryWeapon": { img: item.img, name: item.name, uuid: item.uuid } }); +// } +// } +// else if(item.type === 'armor'){ +// if(event.currentTarget.classList.contains('armor-section')){ +// if(!this.object.system.characterGuide.suggestedArmor) await this.object.update({ "system.characterGuide.suggestedArmor": { img: item.img, name: item.name, uuid: item.uuid } }); +// } +// } +// else if(event.currentTarget.classList.contains('choice-a-section')){ +// if(item.type === 'miscellaneous' || item.type === 'consumable'){ +// if(this.object.system.inventory.choiceA.length < 2) await this.object.update({ "system.inventory.choiceA": [...this.object.system.inventory.choiceA, { img: item.img, name: item.name, uuid: item.uuid }] }); +// } +// } +// else if(item.type === 'miscellaneous'){ +// if(event.currentTarget.classList.contains('take-section')){ +// if(this.object.system.inventory.take.length < 3) await this.object.update({ "system.inventory.take": [...this.object.system.inventory.take, { img: item.img, name: item.name, uuid: item.uuid }] }); +// } +// else if(event.currentTarget.classList.contains('choice-b-section')){ +// if(this.object.system.inventory.choiceB.length < 2) await this.object.update({ "system.inventory.choiceB": [...this.object.system.inventory.choiceB, { img: item.img, name: item.name, uuid: item.uuid }] }); +// } +// } +// } +// } + +import DaggerheartSheet from './daggerheart-sheet.mjs'; +import Tagify from "@yaireo/tagify"; + +const { ItemSheetV2 } = foundry.applications.sheets; +export default class ClassSheet extends DaggerheartSheet(ItemSheetV2) { + static DEFAULT_OPTIONS = { + tag: 'form', + id: "daggerheart-class", + classes: ["daggerheart", "sheet", "class"], + position: { width: 600 }, + actions: { + removeSubclass: this.removeSubclass, + viewSubclass: this.viewSubclass, + removeFeature: this.removeFeature, + viewFeature: this.viewFeature, + removeItem: this.removeItem, + viewItem: this.viewItem, + removePrimaryWeapon: this.removePrimaryWeapon, + removeSecondaryWeapon: this.removeSecondaryWeapon, + removeArmor: this.removeArmor, + + }, + form: { + handler: this.updateForm, + submitOnChange: true, + closeOnSubmit: false, + }, + dragDrop: [ + { dragSelector: '.suggested-item', dropSelector: null }, + { dragSelector: null, dropSelector: '.take-section' }, + { dragSelector: null, dropSelector: '.choice-a-section' }, + { dragSelector: null, dropSelector: '.choice-b-section' }, + { dragSelector: null, dropSelector: '.primary-weapon-section' }, + { dragSelector: null, dropSelector: '.secondary-weapon-section' }, + { dragSelector: null, dropSelector: '.armor-section' }, + { dragSelector: null, dropSelector: null }, + ] + }; + + static PARTS = { + form: { + id: "feature", + template: "systems/daggerheart/templates/sheets/class.hbs" + } + } + + _getTabs() { + const tabs = { + features: { active: true, cssClass: '', group: 'primary', id: 'features', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.Class.Tabs.Features') }, + guide: { active: false, cssClass: '', group: 'primary', id: 'guide', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.Class.Tabs.Guide') }, + } + for ( const v of Object.values(tabs) ) { + v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active; + v.cssClass = v.active ? "active" : ""; + } + + return tabs; + } + + _attachPartListeners(partId, htmlElement, options) { + super._attachPartListeners(partId, htmlElement, options); + + const domainInput = htmlElement.querySelector('.domain-input'); + const domainTagify = new Tagify(domainInput, { + tagTextProp: "name", + enforceWhitelist: true, + whitelist : Object.keys(SYSTEM.DOMAIN.domains).map(key => { + const domain = SYSTEM.DOMAIN.domains[key]; + return { value: key, name: game.i18n.localize(domain.label), src: domain.src, background: domain.background }; + }), + maxTags: 2, + callbacks : { invalid: this.onAddTag }, + dropdown : { + mapValueTo: 'name', + searchKeys: ['name'], + enabled: 0, + maxItems: 20, + closeOnSelect : true, + highlightFirst: false, + }, + templates: { + tag(tagData){ //z-index: unset; background-image: ${tagData.background}; Maybe a domain specific background for the chips? + return ` + +
+ ${tagData[this.settings.tagTextProp] || tagData.value} + +
+
`; + }} + }); + + domainTagify.on('change', this.onDomainSelect.bind(this)); + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.document = this.document; + context.tabs = this._getTabs(); + context.domains = this.document.system.domains.map(x => SYSTEM.DOMAIN.domains[x].label); + + return context; + } + + static async updateForm(event, _, formData) { + await this.document.update(formData.object) + this.render(); + } + + onAddTag(e){ + if( e.detail.index ===2 ){ + ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.ClassCanOnlyHaveTwoDomains")); + } + } + + async onDomainSelect(event) { + const domains = event.detail?.value ? JSON.parse(event.detail.value) : []; + await this.document.update({ "system.domains": domains.map(x => x.value) }); + this.render(true); + } + + static async removeSubclass(_, button){ + await this.document.update({ "system.subclasses": this.document.system.subclasses.filter(x => x.uuid !== button.dataset.subclass)}); + } + + static async viewSubclass(_, button){ + const subclass = await fromUuid(button.dataset.subclass); + subclass.sheet.render(true); + } + + static async removeFeature(_, button){ + await this.document.update({ "system.features": this.document.system.features.filter(x => x.uuid !== button.dataset.feature)}); + } + + static async viewFeature(_, button){ + const feature = await fromUuid(button.dataset.feature); + feature.sheet.render(true); + } + + static async removeItem(event, button){ + event.stopPropagation(); + const type = button.dataset.type; + const path = `system.inventory.${type}`; + await this.document.update({ [path]: this.document.system.inventory[type].filter(x => x.uuid !== button.dataset.item)}); + } + + static async viewItem(_, button){ + const item = await fromUuid(button.dataset.item); + item.sheet.render(true); + } + + static async removePrimaryWeapon(event){ + event.stopPropagation(); + await this.document.update({ "system.characterGuide.suggestedPrimaryWeapon": null }, { diff: false }); + } + + static async removeSecondaryWeapon(event){ + event.stopPropagation(); + await this.document.update({ "system.characterGuide.suggestedSecondaryWeapon": null }, { diff: false }); + } + + static async removeArmor(event){ + event.stopPropagation(); + await this.document.update({ "system.characterGuide.suggestedArmor": null }, { diff: false }); + } + + async _onDrop(event) { + const data = TextEditor.getDragEventData(event); + const item = await fromUuid(data.uuid); + if(item.type === 'subclass') { + await this.document.update({ "system.subclasses": [...this.document.system.subclasses, { img: item.img, name: item.name, uuid: item.uuid }] }); + } + else if(item.type === 'feature') { + + await this.document.update({ "system.features": [...this.document.system.features, { img: item.img, name: item.name, uuid: item.uuid }] }); + } + else if(item.type === 'weapon'){ + if(event.currentTarget.classList.contains('primary-weapon-section')){ + if(!this.document.system.characterGuide.suggestedPrimaryWeapon && !item.system.secondary) await this.document.update({ "system.characterGuide.suggestedPrimaryWeapon": { img: item.img, name: item.name, uuid: item.uuid } }); + } else if(event.currentTarget.classList.contains('secondary-weapon-section')){ + if(!this.document.system.characterGuide.suggestedSecondaryWeapon && item.system.secondary) await this.document.update({ "system.characterGuide.suggestedSecondaryWeapon": { img: item.img, name: item.name, uuid: item.uuid } }); + } + } + else if(item.type === 'armor'){ + if(event.currentTarget.classList.contains('armor-section')){ + if(!this.document.system.characterGuide.suggestedArmor) await this.document.update({ "system.characterGuide.suggestedArmor": { img: item.img, name: item.name, uuid: item.uuid } }); + } + } + else if(event.currentTarget.classList.contains('choice-a-section')){ + if(item.type === 'miscellaneous' || item.type === 'consumable'){ + if(this.document.system.inventory.choiceA.length < 2) await this.document.update({ "system.inventory.choiceA": [...this.document.system.inventory.choiceA, { img: item.img, name: item.name, uuid: item.uuid }] }); + } + } + else if(item.type === 'miscellaneous'){ + if(event.currentTarget.classList.contains('take-section')){ + if(this.document.system.inventory.take.length < 3) await this.document.update({ "system.inventory.take": [...this.document.system.inventory.take, { img: item.img, name: item.name, uuid: item.uuid }] }); + } + else if(event.currentTarget.classList.contains('choice-b-section')){ + if(this.document.system.inventory.choiceB.length < 2) await this.document.update({ "system.inventory.choiceB": [...this.document.system.inventory.choiceB, { img: item.img, name: item.name, uuid: item.uuid }] }); + } + } + } +} \ No newline at end of file diff --git a/module/applications/sheets/community.mjs b/module/applications/sheets/community.mjs new file mode 100644 index 00000000..1d95799f --- /dev/null +++ b/module/applications/sheets/community.mjs @@ -0,0 +1,117 @@ +// import DhpApplicationMixin from '../daggerheart-sheet.mjs'; + +// export default class CommunitySheet extends DhpApplicationMixin(ItemSheet) { +// static documentType = "community"; + +// constructor(options){ +// super(options); +// } + +// /** @override */ +// static get defaultOptions() { +// return foundry.utils.mergeObject(super.defaultOptions, { +// classes: ["daggerheart", "sheet", "heritage"], +// width: 600, +// height: 'auto', +// dragDrop: [{ dragSelector: null, dropSelector: null }], +// }); +// } + +// /** @override */ +// getData() { +// const context = super.getData(); + +// return context; +// } + + +// async _handleAction(action, event, button) { +// switch(action){ +// case 'editAbility': +// this.editAbility(button); +// break; +// case 'deleteAbility': +// this.deleteAbility(event); +// break; +// } +// } + +// async editAbility(button){ +// const feature = await fromUuid(button.dataset.ability); +// feature.sheet.render(true); +// } + +// async deleteAbility(event){ +// event.preventDefault(); +// event.stopPropagation(); +// await this.item.update({ "system.abilities": this.item.system.abilities.filter(x => x.uuid !== event.currentTarget.dataset.ability) }) +// } + +// async _onDrop(event) { +// const data = TextEditor.getDragEventData(event); +// const item = await fromUuid(data.uuid); +// if(item.type === 'feature' && item.system.type === SYSTEM.ITEM.featureTypes.community.id) { +// await this.object.update({ "system.abilities": [...this.item.system.abilities, { img: item.img, name: item.name, uuid: item.uuid }] }); +// } +// } +// } + +import DaggerheartSheet from './daggerheart-sheet.mjs'; + +const { ItemSheetV2 } = foundry.applications.sheets; +export default class CommunitySheet extends DaggerheartSheet(ItemSheetV2) { + static DEFAULT_OPTIONS = { + tag: 'form', + id: "daggerheart-community", + classes: ["daggerheart", "sheet", "heritage"], + position: { width: 600 }, + actions: { + editAbility: this.editAbility, + deleteAbility: this.deleteAbility, + }, + form: { + handler: this.updateForm, + submitOnChange: true, + closeOnSubmit: false, + }, + dragDrop: [{ dragSelector: null, dropSelector: null }], + }; + + static PARTS = { + form: { + id: "feature", + template: "systems/daggerheart/templates/sheets/community.hbs" + } + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.document = this.document; + + return context; + } + + static async updateForm(event, _, formData) { + await this.document.update(formData.object) + this.render(); + } + + static async editAbility(_, button){ + const feature = await fromUuid(button.dataset.ability); + feature.sheet.render(true); + } + + static async deleteAbility(event, button){ + event.preventDefault(); + event.stopPropagation(); + await this.item.update({ "system.abilities": this.item.system.abilities.filter(x => x.uuid !== button.dataset.ability) }) + } + + async _onDrop(event) { + const data = TextEditor.getDragEventData(event); + const item = await fromUuid(data.uuid); + if(item.type === 'feature' && item.system.type === SYSTEM.ITEM.featureTypes.community.id) { + await this.document.update({ "system.abilities": [...this.document.system.abilities, { img: item.img, name: item.name, uuid: item.uuid }] }); + } + } +} \ No newline at end of file diff --git a/module/applications/sheets/consumable.mjs b/module/applications/sheets/consumable.mjs new file mode 100644 index 00000000..8fdbde4e --- /dev/null +++ b/module/applications/sheets/consumable.mjs @@ -0,0 +1,57 @@ +// import DhpApplicationMixin from '../daggerheart-sheet.mjs'; + +// export default class ConsumableSheet extends DhpApplicationMixin(ItemSheet) { +// static documentType = "consumable"; + +// /** @override */ +// static get defaultOptions() { +// return foundry.utils.mergeObject(super.defaultOptions, { +// classes: ["daggerheart", "sheet", "consumable"], +// width: 480, +// height: 'auto', +// }); +// } + +// /** @override */ +// getData() { +// const context = super.getData(); + +// return context; +// } +// } + +import DaggerheartSheet from './daggerheart-sheet.mjs'; + +const { ItemSheetV2 } = foundry.applications.sheets; +export default class ConsumableSheet extends DaggerheartSheet(ItemSheetV2) { + static DEFAULT_OPTIONS = { + tag: 'form', + id: "daggerheart-consumable", + classes: ["daggerheart", "sheet", "consumable"], + position: { width: 480 }, + form: { + handler: this.updateForm, + submitOnChange: true, + closeOnSubmit: false, + }, + }; + + static PARTS = { + form: { + id: "feature", + template: "systems/daggerheart/templates/sheets/consumable.hbs" + } + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.document = this.document; + + return context; + } + + static async updateForm(event, _, formData) { + await this.document.update(formData.object) + this.render(); + } +} \ No newline at end of file diff --git a/module/applications/sheets/daggerheart-sheet.mjs b/module/applications/sheets/daggerheart-sheet.mjs new file mode 100644 index 00000000..51844012 --- /dev/null +++ b/module/applications/sheets/daggerheart-sheet.mjs @@ -0,0 +1,73 @@ +const { HandlebarsApplicationMixin } = foundry.applications.api; + +export default function DhpApplicationMixin(Base) { + return class DhpSheetV2 extends HandlebarsApplicationMixin(Base) { + constructor(options={}){ + super(options); + + this._dragDrop = this._createDragDropHandlers(); + } + + _attachPartListeners(partId, htmlElement, options) { + super._attachPartListeners(partId, htmlElement, options); + + this._dragDrop.forEach(d => d.bind(htmlElement)); + } + + static DEFAULT_OPTIONS = { + position: { + width: 480, + height: "auto" + }, + actions: { + onEditImage: this._onEditImage + }, + dragDrop: [], + }; + + async _prepareContext(_options, objectPath='document') { + const context = await super._prepareContext(_options); + context.source = this[objectPath].toObject(); + context.fields = this[objectPath].schema.fields; + context.systemFields = this[objectPath].system ? this[objectPath].system.schema.fields : {}; + + return context; + } + + static _onEditImage(event, target) { + const attr = target.dataset.edit; + const current = foundry.utils.getProperty(this.document, attr); + const { img } = this.document.constructor.getDefaultArtwork?.(this.document.toObject()) ?? {}; + const fp = new FilePicker({ + current, + type: "image", + redirectToRoot: img ? [img] : [], + callback: async path => this._updateImage.bind(this)(path), + top: this.position.top + 40, + left: this.position.left + 10 + }); + return fp.browse(); + } + + async _updateImage(path){ + await this.document.update({ "img": path }); + } + + _createDragDropHandlers() { + return this.options.dragDrop.map(d => { + // d.permissions = { + // dragstart: this._canDragStart.bind(this), + // drop: this._canDragDrop.bind(this) + // }; + d.callbacks = { + // dragstart: this._onDragStart.bind(this), + // dragover: this._onDragOver.bind(this), + drop: this._onDrop.bind(this) + }; + return new foundry.applications.ux.DragDrop.implementation(d); + }); + } + + _onDrop(event) {} + } +} \ No newline at end of file diff --git a/module/applications/sheets/domainCard.mjs b/module/applications/sheets/domainCard.mjs new file mode 100644 index 00000000..ac1e37cf --- /dev/null +++ b/module/applications/sheets/domainCard.mjs @@ -0,0 +1,110 @@ +// import DhpApplicationMixin from '../daggerheart-sheet.mjs'; + +// export default class DomainCardSheet extends DhpApplicationMixin(ItemSheet) { +// static documentType = "domainCard"; + +// /** @override */ +// static get defaultOptions() { +// return foundry.utils.mergeObject(super.defaultOptions, { +// classes: ["daggerheart", "sheet", "domain-card"], +// width: 600, +// height: 600, +// tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "features" }] +// }); +// } + +// /** @override */ +// getData() { +// const context = super.getData(); +// context.config = CONFIG.daggerheart; + +// return context; +// } + + +// async _handleAction(action, event, button) { +// switch(action){ +// case 'attributeRoll': + +// break; +// } +// } +// } + +import DaggerheartAction from '../../data/action.mjs'; +import DaggerheartActionConfig from '../config/Action.mjs'; +import DaggerheartSheet from './daggerheart-sheet.mjs'; + +const { ItemSheetV2 } = foundry.applications.sheets; +export default class DomainCardSheet extends DaggerheartSheet(ItemSheetV2) { + static DEFAULT_OPTIONS = { + tag: 'form', + id: "daggerheart-domainCard", + classes: ["daggerheart", "sheet", "domain-card"], + position: { width: 600, height: 600 }, + actions: { + addAction: this.addAction, + editAction: this.editAction, + removeAction: this.removeAction, + }, + form: { + handler: this.updateForm, + submitOnChange: true, + closeOnSubmit: false, + }, + }; + + static PARTS = { + form: { + id: "feature", + template: "systems/daggerheart/templates/sheets/domainCard.hbs" + } + } + + _getTabs() { + const tabs = { + general: { active: true, cssClass: '', group: 'primary', id: 'general', icon: null, label: 'General' }, + actions: { active: false, cssClass: '', group: 'primary', id: 'actions', icon: null, label: 'Actions' }, + } + for ( const v of Object.values(tabs) ) { + v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active; + v.cssClass = v.active ? "active" : ""; + } + + return tabs; + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.config = CONFIG.daggerheart; + context.tabs = this._getTabs(); + + return context; + } + + static async updateForm(event, _, formData) { + await this.document.update(formData.object) + this.render(); + } + + static async addAction(){ + const actionIndexes = this.document.system.actions.map(x => x.id.split('-')[2]).sort((a, b) => a-b); + const action = await new DaggerheartAction({ + id: `${this.document.id}-Action-${actionIndexes.length > 0 ? actionIndexes[0]+1 : 1}`, + }, { + parent: this.document, + }); + await this.document.update({ "system.actions": [...this.document.system.actions, action] }); + await (new DaggerheartActionConfig(this.document.system.actions[this.document.system.actions.length-1])).render(true); + } + + static async editAction(_, button){ + const action = this.document.system.actions[button.dataset.index]; + await (new DaggerheartActionConfig(action)).render(true); + } + + static async removeAction(event, button){ + event.stopPropagation(); + await this.document.update({ "system.actions": this.document.system.actions.filter((_, index) => index !== Number.parseInt(button.dataset.index)) }); + } +} \ No newline at end of file diff --git a/module/applications/sheets/environment.mjs b/module/applications/sheets/environment.mjs new file mode 100644 index 00000000..f6ff3cae --- /dev/null +++ b/module/applications/sheets/environment.mjs @@ -0,0 +1,129 @@ +import DaggerheartSheet from "./daggerheart-sheet.mjs"; + +const { DocumentSheetV2 } = foundry.applications.api; +export default class DhpEnvironment extends DaggerheartSheet(DocumentSheetV2) { + + constructor(options){ + super(options); + + this.editMode = false; + } + + static DEFAULT_OPTIONS = { + tag: 'form', + classes: ["daggerheart", "sheet", "adversary", "environment"], + position: { + width: 600, + height: "auto" + }, + actions: { + toggleSlider: this.toggleSlider, + viewFeature: this.viewFeature, + addFeature: this.addFeature, + removeFeature: this.removeFeature, + addTone: this.addTone, + removeTone: this.removeTone, + useFeature: this.useFeature, + }, + form: { + handler: this._updateForm, + closeOnSubmit: false, + submitOnChange: true, + } + }; + + /** @override */ + static PARTS = { + form: { + id: "form", + template: "systems/daggerheart/templates/sheets/environment.hbs" + } + } + + /* -------------------------------------------- */ + + /** @inheritDoc */ + get title() { + return `${game.i18n.localize('Environment')} - ${this.document.name}`; + } + + async _prepareContext(_options) { + return { + title: `${this.document.name} - ${game.i18n.localize(SYSTEM.ACTOR.adversaryTypes[this.document.system.type].name)}`, + user: this.document, + source: this.document.toObject(), + fields: this.document.schema.fields, + data: { + type: game.i18n.localize(SYSTEM.ACTOR.adversaryTypes[this.document.system.type].name), + features: this.document.items.reduce((acc, x) => { + if(x.type === 'feature'){ + const feature = x.toObject(); + acc.push({ + ...feature, + system: { + ...feature.system, + actionType: game.i18n.localize(SYSTEM.ITEM.actionTypes[feature.system.actionType].name) + }, + uuid: x.uuid + }); + } + + return acc; + }, []), + }, + editMode: this.editMode, + config: SYSTEM, + } + } + + static async _updateForm(event, _, formData) { + await this.document.update(formData.object) + this.render(); + } + + static toggleSlider(){ + this.editMode = !this.editMode; + this.render(); + } + + static async viewFeature(_, button){ + const move = await fromUuid(button.dataset.feature); + move.sheet.render(true); + } + + static async addFeature(){ + const result = await this.document.createEmbeddedDocuments("Item", [{ + name: game.i18n.localize('DAGGERHEART.Sheets.Environment.NewFeature'), + type: 'feature', + }]); + + await result[0].sheet.render(true); + } + + static async removeFeature(_, button){ + await this.document.items.find(x => x.uuid === button.dataset.feature).delete(); + } + + static async addTone(){ + await this.document.update({ "system.toneAndFeel": [...this.document.system.toneAndFeel, ''] }); + } + + static async removeTone(button){ + await this.document.update({ "system.toneAndFeel": this.document.system.toneAndFeel.filter((_, index) => index !== Number.parseInt(button.dataset.tone) )}); + } + + static async useFeature(_, button){ + const item = this.document.items.find(x => x.uuid === button.dataset.feature); + + const cls = getDocumentClass("ChatMessage"); + const msg = new cls({ + user: game.user.id, + content: await renderTemplate("systems/daggerheart/templates/chat/ability-use.hbs", { + title: game.i18n.format("DAGGERHEART.Chat.EnvironmentTitle", { actionType: button.dataset.actionType }), + card: { name: item.name, img: item.img, description: item.system.description }, + }), + }); + + cls.create(msg.toObject()); + } +} \ No newline at end of file diff --git a/module/applications/sheets/feature.mjs b/module/applications/sheets/feature.mjs new file mode 100644 index 00000000..6adbbf3a --- /dev/null +++ b/module/applications/sheets/feature.mjs @@ -0,0 +1,116 @@ +import DaggerheartAction from '../../data/action.mjs'; +import DaggerheartActionConfig from '../config/Action.mjs'; +import DaggerheartSheet from './daggerheart-sheet.mjs'; + +const { ItemSheetV2 } = foundry.applications.sheets; +export default class FeatureSheet extends DaggerheartSheet(ItemSheetV2) { + constructor(options={}){ + super(options); + + this.selectedEffectType = null; + } + + static DEFAULT_OPTIONS = { + tag: 'form', + id: "daggerheart-feature", + classes: ["daggerheart", "sheet", "feature"], + position: { width: 600, height: 600 }, + actions: { + addEffect: this.addEffect, + removeEffect: this.removeEffect, + addAction: this.addAction, + editAction: this.editAction, + removeAction: this.removeAction, + }, + form: { + handler: this.updateForm, + submitOnChange: true, + closeOnSubmit: false, + }, + }; + + static PARTS = { + form: { + id: "feature", + template: "systems/daggerheart/templates/sheets/feature.hbs" + } + } + + _getTabs() { + const tabs = { + features: { active: true, cssClass: '', group: 'primary', id: 'features', icon: null, label: 'Features' }, + effects: { active: false, cssClass: '', group: 'primary', id: 'effects', icon: null, label: 'Effects' }, + actions: { active: false, cssClass: '', group: 'primary', id: 'actions', icon: null, label: 'Actions' }, + } + for ( const v of Object.values(tabs) ) { + v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active; + v.cssClass = v.active ? "active" : ""; + } + + return tabs; + } + + _attachPartListeners(partId, htmlElement, options) { + super._attachPartListeners(partId, htmlElement, options); + $(htmlElement).find(".effect-select").on("change", this.effectSelect.bind(this)); + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.document = this.document; + context.tabs = this._getTabs(), + context.generalConfig = SYSTEM.GENERAL; + context.itemConfig = SYSTEM.ITEM; + context.properties = SYSTEM.ACTOR.featureProperties; + context.dice = SYSTEM.GENERAL.diceTypes; + context.selectedEffectType = this.selectedEffectType; + context.effectConfig = SYSTEM.EFFECTS; + + return context; + } + + static async updateForm(event, _, formData) { + await this.document.update(formData.object) + this.render(); + } + + effectSelect(event){ + this.selectedEffectType = event.currentTarget.value; + this.render(true); + } + + static async addEffect(){ + if(!this.selectedEffectType) return; + + const { id, name, ...rest } = SYSTEM.EFFECTS.effectTypes[this.selectedEffectType]; + const update = { + [foundry.utils.randomID()]: { + type: this.selectedEffectType, + value: '', + ...rest + } + }; + await this.item.update({ "system.effects": update }); + } + + static async removeEffect(_, button){ + const path = `system.effects.-=${button.dataset.effect}`; + await this.item.update({ [path]: null }); + } + + static async addAction(){ + const action = await new DaggerheartAction({}, {parent: this.document}); + await this.document.update({ "system.actions": [...this.document.system.actions, action] }); + await (new DaggerheartActionConfig(this.document.system.actions[this.document.system.actions.length-1])).render(true); + } + + static async editAction(_, button){ + const action = this.document.system.actions[button.dataset.index]; + await (new DaggerheartActionConfig(action)).render(true); + } + + static async removeAction(event, button){ + event.stopPropagation(); + await this.document.update({ "system.actions": this.document.system.actions.filter((_, index) => index !== Number.parseInt(button.dataset.index)) }); + } +} \ No newline at end of file diff --git a/module/applications/sheets/miscellaneous.mjs b/module/applications/sheets/miscellaneous.mjs new file mode 100644 index 00000000..4c4088a8 --- /dev/null +++ b/module/applications/sheets/miscellaneous.mjs @@ -0,0 +1,57 @@ +// import DhpApplicationMixin from '../daggerheart-sheet.mjs'; + +// export default class MiscellaneousSheet extends DhpApplicationMixin(ItemSheet) { +// static documentType = "miscellaneous"; + +// /** @override */ +// static get defaultOptions() { +// return foundry.utils.mergeObject(super.defaultOptions, { +// classes: ["daggerheart", "sheet", "miscellaneous"], +// width: 400, +// height: 'auto', +// }); +// } + +// /** @override */ +// getData() { +// const context = super.getData(); + +// return context; +// } +// } + +import DaggerheartSheet from './daggerheart-sheet.mjs'; + +const { ItemSheetV2 } = foundry.applications.sheets; +export default class MiscellaneousSheet extends DaggerheartSheet(ItemSheetV2) { + static DEFAULT_OPTIONS = { + tag: 'form', + id: "daggerheart-miscellaneous", + classes: ["daggerheart", "sheet", "miscellaneous"], + position: { width: 400 }, + form: { + handler: this.updateForm, + submitOnChange: true, + closeOnSubmit: false, + }, + }; + + static PARTS = { + form: { + id: "feature", + template: "systems/daggerheart/templates/sheets/miscellaneous.hbs" + } + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.document = this.document; + + return context; + } + + static async updateForm(event, _, formData) { + await this.document.update(formData.object) + this.render(); + } +} \ No newline at end of file diff --git a/module/applications/sheets/pc.mjs b/module/applications/sheets/pc.mjs new file mode 100644 index 00000000..cfe3038b --- /dev/null +++ b/module/applications/sheets/pc.mjs @@ -0,0 +1,2029 @@ +import { capitalize } from '../../helpers/utils.mjs'; +import DhpDeathMove from '../deathMove.mjs'; +import DhpDowntime from '../downtime.mjs'; +import DhpLevelup from '../levelup.mjs'; +import AncestrySelectionDialog from '../ancestrySelectionDialog.mjs'; +import DaggerheartSheet from './daggerheart-sheet.mjs'; + +const { ActorSheetV2 } = foundry.applications.sheets; +export default class PCSheet extends DaggerheartSheet(ActorSheetV2) { + constructor(options={}){ + super(options); + + this.editAttributes = false; + this.onVaultTab = false; + this.currentInventoryPage = 0; + this.selectedScar = null; + this.storyEditor = null; + this.dropItemBlock = false; + this.multiclassFeatureSetSelected = false; + } + + static DEFAULT_OPTIONS = { + tag: 'form', + id: "daggerheart-pc", + classes: ["daggerheart", "sheet", "pc"], + position: { width: 810, height: 1080 }, + actions: { + toggleEditAttributes: this.toggleEditAttributes, + attributeRoll: this.rollAttribute, + toggleMarks: this.toggleMarks, + toggleAttributeMark: this.toggleAttributeMark, + toggleHP: this.toggleHP, + toggleStress: this.toggleStress, + toggleHope: this.toggleHope, + toggleGold: this.toggleGold, + attackRoll: this.attackRoll, + tabToLoadout: () => this.domainCardsTab(false), + tabToVault: () => this.domainCardsTab(true), + sendToVault: (_, button) => this.moveDomainCard(button, true), + sentToLoadout: (_, button) => this.moveDomainCard(button, false), + useDomainCard: this.useDomainCard, + selectClass: this.selectClass, + selectSubclass: this.selectSubclass, + selectAncestry: this.selectAncestry, + selectCommunity: this.selectCommunity, + viewObject: this.viewObject, + useFeature: this.useFeature, + takeShortRest: this.takeShortRest, + takeLongRest: this.takeLongRest, + removeActiveItem: this.removeActiveItem, + removeInventoryWeapon: this.removeInventoryWeapon, + addMiscItem: this.addMiscItem, + deleteItem: this.deleteItem, + addScar: this.addScar, + selectScar: this.selectScar, + deleteScar: this.deleteScar, + makeDeathMove: this.makeDeathMove, + toggleFeatureDice: this.toggleFeatureDice, + setStoryEditor: this.setStoryEditor, + itemQuantityDecrease: (_, button) => this.setItemQuantity(button, -1), + itemQuantityIncrease: (_, button) => this.setItemQuantity(button, 1), + useAbility: this.useAbility, + useAdvancementCard: this.useAdvancementCard, + useAdvancementAbility: this.useAdvancementAbility, + selectFeatureSet: this.selectFeatureSet, + }, + form: { + handler: this.updateForm, + submitOnChange: true, + closeOnSubmit: false, + }, + dragDrop: [ + {dragSelector: null, dropSelector: ".weapon-section" }, + {dragSelector: null, dropSelector: ".armor-section"}, + {dragSelector: null, dropSelector: ".inventory-weapon-section-first"}, + {dragSelector: null, dropSelector: ".inventory-weapon-section-second"}, + {dragSelector: ".item-list .item", dropSelector: null}, + ], + }; + + static PARTS = { + form: { + id: "pc", + template: "systems/daggerheart/templates/sheets/pc/pc.hbs" + } + } + + _getTabs() { + const setActive = (tabs) => { + for ( const v of Object.values(tabs) ) { + v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active; + v.cssClass = v.active ? "active" : ""; + } + } + + const primaryTabs = { + features: { active: true, cssClass: '', group: 'primary', id: 'features', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.PC.Tabs.Features') }, + loadout: { active: false, cssClass: '', group: 'primary', id: 'loadout', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.PC.Tabs.Loadout') }, + inventory: { active: false, cssClass: '', group: 'primary', id: 'inventory', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.PC.Tabs.Inventory') }, + story: { active: false, cssClass: '', group: 'primary', id: 'story', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.PC.Tabs.Story') }, + } + const secondaryTabs = { + foundation: { active: true, cssClass: '', group: 'secondary', id: 'foundation', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.PC.Tabs.Foundation') }, + loadout: { active: false, cssClass: '', group: 'secondary', id: 'loadout', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.PC.Tabs.Loadout') }, + vault: { active: false, cssClass: '', group: 'secondary', id: 'vault', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.PC.Tabs.Vault') }, + } + + setActive(primaryTabs); + setActive(secondaryTabs); + + return { primary: primaryTabs, secondary: secondaryTabs }; + } + + _attachPartListeners(partId, htmlElement, options) { + super._attachPartListeners(partId, htmlElement, options); + $(htmlElement).find(".attribute-value").on("change", this.attributeChange.bind(this)); + $(htmlElement).find(".tab-selector").on("click", this.tabSwitch.bind(this)); + $(htmlElement).find(".level-title.levelup").on("click", this.openLevelUp.bind(this)); + $(htmlElement).find(".feature-input").on("change", this.onFeatureInputBlur.bind(this)); + $(htmlElement).find(".experience-description").on("change", this.experienceDescriptionChange.bind(this)); + $(htmlElement).find(".experience-value").on("change", this.experienceValueChange.bind(this)); + $(htmlElement).find("[data-item]").on("change", this.itemUpdate.bind(this)); + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.document = this.document; + context.tabs = this._getTabs(); + + context.config = SYSTEM; + context.editAttributes = this.editAttributes; + context.onVaultTab = this.onVaultTab; + context.selectedScar = this.selectedScar; + context.storyEditor = this.storyEditor; + context.multiclassFeatureSetSelected = this.multiclassFeatureSetSelected; + + const selectedAttributes = Object.values(this.document.system.attributes).map(x => x.data.base); + context.abilityScoreArray = JSON.parse(await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.General.AbilityArray)).reduce((acc, x) => { + const selectedIndex = selectedAttributes.indexOf(x); + if(selectedIndex !== -1){ + selectedAttributes.splice(selectedIndex, 1); + } else { + acc.push({ name: x, value: x }); + } + + return acc; + }, []); + if(!context.abilityScoreArray.includes(0)) context.abilityScoreArray.push({ name: 0, value: 0 }); + context.abilityScoresFinished = context.abilityScoreArray.every(x => x.value === 0); + + context.domains = this.document.system.class ? { + first: this.document.system.class.system.domains[0] ? SYSTEM.DOMAIN.domains[this.document.system.class.system.domains[0]].src : null, + second: this.document.system.class.system.domains[1] ? SYSTEM.DOMAIN.domains[this.document.system.class.system.domains[1]].src : null, + } : { }; + + context.attributes = Object.keys(this.document.system.attributes).reduce((acc, key) => { + acc[key] = { + ...this.document.system.attributes[key], + name: game.i18n.localize(SYSTEM.ACTOR.abilities[key].name), + verbs: SYSTEM.ACTOR.abilities[key].verbs.map(x => game.i18n.localize(x)), + }; + + return acc; + }, {}); + + const ancestry = await this.mapFeatureType(this.document.system.ancestry ? [this.document.system.ancestry] : [], SYSTEM.GENERAL.objectTypes); + const community = await this.mapFeatureType(this.document.system.community ? [this.document.system.community] : [], SYSTEM.GENERAL.objectTypes); + const foundation = { + ancestry: ancestry[0], + community: community[0], + advancement: { + ...this.mapAdvancementFeatures(this.document, SYSTEM) + } + }; + + const nrLoadoutCards = this.document.system.domainCards.loadout.length; + const loadout = await this.mapFeatureType(this.document.system.domainCards.loadout, SYSTEM.DOMAIN.cardTypes); + const vault = await this.mapFeatureType(this.document.system.domainCards.vault, SYSTEM.DOMAIN.cardTypes); + context.abilities = { + foundation: foundation, + loadout: { + top: loadout.slice(0, Math.min(2, nrLoadoutCards)), + bottom: nrLoadoutCards > 2 ? loadout.slice(2, Math.min(5, nrLoadoutCards)) : [], + nrTotal: nrLoadoutCards, + }, + vault: vault.map(x => ({ ...x, uuid: x.uuid, sendToLoadoutDisabled: this.document.system.domainCards.loadout.length >= this.document.system.domainData.maxLoadout })) + }; + + context.inventory = { + consumable: { + titles: { + name: game.i18n.localize("DAGGERHEART.Sheets.PC.InventoryTab.ConsumableTitle"), + quantity: game.i18n.localize("DAGGERHEART.Sheets.PC.InventoryTab.QuantityTitle"), + }, + items: this.document.items.filter(x => x.type === 'consumable'), + }, + miscellaneous: { + titles: { + name: game.i18n.localize("DAGGERHEART.Sheets.PC.InventoryTab.MiscellaneousTitle"), + quantity: game.i18n.localize("DAGGERHEART.Sheets.PC.InventoryTab.QuantityTitle"), + }, + items: this.document.items.filter(x => x.type === 'miscellaneous'), + }, + } + + if(context.inventory.length === 0){ + context.inventory = Array(1).fill(Array(5).fill([])); + } + + context.classFeatures = (this.multiclassFeatureSetSelected ? this.document.system.multiclassFeatures : this.document.system.classFeatures).map(x => { + if(x.system.featureType.type !== 'dice'){ + return x; + } + + return { ...x, uuid: x.uuid, system: { ...x.system, featureType: { ...x.system.featureType, data: { ...x.system.featureType.data, property: this.document.system.subclass ? SYSTEM.ACTOR.featureProperties[x.system.featureType.data.property].path(this.document) : 0 }}}}; + }); + + return context; + } + + static async updateForm(event, _, formData) { + await this.document.update(formData.object) + this.render(); + } + + async mapFeatureType(data, configType){ + return await Promise.all(data.map(async x => { + const abilities = x.system.abilities ? await Promise.all(x.system.abilities.map(async x => await fromUuid(x.uuid))) : []; + + return { + ...x, + uuid: x.uuid, + system: { + ...x.system, + abilities: abilities, + type: game.i18n.localize(configType[x.system.type??x.type].label) + } + } + })); + } + + mapAdvancementFeatures(actor, config) { + if(!actor.system.subclass) return { foundation: null, advancements: [] }; + + const { subclass, multiclassSubclass } = actor.system.subclassFeatures; + + const foundation = { + type: 'foundation', + multiclass: false, + img: actor.system.subclass.img, + subtitle: game.i18n.localize("DAGGERHEART.Sheets.PC.DomainCard.FoundationTitle"), + domains: actor.system.class.system.domains.map(x => config.DOMAIN.domains[x].src), + className: actor.system.class.name, + subclassUuid: actor.system.subclass.uuid, + subclassName: actor.system.subclass.name, + spellcast: config.ACTOR.abilities[actor.system.subclass.system.spellcastingTrait]?.name ?? null, + description: actor.system.subclass.system.foundationFeature.description, + abilities: subclass.foundation, + abilityKey: 'foundationFeature', + }; + + const firstKey = actor.system.subclass.system.specializationFeature.unlocked && actor.system.subclass.system.specializationFeature.tier === 2 ? 'sub' : + actor.system.multiclass?.system?.multiclassTier === 2 ? 'multi' : null; + const firstType = firstKey === 'sub' ? 'specialization' : 'foundation'; + const firstBase = firstKey === 'sub' ? actor.system.subclass : firstKey === 'multi' ? actor.system.multiclassSubclass : null; + const first = !firstBase ? null : { + type: firstType, + multiclass: firstKey === 'multi', + img: firstBase.img, + subtitle: firstKey === 'sub' ? game.i18n.localize("DAGGERHEART.Sheets.PC.DomainCard.SpecializationTitle") : game.i18n.localize("DAGGERHEART.Sheets.PC.DomainCard.FoundationTitle"), + domains: firstKey === 'sub' ? actor.system.class.system.domains.map(x => config.DOMAIN.domains[x].src) : actor.system.multiclass.system.domains.map(x => config.DOMAIN.domains[x].src), + className: firstKey === 'sub' ? actor.system.class.name : actor.system.multiclass.name, + subclassUuid: firstBase.uuid, + subclassName: firstBase.name, + spellcast: firstKey === 'sub' ? null : config.ACTOR.abilities[firstBase.system.spellcastingTrait]?.name ?? null, + description: firstKey === 'sub' ? firstBase.system.specializationFeature.description : firstBase.system.foundationFeature.description, + abilities: firstKey === 'sub' ? subclass.specialization : multiclassSubclass.foundation, + abilityKey: firstKey === 'sub' ? 'specializationFeature' : 'foundationFeature', + }; + + const secondKey = (actor.system.subclass.system.specializationFeature.unlocked && actor.system.subclass.system.specializationFeature.tier === 3) || (actor.system.subclass.system.masteryFeature.unlocked && actor.system.subclass.system.masteryFeature.tier === 3) ? 'sub' : + (actor.system.multiclass?.system?.multiclassTier === 3) || (actor.system.multiclassSubclass?.system?.specializationFeature?.unlocked) ? 'multi' : null; + const secondBase = secondKey === 'sub' ? actor.system.subclass : secondKey === 'multi' ? actor.system.multiclassSubclass : null; + const secondAbilities = secondKey === 'sub' ? subclass : multiclassSubclass; + const secondType = secondBase ? secondBase.system.masteryFeature.unlocked ? 'mastery' : secondBase.system.specializationFeature.unlocked ? 'specialization' : 'foundation' : null; + const second = !secondBase ? null : { + type: secondType, + multiclass: secondKey === 'multi', + img: secondBase.img, + subtitle: secondBase.system.masteryFeature.unlocked ? game.i18n.localize("DAGGERHEART.Sheets.PC.DomainCard.MasteryTitle") : + secondBase.system.specializationFeature.unlocked ? game.i18n.localize("DAGGERHEART.Sheets.PC.DomainCard.SpecializationTitle") : game.i18n.localize("DAGGERHEART.Sheets.PC.DomainCard.FoundationTitle"), + domains: secondKey === 'sub' ? actor.system.class.system.domains.map(x => config.DOMAIN.domains[x].src) : actor.system.multiclass.system.domains.map(x => config.DOMAIN.domains[x].src), + className: secondKey === 'sub' ? actor.system.class.name : actor.system.multiclass.name, + subclassUuid: secondBase.uuid, + subclassName: secondBase.name, + spellcast: secondKey === 'sub' || secondBase.system.specializationFeature.unlocked ? null : config.ACTOR.abilities[firstBase.system.spellcastingTrait]?.name ?? null, + description: + secondBase.system.masteryFeature.unlocked ? secondBase.system.masteryFeature.description : + secondBase.system.specializationFeature.unlocked ? secondBase.system.specializationFeature.description : firstBase.system.foundationFeature.description, + abilities: + secondBase.system.masteryFeature.unlocked ? secondAbilities.mastery : + secondBase.system.specializationFeature.unlocked ? secondAbilities.specialization : secondAbilities.foundation, + abilityKey: secondBase.system.masteryFeature.unlocked ? 'masteryFeature' : secondBase.system.specializationFeature.unlocked ? 'specializationFeature' : 'foundationFeature', + }; + + return { + foundation: foundation, + first: first, + second: second, + } + } + + async attributeChange(event){ + const path = `system.attributes.${event.currentTarget.dataset.attribute}.data.base`; + await this.document.update({ [path]: event.currentTarget.value }); + } + + static toggleEditAttributes(){ + this.editAttributes = !this.editAttributes; + this.render(); + } + + static async rollAttribute(_, event){ + const { roll, hope, fear, advantage, disadvantage, modifiers } = await this.document.dualityRoll({ title: 'Attribute Bonus', value: event.currentTarget.dataset.value }, event.shiftKey); + + const cls = getDocumentClass("ChatMessage"); + const msg = new cls({ + type: 'dualityRoll', + system: { + roll: roll._formula, + modifiers: modifiers, + hope: hope, + fear: fear, + advantage: advantage, + disadvantage: disadvantage, + }, + user: game.user.id, + content: "systems/daggerheart/templates/chat/duality-roll.hbs", + rolls: [roll] + }); + + await cls.create(msg.toObject()); + } + + static async toggleMarks(_, button){ + const markValue = Number.parseInt(button.dataset.value); + const newValue = this.document.system.armor.system.marks.value >= markValue ? markValue-1 : markValue; + await this.document.system.armor.update({ 'system.marks.value': newValue }); + } + + static async toggleAttributeMark(_, button){ + const attribute = this.document.system.attributes[button.dataset.attribute]; + const newMark = this.document.system.availableAttributeMarks.filter(x => x > Math.max.apply(null, this.document.system.attributes[button.dataset.attribute].levelMarks)).sort((a, b) => a > b ? 1 : -1)[0]; + + if(attribute.levelMark || !newMark) return; + + + const path = `system.attributes.${button.dataset.attribute}.levelMarks`; + await this.document.update({ [path]: [...attribute.levelMarks, newMark] }); + } + + static async toggleHP(_, button){ + const healthValue = Number.parseInt(button.dataset.value); + const newValue = this.document.system.resources.health.value >= healthValue ? healthValue-1 : healthValue; + await this.document.update({ 'system.resources.health.value': newValue }); + } + + static async toggleStress(_, button){ + const healthValue = Number.parseInt(button.dataset.value); + const newValue = this.document.system.resources.stress.value >= healthValue ? healthValue-1 : healthValue; + await this.document.update({ 'system.resources.stress.value': newValue }); + } + + static async toggleHope(_, button){ + const hopeValue = Number.parseInt(button.dataset.value); + const newValue = this.document.system.resources.hope.value >= hopeValue ? hopeValue-1 : hopeValue; + await this.document.update({ 'system.resources.hope.value': newValue }); + } + + static async toggleGold(_, button){ + const goldValue = Number.parseInt(button.dataset.value); + const goldType = button.dataset.type; + const newValue = this.document.system.gold[goldType] >= goldValue ? goldValue-1 : goldValue; + + const update = `system.gold.${goldType}`; + await this.document.update({ [update]: newValue }); + } + + static async attackRoll(_, event){ + const weapon = await fromUuid(event.currentTarget.dataset.weapon); + const damage = { + value: `${this.document.system.proficiency.value}${weapon.system.damage.value}`, + type: weapon.system.damage.type, + bonusDamage: this.document.system.bonuses.damage + }; + const modifier = this.document.system.attributes[weapon.system.trait].data.value; + + const { roll, hope, fear, advantage, disadvantage, modifiers, bonusDamageString } = await this.document.dualityRoll({ title: 'Attribute Modifier', value: modifier }, event.shiftKey, damage.bonusDamage); + + damage.value = damage.value.concat(bonusDamageString); + + const targets = Array.from(game.user.targets).map(x => ({ + id: x.id, + name: x.actor.name, + img: x.actor.img, + difficulty: x.actor.system.difficulty, + evasion: x.actor.system.evasion, + })); + + const cls = getDocumentClass("ChatMessage"); + const msg = new cls({ + type: 'dualityRoll', + system: { + roll: roll._formula, + modifiers: modifiers, + hope: hope, + fear: fear, + advantage: advantage, + disadvantage: disadvantage, + damage: damage, + targets: targets, + }, + content: "systems/daggerheart/templates/chat/attack-roll.hbs", + rolls: [roll] + }); + + await cls.create(msg.toObject()); + } + + tabSwitch(event){ + const tab = event.currentTarget.dataset.tab; + if(tab !== 'loadout'){ + this.onVaultTab = false; + } + + this.render(); + } + + openLevelUp(){ + new DhpLevelup(this.document).render(true); + } + + static domainCardsTab(toVault){ + this.onVaultTab = toVault; + this.render(); + } + + static async moveDomainCard(button, toVault){ + if(!toVault && this.document.system.domainCards.loadout.length >= this.document.system.domainData.maxLoadout){ + return; + } + + const card = this.document.items.find(x => x.uuid === button.dataset.domain); + await card.update({ "system.inVault": toVault }); + } + + static async useDomainCard(_, button){ + const card = this.document.items.find(x => x.uuid === button.dataset.key); + + const cls = getDocumentClass("ChatMessage"); + const msg = new cls({ + type: 'abilityUse', + user: game.user.id, + content: "systems/daggerheart/templates/chat/ability-use.hbs", + system: { + title: `${game.i18n.localize("DAGGERHEART.Chat.DomainCard.Title")} - ${capitalize(button.dataset.domain)}`, + img: card.img, + name: card.name, + description: card.system.effect, + actions: card.system.actions, + }, + }); + + cls.create(msg.toObject()); + } + + static async selectClass(){ + (await game.packs.get('daggerheart.playtest-classes'))?.render(true); + } + + static async selectSubclass(){ + (await game.packs.get('daggerheart.playtest-subclasses'))?.render(true); + } + + static async selectAncestry(){ + const dialogClosed = new Promise((resolve, _) => { + new AncestrySelectionDialog(resolve).render(true); + }); + const result = await dialogClosed; + + // await this.emulateItemDrop({ type: 'item', data: result }); + for(var ancestry of this.document.items.filter(x => x => x.type === 'ancestry')){ + await ancestry.delete(); + } + + const createdItems = []; + for(var feature of this.document.items.filter(x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.ancestry.id)){ + await feature.delete(); + } + + // createdItems.push(...result.data.system.abilities); + createdItems.push(result.data); + + + await this.document.createEmbeddedDocuments('Item', createdItems); + + // await this.document.createEmbeddedDocuments("Item", [result.toObject()]); + // (await game.packs.get('daggerheart.playtest-ancestries'))?.render(true); + } + + static async selectCommunity(){ + (await game.packs.get('daggerheart.playtest-communities'))?.render(true);; + } + + static async viewObject(button){ + const object = await fromUuid(button.dataset.value); + if(!object) return; + + const tab = button.dataset.tab; + if(tab) object.sheet._tabs[0].active = tab; + + if(object.sheet.editMode) object.sheet.editMode = false; + + object.sheet.render(true); + } + + static async takeShortRest(){ + await new DhpDowntime(this.document, true).render(true); + await this.minimize(); + } + + static async takeLongRest(){ + await new DhpDowntime(this.document, false).render(true); + await this.minimize(); + } + + static async removeActiveItem(_, event){ + event.stopPropagation(); + const item = await fromUuid(event.currentTarget.dataset.item); + await item.delete(); + } + + static async removeInventoryWeapon(_, event){ + event.stopPropagation(); + const item = await fromUuid(event.currentTarget.dataset.item); + await item.delete(); + } + + static async addMiscItem(){ + const result = await this.document.createEmbeddedDocuments("Item", [{ + name: game.i18n.localize('DAGGERHEART.Sheets.PC.NewItem'), + type: 'miscellaneous' + }]); + + await result[0].sheet.render(true); + } + + static async addScar(){ + if(this.document.system.story.scars.length === 5) return; + + await this.document.update({ "system.story.scars": [...this.document.system.story.scars, { name: game.i18n.localize("DAGGERHEART.Sheets.PC.NewScar"), description: '' }] }); + } + + static async selectScar(_, button){ + this.selectedScar = Number.parseInt(button.dataset.value); + this.render(); + } + + static async deleteScar(event, button) { + event.stopPropagation(); + await this.document.update({ "system.story.scars": this.document.system.story.scars.filter((_, index) => index !== Number.parseInt(button.currentTarget.dataset.scar) ) }) + } + + static async makeDeathMove() { + if(this.document.system.resources.health.value === this.document.system.resources.health.max){ + await new DhpDeathMove(this.document).render(true); + await this.minimize(); + } + } + + static async toggleFeatureDice(_, button){ + const index = Number.parseInt(button.dataset.index); + const feature = this.document.system.classFeatures.find(x => x.uuid === button.dataset.feature); + const path = `system.featureType.data.numbers.${index}`; + if(feature.system.featureType.data.numbers[index]?.used) return; + + if(Object.keys(feature.system.featureType.data.numbers).length <= index) { + const roll = new Roll(feature.system.featureType.data.value); + const rollData = await roll.evaluate(); + const cls = getDocumentClass("ChatMessage"); + const msg = new cls({ + user: game.user.id, + rolls: [roll] + }); + + await cls.create(msg.toObject()); + + await feature.update({ [path]: { value: Number.parseInt(rollData.total), used: false } }); + } else { + await Dialog.confirm({ + title: game.i18n.localize("Confirm feature use"), + content: `Are you sure you want to use ${feature.name}?`, + yes: async () => { + await feature.update({ [path]: { used: true } }); + + const cls = getDocumentClass("ChatMessage"); + const msg = new cls({ + user: game.user.id, + content: await renderTemplate("systems/daggerheart/templates/chat/ability-use.hbs", { + title: game.i18n.localize("DAGGERHEART.Chat.FeatureTitle"), + card: { name: `${feature.name} - Roll Of ${feature.system.featureType.data.numbers[index].value}`, img: feature.img }, + }), + }); + + cls.create(msg.toObject()); + }, + no: () => { return; }, + defaultYes: false + }); + + } + } + + async onFeatureInputBlur(event){ + const feature = this.document.system.classFeatures.find(x => x.uuid === event.currentTarget.dataset.feature); + const value = Number.parseInt(event.currentTarget.value); + if(!Number.isNaN(value)) await feature?.update({ "system.featureType.data.value": value }); + } + + async experienceDescriptionChange(event){ + const newExperiences = [...this.document.system.experiences]; + newExperiences[event.currentTarget.dataset.index].description = event.currentTarget.value; + await this.document.update({ "system.experiences": newExperiences }); + } + + async experienceValueChange(event){ + const newExperiences = [...this.document.system.experiences]; + newExperiences[event.currentTarget.dataset.index].value = event.currentTarget.value; + await this.document.update({ "system.experiences": newExperiences }); + } + + static setStoryEditor(_, button) { + this.storyEditor = this.storyEditor === button.dataset.value ? null : button.dataset.value; + this.render(); + } + + async itemUpdate(event){ + const name = event.currentTarget.dataset.item; + const item = await fromUuid($(event.currentTarget).closest('[data-item-id]')[0].dataset.itemId); + await item.update({ [name]: event.currentTarget.value }); + } + + static async deleteItem(_, button){ + const item = await fromUuid($(button).closest('[data-item-id]')[0].dataset.itemId); + await item.delete(); + } + + static async setItemQuantity(button, value){ + const item = await fromUuid($(button).closest('[data-item-id]')[0].dataset.itemId); + await item.update({ "system.quantity": Math.max(item.system.quantity + value, 1) }); + } + + static async useFeature(_, button) { + const item = await fromUuid(button.dataset.id); + + const cls = getDocumentClass("ChatMessage"); + const msg = new cls({ + type: 'abilityUse', + user: game.user.id, + content: "systems/daggerheart/templates/chat/ability-use.hbs", + system: { + title: game.i18n.localize("DAGGERHEART.Chat.FeatureTitle"), + img: item.img, + name: item.name, + description: item.system.description, + actions: item.system.actions, + }, + }); + + cls.create(msg.toObject()); + } + + static async useAbility(_, button) { + const item = await fromUuid(button.dataset.feature); + const type = button.dataset.type + + const cls = getDocumentClass("ChatMessage"); + const msg = new cls({ + type: 'abilityUse', + user: game.user.id, + system: { + title: type === 'ancestry' ? game.i18n.localize("DAGGERHEART.Chat.FoundationCard.AncestryTitle") : + type === 'community' ? game.i18n.localize("DAGGERHEART.Chat.FoundationCard.CommunityTitle") : + game.i18n.localize("DAGGERHEART.Chat.FoundationCard.SubclassFeatureTitle"), + img: item.img, + name: item.name, + description: item.system.description, + actions: [], + }, + content: "systems/daggerheart/templates/chat/ability-use.hbs", + }); + + cls.create(msg.toObject()); + } + + static async useAdvancementCard(_, button){ + const item = button.dataset.multiclass === 'true' ? this.document.system.multiclassSubclass : this.document.system.subclass; + const ability = item.system[`${button.dataset.key}Feature`]; + const title = `${item.name} - ${game.i18n.localize(`DAGGERHEART.Sheets.PC.DomainCard.${capitalize(button.dataset.key)}Title`)}`; + + + const cls = getDocumentClass("ChatMessage"); + const msg = new cls({ + user: game.user.id, + content: await renderTemplate("systems/daggerheart/templates/chat/ability-use.hbs", { + title: game.i18n.localize("DAGGERHEART.Chat.FoundationCard.SubclassFeatureTitle"), + card: { name: title, img: item.img, description: ability.description }, + }), + }); + + cls.create(msg.toObject()); + } + + static async useAdvancementAbility(_, button){ + // const item = await fromUuid(button.dataset.id); + const item = this.document.items.find(x => x.uuid === button.dataset.id); + + const cls = getDocumentClass("ChatMessage"); + const msg = new cls({ + user: game.user.id, + content: await renderTemplate("systems/daggerheart/templates/chat/ability-use.hbs", { + title: game.i18n.localize("DAGGERHEART.Chat.FoundationCard.SubclassFeatureTitle"), + card: { name: item.name, img: item.img, description: item.system.description }, + }), + }); + + cls.create(msg.toObject()); + } + + static async selectFeatureSet(_, button){ + const multiclass = button.dataset.multiclass === 'true'; + this.multiclassFeatureSetSelected = multiclass; + this.render(); + } + + static async close(options){ + this.onVaultTab = false; + super.close(options); + } + + async _onDragStart(_, event){ + if(event.currentTarget.classList.contains('inventory-item')){ + if(!['weapon', 'armor'].includes(event.currentTarget.dataset.type)){ + return; + } + + const targets = { + 'weapon': ['weapon-section', 'inventory-weapon-section'], + 'armor': ['armor-section', 'inventory-armor-section'], + }; + + event.dataTransfer.setData("text/plain", JSON.stringify({ uuid: event.currentTarget.dataset.item, internal: true, targets: targets[event.currentTarget.dataset.type] })); + } + + super._onDragStart(event); + } + + async _onDrop(event){ + const itemData = event.dataTransfer?.getData('text/plain'); + const item = itemData ? JSON.parse(itemData) : null; + if (item?.internal){ + let target = null; + event.currentTarget.classList.forEach(x => { + if(item.targets.some(target => target === x)){ + target = x; + } + }); + if(target){ + const itemObject = await fromUuid(item.uuid); + switch(target){ + case 'weapon-section': + if(itemObject.system.secondary && this.document.system.activeWeapons.burden === 'twoHanded'){ + ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.SecondaryEquipWhileTwohanded")); + return; + } + else if(itemObject.system.burden === 'twoHanded' && this.document.system.activeWeapons.secondary){ + ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.TwohandedEquipWhileSecondary")); + return; + } + + const existingWeapon = this.document.items.find(x => x.system.active && x.system.secondary === itemObject.system.secondary); + await existingWeapon?.update({ "system.active": false }); + await itemObject.update({ "system.active": true }); + break; + case 'armor-section': + const existingArmor = this.document.items.find(x => x.type === 'armor' && x.system.active); + await existingArmor?.update({ "system.active": false }); + await itemObject.update({ "system.active": true }); + break; + case 'inventory-weapon-section': + const existingInventoryWeapon = this.document.items.find(x => x.system.inventoryWeapon); + await existingInventoryWeapon?.update({ "system.inventoryWeapon": false }); + await itemObject.update({ "system.inventoryWeapon": true }); + break; + case 'inventory-armor-section': + const existingInventoryArmor = this.document.items.find(x => x.system.inventoryArmor); + await existingInventoryArmor?.update({ "system.inventoryArmor": false }); + await itemObject.update({ "system.inventoryArmor": true }); + break; + } + } + } + else { + super._onDrop(event); + this._onDropItem(event, TextEditor.getDragEventData(event)); + } + } + + async _onDropItem(event, data){ + if(this.dropItemBlock){ + return; + } + else { + this.dropItemBlock = true; + setTimeout(() => this.dropItemBlock = false, 500); + } + + const element = event.currentTarget; + const item = await Item.implementation.fromDropData(data); + const itemData = item.toObject(); + + const createdItems = []; + + if(item.type === 'domainCard'){ + if(!this.document.system.class) + { + ui.notifications.error(game.i18n.localize("DAGGERHEART.Notification.Error.NoClassSelected")); + return; + } + + if(!this.document.system.domains.find(x => x === item.system.domain)){ + ui.notifications.error(game.i18n.localize("DAGGERHEART.Notification.Error.LacksDomain")); + return; + } + + if(this.document.system.domainCards.total.length === this.document.system.domainData.maxCards){ + ui.notifications.error(game.i18n.localize("DAGGERHEART.Notification.Error.MaxLoadoutReached")); + return; + } + + if(this.document.system.domainCards.total.find(x => x.name === item.name)){ + ui.notifications.error(game.i18n.localize("DAGGERHEART.Notification.Error.DuplicateDomainCard")); + return; + } + + if(this.document.system.domainCards.loadout.length >= this.document.system.domainData.maxLoadout){ + itemData.system.inVault = true; + } + + if ( this.document.uuid === item.parent?.uuid ) return this._onSortItem(event, itemData); + const createdItem = await this._onDropItemCreate(itemData); + + return createdItem; + } + else { + if(!item.system.multiclass && ['class', 'subclass', 'ancestry', 'community'].includes(item.type)){ + const existing = this.document.items.find(x => x.type === item.type); + await existing?.delete(); + } + + if(item.type === 'subclass'){ + if(!item.system.multiclass){ + if(!this.document.system.class){ + ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.SelectClassBeforeSubclass")); + return; + } + else if(!this.document.system.class.system.subclasses.some(x => x.uuid === item.uuid)){ + ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.SubclassNotOfClass")); + return; + } + + for(var feature of this.document.items.filter(x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.subclass.id)){ + await feature.delete(); + } + } + + const features = [itemData.system.foundationFeature, itemData.system.specializationFeature, itemData.system.masteryFeature]; + for(var i = 0; i < features.length; i++){ + const feature = features[i]; + for(var ability of feature.abilities){ + const data = (await fromUuid(ability.uuid)).toObject(); + if(i > 0 ) data.system.disabled = true; + data.uuid = itemData.uuid; + + const abilityData = await this._onDropItemCreate(data); + ability.uuid = abilityData[0].uuid; + + createdItems.push(abilityData); + } + } + } + else if(item.type === 'class'){ + if(!item.system.multiclass){ + for(var feature of this.document.items.filter(x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.class.id)){ + await feature.delete(); + } + } + + for(var feature of item.system.features){ + const data = (await fromUuid(feature.uuid)).toObject(); + const itemData = await this._onDropItemCreate(data); + createdItems.push(itemData); + } + } + else if(item.type === 'ancestry'){ + for(var feature of this.document.items.filter(x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.ancestry.id)){ + await feature.delete(); + } + + for(var feature of item.system.abilities){ + const data = (await fromUuid(feature.uuid)).toObject(); + const itemData = await this._onDropItemCreate(data); + createdItems.push(itemData); + } + } + else if(item.type === 'community'){ + for(var feature of this.document.items.filter(x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.community.id)){ + await feature.delete(); + } + + for(var feature of item.system.abilities){ + const data = (await fromUuid(feature.uuid)).toObject(); + const itemData = await this._onDropItemCreate(data); + createdItems.push(itemData); + } + } + + if ( this.document.uuid === item.parent?.uuid ) return this._onSortItem(event, item); + + if(item.type === 'weapon'){ + if(!element) return; + + if(element.classList.contains('weapon-section')){ + if(item.system.secondary && this.document.system.activeWeapons.burden === 'twoHanded'){ + ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.SecondaryEquipWhileTwohanded")); + return; + } + else if(item.system.burden === 'twoHanded' && this.document.system.activeWeapons.secondary){ + ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.TwohandedEquipWhileSecondary")); + return; + } + + const existing = this.document.system.activeWeapons.primary && !item.system.secondary ? await fromUuid(this.document.system.activeWeapons.primary.uuid) : + this.document.system.activeWeapons.secondary && item.system.secondary ? await fromUuid(this.document.system.activeWeapons.secondary.uuid) : null; + await existing?.delete(); + itemData.system.active = true; + } + else if(element.classList.contains('inventory-weapon-section-first')){ + const existing = this.document.system.inventoryWeapons.first ? await fromUuid(this.document.system.inventoryWeapons.first.uuid) : null; + await existing?.delete(); + + itemData.system.inventoryWeapon = 1; + } + else if(element.classList.contains('inventory-weapon-section-second')){ + const existing = this.document.system.inventoryWeapons.second ? await fromUuid(this.document.system.inventoryWeapons.second.uuid) : null; + await existing?.delete(); + + itemData.system.inventoryWeapon = 2; + } + else return []; + } + + if(item.type === 'armor'){ + if(!element) return; + + if(element.classList.contains('armor-section')){ + const existing = this.document.system.armor ? await fromUuid(this.document.system.armor.uuid) : null; + await existing?.delete(); + } + + else return; + } + + const createdItem = await this._onDropItemCreate(itemData); + createdItems.push(createdItem); + + return createdItems; + } + } + + async _onDropItemCreate(itemData, event) { + itemData = itemData instanceof Array ? itemData : [itemData]; + return this.document.createEmbeddedDocuments("Item", itemData); + } + + async emulateItemDrop(data) { + const event = new DragEvent("drop", { altKey: game.keyboard.isModifierActive("Alt") }); + return this._onDropItem(event, data); + } +} + +// export default class PCSheet extends DhpApplicationMixin(ActorSheet) { +// static applicationType = "sheets/pc"; +// static documentType = "pc"; + +// constructor(actor, options){ +// super(actor, options); + +// this.editAttributes = false; +// this.onVaultTab = false; +// this.currentInventoryPage = 0; +// this.selectedScar = null; +// this.storyEditor = null; +// this.dropItemBlock = false; +// this.multiclassFeatureSetSelected = false; +// } + +// /** @override */ +// static get defaultOptions() { +// return foundry.utils.mergeObject(super.defaultOptions, { +// classes: ["daggerheart", "sheet", "pc"], +// width: 810, +// height: 1080, +// resizable: false, +// tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "features" }, { navSelector: ".loadout-tabs", contentSelector: ".loadout-body", initial: "loadout"}], +// dragDrop: [ +// {dragSelector: null, dropSelector: ".weapon-section" }, +// {dragSelector: null, dropSelector: ".armor-section"}, +// {dragSelector: null, dropSelector: ".inventory-weapon-section-first"}, +// {dragSelector: null, dropSelector: ".inventory-weapon-section-second"}, +// {dragSelector: ".item-list .item", dropSelector: null}, +// ] +// }, { overwrite: true, inplace: true }); +// } + +// async mapFeatureType(data, configType){ +// return await Promise.all(data.map(async x => { +// const abilities = x.system.abilities ? await Promise.all(x.system.abilities.map(async x => await fromUuid(x.uuid))) : []; + +// return { +// ...x, +// uuid: x.uuid, +// system: { +// ...x.system, +// abilities: abilities, +// type: game.i18n.localize(configType[x.system.type??x.type].label) +// } +// } +// })); +// } + +// mapAdvancementFeatures(actor, config) { +// if(!actor.system.subclass) return { foundation: null, advancements: [] }; + +// const { subclass, multiclassSubclass } = actor.system.subclassFeatures; + +// const foundation = { +// type: 'foundation', +// multiclass: false, +// img: actor.system.subclass.img, +// subtitle: game.i18n.localize("DAGGERHEART.Sheets.PC.DomainCard.FoundationTitle"), +// domains: actor.system.class.system.domains.map(x => config.DOMAIN.domains[x].src), +// className: actor.system.class.name, +// subclassUuid: actor.system.subclass.uuid, +// subclassName: actor.system.subclass.name, +// spellcast: config.ACTOR.abilities[actor.system.subclass.system.spellcastingTrait]?.name ?? null, +// description: actor.system.subclass.system.foundationFeature.description, +// abilities: subclass.foundation, +// abilityKey: 'foundationFeature', +// }; + +// const firstKey = actor.system.subclass.system.specializationFeature.unlocked && actor.system.subclass.system.specializationFeature.tier === 2 ? 'sub' : +// actor.system.multiclass?.system?.multiclassTier === 2 ? 'multi' : null; +// const firstType = firstKey === 'sub' ? 'specialization' : 'foundation'; +// const firstBase = firstKey === 'sub' ? actor.system.subclass : firstKey === 'multi' ? actor.system.multiclassSubclass : null; +// const first = !firstBase ? null : { +// type: firstType, +// multiclass: firstKey === 'multi', +// img: firstBase.img, +// subtitle: firstKey === 'sub' ? game.i18n.localize("DAGGERHEART.Sheets.PC.DomainCard.SpecializationTitle") : game.i18n.localize("DAGGERHEART.Sheets.PC.DomainCard.FoundationTitle"), +// domains: firstKey === 'sub' ? actor.system.class.system.domains.map(x => config.DOMAIN.domains[x].src) : actor.system.multiclass.system.domains.map(x => config.DOMAIN.domains[x].src), +// className: firstKey === 'sub' ? actor.system.class.name : actor.system.multiclass.name, +// subclassUuid: firstBase.uuid, +// subclassName: firstBase.name, +// spellcast: firstKey === 'sub' ? null : config.ACTOR.abilities[firstBase.system.spellcastingTrait]?.name ?? null, +// description: firstKey === 'sub' ? firstBase.system.specializationFeature.description : firstBase.system.foundationFeature.description, +// abilities: firstKey === 'sub' ? subclass.specialization : multiclassSubclass.foundation, +// abilityKey: firstKey === 'sub' ? 'specializationFeature' : 'foundationFeature', +// }; + +// const secondKey = (actor.system.subclass.system.specializationFeature.unlocked && actor.system.subclass.system.specializationFeature.tier === 3) || (actor.system.subclass.system.masteryFeature.unlocked && actor.system.subclass.system.masteryFeature.tier === 3) ? 'sub' : +// (actor.system.multiclass?.system?.multiclassTier === 3) || (actor.system.multiclassSubclass?.system?.specializationFeature?.unlocked) ? 'multi' : null; +// const secondBase = secondKey === 'sub' ? actor.system.subclass : secondKey === 'multi' ? actor.system.multiclassSubclass : null; +// const secondAbilities = secondKey === 'sub' ? subclass : multiclassSubclass; +// const secondType = secondBase ? secondBase.system.masteryFeature.unlocked ? 'mastery' : secondBase.system.specializationFeature.unlocked ? 'specialization' : 'foundation' : null; +// const second = !secondBase ? null : { +// type: secondType, +// multiclass: secondKey === 'multi', +// img: secondBase.img, +// subtitle: secondBase.system.masteryFeature.unlocked ? game.i18n.localize("DAGGERHEART.Sheets.PC.DomainCard.MasteryTitle") : +// secondBase.system.specializationFeature.unlocked ? game.i18n.localize("DAGGERHEART.Sheets.PC.DomainCard.SpecializationTitle") : game.i18n.localize("DAGGERHEART.Sheets.PC.DomainCard.FoundationTitle"), +// domains: secondKey === 'sub' ? actor.system.class.system.domains.map(x => config.DOMAIN.domains[x].src) : actor.system.multiclass.system.domains.map(x => config.DOMAIN.domains[x].src), +// className: secondKey === 'sub' ? actor.system.class.name : actor.system.multiclass.name, +// subclassUuid: secondBase.uuid, +// subclassName: secondBase.name, +// spellcast: secondKey === 'sub' || secondBase.system.specializationFeature.unlocked ? null : config.ACTOR.abilities[firstBase.system.spellcastingTrait]?.name ?? null, +// description: +// secondBase.system.masteryFeature.unlocked ? secondBase.system.masteryFeature.description : +// secondBase.system.specializationFeature.unlocked ? secondBase.system.specializationFeature.description : firstBase.system.foundationFeature.description, +// abilities: +// secondBase.system.masteryFeature.unlocked ? secondAbilities.mastery : +// secondBase.system.specializationFeature.unlocked ? secondAbilities.specialization : secondAbilities.foundation, +// abilityKey: secondBase.system.masteryFeature.unlocked ? 'masteryFeature' : secondBase.system.specializationFeature.unlocked ? 'specializationFeature' : 'foundationFeature', +// }; + +// return { +// foundation: foundation, +// first: first, +// second: second, +// } +// } + +// /** @override */ +// async getData() { +// const context = super.getData(); +// context.config = SYSTEM; +// context.editAttributes = this.editAttributes; +// context.onVaultTab = this.onVaultTab; +// context.selectedScar = this.selectedScar; +// context.storyEditor = this.storyEditor; +// context.multiclassFeatureSetSelected = this.multiclassFeatureSetSelected; + +// const selectedAttributes = Object.values(this.actor.system.attributes).map(x => x.data.base); +// context.abilityScoreArray = JSON.parse(await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.General.AbilityArray)).reduce((acc, x) => { +// const selectedIndex = selectedAttributes.indexOf(x); +// if(selectedIndex !== -1){ +// selectedAttributes.splice(selectedIndex, 1); +// } else { +// acc.push({ name: x, value: x }); +// } + +// return acc; +// }, []); +// if(!context.abilityScoreArray.includes(0)) context.abilityScoreArray.push({ name: 0, value: 0 }); +// context.abilityScoresFinished = context.abilityScoreArray.every(x => x.value === 0); + +// context.domains = this.actor.system.class ? { +// first: this.actor.system.class.system.domains[0] ? SYSTEM.DOMAIN.domains[this.actor.system.class.system.domains[0]].src : null, +// second: this.actor.system.class.system.domains[1] ? SYSTEM.DOMAIN.domains[this.actor.system.class.system.domains[1]].src : null, +// } : { }; + +// context.attributes = Object.keys(this.actor.system.attributes).reduce((acc, key) => { +// acc[key] = { +// ...this.actor.system.attributes[key], +// name: game.i18n.localize(SYSTEM.ACTOR.abilities[key].name), +// verbs: SYSTEM.ACTOR.abilities[key].verbs.map(x => game.i18n.localize(x)), +// }; + +// return acc; +// }, {}); + +// const ancestry = await this.mapFeatureType(this.actor.system.ancestry ? [this.actor.system.ancestry] : [], SYSTEM.GENERAL.objectTypes); +// const community = await this.mapFeatureType(this.actor.system.community ? [this.actor.system.community] : [], SYSTEM.GENERAL.objectTypes); +// const foundation = { +// ancestry: ancestry[0], +// community: community[0], +// advancement: { +// ...this.mapAdvancementFeatures(this.actor, SYSTEM) +// } +// }; + +// const nrLoadoutCards = this.actor.system.domainCards.loadout.length; +// const loadout = await this.mapFeatureType(this.actor.system.domainCards.loadout, SYSTEM.DOMAIN.cardTypes); +// const vault = await this.mapFeatureType(this.actor.system.domainCards.vault, SYSTEM.DOMAIN.cardTypes); +// context.abilities = { +// foundation: foundation, +// loadout: { +// top: loadout.slice(0, Math.min(2, nrLoadoutCards)), +// bottom: nrLoadoutCards > 2 ? loadout.slice(2, Math.min(5, nrLoadoutCards)) : [], +// nrTotal: nrLoadoutCards, +// }, +// vault: vault.map(x => ({ ...x, uuid: x.uuid, sendToLoadoutDisabled: this.actor.system.domainCards.loadout.length >= this.actor.system.domainData.maxLoadout })) +// }; + +// context.inventory = { +// consumable: { +// titles: { +// name: game.i18n.localize("DAGGERHEART.Sheets.PC.InventoryTab.ConsumableTitle"), +// quantity: game.i18n.localize("DAGGERHEART.Sheets.PC.InventoryTab.QuantityTitle"), +// }, +// items: this.actor.items.filter(x => x.type === 'consumable'), +// }, +// miscellaneous: { +// titles: { +// name: game.i18n.localize("DAGGERHEART.Sheets.PC.InventoryTab.MiscellaneousTitle"), +// quantity: game.i18n.localize("DAGGERHEART.Sheets.PC.InventoryTab.QuantityTitle"), +// }, +// items: this.actor.items.filter(x => x.type === 'miscellaneous'), +// }, +// } + +// if(context.inventory.length === 0){ +// context.inventory = Array(1).fill(Array(5).fill([])); +// } + +// context.classFeatures = (this.multiclassFeatureSetSelected ? this.actor.system.multiclassFeatures : this.actor.system.classFeatures).map(x => { +// if(x.system.featureType.type !== 'dice'){ +// return x; +// } + +// return { ...x, uuid: x.uuid, system: { ...x.system, featureType: { ...x.system.featureType, data: { ...x.system.featureType.data, property: this.actor.system.subclass ? SYSTEM.ACTOR.featureProperties[x.system.featureType.data.property].path(this.actor) : 0 }}}}; +// }); + +// return context; +// } + +// activateListeners(html) { +// super.activateListeners(html); + +// html.find(".attribute-value").on("change", this.attributeChange.bind(this)); +// html.on('click', '.tab-selector', this.tabSwitch.bind(this)); +// html.on('click', '.level-title.levelup', this.openLevelUp.bind(this)); +// html.find(".feature-input").on("change", this.onFeatureInputBlur.bind(this)); +// html.find(".experience-description").on("change", this.experienceDescriptionChange.bind(this)); +// html.find(".experience-value").on("change", this.experienceValueChange.bind(this)); +// html.on("change", "[data-item]", this.itemUpdate.bind(this)); +// } + +// async _handleAction(action, event, button) { +// switch(action){ +// case 'toggleEditAttributes': +// this.toggleEditAttributes(); +// break; +// case 'attributeRoll': +// await this.rollAttribute(event); +// break; +// case 'toggleMarks': +// await this.toggleMarks(button); +// break; +// case 'toggleAttributeMark': +// await this.toggleAttributeMark(button); +// break; +// case 'toggleHP': +// await this.toggleHP(button); +// break; +// case 'toggleStress': +// await this.toggleStress(button); +// break; +// case 'toggleHope': +// await this.toggleHope(button); +// break; +// case 'toggleGold': +// await this.toggleGold(button); +// break; +// case 'attackRoll': +// await this.attackRoll(event); +// break; +// case 'tabToLoadout': +// this.domainCardsTab(false); +// break; +// case 'tabToVault': +// this.domainCardsTab(true); +// break; +// case 'sendToVault': +// await this.moveDomainCard(button, true); +// break; +// case 'sendToLoadout': +// await this.moveDomainCard(button, false); +// break; +// case 'useDomainCard': +// await this.useDomainCard(button); +// break; +// case 'selectClass': +// await this.selectClass(); +// break; +// case 'selectSubclass': +// await this.selectSubclass(); +// break; +// case 'selectAncestry': +// await this.selectAncestry(); +// break; +// case 'selectCommunity': +// await this.selectCommunity(); +// break; +// case 'viewObject': +// await this.viewObject(button); +// break; +// case 'useFeature': +// await this.useFeature(button); +// break; +// case 'takeShortRest': +// await this.takeShortRest(); +// break; +// case 'takeLongRest': +// await this.takeLongRest(); +// break; +// case 'removeActiveItem': +// await this.removeActiveItem(event); +// break; +// case 'removeInventoryWeapon': +// await this.removeInventoryWeapon(event); +// break; +// case 'addMiscItem': +// await this.addMiscItem(); +// break; +// case 'deleteItem': +// await this.deleteItem(button); +// break; +// case 'addScar': +// await this.addScar(); +// break; +// case 'selectScar': +// await this.selectScar(button); +// break; +// case 'deleteScar': +// await this.deleteScar(event); +// break; +// case 'makeDeathMove': +// await this.makeDeathMove(); +// break; +// case 'toggleFeatureDice': +// await this.toggleFeatureDice(button); +// break; +// case 'setStoryEditor': +// this.setStoryEditor(button); +// break; +// case 'itemQuantityDecrease': +// await this.setItemQuantity(button, -1); +// break; +// case 'itemQuantityIncrease': +// await this.setItemQuantity(button, 1); +// break; +// case 'useAbility': +// await this.useAbility(button); +// break; +// case 'useAdvancementCard': +// await this.useAdvancementCard(button); +// break; +// case 'useAdvancementAbility': +// await this.useAdvancementAbility(button); +// break; +// case 'selectFeatureSet': +// await this.selectFeatureSet(button); +// break; +// } +// } + +// async attributeChange(event){ +// const path = `system.attributes.${event.currentTarget.dataset.attribute}.data.base`; +// await this.actor.update({ [path]: event.currentTarget.value }); +// } + +// toggleEditAttributes(){ +// this.editAttributes = !this.editAttributes; +// this.render(); +// } + +// async rollAttribute(event){ +// const { roll, hope, fear, advantage, disadvantage, modifiers } = await this.actor.dualityRoll({ title: 'Attribute Bonus', value: event.currentTarget.dataset.value }, event.shiftKey); + +// const cls = getDocumentClass("ChatMessage"); +// const msg = new cls({ +// type: 'dualityRoll', +// system: { +// roll: roll._formula, +// modifiers: modifiers, +// hope: hope, +// fear: fear, +// advantage: advantage, +// disadvantage: disadvantage, +// }, +// user: game.user.id, +// content: "systems/daggerheart/templates/chat/duality-roll.hbs", +// rolls: [roll] +// }); + +// await cls.create(msg.toObject()); +// } + +// async toggleMarks(button){ +// const markValue = Number.parseInt(button.dataset.value); +// const newValue = this.actor.system.armor.system.marks.value >= markValue ? markValue-1 : markValue; +// await this.actor.system.armor.update({ 'system.marks.value': newValue }); +// } + +// async toggleAttributeMark(button){ +// const attribute = this.actor.system.attributes[button.dataset.attribute]; +// const newMark = this.actor.system.availableAttributeMarks.filter(x => x > Math.max.apply(null, this.actor.system.attributes[button.dataset.attribute].levelMarks)).sort((a, b) => a > b ? 1 : -1)[0]; + +// if(attribute.levelMark || !newMark) return; + + +// const path = `system.attributes.${button.dataset.attribute}.levelMarks`; +// await this.actor.update({ [path]: [...attribute.levelMarks, newMark] }); +// } + +// async toggleHP(button){ +// const healthValue = Number.parseInt(button.dataset.value); +// const newValue = this.actor.system.resources.health.value >= healthValue ? healthValue-1 : healthValue; +// await this.actor.update({ 'system.resources.health.value': newValue }); +// } + +// async toggleStress(button){ +// const healthValue = Number.parseInt(button.dataset.value); +// const newValue = this.actor.system.resources.stress.value >= healthValue ? healthValue-1 : healthValue; +// await this.actor.update({ 'system.resources.stress.value': newValue }); +// } + +// async toggleHope(button){ +// const hopeValue = Number.parseInt(button.dataset.value); +// const newValue = this.actor.system.resources.hope.value >= hopeValue ? hopeValue-1 : hopeValue; +// await this.actor.update({ 'system.resources.hope.value': newValue }); +// } + +// async toggleGold(button){ +// const goldValue = Number.parseInt(button.dataset.value); +// const goldType = button.dataset.type; +// const newValue = this.actor.system.gold[goldType] >= goldValue ? goldValue-1 : goldValue; + +// const update = `system.gold.${goldType}`; +// await this.actor.update({ [update]: newValue }); +// } + +// async attackRoll(event){ +// const weapon = await fromUuid(event.currentTarget.dataset.weapon); +// const damage = { +// value: `${this.actor.system.proficiency.value}${weapon.system.damage.value}`, +// type: weapon.system.damage.type, +// bonusDamage: this.actor.system.bonuses.damage +// }; +// const modifier = this.actor.system.attributes[weapon.system.trait].data.value; + +// const { roll, hope, fear, advantage, disadvantage, modifiers, bonusDamageString } = await this.actor.dualityRoll({ title: 'Attribute Modifier', value: modifier }, event.shiftKey, damage.bonusDamage); + +// damage.value = damage.value.concat(bonusDamageString); + +// const targets = Array.from(game.user.targets).map(x => ({ +// id: x.id, +// name: x.actor.name, +// img: x.actor.img, +// difficulty: x.actor.system.difficulty, +// evasion: x.actor.system.evasion, +// })); + +// const cls = getDocumentClass("ChatMessage"); +// const msg = new cls({ +// type: 'dualityRoll', +// system: { +// roll: roll._formula, +// modifiers: modifiers, +// hope: hope, +// fear: fear, +// advantage: advantage, +// disadvantage: disadvantage, +// damage: damage, +// targets: targets, +// }, +// content: "systems/daggerheart/templates/chat/attack-roll.hbs", +// rolls: [roll] +// }); + +// await cls.create(msg.toObject()); +// } + +// tabSwitch(event){ +// const tab = event.currentTarget.dataset.tab; +// if(tab !== 'loadout'){ +// this.onVaultTab = false; +// } + +// this.render(); +// } + +// openLevelUp(event){ +// new DhpLevelup(this.actor).render(true); +// } + +// domainCardsTab(toVault){ +// this.onVaultTab = toVault; +// this.render(); +// } + +// async moveDomainCard(button, toVault){ +// if(!toVault && this.actor.system.domainCards.loadout.length >= this.actor.system.domainData.maxLoadout){ +// return; +// } + +// const card = this.actor.items.find(x => x.uuid === button.dataset.domain); +// await card.update({ "system.inVault": toVault }); +// } + +// async useDomainCard(button){ +// const card = this.actor.items.find(x => x.uuid === button.dataset.key); + +// const cls = getDocumentClass("ChatMessage"); +// const msg = new cls({ +// type: 'abilityUse', +// user: game.user.id, +// content: "systems/daggerheart/templates/chat/ability-use.hbs", +// system: { +// title: `${game.i18n.localize("DAGGERHEART.Chat.DomainCard.Title")} - ${capitalize(button.dataset.domain)}`, +// img: card.img, +// name: card.name, +// description: card.system.effect, +// actions: card.system.actions, +// }, +// }); + +// cls.create(msg.toObject()); +// } + +// async selectClass(){ +// (await game.packs.get('daggerheart.playtest-classes'))?.render(true); +// } + +// async selectSubclass(){ +// (await game.packs.get('daggerheart.playtest-subclasses'))?.render(true); +// } + +// async selectAncestry(){ +// const dialogClosed = new Promise((resolve, _) => { +// new AncestrySelectionDialog(resolve).render(true); +// }); +// const result = await dialogClosed; + +// // await this.emulateItemDrop({ type: 'item', data: result }); +// for(var ancestry of this.actor.items.filter(x => x => x.type === 'ancestry')){ +// await ancestry.delete(); +// } + +// const createdItems = []; +// for(var feature of this.actor.items.filter(x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.ancestry.id)){ +// await feature.delete(); +// } + +// // createdItems.push(...result.data.system.abilities); +// createdItems.push(result.data); + + +// await this.actor.createEmbeddedDocuments('Item', createdItems); + +// // await this.actor.createEmbeddedDocuments("Item", [result.toObject()]); +// // (await game.packs.get('daggerheart.playtest-ancestries'))?.render(true); +// } + +// async selectCommunity(){ +// (await game.packs.get('daggerheart.playtest-communities'))?.render(true);; +// } + +// async viewObject(button){ +// const object = await fromUuid(button.dataset.value); +// if(!object) return; + +// const tab = button.dataset.tab; +// if(tab) object.sheet._tabs[0].active = tab; + +// if(object.sheet.editMode) object.sheet.editMode = false; + +// object.sheet.render(true); +// } + +// async takeShortRest(){ +// await new DhpDowntime(this.actor, true).render(true); +// await this.minimize(); +// } + +// async takeLongRest(){ +// await new DhpDowntime(this.actor, false).render(true); +// await this.minimize(); +// } + +// async removeActiveItem(event){ +// event.stopPropagation(); +// const item = await fromUuid(event.currentTarget.dataset.item); +// await item.delete(); +// } + +// async removeInventoryWeapon(event){ +// event.stopPropagation(); +// const item = await fromUuid(event.currentTarget.dataset.item); +// await item.delete(); +// } + +// async addMiscItem(){ +// const result = await this.actor.createEmbeddedDocuments("Item", [{ +// name: game.i18n.localize('DAGGERHEART.Sheets.PC.NewItem'), +// type: 'miscellaneous' +// }]); + +// await result[0].sheet.render(true); +// } + +// async addScar(){ +// if(this.actor.system.story.scars.length === 5) return; + +// await this.actor.update({ "system.story.scars": [...this.actor.system.story.scars, { name: game.i18n.localize("DAGGERHEART.Sheets.PC.NewScar"), description: '' }] }); +// } + +// async selectScar(button){ +// this.selectedScar = Number.parseInt(button.dataset.value); +// this.render(); +// } + +// async deleteScar(event) { +// event.stopPropagation(); +// await this.actor.update({ "system.story.scars": this.actor.system.story.scars.filter((_, index) => index !== Number.parseInt(event.currentTarget.dataset.scar) ) }) +// } + +// async makeDeathMove() { +// if(this.actor.system.resources.health.value === this.actor.system.resources.health.max){ +// await new DhpDeathMove(this.actor).render(true); +// await this.minimize(); +// } +// } + +// async toggleFeatureDice(button){ +// const index = Number.parseInt(button.dataset.index); +// const feature = this.actor.system.classFeatures.find(x => x.uuid === button.dataset.feature); +// const path = `system.featureType.data.numbers.${index}`; +// if(feature.system.featureType.data.numbers[index]?.used) return; + +// if(Object.keys(feature.system.featureType.data.numbers).length <= index) { +// const roll = new Roll(feature.system.featureType.data.value); +// const rollData = await roll.evaluate(); +// const cls = getDocumentClass("ChatMessage"); +// const msg = new cls({ +// user: game.user.id, +// rolls: [roll] +// }); + +// await cls.create(msg.toObject()); + +// await feature.update({ [path]: { value: Number.parseInt(rollData.total), used: false } }); +// } else { +// await Dialog.confirm({ +// title: game.i18n.localize("Confirm feature use"), +// content: `Are you sure you want to use ${feature.name}?`, +// yes: async () => { +// await feature.update({ [path]: { used: true } }); + +// const cls = getDocumentClass("ChatMessage"); +// const msg = new cls({ +// user: game.user.id, +// content: await renderTemplate("systems/daggerheart/templates/chat/ability-use.hbs", { +// title: game.i18n.localize("DAGGERHEART.Chat.FeatureTitle"), +// card: { name: `${feature.name} - Roll Of ${feature.system.featureType.data.numbers[index].value}`, img: feature.img }, +// }), +// }); + +// cls.create(msg.toObject()); +// }, +// no: () => { return; }, +// defaultYes: false +// }); + +// } +// } + +// async onFeatureInputBlur(event){ +// const feature = this.actor.system.classFeatures.find(x => x.uuid === event.currentTarget.dataset.feature); +// const value = Number.parseInt(event.currentTarget.value); +// if(!Number.isNaN(value)) await feature?.update({ "system.featureType.data.value": value }); +// } + +// async experienceDescriptionChange(event){ +// const newExperiences = [...this.actor.system.experiences]; +// newExperiences[event.currentTarget.dataset.index].description = event.currentTarget.value; +// await this.actor.update({ "system.experiences": newExperiences }); +// } + +// async experienceValueChange(event){ +// const newExperiences = [...this.actor.system.experiences]; +// newExperiences[event.currentTarget.dataset.index].value = event.currentTarget.value; +// await this.actor.update({ "system.experiences": newExperiences }); +// } + +// setStoryEditor(button) { +// this.storyEditor = this.storyEditor === button.dataset.value ? null : button.dataset.value; +// this.render(); +// } + +// async itemUpdate(event){ +// const name = event.currentTarget.dataset.item; +// const item = await fromUuid($(event.currentTarget).closest('[data-item-id]')[0].dataset.itemId); +// await item.update({ [name]: event.currentTarget.value }); +// } + +// async deleteItem(button){ +// const item = await fromUuid($(button).closest('[data-item-id]')[0].dataset.itemId); +// await item.delete(); +// } + +// async setItemQuantity(button, value){ +// const item = await fromUuid($(button).closest('[data-item-id]')[0].dataset.itemId); +// await item.update({ "system.quantity": Math.max(item.system.quantity + value, 1) }); +// } + +// async useFeature(button) { +// const item = await fromUuid(button.dataset.id); + +// const cls = getDocumentClass("ChatMessage"); +// const msg = new cls({ +// type: 'abilityUse', +// user: game.user.id, +// content: "systems/daggerheart/templates/chat/ability-use.hbs", +// system: { +// title: game.i18n.localize("DAGGERHEART.Chat.FeatureTitle"), +// img: item.img, +// name: item.name, +// description: item.system.description, +// actions: item.system.actions, +// }, +// }); + +// cls.create(msg.toObject()); +// } + +// async useAbility(button) { +// const item = await fromUuid(button.dataset.feature); +// const type = button.dataset.type + +// const cls = getDocumentClass("ChatMessage"); +// const msg = new cls({ +// type: 'abilityUse', +// user: game.user.id, +// system: { +// title: type === 'ancestry' ? game.i18n.localize("DAGGERHEART.Chat.FoundationCard.AncestryTitle") : +// type === 'community' ? game.i18n.localize("DAGGERHEART.Chat.FoundationCard.CommunityTitle") : +// game.i18n.localize("DAGGERHEART.Chat.FoundationCard.SubclassFeatureTitle"), +// img: item.img, +// name: item.name, +// description: item.system.description, +// actions: [], +// }, +// content: "systems/daggerheart/templates/chat/ability-use.hbs", +// }); + +// cls.create(msg.toObject()); +// } + +// async useAdvancementCard(button){ +// const item = button.dataset.multiclass === 'true' ? this.actor.system.multiclassSubclass : this.actor.system.subclass; +// const ability = item.system[`${button.dataset.key}Feature`]; +// const title = `${item.name} - ${game.i18n.localize(`DAGGERHEART.Sheets.PC.DomainCard.${capitalize(button.dataset.key)}Title`)}`; + + +// const cls = getDocumentClass("ChatMessage"); +// const msg = new cls({ +// user: game.user.id, +// content: await renderTemplate("systems/daggerheart/templates/chat/ability-use.hbs", { +// title: game.i18n.localize("DAGGERHEART.Chat.FoundationCard.SubclassFeatureTitle"), +// card: { name: title, img: item.img, description: ability.description }, +// }), +// }); + +// cls.create(msg.toObject()); +// } + +// async useAdvancementAbility(button){ +// // const item = await fromUuid(button.dataset.id); +// const item = this.actor.items.find(x => x.uuid === button.dataset.id); + +// const cls = getDocumentClass("ChatMessage"); +// const msg = new cls({ +// user: game.user.id, +// content: await renderTemplate("systems/daggerheart/templates/chat/ability-use.hbs", { +// title: game.i18n.localize("DAGGERHEART.Chat.FoundationCard.SubclassFeatureTitle"), +// card: { name: item.name, img: item.img, description: item.system.description }, +// }), +// }); + +// cls.create(msg.toObject()); +// } + +// async selectFeatureSet(button){ +// const multiclass = button.dataset.multiclass === 'true'; +// this.multiclassFeatureSetSelected = multiclass; +// this.render(); +// } + +// async close(options){ +// this.onVaultTab = false; +// super.close(options); +// } + +// async _onDragStart(event){ +// if(event.currentTarget.classList.contains('inventory-item')){ +// if(!['weapon', 'armor'].includes(event.currentTarget.dataset.type)){ +// return; +// } + +// const targets = { +// 'weapon': ['weapon-section', 'inventory-weapon-section'], +// 'armor': ['armor-section', 'inventory-armor-section'], +// }; + +// event.dataTransfer.setData("text/plain", JSON.stringify({ uuid: event.currentTarget.dataset.item, internal: true, targets: targets[event.currentTarget.dataset.type] })); +// } + +// super._onDragStart(event); +// } + +// async _onDrop(event){ +// const itemData = event.dataTransfer?.getData('text/plain'); +// const item = itemData ? JSON.parse(itemData) : null; +// if (item?.internal){ +// let target = null; +// event.currentTarget.classList.forEach(x => { +// if(item.targets.some(target => target === x)){ +// target = x; +// } +// }); +// if(target){ +// const itemObject = await fromUuid(item.uuid); +// switch(target){ +// case 'weapon-section': +// if(itemObject.system.secondary && this.actor.system.activeWeapons.burden === 'twoHanded'){ +// ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.SecondaryEquipWhileTwohanded")); +// return; +// } +// else if(itemObject.system.burden === 'twoHanded' && this.actor.system.activeWeapons.secondary){ +// ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.TwohandedEquipWhileSecondary")); +// return; +// } + +// const existingWeapon = this.actor.items.find(x => x.system.active && x.system.secondary === itemObject.system.secondary); +// await existingWeapon?.update({ "system.active": false }); +// await itemObject.update({ "system.active": true }); +// break; +// case 'armor-section': +// const existingArmor = this.actor.items.find(x => x.type === 'armor' && x.system.active); +// await existingArmor?.update({ "system.active": false }); +// await itemObject.update({ "system.active": true }); +// break; +// case 'inventory-weapon-section': +// const existingInventoryWeapon = this.actor.items.find(x => x.system.inventoryWeapon); +// await existingInventoryWeapon?.update({ "system.inventoryWeapon": false }); +// await itemObject.update({ "system.inventoryWeapon": true }); +// break; +// case 'inventory-armor-section': +// const existingInventoryArmor = this.actor.items.find(x => x.system.inventoryArmor); +// await existingInventoryArmor?.update({ "system.inventoryArmor": false }); +// await itemObject.update({ "system.inventoryArmor": true }); +// break; +// } +// } +// } +// else { +// super._onDrop(event); +// } +// } + +// async _onDropItem(event, data){ +// if(this.dropItemBlock){ +// return; +// } +// else { +// this.dropItemBlock = true; +// setTimeout(() => this.dropItemBlock = false, 500); +// } + +// const element = event.currentTarget; +// const item = await Item.implementation.fromDropData(data); +// const itemData = item.toObject(); + +// const createdItems = []; + +// if(item.type === 'domainCard'){ +// if(!this.actor.system.class) +// { +// ui.notifications.error(game.i18n.localize("DAGGERHEART.Notification.Error.NoClassSelected")); +// return; +// } + +// if(!this.actor.system.domains.find(x => x === item.system.domain)){ +// ui.notifications.error(game.i18n.localize("DAGGERHEART.Notification.Error.LacksDomain")); +// return; +// } + +// if(this.actor.system.domainCards.total.length === this.actor.system.domainData.maxCards){ +// ui.notifications.error(game.i18n.localize("DAGGERHEART.Notification.Error.MaxLoadoutReached")); +// return; +// } + +// if(this.actor.system.domainCards.total.find(x => x.name === item.name)){ +// ui.notifications.error(game.i18n.localize("DAGGERHEART.Notification.Error.DuplicateDomainCard")); +// return; +// } + +// if(this.actor.system.domainCards.loadout.length >= this.actor.system.domainData.maxLoadout){ +// itemData.system.inVault = true; +// } + +// if ( this.actor.uuid === item.parent?.uuid ) return this._onSortItem(event, itemData); +// const createdItem = await this._onDropItemCreate(itemData); + +// return createdItem; +// } +// else { +// if(!item.system.multiclass && ['class', 'subclass', 'ancestry', 'community'].includes(item.type)){ +// const existing = this.actor.items.find(x => x.type === item.type); +// await existing?.delete(); +// } + +// if(item.type === 'subclass'){ +// if(!item.system.multiclass){ +// if(!this.actor.system.class){ +// ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.SelectClassBeforeSubclass")); +// return; +// } +// else if(!this.actor.system.class.system.subclasses.some(x => x.uuid === item.uuid)){ +// ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.SubclassNotOfClass")); +// return; +// } + +// for(var feature of this.actor.items.filter(x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.subclass.id)){ +// await feature.delete(); +// } +// } + +// const features = [itemData.system.foundationFeature, itemData.system.specializationFeature, itemData.system.masteryFeature]; +// for(var i = 0; i < features.length; i++){ +// const feature = features[i]; +// for(var ability of feature.abilities){ +// const data = (await fromUuid(ability.uuid)).toObject(); +// if(i > 0 ) data.system.disabled = true; +// data.uuid = itemData.uuid; + +// const abilityData = await this._onDropItemCreate(data); +// ability.uuid = abilityData[0].uuid; + +// createdItems.push(abilityData); +// } +// } +// } +// else if(item.type === 'class'){ +// if(!item.system.multiclass){ +// for(var feature of this.actor.items.filter(x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.class.id)){ +// await feature.delete(); +// } +// } + +// for(var feature of item.system.features){ +// const data = (await fromUuid(feature.uuid)).toObject(); +// const itemData = await this._onDropItemCreate(data); +// createdItems.push(itemData); +// } +// } +// else if(item.type === 'ancestry'){ +// for(var feature of this.actor.items.filter(x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.ancestry.id)){ +// await feature.delete(); +// } + +// for(var feature of item.system.abilities){ +// const data = (await fromUuid(feature.uuid)).toObject(); +// const itemData = await this._onDropItemCreate(data); +// createdItems.push(itemData); +// } +// } +// else if(item.type === 'community'){ +// for(var feature of this.actor.items.filter(x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.community.id)){ +// await feature.delete(); +// } + +// for(var feature of item.system.abilities){ +// const data = (await fromUuid(feature.uuid)).toObject(); +// const itemData = await this._onDropItemCreate(data); +// createdItems.push(itemData); +// } +// } + +// if ( this.actor.uuid === item.parent?.uuid ) return this._onSortItem(event, item); + +// if(item.type === 'weapon'){ +// if(!element) return; + +// if(element.classList.contains('weapon-section')){ +// if(item.system.secondary && this.actor.system.activeWeapons.burden === 'twoHanded'){ +// ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.SecondaryEquipWhileTwohanded")); +// return; +// } +// else if(item.system.burden === 'twoHanded' && this.actor.system.activeWeapons.secondary){ +// ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.TwohandedEquipWhileSecondary")); +// return; +// } + +// const existing = this.actor.system.activeWeapons.primary && !item.system.secondary ? await fromUuid(this.actor.system.activeWeapons.primary.uuid) : +// this.actor.system.activeWeapons.secondary && item.system.secondary ? await fromUuid(this.actor.system.activeWeapons.secondary.uuid) : null; +// await existing?.delete(); +// itemData.system.active = true; +// } +// else if(element.classList.contains('inventory-weapon-section-first')){ +// const existing = this.actor.system.inventoryWeapons.first ? await fromUuid(this.actor.system.inventoryWeapons.first.uuid) : null; +// await existing?.delete(); + +// itemData.system.inventoryWeapon = 1; +// } +// else if(element.classList.contains('inventory-weapon-section-second')){ +// const existing = this.actor.system.inventoryWeapons.second ? await fromUuid(this.actor.system.inventoryWeapons.second.uuid) : null; +// await existing?.delete(); + +// itemData.system.inventoryWeapon = 2; +// } +// else return []; +// } + +// if(item.type === 'armor'){ +// if(!element) return; + +// if(element.classList.contains('armor-section')){ +// const existing = this.actor.system.armor ? await fromUuid(this.actor.system.armor.uuid) : null; +// await existing?.delete(); +// } + +// else return; +// } + +// const createdItem = await this._onDropItemCreate(itemData); +// createdItems.push(createdItem); + +// return createdItems; +// } +// } + +// async emulateItemDrop(data) { +// const event = new DragEvent("drop", { altKey: game.keyboard.isModifierActive("Alt") }); +// return this._onDropItem(event, data); +// } +// } \ No newline at end of file diff --git a/module/applications/sheets/subclass.mjs b/module/applications/sheets/subclass.mjs new file mode 100644 index 00000000..0608b2f8 --- /dev/null +++ b/module/applications/sheets/subclass.mjs @@ -0,0 +1,168 @@ +// import DhpApplicationMixin from '../daggerheart-sheet.mjs'; + +// export default class SubclassSheet extends DhpApplicationMixin(ItemSheet) { +// static documentType = "subclass"; + +// constructor(options){ +// super(options); +// } + +// static get defaultOptions() { +// return foundry.utils.mergeObject(super.defaultOptions, { +// classes: ["daggerheart", "sheet", "subclass"], +// width: 600, +// height: 720, +// tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "general" }], +// dragDrop: [ +// { dragSelector: null, dropSelector: '.foundation-tab' }, +// { dragSelector: null, dropSelector: '.specialization-tab' }, +// { dragSelector: null, dropSelector: '.mastery-tab' } +// ], +// }); +// } + +// getData() { +// const context = super.getData(); +// context.config = CONFIG.daggerheart; + +// return context; +// } + +// async _handleAction(action, event, button) { +// switch(action){ +// case "editAbility": +// this.editAbility(button); +// break; +// case "deleteFeatureAbility": +// this.deleteFeatureAbility(event); +// break; +// } +// } + +// async editAbility(button){ +// const feature = await fromUuid(button.dataset.ability); +// feature.sheet.render(true); +// } + +// async deleteFeatureAbility(event){ +// event.preventDefault(); +// event.stopPropagation(); + +// const feature = event.currentTarget.dataset.feature; +// const newAbilities = this.item.system[`${feature}Feature`].abilities.filter(x => x.uuid !== event.currentTarget.dataset.ability); +// const path = `system.${feature}Feature.abilities`; + +// await this.item.update({ [path]: newAbilities }); +// } + +// async _onDrop(event) { +// const data = TextEditor.getDragEventData(event); +// const item = await fromUuid(data.uuid); +// if(item.type === 'feature' && item.system.type === SYSTEM.ITEM.featureTypes.subclass.id) { +// if(event.currentTarget.classList.contains('foundation-tab')){ +// await this.object.update({ "system.foundationFeature.abilities": [...this.item.system.foundationFeature.abilities, { img: item.img, name: item.name, uuid: item.uuid }] }); +// } +// else if(event.currentTarget.classList.contains('specialization-tab')){ +// await this.object.update({ "system.specializationFeature.abilities": [...this.item.system.specializationFeature.abilities, { img: item.img, name: item.name, uuid: item.uuid }] }); +// } +// else if(event.currentTarget.classList.contains('mastery-tab')){ +// await this.object.update({ "system.masteryFeature.abilities": [...this.item.system.masteryFeature.abilities, { img: item.img, name: item.name, uuid: item.uuid }] }); +// } +// } +// } +// } + +import DaggerheartSheet from './daggerheart-sheet.mjs'; +import DaggerheartFeature from '../../data/feature.mjs'; + +const { ItemSheetV2 } = foundry.applications.sheets; +export default class SubclassSheet extends DaggerheartSheet(ItemSheetV2) { + static DEFAULT_OPTIONS = { + tag: 'form', + id: "daggerheart-subclass", + classes: ["daggerheart", "sheet", "subclass"], + position: { width: 600 }, + actions: { + editAbility: this.editAbility, + deleteFeatureAbility: this.deleteFeatureAbility, + }, + form: { + handler: this.updateForm, + submitOnChange: true, + closeOnSubmit: false, + }, + dragDrop: [ + { dragSelector: null, dropSelector: '.foundation-tab' }, + { dragSelector: null, dropSelector: '.specialization-tab' }, + { dragSelector: null, dropSelector: '.mastery-tab' } + ], + }; + + _getTabs() { + const tabs = { + general: { active: true, cssClass: '', group: 'primary', id: 'general', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.Subclass.Tabs.General') }, + foundation: { active: false, cssClass: '', group: 'primary', id: 'foundation', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.Subclass.Tabs.Foundation') }, + specialization: { active: false, cssClass: '', group: 'primary', id: 'specialization', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.Subclass.Tabs.Specialization') }, + mastery: { active: false, cssClass: '', group: 'primary', id: 'mastery', icon: null, label: game.i18n.localize('DAGGERHEART.Sheets.Subclass.Tabs.Mastery') }, + } + for ( const v of Object.values(tabs) ) { + v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active; + v.cssClass = v.active ? "active" : ""; + } + + return tabs; + } + + static PARTS = { + form: { + id: "feature", + template: "systems/daggerheart/templates/sheets/subclass.hbs" + } + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.document = this.document; + context.config = CONFIG.daggerheart; + context.tabs = this._getTabs(); + + return context; + } + + static async updateForm(event, _, formData) { + await this.document.update(formData.object) + this.render(); + } + + static async editAbility(_, button){ + const feature = await fromUuid(button.dataset.ability); + feature.sheet.render(true); + } + + static async deleteFeatureAbility(event, button){ + event.preventDefault(); + event.stopPropagation(); + + const feature = button.dataset.feature; + const newAbilities = this.document.system[`${feature}Feature`].abilities.filter(x => x.uuid !== button.dataset.ability); + const path = `system.${feature}Feature.abilities`; + + await this.document.update({ [path]: newAbilities }); + } + + async _onDrop(event) { + const data = TextEditor.getDragEventData(event); + const item = await fromUuid(data.uuid); + if(item.type === 'feature' && item.system.type === SYSTEM.ITEM.featureTypes.subclass.id) { + if(event.currentTarget.classList.contains('foundation-tab')){ + await this.document.update({ "system.foundationFeature.abilities": [...this.document.system.foundationFeature.abilities, item.system] }); + } + else if(event.currentTarget.classList.contains('specialization-tab')){ + await this.document.update({ "system.specializationFeature.abilities": [...this.document.system.specializationFeature.abilities, data.system] }); + } + else if(event.currentTarget.classList.contains('mastery-tab')){ + await this.document.update({ "system.masteryFeature.abilities": [...this.document.system.masteryFeature.abilities, data.system] }); + } + } + } +} \ No newline at end of file diff --git a/module/applications/sheets/weapon.mjs b/module/applications/sheets/weapon.mjs new file mode 100644 index 00000000..16470595 --- /dev/null +++ b/module/applications/sheets/weapon.mjs @@ -0,0 +1,65 @@ +// import DhpApplicationMixin from '../daggerheart-sheet.mjs'; + +// export default class WeaponSheet extends DhpApplicationMixin(ItemSheet) { +// static documentType = "weapon"; + +// /** @override */ +// static get defaultOptions() { +// return foundry.utils.mergeObject(super.defaultOptions, { +// classes: ["daggerheart", "sheet", "weapon"], +// width: 400, +// height: 'auto', +// }); +// } + +// /** @override */ +// getData() { +// const context = super.getData(); +// context.config = CONFIG.daggerheart; + +// return context; +// } + + +// async _handleAction(action, event, button) { +// switch(action){ +// } +// } +// } + +import DaggerheartSheet from './daggerheart-sheet.mjs'; + +const { ItemSheetV2 } = foundry.applications.sheets; +export default class WeaponSheet extends DaggerheartSheet(ItemSheetV2) { + static DEFAULT_OPTIONS = { + tag: 'form', + id: "daggerheart-weapon", + classes: ["daggerheart", "sheet", "weapon"], + position: { width: 400 }, + form: { + handler: this.updateForm, + submitOnChange: true, + closeOnSubmit: false, + }, + }; + + static PARTS = { + form: { + id: "feature", + template: "systems/daggerheart/templates/sheets/weapon.hbs" + } + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.document = this.document; + context.config = CONFIG.daggerheart; + + return context; + } + + static async updateForm(event, _, formData) { + await this.document.update(formData.object) + this.render(); + } +} \ No newline at end of file diff --git a/module/config/actionConfig.mjs b/module/config/actionConfig.mjs new file mode 100644 index 00000000..f77affca --- /dev/null +++ b/module/config/actionConfig.mjs @@ -0,0 +1,17 @@ +export const actionTypes = { + damage: { + id: "damage", + name: "DAGGERHEART.Effects.Types.Health.Name" + }, +} + +export const targetTypes = { + self: { + id: 'self', + label: 'Self', + }, + other: { + id: 'other', + label: 'Other', + }, +} \ No newline at end of file diff --git a/module/config/actorConfig.mjs b/module/config/actorConfig.mjs new file mode 100644 index 00000000..b73da269 --- /dev/null +++ b/module/config/actorConfig.mjs @@ -0,0 +1,355 @@ +export const abilities = { + agility: { + label: "DAGGERHEART.Abilities.Agility.Name", + verbs: ["DAGGERHEART.Abilities.Agility.Verb.Sprint", "DAGGERHEART.Abilities.Agility.Verb.Leap", "DAGGERHEART.Abilities.Agility.Verb.Maneuver"], + }, + strength: { + label: "DAGGERHEART.Abilities.Strength.Name", + verbs: ["DAGGERHEART.Abilities.Strength.Verb.Lift", "DAGGERHEART.Abilities.Strength.Verb.Smash", "DAGGERHEART.Abilities.Strength.Verb.Grapple"], + }, + finesse: { + label: "DAGGERHEART.Abilities.Finesse.Name", + verbs: ["DAGGERHEART.Abilities.Finesse.Verb.Control", "DAGGERHEART.Abilities.Finesse.Verb.Hide", "DAGGERHEART.Abilities.Finesse.Verb.Tinker"], + }, + instinct: { + label: "DAGGERHEART.Abilities.Instinct.Name", + verbs: ["DAGGERHEART.Abilities.Instinct.Verb.Perceive", "DAGGERHEART.Abilities.Instinct.Verb.Sense", "DAGGERHEART.Abilities.Instinct.Verb.Navigate"], + }, + presence: { + label: "DAGGERHEART.Abilities.Presence.Name", + verbs: ["DAGGERHEART.Abilities.Presence.Verb.Charm", "DAGGERHEART.Abilities.Presence.Verb.Perform", "DAGGERHEART.Abilities.Presence.Verb.Deceive"], + }, + knowledge: { + label: "DAGGERHEART.Abilities.Knowledge.Name", + verbs: ["DAGGERHEART.Abilities.Knowledge.Verb.Recall", "DAGGERHEART.Abilities.Knowledge.Verb.Analyze", "DAGGERHEART.Abilities.Knowledge.Verb.Comprehend"], + }, +}; + +export const featureProperties = { + agility: { + name: "DAGGERHEART.Abilities.Agility.Name", + path: actor => actor.system.attributes.agility.data.value, + }, + strength: { + name: "DAGGERHEART.Abilities.Strength.Name", + path: actor => actor.system.attributes.strength.data.value, + }, + finesse: { + name: "DAGGERHEART.Abilities.Finesse.Name", + path: actor => actor.system.attributes.finesse.data.value, + }, + instinct: { + name: "DAGGERHEART.Abilities.Instinct.Name", + path: actor => actor.system.attributes.instinct.data.value, + }, + presence: { + name: "DAGGERHEART.Abilities.Presence.Name", + path: actor => actor.system.attributes.presence.data.value, + }, + knowledge: { + name: "DAGGERHEART.Abilities.Knowledge.Name", + path: actor => actor.system.attributes.knowledge.data.value, + }, + spellcastingTrait: { + name: "DAGGERHEART.FeatureProperty.SpellcastingTrait", + path: actor => actor.system.attributes[actor.system.subclass.system.spellcastingTrait].data.value, + }, +} + +export const adversaryTypes = { + bruiser: { + name: "DAGGERHEART.Adversary.Bruiser.Name", + description: "DAGGERHEART.Adversary.Bruiser.Description" + }, + horde: { + name: "DAGGERHEART.Adversary.Horde.Name", + description: "DAGGERHEART.Adversary.Horde.Description" + }, + leader: { + name: "DAGGERHEART.Adversary.Leader.Name", + description: "DAGGERHEART.Adversary.Leader.Description" + }, + minion: { + name: "DAGGERHEART.Adversary.Minion.Name", + description: "DAGGERHEART.Adversary.Minion.Description" + }, + ranged: { + name: "DAGGERHEART.Adversary.Ranged.Name", + description: "DAGGERHEART.Adversary.Ranged.Description" + }, + skulker: { + name: "DAGGERHEART.Adversary.Skulker.Name", + description: "DAGGERHEART.Adversary.Skulker.Description" + }, + social: { + name: "DAGGERHEART.Adversary.Social.Name", + description: "DAGGERHEART.Adversary.Social.Description" + }, + solo: { + name: "DAGGERHEART.Adversary.Solo.Name", + description: "DAGGERHEART.Adversary.Solo.Description" + }, + standard: { + name: "DAGGERHEART.Adversary.Standard.Name", + description: "DAGGERHEART.Adversary.Standard.Description" + }, + support: { + name: "DAGGERHEART.Adversary.Support.Name", + description: "DAGGERHEART.Adversary.Support.Description" + }, +}; + +export const adversaryTraits = { + relentless: { + name: "DAGGERHEART.Adversary.Trait..Name", + description: "DAGGERHEART.Adversary.Trait..Description", + tip: "DAGGERHEART.Adversary.Trait..Tip", + }, + slow: { + name: "DAGGERHEART.Adversary.Trait..Name", + description: "DAGGERHEART.Adversary.Trait..Description", + tip: "DAGGERHEART.Adversary.Trait..Tip", + }, + minion: { + name: "DAGGERHEART.Adversary.Trait..Name", + description: "DAGGERHEART.Adversary.Trait..Description", + tip: "DAGGERHEART.Adversary.Trait..Tip", + }, +}; + +export const levelChoices = { + attributes: { + name: 'attributes', + title: '', + choices: [], + }, + hitPointSlots: { + name: 'hitPointSlots', + title: '', + choices: [], + }, + stressSlots: { + name: 'stressSlots', + title: '', + choices: [], + }, + experiences: { + name: 'experiences', + title: '', + choices: 'system.experiences', + nrChoices: 2, + }, + proficiency: { + name: 'proficiency', + title: '', + choices: [], + }, + armorOrEvasionSlot: { + name: 'armorOrEvasionSlot', + title: 'Permanently add one Armor Slot or take +1 to your Evasion', + choices: [{ name: 'Armor Marks +1', path: 'armor' }, { name: 'Evasion +1', path: 'evasion' }], + nrChoices: 1, + }, + majorDamageThreshold2: { + name: 'majorDamageThreshold2', + title: '', + choices: [], + }, + severeDamageThreshold2: { + name: 'severeDamageThreshold2', + title: '', + choices: [], + }, + // minorDamageThreshold2: { + // name: 'minorDamageThreshold2', + // title: '', + // choices: [], + // }, + severeDamageThreshold3: { + name: 'severeDamageThreshold3', + title: '', + choices: [], + }, + // major2OrSevere4DamageThreshold: { + // name: 'major2OrSevere4DamageThreshold', + // title: 'Increase your Major Damage Threshold by +2 or Severe Damage Threshold by +4', + // choices: [{ name: 'Major Damage Threshold +2', path: 'major' }, { name: 'Severe Damage Threshold +4', path: 'severe' }], + // nrChoices: 1, + // }, + // minor1OrMajor1DamageThreshold: { + // name: 'minor1OrMajor1DamageThreshold', + // title: 'Increase your Minor or Major Damage Threshold by +1', + // choices: [{ name: 'Minor Damage Threshold +1', path: 'minor' }, { name: 'Major Damage Threshold +1', path: 'major' }], + // nrChoices: 1, + // }, + severeDamageThreshold4: { + name: 'severeDamageThreshold4', + title: '', + choices: [], + }, + // majorDamageThreshold1: { + // name: 'majorDamageThreshold2', + // title: '', + // choices: [], + // }, + subclass: { + name: 'subclass', + title: 'Select subclass to upgrade', + choices: [], + }, + multiclass: { + name: 'multiclass', + title: '', + choices: [{}], + } +}; + +export const levelupData = { + tier1: { + id: "2_4", + tier: 1, + levels: [2,3,4], + label: 'DAGGERHEART.LevelUp.Tier1.Label', + info: "DAGGERHEART.LevelUp.Tier1.InfoLabel", + pretext: "DAGGERHEART.LevelUp.Tier1.Pretext", + posttext: "DAGGERHEART.LevelUp.Tier1.Posttext", + choices: { + [levelChoices.attributes.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Attributes", + maxChoices: 3, + }, + [levelChoices.hitPointSlots.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.HitPointSlots", + maxChoices: 1, + }, + [levelChoices.stressSlots.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.StressSlots", + maxChoices: 1, + }, + [levelChoices.experiences.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Experiences", + maxChoices: 1, + }, + [levelChoices.proficiency.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Proficiency", + maxChoices: 1, + }, + [levelChoices.armorOrEvasionSlot.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.ArmorOrEvasionSlot", + maxChoices: 1, + }, + [levelChoices.majorDamageThreshold2.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.MajorDamageThreshold2", + maxChoices: 1, + }, + [levelChoices.severeDamageThreshold2.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.SevereDamageThreshold2", + maxChoices: 1, + } + } + }, + tier2: { + id: "5_7", + tier: 2, + levels: [5,6,7], + label: 'DAGGERHEART.LevelUp.Tier2.Label', + info: "DAGGERHEART.LevelUp.Tier2.InfoLabel", + pretext: "DAGGERHEART.LevelUp.Tier2.Pretext", + posttext: "DAGGERHEART.LevelUp.Tier2.Posttext", + choices: { + [levelChoices.attributes.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Attributes", + maxChoices: 3, + }, + [levelChoices.hitPointSlots.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.HitPointSlots", + maxChoices: 2, + }, + [levelChoices.stressSlots.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.StressSlots", + maxChoices: 2, + }, + [levelChoices.experiences.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Experiences", + maxChoices: 1, + }, + [levelChoices.proficiency.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Proficiency", + maxChoices: 2, + }, + [levelChoices.armorOrEvasionSlot.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.ArmorOrEvasionSlot", + maxChoices: 2, + }, + [levelChoices.majorDamageThreshold2.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.MajorDamageThreshold2", + maxChoices: 1, + }, + [levelChoices.severeDamageThreshold3.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.SevereDamageThreshold3", + maxChoices: 1, + }, + [levelChoices.subclass.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Subclass", + maxChoices: 1, + }, + [levelChoices.multiclass.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Multiclass", + maxChoices: 1, + cost: 2, + }, + }, + }, + tier3: { + id: "8_10", + tier: 3, + levels: [8,9,10], + label: 'DAGGERHEART.LevelUp.Tier3.Label', + info: "DAGGERHEART.LevelUp.Tier3.InfoLabel", + pretext: "DAGGERHEART.LevelUp.Tier3.Pretext", + posttext: "DAGGERHEART.LevelUp.Tier3.Posttext", + choices: { + [levelChoices.attributes.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Attributes", + maxChoices: 3, + }, + [levelChoices.hitPointSlots.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.HitPointSlots", + maxChoices: 2, + }, + [levelChoices.stressSlots.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.StressSlots", + maxChoices: 2, + }, + [levelChoices.experiences.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Experiences", + maxChoices: 1, + }, + [levelChoices.proficiency.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Proficiency", + maxChoices: 2, + }, + [levelChoices.armorOrEvasionSlot.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.ArmorOrEvasionSlot", + maxChoices: 2, + }, + [levelChoices.majorDamageThreshold2.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.MajorDamageThreshold2", + maxChoices: 1, + }, + [levelChoices.severeDamageThreshold4.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.SevereDamageThreshold4", + maxChoices: 1, + }, + [levelChoices.subclass.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Subclass", + maxChoices: 1, + }, + [levelChoices.multiclass.name]: { + description: "DAGGERHEART.LevelUp.ChoiceDescriptions.Multiclass", + maxChoices: 1, + cost: 2, + }, + }, + } +}; \ No newline at end of file diff --git a/module/config/domainConfig.mjs b/module/config/domainConfig.mjs new file mode 100644 index 00000000..289f1243 --- /dev/null +++ b/module/config/domainConfig.mjs @@ -0,0 +1,101 @@ +export const domains = { + arcana: { + id: 'arcana', + label: 'Arcana', + src: 'icons/magic/symbols/circled-gem-pink.webp', + description: 'DAGGERHEART.Domains.Arcana', + }, + blade: { + id: 'blade', + label: 'Blade', + src: 'icons/weapons/swords/sword-broad-crystal-paired.webp', + description: 'DAGGERHEART.Domains.Blade', + }, + bone: { + id: 'bone', + label: 'Bone', + src: 'icons/skills/wounds/bone-broken-marrow-red.webp', + description: 'DAGGERHEART.Domains.Bone', + }, + codex: { + id: 'codex', + label: 'Codex', + src: 'icons/sundries/books/book-embossed-jewel-gold-purple.webp', + description: 'DAGGERHEART.Domains.Codex', + }, + grace: { + id: 'grace', + label: 'Grace', + src: 'icons/skills/movement/feet-winged-boots-glowing-yellow.webp', + description: 'DAGGERHEART.Domains.Grace', + }, + midnight: { + id: 'midnight', + label: 'Midnight', + src: 'icons/environment/settlement/watchtower-castle-night.webp', + background: 'systems/daggerheart/assets/backgrounds/MidnightBackground.webp', + description: 'DAGGERHEART.Domains.Midnight', + }, + sage: { + id: 'sage', + label: 'Sage', + src: 'icons/sundries/misc/pipe-wooden-straight-brown.webp', + description: 'DAGGERHEART.Domains.Sage', + }, + splendor: { + id: 'splendor', + label: 'Splendor', + src: 'icons/magic/control/control-influence-crown-gold.webp', + description: 'DAGGERHEART.Domains.Splendor', + }, + valor: { + id: 'valor', + label: 'Valor', + src: 'icons/magic/control/control-influence-rally-purple.webp', + description: 'DAGGERHEART.Domains.Valor', + }, +}; + +export const classDomainMap = { + rogue: [domains.midnight, domains.grace], +}; + +export const subclassMap = { + syndicate: { + id: 'syndicate', + label: 'Syndicate', + }, + nightwalker: { + id: 'nightwalker', + label: 'Nightwalker', + }, +}; + +export const classMap = { + rogue: { + label: "Rogue", + subclasses: [subclassMap.syndicate.id, subclassMap.nightwalker.id], + }, + seraph: { + label: "Seraph", + subclasses: [] + }, +}; + +export const cardTypes = { + ability: { + id: 'ability', + label: "DAGGERHEART.Domain.CardTypes.Ability", + img: "", + }, + spell: { + id: 'spell', + label: "DAGGERHEART.Domain.CardTypes.Spell", + img: "" + }, + grimoire: { + id: 'grimoire', + label: "DAGGERHEART.Domain.CardTypes.Grimoire", + img: "" + } +}; \ No newline at end of file diff --git a/module/config/effectConfig.mjs b/module/config/effectConfig.mjs new file mode 100644 index 00000000..e7a097a2 --- /dev/null +++ b/module/config/effectConfig.mjs @@ -0,0 +1,64 @@ +import { range } from "./generalConfig.mjs"; + +export const valueTypes = { + numberString: { + id: 'numberString', + }, + select: { + id: 'select', + } +} + +export const parseTypes = { + string: { + id: 'string', + }, + number: { + id: 'number', + }, +} + +export const applyLocations = { + attackRoll: { + id: 'attackRoll', + name: "DAGGERHEART.Effects.ApplyLocations.AttackRoll.Name", + }, + damageRoll: { + id: 'damageRoll', + name: "DAGGERHEART.Effects.ApplyLocations.DamageRoll.Name", + } +}; + +export const effectTypes = { + health: { + id: "health", + name: "DAGGERHEART.Effects.Types.Health.Name", + values: [], + valueType: valueTypes.numberString.id, + parseType: parseTypes.number.id, + }, + stress: { + id: "stress", + name: "DAGGERHEART.Effects.Types.Stress.Name", + valueType: valueTypes.numberString.id, + parseType: parseTypes.number.id, + }, + reach: { + id: "reach", + name: "DAGGERHEART.Effects.Types.Reach.Name", + valueType: valueTypes.select.id, + parseType: parseTypes.string.id, + options: Object.keys(range).map(x => ({ name: range[x].name, value: x })) + }, + damage: { + id: "damage", + name: "DAGGERHEART.Effects.Types.Damage.Name", + valueType: valueTypes.numberString.id, + parseType: parseTypes.string.id, + appliesOn: applyLocations.damageRoll.id, + applyLocationChoices: { + [applyLocations.damageRoll.id]: applyLocations.damageRoll.name, + [applyLocations.attackRoll.id]: applyLocations.attackRoll.name, + }, + } +}; \ No newline at end of file diff --git a/module/config/generalConfig.mjs b/module/config/generalConfig.mjs new file mode 100644 index 00000000..fa4277f2 --- /dev/null +++ b/module/config/generalConfig.mjs @@ -0,0 +1,268 @@ +export const range = { + melee: { + label: "DAGGERHEART.Range.Melee.Name", + description: "DAGGERHEART.Range.Melee.Description", + distance: 1 + }, + veryClose: { + label: "DAGGERHEART.Range.VeryClose.Name", + description: "DAGGERHEART.Range.VeryClose.Description", + distance: 3 + }, + close: { + label: "DAGGERHEART.Range.Close.Name", + description: "DAGGERHEART.Range.Close.Description", + distance: 10 + }, + far: { + label: "DAGGERHEART.Range.Far.Name", + description: "DAGGERHEART.Range.Far.Description", + distance: 20 + }, + veryFar: { + label: "DAGGERHEART.Range.VeryFar.Name", + description: "DAGGERHEART.Range.VeryFar.Description", + distance: 30 + } +} + +export const burden = { + oneHanded: "DAGGERHEART.Burden.OneHanded", + twoHanded: "DAGGERHEART.Burden.TwoHanded" +} + +export const damageTypes = { + physical: { + id: 'physical', + label: "DAGGERHEART.DamageType.Physical.Name", + abbreviation: "DAGGERHEART.DamageType.Physical.Abbreviation", + }, + magical: { + id: 'magical', + label: "DAGGERHEART.DamageType.Magical.Name", + abbreviation: "DAGGERHEART.DamageType.Magical.Abbreviation", + }, +} + +export const healingTypes = { + health: { + id: 'health', + label: "DAGGERHEART.HealingType.HitPoints.Name", + abbreviation: "DAGGERHEART.HealingType.HitPoints.Abbreviation" + }, + stress: { + id: 'stress', + label: "DAGGERHEART.HealingType.Stress.Name", + abbreviation: "DAGGERHEART.HealingType.Stress.Abbreviation" + }, +}; + +export const conditions = { + vulnerable: { + id: 'vulnerable', + name: "DAGGERHEART.Condition.Vulnerable.Name", + icon: "icons/magic/control/silhouette-fall-slip-prone.webp", + description: "DAGGERHEART.Condition.Vulnerable.Description" + }, + hidden: { + id: 'hidden', + name: "DAGGERHEART.Condition.Hidden.Name", + icon: "icons/magic/perception/silhouette-stealth-shadow.webp", + description: "DAGGERHEART.Condition.Hidden.Description" + }, + restrained: { + id: 'restrained', + name: "DAGGERHEART.Condition.Restrained.Name", + icon: "icons/magic/control/debuff-chains-shackle-movement-red.webp", + description: "DAGGERHEART.Condition.Restrained.Description" + }, +} + +export const downtime = { + shortRest: { + tendToWounds: { + id: "tendToWounds", + name: "DAGGERHEART.Downtime.TendToWounds.Name", + img: "icons/magic/life/cross-worn-green.webp", + description: "DAGGERHEART.Downtime.TendToWounds.Description", + }, + clearStress: { + id: "clearStress", + name: "DAGGERHEART.Downtime.ClearStress.Name", + img: "icons/magic/perception/eye-ringed-green.webp", + description: "DAGGERHEART.Downtime.ClearStress.Description", + }, + repairArmor: { + id: "repairArmor", + name: "DAGGERHEART.Downtime.RepairArmor.Name", + img: "icons/skills/trades/smithing-anvil-silver-red.webp", + description: "DAGGERHEART.Downtime.RepairArmor.Description", + }, + prepare: { + id: "prepare", + name: "DAGGERHEART.Downtime.Prepare.Name", + img: "icons/skills/trades/academics-merchant-scribe.webp", + description: "DAGGERHEART.Downtime.Prepare.Description", + }, + }, + longRest: { + tendToWounds: { + id: "tendToWounds", + name: "DAGGERHEART.Downtime.TendToWounds.Name", + img: "icons/magic/life/cross-worn-green.webp", + description: "DAGGERHEART.Downtime.TendToWounds.Description", + }, + clearStress: { + id: "clearStress", + name: "DAGGERHEART.Downtime.ClearStress.Name", + img: "icons/magic/perception/eye-ringed-green.webp", + description: "DAGGERHEART.Downtime.ClearStress.Description", + }, + repairArmor: { + id: "repairArmor", + name: "DAGGERHEART.Downtime.RepairArmor.Name", + img: "icons/skills/trades/smithing-anvil-silver-red.webp", + description: "DAGGERHEART.Downtime.RepairArmor.Description", + }, + prepare: { + id: "prepare", + name: "DAGGERHEART.Downtime.Prepare.Name", + img: "icons/skills/trades/academics-merchant-scribe.webp", + description: "DAGGERHEART.Downtime.Prepare.Description", + }, + workOnAProject: { + id: "workOnAProject", + name: "DAGGERHEART.Downtime.WorkOnAProject.Name", + img: "icons/skills/social/thumbsup-approval-like.webp", + description: "DAGGERHEART.Downtime.WorkOnAProject.Description", + } + }, + custom: { + id: 'customActivity', + name: "", + img: "icons/skills/trades/academics-investigation-puzzles.webp", + description: "", + namePlaceholder: "DAGGERHEART.Downtime.Custom.NamePlaceholder", + placeholder: "DAGGERHEART.Downtime.Custom.Placeholder", + } +} + +export const deathMoves = { + avoidDeath: { + id: "avoidDeath", + name: "DAGGERHEART.DeathMoves.AvoidDeath.Name", + img: "icons/magic/time/hourglass-yellow-green.webp", + description: "DAGGERHEART.DeathMoves.AvoidDeath.Description", + }, + riskItAll: { + id: 'riskItAll', + name: "DAGGERHEART.DeathMoves.RiskItAll.Name", + img: "icons/sundries/gaming/dice-pair-white-green.webp", + description: "DAGGERHEART.DeathMoves.RiskItAll.Description", + }, + blazeOfGlory: { + id: "blazeOfGlory", + name: "DAGGERHEART.DeathMoves.BlazeOfGlory.Name", + img: "icons/magic/life/heart-cross-strong-flame-purple-orange.webp", + description: "DAGGERHEART.DeathMoves.BlazeOfGlory.Description", + } +}; + +export const tiers = { + 0: { + key: 0, + id: 'tier0', + name: 'DAGGERHEART.General.Tier.0', + }, + 1: { + key: 1, + id: 'tier1', + name: 'DAGGERHEART.General.Tier.1', + }, + 2: { + key: 2, + id: 'tier2', + name: 'DAGGERHEART.General.Tier.2', + }, + 3: { + key: 3, + id: 'tier3', + name: 'DAGGERHEART.General.Tier.3', + } +}; + +export const objectTypes = { + pc: { + name: "TYPES.Actor.pc", + }, + npc: { + name: "TYPES.Actor.npc", + }, + adversary: { + name: "TYPES.Actor.adversary", + }, + ancestry: { + name: "TYPES.Item.ancestry", + }, + community: { + name: "TYPES.Item.community", + }, + class: { + name: "TYPES.Item.class", + }, + subclass: { + name: "TYPES.Item.subclass", + }, + feature: { + name: "TYPES.Item.feature", + }, + domainCard: { + name: "TYPES.Item.domainCard", + }, + consumable: { + name: "TYPES.Item.consumable", + }, + miscellaneous: { + name: "TYPES.Item.miscellaneous", + }, + weapon: { + name: "TYPES.Item.weapon", + }, + armor: { + name: "TYPES.Item.armor", + } +}; + +export const diceTypes = { + d4: "d4", + d6: "d6", + d8: "d8", + d12: "d12", + d20: "d20" +}; + +export const refreshTypes = { + session: { + id: 'session', + label: "DAGGERHEART.General.RefreshType.Session" + }, + shortRest: { + id: 'shortRest', + label: "DAGGERHEART.General.RefreshType.Shortrest", + }, + longRest: { + id: 'longRest', + label: "DAGGERHEART.General.RefreshType.Longrest" + } +} + +export const abilityCosts = { + hope: { + id: 'hope', + label: 'Hope', + }, + stress: { + id: 'stress', + label: 'Stress', + } +} \ No newline at end of file diff --git a/module/config/itemConfig.mjs b/module/config/itemConfig.mjs new file mode 100644 index 00000000..4fb9313c --- /dev/null +++ b/module/config/itemConfig.mjs @@ -0,0 +1,351 @@ +export const armorFeatures = { + light: { + label: "DAGGERHEART.ArmorFeature.Light.Name", + description: "DAGGERHEART.ArmorFeature.Light.Description", + }, + heavy: { + label: "DAGGERHEART.ArmorFeature.Heavy.Name", + description: "DAGGERHEART.ArmorFeature.Heavy.Description", + }, + veryHeavy: { + label: "DAGGERHEART.ArmorFeature.VeryHeavy.Name", + description: "DAGGERHEART.ArmorFeature.VeryHeavy.Description", + }, + reinforced: { + label: "DAGGERHEART.ArmorFeature.Reinforced.Name", + description: "DAGGERHEART.ArmorFeature.Reinforced.Description", + }, + sturdy: { + label: "DAGGERHEART.ArmorFeature.Sturdy.Name", + description: "DAGGERHEART.ArmorFeature.Sturdy.Description", + }, + warded: { + label: "DAGGERHEART.ArmorFeature.Warded.Name", + description: "DAGGERHEART.ArmorFeature.Warded.Description", + }, + resistant: { + label: "DAGGERHEART.ArmorFeature.Resistant.Name", + description: "DAGGERHEART.ArmorFeature.Resistant.Description", + }, + quiet: { + label: "DAGGERHEART.ArmorFeature.Quiet.Name", + description: "DAGGERHEART.ArmorFeature.Quiet.Description", + }, + hopeful: { + label: "DAGGERHEART.ArmorFeature.Hopeful.Name", + description: "DAGGERHEART.ArmorFeature.Hopeful.Description", + }, + impenetrable: { + label: "DAGGERHEART.ArmorFeature.Impenetrable.Name", + description: "DAGGERHEART.ArmorFeature.Impenetrable.Description", + }, + painful: { + label: "DAGGERHEART.ArmorFeature.Painful.Name", + description: "DAGGERHEART.ArmorFeature.Painful.Description", + }, + gilded: { + label: "DAGGERHEART.ArmorFeature.Gilded.Name", + description: "DAGGERHEART.ArmorFeature.Gilded.Description", + }, + physical: { + label: "DAGGERHEART.ArmorFeature.Physical.Name", + description: "DAGGERHEART.ArmorFeature.Physical.Description", + }, + magic: { + label: "DAGGERHEART.ArmorFeature.Magic.Name", + description: "DAGGERHEART.ArmorFeature.Magic.Description", + }, + sharp: { + label: "DAGGERHEART.ArmorFeature.Sharp.Name", + description: "DAGGERHEART.ArmorFeature.Sharp.Description", + }, + burning: { + label: "DAGGERHEART.ArmorFeature.Burning.Name", + description: "DAGGERHEART.ArmorFeature.Burning.Description", + }, + timeslowing: { + label: "DAGGERHEART.ArmorFeature.Timeslowing.Name", + description: "DAGGERHEART.ArmorFeature.Timeslowing.Description", + }, + truthseeking: { + label: "DAGGERHEART.ArmorFeature.Truthseeking.Name", + description: "DAGGERHEART.ArmorFeature.Truthseeking.Description", + }, + channeling: { + label: "DAGGERHEART.ArmorFeature.Channeling.Name", + description: "DAGGERHEART.ArmorFeature.Channeling.Description", + }, + difficult: { + label: "DAGGERHEART.ArmorFeature.Difficult.Name", + description: "DAGGERHEART.ArmorFeature.Difficult.Description", + }, + variable: { + label: "DAGGERHEART.ArmorFeature.Variable.Name", + description: "DAGGERHEART.ArmorFeature.Variable.Description", + }, +}; + +export const weaponFeatures = { + light: { + label: "DAGGERHEART.WeaponFeature.Light.Name", + description: "DAGGERHEART.WeaponFeature.Light.Description", + }, + heavy: { + label: "DAGGERHEART.WeaponFeature.Heavy.Name", + description: "DAGGERHEART.WeaponFeature.Heavy.Description", + }, + massive: { + label: "DAGGERHEART.WeaponFeature.Massive.Name", + description: "DAGGERHEART.WeaponFeature.Massive.Description", + }, + reliable: { + label: "DAGGERHEART.WeaponFeature.Reliable.Name", + description: "DAGGERHEART.WeaponFeature.Reliable.Description", + }, + quick: { + label: "DAGGERHEART.WeaponFeature.Quick.Name", + description: "DAGGERHEART.WeaponFeature.Quick.Description", + }, + cumbersome: { + label: "DAGGERHEART.WeaponFeature.Cumbersome.Name", + description: "DAGGERHEART.WeaponFeature.Cumbersome.Description", + }, + versatile: { + label: "DAGGERHEART.WeaponFeature.Versatile.Name", + description: "DAGGERHEART.WeaponFeature.Versatile.Description", + override: { + damage: "", + } + }, + powerful: { + label: "DAGGERHEART.WeaponFeature.Powerful.Name", + description: "DAGGERHEART.WeaponFeature.Powerful.Description", + }, + scary: { + label: "DAGGERHEART.WeaponFeature.Scary.Name", + description: "DAGGERHEART.WeaponFeature.Scary.Description", + }, + brutal: { + label: "DAGGERHEART.WeaponFeature.Brutal.Name", + description: "DAGGERHEART.WeaponFeature.Brutal.Description", + }, + reloading: { + label: "DAGGERHEART.WeaponFeature.Reloading.Name", + description: "DAGGERHEART.WeaponFeature.Reloading.Description", + }, + eruptive: { + label: "DAGGERHEART.WeaponFeature.Eruptive.Name", + description: "DAGGERHEART.WeaponFeature.Eruptive.Description", + }, + persuasive: { + label: "DAGGERHEART.WeaponFeature.Persuasive.Name", + description: "DAGGERHEART.WeaponFeature.Persuasive.Description", + }, + pompous: { + label: "DAGGERHEART.WeaponFeature.Pompous.Name", + description: "DAGGERHEART.WeaponFeature.Pompous.Description", + }, + invigorating: { + label: "DAGGERHEART.WeaponFeature.Invigorating.Name", + description: "DAGGERHEART.WeaponFeature.Invigorating.Description", + }, + dense: { + label: "DAGGERHEART.WeaponFeature.Dense.Name", + description: "DAGGERHEART.WeaponFeature.Dense.Description", + }, + soulswift: { + label: "DAGGERHEART.WeaponFeature.Soulswift.Name", + description: "DAGGERHEART.WeaponFeature.Soulswift.Description", + }, + protective: { + label: "DAGGERHEART.WeaponFeature.Protective.Name", + description: "DAGGERHEART.WeaponFeature.Protective.Description", + }, + devastating: { + label: "DAGGERHEART.WeaponFeature.Devastating.Name", + description: "DAGGERHEART.WeaponFeature.Devastating.Description", + }, + retractable: { + label: "DAGGERHEART.WeaponFeature.Retractable.Name", + description: "DAGGERHEART.WeaponFeature.Retractable.Description", + }, + burn: { + label: "DAGGERHEART.WeaponFeature.Burn.Name", + description: "DAGGERHEART.WeaponFeature.Burn.Description", + }, + painful: { + label: "DAGGERHEART.WeaponFeature.Painful.Name", + description: "DAGGERHEART.WeaponFeature.Painful.Description", + }, + otherwordly: { + label: "DAGGERHEART.WeaponFeature.Otherwordly.Name", + description: "DAGGERHEART.WeaponFeature.Otherwordly.Description", + }, + lucky: { + label: "DAGGERHEART.WeaponFeature.Lucky.Name", + description: "DAGGERHEART.WeaponFeature.Lucky.Description", + }, + selfCorrecting: { + label: "DAGGERHEART.WeaponFeature.SelfCorrecting.Name", + description: "DAGGERHEART.WeaponFeature.SelfCorrecting.Description", + }, + healing: { + label: "DAGGERHEART.WeaponFeature.Healing.Name", + description: "DAGGERHEART.WeaponFeature.Healing.Description", + }, + timebender: { + label: "DAGGERHEART.WeaponFeature.Timebender.Name", + description: "DAGGERHEART.WeaponFeature.Timebender.Description", + }, + enchanted: { + label: "DAGGERHEART.WeaponFeature.Enchanted.Name", + description: "DAGGERHEART.WeaponFeature.Enchanted.Description", + }, + serrated: { + label: "DAGGERHEART.WeaponFeature.Serrated.Name", + description: "DAGGERHEART.WeaponFeature.Serrated.Description", + }, + grappling: { + label: "DAGGERHEART.WeaponFeature.Grappling.Name", + description: "DAGGERHEART.WeaponFeature.Grappling.Description", + }, + long: { + label: "DAGGERHEART.WeaponFeature.Long.Name", + description: "DAGGERHEART.WeaponFeature.Long.Description", + }, + destructive: { + label: "DAGGERHEART.WeaponFeature.Destructive.Name", + description: "DAGGERHEART.WeaponFeature.Destructive.Description", + }, + concussive: { + label: "DAGGERHEART.WeaponFeature.Concussive.Name", + description: "DAGGERHEART.WeaponFeature.Concussive.Description", + }, + bouncing: { + label: "DAGGERHEART.WeaponFeature.Bouncing.Name", + description: "DAGGERHEART.WeaponFeature.Bouncing.Description", + }, + penetrating: { + label: "DAGGERHEART.WeaponFeature.Penetrating.Name", + description: "DAGGERHEART.WeaponFeature.Penetrating.Description", + }, + lifestealing: { + label: "DAGGERHEART.WeaponFeature.Lifestealing.Name", + description: "DAGGERHEART.WeaponFeature.Lifestealing.Description", + }, + greedy: { + label: "DAGGERHEART.WeaponFeature.Greedy.Name", + description: "DAGGERHEART.WeaponFeature.Greedy.Description", + }, + bonded: { + label: "DAGGERHEART.WeaponFeature.Bonded.Name", + description: "DAGGERHEART.WeaponFeature.Bonded.Description", + }, + barrier: { + label: "DAGGERHEART.WeaponFeature.Barrier.Name", + description: "DAGGERHEART.WeaponFeature.Barrier.Description", + }, + paired: { + label: "DAGGERHEART.WeaponFeature.Paired.Name", + description: "DAGGERHEART.WeaponFeature.Paired.Description", + }, + whipcrack: { + label: "DAGGERHEART.WeaponFeature.Whipcrack.Name", + description: "DAGGERHEART.WeaponFeature.Whipcrack.Description", + }, + hook: { + label: "DAGGERHEART.WeaponFeature.Hook.Name", + description: "DAGGERHEART.WeaponFeature.Hook.Description", + }, + doubleDuty: { + label: "DAGGERHEART.WeaponFeature.DoubleDuty.Name", + description: "DAGGERHEART.WeaponFeature.DoubleDuty.Description", + }, + parry: { + label: "DAGGERHEART.WeaponFeature.Parry.Name", + description: "DAGGERHEART.WeaponFeature.Parry.Description", + }, + retrieve: { + label: "DAGGERHEART.WeaponFeature.Retrieve.Name", + description: "DAGGERHEART.WeaponFeature.Retrieve.Description", + }, + deflecting: { + label: "DAGGERHEART.WeaponFeature.Deflecting.Name", + description: "DAGGERHEART.WeaponFeature.Deflecting.Description", + }, + chargedAttack: { + label: "DAGGERHEART.WeaponFeature.ChargedAttack.Name", + description: "DAGGERHEART.WeaponFeature.ChargedAttack.Description", + }, + sheltering: { + label: "DAGGERHEART.WeaponFeature.Sheltering.Name", + description: "DAGGERHEART.WeaponFeature.Sheltering.Description", + }, + doubledUp: { + label: "DAGGERHEART.WeaponFeature.DoubledUp.Name", + description: "DAGGERHEART.WeaponFeature.DoubledUp.Description", + }, + lockedOn: { + label: "DAGGERHEART.WeaponFeature.LockedOn.Name", + description: "DAGGERHEART.WeaponFeature.LockedOn.Description", + }, +}; + +export const featureTypes = { + ancestry: { + id: "ancestry", + label: "DAGGERHEART.Feature.Type.Ancestry" + }, + community: { + id: "community", + label: "DAGGERHEART.Feature.Type.Community" + }, + class: { + id: "class", + label: "DAGGERHEART.Feature.Type.Class" + }, + subclass: { + id: "subclass", + label: "DAGGERHEART.Feature.Type.Subclass" + }, +} + +export const valueTypes = { + normal: { + id: 'normal', + name: "DAGGERHEART.Feature.ValueType.Normal", + data: { + value: 0, + max: 0, + } + }, + input: { + id: 'input', + name: "DAGGERHEART.Feature.ValueType.Input", + data: { + value: null, + } + }, + dice: { + id: 'dice', + name: "DAGGERHEART.Feature.ValueType.Dice", + data: { + value: null, + } + } +} + +export const actionTypes = { + passive: { + id: "passive", + label: "DAGGERHEART.ActionType.Passive" + }, + action: { + id: "action", + label: "DAGGERHEART.ActionType.Action" + }, + reaction: { + id: "reaction", + label: "DAGGERHEART.ActionType.Reaction" + } +}; diff --git a/module/config/settingsConfig.mjs b/module/config/settingsConfig.mjs new file mode 100644 index 00000000..7c790b72 --- /dev/null +++ b/module/config/settingsConfig.mjs @@ -0,0 +1,28 @@ +export const menu = { + Automation: { + Name: "GameSettingsAutomation", + Icon: "fa-solid fa-robot", + }, + Homebrew: { + Name: "GameSettingsHomebrew", + Icon: "fa-solid fa-flask-vial", + }, + Range: { + Name: "GameSettingsRange", + Icon: "fa-solid fa-ruler", + }, +}; + +export const gameSettings = { + Automation: { + Hope: "AutomationHope", + ActionPoints: "AutomationActionPoints", + }, + Resources: { + Fear: "ResourcesFear" + }, + General: { + AbilityArray: "AbilityArray", + RangeMeasurement: "RangeMeasurement", + } +} \ No newline at end of file diff --git a/module/config/system.mjs b/module/config/system.mjs new file mode 100644 index 00000000..0129d706 --- /dev/null +++ b/module/config/system.mjs @@ -0,0 +1,20 @@ +import * as GENERAL from './generalConfig.mjs'; +import * as DOMAIN from "./domainConfig.mjs"; +import * as ACTOR from './actorConfig.mjs'; +import * as ITEM from './itemConfig.mjs'; +import * as SETTINGS from './settingsConfig.mjs'; +import * as EFFECTS from './effectConfig.mjs'; +import * as ACTIONS from './actionConfig.mjs'; + +export const SYSTEM_ID = "daggerheart"; + +export const SYSTEM = { + id: SYSTEM_ID, + GENERAL, + DOMAIN, + ACTOR, + ITEM, + SETTINGS, + EFFECTS, + ACTIONS, +}; \ No newline at end of file diff --git a/module/data/_module.mjs b/module/data/_module.mjs new file mode 100644 index 00000000..2e6db942 --- /dev/null +++ b/module/data/_module.mjs @@ -0,0 +1,18 @@ +export { default as DhpPC } from './pc.mjs'; +export { default as DhpClass } from './class.mjs'; +export { default as DhpSubclass } from './subclass.mjs'; +export { default as DhpCombat } from './combat.mjs'; +export { default as DhpCombatant } from './combatant.mjs'; +export { default as DhpAdversary } from './adversary.mjs'; +export { default as DhpFeature } from './feature.mjs'; +export { default as DhpDomainCard } from './domainCard.mjs'; +export { default as DhpAncestry } from './ancestry.mjs'; +export { default as DhpCommunity } from './community.mjs'; +export { default as DhpMiscellaneous } from './miscellaneous.mjs'; +export { default as DhpConsumable } from './consumable.mjs'; +export { default as DhpWeapon } from './weapon.mjs'; +export { default as DhpArmor } from './armor.mjs'; +export { default as DhpDualityRoll } from './dualityRoll.mjs'; +export { default as DhpAdversaryRoll } from './adversaryRoll.mjs'; +export { default as DhpAbilityUse } from './abilityUse.mjs'; +export { default as DhpEnvironment } from './environment.mjs'; \ No newline at end of file diff --git a/module/data/abilityUse.mjs b/module/data/abilityUse.mjs new file mode 100644 index 00000000..d1f3f7b9 --- /dev/null +++ b/module/data/abilityUse.mjs @@ -0,0 +1,30 @@ +export default class DhpAbilityUse extends foundry.abstract.TypeDataModel { + static defineSchema() { + const fields = foundry.data.fields; + + return { + title: new fields.StringField({}), + img: new fields.StringField({}), + name: new fields.StringField({}), + description: new fields.StringField({}), + actions: new fields.ArrayField(new fields.SchemaField({ + 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({ nullable: true }), + value: new fields.NumberField({ nullable: true }), + }), + target: new fields.SchemaField({ + type: new fields.StringField({}), + }), + })), + } + } +} \ No newline at end of file diff --git a/module/data/action.mjs b/module/data/action.mjs new file mode 100644 index 00000000..7d02c148 --- /dev/null +++ b/module/data/action.mjs @@ -0,0 +1,38 @@ +export default class DaggerheartAction extends foundry.abstract.DataModel { + static defineSchema() { + const fields = foundry.data.fields; + return { + id: new fields.StringField({}), + name: new fields.StringField({ initial: 'New Action' }), + damage: new fields.SchemaField({ + type: new fields.StringField({ choices: SYSTEM.GENERAL.damageTypes, nullable: true, initial: null }), + value: new fields.StringField({}), + }), + healing: new fields.SchemaField({ + type: new fields.StringField({ choices: SYSTEM.GENERAL.healingTypes, nullable: true, initial: null }), + value: new fields.StringField(), + }), + conditions: new fields.ArrayField(new fields.SchemaField({ + name: new fields.StringField(), + icon: new fields.StringField(), + description: new fields.StringField(), + })), + cost: new fields.SchemaField({ + type: new fields.StringField({ choices: SYSTEM.GENERAL.abilityCosts, nullable: true, initial: null }), + value: new fields.NumberField({ nullable: true, initial: null }), + }), + target: new fields.SchemaField({ + type: new fields.StringField({ choices: SYSTEM.ACTIONS.targetTypes, initial: SYSTEM.ACTIONS.targetTypes.other.id }) + }), + // uses: new fields.SchemaField({ + // nr: new fields.StringField({}), + // refreshType: new fields.StringField({ choices: SYSTEM.GENERAL.refreshTypes, initial: SYSTEM.GENERAL.refreshTypes.session.id }), + // refreshed: new fields.BooleanField({ initial: true }), + // }), + } + } + + use = async () => { + console.log('Test Use'); + }; +} \ No newline at end of file diff --git a/module/data/adversary.mjs b/module/data/adversary.mjs new file mode 100644 index 00000000..ca7bcae9 --- /dev/null +++ b/module/data/adversary.mjs @@ -0,0 +1,48 @@ +import { MappingField } from "./fields.mjs"; + +export default class DhpAdversary extends foundry.abstract.TypeDataModel { + static defineSchema() { + const fields = foundry.data.fields; + return { + resources: new fields.SchemaField({ + health: new fields.SchemaField({ + value: new fields.NumberField({ initial: 0, integer: true }), + min: new fields.NumberField({ initial: 0, integer: true }), + max: new fields.NumberField({ initial: 0, integer: true }), + }), + stress: new fields.SchemaField({ + value: new fields.NumberField({ initial: 0, integer: true }), + min: new fields.NumberField({ initial: 0, integer: true }), + max: new fields.NumberField({ initial: 0, integer: true }), + }), + }), + tier: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.tiers), integer: false }), + type: new fields.StringField({ choices: Object.keys(SYSTEM.ACTOR.adversaryTypes), integer: false, initial: Object.keys(SYSTEM.ACTOR.adversaryTypes).find(x => x === 'standard') }), + description: new fields.StringField({}), + motivesAndTactics: new fields.ArrayField(new fields.StringField({})), + attackModifier: new fields.NumberField({ integer: true, nullabe: true, initial: null }), + attack: new fields.SchemaField({ + name: new fields.StringField({}), + range: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.range), integer: false }), + damage: new fields.SchemaField({ + value: new fields.StringField({}), + type: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.damageTypes), integer: false }), + }) + }), + difficulty: new fields.NumberField({ initial: 1, integer: true }), + damageThresholds: new fields.SchemaField({ + minor: new fields.NumberField({ initial: 0, integer: true }), + major: new fields.NumberField({ initial: 0, integer: true }), + severe: new fields.NumberField({ initial: 0, integer: true }), + }), + experiences: new fields.ArrayField(new fields.SchemaField({ + name: new fields.StringField({}), + value: new fields.NumberField({ integer: true, nullable: true, initial: null }), + })), + } + } + + get moves(){ + return this.parent.items.filter(x => x.type === 'feature'); + } +} \ No newline at end of file diff --git a/module/data/adversaryRoll.mjs b/module/data/adversaryRoll.mjs new file mode 100644 index 00000000..65450a4b --- /dev/null +++ b/module/data/adversaryRoll.mjs @@ -0,0 +1,50 @@ +export default class DhpAdversaryRoll extends foundry.abstract.TypeDataModel { + static defineSchema() { + const fields = foundry.data.fields; + + return { + roll: new fields.StringField({}), + total: new fields.NumberField({ integer: true }), + modifiers: new fields.ArrayField(new fields.SchemaField({ + value: new fields.NumberField({ integer: true }), + label: new fields.StringField({}), + title: new fields.StringField({}), + })), + diceResults: new fields.ArrayField(new fields.SchemaField({ + value: new fields.NumberField({ integer: true }), + discarded: new fields.BooleanField({ initial: false }), + })), + targets: new fields.ArrayField(new fields.SchemaField({ + id: new fields.StringField({}), + name: new fields.StringField({}), + img: new fields.StringField({}), + difficulty: new fields.NumberField({ integer: true, nullable: true }), + evasion: new fields.NumberField({ integer: true }), + hit: new fields.BooleanField({ initial: false }), + })), + damage: new fields.SchemaField({ + value: new fields.StringField({}), + type: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.damageTypes), integer: false }), + }, { nullable: true, initial: null }) + } + } + + prepareDerivedData(){ + const diceKeys = Object.keys(this.diceResults); + const highestIndex = 0; + for(var index in diceKeys){ + const resultIndex = Number.parseInt(index); + if(highestIndex === resultIndex) continue; + + const current = this.diceResults[resultIndex]; + const highest = this.diceResults[highestIndex]; + + if(current.value > highest.value) this.diceResults[highestIndex].discarded = true; + else this.diceResults[resultIndex].discarded = true; + } + + this.targets.forEach(target => { + target.hit = target.difficulty ? this.total >= target.difficulty : this.total >= target.evasion; + }); + } +} \ No newline at end of file diff --git a/module/data/ancestry.mjs b/module/data/ancestry.mjs new file mode 100644 index 00000000..fe9294af --- /dev/null +++ b/module/data/ancestry.mjs @@ -0,0 +1,11 @@ +import featuresSchema from "./interface/featuresSchema.mjs"; + +export default class DhpAncestry extends foundry.abstract.TypeDataModel { + static defineSchema() { + const fields = foundry.data.fields; + return { + description: new fields.HTMLField({}), + abilities: featuresSchema(), + } + } +} \ No newline at end of file diff --git a/module/data/armor.mjs b/module/data/armor.mjs new file mode 100644 index 00000000..fefe9785 --- /dev/null +++ b/module/data/armor.mjs @@ -0,0 +1,40 @@ +export default class DhpArmor extends foundry.abstract.TypeDataModel { + static defineSchema() { + const fields = foundry.data.fields; + return { + baseScore: new fields.NumberField({ initial: 1, integer: true }), + feature: new fields.StringField({ choices: SYSTEM.ITEM.armorFeatures, integer: false }), + marks: new fields.SchemaField({ + max: new fields.NumberField({ initial: 6, integer: true }), + value: new fields.NumberField({ initial: 0, integer: true }), + }), + description: new fields.HTMLField({}), + } + } + + get featureInfo() { + return this.feature ? CONFIG.daggerheart.ITEM.armorFeatures[this.feature] : null; + } + + prepareDerivedData(){ + if(this.parent.parent){ + this.applyLevels(); + } + } + + // Currently bugged as it double triggers. Should get fixed in an updated foundry version. + applyLevels(){ + // let armorBonus = 0; + // for(var level in this.parent.parent.system.levelData.levelups){ + // var levelData = this.parent.parent.system.levelData.levelups[level]; + // for(var tier in levelData){ + // var tierData = levelData[tier]; + // if(tierData){ + // armorBonus += Object.keys(tierData.armorOrEvasionSlot).filter(x => tierData.armorOrEvasionSlot[x] === 'armor').length; + // } + // } + // } + + // this.marks.max += armorBonus; + } +} \ No newline at end of file diff --git a/module/data/class.mjs b/module/data/class.mjs new file mode 100644 index 00000000..deacee88 --- /dev/null +++ b/module/data/class.mjs @@ -0,0 +1,93 @@ +import { getTier } from "../helpers/utils.mjs"; +import DhpFeature from "./feature.mjs"; + +export default class DhpClass extends foundry.abstract.TypeDataModel { + static defineSchema() { + const fields = foundry.data.fields; + return { + domains: new fields.ArrayField(new fields.StringField({})), + classItems: new fields.ArrayField(new fields.SchemaField({ + name: new fields.StringField({}), + img: new fields.StringField({}), + uuid: new fields.StringField({}), + })), + damageThresholds: new fields.SchemaField({ + minor: new fields.NumberField({ initial: 0, integer: true }), + major: new fields.NumberField({ initial: 0, integer: true }), + severe: new fields.NumberField({ initial: 0, integer: true }), + }), + evasion: new fields.NumberField({ initial: 0, integer: true}), + features: new fields.ArrayField(new fields.SchemaField({ + name: new fields.StringField({}), + img: new fields.StringField({}), + uuid: new fields.StringField({}), + })), + subclasses: new fields.ArrayField(new fields.SchemaField({ + name: new fields.StringField({}), + img: new fields.StringField({}), + uuid: new fields.StringField({}), + })), + inventory: new fields.SchemaField({ + take: new fields.ArrayField(new fields.SchemaField({ + name: new fields.StringField({}), + img: new fields.StringField({}), + uuid: new fields.StringField({}), + })), + choiceA: new fields.ArrayField(new fields.SchemaField({ + name: new fields.StringField({}), + img: new fields.StringField({}), + uuid: new fields.StringField({}), + })), + choiceB: new fields.ArrayField(new fields.SchemaField({ + name: new fields.StringField({}), + img: new fields.StringField({}), + uuid: new fields.StringField({}), + })), + extra: new fields.SchemaField({ + title: new fields.StringField({}), + description: new fields.StringField({}) + }, { initial: null, nullable: true }), + }), + characterGuide: new fields.SchemaField({ + suggestedTraits: new fields.SchemaField({ + agility: new fields.NumberField({ initial: 0, integer: true }), + strength: new fields.NumberField({ initial: 0, integer: true }), + finesse: new fields.NumberField({ initial: 0, integer: true }), + instinct: new fields.NumberField({ initial: 0, integer: true }), + presence: new fields.NumberField({ initial: 0, integer: true }), + knowledge: new fields.NumberField({ initial: 0, integer: true }), + }), + suggestedPrimaryWeapon: new fields.SchemaField({ + name: new fields.StringField({}), + img: new fields.StringField({}), + uuid: new fields.StringField({}), + }, { initial: null, nullable: true }), + suggestedSecondaryWeapon: new fields.SchemaField({ + name: new fields.StringField({}), + img: new fields.StringField({}), + uuid: new fields.StringField({}), + }, { initial: null, nullable: true }), + suggestedArmor: new fields.SchemaField({ + name: new fields.StringField({}), + img: new fields.StringField({}), + uuid: new fields.StringField({}), + }, { initial: null, nullable: true }), + characterDescription: new fields.SchemaField({ + clothes: new fields.StringField({}), + eyes: new fields.StringField({}), + body: new fields.StringField({}), + color: new fields.StringField({}), + attitude: new fields.StringField({}), + }), + backgroundQuestions: new fields.ArrayField(new fields.StringField({}), { initial: ['', '', ''] }), + connections: new fields.ArrayField(new fields.StringField({}), { initial: ['', '' ,''] }), + }), + multiclass: new fields.NumberField({ initial: null, nullable: true, integer: true }), + description: new fields.HTMLField({}), + } + } + + get multiclassTier(){ + return getTier(this.multiclass, true); + } +} \ No newline at end of file diff --git a/module/data/combat.mjs b/module/data/combat.mjs new file mode 100644 index 00000000..0fa1d340 --- /dev/null +++ b/module/data/combat.mjs @@ -0,0 +1,9 @@ +export default class DhpCombat extends foundry.abstract.TypeDataModel { + static defineSchema() { + const fields = foundry.data.fields; + return { + actions: new fields.NumberField({ initial: 0, integer: true }), + activeCombatant: new fields.StringField({}), + } + } +} \ No newline at end of file diff --git a/module/data/combatant.mjs b/module/data/combatant.mjs new file mode 100644 index 00000000..807665d5 --- /dev/null +++ b/module/data/combatant.mjs @@ -0,0 +1,8 @@ +export default class DhpCombatant extends foundry.abstract.TypeDataModel { + static defineSchema() { + const fields = foundry.data.fields; + return { + active: new fields.BooleanField({ initial: false }) + } + } +} \ No newline at end of file diff --git a/module/data/community.mjs b/module/data/community.mjs new file mode 100644 index 00000000..fcb887cd --- /dev/null +++ b/module/data/community.mjs @@ -0,0 +1,11 @@ +import featuresSchema from "./interface/featuresSchema.mjs"; + +export default class DhpCommunity extends foundry.abstract.TypeDataModel { + static defineSchema() { + const fields = foundry.data.fields; + return { + description: new fields.HTMLField({}), + abilities: featuresSchema(), + } + } +} \ No newline at end of file diff --git a/module/data/consumable.mjs b/module/data/consumable.mjs new file mode 100644 index 00000000..21938ecd --- /dev/null +++ b/module/data/consumable.mjs @@ -0,0 +1,10 @@ +export default class DhpConsumable extends foundry.abstract.TypeDataModel { + static defineSchema() { + const fields = foundry.data.fields; + return { + description: new fields.HTMLField({}), + quantity: new fields.NumberField({ initial: 1, integer: true }), + consumeOnUse: new fields.BooleanField({ initial: false }), + } + } +} \ No newline at end of file diff --git a/module/data/domainCard.mjs b/module/data/domainCard.mjs new file mode 100644 index 00000000..181ab15f --- /dev/null +++ b/module/data/domainCard.mjs @@ -0,0 +1,17 @@ +import DaggerheartAction from "./action.mjs"; + +export default class DhpDomainCard extends foundry.abstract.TypeDataModel { + static defineSchema() { + const fields = foundry.data.fields; + return { + domain: new fields.StringField({ choices: SYSTEM.DOMAIN.domains, integer: false }, { required: true, initial: [] }), + level: new fields.NumberField({ initial: 1, integer: true }), + recallCost: new fields.NumberField({ initial: 0, integer: true }), + type: new fields.StringField({ choices: SYSTEM.DOMAIN.cardTypes, integer: false }, { required: true, initial: [] }), + foundation: new fields.BooleanField({ initial: false }), + effect: new fields.HTMLField({}), + inVault: new fields.BooleanField({ initial: false }), + actions: new fields.ArrayField(new fields.EmbeddedDataField(DaggerheartAction)), + } + } +} \ No newline at end of file diff --git a/module/data/dualityRoll.mjs b/module/data/dualityRoll.mjs new file mode 100644 index 00000000..ffb40484 --- /dev/null +++ b/module/data/dualityRoll.mjs @@ -0,0 +1,150 @@ +const fields = foundry.data.fields; +const diceField = () => new fields.SchemaField({ + dice: new fields.StringField({}), + value: new fields.NumberField({ integer: true}), +}); + +export default class DhpDualityRoll extends foundry.abstract.TypeDataModel { + static defineSchema() { + + return { + roll: new fields.StringField({}), + modifiers: new fields.ArrayField(new fields.SchemaField({ + value: new fields.NumberField({ integer: true }), + label: new fields.StringField({}), + title: new fields.StringField({}), + })), + hope: diceField(), + fear: diceField(), + advantage: diceField(), + disadvantage: diceField(), + advantageSelected: new fields.NumberField({ initial: 0 }), + targets: new fields.ArrayField(new fields.SchemaField({ + id: new fields.StringField({}), + name: new fields.StringField({}), + img: new fields.StringField({}), + difficulty: new fields.NumberField({ integer: true, nullable: true }), + evasion: new fields.NumberField({ integer: true }), + hit: new fields.BooleanField({ initial: false }), + })), + damage: new fields.SchemaField({ + value: new fields.StringField({}), + type: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.damageTypes), integer: false }), + bonusDamage: new fields.ArrayField(new fields.SchemaField({ + value: new fields.StringField({}), + type: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.damageTypes), integer: false }), + initiallySelected: new fields.BooleanField(), + appliesOn: new fields.StringField({ choices: Object.keys(SYSTEM.EFFECTS.applyLocations) }, { nullable: true, initial: null }), + description: new fields.StringField({}), + hopeIncrease: new fields.StringField({ nullable: true }) + }), { nullable: true, initial: null }) + }) + } + } + + get total() { + const modifiers = this.modifiers.reduce((acc, x) => acc+x.value, 0); + const advantage = this.advantage.value ?? this.disadvantage.value ? -this.disadvantage.value : 0; + return this.hope.value + this.fear.value + advantage + modifiers; + } + + get totalLabel() { + const label = this.hope.value > this.fear.value ? "DAGGERHEART.General.Hope" : this.fear.value > this.hope.value ? "DAGGERHEART.General.Fear" : "DAGGERHEART.General.CriticalSuccess"; + + return game.i18n.localize(label); + } + + prepareDerivedData(){ + const total = this.total; + + this.targets.forEach(target => { + target.hit = target.difficulty ? total >= target.difficulty : total >= target.evasion; + }); + } +} + +//V1.3 +// const fields = foundry.data.fields; +// const diceField = () => new fields.SchemaField({ +// dice: new fields.StringField({}), +// value: new fields.NumberField({ integer: true}), +// }); + +// export default class DhpDualityRoll extends foundry.abstract.TypeDataModel { +// static defineSchema() { + +// return { +// roll: new fields.StringField({}), +// modifiers: new fields.ArrayField(new fields.SchemaField({ +// value: new fields.NumberField({ integer: true }), +// label: new fields.StringField({}), +// title: new fields.StringField({}), +// })), +// hope: diceField(), +// fear: diceField(), +// advantage: diceField(), +// disadvantage: diceField(), +// advantageSelected: new fields.NumberField({ initial: 0 }), +// targets: new fields.ArrayField(new fields.SchemaField({ +// id: new fields.StringField({}), +// name: new fields.StringField({}), +// img: new fields.StringField({}), +// difficulty: new fields.NumberField({ integer: true, nullable: true }), +// evasion: new fields.NumberField({ integer: true }), +// hit: new fields.BooleanField({ initial: false }), +// })), +// damage: new fields.SchemaField({ +// value: new fields.StringField({}), +// type: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.damageTypes), integer: false }), +// bonusDamage: new fields.ArrayField(new fields.SchemaField({ +// value: new fields.StringField({}), +// type: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.damageTypes), integer: false }), +// initiallySelected: new fields.BooleanField(), +// appliesOn: new fields.StringField({ choices: Object.keys(SYSTEM.EFFECTS.applyLocations) }, { nullable: true, initial: null }), +// description: new fields.StringField({}), +// hopeIncrease: new fields.StringField({ nullable: true }) +// }), { nullable: true, initial: null }) +// }) +// } +// } + +// get total() { +// const modifiers = this.modifiers.reduce((acc, x) => acc+x.value, 0); +// const regular = { +// normal: this.disadvantage.value ? Math.min(this.disadvantage.value, this.hope.value) + this.fear.value + modifiers : this.hope.value + this.fear.value + modifiers, +// alternate: this.advantage.value ? this.advantage.value + this.fear.value + modifiers : null, +// }; + +// const advantageSolve = this.advantageSelected === 0 ? null : { +// normal: this.advantageSelected === 1 ? this.hope.value + this.fear.value + modifiers : this.advantage.value + this.fear.value + modifiers, +// alternate: null, +// }; + +// return advantageSolve ?? regular; +// } + +// get totalLabel() { +// if(this.advantage.value && this.advantageSelected === 0) return game.i18n.localize("DAGGERHEART.Chat.DualityRoll.AdvantageChooseTitle"); + +// const hope = !this.advantage.value || this.advantageSelected === 1 ? this.hope.value : this.advantage.value; +// const label = hope > this.fear.value ? "DAGGERHEART.General.Hope" : this.fear.value > hope ? "DAGGERHEART.General.Fear" : "DAGGERHEART.General.CriticalSuccess"; + +// return game.i18n.localize(label); +// } + +// get dualityDiceStates() { +// return { +// hope: this.hope.value > this.fear.value ? 'hope' : this.fear.value > this.hope.value ? 'fear' : 'critical', +// alternate: this.advantage.value > this.fear.value ? 'hope' : this.fear.value > this.advantage.value ? 'fear' : 'critical', +// } +// } + +// prepareDerivedData(){ +// const total = this.total; +// if(total.alternate) return false; + +// this.targets.forEach(target => { +// target.hit = target.difficulty ? total.normal >= target.difficulty : total.normal >= target.evasion; +// }); +// } +// } \ No newline at end of file diff --git a/module/data/environment.mjs b/module/data/environment.mjs new file mode 100644 index 00000000..05c6aeae --- /dev/null +++ b/module/data/environment.mjs @@ -0,0 +1,20 @@ +export default class DhpEnvironment extends foundry.abstract.TypeDataModel { + static defineSchema() { + const fields = foundry.data.fields; + return { + resources: new fields.SchemaField({ + + }), + tier: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.tiers), integer: false }), + type: new fields.StringField({ choices: Object.keys(SYSTEM.ACTOR.adversaryTypes), integer: false, initial: Object.keys(SYSTEM.ACTOR.adversaryTypes).find(x => x === 'standard') }), + description: new fields.StringField({}), + toneAndFeel: new fields.StringField({}), + difficulty: new fields.NumberField({ initial: 1, integer: true }), + potentialAdversaries: new fields.StringField({}), + } + } + + get features(){ + return this.parent.items.filter(x => x.type === 'feature'); + } +} \ No newline at end of file diff --git a/module/data/feature.mjs b/module/data/feature.mjs new file mode 100644 index 00000000..56bc31cc --- /dev/null +++ b/module/data/feature.mjs @@ -0,0 +1,77 @@ +import { getTier } from "../helpers/utils.mjs"; +import DaggerheartAction from "./action.mjs"; +import { MappingField } from "./fields.mjs"; +import DhpEffect from "./interface/effects.mjs"; + +export default class DhpFeature extends DhpEffect { + static defineSchema() { + const fields = foundry.data.fields; + return foundry.utils.mergeObject({}, { + type: new fields.StringField({ choices: SYSTEM.ITEM.featureTypes }), + actionType: new fields.StringField({ choices: SYSTEM.ITEM.actionTypes, initial: SYSTEM.ITEM.actionTypes.passive.id }), + featureType: new fields.SchemaField({ + type: new fields.StringField({ choices: SYSTEM.ITEM.valueTypes, initial: Object.keys(SYSTEM.ITEM.valueTypes).find(x => x === 'normal') }), + data: new fields.SchemaField({ + value: new fields.StringField({}), + property: new fields.StringField({ choices: SYSTEM.ACTOR.featureProperties, initial: Object.keys(SYSTEM.ACTOR.featureProperties).find(x => x === 'spellcastingTrait') }), + max: new fields.NumberField({ initial: 1, integer: true }), + numbers: new MappingField(new fields.SchemaField({ + value: new fields.NumberField({ integer: true }), + used: new fields.BooleanField({ initial: false }), + })), + }), + }), + refreshData: new fields.SchemaField({ + type: new fields.StringField({ choices: SYSTEM.GENERAL.refreshTypes }), + uses: new fields.NumberField({ initial: 1, integer: true }), + refreshed: new fields.BooleanField({ initial: true }) + }, { nullable: true, initial: null }), + multiclass: new fields.NumberField({ initial: null, nullable: true, integer: true }), + disabled: new fields.BooleanField({ initial: false }), + description: new fields.HTMLField({}), + effects: new MappingField(new fields.SchemaField({ + type: new fields.StringField({ choices: SYSTEM.EFFECTS.effectTypes }), + valueType: new fields.StringField({ choices: SYSTEM.EFFECTS.valueTypes }), + parseType: new fields.StringField({ choices: SYSTEM.EFFECTS.parseTypes }), + initiallySelected: new fields.BooleanField({ initial: true }), + options: new fields.ArrayField(new fields.SchemaField({ + name: new fields.StringField({}), + value: new fields.StringField({}), + }), { nullable: true, initial: null }), + dataField: new fields.StringField({}), + appliesOn: new fields.StringField({ choices: SYSTEM.EFFECTS.applyLocations }, { nullable: true, initial: null }), + applyLocationChoices: new MappingField(new fields.StringField({}), { nullable: true, initial: null }), + valueData: new fields.SchemaField({ + value: new fields.StringField({}), + fromValue: new fields.StringField({ initial: null, nullable: true }), + type: new fields.StringField({ initial: null, nullable: true }), + hopeIncrease: new fields.StringField({ initial: null, nullable: true }) + }), + })), + actions: new fields.ArrayField(new fields.EmbeddedDataField(DaggerheartAction)), + }); + } + + get multiclassTier(){ + return getTier(this.multiclass); + } + + async refresh(){ + if(this.refreshData){ + if(this.featureType.type === SYSTEM.ITEM.valueTypes.dice.id) { + const update = { "system.refreshData.refreshed": true }; + Object.keys(this.featureType.data.numbers).forEach(x => update[`system.featureType.data.numbers.-=${x}`] = null); + await this.parent.update(update); + } + else { + await this.parent.update({ "system.refreshData.refreshed": true}); + } + } + } + + // prepareDerivedData(){ + // if(this.featureType.type === SYSTEM.ITEM.valueTypes.dice.id){ + // this.featureType.numbers = ; + // } + // } +} \ No newline at end of file diff --git a/module/data/fields.mjs b/module/data/fields.mjs new file mode 100644 index 00000000..d75be130 --- /dev/null +++ b/module/data/fields.mjs @@ -0,0 +1,109 @@ +export 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; + } + + /* -------------------------------------------- */ + + /** @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]) => 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) ) throw new foundry.data.fields.ModelValidationError(errors); + } + + /* -------------------------------------------- */ + + /** + * Validate each value of the object. + * @param {object} value The object to validate. + * @param {object} options Validation options. + * @returns {Object} An object of value-specific errors by key. + */ + _validateValues(value, options) { + const errors = {}; + for ( const [k, v] of Object.entries(value) ) { + 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); + } + } \ No newline at end of file diff --git a/module/data/interface/effects.mjs b/module/data/interface/effects.mjs new file mode 100644 index 00000000..3ed91430 --- /dev/null +++ b/module/data/interface/effects.mjs @@ -0,0 +1,75 @@ +import DaggerheartAction from "../action.mjs"; +import { MappingField } from "../fields.mjs"; + +export default class DhpEffects extends foundry.abstract.TypeDataModel { + static defineSchema() { + const fields = foundry.data.fields; + return { + effects: new MappingField(new fields.SchemaField({ + type: new fields.StringField({ choices: Object.keys(SYSTEM.EFFECTS.effectTypes) }), + valueType: new fields.StringField({ choices: Object.keys(SYSTEM.EFFECTS.valueTypes) }), + parseType: new fields.StringField({ choices: Object.keys(SYSTEM.EFFECTS.parseTypes) }), + initiallySelected: new fields.BooleanField({ initial: true }), + options: new fields.ArrayField(new fields.SchemaField({ + name: new fields.StringField({}), + value: new fields.StringField({}), + }), { nullable: true, initial: null }), + dataField: new fields.StringField({}), + appliesOn: new fields.StringField({ choices: Object.keys(SYSTEM.EFFECTS.applyLocations) }, { nullable: true, initial: null }), + applyLocationChoices: new MappingField(new fields.StringField({}), { nullable: true, initial: null }), + valueData: new fields.SchemaField({ + value: new fields.StringField({}), + fromValue: new fields.StringField({ initial: null, nullable: true }), + type: new fields.StringField({ initial: null, nullable: true }), + hopeIncrease: new fields.StringField({ initial: null, nullable: true }) + }), + })), + actions: new fields.ArrayField(new fields.EmbeddedDataField(DaggerheartAction)), + // actions: new fields.SchemaField({ + // damage: new fields.ArrayField(new fields.SchemaField({ + // type: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.extendedDamageTypes), initial: SYSTEM.GENERAL.extendedDamageTypes.physical.id }), + // value: new fields.StringField({}), + // })), + // uses: new fields.SchemaField({ + // nr: new fields.StringField({}), + // refreshType: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.refreshTypes), initial: SYSTEM.GENERAL.refreshTypes.session.id }), + // refreshed: new fields.BooleanField({ initial: true }), + // }), + // }), + } + } + + get effectData(){ + const effectValues = Object.values(this.effects); + const effectCategories = Object.keys(SYSTEM.EFFECTS.effectTypes).reduce((acc, effectType) => { + acc[effectType] = effectValues.reduce((acc, effect) => { + if(effect.type === effectType){ + acc.push({ ...effect, valueData: this.#parseValues(effect.parseType, effect.valueData) }); + } + + return acc; + }, []); + + return acc; + }, {}); + + return effectCategories; + } + + #parseValues(parseType, values){ + return Object.keys(values).reduce((acc, prop) => { + acc[prop] = this.#parseValue(parseType, values[prop]); + + return acc; + }, {}); + } + + #parseValue(parseType, value) { + switch(parseType){ + case SYSTEM.EFFECTS.parseTypes.number.id: + return Number.parseInt(value); + default: + return value; + } + } +} \ No newline at end of file diff --git a/module/data/interface/featuresSchema.mjs b/module/data/interface/featuresSchema.mjs new file mode 100644 index 00000000..b35d6e46 --- /dev/null +++ b/module/data/interface/featuresSchema.mjs @@ -0,0 +1,10 @@ +const fields = foundry.data.fields; + +const featuresSchema = () => new fields.ArrayField(new fields.SchemaField({ + name: new fields.StringField({}), + img: new fields.StringField({}), + uuid: new fields.StringField({}), + subclassLevel: new fields.StringField({}), +})) + +export default featuresSchema; \ No newline at end of file diff --git a/module/data/miscellaneous.mjs b/module/data/miscellaneous.mjs new file mode 100644 index 00000000..45429992 --- /dev/null +++ b/module/data/miscellaneous.mjs @@ -0,0 +1,9 @@ +export default class DhpMiscellaneous extends foundry.abstract.TypeDataModel { + static defineSchema() { + const fields = foundry.data.fields; + return { + description: new fields.HTMLField({}), + quantity: new fields.NumberField({ initial: 1, integer: true }) + } + } +} \ No newline at end of file diff --git a/module/data/pc.mjs b/module/data/pc.mjs new file mode 100644 index 00000000..df6852c2 --- /dev/null +++ b/module/data/pc.mjs @@ -0,0 +1,497 @@ +import { getPathValue, getTier } from "../helpers/utils.mjs"; +import { MappingField } from "./fields.mjs"; + +const fields = foundry.data.fields; + +const attributeField = () => new fields.SchemaField({ + data: new fields.SchemaField({ + value: new fields.NumberField({ initial: 0, integer: true }), + base: new fields.NumberField({ initial: 0, integer: true }), + bonus: new fields.NumberField({ initial: 0, integer: true }), + actualValue: new fields.NumberField({ initial: 0, integer: true }), + overrideValue: new fields.NumberField({ initial: 0, integer: true }), + }), + levelMarks: new fields.ArrayField(new fields.NumberField({ nullable: true, initial: null, integer: true })), + levelMark: new fields.NumberField({ nullable: true, initial: null, integer: true }), +}); + +const levelUpTier = () => ({ + attributes: new MappingField(new fields.BooleanField()), + hitPointSlots: new MappingField(new fields.BooleanField()), + stressSlots: new MappingField(new fields.BooleanField()), + experiences: new MappingField(new fields.ArrayField(new fields.StringField({}))), + proficiency: new MappingField(new fields.BooleanField()), + armorOrEvasionSlot: new MappingField(new fields.StringField({})), + majorDamageThreshold2: new MappingField(new fields.BooleanField()), + severeDamageThreshold2: new MappingField(new fields.BooleanField()), + severeDamageThreshold3: new MappingField(new fields.BooleanField()), + severeDamageThreshold4: new MappingField(new fields.BooleanField()), + subclass: new MappingField(new fields.SchemaField({ + multiclass: new fields.BooleanField(), + feature: new fields.StringField({}), + })), + multiclass: new MappingField(new fields.BooleanField()), +}); + +// const weapon = () => new fields.SchemaField({ +// name: new fields.StringField({}), +// trait: new fields.StringField({}), +// range: new fields.StringField({}), +// damage: new fields.SchemaField({ +// value: new fields.StringField({}), +// type: new fields.StringField({}), +// }), +// feature: new fields.StringField({}), +// img: new fields.StringField({}), +// uuid: new fields.StringField({}), +// }, { initial: null, nullable: true }); + +export default class DhpPC extends foundry.abstract.TypeDataModel { + static defineSchema() { + return { + resources: new fields.SchemaField({ + health: new fields.SchemaField({ + value: new fields.NumberField({ initial: 0, integer: true }), + min: new fields.NumberField({ initial: 0, integer: true }), + max: new fields.NumberField({ initial: 6, integer: true }), + }), + stress: new fields.SchemaField({ + value: new fields.NumberField({ initial: 0, integer: true }), + min: new fields.NumberField({ initial: 0, integer: true }), + max: new fields.NumberField({ initial: 6, integer: true }), + }), + hope: new fields.SchemaField({ + value: new fields.NumberField({ initial: -1, integer: true }), // FIXME. Logic is gte and needs -1 in PC/Hope. Change to 0 + min: new fields.NumberField({ initial: 0, integer: true }), + }), + }), + bonuses: new fields.SchemaField({ + damage: new fields.ArrayField(new fields.SchemaField({ + value: new fields.NumberField({ integer: true, initial: 0 }), + type: new fields.StringField({ nullable: true }), + initiallySelected: new fields.BooleanField(), + hopeIncrease: new fields.StringField({ initial: null, nullable: true }), + description: new fields.StringField({}), + })), + }), + attributes: new fields.SchemaField({ + agility: attributeField(), + strength: attributeField(), + finesse: attributeField(), + instinct: attributeField(), + presence: attributeField(), + knowledge: attributeField(), + }), + proficiency: new fields.SchemaField({ + value: new fields.NumberField({ initial: 1, integer: true}), + min: new fields.NumberField({ initial: 1, integer: true}), + max: new fields.NumberField({ initial: 6, integer: true}), + }), + damageThresholds: new fields.SchemaField({ + minor: new fields.NumberField({ initial: 0, integer: true }), + major: new fields.NumberField({ initial: 0, integer: true }), + severe: new fields.NumberField({ initial: 0, integer: true }), + }), + evasion: new fields.NumberField({ initial: 0, integer: true }), + // armor: new fields.SchemaField({ + // value: new fields.NumberField({ initial: 0, integer: true }), + // customValue: new fields.NumberField({ initial: null, nullable: true }), + // }), + experiences: new fields.ArrayField(new fields.SchemaField({ + id: new fields.StringField({ required: true }), + level: new fields.NumberField({ required: true, integer: true }), + description: new fields.StringField({}), + value: new fields.NumberField({ integer: true, nullable: true, initial: null }), + }), { + initial: [ + { id: foundry.utils.randomID(), level: 1, description: '', value: 2 }, + { id: foundry.utils.randomID(), level: 1, description: '', value: 2 }, + ] + }), + gold: new fields.SchemaField({ + coins: new fields.NumberField({ initial: 0, integer: true }), + handfulls: new fields.NumberField({ initial: 0, integer: true }), + bags: new fields.NumberField({ initial: 0, integer: true }), + chests: new fields.NumberField({ initial: 0, integer: true }), + }), + pronouns: new fields.StringField({}), + domainData: new fields.SchemaField({ + maxLoadout: new fields.NumberField({ initial: 2, integer: true }), + maxCards: new fields.NumberField({ initial: 2, integer: true }), + }), + levelData: new fields.SchemaField({ + currentLevel: new fields.NumberField({ initial: 1, integer: true }), + changedLevel: new fields.NumberField({ initial: 1, integer: true }), + levelups: new MappingField(new fields.SchemaField({ + level: new fields.NumberField({ required: true, integer: true }), + tier1: new fields.SchemaField({ + ...levelUpTier() + }), + tier2: new fields.SchemaField({ + ...levelUpTier() + }, { nullable: true, initial: null }), + tier3: new fields.SchemaField({ + ...levelUpTier() + }, { nullable: true, initial: null }), + })), + }), + story: new fields.SchemaField({ + background: new fields.HTMLField(), + appearance: new fields.HTMLField(), + connections: new fields.HTMLField(), + scars: new fields.ArrayField(new fields.SchemaField({ + name: new fields.StringField({}), + description: new fields.HTMLField(), + })), + }), + description: new fields.StringField({}), + //Temporary until new FoundryVersion fix --> See Armor.Mjs DataPreparation + armorMarks: new fields.SchemaField({ + max: new fields.NumberField({ initial: 6, integer: true }), + value: new fields.NumberField({ initial: 0, integer: true }), + }), + } + } + + get canLevelUp(){ + // return Object.values(this.levels.data).some(x => !x.completed); + return this.levelData.currentLevel !== this.levelData.changedLevel; + } + + get tier(){ + return this.#getTier(this.levelData.currentLevel); + } + + get ancestry(){ + return this.parent.items.find(x => x.type === 'ancestry') ?? null; + } + + get class(){ + return this.parent.items.find(x => x.type === 'class' && !x.system.multiclass) ?? null; + } + + get multiclass(){ + return this.parent.items.find(x => x.type === 'class' && x.system.multiclass) ?? null; + } + + get multiclassSubclass(){ + return this.parent.items.find(x => x.type === 'subclass' && x.system.multiclass) ?? null; + } + + get subclass(){ + return this.parent.items.find(x => x.type === 'subclass' && !x.system.multiclass) ?? null; + } + + get subclassFeatures(){ + const subclass = this.subclass; + const multiclass = this.multiclassSubclass; + const subclassItems = this.parent.items.filter(x => x.type === 'feature' && x.system.type === 'subclass'); + return { + subclass: !subclass ? {} : { + foundation: subclassItems.filter(x => subclass.system.foundationFeature.abilities.some(ability => ability.uuid === x.uuid)), + specialization: subclassItems.filter(x => subclass.system.specializationFeature.abilities.some(ability => ability.uuid === x.uuid)), + mastery: subclassItems.filter(x => subclass.system.masteryFeature.abilities.some(ability => ability.uuid === x.uuid)), + }, + multiclassSubclass: !multiclass ? {} : { + foundation: subclassItems.filter(x => multiclass.system.foundationFeature.abilities.some(ability => ability.uuid === x.uuid)), + specialization: subclassItems.filter(x => multiclass.system.specializationFeature.abilities.some(ability => ability.uuid === x.uuid)), + mastery: subclassItems.filter(x => multiclass.system.masteryFeature.abilities.some(ability => ability.uuid === x.uuid)), + } + } + } + + get community(){ + return this.parent.items.find(x => x.type === 'community') ?? null; + } + + get classFeatures(){ + return this.parent.items.filter(x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.class.id && !x.system.multiclass); + } + + get multiclassFeatures(){ + return this.parent.items.filter(x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.class.id && x.system.multiclass); + } + + get domains(){ + const classDomains = this.class ? this.class.system.domains : []; + const multiclassDomains = this.multiclass ? this.multiclass.system.domains : []; + return [...classDomains, ...multiclassDomains] + } + + get domainCards(){ + const domainCards = this.parent.items.filter(x => x.type === 'domainCard'); + const loadout = domainCards.filter(x => !x.system.inVault); + const vault = domainCards.filter(x => x.system.inVault); + + return { + loadout: loadout, + vault: vault, + total: [...loadout, ...vault] + }; + } + + get armor(){ + return this.parent.items.find(x => x.type === 'armor'); + } + + get activeWeapons(){ + const primaryWeapon = this.parent.items.find(x => x.type === 'weapon' && x.system.active && !x.system.secondary); + const secondaryWeapon = this.parent.items.find(x => x.type === 'weapon' && x.system.active && x.system.secondary); + return { + primary: this.#weaponData(primaryWeapon), + secondary: this.#weaponData(secondaryWeapon), + burden: this.getBurden(primaryWeapon, secondaryWeapon) + }; + } + + get inventoryWeapons(){ + const inventoryWeaponFirst = this.parent.items.find(x => x.type === 'weapon' && x.system.inventoryWeapon === 1); + const inventoryWeaponSecond = this.parent.items.find(x => x.type === 'weapon' && x.system.inventoryWeapon === 2); + return { + first: this.#weaponData(inventoryWeaponFirst), + second: this.#weaponData(inventoryWeaponSecond), + }; + } + + get totalAttributeMarks(){ + return Object.keys(this.levelData.levelups).reduce((nr, level) => { + const nrAttributeMarks = Object.keys(this.levelData.levelups[level]).reduce((nr, tier) => { + nr += Object.keys(this.levelData.levelups[level][tier]?.attributes ?? {}).length * 2; + + return nr; + }, 0); + + nr.push(...Array(nrAttributeMarks).fill(Number.parseInt(level))); + + return nr; + }, []); + } + + get availableAttributeMarks(){ + const attributeMarks = Object.keys(this.attributes).flatMap(y => this.attributes[y].levelMarks); + return this.totalAttributeMarks.reduce((acc, attribute) => { + if(!attributeMarks.findSplice(x => x === attribute)){ + acc.push(attribute); + } + + return acc; + }, []); + } + + get effects(){ + return this.parent.items.reduce((acc, item) => { + const effects = item.system.effectData; + if(effects && !item.system.disabled){ + for(var key in effects){ + const effect = effects[key]; + for(var effectEntry of effect){ + if(!acc[key]) acc[key] = []; + acc[key].push({ name: item.name, value: effectEntry }); + } + } + } + + return acc; + }, {}); + } + + get refreshableFeatures(){ + return this.parent.items.reduce((acc, x) => { + if(x.type === 'feature' && x.system.refreshData.type){ + acc[x.system.refreshData.type].push(x); + } + + return acc; + }, { shortRest: [], longRest: [] }); + } + + #weaponData(weapon){ + return weapon ? { + name: weapon.name, + trait: CONFIG.daggerheart.ACTOR.abilities[weapon.system.trait].name, //Should not be done in data? + range: CONFIG.daggerheart.GENERAL.range[weapon.system.range], + damage: { + value: weapon.system.damage.value, + type: CONFIG.daggerheart.GENERAL.damageTypes[weapon.system.damage.type], + }, + feature: CONFIG.daggerheart.ITEM.weaponFeatures[weapon.system.feature], + img: weapon.img, + uuid: weapon.uuid + } : null + } + + prepareDerivedData(){ + this.resources.hope.max = 6 - this.story.scars.length; + if(this.resources.hope.value >= this.resources.hope.max){ + this.resources.hope.value = Math.max(this.resources.hope.max-1, 0); + } + + for(var attributeKey in this.attributes){ + const attribute = this.attributes[attributeKey]; + + attribute.levelMark = attribute.levelMarks.find(x => this.isSameTier(x)) ?? null; + + const actualValue = attribute.data.base + attribute.levelMarks.length + attribute.data.bonus; + attribute.data.actualValue = actualValue; + attribute.data.value = attribute.data.overrideValue ? attribute.data.overrideValue : attribute.data.actualValue; + } + + this.evasion = this.class?.system?.evasion ?? 0; + // this.armor.value = this.activeArmor?.baseScore ?? 0; + this.damageThresholds = this.class?.system?.damageThresholds ?? { minor: 0, major: 0, severe: 0 }; + + this.applyLevels(); + this.applyEffects(); + } + + applyLevels(){ + let healthBonus = 0, stressBonus = 0, proficiencyBonus = 0, evasionBonus = 0, armorBonus = 0, minorThresholdBonus = 0, majorThresholdBonus = 0, severeThresholdBonus = 0; + let experienceBonuses = {}; + let advancementFirst = null, advancementSecond = null; + for(var level in this.levelData.levelups){ + var levelData = this.levelData.levelups[level]; + for(var tier in levelData){ + var tierData = levelData[tier]; + if(tierData){ + healthBonus += Object.keys(tierData.hitPointSlots).length; + stressBonus += Object.keys(tierData.stressSlots).length; + proficiencyBonus += Object.keys(tierData.proficiency).length; + advancementFirst = Object.keys(tierData.subclass).length > 0 && (level >= 5 && level <= 7) ? { ...tierData.subclass[0], tier: getTier(Number.parseInt(level), true) } : advancementFirst; + advancementSecond = Object.keys(tierData.subclass).length > 0 && (level >= 8 && level <= 10) ? { ...tierData.subclass[0], tier: getTier(Number.parseInt(level), true) } : advancementSecond; + + for(var index in Object.keys(tierData.experiences)){ + for(var experienceKey in tierData.experiences[index]){ + var experience = tierData.experiences[index][experienceKey]; + experienceBonuses[experience] = experienceBonuses[experience] ? experienceBonuses[experience]+1 : 1; + } + } + + evasionBonus += Object.keys(tierData.armorOrEvasionSlot).filter(x => tierData.armorOrEvasionSlot[x] === 'evasion').length; + armorBonus += Object.keys(tierData.armorOrEvasionSlot).filter(x => tierData.armorOrEvasionSlot[x] === 'armor').length; + + majorThresholdBonus += Object.keys(tierData.majorDamageThreshold2).length * 2; + severeThresholdBonus += Object.keys(tierData.severeDamageThreshold2).length * 2; + severeThresholdBonus += Object.keys(tierData.severeDamageThreshold3).length * 3; + severeThresholdBonus += Object.keys(tierData.severeDamageThreshold4).length * 4; + } + } + } + + this.resources.health.max += healthBonus; + this.resources.stress.max += stressBonus; + this.proficiency.value += proficiencyBonus; + this.evasion += evasionBonus; + this.armorMarks = { + max: this.armor ? this.armor.system.marks.max + armorBonus : 0, + value: this.armor ? this.armor.system.marks.value : 0, + }; + this.damageThresholds.minor += minorThresholdBonus; + this.damageThresholds.major += majorThresholdBonus; + this.damageThresholds.severe += severeThresholdBonus; + + this.experiences = this.experiences.map(x => ({ ...x, value: x.value + (experienceBonuses[x.id] ?? 0) })); + + const subclassFeatures = this.subclassFeatures; + if(advancementFirst){ + if(advancementFirst.multiclass){ + this.multiclassSubclass.system[`${advancementFirst.feature}Feature`].unlocked = true; + this.multiclassSubclass.system[`${advancementFirst.feature}Feature`].tier = advancementFirst.tier; + subclassFeatures.multiclassSubclass[advancementFirst.feature].forEach(x => x.system.disabled = false); + } else { + this.subclass.system[`${advancementFirst.feature}Feature`].unlocked = true; + this.subclass.system[`${advancementFirst.feature}Feature`].tier = advancementFirst.tier; + subclassFeatures.subclass[advancementFirst.feature].forEach(x => x.system.disabled = false); + } + } + if(advancementSecond){ + if(advancementSecond.multiclass){ + this.multiclassSubclass.system[`${advancementSecond.feature}Feature`].unlocked = true; + this.multiclassSubclass.system[`${advancementSecond.feature}Feature`].tier = advancementSecond.tier; + subclassFeatures.multiclassSubclass[advancementSecond.feature].forEach(x => x.system.disabled = false); + } else { + this.subclass.system[`${advancementSecond.feature}Feature`].unlocked = true; + this.subclass.system[`${advancementSecond.feature}Feature`].tier = advancementSecond.tier; + subclassFeatures.subclass[advancementSecond.feature].forEach(x => x.system.disabled = false); + } + } + + + //General progression + for(var i = 0; i < this.levelData.currentLevel; i++){ + const tier = getTier(i+1); + if(tier !== 'tier0'){ + this.domainData.maxLoadout = Math.min(this.domainData.maxLoadout+1, 5); + this.domainData.maxCards += 1; + } + + switch(tier){ + case 'tier1': + this.damageThresholds.severe += 2; + break; + case 'tier2': + this.damageThresholds.major += 1; + this.damageThresholds.severe += 3; + break; + case 'tier3': + this.damageThresholds.major += 2; + this.damageThresholds.severe += 4; + break; + } + } + } + + applyEffects(){ + const effects = this.effects; + for(var key in effects){ + const effectType = effects[key]; + for(var effect of effectType) { + switch(key) { + case SYSTEM.EFFECTS.effectTypes.health.id: + this.resources.health.max += effect.value.valueData.value; + break; + case SYSTEM.EFFECTS.effectTypes.stress.id: + this.resources.stress.max += effect.value.valueData.value; + break; + case SYSTEM.EFFECTS.effectTypes.damage.id: + this.bonuses.damage.push({ + value: getPathValue(effect.value.valueData.value, this), + type: 'physical', + description: effect.name, + hopeIncrease: effect.value.valueData.hopeIncrease, + initiallySelected: effect.value.initiallySelected, + appliesOn: effect.value.appliesOn, + }); + } + } + } + } + + getBurden(primary, secondary){ + const twoHanded = + primary?.system?.burden === 'twoHanded' || + secondary?.system?.burden === 'twoHanded' || + ( + primary?.system?.burden === 'oneHanded' && + secondary?.system?.burden === 'oneHanded' + ); + const oneHanded = + !twoHanded && + ( + primary?.system?.burden === 'oneHanded' || + secondary?.system?.burden === 'oneHanded' + ); + + return twoHanded ? 'twoHanded' : oneHanded ? 'oneHanded' : null; + } + + isSameTier(level){ + return this.#getTier(this.levelData.currentLevel) === this.#getTier(level); + } + + #getTier(level){ + if(level >= 8) return 3; + else if(level >= 5) return 2; + else if(level >= 2) return 1; + else return 0; + } +} \ No newline at end of file diff --git a/module/data/subclass.mjs b/module/data/subclass.mjs new file mode 100644 index 00000000..59080343 --- /dev/null +++ b/module/data/subclass.mjs @@ -0,0 +1,34 @@ +import { getTier } from "../helpers/utils.mjs"; +import featuresSchema from "./interface/featuresSchema.mjs"; +import DaggerheartFeature from './feature.mjs'; + +export default class DhpSubclass extends foundry.abstract.TypeDataModel { + static defineSchema() { + const fields = foundry.data.fields; + return { + description: new fields.HTMLField({}), + spellcastingTrait: new fields.StringField({ choices: SYSTEM.ACTOR.abilities, integer: false, nullable: true, initial: null }), + foundationFeature: new fields.SchemaField({ + description: new fields.HTMLField({}), + abilities: new fields.ArrayField(new fields.EmbeddedDataField(DaggerheartFeature)), + }), + specializationFeature: new fields.SchemaField({ + unlocked: new fields.BooleanField({ initial: false }), + tier: new fields.NumberField({ initial: null, nullable: true, integer: true }), + description: new fields.HTMLField({}), + abilities: new fields.ArrayField(new fields.EmbeddedDataField(DaggerheartFeature)), + }), + masteryFeature: new fields.SchemaField({ + unlocked: new fields.BooleanField({ initial: false }), + tier: new fields.NumberField({ initial: null, nullable: true, integer: true }), + description: new fields.HTMLField({}), + abilities: new fields.ArrayField(new fields.EmbeddedDataField(DaggerheartFeature)), + }), + multiclass: new fields.NumberField({ initial: null, nullable: true, integer: true }), + } + } + + get multiclassTier(){ + return getTier(this.multiclass); + } +} \ No newline at end of file diff --git a/module/data/weapon.mjs b/module/data/weapon.mjs new file mode 100644 index 00000000..aab5e79b --- /dev/null +++ b/module/data/weapon.mjs @@ -0,0 +1,47 @@ +export default class DhpWeapon extends foundry.abstract.TypeDataModel { + static defineSchema() { + const fields = foundry.data.fields; + return { + active: new fields.BooleanField({ initial: false }), + inventoryWeapon: new fields.NumberField({ initial: null, nullable: true, integer: true }), + secondary: new fields.BooleanField({ initial: false }), + trait: new fields.StringField({ choices: SYSTEM.ACTOR.abilities, integer: false }), + range: new fields.StringField({ choices: SYSTEM.GENERAL.range, integer: false }), + damage: new fields.SchemaField({ + value: new fields.StringField({}), + type: new fields.StringField({ choices: SYSTEM.GENERAL.damageTypes, integer: false }), + }), + burden: new fields.StringField({ choices: SYSTEM.GENERAL.burden, integer: false }), + feature: new fields.StringField({ choices: SYSTEM.ITEM.weaponFeatures, integer: false }), + quantity: new fields.NumberField({ initial: 1, integer: true }), + description: new fields.HTMLField({}), + } + } + + prepareDerivedData(){ + if(this.parent.parent){ + this.applyEffects(); + } + } + + applyEffects(){ + const effects = this.parent.parent.system.effects; + for(var key in effects){ + const effectType = effects[key]; + for(var effect of effectType) { + switch(key) { + case SYSTEM.EFFECTS.effectTypes.reach.id: + if(SYSTEM.GENERAL.range[this.range].distance < SYSTEM.GENERAL.range[effect.valueData.value].distance){ + this.range = effect.valueData.value; + } + + break; + // case SYSTEM.EFFECTS.effectTypes.damage.id: + + // if(this.damage.type === 'physical') this.damage.value = (`${this.damage.value} + ${this.parent.parent.system.levelData.currentLevel}`); + // break; + } + } + } + } +} \ No newline at end of file diff --git a/module/dialogs/selectDialog.mjs b/module/dialogs/selectDialog.mjs new file mode 100644 index 00000000..8e3a2046 --- /dev/null +++ b/module/dialogs/selectDialog.mjs @@ -0,0 +1,94 @@ +export default class SelectDialog extends Dialog { + constructor(data, options) { + super(options); + + this.data = { + title: data.title, + buttons: data.buttons, + content: renderTemplate("systems/daggerheart/templates/dialog/item-select.hbs", { + items: data.choices + }), + }; + + this.actor = data.actor; + this.actionCostMax = data.actionCostMax; + this.nrChoices = data.nrChoices; + this.validate= data.validate; + } + + async getData(options={}) { + let buttons = Object.keys(this.data.buttons).reduce((obj, key) => { + let b = this.data.buttons[key]; + b.cssClass = (this.data.default === key ? [key, "default", "bright"] : [key]).join(" "); + if ( b.condition !== false ) obj[key] = b; + return obj; + }, {}); + + const content = await this.data.content; + + return { + content: content, + buttons: buttons + }; + } + + activateListeners(html) { + super.activateListeners(html); + $(html).find('.item-button').click(this.selectChoice); + } + + selectChoice = async (event) => { + if(this.validate){ + if(!this.validate(event.currentTarget.dataset.validateProp)){ + return; + } + } + + event.currentTarget.classList.toggle('checked'); + $(event.currentTarget).find('i')[0].classList.toggle('checked'); + + const buttons = $(this.element[0]).find('button.checked'); + if(buttons.length === this.nrChoices){ + $(event.currentTarget).closest('.window-content').find('.confirm')[0].disabled = false; + } else { + $(event.currentTarget).closest('.window-content').find('.confirm')[0].disabled = true; + } + } + + /** + * + * @param {*} data + * choices, actor, title, cancelMessage, nrChoices, validate + * @returns + */ + static async selectItem(data) { + return this.wait({ + title: data.title ?? "Selection", + buttons: { + no: { + icon: '', + label: game.i18n.localize("DAGGERHEART.General.Cancel"), + callback: _ => { + if(data.cancelMessage){ + ChatMessage.create({content: data.cancelMessage }); + } + return []; + } + }, + confirm: { + icon: '', + label: game.i18n.localize("DAGGERHEART.General.OK"), + callback: html => { + const buttons = $(html).find('button.checked'); + return buttons.map(key => Number.parseInt(buttons[key].dataset.index)).toArray(); + }, + disabled: true + }, + }, + choices: data.choices, + actor: data.actor, + nrChoices: data.nrChoices ?? 1, + validate: data.validate + }); + } +} \ No newline at end of file diff --git a/module/documents/_module.mjs b/module/documents/_module.mjs new file mode 100644 index 00000000..e41e7ee0 --- /dev/null +++ b/module/documents/_module.mjs @@ -0,0 +1,3 @@ +export { default as DhpActor } from './actor.mjs'; +export { default as DhpItem } from './item.mjs'; +export { default as DhpCombat } from './combat.mjs'; \ No newline at end of file diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs new file mode 100644 index 00000000..e599a061 --- /dev/null +++ b/module/documents/actor.mjs @@ -0,0 +1,349 @@ +import DamageSelectionDialog from "../applications/damageSelectionDialog.mjs"; +import NpcRollSelectionDialog from "../applications/npcRollSelectionDialog.mjs"; +import RollSelectionDialog from "../applications/rollSelectionDialog.mjs"; +import { GMUpdateEvent, socketEvent } from "../helpers/socket.mjs"; + +export default class DhpActor extends Actor { + _preCreate(data, changes, user){ + if(data.type === 'pc'){ + data.prototypeToken = { actorLink: true, disposition: 1, sight: { enabled: true } }; + } + + super._preCreate(data, changes, user); + } + + prepareData(){ + super.prepareData(); + } + + async _preUpdate(changed, options, user) { + //Level Down + if(changed.system?.levelData?.changedLevel && this.system.levelData.currentLevel > changed.system.levelData.changedLevel){ + changed.system.levelData.currentLevel = changed.system.levelData.changedLevel; + changed.system.levelData.levelups = Object.keys(this.system.levelData.levelups).reduce((acc, x) => { + if(x > changed.system.levelData.currentLevel){ + acc[`-=${x}`] = null; + } + + return acc; + }, {}); + + changed.system.attributes = Object.keys(this.system.attributes).reduce((acc, key) => { + acc[key] = { levelMarks: this.system.attributes[key].levelMarks.filter(x => x <= changed.system.levelData.currentLevel) }; + + return acc; + }, {}); + + changed.system.experiences = this.system.experiences.filter(x => x.level <= changed.system.levelData.currentLevel); + + if(this.system.multiclass && this.system.multiclass.system.multiclass > changed.system.levelData.changedLevel){ + const multiclassFeatures = this.items.filter(x => x.system.multiclass); + for(var feature of multiclassFeatures){ + await feature.delete(); + } + } + } + + super._preUpdate(changed, options, user); + } + + async diceRoll(modifier, shiftKey) { + if(this.type === 'pc'){ + return await this.dualityRoll(modifier, shiftKey); + } + else { + return await this.npcRoll(modifier, shiftKey); + } + } + + async npcRoll(modifier, shiftKey) { + let nrDice = 1; + let advantage = null; + + const modifiers = [ + { + value: Number.parseInt(modifier.value), + label: modifier.value >= 0 ? `+${modifier.value}` : `-${modifier.value}`, + title: modifier.title, + } + ]; + if(!shiftKey) { + const dialogClosed = new Promise((resolve, _) => { + new NpcRollSelectionDialog(this.system.experiences, resolve).render(true); + }); + const result = await dialogClosed; + + nrDice = result.nrDice; + advantage = result.advantage; + result.experiences.forEach(x => modifiers.push({ value: x.value, label: x.value >= 0 ? `+${x.value}` : `-${x.value}`, title: x.description })) + } + + const roll = new Roll(`${nrDice}d20${advantage === true ? 'kh' : advantage === false ? 'kl': ''} ${modifiers.map(x => `+ ${x.value}`).join(' ')}`); + let rollResult = await roll.evaluate(); + const diceResults = rollResult.dice.flatMap(x => x.results.flatMap(result => ({ value: result.result }))); + + return { roll, diceResults: diceResults, modifiers: modifiers }; + } + + async dualityRoll(modifier, shiftKey, bonusDamage=[]){ + let hopeDice = 'd12', fearDice = 'd12', advantageDice = null, disadvantageDice = null, bonusDamageString = ""; + const modifiers = [ + { + value: Number.parseInt(modifier.value), + label: modifier.value >= 0 ? `+${modifier.value}` : `-${modifier.value}`, + title: modifier.title, + } + ]; + if(!shiftKey) { + const dialogClosed = new Promise((resolve, _) => { + new RollSelectionDialog(this.system.experiences, bonusDamage, this.system.resources.hope.value, resolve).render(true); + }); + const result = await dialogClosed; + hopeDice = result.hope, fearDice = result.fear, advantageDice = result.advantage, disadvantageDice = result.disadvantage; + result.experiences.forEach(x => modifiers.push({ value: x.value, label: x.value >= 0 ? `+${x.value}` : `-${x.value}`, title: x.description })) + bonusDamageString = result.bonusDamage; + + const automateHope = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.Hope); + if(automateHope && result.hopeUsed){ + await this.update({ "system.resources.hope.value": this.system.resources.hope.value - result.hopeUsed }); + } + } + + const roll = new Roll(`1${hopeDice} + 1${fearDice}${advantageDice ? ` + 1${advantageDice}` : disadvantageDice ? ` - 1${disadvantageDice}` : ''} ${modifiers.map(x => `+ ${x.value}`).join(' ')}`); + let rollResult = await roll.evaluate(); + rollResult.dice[0].options.appearance = { + colorset:"inspired", + foreground: "#FFFFFF", + background: "#008080", + outline: "#000000", + edge: "#806400", + texture: "bloodmoon", + material: "metal", + font: "Arial Black", + system: "standard" + }; + if(advantageDice || disadvantageDice){ + rollResult.dice[1].options.appearance = { + colorset:"inspired", + foreground: disadvantageDice ? "#b30000" : "#FFFFFF", + background: "#008080", + outline: disadvantageDice ? "#000000" : "#000000", + edge: "#806400", + texture: "bloodmoon", + material: "metal", + font: "Arial Black", + system: "standard" + }; + rollResult.dice[2].options.appearance = { + colorset:"bloodmoon", + foreground: "#000000", + background: "#430070", + outline: "#b30000", + edge: "#000000", + texture: "bloodmoon", + material: "metal", + font: "Arial Black", + system: "standard" + }; + } + else { + rollResult.dice[1].options.appearance = { + colorset:"bloodmoon", + foreground: "#000000", + background: "#430070", + outline: "#b30000", + edge: "#000000", + texture: "bloodmoon", + material: "metal", + font: "Arial Black", + system: "standard" + }; + } + + const hope = rollResult.dice[0].results[0].result; + const advantage = advantageDice ? rollResult.dice[1].results[0].result : null; + const disadvantage = disadvantageDice ? rollResult.dice[1].results[0].result : null; + const fear = advantage || disadvantage ? rollResult.dice[2].results[0].result : rollResult.dice[1].results[0].result; + + if(disadvantage){ + rollResult = {...rollResult, total: rollResult.total - Math.max(hope, disadvantage) }; + } + if(advantage){ + rollResult = {...rollResult, total: 'Select Hope Die' }; + } + + const automateHope = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.Hope); + if (automateHope && hope > fear){ + await this.update({ "system.resources.hope.value": Math.min(this.system.resources.hope.value+1, this.system.resources.hope.max) }); + } + + if(automateHope && hope === fear){ + await this.update({ "system.resources": { + "hope.value": Math.min(this.system.resources.hope.value+1, this.system.resources.hope.max), + "stress.value": Math.max(this.system.resources.stress.value-1, 0), + }}); + } + + return { roll, rollResult, hope: { dice: hopeDice, value: hope }, fear: { dice: fearDice, value: fear }, advantage: { dice: advantageDice, value: advantage }, disadvantage: { dice: disadvantageDice, value: disadvantage }, modifiers: modifiers, bonusDamageString }; + } + + async damageRoll(damage, shiftKey){ + let rollString = damage.value; + let bonusDamage = damage.bonusDamage?.filter(x => x.initiallySelected) ?? []; + if(!shiftKey) { + const dialogClosed = new Promise((resolve, _) => { + new DamageSelectionDialog(rollString, bonusDamage, this.system.resources.hope.value, resolve).render(true); + }); + const result = await dialogClosed; + bonusDamage = result.bonusDamage; + rollString = result.rollString; + + const automateHope = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.Hope); + if(automateHope && result.hopeUsed){ + await this.update({ "system.resources.hope.value": this.system.resources.hope.value - result.hopeUsed }); + } + } + + const roll = new Roll(rollString); + let rollResult = await roll.evaluate(); + + const dice = []; + const modifiers = []; + for(var i = 0; i < rollResult.terms.length; i++){ + const term = rollResult.terms[i]; + if(term.faces){ + dice.push({type: `d${term.faces}`, value: term.total}); + } + else if (term.operator){ + + } + else if(term.number){ + const operator = i === 0 ? '' : rollResult.terms[i-1].operator; + modifiers.push(`${operator}${term.number}`); + } + } + + const cls = getDocumentClass("ChatMessage"); + const msg = new cls({ + user: game.user.id, + content: await renderTemplate("systems/daggerheart/templates/chat/damage-roll.hbs", { + roll: rollString, + total: rollResult.total, + dice: dice, + modifiers: modifiers + }), + rolls: [roll] + }); + + cls.create(msg.toObject()); + } + + async takeDamage(damage, type){ + const hpDamage = + damage >= this.system.damageThresholds.severe ? 3 : + damage >= this.system.damageThresholds.major ? 2 : + damage >= this.system.damageThresholds.minor ? 1 : + 0; + + const update = { "system.resources.health.value": Math.min(this.system.resources.health.value+hpDamage, this.system.resources.health.max) }; + + if(game.user.isGM){ + await this.update(update); + } else { + await game.socket.emit(`system.${SYSTEM.id}`, { + action: socketEvent.GMUpdate, + data: { + action: GMUpdateEvent.UpdateDocument, + uuid: this.uuid, + update: update, + } + }); + } + } + + async takeHealing(healing, type) { + let update = { }; + switch(type){ + case SYSTEM.GENERAL.healingTypes.health.id: + update = { "system.resources.health.value": Math.max(this.system.resources.health.value - healing, 0) }; + break; + case SYSTEM.GENERAL.healingTypes.stress.id: + update = { "system.resources.stress.value": Math.max(this.system.resources.stress.value - healing, 0) }; + break; + } + + if(game.user.isGM){ + await this.update(update); + } else { + await game.socket.emit(`system.${SYSTEM.id}`, { + action: socketEvent.GMUpdate, + data: { + action: GMUpdateEvent.UpdateDocument, + uuid: this.uuid, + update: update, + } + }); + } + } + + async emulateItemDrop(data) { + const event = new DragEvent("drop", { altKey: game.keyboard.isModifierActive("Alt") }); + return this.sheet._onDropItem(event, { data: data }); + } + + //Move to action-scope? + async useAction(action) { + const userTargets = Array.from(game.user.targets); + const otherTarget = action.target.type ===SYSTEM.ACTIONS.targetTypes.other.id; + if(otherTarget && userTargets.length === 0) { + ui.notifications.error(game.i18n.localize("DAGGERHEART.Notification.Error.ActionRequiresTarget")); + return; + } + + if(action.cost.type != null && action.cost.value != null){ + if (this.system.resources[action.cost.type].value < action.cost.value-1) { + ui.notifications.error(game.i18n.localize(`Insufficient ${action.cost.type} to use this ability`)); + return; + } + } + + // const targets = otherTarget ? userTargets : [game.user.character]; + if(action.damage.type){ + let roll = { formula: action.damage.value, result: action.damage.value }; + if(Number.isNaN(Number.parseInt(action.damage.value))){ + roll = await new Roll(`1${action.damage.value}`).evaluate(); + } + + const cls = getDocumentClass("ChatMessage"); + const msg = new cls({ + user: game.user.id, + content: await renderTemplate("systems/daggerheart/templates/chat/damage-roll.hbs", { + roll: roll.formula, + total: roll.result, + type: action.damage.type, + }), + }); + + cls.create(msg.toObject()); + } + + if(action.healing.type){ + let roll = { formula: action.healing.value, result: action.healing.value }; + if(Number.isNaN(Number.parseInt(action.healing.value))){ + roll = await new Roll(`1${action.healing.value}`).evaluate(); + } + + const cls = getDocumentClass("ChatMessage"); + const msg = new cls({ + user: game.user.id, + content: await renderTemplate("systems/daggerheart/templates/chat/healing-roll.hbs", { + roll: roll.formula, + total: roll.result, + type: action.healing.type, + }), + }); + + cls.create(msg.toObject()); + } + } +} \ No newline at end of file diff --git a/module/documents/combat.mjs b/module/documents/combat.mjs new file mode 100644 index 00000000..cf6e7efb --- /dev/null +++ b/module/documents/combat.mjs @@ -0,0 +1,41 @@ +import { GMUpdateEvent, socketEvent } from "../helpers/socket.mjs"; + +export default class DhpCombat extends Combat { + _sortCombatants(a, b) { + if(a.isNPC !== b.isNPC){ + const aVal = a.isNPC ? 0 : 1; + const bVal = b.isNPC ? 0 : 1; + + return aVal - bVal; + } + + return a.name.localeCompare(b.name); + } + + async useActionToken(combatantId) { + const automateActionPoints = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.ActionPoints); + + if(game.user.isGM){ + if(this.system.actions < 1) return; + + const update = automateActionPoints ? + { "system.activeCombatant": combatantId, "system.actions": Math.max(this.system.actions-1, 0) } : + { "system.activeCombatant": combatantId }; + + await this.update(update); + } else { + const update = automateActionPoints ? + { "system.activeCombatant": combatantId, "system.actions": this.system.actions+1} : + { "system.activeCombatant": combatantId }; + + await game.socket.emit(`system.${SYSTEM.id}`, { + action: socketEvent.GMUpdate, + data: { + action: GMUpdateEvent.UpdateDocument, + uuid: this.uuid, + update: update + } + }); + } + } +} \ No newline at end of file diff --git a/module/documents/item.mjs b/module/documents/item.mjs new file mode 100644 index 00000000..0174b184 --- /dev/null +++ b/module/documents/item.mjs @@ -0,0 +1,72 @@ +export default class DhpItem extends Item { + _preCreate(data, changes, user){ + super._preCreate(data, changes, user); + } + + prepareData(){ + super.prepareData(); + + if(this.type === 'class'){ + // Bad. Make this better. + // this.system.domains = CONFIG.daggerheart.DOMAIN.classDomainMap[Object.keys(CONFIG.daggerheart.DOMAIN.classDomainMap).find(x => x === this.name.toLowerCase())]; + } + } + + isInventoryItem(){ + return ['weapon', 'armor', 'miscellaneous', 'consumable'].includes(this.type); + } + + _onUpdate(data, options, userId) { + super._onUpdate(data, options, userId); + } + + static async createDialog(data = {}, { parent = null, pack = null, ...options } = {}) { + const documentName = this.metadata.name; + const types = game.documentTypes[documentName].filter(t => t !== CONST.BASE_DOCUMENT_TYPE); + let collection; + if ( !parent ) { + if ( pack ) collection = game.packs.get(pack); + else collection = game.collections.get(documentName); + } + const folders = collection?._formatFolderSelectOptions() ?? []; + const label = game.i18n.localize(this.metadata.label); + const title = game.i18n.format("DOCUMENT.Create", {type: label}); + const typeObjects = types.reduce((obj, t) => { + const label = CONFIG[documentName]?.typeLabels?.[t] ?? t; + obj[t] = { value: t, label: game.i18n.has(label) ? game.i18n.localize(label) : t }; + return obj; + }, {}); + + // Render the document creation form + const html = await renderTemplate("systems/daggerheart/templates/sidebar/documentCreate.hbs", { + folders, + name: data.name || game.i18n.format("DOCUMENT.New", {type: label}), + folder: data.folder, + hasFolders: folders.length >= 1, + type: data.type || CONFIG[documentName]?.defaultType || typeObjects.armor, + types: { + Items: [typeObjects.armor, typeObjects.weapon, typeObjects.consumable, typeObjects.miscellaneous], + Character: [typeObjects.class, typeObjects.subclass, typeObjects.ancestry, typeObjects.community, typeObjects.feature, typeObjects.domainCard], + }, + hasTypes: types.length > 1 + }); + + // Render the confirmation dialog window + return Dialog.prompt({ + title: title, + content: html, + label: title, + callback: html => { + const form = html[0].querySelector("form"); + const fd = new FormDataExtended(form); + foundry.utils.mergeObject(data, fd.object, {inplace: true}); + if ( !data.folder ) delete data.folder; + if ( types.length === 1 ) data.type = types[0]; + if ( !data.name?.trim() ) data.name = this.defaultName(); + return this.create(data, {parent, pack, renderSheet: true}); + }, + rejectClose: false, + options + }); + } + } \ No newline at end of file diff --git a/module/helpers/handlebarsHelper.mjs b/module/helpers/handlebarsHelper.mjs new file mode 100644 index 00000000..728f66f9 --- /dev/null +++ b/module/helpers/handlebarsHelper.mjs @@ -0,0 +1,105 @@ +import { getWidthOfText } from "./utils.mjs"; + +export default class RegisterHandlebarsHelpers { + static registerHelpers(){ + Handlebars.registerHelper({ + looseEq: this.looseEq, + times: this.times, + join: this.join, + add: this.add, + subtract: this.subtract, + objectSelector: this.objectSelector, + includes: this.includes, + simpleEditor: this.simpleEditor, + debug: this.debug, + }); + }; + + static looseEq(a, b){ + return a == b; + } + + static times(nr, block){ + var accum = ''; + for(var i = 0; i < nr; ++i) + accum += block.fn(i); + return accum; + } + + static join(...options){ + return options.slice(0, options.length-1); + } + + static add(a, b){ + const aNum = Number.parseInt(a); + const bNum = Number.parseInt(b); + return (Number.isNaN(aNum) ? 0 : aNum) + (Number.isNaN(bNum) ? 0 : bNum); + } + + static subtract(a, b){ + const aNum = Number.parseInt(a); + const bNum = Number.parseInt(b); + return (Number.isNaN(aNum) ? 0 : aNum) - (Number.isNaN(bNum) ? 0 : bNum); + } + + static objectSelector(options){ + let { title, values, titleFontSize, ids, style } = options.hash; + + const titleLength = getWidthOfText(title, titleFontSize, true, true); + const margins = 12; + + const buttons = options.fn(); + const nrButtons = Math.max($(buttons).length-1, 1); + const iconWidth = 26; + + const texts = values.reduce((acc, x, index) => { + if(x){ + acc.push(`${x}`); + } + + return acc; + }, []).join(' '); + + const html = + `
+
+ ${title} +
+ ${texts} +
+ ${buttons} +
+
+ `; + + return new Handlebars.SafeString(html); + } + + static rangePicker(options) { + let {name, value, min, max, step} = options.hash; + name = name || "range"; + value = value ?? ""; + if ( Number.isNaN(value) ) value = ""; + const html = + ` + ${value}`; + return new Handlebars.SafeString(html); + } + + static includes(list, item){ + return list.includes(item); + } + + static simpleEditor(content, options) { + const { target, editable=true, button, engine="tinymce", collaborate=false, class: cssClass } = options.hash; + const config = {name: target, value: content, button, collaborate, editable, engine}; + const element = foundry.applications.fields.createEditorInput(config); + if ( cssClass ) element.querySelector(".editor-content").classList.add(cssClass); + return new Handlebars.SafeString(element.outerHTML); + } + + static debug(a) { + console.log(JSON.stringify(a)); + return a; + } +} \ No newline at end of file diff --git a/module/helpers/socket.mjs b/module/helpers/socket.mjs new file mode 100644 index 00000000..5f4ee737 --- /dev/null +++ b/module/helpers/socket.mjs @@ -0,0 +1,20 @@ +export function handleSocketEvent({action=null, data={}}={}) { + switch (action) { + case socketEvent.GMUpdate: + Hooks.callAll(socketEvent.GMUpdate, data.action, data.uuid, data.update); + break; + case socketEvent.DhpFearUpdate: + Hooks.callAll(socketEvent.DhpFearUpdate); + break; + } +} + +export const socketEvent = { + GMUpdate: "DhpGMUpdate", + DhpFearUpdate: "DhpFearUpdate", +}; + +export const GMUpdateEvent = { + UpdateDocument: "DhpGMUpdateDocument", + UpdateFear: "DhpUpdateFear" +}; \ No newline at end of file diff --git a/module/helpers/utils.mjs b/module/helpers/utils.mjs new file mode 100644 index 00000000..796bfab8 --- /dev/null +++ b/module/helpers/utils.mjs @@ -0,0 +1,82 @@ +export const loadCompendiumOptions = async (compendiums) => { + const compendiumValues = []; + + for(var compendium of compendiums){ + const values = await getCompendiumOptions(compendium); + compendiumValues.push(values); + } + + return compendiumValues; +}; + +const getCompendiumOptions = async (compendium) => { + const compendiumPack = await game.packs.get(compendium); + + const values = []; + for(var value of compendiumPack.index){ + const document = await compendiumPack.getDocument(value._id); + values.push(document); + } + + return values; +}; + +export const getWidthOfText = (txt, fontsize, allCaps, bold) => { + // if(getWidthOfText.e === undefined){ + // getWidthOfText.e = document.createElement('span'); + // getWidthOfText.e.style.display = "none"; + // document.body.appendChild(getWidthOfText.e); + // } + // if(getWidthOfText.e.style.fontSize !== fontsize) + // getWidthOfText.e.style.fontSize = fontsize; + // if(getWidthOfText.e.style.fontFamily !== 'Signika, sans-serif') + // getWidthOfText.e.style.fontFamily = 'Signika, sans-serif'; + // getWidthOfText.e.innerText = txt; + // return getWidthOfText.e.offsetWidth; + const text = allCaps ? txt.toUpperCase() : txt; + if(getWidthOfText.c === undefined){ + getWidthOfText.c=document.createElement('canvas'); + getWidthOfText.ctx=getWidthOfText.c.getContext('2d'); + } + var fontspec = `${bold ? 'bold': ''} ${fontsize}px` + ' ' + 'Signika, sans-serif'; + if(getWidthOfText.ctx.font !== fontspec) + getWidthOfText.ctx.font = fontspec; + + return getWidthOfText.ctx.measureText(text).width; +} + +export const padArray = (arr, len, fill) => { + return arr.concat(Array(len).fill(fill)).slice(0,len); +} + +export const getTier = (level, asNr) => { + switch(Math.floor((level+1)/3)){ + case 1: + return asNr ? 1 : 'tier1'; + case 2: + return asNr ? 2 : 'tier2'; + case 3: + return asNr ? 3 : 'tier3'; + default: + return asNr ? 0 : 'tier0'; + } +} + +export const capitalize = (string) => { + return string.charAt(0).toUpperCase() + string.slice(1); +} + +export const getPathValue = (path, entity, numeric) => { + const pathValue = foundry.utils.getProperty(entity, path); + if(pathValue) return numeric ? Number.parseInt(pathValue) : pathValue; + + return numeric ? Number.parseInt(path) : path; +}; + +export const generateId = (title, length) => { + const id = title.split(" ").map((w, i) => { + const p = w.slugify({replacement: "", strict: true}); + return i ? p.titleCase() : p; + }).join(""); + return Number.isNumeric(length) ? id.slice(0, length).padEnd(length, "0") : id; +} \ No newline at end of file diff --git a/module/ui/chatLog.mjs b/module/ui/chatLog.mjs new file mode 100644 index 00000000..c8931c46 --- /dev/null +++ b/module/ui/chatLog.mjs @@ -0,0 +1,103 @@ +export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLog { + constructor(){ + super(); + + this.targetTemplate = { + activeLayer: undefined, + document: undefined, + object: undefined, + minimizedSheets: [], + config: undefined, + targets: undefined + } + this.setupHooks(); + } + + addChatListeners = async (app, html, data) => { + html.querySelectorAll('.roll-damage-button').forEach(element => element.addEventListener('click', event => this.onRollDamage(event, data.message))); + html.querySelectorAll('.target-container').forEach(element => element.addEventListener('hover', hover(this.hoverTarget, this.unhoverTarget))); // ???? + // html.find('.target-container').mouseout(this.unhoverTarget); + html.querySelectorAll('.damage-button').forEach(element => element.addEventListener('click', this.onDamage)); + html.querySelectorAll('.healing-button').forEach(element => element.addEventListener('click', this.onHealing)); + html.querySelectorAll('.target-indicator').forEach(element => element.addEventListener('click', this.onToggleTargets)); + html.querySelectorAll('.advantage').forEach(element => element.hover(this.hoverAdvantage)); // ?? + html.querySelectorAll('.advantage').forEach(element => element.addEventListener('click', event => this.selectAdvantage.bind(this)(event, data.message))); + html.querySelectorAll('.ability-use-button').forEach(element => element.addEventListener('click', this.abilityUseButton.bind(this)(event, data.message))); + } + + setupHooks(){ + Hooks.on('renderChatMessageHTML', this.addChatListeners.bind()); + } + + close(options){ + Hooks.off('renderChatMessageHTML', this.addChatListeners); + super.close(options); + } + + onRollDamage = async (event, message) => { + event.stopPropagation(); + + await game.user.character.damageRoll(message.system.damage, event.shiftKey); + }; + + hoverTarget = (event) => { + event.stopPropagation(); + const token = canvas.tokens.get(event.currentTarget.dataset.token); + if ( !token.controlled ) token._onHoverIn(event, {hoverOutOthers: true}); + } + + unhoverTarget = (event) => { + const token = canvas.tokens.get(event.currentTarget.dataset.token); + if ( !token.controlled ) token._onHoverOut(event); + }; + + onDamage = async (event) => { + event.stopPropagation(); + const damage = Number.parseInt(event.currentTarget.dataset.value); + const targets = Array.from(game.user.targets); + + if(targets.length === 0) ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.NoTargetsSelected")); + + for(var target of targets){ + await target.actor.takeDamage(damage, event.currentTarget.dataset.type); + } + }; + + onHealing = async (event) => { + event.stopPropagation(); + const healing = Number.parseInt(event.currentTarget.dataset.value); + const targets = Array.from(game.user.targets); + + if(targets.length === 0) ui.notifications.info(game.i18n.localize("DAGGERHEART.Notification.Info.NoTargetsSelected")); + + for(var target of targets){ + await target.actor.takeHealing(healing, event.currentTarget.dataset.type); + } + } + + onToggleTargets = async (event) => { + event.stopPropagation(); + $($(event.currentTarget).parent()).find('.target-container').toggleClass('hidden'); + }; + + hoverAdvantage = (event) => { + $(event.currentTarget).siblings('.advantage').toggleClass('unused'); + }; + + selectAdvantage = async (event, message) => { + event.stopPropagation(); + + const updateMessage = game.messages.get(message._id); + await updateMessage.update({ system: { advantageSelected: event.currentTarget.id === 'hope' ? 1 : 2 }}); + + $(event.currentTarget).siblings('.advantage').off('click'); + $(event.currentTarget).off('click'); + } + + abilityUseButton = async (event, message) => { + event.stopPropagation(); + + const action = message.system.actions[Number.parseInt(event.currentTarget.dataset.index)]; + await game.user.character.useAction(action); + } +} \ No newline at end of file diff --git a/module/ui/combatTracker.mjs b/module/ui/combatTracker.mjs new file mode 100644 index 00000000..8ee6b3d3 --- /dev/null +++ b/module/ui/combatTracker.mjs @@ -0,0 +1,200 @@ +import { GMUpdateEvent, socketEvent } from "../helpers/socket.mjs"; + +export default class DhpCombatTracker extends foundry.applications.sidebar.tabs.CombatTracker { + constructor(data, context) { + super(data, context); + + Hooks.on(socketEvent.DhpFearUpdate, this.onFearUpdate); + } + + get template(){ + return 'systems/daggerheart/templates/ui/combatTracker.hbs'; + } + + activateListeners(html) { + super.activateListeners(html); + html.on("click", ".token-action-tokens .use-action-token", this.useActionToken.bind(this)); + html.on("click", ".encounter-gm-resources .trade-actions", this.tradeActions.bind(this)); + html.on("click", ".encounter-gm-resources .trade-fear", this.tradeFear.bind(this)); + html.on("click", ".encounter-gm-resources .icon-button.up", this.increaseResource.bind(this)); + html.on("click", ".encounter-gm-resources .icon-button.down", this.decreaseResource.bind(this)); + } + + async useActionToken(event){ + event.stopPropagation(); + const combatant = event.currentTarget.dataset.combatant; + await game.combat.useActionToken(combatant); + } + + async tradeActions(event){ + if(event.currentTarget.classList.contains('disabled')) return; + + const currentFear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear); + const value = currentFear+1; + + if(value <= 6){ + Hooks.callAll(socketEvent.GMUpdate,GMUpdateEvent.UpdateFear, null, value); + await game.socket.emit(`system.${SYSTEM.id}`, { + action: socketEvent.GMUpdate, + data: { action: GMUpdateEvent.UpdateFear, update: value }, + }); + await game.combat.update({ "system.actions": game.combat.system.actions-2 }); + } + } + + async tradeFear(){ + if(event.currentTarget.classList.contains('disabled')) return; + + const currentFear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear); + const value = currentFear-1; + if(value >= 0){ + Hooks.callAll(socketEvent.GMUpdate,GMUpdateEvent.UpdateFear, null, value); + await game.socket.emit(`system.${SYSTEM.id}`, { + action: socketEvent.GMUpdate, + data: { action: GMUpdateEvent.UpdateFear, update: value }, + }); + await game.combat.update({ "system.actions": game.combat.system.actions+2 }); + } + } + + async increaseResource(event) { + if(event.currentTarget.dataset.type === 'action'){ + await game.combat.update({ "system.actions": game.combat.system.actions+1 }); + } + + const currentFear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear); + const value = currentFear+1; + if(event.currentTarget.dataset.type === 'fear' && value <= 6){ + Hooks.callAll(socketEvent.GMUpdate,GMUpdateEvent.UpdateFear, null, value); + await game.socket.emit(`system.${SYSTEM.id}`, { + action: socketEvent.GMUpdate, + data: { action: GMUpdateEvent.UpdateFear, update: value }, + }); + } + + this.render(); + } + + async decreaseResource(event) { + if(event.currentTarget.dataset.type === 'action' && game.combat.system.actions-1 >= 0){ + await game.combat.update({ "system.actions": game.combat.system.actions-1 }); + } + + const currentFear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear); + const value = currentFear-1; + if(event.currentTarget.dataset.type === 'fear' && value >= 0){ + Hooks.callAll(socketEvent.GMUpdate,GMUpdateEvent.UpdateFear, null, value); + await game.socket.emit(`system.${SYSTEM.id}`, { + action: socketEvent.GMUpdate, + data: { action: GMUpdateEvent.UpdateFear, update: value }, + }); + } + + this.render(); + } + + async getData(options={}) { + let context = await super.getData(options); + + // Get the combat encounters possible for the viewed Scene + const combat = this.viewed; + const hasCombat = combat !== null; + const combats = this.combats; + const currentIdx = combats.findIndex(c => c === combat); + const previousId = currentIdx > 0 ? combats[currentIdx-1].id : null; + const nextId = currentIdx < combats.length - 1 ? combats[currentIdx+1].id : null; + const settings = game.settings.get("core", Combat.CONFIG_SETTING); + + // Prepare rendering data + context = foundry.utils.mergeObject(context, { + combats: combats, + currentIndex: currentIdx + 1, + combatCount: combats.length, + hasCombat: hasCombat, + combat, + turns: [], + previousId, + nextId, + started: this.started, + control: false, + settings, + linked: combat?.scene !== null, + labels: {} + }); + context.labels.scope = game.i18n.localize(`COMBAT.${context.linked ? "Linked" : "Unlinked"}`); + if ( !hasCombat ) return context; + + // Format information about each combatant in the encounter + let hasDecimals = false; + const turns = []; + for ( let [i, combatant] of combat.turns.entries() ) { + if ( !combatant.visible ) continue; + + // Prepare turn data + const resource = combatant.permission >= CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER ? combatant.resource : null; + const turn = { + id: combatant.id, + name: combatant.name, + img: await this._getCombatantThumbnail(combatant), + active: combatant.id === combat.system.activeCombatant, + owner: combatant.isOwner, + defeated: combatant.isDefeated, + hidden: combatant.hidden, + initiative: combatant.initiative, + hasRolled: combatant.initiative !== null, + hasResource: resource !== null, + resource: resource, + canPing: (combatant.sceneId === canvas.scene?.id) && game.user.hasPermission("PING_CANVAS"), + playerCharacter: game.user?.character?.id === combatant.actor.id, + ownedByPlayer: combatant.hasPlayerOwner, + }; + if ( (turn.initiative !== null) && !Number.isInteger(turn.initiative) ) hasDecimals = true; + turn.css = [ + turn.active ? "active" : "", + turn.hidden ? "hidden" : "", + turn.defeated ? "defeated" : "" + ].join(" ").trim(); + + // Actor and Token status effects + turn.effects = new Set(); + if ( combatant.token ) { + combatant.token.effects.forEach(e => turn.effects.add(e)); + if ( combatant.token.overlayEffect ) turn.effects.add(combatant.token.overlayEffect); + } + if ( combatant.actor ) { + for ( const effect of combatant.actor.temporaryEffects ) { + if ( effect.statuses.has(CONFIG.specialStatusEffects.DEFEATED) ) turn.defeated = true; + else if ( effect.icon ) turn.effects.add(effect.icon); + } + } + turns.push(turn); + } + + // Format initiative numeric precision + const precision = CONFIG.Combat.initiative.decimals; + turns.forEach(t => { + if ( t.initiative !== null ) t.initiative = t.initiative.toFixed(hasDecimals ? precision : 0); + }); + + const fear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear); + + // Merge update data for rendering + return foundry.utils.mergeObject(context, { + round: combat.round, + turn: combat.turn, + turns: turns, + control: combat.combatant?.players?.includes(game.user), + fear: fear, + }); + } + + onFearUpdate = async () => { + this.render(true); + } + + async close(options){ + Hooks.off(socketEvent.DhpFearUpdate, this.onFearUpdate); + + return super.close(options); + } +} \ No newline at end of file diff --git a/module/ui/players.mjs b/module/ui/players.mjs new file mode 100644 index 00000000..829148eb --- /dev/null +++ b/module/ui/players.mjs @@ -0,0 +1,53 @@ +import { GMUpdateEvent, socketEvent } from "../helpers/socket.mjs"; + +export default class DhpPlayers extends foundry.applications.ui.Players { + constructor(data, context) { + super(data, context); + + Hooks.on(socketEvent.DhpFearUpdate, this.onFearUpdate); + } + + get template(){ + return 'systems/daggerheart/templates/ui/players.hbs'; + } + + async getData(options={}) { + const context = super.getData(options); + context.fear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear); + context.user = game.user; + + return context; + } + + activateListeners(html) { + // Toggle online/offline + html.find(".players-mode").click(this._onToggleOfflinePlayers.bind(this)); + html.find(".fear-control.up").click(async event => await this.updateFear(event, 1)); + html.find(".fear-control.down").click(async event => await this.updateFear(event, -1)); + + // Context menu + const contextOptions = this._getUserContextOptions(); + Hooks.call("getUserContextOptions", html, contextOptions); + new ContextMenu(html, ".player", contextOptions); + } + + async updateFear(_, change){ + const fear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear); + const value = Math.max(Math.min(fear+change, 6), 0); + Hooks.callAll(socketEvent.GMUpdate,GMUpdateEvent.UpdateFear, null, value); + await game.socket.emit(`system.${SYSTEM.id}`, { + action: socketEvent.GMUpdate, + data: { action: GMUpdateEvent.UpdateFear, update: value }, + }); + } + + onFearUpdate = async () => { + this.render(true); + } + + async close(options){ + Hooks.off(socketEvent.DhpFearUpdate, this.onFearUpdate); + + return super.close(options); + } +} \ No newline at end of file diff --git a/module/ui/ruler.mjs b/module/ui/ruler.mjs new file mode 100644 index 00000000..565c7217 --- /dev/null +++ b/module/ui/ruler.mjs @@ -0,0 +1,29 @@ +export default class DhpRuler extends foundry.canvas.interaction.Ruler { + _getSegmentLabel(segment, totalDistance) { + const range = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.General.RangeMeasurement); + if(!range.enabled) return super._getSegmentLabel(segment, totalDistance); + + const segmentDistance = Math.round(segment.distance * 100) / 100; + const totalDistanceValue = Math.round(totalDistance * 100) / 100; + + return `${this.#getRangeLabel(segmentDistance, range)} [${this.#getRangeLabel(totalDistanceValue, range)}]`; + } + + #getRangeLabel(distance, settings){ + if(distance <= settings.melee){ + return game.i18n.localize("DAGGERHEART.Range.Melee.Name"); + } + if(distance <= settings.veryClose){ + return game.i18n.localize("DAGGERHEART.Range.VeryClose.Name"); + } + if(distance <= settings.close){ + return game.i18n.localize("DAGGERHEART.Range.Close.Name"); + } + if(distance <= settings.far){ + return game.i18n.localize("DAGGERHEART.Range.Far.Name"); + } + if(distance <= settings.veryFar){ + return game.i18n.localize("DAGGERHEART.Range.VeryFar.Name"); + } + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..61c94ce7 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6291 @@ +{ + "name": "daggerheart", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "@yaireo/tagify": "^4.17.9", + "gulp": "^4.0.2", + "gulp-less": "^5.0.0" + }, + "devDependencies": { + "@foundryvtt/foundryvtt-cli": "^1.0.2", + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-node-resolve": "^15.2.3", + "concurrently": "^8.2.2", + "postcss": "^8.4.32", + "rollup-plugin-postcss": "^4.0.2" + } + }, + "node_modules/@babel/runtime": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz", + "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@foundryvtt/foundryvtt-cli": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@foundryvtt/foundryvtt-cli/-/foundryvtt-cli-1.0.2.tgz", + "integrity": "sha512-pERML7ViBiqwP11NS1kci0Q38t4h557F/Mj+DjYmmgumMJIZqDsVv2XU3bwOJS7+6yzbUmUc2/jRD6EIx+U/fw==", + "dev": true, + "dependencies": { + "chalk": "^5.2.0", + "classic-level": "^1.2.0", + "esm": "^3.2.25", + "js-yaml": "^4.1.0", + "mkdirp": "^3.0.0", + "nedb-promises": "^6.2.1", + "yargs": "^17.7.1" + }, + "bin": { + "fvtt": "fvtt.mjs" + }, + "engines": { + "node": ">17.0.0" + } + }, + "node_modules/@foundryvtt/foundryvtt-cli/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@foundryvtt/foundryvtt-cli/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@foundryvtt/foundryvtt-cli/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@foundryvtt/foundryvtt-cli/node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/@foundryvtt/foundryvtt-cli/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@foundryvtt/foundryvtt-cli/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@foundryvtt/foundryvtt-cli/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@foundryvtt/foundryvtt-cli/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@foundryvtt/foundryvtt-cli/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@foundryvtt/foundryvtt-cli/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@foundryvtt/foundryvtt-cli/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@rollup/plugin-commonjs": { + "version": "25.0.7", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.7.tgz", + "integrity": "sha512-nEvcR+LRjEjsaSsc4x3XZfCCvZIaSMenZu/OiwOKGN2UhQpAYI7ru7czFvyWbErlpoGjnSX3D5Ch5FcMA3kRWQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "glob": "^8.0.3", + "is-reference": "1.2.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.68.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "15.2.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", + "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.2.1", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", + "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@seald-io/binary-search-tree": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@seald-io/binary-search-tree/-/binary-search-tree-1.0.3.tgz", + "integrity": "sha512-qv3jnwoakeax2razYaMsGI/luWdliBLHTdC6jU55hQt1hcFqzauH/HsBollQ7IR4ySTtYhT+xyHoijpA16C+tA==", + "dev": true + }, + "node_modules/@seald-io/nedb": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@seald-io/nedb/-/nedb-4.0.4.tgz", + "integrity": "sha512-CUNcMio7QUHTA+sIJ/DC5JzVNNsHe743TPmC4H5Gij9zDLMbmrCT2li3eVB72/gF63BPS8pWEZrjlAMRKA8FDw==", + "dev": true, + "dependencies": { + "@seald-io/binary-search-tree": "^1.0.3", + "localforage": "^1.9.0", + "util": "^0.12.4" + } + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "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/@yaireo/tagify": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/@yaireo/tagify/-/tagify-4.22.2.tgz", + "integrity": "sha512-R2QSHX3eCJiAf7kIoTojlMbjHiS271z5V2XLyVf4VvgPVQpXBNFskI41DyaDiMS5enXZ13j8kmm92GI+QmgdnQ==", + "engines": { + "node": ">=14.20.0", + "npm": ">=8.0.0" + }, + "peerDependencies": { + "prop-types": "^15.7.2" + } + }, + "node_modules/abstract-level": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abstract-level/-/abstract-level-1.0.4.tgz", + "integrity": "sha512-eUP/6pbXBkMbXFdx4IH2fVgvB7M0JvR7/lIL33zcs0IBcwjdzSSl31TOJsaCzmKSSDF9h8QYSOJux4Nd4YJqFg==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "catering": "^2.1.0", + "is-buffer": "^2.0.5", + "level-supports": "^4.0.0", + "level-transcoder": "^1.0.1", + "module-error": "^1.0.1", + "queue-microtask": "^1.2.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/abstract-level/node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, + "node_modules/ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dependencies": { + "ansi-wrap": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-gray": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "integrity": "sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dependencies": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "node_modules/anymatch/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==", + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/append-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", + "integrity": "sha512-WLbYiXzD3y/ATLZFufV/rZvWdZOs+Z/+5v1rBZ463Jn398pa6kcde27cvozYnBoxXblGZTFfoPpsaEw0orU5BA==", + "dependencies": { + "buffer-equal": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-filter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", + "integrity": "sha512-A2BETWCqhsecSvCkWAeVBFLH6sXEUGASuzkpjL3GR1SlL/PWL6M3J8EAAld2Uubmh39tvkJTqC9LeLHCUKmFXA==", + "dependencies": { + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", + "integrity": "sha512-tVqVTHt+Q5Xb09qRkbu+DidW1yYzz5izWS2Xm2yFm7qJnmUfz4HPzNxbHkdRJbz2lrqI7S+z17xNYdFcBBO8Hw==", + "dependencies": { + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-initial": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", + "integrity": "sha512-BC4Yl89vneCYfpLrs5JU2aAu9/a+xWbeKhvISg9PT7eWFB9UlRvI+rKEtk6mgxWr3dSkk9gQ8hCrdqt06NXPdw==", + "dependencies": { + "array-slice": "^1.0.0", + "is-number": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-initial/node_modules/is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-last": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", + "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", + "dependencies": { + "is-number": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-last/node_modules/is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-sort": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", + "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", + "dependencies": { + "default-compare": "^1.0.0", + "get-value": "^2.0.6", + "kind-of": "^5.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/async-done": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", + "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.2", + "process-nextick-args": "^2.0.0", + "stream-exhaust": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/async-each": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.6.tgz", + "integrity": "sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/async-settle": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", + "integrity": "sha512-VPXfB4Vk49z1LHHodrEQ6Xf7W4gg1w0dAPROHngx7qgDjqmIQ+fXmwgGXTW/ITLai0YLSvWepJOP9EVpMnEAcw==", + "dependencies": { + "async-done": "^1.2.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "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==", + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/bach": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", + "integrity": "sha512-bZOOfCb3gXBXbTFXq3OZtGR88LwGeJvzu6szttaIzymOTS4ZttBNOWSv7aLZja2EMycKtRYV0Oa8SNKH/zkxvg==", + "dependencies": { + "arr-filter": "^1.1.1", + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "array-each": "^1.0.0", + "array-initial": "^1.0.0", + "array-last": "^1.1.1", + "async-done": "^1.2.2", + "async-settle": "^1.0.0", + "now-and-later": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dependencies": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "optional": true, + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.1.tgz", + "integrity": "sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg==", + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dependencies": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001599", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz", + "integrity": "sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/catering": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", + "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "deprecated": "Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies", + "dependencies": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + }, + "optionalDependencies": { + "fsevents": "^1.2.7" + } + }, + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/classic-level": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/classic-level/-/classic-level-1.4.1.tgz", + "integrity": "sha512-qGx/KJl3bvtOHrGau2WklEZuXhS3zme+jf+fsu6Ej7W7IP/C49v7KNlWIsT1jZu0YnfzSIYDGcEWpCa1wKGWXQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "abstract-level": "^1.0.2", + "catering": "^2.1.0", + "module-error": "^1.0.1", + "napi-macros": "^2.2.2", + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==", + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==" + }, + "node_modules/cloneable-readable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", + "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", + "dependencies": { + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/collection-map": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", + "integrity": "sha512-5D2XXSpkOnleOI21TG7p3T0bGAsZ/XknZpKBmGYyluO8pw4zA3K8ZlrBIbC4FXg3m6z/RNFiUFfT2sQK01+UHA==", + "dependencies": { + "arr-map": "^2.0.2", + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", + "dependencies": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "dev": true + }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-with-sourcemaps": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz", + "integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==", + "dev": true, + "dependencies": { + "source-map": "^0.6.1" + } + }, + "node_modules/concurrently": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-8.2.2.tgz", + "integrity": "sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2", + "date-fns": "^2.30.0", + "lodash": "^4.17.21", + "rxjs": "^7.8.1", + "shell-quote": "^1.8.1", + "spawn-command": "0.0.2", + "supports-color": "^8.1.1", + "tree-kill": "^1.2.2", + "yargs": "^17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": "^14.13.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/concurrently/node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/concurrently/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/concurrently/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/concurrently/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "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==" + }, + "node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dependencies": { + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/copy-props": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.5.tgz", + "integrity": "sha512-XBlx8HSqrT0ObQwmSzM7WE5k8FxTV75h1DX1Z3n6NhQ/UYYAvInWYmG06vFt7hQZArE2fuO62aihiWIVQwh1sw==", + "dependencies": { + "each-props": "^1.3.2", + "is-plain-object": "^5.0.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==" + }, + "node_modules/css-declaration-sorter": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", + "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "5.1.15", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz", + "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", + "dev": true, + "dependencies": { + "cssnano-preset-default": "^5.2.14", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-preset-default": { + "version": "5.2.14", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", + "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", + "dev": true, + "dependencies": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.1", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.4", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.2", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", + "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dev": true, + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "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==", + "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", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", + "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", + "dependencies": { + "kind-of": "^5.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-resolution": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", + "integrity": "sha512-2xaP6GiwVwOEbXCGoJ4ufgC76m8cj805jrghScewJC2ZDsb9U0b4BIrba+xt/Uytyd0HvQ6+WymSRTfnYj59GQ==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", + "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", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/each-props": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", + "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", + "dependencies": { + "is-plain-object": "^2.0.1", + "object.defaults": "^1.1.0" + } + }, + "node_modules/each-props/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.711", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.711.tgz", + "integrity": "sha512-hRg81qzvUEibX2lDxnFlVCHACa+LtrCPIsWAxo161LDYIB3jauf57RGsMZV9mvGwE98yGH06icj3zBEoOkxd/w==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "optional": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "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, + "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==", + "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==", + "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==", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", + "dev": true, + "engines": { + "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==", + "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/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/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==", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "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==", + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fancy-log": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", + "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", + "dependencies": { + "ansi-gray": "^0.1.1", + "color-support": "^1.1.3", + "parse-node-version": "^1.0.0", + "time-stamp": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/fast-levenshtein": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz", + "integrity": "sha512-Ia0sQNrMPXXkqVFt6w6M1n1oKo3NfKs+mvaV811Jwir7vAk9a6PVV9VPYf6X3BU97QiLEmuW3uXH9u87zDFfdw==" + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "optional": true + }, + "node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/fined": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "dependencies": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/fined/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/flagged-respawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dependencies": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fs-mkdirp-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", + "integrity": "sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==", + "dependencies": { + "graceful-fs": "^4.1.11", + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/fs-mkdirp-stream/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "deprecated": "The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generic-names": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-4.0.0.tgz", + "integrity": "sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==", + "dev": true, + "dependencies": { + "loader-utils": "^3.2.0" + } + }, + "node_modules/get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "node_modules/glob-parent/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-stream": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", + "integrity": "sha512-uMbLGAP3S2aDOHUDfdoYcdIePUCfysbAd0IAoWVZbeGU/oNQ8asHVSshLDJUPWxfzj8zsCG7/XeHPHTtow0nsw==", + "dependencies": { + "extend": "^3.0.0", + "glob": "^7.1.1", + "glob-parent": "^3.1.0", + "is-negated-glob": "^1.0.0", + "ordered-read-streams": "^1.0.0", + "pumpify": "^1.3.5", + "readable-stream": "^2.1.5", + "remove-trailing-separator": "^1.0.1", + "to-absolute-glob": "^2.0.0", + "unique-stream": "^2.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/glob-stream/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob-stream/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-stream/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/glob-watcher": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz", + "integrity": "sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==", + "dependencies": { + "anymatch": "^2.0.0", + "async-done": "^1.2.0", + "chokidar": "^2.0.0", + "is-negated-glob": "^1.0.0", + "just-debounce": "^1.0.0", + "normalize-path": "^3.0.0", + "object.defaults": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glogg": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", + "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", + "dependencies": { + "sparkles": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/gulp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", + "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", + "dependencies": { + "glob-watcher": "^5.0.3", + "gulp-cli": "^2.2.0", + "undertaker": "^1.2.1", + "vinyl-fs": "^3.0.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-cli": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz", + "integrity": "sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==", + "dependencies": { + "ansi-colors": "^1.0.1", + "archy": "^1.0.0", + "array-sort": "^1.0.0", + "color-support": "^1.1.3", + "concat-stream": "^1.6.0", + "copy-props": "^2.0.1", + "fancy-log": "^1.3.2", + "gulplog": "^1.0.0", + "interpret": "^1.4.0", + "isobject": "^3.0.1", + "liftoff": "^3.1.0", + "matchdep": "^2.0.0", + "mute-stdout": "^1.0.0", + "pretty-hrtime": "^1.0.0", + "replace-homedir": "^1.0.0", + "semver-greatest-satisfied-range": "^1.1.0", + "v8flags": "^3.2.0", + "yargs": "^7.1.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-less": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/gulp-less/-/gulp-less-5.0.0.tgz", + "integrity": "sha512-W2I3TewO/By6UZsM/wJG3pyK5M6J0NYmJAAhwYXQHR+38S0iDtZasmUgFCH3CQj+pQYw/PAIzxvFvwtEXz1HhQ==", + "dependencies": { + "less": "^3.7.1 || ^4.0.0", + "object-assign": "^4.0.1", + "plugin-error": "^1.0.0", + "replace-ext": "^2.0.0", + "through2": "^4.0.0", + "vinyl-sourcemaps-apply": "^0.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/gulplog": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", + "integrity": "sha512-hm6N8nrm3Y08jXie48jsC55eCZz9mnb4OirAStEk2deqeyhXU3C1otDVh+ccttMuc1sBi6RX6ZJ720hs9RCvgw==", + "dependencies": { + "glogg": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-replace-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", + "integrity": "sha512-chIaY3Vh2mh2Q3RGXttaDIzeiPvaVXJ+C4DAh/w3c37SKZ/U6PGMmuicR2EQQp9bKG8zLMCl7I+PtIoOOPp8Gg==", + "dev": true + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true + }, + "node_modules/import-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-3.0.0.tgz", + "integrity": "sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==", + "dev": true, + "dependencies": { + "import-from": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz", + "integrity": "sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dependencies": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", + "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==", + "dependencies": { + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", + "dependencies": { + "binary-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", + "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", + "dependencies": { + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true + }, + "node_modules/is-negated-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dependencies": { + "is-unc-path": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dependencies": { + "unc-path-regex": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==" + }, + "node_modules/is-valid-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", + "integrity": "sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==" + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "engines": { + "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==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "peer": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "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==" + }, + "node_modules/just-debounce": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.1.0.tgz", + "integrity": "sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==" + }, + "node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/last-run": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", + "integrity": "sha512-U/VxvpX4N/rFvPzr3qG5EtLKEnNI0emvIQB3/ecEwv+8GHaUKbIB8vxv1Oai5FAF0d0r7LXHhLLe5K/yChm5GQ==", + "dependencies": { + "default-resolution": "^2.0.0", + "es6-weak-map": "^2.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==", + "dependencies": { + "invert-kv": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lead": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", + "integrity": "sha512-IpSVCk9AYvLHo5ctcIXxOBpMWUe+4TKN3VPWAKUbJikkmsGp0VrSM8IttVc32D6J4WUsiPE6aEFRNmIoF/gdow==", + "dependencies": { + "flush-write-stream": "^1.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/less": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", + "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", + "dependencies": { + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" + } + }, + "node_modules/level-supports": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-4.0.1.tgz", + "integrity": "sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/level-transcoder": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/level-transcoder/-/level-transcoder-1.0.1.tgz", + "integrity": "sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "module-error": "^1.0.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/lie": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", + "integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==", + "dev": true, + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/liftoff": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", + "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", + "dependencies": { + "extend": "^3.0.0", + "findup-sync": "^3.0.0", + "fined": "^1.0.1", + "flagged-respawn": "^1.0.0", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.0", + "rechoir": "^0.6.2", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/liftoff/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/load-json-file/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/localforage": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz", + "integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==", + "dev": true, + "dependencies": { + "lie": "3.1.1" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "peer": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.8", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", + "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "optional": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/make-iterator/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", + "integrity": "sha512-LFgVbaHIHMqCRuCZyfCtUOq9/Lnzhi7Z0KFUE2fhD54+JN2jLh3hC02RLkqauJ3U4soU6H1J3tfj/Byk7GoEjA==", + "dependencies": { + "findup-sync": "^2.0.0", + "micromatch": "^3.0.4", + "resolve": "^1.4.0", + "stack-trace": "0.0.10" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/matchdep/node_modules/findup-sync": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha512-vs+3unmJT45eczmcAZ6zMJtxN3l/QXeccaXQx5cu/MeJMhewVfoWZqibRkOxPnmoR59+Zy5hjabfQc6JLSah4g==", + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/matchdep/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "dev": true + }, + "node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "dev": true, + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/module-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/module-error/-/module-error-1.0.2.tgz", + "integrity": "sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/mute-stdout": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", + "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/nan": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz", + "integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==", + "optional": true + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/napi-macros": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.2.2.tgz", + "integrity": "sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g==", + "dev": true + }, + "node_modules/nedb-promises": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/nedb-promises/-/nedb-promises-6.2.3.tgz", + "integrity": "sha512-enq0IjNyBz9Qy9W/QPCcLGh/QORGBjXbIeZeWvIjO3OMLyAvlKT3hiJubP2BKEiFniUlR3L01o18ktqgn5jxqA==", + "dev": true, + "dependencies": { + "@seald-io/nedb": "^4.0.2" + } + }, + "node_modules/needle": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", + "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "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==" + }, + "node_modules/node-gyp-build": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz", + "integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==", + "dev": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/now-and-later": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", + "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", + "dependencies": { + "once": "^1.3.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", + "dependencies": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", + "dependencies": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==", + "dependencies": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.reduce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", + "integrity": "sha512-naLhxxpUESbNkRqc35oQ2scZSJueHGQNUfMW/0U37IgN6tE2dgDWg3whf+NEliy3F/QysrO48XKUz/nGPe+AQw==", + "dependencies": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/ordered-read-streams": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", + "integrity": "sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==", + "dependencies": { + "readable-stream": "^2.0.1" + } + }, + "node_modules/os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==", + "dependencies": { + "lcid": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-queue": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dev": true, + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", + "dependencies": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==" + }, + "node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", + "dependencies": { + "path-root-regex": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", + "dependencies": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-type/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/plugin-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "dependencies": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/plugin-error/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/plugin-error/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/plugin-error/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.4.37", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.37.tgz", + "integrity": "sha512-7iB/v/r7Woof0glKLH8b1SPHrsX7uhdO+Geb41QpF/+mWZHU3uxxSlN+UXGVit1PawOYDToO+AbZzhBzWRDwbQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-calc": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", + "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-colormin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", + "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-convert-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", + "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-comments": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", + "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", + "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-empty": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", + "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", + "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-load-config": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", + "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", + "dev": true, + "dependencies": { + "lilconfig": "^2.0.5", + "yaml": "^1.10.2" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-merge-longhand": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", + "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-merge-rules": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", + "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^3.1.0", + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", + "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", + "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", + "dev": true, + "dependencies": { + "colord": "^2.9.1", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-params": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", + "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", + "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-modules": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-4.3.1.tgz", + "integrity": "sha512-ItUhSUxBBdNamkT3KzIZwYNNRFKmkJrofvC2nWab3CPKhYBQ1f27XXh1PAPE27Psx58jeelPsxWB/+og+KEH0Q==", + "dev": true, + "dependencies": { + "generic-names": "^4.0.0", + "icss-replace-symbols": "^1.1.0", + "lodash.camelcase": "^4.3.0", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "string-hash": "^1.1.1" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.4.tgz", + "integrity": "sha512-L4QzMnOdVwRm1Qb8m4x8jsZzKAaPAgrUF1r/hjDR2Xj7R+8Zsf97jAlSQzWtKx5YNiNGN8QxmPFIc/sh+RQl+Q==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.1.1.tgz", + "integrity": "sha512-uZgqzdTleelWjzJY+Fhti6F3C9iF1JR/dODLs/JDefozYcKTBCdD8BIl6nNPbTbcLnGrk56hzwZC2DaGNvYjzA==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", + "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", + "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", + "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", + "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-string": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", + "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", + "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", + "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", + "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", + "dev": true, + "dependencies": { + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", + "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-ordered-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", + "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", + "dev": true, + "dependencies": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", + "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", + "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.16", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", + "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-svgo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", + "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", + "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", + "engines": { + "node": ">= 0.8" + } + }, + "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==" + }, + "node_modules/promise.series": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/promise.series/-/promise.series-0.2.0.tgz", + "integrity": "sha512-VWQJyU2bcDTgZw8kpfBpB/ejZASlCrzwz5f2hjb/zlujOEB4oeiAhHygAWq8ubsX2GVkD4kCU5V2dwOTaCY5EQ==", + "dev": true, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "peer": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "optional": true + }, + "node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dependencies": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "peer": true + }, + "node_modules/read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", + "dependencies": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", + "dependencies": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "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/readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dependencies": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dependencies": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regex-not/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regex-not/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regex-not/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/remove-bom-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", + "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", + "dependencies": { + "is-buffer": "^1.1.5", + "is-utf8": "^0.2.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/remove-bom-stream": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", + "integrity": "sha512-wigO8/O08XHb8YPzpDDT+QmRANfW6vLqxfaXm1YXhnFf3AkSLyjfG3GEFg4McZkmgL7KvCj5u2KczkvSP6NfHA==", + "dependencies": { + "remove-bom-buffer": "^3.0.0", + "safe-buffer": "^5.1.0", + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remove-bom-stream/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==" + }, + "node_modules/repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/replace-ext": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz", + "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/replace-homedir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", + "integrity": "sha512-CHPV/GAglbIB1tnQgaiysb8H2yCy8WQ7lcEwQ/eT+kLj0QHV8LnJW0zpqpE7RSkrMSRoa+EBoag86clf7WAgSg==", + "dependencies": { + "homedir-polyfill": "^1.0.1", + "is-absolute": "^1.0.0", + "remove-trailing-separator": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-options": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", + "integrity": "sha512-NYDgziiroVeDC29xq7bp/CacZERYsA9bXYd1ZmcJlF3BcrZv5pTb4NG7SjdyKDnXZ84aC4vo2u6sNKIA1LCu/A==", + "dependencies": { + "value-or-function": "^3.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", + "deprecated": "https://github.com/lydell/resolve-url#deprecated" + }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "engines": { + "node": ">=0.12" + } + }, + "node_modules/rollup-plugin-postcss": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-postcss/-/rollup-plugin-postcss-4.0.2.tgz", + "integrity": "sha512-05EaY6zvZdmvPUDi3uCcAQoESDcYnv8ogJJQRp6V5kZ6J6P7uAVJlrTZcaaA20wTH527YTnKfkAoPxWI/jPp4w==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "concat-with-sourcemaps": "^1.1.0", + "cssnano": "^5.0.1", + "import-cwd": "^3.0.0", + "p-queue": "^6.6.2", + "pify": "^5.0.0", + "postcss-load-config": "^3.0.0", + "postcss-modules": "^4.0.0", + "promise.series": "^0.2.0", + "resolve": "^1.19.0", + "rollup-pluginutils": "^2.8.2", + "safe-identifier": "^0.4.2", + "style-inject": "^0.3.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "postcss": "8.x" + } + }, + "node_modules/rollup-plugin-postcss/node_modules/pify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", + "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "dev": true, + "dependencies": { + "estree-walker": "^0.6.1" + } + }, + "node_modules/rollup-pluginutils/node_modules/estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "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==" + }, + "node_modules/safe-identifier": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/safe-identifier/-/safe-identifier-0.4.2.tgz", + "integrity": "sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w==", + "dev": true + }, + "node_modules/safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", + "dependencies": { + "ret": "~0.1.10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "optional": true + }, + "node_modules/sax": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", + "optional": true + }, + "node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/semver-greatest-satisfied-range": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", + "integrity": "sha512-Ny/iyOzSSa8M5ML46IAx3iXc6tfOsYU2R4AXi2UpHk60Zrgyq6eqPj/xiOfS0rRl/iiQ/rdJkVjw/5cdUyCntQ==", + "dependencies": { + "sver-compat": "^1.5.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shell-quote": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dependencies": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dependencies": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dependencies": { + "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/snapdragon/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map": { + "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" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "node_modules/source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "deprecated": "See https://github.com/lydell/source-map-url#deprecated" + }, + "node_modules/sparkles": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", + "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/spawn-command": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz", + "integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==", + "dev": true + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", + "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==" + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility", + "dev": true + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "engines": { + "node": "*" + } + }, + "node_modules/static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/stream-exhaust": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", + "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==" + }, + "node_modules/stream-shift": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==" + }, + "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==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", + "integrity": "sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==", + "dev": true + }, + "node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", + "dependencies": { + "is-utf8": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/style-inject": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/style-inject/-/style-inject-0.3.0.tgz", + "integrity": "sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==", + "dev": true + }, + "node_modules/stylehacks": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", + "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sver-compat": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", + "integrity": "sha512-aFTHfmjwizMNlNE6dsGmoAM4lHjL0CyiobWaFiXWSlD7cIxshW422Nb8KbXCmR6z+0ZEPY+daXJrDyh/vuwTyg==", + "dependencies": { + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dev": true, + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/through2-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", + "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", + "dependencies": { + "through2": "~2.0.0", + "xtend": "~4.0.0" + } + }, + "node_modules/through2-filter/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/through2/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/time-stamp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", + "integrity": "sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-absolute-glob": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", + "integrity": "sha512-rtwLUQEwT8ZeKQbyFJyomBRYXyE16U5VKuy0ftxLMK/PZb2fkOsg5r9kHdauuVDbsNdIBoC/HCthpidamQFXYA==", + "dependencies": { + "is-absolute": "^1.0.0", + "is-negated-glob": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dependencies": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-through": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", + "integrity": "sha512-+QIz37Ly7acM4EMdw2PRN389OneM5+d844tirkGp4dPKzI5OE72V9OsbFp+CIYJDahZ41ZV05hNtcPAQUAm9/Q==", + "dependencies": { + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/to-through/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==" + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + }, + "node_modules/unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/undertaker": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.3.0.tgz", + "integrity": "sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg==", + "dependencies": { + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "bach": "^1.0.0", + "collection-map": "^1.0.0", + "es6-weak-map": "^2.0.1", + "fast-levenshtein": "^1.0.0", + "last-run": "^1.1.0", + "object.defaults": "^1.0.0", + "object.reduce": "^1.0.0", + "undertaker-registry": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/undertaker-registry": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", + "integrity": "sha512-UR1khWeAjugW3548EfQmL9Z7pGMlBgXteQpr1IZeZBtnkCJQJIJ1Scj0mb9wQaPvUZ9Q17XqW6TIaPchJkyfqw==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unique-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", + "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", + "dependencies": { + "json-stable-stringify-without-jsonify": "^1.0.1", + "through2-filter": "^3.0.0" + } + }, + "node_modules/unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", + "dependencies": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", + "dependencies": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", + "deprecated": "Please see https://github.com/lydell/urix#deprecated" + }, + "node_modules/use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/v8flags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/value-or-function": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", + "integrity": "sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", + "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==", + "dependencies": { + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl-fs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", + "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", + "dependencies": { + "fs-mkdirp-stream": "^1.0.0", + "glob-stream": "^6.1.0", + "graceful-fs": "^4.0.0", + "is-valid-glob": "^1.0.0", + "lazystream": "^1.0.0", + "lead": "^1.0.0", + "object.assign": "^4.0.4", + "pumpify": "^1.3.5", + "readable-stream": "^2.3.3", + "remove-bom-buffer": "^3.0.0", + "remove-bom-stream": "^1.2.0", + "resolve-options": "^1.1.0", + "through2": "^2.0.0", + "to-through": "^2.0.0", + "value-or-function": "^3.0.0", + "vinyl": "^2.0.0", + "vinyl-sourcemap": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl-fs/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/vinyl-sourcemap": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", + "integrity": "sha512-NiibMgt6VJGJmyw7vtzhctDcfKch4e4n9TBeoWlirb7FMg9/1Ov9k+A5ZRAtywBpRPiyECvQRQllYM8dECegVA==", + "dependencies": { + "append-buffer": "^1.0.2", + "convert-source-map": "^1.5.0", + "graceful-fs": "^4.1.6", + "normalize-path": "^2.1.1", + "now-and-later": "^2.0.0", + "remove-bom-buffer": "^3.0.0", + "vinyl": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl-sourcemap/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==", + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/vinyl-sourcemaps-apply": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz", + "integrity": "sha512-+oDh3KYZBoZC8hfocrbrxbLUeaYtQK7J5WU5Br9VqWqmCll3tFJqKp97GC9GmMsVIL0qnx2DgEDVxdo5EZ5sSw==", + "dependencies": { + "source-map": "^0.5.1" + } + }, + "node_modules/vinyl-sourcemaps-apply/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/vinyl/node_modules/replace-ext": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz", + "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==" + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "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==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", + "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==" + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.2.tgz", + "integrity": "sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==", + "dependencies": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^5.0.1" + } + }, + "node_modules/yargs-parser": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.1.tgz", + "integrity": "sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==", + "dependencies": { + "camelcase": "^3.0.0", + "object.assign": "^4.1.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..ce58d439 --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "dependencies": { + "@yaireo/tagify": "^4.17.9", + "gulp": "^4.0.2", + "gulp-less": "^5.0.0", + "rollup": "^4.40.0" + }, + "scripts": { + "start": "concurrently \"rollup -c --watch\" \"node C:/FoundryDev/resources/app/main.js --dataPath=C:/FoundryDevFiles --noupnp\" \"gulp\"", + "start-test": "node C:/FoundryDev/resources/app/main.js --dataPath=C:/FoundryDevFiles && rollup -c --watch && gulp", + "pushLDBtoYML": "node ./tools/pushLDBtoYML.mjs", + "pullYMLtoLDB": "node ./tools/pullYMLtoLDB.mjs" + }, + "devDependencies": { + "@foundryvtt/foundryvtt-cli": "^1.0.2", + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-node-resolve": "^15.2.3", + "postcss": "^8.4.32", + "rollup-plugin-postcss": "^4.0.2", + "concurrently": "^8.2.2" + } +} diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 00000000..f75aa23c --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +/** @type {import('postcss-load-config').Config} */ +const config = { + plugins: [] +} + + module.exports = config \ No newline at end of file diff --git a/rollup.config.mjs b/rollup.config.mjs new file mode 100644 index 00000000..c3894007 --- /dev/null +++ b/rollup.config.mjs @@ -0,0 +1,29 @@ +import postcss from 'rollup-plugin-postcss'; +import commonjs from '@rollup/plugin-commonjs'; +import resolve from '@rollup/plugin-node-resolve'; + +export default { + input: 'daggerheart.mjs', + output: { + file: 'build/daggerheart.js', + format: 'cjs', + sourcemap: true, + }, + plugins: [ + postcss({ + config: { + path: './postcss.config.js' + }, + use: { + less: { javascriptEnabled: true } + }, + extensions: ['.less'], + extract: false + }), + commonjs({ + include: /node_modules/, + requireReturnsDefault: 'auto', + }), + resolve() + ], +} \ No newline at end of file diff --git a/src/packs/classes/class_Test_Class_h9wTtM4iczXHqvf8.json b/src/packs/classes/class_Test_Class_h9wTtM4iczXHqvf8.json new file mode 100644 index 00000000..34439c44 --- /dev/null +++ b/src/packs/classes/class_Test_Class_h9wTtM4iczXHqvf8.json @@ -0,0 +1,70 @@ +{ + "name": "Test Class", + "type": "class", + "img": "icons/svg/item-bag.svg", + "system": { + "domains": [], + "classItems": [], + "damageThresholds": { + "minor": 0, + "major": 0, + "severe": 0 + }, + "evasion": 0, + "features": [], + "subclasses": [], + "inventory": { + "take": [], + "choiceA": [], + "choiceB": [], + "extra": null + }, + "characterGuide": { + "suggestedTraits": { + "agility": 0, + "strength": 0, + "finesse": 0, + "instinct": 0, + "presence": 0, + "knowledge": 0 + }, + "suggestedPrimaryWeapon": null, + "suggestedSecondaryWeapon": null, + "suggestedArmor": null, + "characterDescription": {}, + "backgroundQuestions": [ + "", + "", + "" + ], + "connections": [ + "", + "", + "" + ] + }, + "multiclass": null, + "description": "" + }, + "effects": [], + "folder": null, + "ownership": { + "default": 0, + "HeB5VwikUgL2Hxck": 3 + }, + "flags": {}, + "_stats": { + "compendiumSource": null, + "duplicateSource": null, + "exportSource": null, + "coreVersion": "13.342", + "systemId": "daggerheart", + "systemVersion": "0.0.1", + "createdTime": 1747924765406, + "modifiedTime": 1747924765406, + "lastModifiedBy": "HeB5VwikUgL2Hxck" + }, + "_id": "h9wTtM4iczXHqvf8", + "sort": 0, + "_key": "!items!h9wTtM4iczXHqvf8" +} diff --git a/styles/application.less b/styles/application.less new file mode 100644 index 00000000..51874a98 --- /dev/null +++ b/styles/application.less @@ -0,0 +1,562 @@ +form.daggerheart.views.downtime { // Shouldn't be needed, but DEFAULT_OPTIONS doesn't accept Height: 'auto' + height: auto !important; +} + +div.daggerheart.views.death-move { // Shouldn't be needed, but DEFAULT_OPTIONS doesn't accept Height: 'auto' + height: auto !important; +} + +div.daggerheart.views.multiclass { // Shouldn't be needed, but DEFAULT_OPTIONS doesn't accept Height: 'auto' + height: auto !important; +} + +.daggerheart.views { + &.levelup { + .levelup-title-container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: 32px; + margin-bottom: 4px; + + .level-title { + text-decoration: underline; + } + + .level-display { + display: flex; + align-items: center; + + i { + margin: 0 @halfMargin; + } + } + } + + .levelup-section { + display: flex; + align-items: flex-start; + margin-bottom: 8px; + font-size: 11px; + + .levelup-container { + flex: 1; + + &:nth-of-type(2) { + padding: 0 4px; + } + + &.disabled { + opacity: 0.2; + } + + .levelup-inner-container { + height: 700px; + padding: 24px 58px 0; + display: flex; + flex-direction: column; + align-items: center; + position: relative; + + .levelup-legend { + margin-left: auto; + margin-right: auto; + font-weight: bold; + z-index: 1; + } + + .levelup-info { + background: @primaryAccent; + width: 100%; + text-align: center; + position: absolute; + top: -6px; + padding: 8px 0; + } + + .levelup-pretext { + padding: 8px 0; + } + + .levelup-body { + display: flex; + flex-direction: column; + + .levelup-choice-row { + display: flex; + align-items: center; + padding: 4px; + + .levelup-choice-row-inner { + display: flex; + align-items: center; + } + + .levelup-choice-input-container { + position: relative; + display: flex; + align-items: center; + + input { + &:disabled:checked::before { + opacity: 0.4; + color: var(--color-warm-1); + } + } + + i.fa-link { + transform: rotate(45deg); + position: relative; + top: 2px; + margin: 0 -3px; + } + + i.fa-lock { + position: absolute; + top: 0; + left: 0; + font-size: 8px; + } + } + } + } + + .levelup-posttext { + padding: 8px 0; + } + } + } + } + } + + .downtime-container { + .activity-container { + display: flex; + align-items: center; + padding: 8px; + + .activity-title { + flex: 1; + display: flex; + align-items: center; + + .activity-title-text { + font-size: 24px; + font-weight: bold; + } + + .activity-image { + width: 120px; + border: 2px solid black; + border-radius: 50%; + margin-right: 8px; + cursor: pointer; + + &:hover, &.selected { + filter: drop-shadow(0 0 6px gold); + } + } + + .custom-name-input { + font-size: 24px; + font-weight: bold; + padding: 0; + background: transparent; + color: rgb(239, 230, 216); + } + } + + .activity-body { + flex: 1; + font-style: italic; + } + } + } + + &.downtime { + .activity-text-area { + resize: none; + } + } + + .range-reset { + flex: 0; + width: 21px; + height: 21px; + margin: 3px 4px; + border: 1px solid black; + display: flex; + align-items: center; + justify-content: center; + } + + &.roll-selection { + .roll-selection-container { + i { + filter: invert(0%) sepia(100%) saturate(0%) hue-rotate(21deg) brightness(17%) contrast(103%); + } + } + + .roll-dialog-container { + .disadvantage, .advantage { + border: 2px solid @secondaryAccent; + border-radius: 6px; + display: flex; + align-items: center; + padding: 4px; + margin-bottom: 6px; + + &.selected { + filter: drop-shadow(0px 0px 3px @mainShadow); + } + + input { + border: 0; + } + + button { + flex: 0; + border-radius: 50%; + height: 20px; + width: 20px; + display: flex; + align-items: center; + justify-content: center; + margin: 2px 0 2px 4px; + padding: 12px; + + i { + margin: 0; + } + } + } + + .roll-dialog-experience-container { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: @halfMargin; + + .roll-dialog-chip { + border: @thinBorder solid black; + border-radius: 6px; + min-width: calc(33% - 2px); + flex: 1; + display: flex; + align-items: center; + justify-content: center; + gap: @halfMargin; + cursor: pointer; + padding: @fullPadding; + background: grey; + overflow: hidden; + font-weight: bold; + + &.hover { + filter: drop-shadow(0 0 3px @mainShadow); + } + + span { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + + &.selected { + background: green; + + span { + filter: drop-shadow(0 0 3px @secondaryShadow); + } + } + } + } + + .hope-container { + display: flex; + gap: @fullMargin; + align-items: center; + font-size: 18px; + } + } + } + + &.npc-roll-selection { + .npc-roll-dialog-container { + display: flex; + flex-direction: column; + + .selection-container { + display: flex; + align-items: center; + margin-bottom: @fullMargin; + + .dice-container { + display: flex; + align-items: center; + flex: 1; + + .dice-inner-container{ + position: relative; + display: flex; + align-items: center; + + i { + font-size: 18px; + } + + img { + border: 0; + position: relative; + left: 1px; + } + + .dice-number { + position: absolute; + top: calc(50% - 14px); + left: calc(50% - 7px); + font-size: 24px; + font-weight: bold; + } + } + } + } + + .roll-dialog-experience-container { + display: flex; + align-items: flex-start; + flex-wrap: wrap; + gap: @halfMargin; + flex: 2; + height: 100%; + + .roll-dialog-chip { + border: @thinBorder solid black; + border-radius: 6px; + flex-basis: calc(50% - 2px); + display: flex; + align-items: center; + justify-content: space-between; + cursor: pointer; + padding: @fullPadding; + background: grey; + overflow: hidden; + + &.hover { + filter: drop-shadow(0 0 3px @mainShadow); + } + + span { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + + &.selected i { + color: green; + } + } + } + } + } + + &.multiclass { + .multiclass-container { + margin-bottom: @largeMargin; + + .multiclass-category-title { + margin-top: @largeMargin; + } + + .multiclass-class-choices { + display: flex; + width: 100%; + height: 100%; + flex-wrap: wrap; + } + + .multiclass-spaced-choices { + display: flex; + justify-content: space-around; + width: 100%; + height: 100%; + } + + .multiclass-class-choice { + display: flex; + align-items: center; + flex-basis: 33.33%; + font-weight: bold; + font-size: 24px; + cursor: pointer; + + &.selected:not(.disabled), &:hover:not(.disabled) { + filter: drop-shadow(0 0 3px gold); + } + + &.inactive, &.disabled { + cursor: initial; + opacity: 0.4; + } + + img { + width: 80px; + height: 80px; + margin-right: @largeMargin; + } + } + } + } + + &.damage-selection { + .hope-container { + display: flex; + gap: @fullMargin; + align-items: center; + font-size: 18px; + } + } + + &.action { + .action-category { + display: flex; + flex-direction: column; + + .action-category-label { + display: flex; + align-items: center; + justify-content: space-between; + border-radius: 6px; + cursor: pointer; + padding: 0 @fullPadding; + margin: 0 auto @halfMargin; + + &:hover { + background-color: darkgray; + } + } + + .action-category-data { + max-height: 0; + transition: max-height 0.2s ease-in-out; + overflow: hidden; + + &.open { + max-height: initial; + } + } + } + } + + &.ancestry-selection { + .ancestry-section { + display: flex; + flex-direction: column; + align-items: center; + margin-bottom: @fullMargin; + + .ancestry-container { + width: 100%; + display: flex; + flex-wrap: wrap; + + .ancestry-inner-container { + flex-basis: 25%; + display: flex; + flex-direction: column; + align-items: center; + + .image-container { + img { + width: 120px; + border: 4px solid black; + border-radius: 50%; + + &.selected { + border-color: @secondaryShadow; + } + + &:hover:not(.selected) { + filter: drop-shadow(0 0 3px @secondaryShadow); + } + + &.disabled { + opacity: 0.3; + } + } + } + + .name-container { + div { + font-size: 18px; + font-weight: bold; + cursor: help; + } + } + } + } + + .mixed-ancestry-container { + width: 100%; + display: flex; + gap: @fullMargin; + + > div { + flex: 1; + } + + .mixed-ancestry-name { + text-align: center; + div { + font-size: 24px; + } + } + + .mixed-ancestry-images { + display: flex; + align-items: center; + gap: @halfMargin; + + .mixed-ancestry-image { + position: relative; + max-width: 33%; + + &:hover i { + opacity: 1; + } + + i { + position: absolute; + font-size: 32px; + top: calc(50% - 20px); + left: calc(50% - 20px); + padding: @fullPadding; + background-color: grey; + opacity: 0; + cursor: pointer; + + &:hover { + filter: drop-shadow(0 0 3px @secondaryShadow); + } + } + + img { + max-width: 100%; + } + } + + img { + max-width: 33%; + border: 4px solid black; + border-radius: 50%; + + &.selected { + border-color: @secondaryShadow; + } + } + } + } + } + } +} \ No newline at end of file diff --git a/styles/chat.less b/styles/chat.less new file mode 100644 index 00000000..e7eda717 --- /dev/null +++ b/styles/chat.less @@ -0,0 +1,212 @@ +.daggerheart.chat { + &.downtime { + display: flex; + flex-direction: column; + align-items: center; + + .downtime-title-container { + display: flex; + flex-direction: column; + align-items: center; + + .downtime-subtitle { + font-size: 17px; + } + } + + .downtime-image { + width: 80px; + } + + .downtime-refresh-container { + margin-top: @fullMargin; + width: 100%; + + .refresh-title { + font-weight: bold; + } + } + } + + &.roll { + .dice-tooltip { + .dice-rolls { + display: flex; + align-items: center; + justify-content: space-around; + + .dice-hope-container { + display: flex; + + .roll.die:not(:last-of-type) { + margin-right: @fullMargin; + } + } + + .modifiers-container { + display: flex; + + .modifier-value:not(:last-of-type) { + margin-right: @fullMargin; + } + } + + .roll.die { + &.hope { + color: white; + -webkit-text-stroke-color: @hope; + -webkit-text-stroke-width: 1.5px; + font-weight: 400; + } + &.fear { + color: white; + -webkit-text-stroke-color: @fear; + -webkit-text-stroke-width: 1.5px; + font-weight: 400; + } + &.disadvantage { + color: white; + -webkit-text-stroke-color: @disadvantage; + -webkit-text-stroke-width: 1.5px; + font-weight: 400; + } + &.advantage { + color: white; + -webkit-text-stroke-color: @advantage; + -webkit-text-stroke-width: 1.5px; + font-weight: 400; + } + //V1.3 + // &.advantage { + // filter: drop-shadow(0 -4px 4px gold); + // cursor: pointer; + // } + + &.unused { + opacity: 0.3; + } + } + + .modifier-value { + text-align: center; + font-weight: bold; + font-size: 16px; + } + } + } + + .dice-total { + .dice-total-value { + .hope { + color: @hope; + } + .fear { + color: @fear; + } + .critical { + color: @critical; + } + } + } + + .dice-total-label { + font-size: 12px; + font-weight: bold; + font-variant: all-small-caps; + margin: -@fullMargin 0; + } + + .target-section { + margin-top: 5px; + + .target-container { + display: flex; + transition: all 0.2s ease-in-out; + + &:hover { + filter: drop-shadow(0 0 3px @secondaryShadow); + border-color: gold; + } + + &.hidden { + display: none; + border: 0; + } + + &.hit { + background: @hit; + } + + &.miss { + background: @miss; + } + + img { + flex: 0; + width: 22px; + height: 22px; + margin-left: 8px; + align-self: center; + border-color: transparent; + } + + .target-inner-container { + flex: 1; + display: flex; + justify-content: center; + margin-right: @hugeMargin; + } + } + } + + .roll-damage-button { + margin-top: 5px; + } + } + + &.domain-card { + display: flex; + flex-direction: column; + align-items: center; + + .domain-card-title { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + + div { + font-size: 20px; + font-variant: small-caps; + font-weight: bold; + } + + h2 { + width: 100%; + text-align: center; + } + } + + .ability-card-footer { + display: flex; + width: 100%; + margin-top: @fullMargin; + flex-wrap: wrap; + + button { + border-radius: 6px; + background: @positive; + border-color: black; + flex-basis: calc(50% - 2px); + + &:nth-of-type(n+3){ + margin-top: @tinyMargin; + } + } + } + + img { + width: 80px; + } + } +} \ No newline at end of file diff --git a/styles/class.less b/styles/class.less new file mode 100644 index 00000000..42e33ee4 --- /dev/null +++ b/styles/class.less @@ -0,0 +1,5 @@ +.daggerheart.sheet.class { + .editor { + height: 500px; + } +} \ No newline at end of file diff --git a/styles/components.less b/styles/components.less new file mode 100644 index 00000000..a836cbc8 --- /dev/null +++ b/styles/components.less @@ -0,0 +1,45 @@ +.slider-container { + position: relative; + background: lightslategray; + + .slider-inner-container { + position: absolute; + top: 1px; + left: -60px; + background-color: inherit; + color: inherit; + border-radius: 30px; + cursor: pointer; + display: flex; + align-items: center; + height: 20px; + width: 40px; + padding: 0 4px; + border: @thinBorder solid black; + + &:hover { + filter: drop-shadow(0 0 3px red); + } + + input:checked { + opacity: 0; + width: 0; + height: 0; + + & + .slider-icon { + transform: translateX(17px); + transition: 1s; + } + } + + .slider-icon { + position: absolute; + left: 4px; + height: 15px; + width: 15px; + border-radius: 50%; + transition: 1s; + transform: translateX(0); + } + } +} \ No newline at end of file diff --git a/styles/daggerheart.css b/styles/daggerheart.css new file mode 100644 index 00000000..8120d8fe --- /dev/null +++ b/styles/daggerheart.css @@ -0,0 +1,2613 @@ +/* General */ +/* Drop Shadows */ +/* Background */ +/* Base Value */ +/* Margins */ +/* Borders */ +/* Padding */ +/* Inputs */ +@import "../node_modules/@yaireo/tagify/dist/tagify.css"; +.daggerheart.sheet.class .editor { + height: 500px; +} +.daggerheart.sheet.pc { + width: 810px !important; +} +.daggerheart.sheet.pc div[data-application-part] { + display: flex; + flex-direction: column; +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header { + display: flex; + gap: 4px; + height: 120px; + margin-bottom: 4px; +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .portrait { + border: 0; + border-right: 1px solid var(--color-underline-header); +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .class-info { + flex: 1; + background: #778899; +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .class-info .portrait { + max-width: 120px; +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .class-info .class-title { + text-align: center; + display: flex; + justify-content: space-between; +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .class-info .class-title span:hover { + filter: drop-shadow(0px 0px 3px red); + cursor: pointer; +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .class-info .class-title .domain-container { + margin-left: 4px; +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .class-info .class-add-container { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + flex: 0; +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .class-info .class-add-container button { + height: 22px; + width: 22px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + margin-left: 4px; + background: #778899; +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .class-info .domain-title { + text-transform: uppercase; + display: flex; + flex-direction: column; + align-items: center; + line-height: 23px; + font-weight: bold; + font-style: italic; +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .class-info .domain-image { + height: 30px; + flex: 0; +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .general-info { + flex: 2; + display: flex; + flex-direction: column; + justify-content: space-between; +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .general-info .general-input { + position: relative; +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .general-info .general-input .general-title { + position: absolute; + left: 4px; + text-align: center; + font-weight: bold; + text-transform: uppercase; +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .general-info .pc-tabs { + flex: 1; + margin: 0; +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .general-info .rest-container { + flex-wrap: nowrap; + display: flex; + height: var(--form-field-height); + flex: 0; +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .general-info .rest-container button { + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + width: var(--form-field-height); +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .general-info .rest-container button i { + font-size: 13px; +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .general-info .level-container { + position: relative; + bottom: 4px; + flex: none; + width: 40px; + border: none; + outline: none; + margin-left: 8px; +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .general-info .level-container.levelup { + filter: drop-shadow(0px 0px 3px gold); +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .general-info .level-container img { + height: 40px; + width: 40px; + border: none; +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .general-info .level-container .level-value-container { + width: 48px; + position: absolute; + top: calc(50% - 17px); + left: calc(50% - 23px); +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .general-info .level-container .level-value-container .level-value { + font-weight: bold; + font-size: 20px; + text-align: center; +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .general-info .level-container .level-value-container .level-value:not(:hover), +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .general-info .level-container .level-value-container .level-value:not(:focus) { + border: none; +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .general-info .level-container .level-value-container .levelup-marker { + position: absolute; + top: 0; + right: calc(50% - 12px); + color: gold; + filter: drop-shadow(0px 0px 3px black); +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .general-info .level-container .level-value-container .levelup-marker.double-digit { + right: calc(50% - 20px); +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .general-info .level-container .level-title { + position: absolute; + bottom: 2px; + width: 42px; + background-color: black; + color: white; + left: calc(50% - 21px); + text-align: center; + border-radius: 5px; + font-size: 12px; +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .general-info .level-container .level-title.levelup { + color: gold; + filter: drop-shadow(0px 0px 3px orange); + font-weight: bold; + cursor: pointer; +} +.daggerheart.sheet.pc div[data-application-part] .pc-sheet-header .general-info .level-container .level-title.levelup:hover { + background-color: aliceblue; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body { + display: flex; + flex-direction: column; + flex: 1; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .tab-container { + height: 100%; + display: flex; + flex-direction: column; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .tab-container .tab-inner-container { + flex: 1; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .tab-container .tab-inner-container .body-section { + display: flex; + flex-direction: column; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .tab-container .tab-inner-container .body-section fieldset { + flex: 0; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .system-info { + font-size: 12px; + font-style: italic; + font-weight: bold; + margin-top: -4px; + flex: 0; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .feature-sheet-body { + gap: 4px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-container { + position: relative; + display: flex; + flex-wrap: wrap; + border-radius: 6px; + padding-left: 0; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-container legend { + margin-left: auto; + margin-right: auto; + font-weight: bold; + text-transform: uppercase; + padding: 0 8px; + position: relative; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-container .attributes-menu { + position: absolute; + bottom: calc(50% - 12px); + font-size: 24px; + left: -8px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-container .attribute { + position: relative; + padding: 0 0 4px; + display: flex; + flex-direction: column; + align-items: center; + flex-basis: 33.33%; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-container .attribute .attribute-banner { + position: relative; + top: 8px; + z-index: 2; + background: black; + color: white; + text-transform: uppercase; + padding: 2px; + border-radius: 6px; + display: flex; + align-items: center; + overflow: hidden; + min-width: 96px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-container .attribute .attribute-banner .attribute-roll { + position: absolute; + width: 16px; + transition: transform 0.2s; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-container .attribute .attribute-banner .attribute-roll:hover { + transform: rotate(30deg); + filter: drop-shadow(0px 0px 3px red); + cursor: pointer; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-container .attribute .attribute-banner .attribute-text { + width: 100%; + margin-left: 16px; + font-size: 12px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-container .attribute .attribute-mark { + height: 23px; + width: 23px; + position: absolute; + right: -5px; + top: 6px; + border: 2px solid black; + border-radius: 50%; + background: white; + z-index: 2; + display: flex; + align-items: center; + justify-content: center; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-container .attribute .attribute-mark.selectable { + border-color: gold; + filter: drop-shadow(0 0 3px black); +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-container .attribute .attribute-mark.selectable:hover i { + opacity: 0.3; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-container .attribute .attribute-mark i.selected, +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-container .attribute .attribute-mark:hover i.selected { + color: green; + opacity: 1; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-container .attribute .attribute-mark i { + color: black; + font-size: 17px; + opacity: 0; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-container .attribute .attribute-image { + position: relative; + width: fit-content; + display: flex; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-container .attribute .attribute-image img { + height: 80px; + width: 80px; + border: none; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-container .attribute .attribute-image .attribute-value { + width: 55px; + padding-right: 10px; + position: absolute; + top: calc(50% - 18px); + left: calc(50% - 24px); + font-weight: bold; + font-size: 30px; + line-height: 30px; + text-align: center; + border: none; + appearance: none; + -moz-appearance: none; + -webkit-appearance: none; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-container .attribute .attribute-image .attribute-value.negative { + left: calc(50% - 29px); +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-container .attribute .attribute-image .attribute-value.unselected { + filter: drop-shadow(0 0 3px gold); +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-container .attribute .attribute-image .attribute-text { + width: 47px; + position: absolute; + top: calc(50% - 22px); + left: calc(50% - 24px); + font-weight: bold; + font-size: 30px; + text-align: center; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-container .attribute .attribute-image .attribute-text.negative { + left: calc(50% - 29px); +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-container .attribute .attribute-verb { + font-variant: petite-caps; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .defense-row { + height: 100%; + width: 100%; + display: flex; + align-items: baseline; + justify-content: space-evenly; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .defense-row .defense-section { + display: flex; + align-items: center; + margin-right: 8px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .defense-row .defense-section .defense-container { + position: relative; + padding: 4px; + max-width: 100px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .defense-row .defense-section .defense-container img { + border: none; + max-width: 80px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .defense-row .defense-section .defense-container .defense-value { + width: 47px; + position: absolute; + top: calc(50% - 22px); + left: calc(50% - 24px); + font-weight: bold; + font-size: 30px; + text-align: center; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .defense-row .defense-section .defense-container .defense-value:not(:hover), +.daggerheart.sheet.pc div[data-application-part] .sheet-body .defense-row .defense-section .defense-container .defense-value:not(:focus) { + border: none; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .defense-row .defense-section .defense-container .defense-banner { + position: absolute; + bottom: 20px; + left: calc(50% - 42px); + z-index: 2; + background-color: black; + color: white; + width: 84px; + text-align: center; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .defense-row .armor-marks { + max-width: 67px; + padding: 4px; + align-self: end; + margin-left: 4px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .defense-row .armor-marks .mark { + width: 16px; + height: 16px; + margin: 0px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .defense-row .armor-marks .disabled-mark { + opacity: 0.6; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .left-main-container { + position: relative; + display: flex; + flex-direction: column; + align-items: flex-start; + border-radius: 6px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .left-main-container .legend { + margin-left: auto; + margin-right: auto; + font-weight: bold; + text-transform: uppercase; + padding: 0 4px; + position: relative; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .weapon-section { + padding-top: 8px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .threshold-container { + position: relative; + display: flex; + align-items: center; + align-self: center; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .threshold-container .threshold-box { + position: relative; + width: 30px; + height: 30px; + border: 2px solid black; + display: flex; + align-items: center; + justify-content: center; + font-size: 20px; + font-weight: bold; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .threshold-container .threshold-spacer { + position: relative; + z-index: 2; + width: 70px; + height: 18px; + background-color: darkgray; + color: white; + display: flex; + justify-content: center; + align-items: center; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .resource-label { + text-transform: uppercase; + font-weight: bold; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .death-save { + position: absolute; + right: -22px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .death-save:hover:not(.disabled) { + filter: drop-shadow(0 0 3px red); + cursor: pointer; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .death-save.disabled { + opacity: 0.4; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .resource-box { + width: 20px; + height: 12px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .resource-box.stress:nth-child(even) { + position: relative; + right: 1px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .resource-box .disabled { + opacity: 0.6; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .hope-text { + font-size: 11.7px; + margin-right: 6px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .hope-container { + background: darkgray; + border-radius: 6px; + display: flex; + padding: 2px 0px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .hope-container .vertical-separator { + border-left: 2px solid white; + height: auto; + margin: 4px 0; + flex: 0; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .hope-container .hope-inner-container { + position: relative; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .hope-container .hope-inner-container .hope-value { + width: 16px; + height: 16px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .hope-container .hope-inner-container .hope-scar { + position: absolute; + top: calc(50% - 6px); + left: calc(50% - 7px); + opacity: 0.4; + font-size: 12px; + -webkit-transform: scaleX(-1); + transform: scaleX(-1); +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .experience-row { + width: 100%; + display: flex; + align-items: flex-end; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .experience-row .experience-selector { + font-size: 18px; + cursor: pointer; + margin-right: 4px; + opacity: 0.5; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .experience-row .experience-selector:hover:not(.selected) { + filter: drop-shadow(0 0 3px gold); +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .experience-row .experience-selector.selected { + filter: drop-shadow(0 0 3px gold); + opacity: 1; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .experience-row .experience-value { + margin-left: 8px; + width: 30px; + border-bottom: 2px solid black; + border-radius: 4px; + text-align: center; + font-weight: bold; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .experience-row .experience-value.empty { + border: 0; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .experience-row .disabled-experience { + border: 1px solid #7a7971; + background: rgba(0, 0, 0, 0.2); +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .gold-section { + width: calc(100% - 8px); + display: flex; + justify-content: space-between; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .gold-section fieldset.gold-fieldset { + padding-right: 0; + padding-left: 0; + padding-bottom: 4px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .gold-section fieldset.gold-fieldset legend { + margin-left: auto; + margin-right: auto; + font-size: 15px; + font-variant: all-petite-caps; + font-weight: bold; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .gold-section fieldset.gold-fieldset .gold-column { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100%; + gap: 4px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .gold-section fieldset.gold-fieldset .gold-row { + display: flex; + align-items: center; + justify-content: center; + padding: 0 4px; + gap: 2px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .gold-section fieldset.gold-fieldset .gold-row img, +.daggerheart.sheet.pc div[data-application-part] .sheet-body .gold-section fieldset.gold-fieldset .gold-column img { + min-width: 14px; + min-height: 14px; + height: 14px; + border: 0; + filter: invert(0%) sepia(100%) saturate(0%) hue-rotate(21deg) brightness(17%) contrast(103%); +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .gold-section fieldset.gold-fieldset .gold-row img:hover, +.daggerheart.sheet.pc div[data-application-part] .sheet-body .gold-section fieldset.gold-fieldset .gold-column img:hover { + cursor: pointer; + filter: invert(0%) sepia(100%) saturate(0%) hue-rotate(21deg) brightness(17%) contrast(103%) drop-shadow(0 0 3px red); +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .gold-section fieldset.gold-fieldset .gold-row i:hover, +.daggerheart.sheet.pc div[data-application-part] .sheet-body .gold-section fieldset.gold-fieldset .gold-column i:hover { + cursor: pointer; + filter: drop-shadow(0 0 3px red); +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .gold-section fieldset.gold-fieldset .gold-row img:not(.owned), +.daggerheart.sheet.pc div[data-application-part] .sheet-body .gold-section fieldset.gold-fieldset .gold-column img:not(.owned), +.daggerheart.sheet.pc div[data-application-part] .sheet-body .gold-section fieldset.gold-fieldset .gold-row i:not(.owned), +.daggerheart.sheet.pc div[data-application-part] .sheet-body .gold-section fieldset.gold-fieldset .gold-column i:not(.owned) { + opacity: 0.4; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .health-category { + text-transform: uppercase; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .class-feature-selectable { + cursor: pointer; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .class-feature-selectable:hover { + filter: drop-shadow(0 0 3px red); +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .class-feature-selectable.inactive { + opacity: 0.5; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .features-container { + width: 100%; + min-height: 136px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .features-container .feature-container { + display: flex; + align-items: center; + justify-content: space-between; + padding: 4px; + margin-bottom: 0; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .features-container .feature-container .feature-img { + max-width: 42px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .features-container .feature-container .feature-label { + font-weight: bold; + font-size: 30px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .features-container .feature-container button { + flex: 0; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .features-container .feature-tick-container { + flex: 0; + min-width: 56px; + display: flex; + flex-wrap: wrap; + gap: 8px; + margin: 0 24px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .features-container .feature-tick-container .feature-tick { + position: relative; + border: 2px solid #7a7971; + height: 24px; + border-radius: 50%; + width: 24px; + background: rgba(0, 0, 0, 0.05); + display: flex; + justify-content: center; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .features-container .feature-tick-container .feature-tick:hover:not(.disabled):not(.used) { + cursor: pointer; + filter: drop-shadow(0 0 3px red); +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .features-container .feature-tick-container .feature-tick.disabled { + opacity: 0.3; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .features-container .feature-tick-container .feature-tick img { + border: 0; + width: 24px; + height: 24px; + filter: invert(17%) sepia(0%) saturate(0%) hue-rotate(19deg) brightness(102%) contrast(84%); +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .features-container .feature-tick-container .feature-tick .feature-dice-value { + font-size: 18px; + align-self: center; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .features-container .feature-tick-container .feature-tick.used::after { + position: absolute; + content: "/"; + color: #7a7971; + font-weight: 700; + font-size: 1.7em; + left: 4px; + top: -5px; + transform: rotate(25deg); + font-size: 24.5px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .feature-input { + border: 0; + border-bottom: 1px solid #7a7971; + text-align: center; + height: min-content; + background: inherit; + font-size: 20px; + position: relative; + bottom: 3px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .editor { + height: 400px; + width: 100%; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .weapons-title { + position: relative; + display: flex; + flex-direction: column; + align-items: center; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .weapons-title .proficiency-container { + width: 176px; + height: 20px; + position: absolute; + bottom: -15px; + left: calc(50% - 88px); + text-transform: uppercase; + display: flex; + align-items: center; + justify-content: center; + z-index: 1; + clip-path: polygon(11% 100%, 89% 100%, 100% 0%, 0% 0%); + font-size: 10px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .weapons-title .proficiency-container span { + margin-right: 2px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .weapons-title .proficiency-container .proficiency-dot { + background: white; + color: white; + font-size: 10px; + padding: 1px; + border-radius: 50%; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .weapons-title .proficiency-container .proficiency-dot.marked { + color: black; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .weapons-title .proficiency-container .proficiency-dot:not(:last-of-type) { + margin-right: 2px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .weapons-burden { + position: absolute; + top: -4px; + right: -56px; + display: flex; + align-items: center; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .weapons-burden .weapons-burden-icon { + color: white; + font-size: 22px; + -webkit-text-stroke-width: 1px; + -webkit-text-stroke-color: black; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .weapons-burden .weapons-burden-icon.active { + -webkit-text-stroke-color: rgba(0, 0, 0, 0.05); + color: black; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .weapons-burden .weapons-burden-icon.left { + -webkit-transform: scaleX(-1) rotate(20deg); + transform: scaleX(-1) rotate(20deg); + margin-right: 4px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .weapons-burden .weapons-burden-icon.right { + transform: rotate(20deg); +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .armor-container { + display: flex; + align-items: center; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .armor-container .active-item-label-chip { + margin-left: 4px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .item-section .active-item-container { + display: flex; + flex-direction: column; + width: 100%; + padding: 2px 0px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .item-section .active-item-container .weapons-label-row { + display: flex; + align-items: center; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .item-section .active-item-container .weapons-label-row .damage-roll { + width: 24px; + border: none; + margin-left: 4px; + transition: transform 0.2s; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .item-section .active-item-container .weapons-label-row .damage-roll:hover { + transform: rotate(30deg); + filter: drop-shadow(0px 0px 3px red); + cursor: pointer; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .item-section .active-item-label-chip { + width: 62px; + border: 2px solid black; + border-radius: 6px; + background-color: #778899; + display: flex; + align-items: center; + justify-content: space-around; + margin-left: 4px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .item-section .active-item-label-chip img { + height: 20px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .item-section .active-item-label-chip button { + height: 17px; + width: 17px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + background: #7a7971; + border-color: black; + margin: 0; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .item-section .active-item-label-chip button:hover { + background: red; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .item-section .active-item-label-chip button i { + font-size: 10px; + color: black; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-armor-section, +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-weapon-section { + width: 100%; + margin-bottom: 8px; + text-transform: uppercase; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-armor-section h2, +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-weapon-section h2 { + width: 100%; + display: flex; + align-items: center; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-legend { + display: flex; + align-items: center; + margin-bottom: 4px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-legend .page-selector { + margin-left: 4px; + display: flex; + align-items: center; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-legend .page-selector i:hover:not(.disabled) { + cursor: pointer; + filter: drop-shadow(0px 0px 3px red); +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-legend .page-selector i.disabled { + opacity: 0.4; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-add-button { + position: absolute; + border-radius: 50%; + height: 15px; + width: 15px; + top: -20px; + background: grey; + border-color: black; + right: 6px; + display: flex; + font-size: 13px; + align-items: center; + justify-content: center; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory { + width: 100%; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory .inventory-row { + height: 26px; + border-bottom: 1px solid #7a7971; + display: flex; + margin-bottom: 8px; + border-radius: 8px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory .inventory-row .item-container { + flex-basis: 25%; + margin: 0 4px 8px; + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory .inventory-row .item-container:hover { + filter: drop-shadow(0px 0px 3px red); +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory .inventory-row .item-container .inventory-item { + background: #778899; + padding: 4px; + border: 1px solid black; + border-radius: 6px; + display: flex; + align-items: center; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory .inventory-row .item-container .inventory-item .inventory-item-text { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + flex: 1; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory .inventory-row .item-container .inventory-item button { + height: 16px; + width: 16px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + flex: 0; + background: #7a7971; + border-color: black; + margin-left: 4px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory .inventory-row .item-container .inventory-item button i { + font-size: 12px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory .editor { + height: 100px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-items { + width: 100%; + flex: 1; + display: flex; + flex-direction: column; + justify-content: space-between; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .domain-card-tab { + flex: 1; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .domain-card-tab .domain-card-body { + height: 100%; + width: 100%; + padding: 8px; + display: flex; + flex-direction: column; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .domain-card-tab .domain-card-body .card-row { + flex: 1; + display: flex; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .domain-card-tab .domain-card-body .domain-card { + flex: 0; + flex-basis: 33.33%; + margin: 8px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .domain-card-tab .domain-card-body .loadout-body { + flex: 1; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .domain-card-tab .domain-card-body .loadout-body .loadout-container { + height: 100%; + display: flex; + flex-direction: column; + gap: 8px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .domain-card-tab .domain-card-body .loadout-body .loadout-container .top-card-row { + flex: 1; + display: flex; + justify-content: space-around; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .domain-card-tab .domain-card-body .loadout-body .loadout-container .domain-card.outlined { + border: 2px dotted black; + padding: 0; + margin: 8px; + height: calc(100% - 16px); + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-evenly; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .domain-card-tab .domain-card-body .vault-container { + display: flex; + flex-wrap: wrap; + overflow-y: auto; + height: 100%; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .domain-card-tab .domain-card-body .vault-container .vault-card { + flex: 0; + flex-basis: calc(33.33% - 16px); + margin: 8px; + height: calc(50% - 16px); + min-height: calc(50% - 16px); +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .domain-card-tab .domain-card-body .domain-card-menu { + flex: 0; + width: 120px; + height: 100%; + border-width: 2px 0 2px 2px; + border-color: black; + border-style: solid; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .domain-card-tab .domain-card-body .domain-card-menu button { + margin-bottom: 2px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .loadout-tabs { + border-top: 1px solid #b5b3a4; + border-bottom: 1px solid #b5b3a4; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card { + position: relative; + border: 4px solid #708090; + border-radius: 6px; + display: flex; + flex-direction: column; + height: 100%; + font-size: 14px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card .abilities-card-image-container { + position: relative; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card .abilities-card-image { + width: 100%; + height: 100%; + aspect-ratio: 2; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card .abilities-text-container { + flex: 1; + position: relative; + height: 50%; + display: flex; + flex-direction: column; + overflow-y: auto; + padding: 12px 4px 4px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card .abilities-card-level { + position: absolute; + top: 0; + left: 12px; + color: black; + height: 60px; + border: 2px solid orange; + border-top-width: 0; + width: 30px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-evenly; + background: grey; + font-size: 20px; + font-weight: bold; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card .abilities-card-level img { + border: 0; + width: 20px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card .abilities-card-refresh-cost { + position: absolute; + top: 12px; + right: 12px; + color: white; + width: 30px; + height: 30px; + border: 2px solid orange; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + background: black; + font-size: 14px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card .abilities-card-refresh-cost i { + font-size: 11px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card .abilities-card-type { + flex: 0; + display: flex; + justify-content: center; + align-items: center; + font-weight: bold; + position: absolute; + left: 0; + text-align: center; + width: 100%; + bottom: -9px; + z-index: 1; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card .abilities-card-type .abilities-card-type-text { + padding: 0px 4px; + border: 1px solid black; + border-radius: 6px; + background: gold; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card .abilities-card-title { + flex: 0; + display: flex; + justify-content: center; + align-items: center; + font-weight: bold; + font-size: 18px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card .abilities-card-sub-title { + flex: 0; + display: flex; + justify-content: center; + align-items: center; + font-style: italic; + font-size: 12px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card .abilities-card-spellcast { + flex: 0; + display: flex; + justify-content: center; + align-items: center; + text-transform: uppercase; + font-size: 12px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card .abilities-card-spellcast .title { + font-weight: bold; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card .abilities-card-description { + flex: 0; + font-size: 12px; + margin-bottom: 4px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card .abilities-card-effect { + cursor: pointer; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card .abilities-card-effect:hover { + background: rgba(47, 79, 79, 0.25); +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card .abilities-card-effect > * { + margin-top: 0; + margin-bottom: 0; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card .abilities-card-abilities { + flex: 1; + display: flex; + flex-direction: column; + gap: 4px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card .abilities-card-abilities .abilities-card-ability { + font-size: 12px; + cursor: pointer; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card .abilities-card-abilities .abilities-card-ability:hover { + background: rgba(47, 79, 79, 0.25); +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card .abilities-card-abilities .abilities-card-ability > * { + margin: 0; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card:hover .abilities-card-menu { + height: 40px; + left: 0px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card .abilities-card-menu { + display: flex; + justify-content: center; + align-items: center; + height: 0; + transition: height 0.2s; + overflow: hidden; + position: absolute; + bottom: 0; + z-index: 2; + width: 100%; + background: grey; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .abilities-card .abilities-card-menu button { + font-weight: bold; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .heritage-container { + height: 100%; + display: flex; + flex-direction: column; + gap: 8px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .heritage-container .card-row { + height: 50%; + display: flex; + justify-content: space-around; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .heritage-container .heritage-card { + flex-basis: 33.33%; + margin: 8px; + display: flex; + align-items: center; + justify-content: center; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .heritage-container .heritage-card.outlined { + border: 2px dotted black; + font-size: 25px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .empty-ability-container { + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + font-size: 25px; + opacity: 0.7; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .empty-ability-container .empty-ability-inner-container { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .empty-ability-container .empty-ability-inner-container i { + font-size: 48px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .story-container { + gap: 16px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .story-container .story-fieldset { + border-radius: 6px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .story-container .story-legend { + margin-left: auto; + margin-right: auto; + padding: 0 8px; + font-size: 30px; + font-weight: bold; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .story-container .scars-container .editor { + height: 240px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-container { + height: 100%; + overflow: auto; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-container .inventory-item-list { + list-style-type: none; + padding: 0 8px; + margin-top: 0; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-container .inventory-item-list.inventory-item-header { + margin-bottom: 0; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-container .inventory-item-list .inventory-title-row-container { + display: flex; + align-items: center; + width: 100%; + border-bottom: 4px ridge slategrey; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-container .inventory-item-list .inventory-title-row-container .inventory-title-row { + justify-content: space-between; + flex: 1; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-container .inventory-item-list .inventory-title-row-container .inventory-item-title-container { + flex: 1; + display: flex; + align-items: center; + justify-content: flex-start; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-container .inventory-item-list .inventory-title-row-container .inventory-item-quantity { + width: 48px; + display: flex; + align-items: center; + margin-right: 96px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-container .inventory-item-list .inventory-item { + background: crimson; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-container .inventory-item-list .inventory-item:not(:last-of-type) { + border-bottom: 2px ridge slategrey; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-container .inventory-item-list .inventory-item .inventory-item-title-container { + flex: 1; + display: flex; + align-items: center; + justify-content: flex-start; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-container .inventory-item-list .inventory-item .inventory-item-title-container .inventory-item-title { + display: flex; + align-items: center; + cursor: pointer; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-container .inventory-item-list .inventory-item .inventory-item-title-container .inventory-item-title:hover { + filter: drop-shadow(0 0 3px gold); +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-container .inventory-item-list .inventory-item .inventory-item-quantity { + width: 48px; + display: flex; + align-items: center; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-container .inventory-item-list .inventory-item .inventory-item-quantity.spaced { + margin-right: 56px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-container .inventory-item-list .inventory-item .inventory-item-quantity input { + margin: 0 2px; + border: 0; + border-bottom: 2px solid black; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-container .inventory-item-list .inventory-item .inventory-item-quantity i { + font-size: 20px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-container .inventory-item-list .inventory-title-row { + font-size: 20px; + font-weight: bold; + display: flex; + align-items: center; + padding: 0 4px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-container .inventory-item-list .inventory-row { + display: flex; + align-items: center; + padding: 4px; + font-size: 24px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-container .inventory-item-list .inventory-row .row-icon { + margin-left: 4px; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-container .inventory-item-list .inventory-row .active-item { + position: absolute; + font-size: 16px; + left: calc(50% - 8px); + top: calc(50% - 8px); + margin-left: 2px; + color: crimson; +} +.daggerheart.sheet.pc div[data-application-part] .sheet-body .inventory-container .inventory-item-list .inventory-row img { + width: 32px; +} +.combat-sidebar .encounter-gm-resources { + flex: 0; + display: flex; + justify-content: center; + padding: 8px 0; +} +.combat-sidebar .encounter-gm-resources .gm-resource-controls { + display: flex; + flex-direction: column; + align-items: center; + padding: 0 4px; + justify-content: center; +} +.combat-sidebar .encounter-gm-resources .gm-resource-tools { + display: flex; + flex-direction: column; + justify-content: center; + padding: 0 5px 0 4px; +} +.combat-sidebar .encounter-gm-resources .gm-resource-tools i { + margin: 0 2px; + font-size: 16px; +} +.combat-sidebar .encounter-gm-resources .gm-resource-tools i.disabled { + opacity: 0.6; +} +.combat-sidebar .encounter-gm-resources .gm-resource-tools i:hover:not(.disabled) { + cursor: pointer; + filter: drop-shadow(0 0 3px red); +} +.combat-sidebar .encounter-gm-resources .gm-resource { + background: rgba(255, 255, 255, 0.1); + padding: 4px; + border-radius: 8px; + border: 2px solid black; + font-size: 20px; +} +.combat-sidebar .token-action-tokens { + flex: 0 0 48px; + text-align: center; +} +.combat-sidebar .token-action-tokens .use-action-token.disabled { + opacity: 0.6; +} +.combat-sidebar .icon-button.spaced { + margin-left: 4px; +} +.combat-sidebar .icon-button.disabled { + opacity: 0.6; +} +.combat-sidebar .icon-button:hover:not(.disabled) { + cursor: pointer; + filter: drop-shadow(0 0 3px red); +} +.daggerheart.chat.downtime { + display: flex; + flex-direction: column; + align-items: center; +} +.daggerheart.chat.downtime .downtime-title-container { + display: flex; + flex-direction: column; + align-items: center; +} +.daggerheart.chat.downtime .downtime-title-container .downtime-subtitle { + font-size: 17px; +} +.daggerheart.chat.downtime .downtime-image { + width: 80px; +} +.daggerheart.chat.downtime .downtime-refresh-container { + margin-top: 8px; + width: 100%; +} +.daggerheart.chat.downtime .downtime-refresh-container .refresh-title { + font-weight: bold; +} +.daggerheart.chat.roll .dice-tooltip .dice-rolls { + display: flex; + align-items: center; + justify-content: space-around; +} +.daggerheart.chat.roll .dice-tooltip .dice-rolls .dice-hope-container { + display: flex; +} +.daggerheart.chat.roll .dice-tooltip .dice-rolls .dice-hope-container .roll.die:not(:last-of-type) { + margin-right: 8px; +} +.daggerheart.chat.roll .dice-tooltip .dice-rolls .modifiers-container { + display: flex; +} +.daggerheart.chat.roll .dice-tooltip .dice-rolls .modifiers-container .modifier-value:not(:last-of-type) { + margin-right: 8px; +} +.daggerheart.chat.roll .dice-tooltip .dice-rolls .roll.die.hope { + color: white; + -webkit-text-stroke-color: #008080; + -webkit-text-stroke-width: 1.5px; + font-weight: 400; +} +.daggerheart.chat.roll .dice-tooltip .dice-rolls .roll.die.fear { + color: white; + -webkit-text-stroke-color: #430070; + -webkit-text-stroke-width: 1.5px; + font-weight: 400; +} +.daggerheart.chat.roll .dice-tooltip .dice-rolls .roll.die.disadvantage { + color: white; + -webkit-text-stroke-color: #b30000; + -webkit-text-stroke-width: 1.5px; + font-weight: 400; +} +.daggerheart.chat.roll .dice-tooltip .dice-rolls .roll.die.advantage { + color: white; + -webkit-text-stroke-color: green; + -webkit-text-stroke-width: 1.5px; + font-weight: 400; +} +.daggerheart.chat.roll .dice-tooltip .dice-rolls .roll.die.unused { + opacity: 0.3; +} +.daggerheart.chat.roll .dice-tooltip .dice-rolls .modifier-value { + text-align: center; + font-weight: bold; + font-size: 16px; +} +.daggerheart.chat.roll .dice-total .dice-total-value .hope { + color: #008080; +} +.daggerheart.chat.roll .dice-total .dice-total-value .fear { + color: #430070; +} +.daggerheart.chat.roll .dice-total .dice-total-value .critical { + color: #ffd700; +} +.daggerheart.chat.roll .dice-total-label { + font-size: 12px; + font-weight: bold; + font-variant: all-small-caps; + margin: -8px 0; +} +.daggerheart.chat.roll .target-section { + margin-top: 5px; +} +.daggerheart.chat.roll .target-section .target-container { + display: flex; + transition: all 0.2s ease-in-out; +} +.daggerheart.chat.roll .target-section .target-container:hover { + filter: drop-shadow(0 0 3px gold); + border-color: gold; +} +.daggerheart.chat.roll .target-section .target-container.hidden { + display: none; + border: 0; +} +.daggerheart.chat.roll .target-section .target-container.hit { + background: #008000; +} +.daggerheart.chat.roll .target-section .target-container.miss { + background: #ff0000; +} +.daggerheart.chat.roll .target-section .target-container img { + flex: 0; + width: 22px; + height: 22px; + margin-left: 8px; + align-self: center; + border-color: transparent; +} +.daggerheart.chat.roll .target-section .target-container .target-inner-container { + flex: 1; + display: flex; + justify-content: center; + margin-right: 32px; +} +.daggerheart.chat.roll .roll-damage-button { + margin-top: 5px; +} +.daggerheart.chat.domain-card { + display: flex; + flex-direction: column; + align-items: center; +} +.daggerheart.chat.domain-card .domain-card-title { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; +} +.daggerheart.chat.domain-card .domain-card-title div { + font-size: 20px; + font-variant: small-caps; + font-weight: bold; +} +.daggerheart.chat.domain-card .domain-card-title h2 { + width: 100%; + text-align: center; +} +.daggerheart.chat.domain-card .ability-card-footer { + display: flex; + width: 100%; + margin-top: 8px; + flex-wrap: wrap; +} +.daggerheart.chat.domain-card .ability-card-footer button { + border-radius: 6px; + background: #699969; + border-color: black; + flex-basis: calc(50% - 2px); +} +.daggerheart.chat.domain-card .ability-card-footer button:nth-of-type(n+3) { + margin-top: 2px; +} +.daggerheart.chat.domain-card img { + width: 80px; +} +.daggerheart.sheet.feature { + background-color: red; +} +.daggerheart.sheet.feature .editable { + display: flex; + flex-direction: column; +} +.daggerheart.sheet.feature .sheet-body { + flex: 1; + display: flex; + flex-direction: column; +} +.daggerheart.sheet.feature .feature-description { + flex: 1; + display: flex; + flex-direction: column; +} +.daggerheart.sheet.class .class-feature { + display: flex; +} +.daggerheart.sheet.class .class-feature img { + width: 40px; +} +.daggerheart.sheet.class .class-feature button { + width: 40px; +} +.daggerheart.sheet .domain-card-description .editor { + height: 300px; +} +.daggerheart.sheet .item-container { + margin-top: 4px; + gap: 4px; + align-items: baseline; +} +.daggerheart.sheet .item-sidebar { + border-right: 1px groove darkgray; + min-width: 160px; + flex: 0; + padding: 4px; +} +.daggerheart.sheet .item-sidebar label { + margin-right: 8px; + font-weight: bold; +} +.daggerheart.sheet .item-sidebar input[type="checkbox"] { + margin: 0; +} +form.daggerheart.views.downtime { + height: auto !important; +} +div.daggerheart.views.death-move { + height: auto !important; +} +div.daggerheart.views.multiclass { + height: auto !important; +} +.daggerheart.views.levelup .levelup-title-container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: 32px; + margin-bottom: 4px; +} +.daggerheart.views.levelup .levelup-title-container .level-title { + text-decoration: underline; +} +.daggerheart.views.levelup .levelup-title-container .level-display { + display: flex; + align-items: center; +} +.daggerheart.views.levelup .levelup-title-container .level-display i { + margin: 0 4px; +} +.daggerheart.views.levelup .levelup-section { + display: flex; + align-items: flex-start; + margin-bottom: 8px; + font-size: 11px; +} +.daggerheart.views.levelup .levelup-section .levelup-container { + flex: 1; +} +.daggerheart.views.levelup .levelup-section .levelup-container:nth-of-type(2) { + padding: 0 4px; +} +.daggerheart.views.levelup .levelup-section .levelup-container.disabled { + opacity: 0.2; +} +.daggerheart.views.levelup .levelup-section .levelup-container .levelup-inner-container { + height: 700px; + padding: 24px 58px 0; + display: flex; + flex-direction: column; + align-items: center; + position: relative; +} +.daggerheart.views.levelup .levelup-section .levelup-container .levelup-inner-container .levelup-legend { + margin-left: auto; + margin-right: auto; + font-weight: bold; + z-index: 1; +} +.daggerheart.views.levelup .levelup-section .levelup-container .levelup-inner-container .levelup-info { + background: #778899; + width: 100%; + text-align: center; + position: absolute; + top: -6px; + padding: 8px 0; +} +.daggerheart.views.levelup .levelup-section .levelup-container .levelup-inner-container .levelup-pretext { + padding: 8px 0; +} +.daggerheart.views.levelup .levelup-section .levelup-container .levelup-inner-container .levelup-body { + display: flex; + flex-direction: column; +} +.daggerheart.views.levelup .levelup-section .levelup-container .levelup-inner-container .levelup-body .levelup-choice-row { + display: flex; + align-items: center; + padding: 4px; +} +.daggerheart.views.levelup .levelup-section .levelup-container .levelup-inner-container .levelup-body .levelup-choice-row .levelup-choice-row-inner { + display: flex; + align-items: center; +} +.daggerheart.views.levelup .levelup-section .levelup-container .levelup-inner-container .levelup-body .levelup-choice-row .levelup-choice-input-container { + position: relative; + display: flex; + align-items: center; +} +.daggerheart.views.levelup .levelup-section .levelup-container .levelup-inner-container .levelup-body .levelup-choice-row .levelup-choice-input-container input:disabled:checked::before { + opacity: 0.4; + color: var(--color-warm-1); +} +.daggerheart.views.levelup .levelup-section .levelup-container .levelup-inner-container .levelup-body .levelup-choice-row .levelup-choice-input-container i.fa-link { + transform: rotate(45deg); + position: relative; + top: 2px; + margin: 0 -3px; +} +.daggerheart.views.levelup .levelup-section .levelup-container .levelup-inner-container .levelup-body .levelup-choice-row .levelup-choice-input-container i.fa-lock { + position: absolute; + top: 0; + left: 0; + font-size: 8px; +} +.daggerheart.views.levelup .levelup-section .levelup-container .levelup-inner-container .levelup-posttext { + padding: 8px 0; +} +.daggerheart.views .downtime-container .activity-container { + display: flex; + align-items: center; + padding: 8px; +} +.daggerheart.views .downtime-container .activity-container .activity-title { + flex: 1; + display: flex; + align-items: center; +} +.daggerheart.views .downtime-container .activity-container .activity-title .activity-title-text { + font-size: 24px; + font-weight: bold; +} +.daggerheart.views .downtime-container .activity-container .activity-title .activity-image { + width: 120px; + border: 2px solid black; + border-radius: 50%; + margin-right: 8px; + cursor: pointer; +} +.daggerheart.views .downtime-container .activity-container .activity-title .activity-image:hover, +.daggerheart.views .downtime-container .activity-container .activity-title .activity-image.selected { + filter: drop-shadow(0 0 6px gold); +} +.daggerheart.views .downtime-container .activity-container .activity-title .custom-name-input { + font-size: 24px; + font-weight: bold; + padding: 0; + background: transparent; + color: #efe6d8; +} +.daggerheart.views .downtime-container .activity-container .activity-body { + flex: 1; + font-style: italic; +} +.daggerheart.views.downtime .activity-text-area { + resize: none; +} +.daggerheart.views .range-reset { + flex: 0; + width: 21px; + height: 21px; + margin: 3px 4px; + border: 1px solid black; + display: flex; + align-items: center; + justify-content: center; +} +.daggerheart.views.roll-selection .roll-selection-container i { + filter: invert(0%) sepia(100%) saturate(0%) hue-rotate(21deg) brightness(17%) contrast(103%); +} +.daggerheart.views.roll-selection .roll-dialog-container .disadvantage, +.daggerheart.views.roll-selection .roll-dialog-container .advantage { + border: 2px solid #708090; + border-radius: 6px; + display: flex; + align-items: center; + padding: 4px; + margin-bottom: 6px; +} +.daggerheart.views.roll-selection .roll-dialog-container .disadvantage.selected, +.daggerheart.views.roll-selection .roll-dialog-container .advantage.selected { + filter: drop-shadow(0px 0px 3px red); +} +.daggerheart.views.roll-selection .roll-dialog-container .disadvantage input, +.daggerheart.views.roll-selection .roll-dialog-container .advantage input { + border: 0; +} +.daggerheart.views.roll-selection .roll-dialog-container .disadvantage button, +.daggerheart.views.roll-selection .roll-dialog-container .advantage button { + flex: 0; + border-radius: 50%; + height: 20px; + width: 20px; + display: flex; + align-items: center; + justify-content: center; + margin: 2px 0 2px 4px; + padding: 12px; +} +.daggerheart.views.roll-selection .roll-dialog-container .disadvantage button i, +.daggerheart.views.roll-selection .roll-dialog-container .advantage button i { + margin: 0; +} +.daggerheart.views.roll-selection .roll-dialog-container .roll-dialog-experience-container { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 4px; +} +.daggerheart.views.roll-selection .roll-dialog-container .roll-dialog-experience-container .roll-dialog-chip { + border: 1px solid black; + border-radius: 6px; + min-width: calc(33% - 2px); + flex: 1; + display: flex; + align-items: center; + justify-content: center; + gap: 4px; + cursor: pointer; + padding: 4px; + background: grey; + overflow: hidden; + font-weight: bold; +} +.daggerheart.views.roll-selection .roll-dialog-container .roll-dialog-experience-container .roll-dialog-chip.hover { + filter: drop-shadow(0 0 3px red); +} +.daggerheart.views.roll-selection .roll-dialog-container .roll-dialog-experience-container .roll-dialog-chip span { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.daggerheart.views.roll-selection .roll-dialog-container .roll-dialog-experience-container .roll-dialog-chip.selected { + background: green; +} +.daggerheart.views.roll-selection .roll-dialog-container .roll-dialog-experience-container .roll-dialog-chip.selected span { + filter: drop-shadow(0 0 3px gold); +} +.daggerheart.views.roll-selection .roll-dialog-container .hope-container { + display: flex; + gap: 8px; + align-items: center; + font-size: 18px; +} +.daggerheart.views.npc-roll-selection .npc-roll-dialog-container { + display: flex; + flex-direction: column; +} +.daggerheart.views.npc-roll-selection .npc-roll-dialog-container .selection-container { + display: flex; + align-items: center; + margin-bottom: 8px; +} +.daggerheart.views.npc-roll-selection .npc-roll-dialog-container .selection-container .dice-container { + display: flex; + align-items: center; + flex: 1; +} +.daggerheart.views.npc-roll-selection .npc-roll-dialog-container .selection-container .dice-container .dice-inner-container { + position: relative; + display: flex; + align-items: center; +} +.daggerheart.views.npc-roll-selection .npc-roll-dialog-container .selection-container .dice-container .dice-inner-container i { + font-size: 18px; +} +.daggerheart.views.npc-roll-selection .npc-roll-dialog-container .selection-container .dice-container .dice-inner-container img { + border: 0; + position: relative; + left: 1px; +} +.daggerheart.views.npc-roll-selection .npc-roll-dialog-container .selection-container .dice-container .dice-inner-container .dice-number { + position: absolute; + top: calc(50% - 14px); + left: calc(50% - 7px); + font-size: 24px; + font-weight: bold; +} +.daggerheart.views.npc-roll-selection .npc-roll-dialog-container .roll-dialog-experience-container { + display: flex; + align-items: flex-start; + flex-wrap: wrap; + gap: 4px; + flex: 2; + height: 100%; +} +.daggerheart.views.npc-roll-selection .npc-roll-dialog-container .roll-dialog-experience-container .roll-dialog-chip { + border: 1px solid black; + border-radius: 6px; + flex-basis: calc(50% - 2px); + display: flex; + align-items: center; + justify-content: space-between; + cursor: pointer; + padding: 4px; + background: grey; + overflow: hidden; +} +.daggerheart.views.npc-roll-selection .npc-roll-dialog-container .roll-dialog-experience-container .roll-dialog-chip.hover { + filter: drop-shadow(0 0 3px red); +} +.daggerheart.views.npc-roll-selection .npc-roll-dialog-container .roll-dialog-experience-container .roll-dialog-chip span { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.daggerheart.views.npc-roll-selection .npc-roll-dialog-container .roll-dialog-experience-container .roll-dialog-chip.selected i { + color: green; +} +.daggerheart.views.multiclass .multiclass-container { + margin-bottom: 16px; +} +.daggerheart.views.multiclass .multiclass-container .multiclass-category-title { + margin-top: 16px; +} +.daggerheart.views.multiclass .multiclass-container .multiclass-class-choices { + display: flex; + width: 100%; + height: 100%; + flex-wrap: wrap; +} +.daggerheart.views.multiclass .multiclass-container .multiclass-spaced-choices { + display: flex; + justify-content: space-around; + width: 100%; + height: 100%; +} +.daggerheart.views.multiclass .multiclass-container .multiclass-class-choice { + display: flex; + align-items: center; + flex-basis: 33.33%; + font-weight: bold; + font-size: 24px; + cursor: pointer; +} +.daggerheart.views.multiclass .multiclass-container .multiclass-class-choice.selected:not(.disabled), +.daggerheart.views.multiclass .multiclass-container .multiclass-class-choice:hover:not(.disabled) { + filter: drop-shadow(0 0 3px gold); +} +.daggerheart.views.multiclass .multiclass-container .multiclass-class-choice.inactive, +.daggerheart.views.multiclass .multiclass-container .multiclass-class-choice.disabled { + cursor: initial; + opacity: 0.4; +} +.daggerheart.views.multiclass .multiclass-container .multiclass-class-choice img { + width: 80px; + height: 80px; + margin-right: 16px; +} +.daggerheart.views.damage-selection .hope-container { + display: flex; + gap: 8px; + align-items: center; + font-size: 18px; +} +.daggerheart.views.action .action-category { + display: flex; + flex-direction: column; +} +.daggerheart.views.action .action-category .action-category-label { + display: flex; + align-items: center; + justify-content: space-between; + border-radius: 6px; + cursor: pointer; + padding: 0 4px; + margin: 0 auto 4px; +} +.daggerheart.views.action .action-category .action-category-label:hover { + background-color: darkgray; +} +.daggerheart.views.action .action-category .action-category-data { + max-height: 0; + transition: max-height 0.2s ease-in-out; + overflow: hidden; +} +.daggerheart.views.action .action-category .action-category-data.open { + max-height: initial; +} +.daggerheart.views.ancestry-selection .ancestry-section { + display: flex; + flex-direction: column; + align-items: center; + margin-bottom: 8px; +} +.daggerheart.views.ancestry-selection .ancestry-section .ancestry-container { + width: 100%; + display: flex; + flex-wrap: wrap; +} +.daggerheart.views.ancestry-selection .ancestry-section .ancestry-container .ancestry-inner-container { + flex-basis: 25%; + display: flex; + flex-direction: column; + align-items: center; +} +.daggerheart.views.ancestry-selection .ancestry-section .ancestry-container .ancestry-inner-container .image-container img { + width: 120px; + border: 4px solid black; + border-radius: 50%; +} +.daggerheart.views.ancestry-selection .ancestry-section .ancestry-container .ancestry-inner-container .image-container img.selected { + border-color: gold; +} +.daggerheart.views.ancestry-selection .ancestry-section .ancestry-container .ancestry-inner-container .image-container img:hover:not(.selected) { + filter: drop-shadow(0 0 3px gold); +} +.daggerheart.views.ancestry-selection .ancestry-section .ancestry-container .ancestry-inner-container .image-container img.disabled { + opacity: 0.3; +} +.daggerheart.views.ancestry-selection .ancestry-section .ancestry-container .ancestry-inner-container .name-container div { + font-size: 18px; + font-weight: bold; + cursor: help; +} +.daggerheart.views.ancestry-selection .ancestry-section .mixed-ancestry-container { + width: 100%; + display: flex; + gap: 8px; +} +.daggerheart.views.ancestry-selection .ancestry-section .mixed-ancestry-container > div { + flex: 1; +} +.daggerheart.views.ancestry-selection .ancestry-section .mixed-ancestry-container .mixed-ancestry-name { + text-align: center; +} +.daggerheart.views.ancestry-selection .ancestry-section .mixed-ancestry-container .mixed-ancestry-name div { + font-size: 24px; +} +.daggerheart.views.ancestry-selection .ancestry-section .mixed-ancestry-container .mixed-ancestry-images { + display: flex; + align-items: center; + gap: 4px; +} +.daggerheart.views.ancestry-selection .ancestry-section .mixed-ancestry-container .mixed-ancestry-images .mixed-ancestry-image { + position: relative; + max-width: 33%; +} +.daggerheart.views.ancestry-selection .ancestry-section .mixed-ancestry-container .mixed-ancestry-images .mixed-ancestry-image:hover i { + opacity: 1; +} +.daggerheart.views.ancestry-selection .ancestry-section .mixed-ancestry-container .mixed-ancestry-images .mixed-ancestry-image i { + position: absolute; + font-size: 32px; + top: calc(50% - 20px); + left: calc(50% - 20px); + padding: 4px; + background-color: grey; + opacity: 0; + cursor: pointer; +} +.daggerheart.views.ancestry-selection .ancestry-section .mixed-ancestry-container .mixed-ancestry-images .mixed-ancestry-image i:hover { + filter: drop-shadow(0 0 3px gold); +} +.daggerheart.views.ancestry-selection .ancestry-section .mixed-ancestry-container .mixed-ancestry-images .mixed-ancestry-image img { + max-width: 100%; +} +.daggerheart.views.ancestry-selection .ancestry-section .mixed-ancestry-container .mixed-ancestry-images img { + max-width: 33%; + border: 4px solid black; + border-radius: 50%; +} +.daggerheart.views.ancestry-selection .ancestry-section .mixed-ancestry-container .mixed-ancestry-images img.selected { + border-color: gold; +} +.daggerheart.sheet.heritage .editor { + height: 200px; +} +.daggerheart.sheet.class .guide .guide-section { + gap: 8px; +} +.daggerheart.sheet.class .guide .drop-section { + width: 100%; +} +.daggerheart.sheet.class .guide .drop-section legend { + margin-left: auto; + margin-right: auto; + font-size: 12px; +} +.daggerheart.sheet.class .guide .drop-section .drop-section-body { + min-height: 40px; + display: flex; + flex-direction: column; + align-items: center; +} +.daggerheart.sheet.class .guide .trait-input { + text-align: center; + min-width: 24px; +} +.daggerheart.sheet.class .guide .suggested-item { + padding: 2px 4px; + border-radius: 6px; + border: 1px solid black; + background: #778899; + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; +} +.daggerheart.sheet.class .guide .suggested-item:not(:last-child) { + margin: 4px; +} +.daggerheart.sheet.class .guide .suggested-item img { + width: 30px; +} +.daggerheart.sheet.class .guide .suggested-item div { + text-align: center; +} +.daggerheart.sheet.class .guide .suggested-item i { + border-radius: 50%; + margin-right: 4px; + font-size: 11px; +} +.daggerheart.sheet.class .guide .extra-section { + display: flex; + flex-direction: column; + align-items: center; +} +.daggerheart.sheet.class .guide .extra-section .extra-title { + font-size: 14px; + font-weight: bold; +} +.daggerheart.sheet.class .guide .extra-section .extra-input { + margin-bottom: 4px; +} +.daggerheart.sheet.class .guide-section-title-centered { + font-weight: bold; + font-size: 18px; +} +.daggerheart.sheet.class .inventory-section { + width: 100%; + border: 2px solid black; + border-style: dotted; + min-height: 80px; +} +.daggerheart.sheet.class .inventory-section .inventory-title { + font-weight: bold; + font-size: 14px; + text-align: center; +} +.daggerheart.sheet.class .tagify { + background: var(--color-light-1); + border: 1px solid var(--color-border); + height: 34px; + width: 100%; + border-radius: 3px; + margin-right: 1px; +} +.daggerheart.sheet.class .tagify tag div { + display: flex; + justify-content: space-between; + align-items: center; + height: 22px; +} +.daggerheart.sheet.class .tagify tag div span { + font-weight: 400; +} +.daggerheart.sheet.class .tagify tag div img { + margin-left: 8px; + height: 20px; + width: 20px; +} +.daggerheart.sheet.adversary .adversary-header-container { + position: relative; + background-color: grey; + display: flex; +} +.daggerheart.sheet.adversary .adversary-header-container .adversary-header { + flex: 1; +} +.daggerheart.sheet.adversary .adversary-header-container .adversary-header img { + height: 60px; + width: 60px; +} +.daggerheart.sheet.adversary .adversary-header-container .adversary-header .adversary-title { + display: flex; + align-items: center; + text-align: center; + font-size: 28px; +} +.daggerheart.sheet.adversary .adversary-header-container .adversary-header .adversary-title .title-text { + width: 100%; +} +.daggerheart.sheet.adversary .adversary-header-container .adversary-header .adversary-title input { + font-size: 28px; + border: 0; + height: 100%; +} +.daggerheart.sheet.adversary .adversary-header-container .adversary-toggle { + position: absolute; + top: 0; + right: 0; + background-color: white; + color: black; + flex: 0; +} +.daggerheart.sheet.adversary .motive-container { + background: lightgrey; + margin-bottom: 8px; + padding-bottom: 4px; +} +.daggerheart.sheet.adversary .motive-container .motive-title { + display: flex; + align-items: center; + justify-content: center; + flex-wrap: wrap; +} +.daggerheart.sheet.adversary .motive-container .motive-title .motive-title-base { + font-size: 21px; +} +.daggerheart.sheet.adversary .motive-container .motive-title .motive-title-value { + font-style: italic; + position: relative; + top: 2px; +} +.daggerheart.sheet.adversary .motive-container .motive-title i { + margin-left: 4px; + cursor: pointer; +} +.daggerheart.sheet.adversary .motive-container .motive-title i:hover { + filter: drop-shadow(0 0 3px red); +} +.daggerheart.sheet.adversary .adversary-content-container { + display: flex; + align-items: baseline; +} +.daggerheart.sheet.adversary .adversary-statistics-container { + flex: 1; + margin-right: 24px; + display: flex; + flex-direction: column; + gap: 12px; +} +.daggerheart.sheet.adversary .adversary-statistics-container .statistic-title { + flex: 0; + white-space: nowrap; + font-weight: bold; +} +.daggerheart.sheet.adversary .adversary-statistics-container .statistic-row { + display: flex; + align-items: center; +} +.daggerheart.sheet.adversary .adversary-statistics-container .statistic-row .statistic-value { + flex: 0; + white-space: nowrap; + margin-left: 4px; +} +.daggerheart.sheet.adversary .adversary-statistics-container .statistic-row .adversary-roll { + border: 0; + width: 16px; + margin-left: 4px; + align-self: baseline; + transition: transform 0.2s; +} +.daggerheart.sheet.adversary .adversary-statistics-container .statistic-row .adversary-roll:hover { + transform: rotate(30deg); + filter: drop-shadow(0px 0px 3px red); + cursor: pointer; +} +.daggerheart.sheet.adversary .adversary-statistics-container .statistic-resource-container { + display: flex; + align-items: center; +} +.daggerheart.sheet.adversary .adversary-statistics-container .statistic-resource-container label { + min-width: 44px; +} +.daggerheart.sheet.adversary .adversary-statistics-container .statistic-resource-container .statistic-resource-inner-container { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 4px; +} +.daggerheart.sheet.adversary .adversary-statistics-container .statistic-resource-container .resource-title { + align-self: center; + font-weight: bold; +} +.daggerheart.sheet.adversary .adversary-statistics-container .statistic-resource-container .statistic-resource-input { + margin: 0; + flex: 0; + min-width: 16px; +} +.daggerheart.sheet.adversary .adversary-statistics-container .attack-container { + border: 1px solid black dotted; +} +.daggerheart.sheet.adversary .adversary-statistics-container .experience-row { + display: flex; +} +.daggerheart.sheet.adversary .adversary-statistics-container .experience-row * { + flex: 0; + white-space: nowrap; +} +.daggerheart.sheet.adversary .adversary-statistics-container .experience-container i { + margin-left: 4px; + cursor: pointer; +} +.daggerheart.sheet.adversary .adversary-statistics-container .experience-container i:hover { + filter: drop-shadow(0 0 3px red); +} +.daggerheart.sheet.adversary .adversary-statistics-container .experience-chip { + border: 2px solid #708090; + border-radius: 6px; + display: flex; + align-items: center; + padding: 4px; + margin-bottom: 6px; +} +.daggerheart.sheet.adversary .adversary-statistics-container .experience-chip .experience-text { + flex: 1; +} +.daggerheart.sheet.adversary .adversary-statistics-container .experience-chip .experience-value { + flex: 0; + min-width: 26px; + margin: 0 4px; +} +.daggerheart.sheet.adversary .adversary-statistics-container .experience-chip .experience-button { + flex: 0; + border-radius: 50%; + height: 20px; + width: 20px; + display: flex; + align-items: center; + justify-content: center; + padding: 12px; +} +.daggerheart.sheet.adversary .adversary-damage-threshold-container input { + min-width: 26px; +} +.daggerheart.sheet.adversary .adversary-moves-container { + flex: 2.5; +} +.daggerheart.sheet.adversary .adversary-moves-container .moves-title { + text-decoration: underline; + font-weight: bold; +} +.daggerheart.sheet.adversary .adversary-moves-container .move-container { + cursor: pointer; +} +.daggerheart.sheet.adversary .adversary-moves-container .move-container:hover { + background: #2f4f4f40; +} +.daggerheart.sheet.adversary .adversary-moves-container .move-container .moves-name { + font-weight: bold; + text-decoration: none; +} +.daggerheart.sheet.adversary .adversary-moves-container .move-container .move-description p { + margin-top: 0; +} +.daggerheart.sheet.adversary .adversary-moves-container .moves-edit-container i { + margin-left: 4px; + cursor: pointer; +} +.daggerheart.sheet.adversary .adversary-moves-container .moves-edit-container i:hover { + filter: drop-shadow(0 0 3px red); +} +.daggerheart.sheet.adversary .chip-container { + display: flex; + align-items: center; + justify-content: space-between; + background: #778899; + padding: 8px; + border: 2px solid black; + border-radius: 6px; +} +.daggerheart.sheet.adversary .chip-container:not(:last-child) { + margin-bottom: 8px; +} +.daggerheart.sheet.adversary .chip-container .chip-inner-container { + display: flex; + align-items: center; +} +.daggerheart.sheet.adversary .chip-container .chip-inner-container img { + height: 40px; + width: 40px; + margin-right: 8px; +} +.daggerheart.sheet.adversary .chip-container .chip-inner-container .chip-title { + font-size: 22px; + font-weight: bold; + font-style: italic; +} +.daggerheart.sheet.adversary .chip-container button { + height: 40px; + width: 40px; + background: white; +} +.daggerheart.sheet .title-container { + display: flex; + gap: 8px; +} +.daggerheart.sheet .title-container div { + flex: 1; + align-items: baseline; +} +.daggerheart.sheet .editor-form-group { + display: flex; + flex-direction: column; +} +.daggerheart.sheet .editor-form-group label { + font-weight: bold; + text-align: center; +} +.daggerheart.sheet .option-select { + position: absolute; + top: calc(50% - 10px); + right: 8px; + height: 20px; + width: 20px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + padding: 8px; +} +.daggerheart.sheet .option-select.deeper { + right: 32px; +} +.daggerheart.sheet .option-select:hover:not(:disabled) { + filter: drop-shadow(0px 0px 3px red); + cursor: pointer; +} +.daggerheart.sheet .option-select i { + margin: 0; + font-size: 11px; +} +.daggerheart.sheet .ability-title { + width: 100%; + display: flex; +} +.daggerheart.sheet .ability-title h2 { + flex: 1; +} +.daggerheart.sheet .ability-title i { + cursor: pointer; +} +.daggerheart.sheet .ability-title i:hover { + filter: drop-shadow(0px 0px 3px red); +} +.daggerheart.sheet .ability-choices { + display: flex; + align-items: center; + flex-wrap: wrap; +} +.daggerheart.sheet .ability-chip { + border: 2px solid #708090; + border-radius: 6px; + display: flex; + align-items: center; + padding: 4px; + margin-bottom: 6px; + flex: calc(33% - 4px); + max-width: calc(33% - 4px); +} +.daggerheart.sheet .ability-chip.selected { + filter: drop-shadow(0px 0px 3px red); +} +.daggerheart.sheet .ability-chip:nth-of-type(3n-1) { + margin-left: 6px; + margin-right: 6px; +} +.daggerheart.sheet .ability-chip input { + border: 0; +} +.daggerheart.sheet .ability-chip button { + flex: 0; + border-radius: 50%; + height: 20px; + width: 20px; + display: flex; + align-items: center; + justify-content: center; + margin: 2px 0 2px 4px; + padding: 12px; +} +.daggerheart.sheet .ability-chip button i { + margin: 0; +} +.daggerheart.sheet .object-select-display { + position: relative; + width: calc(100% - 2px); + background: rgba(0, 0, 0, 0.05); + height: var(--form-field-height); + display: flex; + border: 1px solid #7a7971; + border-radius: 3px; +} +.daggerheart.sheet .object-select-display .object-select-title { + position: absolute; + left: 4px; + text-align: center; + font-weight: bold; + text-transform: uppercase; +} +.daggerheart.sheet .object-select-display .object-select-text { + align-self: center; +} +.daggerheart.sheet .object-select-display .object-select-item { + cursor: pointer; +} +.daggerheart.sheet .object-select-display .object-select-item:hover { + filter: drop-shadow(0px 0px 3px red); +} +.daggerheart.sheet .feature-container { + display: flex; + align-items: center; + justify-content: space-between; + background: #778899; + padding: 8px; + border: 2px solid black; + border-radius: 6px; +} +.daggerheart.sheet .feature-container:not(:last-child) { + margin-bottom: 8px; +} +.daggerheart.sheet .feature-container .feature-inner-container { + display: flex; + align-items: center; +} +.daggerheart.sheet .feature-container .feature-inner-container img { + height: 40px; + width: 40px; + margin-right: 8px; +} +.daggerheart.sheet .feature-container .feature-inner-container .feature-title { + font-size: 22px; + font-weight: bold; + font-style: italic; +} +.daggerheart.sheet .feature-container button { + height: 40px; + width: 40px; + background: inherit; + border: 0; +} +.slider-container { + position: relative; + background: lightslategray; +} +.slider-container .slider-inner-container { + position: absolute; + top: 1px; + left: -60px; + background-color: inherit; + color: inherit; + border-radius: 30px; + cursor: pointer; + display: flex; + align-items: center; + height: 20px; + width: 40px; + padding: 0 4px; + border: 1px solid black; +} +.slider-container .slider-inner-container:hover { + filter: drop-shadow(0 0 3px red); +} +.slider-container .slider-inner-container input:checked { + opacity: 0; + width: 0; + height: 0; +} +.slider-container .slider-inner-container input:checked + .slider-icon { + transform: translateX(17px); + transition: 1s; +} +.slider-container .slider-inner-container .slider-icon { + position: absolute; + left: 4px; + height: 15px; + width: 15px; + border-radius: 50%; + transition: 1s; + transform: translateX(0); +} +.item-button.checked { + background: green; +} +.item-button .item-icon { + opacity: 0; + transition: opacity 0.2s; +} +.item-button .item-icon.checked { + opacity: 1; +} +#logo { + content: url(../assets/DaggerheartLogo.webp); + height: 50px; + width: 50px; + position: relative; + left: 25px; +} +.daggerheart { + /* Flex */ + /****/ +} +.daggerheart .vertical-separator { + border-left: 2px solid black; + height: 56px; + flex: 0; + align-self: center; +} +.daggerheart .flex-centered { + display: flex; + align-items: center; + justify-content: center; +} +.daggerheart .flex-col-centered { + display: flex; + flex-direction: column; + align-items: center; +} +.daggerheart .flex-spaced { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; +} +.daggerheart .flex-min { + display: flex; + flex: 0; +} +.daggerheart img[data-edit="img"] { + min-width: 64px; + min-height: 64px; +} +.daggerheart .editor { + height: 200px; +} +.daggerheart button i { + margin: 0; +} +.daggerheart .icon-button.spaced { + margin-left: 4px; +} +.daggerheart .icon-button.active { + filter: drop-shadow(0 0 3px red); +} +.daggerheart .icon-button.active.secondary { + filter: drop-shadow(0 0 3px gold); +} +.daggerheart .icon-button.disabled { + opacity: 0.6; +} +.daggerheart .icon-button:hover:not(.disabled) { + cursor: pointer; + filter: drop-shadow(0 0 3px red); +} +.daggerheart .icon-button:hover:not(.disabled).secondary { + filter: drop-shadow(0 0 3px gold); +} +#players h3 { + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: nowrap; +} +#players h3 .players-container { + display: flex; + align-items: center; +} +#players h3 .fear-control { + font-size: 10px; +} +#players h3 .fear-control.disabled { + opacity: 0.4; +} +#players h3 .fear-control:hover:not(.disabled) { + cursor: pointer; + filter: drop-shadow(0 0 3px red); +} diff --git a/styles/daggerheart.less b/styles/daggerheart.less new file mode 100644 index 00000000..a23e51aa --- /dev/null +++ b/styles/daggerheart.less @@ -0,0 +1,132 @@ +@import "./variables/variables.less"; +@import "./class.less"; +@import "./pc.less"; +@import "./ui.less"; +@import "./chat.less"; +@import "./item.less"; +@import "./application.less"; +@import "./sheets//sheets.less"; +@import "./components.less"; +@import "./dialog.less"; +@import "../node_modules/@yaireo/tagify/dist/tagify.css"; + +#logo { + content: url(../assets/DaggerheartLogo.webp); + height: 50px; + width: 50px; + position: relative; + left: 25px; +} + +.daggerheart { + .vertical-separator { + border-left: 2px solid black; + height: 56px; + flex: 0; + align-self: center; + } + + /* Flex */ + .flex-centered { + display: flex; + align-items: center; + justify-content: center; + } + + .flex-col-centered { + display: flex; + flex-direction: column; + align-items: center; + } + + .flex-spaced { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + } + + .flex-min { + display: flex; + flex: 0; + } + + /****/ + img[data-edit="img"] { + min-width: 64px; + min-height: 64px; + } + + .editor { + height: 200px; + } + + button { + i { + margin: 0; + } + } + + .icon-button { + &.spaced { + margin-left: @halfMargin; + } + + &.active { + filter: drop-shadow(0 0 3px @mainShadow); + + &.secondary { + filter: drop-shadow(0 0 3px @secondaryShadow); + } + } + + &.disabled { + opacity: 0.6; + } + + + &:hover:not(.disabled){ + cursor: pointer; + filter: drop-shadow(0 0 3px @mainShadow); + + &.secondary { + filter: drop-shadow(0 0 3px @secondaryShadow); + } + } + } + + // .window-content { + // background: crimson; + + // > form, >div { + // background: url(../ui/parchment.jpg) repeat; + // } + // } +} + +#players { + h3 { + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: nowrap; + + .players-container { + display: flex; + align-items: center; + } + + .fear-control { + font-size: 10px; + + &.disabled { + opacity: 0.4; + } + + &:hover:not(.disabled) { + cursor: pointer; + filter: drop-shadow(0 0 3px @mainShadow); + } + } + } +} \ No newline at end of file diff --git a/styles/dialog.less b/styles/dialog.less new file mode 100644 index 00000000..593b7cb2 --- /dev/null +++ b/styles/dialog.less @@ -0,0 +1,12 @@ +.item-button { + &.checked { + background: green; + } + .item-icon { + opacity: 0; + transition: opacity 0.2s; + &.checked { + opacity: 1; + } + } +} \ No newline at end of file diff --git a/styles/item.less b/styles/item.less new file mode 100644 index 00000000..752fcf07 --- /dev/null +++ b/styles/item.less @@ -0,0 +1,60 @@ +.daggerheart.sheet { + &.feature { + background-color: red; + .editable { + display: flex; + flex-direction: column; + } + + .sheet-body { + flex: 1; + display: flex; + flex-direction: column; + } + .feature-description { + flex: 1; + display: flex; + flex-direction: column; + } + } + + &.class { + .class-feature { + display: flex; + img { + width: 40px; + } + button { + width: 40px; + } + } + } + + .domain-card-description { + .editor { + height: 300px; + } + } + + .item-container { + margin-top: @halfMargin; + gap: @halfMargin; + align-items: baseline; + } + + .item-sidebar { + border-right: @thinBorder groove darkgray; + min-width: 160px; + flex: 0; + padding: @fullPadding; + + label { + margin-right: @fullMargin; + font-weight: bold; + } + + input[type="checkbox"] { + margin: 0; + } + } +} \ No newline at end of file diff --git a/styles/pc.less b/styles/pc.less new file mode 100644 index 00000000..6f83d41e --- /dev/null +++ b/styles/pc.less @@ -0,0 +1,1506 @@ +.daggerheart.sheet.pc { + width: 810px !important; // Form won't apply height for some reason + + div[data-application-part] { + display: flex; + flex-direction: column; + + .pc-sheet-header { + display: flex; + gap: @halfMargin; + height: 120px; + margin-bottom: @halfMargin; + + .portrait { + border: 0; + border-right: @thinBorder solid var(--color-underline-header); + } + + .class-info { + flex: 1; + background: @primaryAccent; + // -webkit-clip-path: polygon(0 0, 100% 0, calc(100% - 55px) 100%, 0px 100%); + // clip-path: polygon(0 0, 100% 0, calc(100% - 75px) 100%, 0px 100%); + + .portrait { + max-width: 120px; + } + + .class-title { + text-align: center; + display: flex; + justify-content: space-between; + + span:hover { + filter: drop-shadow(0px 0px 3px red); + cursor: pointer; + } + + .domain-container { + margin-left: @halfMargin; + } + } + + .class-add-container { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + flex: 0; + + button { + height: 22px; + width: 22px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + margin-left: @halfMargin; + background: @primaryAccent; + } + } + + .domain-title { + text-transform: uppercase; + display: flex; + flex-direction: column; + align-items: center; + line-height: 23px; + font-weight: bold; + font-style: italic; + } + + .domain-image { + height: 30px; + flex: 0; + } + } + .general-info { + flex: 2; + display: flex; + flex-direction: column; + justify-content: space-between; + + .general-input { + position: relative; + + .general-title { + position: absolute; + left: 4px; + // height: 100%; + text-align: center; + font-weight: bold; + text-transform: uppercase; + } + } + + .pc-tabs { + flex: 1; + margin: 0; + } + + .rest-container { + flex-wrap: nowrap; + display: flex; + height: var(--form-field-height); + flex: 0; + + button { + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + width: var(--form-field-height); + + i { + font-size: 13px; + } + } + } + + .level-container{ + position: relative; + bottom: 4px; + flex: none; + width: 40px; + border: none; + outline: none; + margin-left: @fullMargin; + + &.levelup { + filter: drop-shadow(0px 0px 3px gold); + } + + img { + height: 40px; + width: 40px; + border: none; + } + + .level-value-container { + width: 48px; + position: absolute; + top: calc(50% - 17px); + left: calc(50% - 23px); + + .level-value { + font-weight: bold; + font-size: 20px; + text-align: center; + &:not(:hover), &:not(:focus) { + border: none; + } + } + + .levelup-marker { + position: absolute; + top: 0; + right: calc(50% - 12px); + color: gold; + filter: drop-shadow(0px 0px 3px black); + + &.double-digit { + right: calc(50% - 20px); + } + } + } + + .level-title { + position: absolute; + bottom: 2px; + width: 42px; + background-color: black; + color: white; + left: calc(50% - 21px); + text-align: center; + border-radius: 5px; + font-size: 12px; + + &.levelup { + color:gold; + filter: drop-shadow(0px 0px 3px orange); + font-weight: bold; + cursor: pointer; + &:hover { + background-color: aliceblue; + } + } + } + } + } + } + + .sheet-body { + display: flex; + flex-direction: column; + flex: 1; + + .tab-container { + height: 100%; + display: flex; + flex-direction: column; + + .tab-inner-container { + flex: 1; + + .body-section { + display: flex; + flex-direction: column; + + fieldset { + flex: 0; + } + } + } + } + + .system-info { + font-size: 12px; + font-style: italic; + font-weight: bold; + margin-top: -@halfMargin; + flex: 0; + } + + .feature-sheet-body { + gap: @halfMargin; + } + + .abilities-container { + position: relative; + display: flex; + flex-wrap: wrap; + border-radius: 6px; + padding-left: 0; + // flex: 2.5; + + legend { + margin-left: auto; + margin-right: auto; + font-weight: bold; + text-transform: uppercase; + padding: 0 @fullMargin; + position: relative; + } + + .attributes-menu { + position: absolute; + bottom: calc(50% - 12px); + font-size: 24px; + left: -8px; + } + + .attribute { + position: relative; + padding: 0 0 @fullPadding; + display: flex; + flex-direction: column; + align-items: center; + flex-basis: 33.33%; + // flex: 1; + + .attribute-banner { + position: relative; + top: 8px; + z-index: 2; + background: black; + color: white; + text-transform: uppercase; + padding: @smallPadding; + border-radius: 6px; + display: flex; + align-items: center; + overflow: hidden; + min-width: 96px; + + .attribute-roll { + position: absolute; + width: 16px; + transition: transform 0.2s; + + &:hover { + transform: rotate(30deg); + filter: drop-shadow(0px 0px 3px red); + cursor: pointer; + } + } + + .attribute-text { + width: 100%; + margin-left: @largeMargin; + font-size: 12px; + } + } + + .attribute-mark { + height: 23px; + width: 23px; + position: absolute; + right: -5px; + top: 6px; + border: 2px solid black; + border-radius: 50%; + background: white; + z-index: 2; + display: flex; + align-items: center; + justify-content: center; + + &.selectable { + border-color: gold; + filter: drop-shadow(0 0 3px black); + + &:hover i { + opacity: 0.3; + } + } + + & i.selected, &:hover i.selected { + color: green; + opacity: 1; + } + + i { + color: black; + font-size: 17px; + opacity: 0; + } + } + + .attribute-image { + position: relative; + width: fit-content; + display: flex; + + img { + height: 80px; + width: 80px; + border: none; + } + + .attribute-value { + width: 55px; + padding-right: 10px; + position: absolute; + top: calc(50% - 18px); + left: calc(50% - 24px); + font-weight: bold; + font-size: 30px; + line-height: 30px; + text-align: center; + border: none; + appearance: none; + -moz-appearance: none; + -webkit-appearance: none; + &.negative { + left: calc(50% - 29px); + } + &.unselected { + filter: drop-shadow(0 0 3px @secondaryShadow); + } + } + + .attribute-text { + width: 47px; + position: absolute; + top: calc(50% - 22px); + left: calc(50% - 24px); + font-weight: bold; + font-size: 30px; + text-align: center; + + &.negative { + left: calc(50% - 29px); + } + } + } + + .attribute-verb { + font-variant: petite-caps; + } + } + } + + .defense-row { + height: 100%; + width: 100%; + display: flex; + align-items: baseline; + justify-content: space-evenly; + + .defense-section { + display: flex; + align-items: center; + margin-right: @fullMargin; + + .defense-container { + position: relative; + padding: @fullPadding; + max-width: 100px; + + img { + border: none; + max-width: 80px; + } + + .defense-value { + width: 47px; + position: absolute; + top: calc(50% - 22px); + left: calc(50% - 24px); + font-weight: bold; + font-size: 30px; + text-align: center; + &:not(:hover), &:not(:focus) { + border: none; + } + } + + .defense-banner { + position: absolute; + bottom: 20px; + left: calc(50% - 42px); + z-index: 2; + background-color: black; + color: white; + width: 84px; + text-align: center; + } + } + } + + .armor-marks { + max-width: 67px; + padding: @fullPadding; + align-self: end; + margin-left: @halfMargin; + + .mark { + width: 16px; + height: 16px; + margin: 0px; + } + + .disabled-mark { + opacity: 0.6; + } + } + } + + .left-main-container { + position: relative; + display: flex; + flex-direction: column; + align-items: flex-start; + border-radius: @normalRadius; + + .legend { + margin-left: auto; + margin-right: auto; + font-weight: bold; + text-transform: uppercase; + padding: 0 @fullPadding; + position: relative; + } + } + + .weapon-section { + padding-top: 8px; + } + + .threshold-container { + position: relative; + display: flex; + align-items: center; + align-self: center; + + .threshold-box { + position: relative; + width: 30px; + height: 30px; + border: @normalBorder solid black; + display: flex; + align-items: center; + justify-content: center; + font-size: 20px; + font-weight: bold; + } + + .threshold-spacer { + position: relative; + z-index: 2; + width: 70px; + height: 18px; + background-color: darkgray; + color: white; + display: flex; + justify-content: center; + align-items: center; + } + } + + .resource-label { + text-transform: uppercase; + font-weight: bold; + } + + .death-save { + position: absolute; + right: -22px; + + &:hover:not(.disabled) { + filter: drop-shadow(0 0 3px @mainShadow); + cursor: pointer; + } + + &.disabled { + opacity: 0.4; + } + } + + .resource-box { + width: 20px; + height: 12px; + + &.stress:nth-child(even) { + position: relative; + right: 1px; + } + + .disabled { + opacity: 0.6; + } + } + + .hope-text { + font-size: 11.7px; + margin-right: 6px; + } + + .hope-container { + background: darkgray; + border-radius: 6px; + display: flex; + padding: @smallPadding 0px; + + .vertical-separator { + border-left: 2px solid white; + height: auto; + margin: @halfMargin 0; + flex: 0; + } + + .hope-inner-container { + position: relative; + + .hope-value { + width: 16px; + height: 16px; + } + + .hope-scar { + position: absolute; + top: calc(50% - 6px); + left: calc(50% - 7px); + opacity: 0.4; + font-size: 12px; + -webkit-transform: scaleX(-1); + transform: scaleX(-1); + } + } + } + + .experience-row { + width: 100%; + display: flex; + align-items: flex-end; + + .experience-selector { + font-size: 18px; + cursor: pointer; + margin-right: @halfMargin; + opacity: 0.5; + + &:hover:not(.selected) { + filter: drop-shadow(0 0 3px gold); + } + + &.selected { + filter: drop-shadow(0 0 3px gold); + opacity: 1; + } + } + + .experience-value { + margin-left: @fullMargin; + width: 30px; + border-bottom: @normalBorder solid black; + border-radius: 4px; + text-align: center; + font-weight: bold; + + &.empty { + border: 0; + } + } + + .disabled-experience { + border: @thinBorder solid @borderTertiary; + background: rgba(0, 0, 0, 0.20); + } + } + .gold-section { + width: calc(100% - 8px); + display: flex; + justify-content: space-between; + + fieldset.gold-fieldset { + padding-right: 0; + padding-left: 0; + padding-bottom: @fullPadding; + + legend { + margin-left: auto; + margin-right: auto; + font-size: 15px; + font-variant: all-petite-caps; + font-weight: bold; + } + + .gold-column { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100%; + gap: @halfMargin; + } + + .gold-row { + display: flex; + align-items: center; + justify-content: center; + padding: 0 @fullPadding; + gap: @tinyMargin; + } + + .gold-row, .gold-column { + img { + min-width: 14px; + min-height: 14px; + height: 14px; + border: 0; + filter: invert(0%) sepia(100%) saturate(0%) hue-rotate(21deg) brightness(17%) contrast(103%); + + &:hover { + cursor: pointer; + filter: invert(0%) sepia(100%) saturate(0%) hue-rotate(21deg) brightness(17%) contrast(103%) drop-shadow(0 0 3px @mainShadow); + } + } + + i:hover { + cursor: pointer; + filter: drop-shadow(0 0 3px @mainShadow); + } + + img:not(.owned), i:not(.owned) { + opacity: 0.4; + } + } + } + } + + .health-category { + text-transform: uppercase; + } + + .class-feature-selectable { + cursor: pointer; + + &:hover { + filter: drop-shadow(0 0 3px @mainShadow); + } + + &.inactive { + opacity: 0.5; + } + } + + .features-container { + width: 100%; + min-height: 136px; + + .feature-container { + display: flex; + align-items: center; + justify-content: space-between; + padding: @fullPadding; + margin-bottom: 0; + + .feature-img { + max-width: 42px; + } + + .feature-label { + font-weight: bold; + font-size: 30px; + } + + button { + flex: 0; + } + } + + .feature-tick-container { + flex: 0; + min-width: 56px; + display: flex; + flex-wrap: wrap; + gap: @fullMargin; + margin: 0 @threeQuarterMargin; + + .feature-tick { + position: relative; + border: @normalBorder solid @borderTertiary; + height: 24px; + border-radius: 50%; + width: 24px; + background: rgba(0, 0, 0, 0.05); + display: flex; + justify-content: center; + + &:hover:not(.disabled):not(.used){ + cursor: pointer; + filter: drop-shadow(0 0 3px @mainShadow); + } + + &.disabled { + opacity: 0.3; + } + + img { + border: 0; + width: 24px; + height: 24px; + filter: invert(17%) sepia(0%) saturate(0%) hue-rotate(19deg) brightness(102%) contrast(84%); + } + + .feature-dice-value { + font-size: 18px; + align-self: center; + } + + &.used::after { + position: absolute; + content: "/"; + color: @borderTertiary; + font-weight: 700; + font-size: 1.7em; + left: 4px; + top: -5px; + transform: rotate(25deg); + font-size: 24.5px; + } + } + } + } + + .feature-input { + border: 0; + border-bottom: @thinBorder solid @borderTertiary; + text-align: center; + height: min-content; + background: inherit; + font-size: 20px; + position: relative; + bottom: 3px; + } + + .editor { + height: 400px; + width: 100%; + } + + .weapons-title { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + + .proficiency-container { + width: 176px; + height: 20px; + position: absolute; + bottom: -15px; + left: calc(50% - 88px); + text-transform: uppercase; + display: flex; + align-items: center; + justify-content: center; + z-index: 1; + clip-path: polygon(11% 100%, 89% 100%, 100% 0%, 0% 0%); + font-size: 10px; + + span { + margin-right: @tinyMargin; + } + + .proficiency-dot { + background: white; + color: white; + font-size: 10px; + padding: 1px; + border-radius: 50%; + + &.marked { + color: black; + } + + &:not(:last-of-type){ + margin-right: @tinyMargin; + } + } + } + } + + .weapons-burden { + position: absolute; + top: -4px; + right: -56px; + display: flex; + align-items: center; + + .weapons-burden-icon { + color: white; + font-size: 22px; + -webkit-text-stroke-width: 1px; + -webkit-text-stroke-color: black; + + &.active { + -webkit-text-stroke-color: rgba(0, 0, 0, 0.05); + color: black; + } + + &.left { + -webkit-transform: scaleX(-1) rotate(20deg); + transform: scaleX(-1) rotate(20deg); + margin-right: 4px; + } + + &.right { + transform: rotate(20deg); + } + } + } + + .armor-container { + display: flex; + align-items: center; + + .active-item-label-chip { + margin-left: @halfMargin; + } + } + + .item-section { + .active-item-container { + display: flex; + flex-direction: column; + width: 100%; + padding: @smallPadding 0px; + + .weapons-label-row { + display: flex; + align-items: center; + + .damage-roll { + width: 24px; + border: none; + margin-left: @halfMargin; + transition: transform 0.2s; + + &:hover { + transform: rotate(30deg); + filter: drop-shadow(0px 0px 3px red); + cursor: pointer; + } + } + } + } + + .active-item-label-chip { + width: 62px; + border: @normalBorder solid black; + border-radius: 6px; + background-color: @primaryAccent; + display: flex; + align-items: center; + justify-content: space-around; + margin-left: @fullPadding; + + img { + height: 20px; + } + + button { + height: 17px; + width: 17px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + background: rgb(122, 121, 113); + border-color: black; + margin: 0; + + &:hover { + background: red; + } + + i { + font-size: 10px; + color: black; + } + } + } + } + + .inventory-armor-section, .inventory-weapon-section { + width: 100%; + margin-bottom: @fullMargin; + text-transform: uppercase; + + h2 { + width: 100%; + display: flex; + align-items: center; + } + } + + .inventory-legend { + display: flex; + align-items: center; + margin-bottom: @halfMargin; + + .page-selector { + margin-left: 4px; + display: flex; + align-items: center; + + i { + &:hover:not(.disabled){ + cursor: pointer; + filter: drop-shadow(0px 0px 3px red); + } + + &.disabled { + opacity: 0.4; + } + } + } + } + + .inventory-add-button { + position: absolute; + border-radius: 50%; + height: 15px; + width: 15px; + top: -20px; + background: grey; + border-color: black; + right: 6px; + display: flex; + font-size: 13px; + align-items: center; + justify-content: center; + } + + .inventory { + width: 100%; + + .inventory-row { + height: 26px; + border-bottom: @thinBorder solid @borderTertiary; + display: flex; + margin-bottom: @fullMargin; + border-radius: 8px; + + .item-container { + flex-basis: 25%; + margin: 0 @halfMargin @fullMargin; + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + + &:hover { + filter: drop-shadow(0px 0px 3px red); + } + + .inventory-item { + background: @primaryAccent; + padding: @fullPadding; + border: @thinBorder solid black; + border-radius: 6px; + display: flex; + align-items: center; + + .inventory-item-text { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + flex: 1; + } + + button { + height: 16px; + width: 16px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + flex: 0; + background: @secondaryBackground; + border-color: black; + margin-left: @halfMargin; + + i { + font-size: 12px; + } + } + } + } + } + + .editor { + height: 100px; + } + } + + .inventory-items { + width: 100%; + flex: 1; + display: flex; + flex-direction: column; + justify-content: space-between; + } + + .domain-card-tab { + flex: 1; + + .domain-card-body { + height: 100%; + width: 100%; + padding: @largePadding; + display: flex; + flex-direction: column; + + .card-row { + flex: 1; + display: flex; + } + + .domain-card { + flex: 0; + flex-basis: 33.33%; + margin: @fullMargin; + } + + .loadout-body { + flex: 1; + + .loadout-container { + height: 100%; + display: flex; + flex-direction: column; + gap: @fullMargin; + + .top-card-row { + flex: 1; + display: flex; + justify-content: space-around; + } + + .domain-card.outlined { + border: @normalBorder dotted black; + padding: 0; + margin: @fullMargin; + height: calc(100% - 16px); + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-evenly; + } + } + } + + .vault-container { + display: flex; + flex-wrap: wrap; + overflow-y: auto; + height: 100%; + + .vault-card { + flex: 0; + flex-basis: calc(33.33% - 16px); + margin: 8px; + height: calc(50% - 16px); + min-height: calc(50% - 16px); + } + } + + .domain-card-menu { + flex: 0; + width: 120px; + height: 100%; + border-width: @normalBorder 0 @normalBorder @normalBorder; + border-color: black; + border-style: solid; + + button { + margin-bottom: @tinyMargin; + } + } + } + } + + .loadout-tabs { + border-top: @thinBorder solid @borderPrimary; + border-bottom: @thinBorder solid @borderPrimary; + } + + .abilities-card { + position: relative; + border: @thickBorder solid @secondaryAccent; + border-radius: 6px; + display: flex; + flex-direction: column; + height: 100%; + font-size: 14px; + + .abilities-card-image-container { + position: relative; + // height: 50%; + } + + .abilities-card-image { + width: 100%; + height: 100%; + aspect-ratio: 2; + } + + .abilities-text-container { + flex: 1; + position: relative; + height: 50%; + display: flex; + flex-direction: column; + overflow-y: auto; + padding: 12px 4px 4px; + } + + .abilities-card-level { + position: absolute; + top: 0; + left: 12px; + color: black; + height: 60px; + border: @normalBorder solid orange; + border-top-width: 0; + width: 30px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-evenly; + background: grey; + font-size: 20px; + font-weight: bold; + + img { + border: 0; + width: 20px; + } + } + .abilities-card-refresh-cost { + position: absolute; + top: 12px; + right: 12px; + color: white; + width: 30px; + height: 30px; + border: @normalBorder solid orange; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + background: black; + font-size: 14px; + i { + font-size: 11px; + } + } + + .abilities-card-type { + flex: 0; + display: flex; + justify-content: center; + align-items: center; + font-weight: bold; + position: absolute; + left: 0; + text-align: center; + width: 100%; + bottom: -9px; + z-index: 1; + + .abilities-card-type-text{ + padding: 0px 4px; + border: 1px solid black; + border-radius: 6px; + background: gold; + } + } + + .abilities-card-title { + flex: 0; + display: flex; + justify-content: center; + align-items: center; + font-weight: bold; + font-size: 18px; + } + + .abilities-card-sub-title { + flex: 0; + display: flex; + justify-content: center; + align-items: center; + font-style: italic; + font-size: 12px; + } + + .abilities-card-spellcast { + flex: 0; + display: flex; + justify-content: center; + align-items: center; + text-transform: uppercase; + font-size: 12px; + + .title { + font-weight: bold; + } + } + + .abilities-card-description { + flex: 0; + font-size: 12px; + margin-bottom: 4px; + } + + .abilities-card-effect { + cursor: pointer; + + &:hover { + background: rgb(47 79 79 / 25%); + } + + > * { + margin-top: 0; + margin-bottom: 0; + } + } + + .abilities-card-abilities { + flex: 1; + display: flex; + flex-direction: column; + gap: 4px; + + .abilities-card-ability { + font-size: 12px; + cursor: pointer; + + &:hover { + background: rgb(47 79 79 / 25%); + } + + > * { + margin: 0; + } + } + } + + &:hover .abilities-card-menu{ + height: 40px; + left: 0px; + } + + .abilities-card-menu { + display: flex; + justify-content: center; + align-items: center; + height: 0; + transition: height 0.2s; + overflow: hidden; + position: absolute; + bottom: 0; + z-index: 2; + width: 100%; + background: grey; + + button { + font-weight: bold; + } + } + } + + .heritage-container { + height: 100%; + display: flex; + flex-direction: column; + gap: @fullMargin; + + .card-row { + height: 50%; + display: flex; + justify-content: space-around; + } + + .heritage-card { + flex-basis: 33.33%; + margin: @fullMargin; + display: flex; + align-items: center; + justify-content: center; + + &.outlined { + border: @normalBorder dotted black; + font-size: 25px; + } + } + } + + .empty-ability-container { + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + font-size: 25px; + opacity: 0.7; + + .empty-ability-inner-container { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + + i { + font-size: 48px; + } + } + } + + .story-container { + gap: @largeMargin; + + .story-fieldset { + border-radius: 6px; + } + + .story-legend { + margin-left: auto; + margin-right: auto; + padding: 0 8px; + font-size: 30px; + font-weight: bold; + } + + .scars-container { + .editor { + height: 240px; + } + } + } + + .inventory-container { + height: 100%; + overflow: auto; + + .inventory-item-list { + list-style-type:none; + padding: 0 @largePadding; + margin-top: 0; + + &.inventory-item-header { + margin-bottom: 0; + } + + .inventory-title-row-container { + display: flex; + align-items: center; + width: 100%; + border-bottom: @thickBorder ridge slategrey; + + .inventory-title-row { + justify-content: space-between; + flex: 1; + } + + .inventory-item-title-container { + flex: 1; + display: flex; + align-items: center; + justify-content: flex-start; + } + + .inventory-item-quantity { + width: 48px; + display: flex; + align-items: center; + margin-right: 96px; // Icon toolbar spacing + } + } + + .inventory-item { + background: crimson; + + &:not(:last-of-type) { + border-bottom: @normalBorder ridge slategrey; + } + + .inventory-item-title-container { + flex: 1; + display: flex; + align-items: center; + justify-content: flex-start; + + .inventory-item-title { + display: flex; + align-items: center; + cursor: pointer; + + &:hover { + filter: drop-shadow(0 0 3px @secondaryShadow); + } + } + } + + .inventory-item-quantity { + width: 48px; + display: flex; + align-items: center; + + &.spaced { + margin-right: 56px; + } + + input { + margin: 0 @tinyMargin; + border: 0; + border-bottom: 2px solid black; + } + + i { + font-size: 20px; + } + } + } + + .inventory-title-row { + font-size: 20px; + font-weight: bold; + display: flex; + align-items: center; + padding: 0 @fullPadding; + } + + .inventory-row { + display: flex; + align-items: center; + padding: @fullPadding; + font-size: 24px; + + .row-icon { + margin-left: @halfMargin; + } + + .active-item { + position: absolute; + font-size: 16px; + left: calc(50% - 8px); + top: calc(50% - 8px); + margin-left: @tinyMargin; + color: crimson; + } + + img { + width: 32px; + } + } + } + } + } + } +} \ No newline at end of file diff --git a/styles/sheets/adversary.less b/styles/sheets/adversary.less new file mode 100644 index 00000000..1a4a6f45 --- /dev/null +++ b/styles/sheets/adversary.less @@ -0,0 +1,281 @@ +.daggerheart.sheet.adversary { + .adversary-header-container { + position: relative; + background-color: grey; + display: flex; + + .adversary-header { + flex: 1; + + img { + height: 60px; + width: 60px; + } + + .adversary-title { + display: flex; + align-items: center; + text-align: center; + font-size: 28px; + + .title-text { + width: 100%; + } + + input { + font-size: 28px; + border: 0; + height: 100%; + } + } + } + + .adversary-toggle { + position: absolute; + top: 0; + right: 0; + background-color: white; + color: black; + flex: 0; + } + } + + .motive-container { + background: lightgrey; + margin-bottom: @fullMargin; + padding-bottom: @fullPadding; + + .motive-title { + display: flex; + align-items: center; + justify-content: center; + flex-wrap: wrap; + + .motive-title-base { + font-size: 21px; + } + + .motive-title-value { + font-style: italic; + position: relative; + top: 2px; + } + + i { + margin-left: 4px; + cursor: pointer; + + &:hover { + filter: drop-shadow(0 0 3px red), + } + } + } + } + + .adversary-content-container { + display: flex; + align-items: baseline; + } + + .adversary-statistics-container { + flex: 1; + margin-right: 24px; + display: flex; + flex-direction: column; + gap: @mediumMargin; + + .statistic-title { + flex: 0; + white-space: nowrap; + font-weight: bold; + } + + .statistic-row { + display: flex; + align-items: center; + + .statistic-value { + flex: 0; + white-space: nowrap; + margin-left: 4px; + } + + .adversary-roll { + border: 0; + width: 16px; + margin-left: 4px; + align-self: baseline; + transition: transform 0.2s; + + &:hover { + transform: rotate(30deg); + filter: drop-shadow(0px 0px 3px red); + cursor: pointer; + } + } + } + + .statistic-resource-container { + display: flex; + align-items: center; + + label { + min-width: 44px; + } + + .statistic-resource-inner-container { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: @halfMargin; + } + + .resource-title { + align-self: center; + font-weight: bold; + } + + .statistic-resource-input { + margin: 0; + flex: 0; + min-width: 16px; + } + } + + .attack-container { + border: 1px solid black dotted; + } + + .experience-row { + display: flex; + + * { + flex: 0; + white-space: nowrap; + } + } + + .experience-container { + i { + margin-left: 4px; + cursor: pointer; + + &:hover { + filter: drop-shadow(0 0 3px red), + } + } + } + + .experience-chip { + border: 2px solid @secondaryAccent; + border-radius: 6px; + display: flex; + align-items: center; + padding: 4px; + margin-bottom: 6px; + + .experience-text { + flex: 1; + } + + .experience-value { + flex: 0; + min-width: @inputSingleMinWidth; + margin: 0 4px; + } + + .experience-button { + flex: 0; + border-radius: 50%; + height: 20px; + width: 20px; + display: flex; + align-items: center; + justify-content: center; + padding: 12px; + } + } + } + + .adversary-damage-threshold-container { + input { + min-width: @inputSingleMinWidth; + } + } + + .adversary-moves-container { + flex: 2.5; + + .moves-title { + text-decoration: underline; + font-weight: bold; + } + .move-container { + cursor: pointer; + + &:hover { + background: @hoverBackground; + } + + .moves-name { + font-weight: bold; + text-decoration: none;; + } + + .move-description { + p { + margin-top: 0; + } + } + } + + .moves-edit-container { + + i { + margin-left: 4px; + cursor: pointer; + + &:hover { + filter: drop-shadow(0 0 3px red), + } + } + } + } + + .chip-container { + display: flex; + align-items: center; + justify-content: space-between; + background: @primaryAccent; + padding: 8px; + border: 2px solid black; + border-radius: 6px; + + &:not(:last-child) { + margin-bottom: 8px; + } + + .chip-inner-container { + display: flex; + align-items: center; + + img { + height: 40px; + width: 40px; + margin-right: 8px; + } + + .chip-title { + font-size: 22px; + font-weight: bold; + font-style: italic; + } + } + + button { + height: 40px; + width: 40px; + background: white; + } + } +} \ No newline at end of file diff --git a/styles/sheets/class.less b/styles/sheets/class.less new file mode 100644 index 00000000..4eb8a6f8 --- /dev/null +++ b/styles/sheets/class.less @@ -0,0 +1,119 @@ +.daggerheart.sheet.class { + .guide { + .guide-section { + gap: @fullMargin; + } + + .drop-section { + width: 100%; + + legend { + margin-left: auto; + margin-right: auto; + font-size: 12px; + } + + .drop-section-body { + min-height: 40px; + display: flex; + flex-direction: column; + align-items: center; + } + } + + .trait-input { + text-align: center; + min-width: 24px; + } + + .suggested-item { + padding: @smallPadding @fullPadding; + border-radius: 6px; + border: @thinBorder solid black; + background: @primaryAccent; + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + + &:not(:last-child) { + margin: @halfMargin; + } + + img { + width: 30px; + } + + div { + text-align: center; + } + + i { + border-radius: 50%; + margin-right: 4px; + font-size: 11px; + } + } + + .extra-section { + display: flex; + flex-direction: column; + align-items: center; + + .extra-title { + font-size: 14px; + font-weight: bold; + } + + .extra-input { + margin-bottom: @halfMargin; + } + } + } + + .guide-section-title-centered { + font-weight: bold; + font-size: 18px; + } + + .inventory-section { + width: 100%; + border: 2px solid black; + border-style: dotted; + min-height: 80px; + + .inventory-title { + font-weight: bold; + font-size: 14px; + text-align: center; + } + } + + .tagify { + background: var(--color-light-1); + border: 1px solid var(--color-border); + height: 34px; + width: 100%; + border-radius: 3px; + margin-right: 1px; + + tag { + div { + display: flex; + justify-content: space-between; + align-items: center; + height: 22px; + + span { + font-weight: 400; + } + + img { + margin-left: 8px; + height: 20px; + width: 20px; + } + } + } + } +} \ No newline at end of file diff --git a/styles/sheets/heritage.less b/styles/sheets/heritage.less new file mode 100644 index 00000000..c16bf582 --- /dev/null +++ b/styles/sheets/heritage.less @@ -0,0 +1,6 @@ +.daggerheart.sheet.heritage { + .editor { + height: 200px; + } + +} \ No newline at end of file diff --git a/styles/sheets/sheets.less b/styles/sheets/sheets.less new file mode 100644 index 00000000..31de74f3 --- /dev/null +++ b/styles/sheets/sheets.less @@ -0,0 +1,186 @@ +@import "./heritage.less"; +@import "./class.less"; +@import "./adversary.less"; + +.daggerheart.sheet { + .title-container { + display: flex; + gap: @fullMargin; + + div { + flex: 1; + align-items: baseline; + } + } + + .editor-form-group { + display: flex; + flex-direction: column; + + label { + font-weight: bold; + text-align: center; + } + } + + .option-select { + position: absolute; + top: calc(50% - 10px); + right: 8px; + height: 20px; + width: 20px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + padding: 8px; + + &.deeper { + right: 32px; + } + + &:hover:not(:disabled) { + filter: drop-shadow(0px 0px 3px @mainShadow); + cursor: pointer; + } + + i { + margin: 0; + font-size: 11px; + } + } + + .ability-title { + width: 100%; + display: flex; + + h2 { + flex: 1; + } + + i { + cursor: pointer; + + &:hover { + filter: drop-shadow(0px 0px 3px @mainShadow); + } + } + } + + .ability-choices { + display: flex; + align-items: center; + flex-wrap: wrap; + } + + .ability-chip { + border: 2px solid @secondaryAccent; + border-radius: 6px; + display: flex; + align-items: center; + padding: 4px; + margin-bottom: 6px; + flex: calc(33% - 4px); + max-width: calc(33% - 4px); + + &.selected { + filter: drop-shadow(0px 0px 3px @mainShadow); + } + + &:nth-of-type(3n-1) { + margin-left: 6px; + margin-right: 6px; + } + + input { + border: 0; + } + + button { + flex: 0; + border-radius: 50%; + height: 20px; + width: 20px; + display: flex; + align-items: center; + justify-content: center; + margin: 2px 0 2px 4px; + padding: 12px; + + i { + margin: 0; + } + } + } + + .object-select-display { + position: relative; + width: calc(100% - 2px); + background: rgba(0, 0, 0, 0.05); + height: var(--form-field-height);; + display: flex; + border: 1px solid rgb(122, 121, 113); + border-radius: 3px; + + .object-select-title { + position: absolute; + left: 4px; + text-align: center; + font-weight: bold; + text-transform: uppercase; + } + + .object-select-text { + align-self: center; + } + + .object-select-item { + cursor: pointer; + &:hover { + filter: drop-shadow(0px 0px 3px red); + } + } + } + + .feature-container { + display: flex; + align-items: center; + justify-content: space-between; + background: @primaryAccent; + padding: 8px; + border: 2px solid black; + border-radius: 6px; + + &:not(:last-child) { + margin-bottom: 8px; + } + + .feature-inner-container { + display: flex; + align-items: center; + + img { + height: 40px; + width: 40px; + margin-right: 8px; + } + + .feature-title { + font-size: 22px; + font-weight: bold; + font-style: italic; + } + } + + button { + height: 40px; + width: 40px; + background: inherit; + border: 0; + + i { + + } + } + } +} \ No newline at end of file diff --git a/styles/ui.less b/styles/ui.less new file mode 100644 index 00000000..d4592066 --- /dev/null +++ b/styles/ui.less @@ -0,0 +1,72 @@ +.combat-sidebar { + .encounter-gm-resources { + flex: 0; + display: flex; + justify-content: center; + padding: @largePadding 0; + + .gm-resource-controls { + display: flex; + flex-direction: column; + align-items: center; + padding: 0 4px; + justify-content: center; + } + + .gm-resource-tools { + display: flex; + flex-direction: column; + justify-content: center; + padding: 0 5px 0 @fullPadding; + + i { + margin: 0 @tinyMargin; + font-size: 16px; + + &.disabled { + opacity: 0.6; + } + + &:hover:not(.disabled) { + cursor: pointer; + filter: drop-shadow(0 0 3px @mainShadow); + } + } + } + + .gm-resource { + background: rgba(255, 255, 255, 0.1); + padding: @fullPadding; + border-radius: 8px; + border: @normalBorder solid black; + font-size: 20px; + } + } + + .token-action-tokens { + flex: 0 0 48px; + text-align: center; + + .use-action-token { + &.disabled { + opacity: 0.6; + } + } + } + + .icon-button { + &.spaced { + margin-left: @halfMargin; + } + + &.disabled { + opacity: 0.6; + } + + + &:hover:not(.disabled){ + cursor: pointer; + filter: drop-shadow(0 0 3px @mainShadow); + } + } +} diff --git a/styles/variables/colors.less b/styles/variables/colors.less new file mode 100644 index 00000000..27b74e97 --- /dev/null +++ b/styles/variables/colors.less @@ -0,0 +1,24 @@ +/* General */ +@hope: #008080; +@fear: #430070; +@critical: #ffd700; +@advantage: green; +@disadvantage: #b30000; +@miss: rgb(255, 0, 0); +@hit: rgb(0, 128, 0); +@positive: #699969; +@negative: #ff7f7f; + +@borderPrimary: #b5b3a4; +@borderTertiary: #7a7971; + +/* Drop Shadows */ +@mainShadow: red; +@secondaryShadow: gold; + +/* Background */ +@secondaryBackground: #7a7971; +@primaryAccent: #778899; +@secondaryAccent: #708090; +@formBackground: #782e22; +@hoverBackground: #2f4f4f40; \ No newline at end of file diff --git a/styles/variables/values.less b/styles/variables/values.less new file mode 100644 index 00000000..eb946e81 --- /dev/null +++ b/styles/variables/values.less @@ -0,0 +1,26 @@ +/* Base Value */ +@distance: 8; + +/* Margins */ +@tinyMargin: (@distance / 4) * 1px; +@halfMargin: (@distance / 2) * 1px; +@fullMargin: @distance * 1px; +@mediumMargin: @distance * 1.5px; // Specific, but might be good? +@largeMargin: @distance * 2px; +@threeQuarterMargin: @distance * 3px; // Too specific? If not used a lot, possibly remove and just use @distance * 3px +@hugeMargin: @distance * 4px; +@massiveMargin: @distance * 8px; + +/* Borders */ +@thinBorder: 1px; +@normalBorder: 2px; +@thickBorder: 4px; +@normalRadius: 6px; + +/* Padding */ +@smallPadding: 2px; +@fullPadding: 4px; +@largePadding: 8px; + +/* Inputs */ +@inputSingleMinWidth: 26px; \ No newline at end of file diff --git a/styles/variables/variables.less b/styles/variables/variables.less new file mode 100644 index 00000000..ca8a2fcc --- /dev/null +++ b/styles/variables/variables.less @@ -0,0 +1,2 @@ +@import "./colors.less"; +@import "./values.less"; \ No newline at end of file diff --git a/system.json b/system.json new file mode 100644 index 00000000..aff6b9ae --- /dev/null +++ b/system.json @@ -0,0 +1,458 @@ +{ + "id": "daggerheart", + "title": "Daggerheart", + "description": "An unofficial implementation of the Daggerheart system", + "version": "0.0.1", + "compatibility": { + "minimum": "13", + "verified": "13.342", + "maximum": "13" + }, + "authors": [ + { + "name": "HarryFurAlle" + } + ], + "scripts": ["build/daggerheart.js"], + "styles": [ + "styles/daggerheart.css" + ], + "packs": [ + { + "name": "classes", + "label": "Classes", + "system": "daggerheart", + "path": "packs/classes.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "class-features", + "label": "Class Features", + "system": "daggerheart", + "path": "packs/class-features.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "subclasses", + "label": "Subclasses", + "system": "daggerheart", + "path": "packs/subclasses.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "arcana-domain", + "label": "Arcana", + "system": "daggerheart", + "path": "packs/domain-cards/arcana.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "blade-domain", + "label": "Blade", + "system": "daggerheart", + "path": "packs/domain-cards/blade.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "bone-domain", + "label": "Bone", + "system": "daggerheart", + "path": "packs/domain-cards/bone.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "codex-domain", + "label": "Codex", + "system": "daggerheart", + "path": "packs/domain-cards/codex.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "grace-domain", + "label": "Grace", + "system": "daggerheart", + "path": "packs/domain-cards/grace.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "midnight-domain", + "label": "Midnight", + "system": "daggerheart", + "path": "packs/domain-cards/midnight.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "sage-domain", + "label": "Sage", + "system": "daggerheart", + "path": "packs/domain-cards/sage.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "splendor-domain", + "label": "Splendor", + "system": "daggerheart", + "path": "packs/domain-cards/splendor.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "valor-domain", + "label": "Valor", + "system": "daggerheart", + "path": "packs/domain-cards/valor.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "ancestries", + "label": "Ancestry", + "system": "daggerheart", + "path": "packs/ancestries.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "communities", + "label": "Communities", + "system": "daggerheart", + "path": "packs/communities.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "weapons-tier0", + "label": "Tier 0", + "system": "daggerheart", + "path": "packs/items/weapons/tier0.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "weapons-tier1", + "label": "Tier 1", + "system": "daggerheart", + "path": "packs/items/weapons/tier1.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "weapons-tier2", + "label": "Tier 2", + "system": "daggerheart", + "path": "packs/items/weapons/tier2.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "weapons-tier3", + "label": "Tier 3", + "system": "daggerheart", + "path": "packs/items/weapons/tier3.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "armors-tier0", + "label": "Tier 0", + "system": "daggerheart", + "path": "packs/items/armors/tier0.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "armors-tier1", + "label": "Tier 1", + "system": "daggerheart", + "path": "packs/items/armors/tier1.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "armors-tier2", + "label": "Tier 2", + "system": "daggerheart", + "path": "packs/items/armors/tier2.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "armors-tier3", + "label": "Tier 3", + "system": "daggerheart", + "path": "packs/items/armors/tier3.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "consumables-tier0", + "label": "Tier 0", + "system": "daggerheart", + "path": "packs/items/consumablesarmors/tier0.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "consumables-tier1", + "label": "Tier 1", + "system": "daggerheart", + "path": "packs/items/consumables/tier1.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "consumables-tier2", + "label": "Tier 2", + "system": "daggerheart", + "path": "packs/items/consumables/tier2.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "consumables-tier3", + "label": "Tier 3", + "system": "daggerheart", + "path": "packs/items/consumables/tier3.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "miscellaneous-general", + "label": "General", + "system": "daggerheart", + "path": "packs/items/miscellaneous/general.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "miscellaneous-tier0", + "label": "Tier 0", + "system": "daggerheart", + "path": "packs/items/miscellaneous/tier0.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "miscellaneous-tier1", + "label": "Tier 1", + "system": "daggerheart", + "path": "packs/items/miscellaneous/tier1.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "miscellaneous-tier2", + "label": "Tier 2", + "system": "daggerheart", + "path": "packs/items/miscellaneous/tier2.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "miscellaneous-tier3", + "label": "Tier 3", + "system": "daggerheart", + "path": "packs/items/miscellaneous/tier3.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "adversaries-tier0", + "label": "Tier 0", + "system": "daggerheart", + "path": "packs/adversaries/tier0.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "adversaries-tier1", + "label": "Tier 1", + "system": "daggerheart", + "path": "packs/adversaries/tier1.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "adversaries-tier2", + "label": "Tier 2", + "system": "daggerheart", + "path": "packs/adversaries/tier2.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "adversaries-tier3", + "label": "Tier 3", + "system": "daggerheart", + "path": "packs/adversaries/tier3.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "environments-tier0", + "label": "Tier 0", + "system": "daggerheart", + "path": "packs/environments/tier0.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "environments-tier1", + "label": "Tier 1", + "system": "daggerheart", + "path": "packs/environments/tier1.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "environments-tier2", + "label": "Tier 2", + "system": "daggerheart", + "path": "packs/environments/tier2.db", + "type": "Item", + "private": false, + "flags": {} + }, + { + "name": "environments-tier3", + "label": "Tier 3", + "system": "daggerheart", + "path": "packs/environments/tier3.db", + "type": "Item", + "private": false, + "flags": {} + } + ], + "packFolders": [ + { + "name": "Daggerheart", + "sorting": "m", + "color": "#08718c", + "packs": [], + "folders": [ + { + "name": "Character Options", + "sorting": "m", + "color": "#000000", + "packs": ["classes", "class-features", "subclasses", "ancestries", "communities"], + "folders": [ + { + "name": "Domains", + "sorting": "m", + "color": "#000000", + "packs": ["arcana-domain", "blade-domain", "bone-domain", "codex-domain", "grace-domain", "midnight-domain", "sage-domain", "splendor-domain", "valor-domain"] + } + ] + }, + { + "name": "Items", + "sorting": "m", + "color": "#000000", + "folders": [ + { + "name": "Weapons", + "sorting": "m", + "color": "#000000", + "packs": ["weapons-tier0", "weapons-tier1", "weapons-tier2", "weapons-tier3"] + }, + { + "name": "Armors", + "sorting": "m", + "color": "#000000", + "packs": ["armors-tier0", "armors-tier1", "armors-tier2", "armors-tier3"] + }, + { + "name": "Consumables", + "sorting": "m", + "color": "#000000", + "packs": ["consumables-tier0", "consumables-tier1", "consumables-tier2", "consumables-tier3"] + }, + { + "name": "Miscellaneous", + "sorting": "m", + "color": "#000000", + "packs": ["miscellaneous-general", "miscellaneous-tier0", "miscellaneous-tier1", "miscellaneous-tier2", "miscellaneous-tier3"] + } + ] + }, + { + "name": "Adversaries", + "sorting": "m", + "color": "#000000", + "packs": ["adversaries-tier0", "adversaries-tier1", "adversaries-tier2", "adversaries-tier3"] + }, + { + "name": "Environments", + "sorting": "m", + "color": "#000000", + "packs": ["environments-tier0", "environments-tier1", "environments-tier2", "environments-tier3"] + } + ] + } + ], + "languages": [ + { + "lang": "en", + "name": "English", + "path": "lang/en.json" + } + ], + "socket": true, + "initiative": "1d20", + "grid": { + "distance": 5, + "units": "feet" + }, + "primaryTokenAttribute": "resources.health", + "secondaryTokenAttribute": "resources.stress", + "url": "https://your/hosted/system/repo/", + "manifest": "https://your/hosted/system/repo/system.json", + "download": "https://your/packaged/download/archive.zip" +} \ No newline at end of file diff --git a/template.json b/template.json new file mode 100644 index 00000000..1b297265 --- /dev/null +++ b/template.json @@ -0,0 +1,33 @@ +{ + "Actor": { + "types": ["pc", "npc", "adversary", "environment"], + "pc": {}, + "npc": {}, + "adversary": {}, + "environment": {} + }, + "Item": { + "types": ["ancestry", "community", "class", "subclass", "feature", "domainCard", "miscellaneous", "consumable", "weapon", "armor", "test"], + "ancestry": {}, + "community": {}, + "class": {}, + "subclass": {}, + "feature": {}, + "domainCard": {}, + "miscellaneous": {}, + "consumable": {}, + "weapon": {}, + "armor": {}, + "test": {} + }, + "Combat": { + "types": ["combat"], + "combat": {} + }, + "ChatMessage": { + "types": ["dualityRoll", "adversaryRoll", "abilityUse"], + "dualityRoll": {}, + "adversaryRoll": {}, + "abilityUse": {} + } +} \ No newline at end of file diff --git a/templates/chat/ability-use.hbs b/templates/chat/ability-use.hbs new file mode 100644 index 00000000..c719d02f --- /dev/null +++ b/templates/chat/ability-use.hbs @@ -0,0 +1,15 @@ +
+
+
{{title}}
+

{{name}}

+
+ +
{{{description}}}
+
+ {{#each actions as |action index|}} + + {{/each}} +
+
\ No newline at end of file diff --git a/templates/chat/adversary-attack-roll.hbs b/templates/chat/adversary-attack-roll.hbs new file mode 100644 index 00000000..8ed8f094 --- /dev/null +++ b/templates/chat/adversary-attack-roll.hbs @@ -0,0 +1,35 @@ +
+
+
{{roll}}
+
+
    +
    + {{#each diceResults}} +
  1. {{this.value}}
  2. + {{/each}} +
    +
    + {{#each modifiers}} +
  3. {{this.label}}
  4. + {{/each}} +
    +
+
+
+
{{total}}
+
+ {{#if (gt targets.length 0)}} +
+ {{#each targets as |target|}} +
+ +
+ {{#if target.hit}}{{localize "Hit"}}{{else}}{{localize "Miss"}}{{/if}} +
+
+ {{/each}} +
+ {{/if}} + +
+
\ No newline at end of file diff --git a/templates/chat/adversary-roll.hbs b/templates/chat/adversary-roll.hbs new file mode 100644 index 00000000..88eb7248 --- /dev/null +++ b/templates/chat/adversary-roll.hbs @@ -0,0 +1,22 @@ +
+
+
{{roll}}
+
+
    +
    + {{#each diceResults}} +
  1. {{this.value}}
  2. + {{/each}} +
    +
    + {{#each modifiers}} +
  3. {{this.label}}
  4. + {{/each}} +
    +
+
+
+
{{total}}
+
+
+
\ No newline at end of file diff --git a/templates/chat/attack-roll.hbs b/templates/chat/attack-roll.hbs new file mode 100644 index 00000000..a32a111f --- /dev/null +++ b/templates/chat/attack-roll.hbs @@ -0,0 +1,49 @@ +
+
+
{{roll}}
+
+
    +
    +
  1. {{hope.value}}
  2. + {{#if advantage.value}} +
  3. {{ advantage.value}}
  4. + {{/if}} + {{#if disadvantage.value}} +
  5. {{disadvantage.value}}
  6. + {{/if}} +
    +
  7. {{fear.value}}
  8. +
    + {{#each modifiers}} +
  9. {{this.label}}
  10. + {{/each}} +
    +
+
+
+
{{totalLabel}}
+
+ {{#if total.alternate}} + {{#with dualityDiceStates}} + {{../total.normal}} - {{../total.alternate}} + {{/with}} + {{else}} + {{total.normal}} + {{/if}} +
+
+ {{#if (gt targets.length 0)}} +
+ {{#each targets as |target|}} +
+ +
+ {{#if target.hit}}{{localize "Hit"}}{{else}}{{#if (not ../total.alternate)}}{{localize "Miss"}}{{else}}?{{/if}}{{/if}} +
+
+ {{/each}} +
+ {{/if}} + +
+
\ No newline at end of file diff --git a/templates/chat/damage-roll.hbs b/templates/chat/damage-roll.hbs new file mode 100644 index 00000000..b67f3e7f --- /dev/null +++ b/templates/chat/damage-roll.hbs @@ -0,0 +1,19 @@ +
+
+
{{this.roll}}
+
+
    + {{#each dice}} +
  1. {{this.value}}
  2. + {{/each}} + {{#each modifiers}} +
  3. {{this}}
  4. + {{/each}} +
+
+
{{this.total}}
+
+ +
+
+
\ No newline at end of file diff --git a/templates/chat/deathMove.hbs b/templates/chat/deathMove.hbs new file mode 100644 index 00000000..ebc577cb --- /dev/null +++ b/templates/chat/deathMove.hbs @@ -0,0 +1,8 @@ +
+

+
{{this.player}} {{localize "DAGGERHEART.Chat.DeathMove.Title"}}
+
{{this.title}}
+

+ +
{{{this.description}}}
+
\ No newline at end of file diff --git a/templates/chat/downtime.hbs b/templates/chat/downtime.hbs new file mode 100644 index 00000000..2c7c200e --- /dev/null +++ b/templates/chat/downtime.hbs @@ -0,0 +1,16 @@ +
+

+
{{this.player}} {{localize "DAGGERHEART.Chat.Downtime.Title"}}
+
{{this.title}}
+

+ +
{{{this.description}}}
+
+
Refreshed Features
+ {{#each this.refreshedFeatures}} +
+
{{this.name}}
+
+ {{/each}} +
+
\ No newline at end of file diff --git a/templates/chat/duality-roll.hbs b/templates/chat/duality-roll.hbs new file mode 100644 index 00000000..5f975821 --- /dev/null +++ b/templates/chat/duality-roll.hbs @@ -0,0 +1,68 @@ +
+
+
{{roll}}
+
+
    +
    +
  1. {{hope.value}}
  2. +
  3. {{fear.value}}
  4. + {{#if advantage.value}} +
  5. {{ advantage.value}}
  6. + {{/if}} + {{#if disadvantage.value}} +
  7. {{disadvantage.value}}
  8. + {{/if}} +
    +
    + {{#each modifiers}} +
  9. {{this.label}}
  10. + {{/each}} +
    +
+
+
+
{{totalLabel}}
+
+ {{total}} +
+
+
+
+ +{{!-- V1.3 --}} +{{!--
+
+
{{roll}}
+
+
    +
    +
  1. {{hope.value}}
  2. + {{#if advantage.value}} +
  3. {{ advantage.value}}
  4. + {{/if}} + {{#if disadvantage.value}} +
  5. {{disadvantage.value}}
  6. + {{/if}} +
    +
  7. {{fear.value}}
  8. +
    + {{#each modifiers}} +
  9. {{this.label}}
  10. + {{/each}} +
    +
+
+
+
{{totalLabel}}
+
+ {{#if total.alternate}} + {{#with dualityDiceStates}} + {{../total.normal}} - {{../total.alternate}} + {{/with}} + {{else}} + {{total.normal}} + {{/if}} +
+
+
+
--}} \ No newline at end of file diff --git a/templates/chat/healing-roll.hbs b/templates/chat/healing-roll.hbs new file mode 100644 index 00000000..60d20fe6 --- /dev/null +++ b/templates/chat/healing-roll.hbs @@ -0,0 +1,19 @@ +
+
+
{{this.roll}}
+
+
    + {{#each dice}} +
  1. {{this.value}}
  2. + {{/each}} + {{#each modifiers}} +
  3. {{this}}
  4. + {{/each}} +
+
+
{{this.total}}
+
+ +
+
+
\ No newline at end of file diff --git a/templates/components/slider.hbs b/templates/components/slider.hbs new file mode 100644 index 00000000..7cbf08d0 --- /dev/null +++ b/templates/components/slider.hbs @@ -0,0 +1,5 @@ +
+
+ +
+
\ No newline at end of file diff --git a/templates/dialog/item-select.hbs b/templates/dialog/item-select.hbs new file mode 100644 index 00000000..5941224e --- /dev/null +++ b/templates/dialog/item-select.hbs @@ -0,0 +1,5 @@ +
+ {{#each this.items as |item index|}} + + {{/each}} +
\ No newline at end of file diff --git a/templates/sheets/adversary.hbs b/templates/sheets/adversary.hbs new file mode 100644 index 00000000..7bb017c0 --- /dev/null +++ b/templates/sheets/adversary.hbs @@ -0,0 +1,243 @@ +
+
+
+ +
+ {{#if this.editMode}} + {{formInput fields.name value=source.name rootId=partId placeholder="{{ localize 'Name' }}"}} + {{else}} +
{{this.title}}
+ {{/if}} +
+
+ +
+ +
+ {{#if this.editMode}} +
+

{{localize "DAGGERHEART.Sheets.Adversary.Description"}}

+ +

+
+
{{localize "DAGGERHEART.Sheets.Adversary.MotivesAndTactics"}}
+ +
+

+
+ {{#each source.system.motivesAndTactics as |motive index|}} +
+ + +
+ {{/each}} +
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+

{{localize "DAGGERHEART.Sheets.Adversary.Attack.Title"}}

+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ + + + +
+
+
+
+ +
+ +
+
+
+ +
+ + + + + + +
+
+
+ +
+ +
+
+
+ +
+ +
+
+

+
+
{{localize "DAGGERHEART.Sheets.Adversary.Experiences"}}
+ +
+

+ {{#each source.system.experiences as |experience index|}} +
+ + + +
+ {{/each}} +
+
+

{{localize "DAGGERHEART.Sheets.Adversary.Moves"}}

+ {{#each this.data.moves as |move key|}} +
+
+ +
{{move.name}}
+
+
+ + +
+
+ {{/each}} +
+
+ {{else}} +
+
+ {{localize "DAGGERHEART.Sheets.Adversary.Description"}}: {{this.data.description}} +
+
+ {{localize "DAGGERHEART.Sheets.Adversary.MotivesAndTactics"}}: {{this.data.motivesAndTactics}} +
+
+
+
+
+
+ + {{this.data.tier}} +
+
+ + {{this.data.type}} +
+
+
+
+ + {{this.data.difficulty}} +
+
+ + +
+
+ + +{{this.data.attack.attackModifier}} + +
+
+ + {{this.data.attack.range}} | {{this.data.attack.damage.value}} {{this.data.attack.damage.typeName}} +
+
+
+
+ + {{this.data.damageThresholds.minor}} +
+ + {{this.data.damageThresholds.major}} +
+ + {{this.data.damageThresholds.severe}} +
+
+ +
+ {{#times this.data.hp.max}} + + {{/times}} +
+
+
+ +
+ {{#times this.data.stress.max}} + + {{/times}} +
+
+
+
+ + {{#each source.system.experiences as |experience index|}} +
+ {{experience.name}} +   + {{#if (gte experience.value 0)}}+{{else}}-{{/if}}{{experience.value}} +
+ {{/each}} +
+ {{!--
+ + {{this.data.hp.max}} +
--}} +
+
+
{{localize "DAGGERHEART.Sheets.Adversary.Moves"}}
+ {{#each this.data.moves as |move index|}} +
+ +
{{{move.system.description}}}
+
+ {{/each}} +
+
+ + {{/if}} +
+
\ No newline at end of file diff --git a/templates/sheets/ancestry.hbs b/templates/sheets/ancestry.hbs new file mode 100644 index 00000000..8cb6bbf1 --- /dev/null +++ b/templates/sheets/ancestry.hbs @@ -0,0 +1,11 @@ +
+
+
+ +
+ {{formInput fields.name value=source.name rootId=partId}} +
+
+
+ {{> "systems/daggerheart/templates/sheets/parts/heritage.hbs" }} +
\ No newline at end of file diff --git a/templates/sheets/armor.hbs b/templates/sheets/armor.hbs new file mode 100644 index 00000000..4cf4ee9b --- /dev/null +++ b/templates/sheets/armor.hbs @@ -0,0 +1,37 @@ +
+
+
+ +
+ {{formInput fields.name value=source.name rootId=partId}} +
+
+
+ +
+ {{formField systemFields.baseScore value=source.system.baseScore label=(localize "DAGGERHEART.Sheets.Armor.BaseScore") }} + {{formField systemFields.feature value=source.system.feature label=(localize "DAGGERHEART.Sheets.Armor.Feature") localize=true blank=""}} +
+

{{localize "DAGGERHEART.Sheets.Armor.Description"}}

+ {{formInput systemFields.description value=source.system.description enriched=source.system.description localize=true toggled=true}} +
+ {{!--
+ +
+ +
+
--}} + {{!--
+ +
+ +
+
+
+

{{localize "DAGGERHEART.Sheets.Armor.Description"}}

+ {{editor item.system.description target="system.description" button=true}} +
--}} +
+
\ No newline at end of file diff --git a/templates/sheets/class.hbs b/templates/sheets/class.hbs new file mode 100644 index 00000000..e88b385b --- /dev/null +++ b/templates/sheets/class.hbs @@ -0,0 +1,300 @@ +
+
+ +
+
+
+
+ +
+ +
+
+
+ +
+ + + + + + +
+
+ {{formField systemFields.evasion value=source.system.evasion label=(localize "DAGGERHEART.Sheets.Class.Evasion")}} + {{!--
+ +
+ +
+
--}} +
+

{{localize "DAGGERHEART.Sheets.Class.ClassFeatures"}}

+
+ {{#each source.system.features as |feature index|}} +
+
+ +
{{feature.name}}
+
+
+ + +
+
+ {{/each}} +
+
+
+

{{localize "DAGGERHEART.Sheets.Class.Subclasses"}}

+
+ {{#each source.system.subclasses as |subclass index|}} +
+
+ +
{{subclass.name}}
+
+
+ + +
+
+ {{/each}} +
+
+
+
+
+
+
+
{{localize "DAGGERHEART.Sheets.Class.Guide.Suggestions.Title"}}
+
+ + {{localize "DAGGERHEART.Sheets.Class.Guide.Suggestions.Traits.Title"}} + + +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ + {{localize "DAGGERHEART.Sheets.Class.Guide.SuggestedPrimaryWeaponTitle"}} + + +
+ {{#if source.system.characterGuide.suggestedPrimaryWeapon}} +
+ +
{{source.system.characterGuide.suggestedPrimaryWeapon.name}}
+ +
+ {{/if}} +
+
+
+ + {{localize "DAGGERHEART.Sheets.Class.Guide.SuggestedSecondaryWeaponTitle"}} + + +
+ {{#if source.system.characterGuide.suggestedSecondaryWeapon}} +
+ +
{{source.system.characterGuide.suggestedSecondaryWeapon.name}}
+ +
+ {{/if}} +
+
+
+ + {{localize "DAGGERHEART.Sheets.Class.Guide.SuggestedArmorTitle"}} + + +
+ {{#if source.system.characterGuide.suggestedArmor}} +
+ +
{{source.system.characterGuide.suggestedArmor.name}}
+ +
+ {{/if}} +
+
+
+
+
{{localize "DAGGERHEART.Sheets.Class.Guide.Inventory.Title"}}
+
+ + {{localize "DAGGERHEART.Sheets.Class.Guide.Inventory.Take"}} + + +
+ {{#each source.system.inventory.take}} +
+ +
{{this.name}}
+ +
+ {{/each}} +
+
+
+ + {{localize "DAGGERHEART.Sheets.Class.Guide.Inventory.ThenChoose"}} + + +
+ {{#each source.system.inventory.choiceA}} +
+ +
{{this.name}}
+ +
+ {{/each}} +
+
+
+ + {{localize "DAGGERHEART.Sheets.Class.Guide.Inventory.AndEither"}} + + +
+ {{#each source.system.inventory.choiceB}} +
+ +
{{this.name}}
+ +
+ {{/each}} +
+
+
+
+
{{localize "DAGGERHEART.Sheets.Class.Guide.Description.Title"}}
+
+
{{localize "DAGGERHEART.Sheets.Class.Guide.Description.Explanation"}}
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ + {{localize "DAGGERHEART.Sheets.Class.Guide.Extra.Title"}} + + +
+
{{localize "DAGGERHEART.Sheets.Class.Guide.Extra.Subtitle"}}
+ + +
+
+
+
+
+
+ {{localize "DAGGERHEART.Sheets.Class.Guide.BackgroundQuestions.Title"}} + +
+ {{#times 3}} +
{{localize "DAGGERHEART.Sheets.Class.Guide.BackgroundQuestions.Question"}} {{add this 1}}
+ + {{/times}} +
+
+ +
+ + {{localize "DAGGERHEART.Sheets.Class.Guide.Connections.Title"}} + + +
+ {{#times 3}} +
{{localize "DAGGERHEART.Sheets.Class.Guide.Connections.Question"}} {{add this 1}}
+ + {{/times}} +
+
+
+
+
+
+
\ No newline at end of file diff --git a/templates/sheets/community.hbs b/templates/sheets/community.hbs new file mode 100644 index 00000000..8cb6bbf1 --- /dev/null +++ b/templates/sheets/community.hbs @@ -0,0 +1,11 @@ +
+
+
+ +
+ {{formInput fields.name value=source.name rootId=partId}} +
+
+
+ {{> "systems/daggerheart/templates/sheets/parts/heritage.hbs" }} +
\ No newline at end of file diff --git a/templates/sheets/consumable.hbs b/templates/sheets/consumable.hbs new file mode 100644 index 00000000..f920826b --- /dev/null +++ b/templates/sheets/consumable.hbs @@ -0,0 +1,36 @@ +
+
+
+ +
+ {{formInput fields.name value=source.name rootId=partId}} +
+
+
+ +
+
+
+ {{formField systemFields.quantity value=source.system.quantity label=(localize "DAGGERHEART.Sheets.Consumable.Quantity") }} + {{formField systemFields.consumeOnUse value=source.system.consumeOnUse label=(localize "DAGGERHEART.Sheets.Consumable.ConsumeOnUse")}} + {{!--
+ +
+ +
+
--}} + {{!--
+ +
+ +
+
--}} +
+
+

{{localize "DAGGERHEART.General.Description"}}

+ {{formInput systemFields.description value=source.system.description enriched=source.system.description localize=true toggled=true}} + {{!-- {{editor item.system.description target="system.description" button=true}} --}} +
+
+
+
\ No newline at end of file diff --git a/templates/sheets/domainCard.hbs b/templates/sheets/domainCard.hbs new file mode 100644 index 00000000..deebf523 --- /dev/null +++ b/templates/sheets/domainCard.hbs @@ -0,0 +1,101 @@ +
+
+
+ +
+ {{formInput fields.name value=source.name rootId=partId}} +
+
+ +
+ +
+
+ {{formField systemFields.type value=source.system.type label="Type" localize=true blank=""}} + {{formField systemFields.foundation value=source.system.foundation label="Foundation" }} + {{formField systemFields.domain value=source.system.domain label="Domain" localize=true blank=""}} + {{formField systemFields.level value=source.system.level label="level" data-dtype="Number"}} + {{formField systemFields.recallCost value=source.system.recallCost label="Recall Cost" data-dtype="Number"}} + {{formField systemFields.effect value=source.system.effect label="Description" enriched=source.system.effect toggled=true}} +
+ +
+

{{localize "Actions"}}

+
+ {{#each source.system.actions as |action index|}} +
+ +
{{action.name}}
+ +
+ {{/each}} +
+
+
+
+ +{{!--
+
+
+ +
+

+
+
+
+ +
+
+ +
+ + + + +
+
+
+ +
+ +
+
+
+ +
+ + + + +
+
+ +
+

{{localize "DAGGERHEART.Sheets.DomainCard.Description"}}

+ {{editor item.system.effect target="system.effect" button=true}} +
+
+ + +

{{localize "Actions"}}

+
+ {{#each this.actions as |action index|}} +
+ +
{{action.name}}
+ +
+ {{/each}} +
+
--}} \ No newline at end of file diff --git a/templates/sheets/environment.hbs b/templates/sheets/environment.hbs new file mode 100644 index 00000000..d5274926 --- /dev/null +++ b/templates/sheets/environment.hbs @@ -0,0 +1,111 @@ +
+
+
+ +
+ {{#if this.editMode}} + + {{else}} +
{{source.name}}
+ {{/if}} +
+
+ +
+
+ {{#if this.editMode}} +
+

{{localize "DAGGERHEART.Sheets.Adversary.Description"}}

+ +

{{localize "DAGGERHEART.Sheets.Environment.ToneAndFeel"}}

+ +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+

{{localize "DAGGERHEART.Sheets.Environment.PotentialAdversaries"}}

+ +
+
+

{{localize "DAGGERHEART.Sheets.Adversary.Moves"}}

+ {{#each data.features as |feature key|}} +
+
+ +
{{feature.name}}
+
+
+ + +
+
+ {{/each}} +
+
+ {{else}} +
+
+ {{localize "DAGGERHEART.Sheets.Adversary.Description"}}: {{source.system.description}} +
+
+ {{localize "DAGGERHEART.Sheets.Environment.ToneAndFeel"}}: {{source.system.toneAndFeel}} +
+
+
+
+
+
+ + {{source.system.tier}} +
+
+ + {{this.data.type}} +
+
+
+
+ + {{source.system.difficulty}} +
+
+
+ + + {{source.system.potentialAdversaries}} +
+
+
+
{{localize "DAGGERHEART.Sheets.Adversary.Moves"}}
+ {{#each data.features as |feature index|}} +
+ +
{{{feature.system.description}}}
+
+ {{/each}} +
+
+ {{/if}} +
+
diff --git a/templates/sheets/feature.hbs b/templates/sheets/feature.hbs new file mode 100644 index 00000000..5baa9a75 --- /dev/null +++ b/templates/sheets/feature.hbs @@ -0,0 +1,80 @@ +
+
+
+ +
+ {{formInput fields.name value=source.name rootId=partId}} +
+
+ +
+ +
+
+
+ {{formField systemFields.type value=source.system.type rootId=partId label="DAGGERHEART.Sheets.Feature.FeatureType" localize=true }} + {{formField systemFields.actionType value=source.system.actionType label="DAGGERHEART.Sheets.Feature.ActionType" rootId=partId localize=true }} +
+ +
+ {{formField systemFields.refreshData.fields.type value=source.system.refreshData.type rootId=partId label="Type" localize=true }} + {{#if document.system.refreshData.type}} + + + {{/if}} +
+
+
+ +
+
+ {{#if (eq document.system.featureType.type "dice")}} + + {{/if}} + + {{#if (eq document.system.featureType.type "dice")}} + + + + + + + {{/if}} +
+
+
+

{{localize "DAGGERHEART.Sheets.Feature.Description"}}

+ {{!-- {{editor document.system.description target="system.description" button=true}} --}} + {{formInput systemFields.description value=source.system.description enriched=source.system.description localize=true toggled=true}} +
+
+
+ {{> "systems/daggerheart/templates/sheets/parts/effects.hbs" config=this.effectConfig selectedEffectType=this.selectedEffectType effects=document.system.effects}} +
+
+

{{localize "Actions"}}

+
+ {{#each document.system.actions as |action index|}} +
+ +
{{action.name}}
+ +
+ {{/each}} +
+
+
+
\ No newline at end of file diff --git a/templates/sheets/miscellaneous.hbs b/templates/sheets/miscellaneous.hbs new file mode 100644 index 00000000..710186c6 --- /dev/null +++ b/templates/sheets/miscellaneous.hbs @@ -0,0 +1,29 @@ +
+
+
+ +
+ {{formInput fields.name value=source.name rootId=partId}} +
+
+
+ +
+
+
+ {{formField systemFields.quantity value=source.system.quantity label=(localize "DAGGERHEART.Sheets.Miscellaneous.Quantity")}} + {{!--
+ +
+ +
+
--}} +
+
+

{{localize "DAGGERHEART.General.Description"}}

+ {{formInput systemFields.description value=source.system.description enriched=source.system.description localize=true toggled=true}} + {{!-- {{editor item.system.description target="system.description" button=true}} --}} +
+
+
+
\ No newline at end of file diff --git a/templates/sheets/parts/armor.hbs b/templates/sheets/parts/armor.hbs new file mode 100644 index 00000000..4f12ccc5 --- /dev/null +++ b/templates/sheets/parts/armor.hbs @@ -0,0 +1,19 @@ +
+ + {{localize "DAGGERHEART.Sheets.PC.Armor.Title"}} + {{#if armor}} +
+ + +
+ {{/if}} +
+ +
+
+ + +
+ +
+
\ No newline at end of file diff --git a/templates/sheets/parts/attributes.hbs b/templates/sheets/parts/attributes.hbs new file mode 100644 index 00000000..77d0248a --- /dev/null +++ b/templates/sheets/parts/attributes.hbs @@ -0,0 +1,39 @@ +
+ + {{localize "Attributes"}} + + + + {{#each this.attributes as |attribute key|}} +
+
+ +
{{key}}
+
+
+ +
+
+ {{#if ../editAttributes}} + + {{else}} +
{{attribute.data.value}}
+ {{/if}} + +
+ {{#each this.descriptors}} +
{{this}}
+ {{/each}} +
+
+ {{#each attribute.verbs}} +
{{this}}
+ {{/each}} +
+ {{/each}} +
\ No newline at end of file diff --git a/templates/sheets/parts/defense.hbs b/templates/sheets/parts/defense.hbs new file mode 100644 index 00000000..cf5ef747 --- /dev/null +++ b/templates/sheets/parts/defense.hbs @@ -0,0 +1,31 @@ +
+ {{localize "Defense"}} + +
+
+
+
{{document.system.evasion}}
+ +
{{localize "DAGGERHEART.Sheets.PC.Defense.Evasion"}}
+
+
+
+
+
+
{{#if document.system.armor.system.baseScore}}{{document.system.armor.system.baseScore}}{{else}}0{{/if}}
+ +
{{localize "DAGGERHEART.Sheets.PC.Defense.Armor"}}
+
+
+ {{#times (subtract 12 document.system.armorMarks.max)}} + + {{/times}} + {{#times document.system.armorMarks.max}} + {{#with (add this 1)}} + + {{/with}} + {{/times}} +
+
+
+
\ No newline at end of file diff --git a/templates/sheets/parts/domainCard.hbs b/templates/sheets/parts/domainCard.hbs new file mode 100644 index 00000000..8acf7008 --- /dev/null +++ b/templates/sheets/parts/domainCard.hbs @@ -0,0 +1,26 @@ +
+
+ +
{{card.system.level}}
+ {{#if inVault}} +
+ {{card.system.recallCost}} +
+ {{else}} +
+ {{card.system.recallCost}} +
+ {{/if}} +
+
{{card.system.type}}
+
+
+
+
{{card.name}}
+ {{#if inVault}} +
{{{card.system.effect}}}
+ {{else}} +
{{{card.system.effect}}}
+ {{/if}} +
+
\ No newline at end of file diff --git a/templates/sheets/parts/effects.hbs b/templates/sheets/parts/effects.hbs new file mode 100644 index 00000000..e429851d --- /dev/null +++ b/templates/sheets/parts/effects.hbs @@ -0,0 +1,69 @@ +
+

+ {{localize "Effects"}} + + +

+ + {{#each this.effects as |effect key|}} +
+ + {{effect.type}} + + + {{#if effect.applyLocationChoices}} +
+ + +
+ {{/if}} + {{#if (eq effect.valueType ../config.valueTypes.numberString.id)}} + {{#if (eq effect.type ../config.effectTypes.damage.id) }} +
+ {{!-- --}} +
+ + + + +
+
+ {{!--
+ + +
--}} +
+ +
+ +
+
+ {{else}} +
+ {{!-- --}} +
+ + +
+
+ {{/if}} + {{/if}} + {{#if (eq effect.valueType ../config.valueTypes.select.id)}} +
+ +
+
+ +
+ {{/if}} +
+ {{/each}} +
\ No newline at end of file diff --git a/templates/sheets/parts/experience.hbs b/templates/sheets/parts/experience.hbs new file mode 100644 index 00000000..4271d9e0 --- /dev/null +++ b/templates/sheets/parts/experience.hbs @@ -0,0 +1,15 @@ +
+ {{localize "DAGGERHEART.Sheets.PC.Experience.Title"}} + {{#each document.system.experiences as |experience index|}} +
+ +
{{experience.value}}
+
+ {{/each}} + {{#times (subtract 5 document.system.experiences.length)}} +
+ +
+
+ {{/times}} +
\ No newline at end of file diff --git a/templates/sheets/parts/features.hbs b/templates/sheets/parts/features.hbs new file mode 100644 index 00000000..ac9f8195 --- /dev/null +++ b/templates/sheets/parts/features.hbs @@ -0,0 +1,48 @@ +
+ + {{#if this.document.system.class}} + {{#if this.document.system.multiclass}} + {{this.document.system.class.name}} {{localize "DAGGERHEART.General.Features"}} + /  + {{this.document.system.multiclass.name}} {{localize "DAGGERHEART.General.Features"}} + {{else}} + {{this.document.system.class.name}} {{localize "DAGGERHEART.General.Features"}} + {{/if}} + {{else}} + {{localize "DAGGERHEART.Sheets.PC.Features.Title"}} + {{/if}} + + +
+ {{#each this.features as |feature index|}} +
+ +
{{feature.name}}
+ +
+
+
{{{feature.system.description}}}
{{!-- Maybe maybe --}} + {{#if (eq feature.system.featureType.type 'input')}} + + {{/if}} + {{#if (eq feature.system.featureType.type 'dice')}} +
+ {{#times feature.system.featureType.data.max}} + {{#if (gt ../this.system.featureType.data.property this)}} +
+ {{#if (lookup (lookup ../this.system.featureType.data.numbers this) 'value')}} +
{{lookup (lookup ../this.system.featureType.data.numbers this) 'value'}}
+ {{else}} + + {{/if}} +
+ {{else}} +
+ {{/if}} + {{/times}} +
+ {{/if}} +
+ {{/each}} +
+
\ No newline at end of file diff --git a/templates/sheets/parts/gold.hbs b/templates/sheets/parts/gold.hbs new file mode 100644 index 00000000..83634403 --- /dev/null +++ b/templates/sheets/parts/gold.hbs @@ -0,0 +1,88 @@ +
+ {{localize "DAGGERHEART.Sheets.PC.Gold.Title"}} + +
+
+ + {{localize "DAGGERHEART.Sheets.PC.Gold.Coins"}} + +
+
+ {{#times 5}} + {{#with (add this 1)}} + + {{!-- --}} + {{/with}} + {{/times}} +
+
+ {{#times 4}} + {{#with (add this 6)}} + + {{!-- --}} + {{/with}} + {{/times}} +
+
+
+
+ + {{localize "DAGGERHEART.Sheets.PC.Gold.Handfulls"}} + +
+
+ {{#times 5}} + {{#with (add this 1)}} + {{!-- --}} + + {{/with}} + {{/times}} +
+
+ {{#times 4}} + {{#with (add this 6)}} + {{!-- --}} + + {{/with}} + {{/times}} +
+
+
+
+ + {{localize "DAGGERHEART.Sheets.PC.Gold.Bags"}} + +
+
+ {{#times 5}} + {{#with (add this 1)}} + {{!-- --}} + + {{/with}} + {{/times}} +
+
+ {{#times 4}} + {{#with (add this 6)}} + {{!-- --}} + + {{/with}} + {{/times}} +
+ + {{!-- --}} + +
+
+
+ + {{localize "DAGGERHEART.Sheets.PC.Gold.Chests"}} + + +
+ + {{!-- --}} +
+
+
+
\ No newline at end of file diff --git a/templates/sheets/parts/health.hbs b/templates/sheets/parts/health.hbs new file mode 100644 index 00000000..e325b1df --- /dev/null +++ b/templates/sheets/parts/health.hbs @@ -0,0 +1,58 @@ +
+ {{localize "DAGGERHEART.Sheets.PC.Health.Title"}} + +
+
+ {{document.system.damageThresholds.minor}} +
+
+ +
{{localize "DAGGERHEART.Sheets.PC.Health.Minor"}}
+
+ +
+ {{document.system.damageThresholds.major}} +
+
+ +
{{localize "DAGGERHEART.Sheets.PC.Health.Major"}}
+
+ +
+ {{document.system.damageThresholds.severe}} +
+
+ +
{{localize "DAGGERHEART.Sheets.PC.Health.Severe"}}
+
+ +
+
+
+
{{localize "DAGGERHEART.Sheets.PC.Health.HealthTitle"}}
+
{{localize "DAGGERHEART.Sheets.PC.Health.StressTitle"}}
+
+
+
+ {{#times document.system.resources.health.max}} + {{#with (add this 1)}} + + {{/with}} + {{/times}} + {{#times (subtract 12 document.system.resources.health.max)}} + + {{/times}} +
+
+ {{#times document.system.resources.stress.max}} + {{#with (add this 1)}} + + {{/with}} + {{/times}} + {{#times (subtract 12 document.system.resources.stress.max)}} + + {{/times}} +
+
+
+
\ No newline at end of file diff --git a/templates/sheets/parts/heritage.hbs b/templates/sheets/parts/heritage.hbs new file mode 100644 index 00000000..6fce3638 --- /dev/null +++ b/templates/sheets/parts/heritage.hbs @@ -0,0 +1,20 @@ +
+ {{formInput systemFields.description value=source.system.description enriched=source.system.description localize=true toggled=true}} +
+

{{localize "DAGGERHEART.Sheets.Heritage.Title"}}

+
+
+ {{#each source.system.abilities as |ability key|}} +
+
+ +
{{ability.name}}
+
+
+ + +
+
+ {{/each}} +
+
\ No newline at end of file diff --git a/templates/sheets/parts/hope.hbs b/templates/sheets/parts/hope.hbs new file mode 100644 index 00000000..eec38297 --- /dev/null +++ b/templates/sheets/parts/hope.hbs @@ -0,0 +1,15 @@ +
+ {{localize "DAGGERHEART.Sheets.PC.Hope.Title"}} + +
+ {{localize "DAGGERHEART.Sheets.PC.Hope.Description"}} +
+ {{#times 6}} + + + {{#if (gte this ../document.system.resources.hope.max)}}{{/if}} + + {{/times}} +
+
+
\ No newline at end of file diff --git a/templates/sheets/parts/inventory.hbs b/templates/sheets/parts/inventory.hbs new file mode 100644 index 00000000..33b9a21f --- /dev/null +++ b/templates/sheets/parts/inventory.hbs @@ -0,0 +1,47 @@ +
+ + {{localize "DAGGERHEART.Sheets.PC.Inventory.Title"}} + +
+
+

+ {{localize "DAGGERHEART.Sheets.PC.Inventory.InventoryWeapon"}} + {{#if weapons.first}} +
+ + +
+ {{/if}} +

+
+
+ + + + +
+ +
+
+
+

+ {{localize "DAGGERHEART.Sheets.PC.Inventory.InventoryWeapon"}} + {{#if weapons.second}} +
+ + +
+ {{/if}} +

+
+
+ + + + +
+ +
+
+
+
\ No newline at end of file diff --git a/templates/sheets/parts/subclassFeature.hbs b/templates/sheets/parts/subclassFeature.hbs new file mode 100644 index 00000000..d4f97a9a --- /dev/null +++ b/templates/sheets/parts/subclassFeature.hbs @@ -0,0 +1,25 @@ +
+ {{#with (concat "system." featureType "Feature" ".")}} +
+ + {{formInput ../field.description value=../feature.description enriched=../feature.description localize=true toggled=true}} + {{!-- {{editor ../feature.description target=(concat this "description") button=true}} --}} +
+
+

{{localize "DAGGERHEART.Sheets.Subclass.SubclassFeature.Abilities"}}

+
+ + {{#each ../feature/abilities as |ability key|}} +
+
+ +
{{ability.name}}
+
+
+ + +
+
+ {{/each}} + {{/with}} +
\ No newline at end of file diff --git a/templates/sheets/parts/weapons.hbs b/templates/sheets/parts/weapons.hbs new file mode 100644 index 00000000..d2a8f977 --- /dev/null +++ b/templates/sheets/parts/weapons.hbs @@ -0,0 +1,57 @@ +
+ +
+ {{localize "DAGGERHEART.Sheets.PC.Weapons.Title"}} +
+ {{localize "DAGGERHEART.Sheets.PC.Weapons.ProficiencyTitle"}} + {{#times 6}} + + {{/times}} +
+
+
+
+ + +
+
+ +
+

+ {{localize "DAGGERHEART.Sheets.PC.Weapons.PrimaryTitle"}} + {{#if weapons.primary}} +
+ + +
+ + {{/if}} +

+
+ + + + +
+ +
+
+

+ {{localize "DAGGERHEART.Sheets.PC.Weapons.SecondaryTitle"}} + {{#if weapons.secondary}} +
+ + +
+ + {{/if}} +

+
+ + + + +
+ +
+
\ No newline at end of file diff --git a/templates/sheets/pc/parts/advancementCard.hbs b/templates/sheets/pc/parts/advancementCard.hbs new file mode 100644 index 00000000..89e7c145 --- /dev/null +++ b/templates/sheets/pc/parts/advancementCard.hbs @@ -0,0 +1,27 @@ +
+
+ +
+ {{#each card.domains}} + + {{/each}} +
+
+
{{card.className}}
+
+
+
+
{{card.subclassName}}
+
{{card.subtitle}}
+ {{#if card.spellcast}}
Spellcast:  {{localize card.spellcast}}
{{/if}} +
{{{card.description}}}
+
+ {{#each card.abilities as |ability key|}} +
+ {{ability.name}} + {{{ability.system.description}}} +
+ {{/each}} +
+
+
\ No newline at end of file diff --git a/templates/sheets/pc/parts/heritageCard.hbs b/templates/sheets/pc/parts/heritageCard.hbs new file mode 100644 index 00000000..40401ac8 --- /dev/null +++ b/templates/sheets/pc/parts/heritageCard.hbs @@ -0,0 +1,18 @@ +
+
+ +
{{card.system.type}}
+
+
+
{{card.name}}
+
{{{card.system.description}}}
+
+ {{#each card.system.abilities as |ability key|}} +
+ {{ability.name}} + {{{ability.system.description}}} +
+ {{/each}} +
+
+
\ No newline at end of file diff --git a/templates/sheets/pc/pc.hbs b/templates/sheets/pc/pc.hbs new file mode 100644 index 00000000..0de09cd2 --- /dev/null +++ b/templates/sheets/pc/pc.hbs @@ -0,0 +1,155 @@ +
+
+
+
+
+ {{document.name}} + {{#if document.system.class}} +
+

+ + {{document.system.class.name}} + +

+ + {{document.system.class.system.domains.[0]}} + and + {{document.system.class.system.domains.[1]}} +
+ {{else}} +
+

Class

+
+ {{/if}} +
+
+
+
+
+
+
+
+ {{localize "DAGGERHEART.Sheets.PC.Name"}} + +
+
+ {{localize "DAGGERHEART.Sheets.PC.Pronouns"}} + +
+
+ + +
+
+
+
+ + {{#if document.system.canLevelUp}}
*
{{/if}} +
+ +
{{localize "DAGGERHEART.Sheets.PC.Level"}}
+
+
+
+ {{#objectSelector title="Heritage" ids=(join document.system.community.uuid document.system.ancestry.uuid) values=(join document.system.community.name document.system.ancestry.name) titleFontSize=14 style="min-width: 272px;"}} + + + {{/objectSelector}} + {{#objectSelector title="Subclass" ids=(join document.system.subclass.uuid) values=(join document.system.subclass.name) titleFontSize=14}} + + {{/objectSelector}} +
+
+
+ +
+
+
+
+
+
+
+
{{localize "DAGGERHEART.General.OpenBetaDisclaimer" version="V1.4"}}
+
+
+ {{> "systems/daggerheart/templates/sheets/parts/defense.hbs" }} + {{> "systems/daggerheart/templates/sheets/parts/health.hbs" }} + {{> "systems/daggerheart/templates/sheets/parts/hope.hbs" }} + {{> "systems/daggerheart/templates/sheets/parts/experience.hbs" }} + {{> "systems/daggerheart/templates/sheets/parts/gold.hbs" }} + {{> "systems/daggerheart/templates/sheets/parts/features.hbs" }} +
+
+ {{> "systems/daggerheart/templates/sheets/parts/attributes.hbs" }} + {{> "systems/daggerheart/templates/sheets/parts/weapons.hbs" weapons=document.system.activeWeapons proficiency=document.system.proficiency.value }} + {{> "systems/daggerheart/templates/sheets/parts/armor.hbs" armor=document.system.armor }} + {{> "systems/daggerheart/templates/sheets/parts/inventory.hbs" weapons=document.system.inventoryWeapons }} +
+
+
+
+
+
+ {{> "systems/daggerheart/templates/sheets/pc/sections/loadout.hbs" abilities=this.abilities actor=this.document config=this.config }} +
+
+ {{> "systems/daggerheart/templates/sheets/pc/sections/inventory.hbs" inventory=this.inventory }} +
+
+
+
+
+ {{localize "DAGGERHEART.Sheets.PC.Story.BackgroundTitle"}} + + {{editor document.system.story.background target="system.story.background" button=true }} +
+
+ {{localize "DAGGERHEART.Sheets.PC.Story.AppearanceTitle"}} + + {{editor document.system.story.appearance target="system.story.appearance" button=true }} +
+
+
+
+ {{localize "DAGGERHEART.Sheets.PC.Story.ConnectionsTitle"}} + + {{editor document.system.story.connections target="system.story.connections" button=true }} +
+
+ + {{localize "DAGGERHEART.Sheets.PC.Story.Scars.Title"}} + + + +
+ {{#each document.system.story.scars as |scar index|}} +
+ + +
+ {{/each}} +
+ {{#with (lookup document.system.story.scars this.selectedScar)}} + {{#if this}} +
+ + {{editor this.description target=(concat "system.story.scars." ../selectedScar ".description") button=true}} +
+ {{/if}} + {{/with}} +
+
+
+
+
+
+ +
+
\ No newline at end of file diff --git a/templates/sheets/pc/sections/inventory.hbs b/templates/sheets/pc/sections/inventory.hbs new file mode 100644 index 00000000..4afb6872 --- /dev/null +++ b/templates/sheets/pc/sections/inventory.hbs @@ -0,0 +1,32 @@ +
+ {{#each this.inventory as |section key|}} +
    +
  1. +
    +
    {{section.titles.name}}
    +
    {{section.titles.quantity}}
    +
    +
  2. +
+
    + {{#each this.items as |item|}} +
  1. +
    +
    +
    + + {{item.name}} +
    +
    +
    + + + +
    + +
    +
  2. + {{/each}} +
+ {{/each}} +
\ No newline at end of file diff --git a/templates/sheets/pc/sections/loadout.hbs b/templates/sheets/pc/sections/loadout.hbs new file mode 100644 index 00000000..516a9411 --- /dev/null +++ b/templates/sheets/pc/sections/loadout.hbs @@ -0,0 +1,134 @@ +
+ +
+
+
+
+
+ {{#if abilities.foundation.ancestry}} + {{> "systems/daggerheart/templates/sheets/pc/parts/heritageCard.hbs" card=abilities.foundation.ancestry }} + {{else}} +
+
+
{{localize "DAGGERHEART.Sheets.PC.Heritage.EmptyAncestry"}}
+
{{localize "DAGGERHEART.Sheets.PC.Heritage.EmptyAncestryTip"}}
+
+
+
+ {{/if}} +
+
+ {{#if abilities.foundation.community}} + {{> "systems/daggerheart/templates/sheets/pc/parts/heritageCard.hbs" card=abilities.foundation.community }} + {{else}} +
+
+
{{localize "DAGGERHEART.Sheets.PC.Heritage.EmptyCommunity"}}
+
{{localize "DAGGERHEART.Sheets.PC.Heritage.EmptyCommunityTip"}}
+
+
+
+ {{/if}} +
+
+
+
+ {{#if abilities.foundation.advancement.foundation}} + {{> "systems/daggerheart/templates/sheets/pc/parts/advancementCard.hbs" card=abilities.foundation.advancement.foundation }} + {{else}} +
+
+
{{localize "DAGGERHEART.Sheets.PC.Heritage.SubclassFoundation"}}
+
{{localize "DAGGERHEART.Sheets.PC.Heritage.SubclassFoundationTip"}}
+
+
+
+ {{/if}} +
+
+ {{#if abilities.foundation.advancement.first}} + {{> "systems/daggerheart/templates/sheets/pc/parts/advancementCard.hbs" card=abilities.foundation.advancement.first }} + {{else}} +
+
+
{{localize "DAGGERHEART.Sheets.PC.Heritage.Subclass"}}
+
{{localize "DAGGERHEART.General.Or"}}
+
{{localize "DAGGERHEART.Sheets.PC.Heritage.Multiclass"}}
+
+
+
+ {{/if}} +
+
+ {{#if abilities.foundation.advancement.second}} + {{> "systems/daggerheart/templates/sheets/pc/parts/advancementCard.hbs" card=abilities.foundation.advancement.second}} + {{else}} +
+
+
{{localize "DAGGERHEART.Sheets.PC.Heritage.Subclass"}}
+
{{localize "DAGGERHEART.General.Or"}}
+
{{localize "DAGGERHEART.Sheets.PC.Heritage.Multiclass"}}
+
+
+
+ {{/if}} +
+
+
+
+
+
+
+ {{#times 2}} +
+ {{#with (lookup ../abilities.loadout.top this)}} + {{> "systems/daggerheart/templates/sheets/parts/domainCard.hbs" card=this inVault=false }} + {{/with}} + {{#if (not (lookup ../abilities.loadout.top this))}} +
+
{{localize "DAGGERHEART.Sheets.PC.DomainCard.AvailableDomainSlot"}}
+
+
+ {{/if}} +
+ {{/times}} +
+
+ {{#times 3}} +
+ {{#with (lookup ../abilities.loadout.bottom this)}} + {{> "systems/daggerheart/templates/sheets/parts/domainCard.hbs" card=this inVault=false }} + {{/with}} + {{#if (gt (add this 3) ../actor/system/domainData.maxLoadout)}} +
+
{{localize "DAGGERHEART.Sheets.PC.DomainCard.UnavailableDomainSlot" level=(add this 2)}}
+
+
+ {{/if}} + + {{#if (and (lte (add this 3) ../actor/system/domainData.maxLoadout) (lt ../abilities.loadout.bottom.length (add this 1)))}} +
+
{{localize "DAGGERHEART.Sheets.PC.DomainCard.AvailableDomainSlot"}}
+
+
+ {{/if}} +
+ {{/times}} +
+
+
+
+
+ {{#each abilities.vault}} +
+ {{> "systems/daggerheart/templates/sheets/parts/domainCard.hbs" card=this inVault=true }} +
+ {{/each}} +
+
+
+
\ No newline at end of file diff --git a/templates/sheets/subclass.hbs b/templates/sheets/subclass.hbs new file mode 100644 index 00000000..6768a719 --- /dev/null +++ b/templates/sheets/subclass.hbs @@ -0,0 +1,45 @@ +
+
+
+ +
+ {{formInput fields.name value=source.name rootId=partId}} +
+
+ +
+
+
+ {{formField systemFields.spellcastingTrait value=source.system.spellcastingTrait label=(localize "DAGGERHEART.Sheets.Subclass.SpellcastingTrait") localize=true}} + {{!--
+ +
+ +
+
--}} +
+ + {{formInput systemFields.description value=source.system.description enriched=source.system.description localize=true toggled=true}} + {{!-- {{editor item.system.description target="system.description" button=true}} --}} +
+
+
+ {{> "systems/daggerheart/templates/sheets/parts/subclassFeature.hbs" field=systemFields.foundationFeature.fields feature=source.system.foundationFeature featureType="foundation" }} +
+
+ {{> "systems/daggerheart/templates/sheets/parts/subclassFeature.hbs" field=systemFields.specializationFeature.fields feature=source.system.specializationFeature featureType="specialization" }} +
+
+ {{> "systems/daggerheart/templates/sheets/parts/subclassFeature.hbs" field=systemFields.masteryFeature.fields feature=source.system.masteryFeature featureType="mastery" }} +
+
+
\ No newline at end of file diff --git a/templates/sheets/weapon.hbs b/templates/sheets/weapon.hbs new file mode 100644 index 00000000..7d5739b7 --- /dev/null +++ b/templates/sheets/weapon.hbs @@ -0,0 +1,86 @@ +
+
+ {{!--
+ +
+

+
+
--}} +
+ +
+ {{formInput fields.name value=source.name rootId=partId}} +
+
+
+ +
+ {{formField systemFields.secondary value=source.system.secondary label=(localize "DAGGERHEART.Sheets.Weapon.SecondaryWeapon") }} + {{formField systemFields.trait value=source.system.trait label=(localize "DAGGERHEART.Sheets.Weapon.Trait") localize=true }} + {{formField systemFields.range value=source.system.range label=(localize "DAGGERHEART.Sheets.Weapon.Range") localize=true }} +
+ +
+ {{formGroup systemFields.damage.fields.value value=source.system.damage.value label=(localize "DAGGERHEART.Sheets.Weapon.Damage.Value") }} + {{formGroup systemFields.damage.fields.type value=source.system.damage.type label=(localize "DAGGERHEART.Sheets.Weapon.Damage.Type") localize=true }} +
+
+ {{formField systemFields.burden value=source.system.burden label=(localize "DAGGERHEART.Sheets.Weapon.Burden") localize=true }} + {{formField systemFields.feature value=source.system.feature label=(localize "DAGGERHEART.Sheets.Weapon.Feature") localize=true }} + {{!--
+ +
+ +
+
--}} + {{!--
+ +
+ +
+
--}} + {{!--
+ +
+ +
+
--}} + {{!--
+ +
+ + + + +
+
--}} + + {{!--
+ +
+ +
+
--}} + {{!--
+ +
+ +
+
--}} +
+

{{localize "DAGGERHEART.Sheets.Weapon.Description"}}

+ {{formInput systemFields.description value=source.system.description enriched=source.system.description localize=true toggled=true}} + {{!-- {{editor item.system.description target="system.description" button=true}} --}} +
+
+
\ No newline at end of file diff --git a/templates/sidebar/documentCreate.hbs b/templates/sidebar/documentCreate.hbs new file mode 100644 index 00000000..ac5559cb --- /dev/null +++ b/templates/sidebar/documentCreate.hbs @@ -0,0 +1,45 @@ +
+
+ +
+ +
+
+ + {{#if hasTypes}} +
+ +
+ +
+
+ {{/if}} + + {{#if hasFolders}} +
+ +
+ +
+
+ {{/if}} + + {{{content}}} +
diff --git a/templates/ui/combatTracker.hbs b/templates/ui/combatTracker.hbs new file mode 100644 index 00000000..04d1a91b --- /dev/null +++ b/templates/ui/combatTracker.hbs @@ -0,0 +1,160 @@ +
+
+ {{#if user.isGM}} + + {{/if}} + +
+ {{#if user.isGM}} + + + + + + + {{/if}} + + {{#if combatCount}} + {{#if combat.round}} +

{{localize 'COMBAT.Round'}} {{combat.round}}

+ {{else}} +

{{localize 'COMBAT.NotStarted'}}

+ {{/if}} + {{else}} +

{{localize "COMBAT.None"}}

+ {{/if}} + + {{#if user.isGM}} + + + + + + + {{/if}} + + + +
+
+ +
+ {{#if combat.system}} +
+ + +
+
+ + {{combat.system.actions}} +
+
+ + +
+
+ + {{fear}} +
+
+ + +
+ {{/if}} +
+ +
    + {{#each turns}} +
  1. + {{this.name}} +
    +

    {{this.name}}

    +
    + {{#if ../user.isGM}} + + + + + + + {{/if}} + {{#if this.canPing}} + + + + {{/if}} + {{#unless ../user.isGM}} + + + + {{/unless}} +
    + {{#each this.effects}} + + {{/each}} +
    +
    +
    + + {{#if this.hasResource}} +
    + {{this.resource}} +
    + {{/if}} + +
    + {{#if this.playerCharacter}} + + {{else if (and (not this.ownedByPlayer) ../user.isGM)}} + + {{/if}} + {{!-- {{#if this.hasRolled}} + {{this.initiative}} + {{else if this.owner}} + + {{/if}} --}} +
    +
  2. + {{/each}} +
+ + +
diff --git a/templates/ui/players.hbs b/templates/ui/players.hbs new file mode 100644 index 00000000..3912e955 --- /dev/null +++ b/templates/ui/players.hbs @@ -0,0 +1,35 @@ + diff --git a/templates/views/action.hbs b/templates/views/action.hbs new file mode 100644 index 00000000..45d91c80 --- /dev/null +++ b/templates/views/action.hbs @@ -0,0 +1,64 @@ +
+
+ {{formField fields.name value=source.name label="Name" rootId=partId}} + +
+
+
+
+ +
Damage
+ +
+ +
+ {{formField fields.damage.fields.type value=source.damage.type label="Damage Type" rootId=partId localize=true}} + {{formField fields.damage.fields.value value=source.damage.value label="Damage" rootId=partId localize=true}} +
+
+
+ +
Healing
+ +
+ +
+ {{formField fields.healing.fields.type value=source.healing.type label="Healing Type" rootId=partId localize=true}} + {{formField fields.healing.fields.value value=source.healing.value label="Healing" rootId=partId localize=true}} +
+
+
+
+
+ +
Cost
+ +
+ +
+ {{formField fields.cost.fields.type value=source.cost.type label="Cost Type" rootId=partId}} + {{formField fields.cost.fields.value value=source.cost.value label="Value" rootId=partId}} +
+
+ + {{formField fields.target.fields.type value=source.target.type label="Target Type" rootId=partId}} +
+
+ {{!--

+ {{localize "Conditions"}} + + +

--}} +
+
+ +
\ No newline at end of file diff --git a/templates/views/ancestrySelection.hbs b/templates/views/ancestrySelection.hbs new file mode 100644 index 00000000..c6df3a5d --- /dev/null +++ b/templates/views/ancestrySelection.hbs @@ -0,0 +1,72 @@ +
+
+

{{localize "Daggerheart Ancestries"}}

+
+ {{#each systemAncestries}} +
+
+ +
+
+
{{this.name}}
+
+
+ {{/each}} +
+
+
+

{{localize "Custom Ancestries"}}

+
+ {{#each customAncestries}} +
+
+ +
+
+
{{this.name}}
+
+
+ {{/each}} + {{#if (eq customAncestries.length 0)}}No Custom Ancestries created in this world{{/if}} +
+
+
+

{{localize "Ancestry Features"}}

+
+ {{#each ancestryFeatures}} +
+
+ +
+
+
{{this.name}}
+
+
+ {{/each}} +
+
+ {{#if (eq this.selectedAncestries.length 2)}} +
+

{{localize "Mixed Ancestry"}}

+
+
+
{{localize "Ancestry Name"}}
+ +
+
+ {{#each selectedAncestries}} + + {{/each}} +
+ + +
+
+
+ +
+ {{/if}} +
+ +
+
\ No newline at end of file diff --git a/templates/views/automation-settings.hbs b/templates/views/automation-settings.hbs new file mode 100644 index 00000000..de4f1131 --- /dev/null +++ b/templates/views/automation-settings.hbs @@ -0,0 +1,19 @@ +
+
+ +
+ +
+
+
+ +
+ +
+
+ +
+ + +
+
\ No newline at end of file diff --git a/templates/views/damageSelection.hbs b/templates/views/damageSelection.hbs new file mode 100644 index 00000000..5479da46 --- /dev/null +++ b/templates/views/damageSelection.hbs @@ -0,0 +1,29 @@ +
+
+ +
+ +
+
+ {{#each this.bonusDamage as |damage index|}} +
+ +
+ + + {{#if (and damage.initiallySelected damage.hopeIncrease)}} + + +
+ +
{{damage.hopeUses}}
+ +
+ {{/if}} +
+
+ {{/each}} +
+ +
+
\ No newline at end of file diff --git a/templates/views/deathMove.hbs b/templates/views/deathMove.hbs new file mode 100644 index 00000000..3b041ea3 --- /dev/null +++ b/templates/views/deathMove.hbs @@ -0,0 +1,19 @@ +
+
+ {{#each this.options as |option key|}} +
+
+ + {{localize this.name}} +
+
+ {{localize this.description}} +
+
+ {{/each}} +
+
+ + +
+
\ No newline at end of file diff --git a/templates/views/downtime.hbs b/templates/views/downtime.hbs new file mode 100644 index 00000000..1623b1c7 --- /dev/null +++ b/templates/views/downtime.hbs @@ -0,0 +1,28 @@ +
+
+ {{#each this.options as |option key|}} +
+
+ + {{localize this.name}} +
+
+ {{localize this.description}} +
+
+ {{/each}} +
+
+ + +
+
+ +
+
+
+
+ + +
+
\ No newline at end of file diff --git a/templates/views/homebrew-settings.hbs b/templates/views/homebrew-settings.hbs new file mode 100644 index 00000000..6d9c9a90 --- /dev/null +++ b/templates/views/homebrew-settings.hbs @@ -0,0 +1,13 @@ +
+
+ +
+ +
+
+ +
+ + +
+
\ No newline at end of file diff --git a/templates/views/levelup.hbs b/templates/views/levelup.hbs new file mode 100644 index 00000000..1c718f7e --- /dev/null +++ b/templates/views/levelup.hbs @@ -0,0 +1,20 @@ +
+
Level {{activeLevel}}
+
+ {{#each data}} + {{> "systems/daggerheart/templates/views/parts/level.hbs" data=this }} + {{/each}} + {{!-- {{#each levelupConfig as |configData key|}} + {{> "systems/daggerheart/templates/views/parts/level.hbs" configData=configData levelData=(lookup ../levelData key) completedSelection=../completedSelection activeTier=../activeTier activeLevel=../activeLevel category=key }} + {{/each}} --}} +
+
+ + {{#if (eq activeLevel changedLevel )}} + + {{else}} + + {{/if}} + +
+
\ No newline at end of file diff --git a/templates/views/multiclass.hbs b/templates/views/multiclass.hbs new file mode 100644 index 00000000..843ec808 --- /dev/null +++ b/templates/views/multiclass.hbs @@ -0,0 +1,37 @@ +
+
+

{{localize "DAGGERHEART.Application.Multiclass.ClassSection.Title"}}

+
+ {{#each classChoices}} +
+ +
{{this.name}}
+
+ {{/each}} +
+

{{localize "DAGGERHEART.Application.Multiclass.SubclassSection.Title"}}

+
+ {{#each subclassChoices}} +
+ +
{{this.name}}
+
+ {{/each}} +
+

{{localize "DAGGERHEART.Application.Multiclass.DomainSection.Title"}}

+
+ {{#each domainChoices}} +
+ +
{{this.name}}
+
+ {{/each}} +
+
+
+ + +
+
\ No newline at end of file diff --git a/templates/views/npcRollSelection.hbs b/templates/views/npcRollSelection.hbs new file mode 100644 index 00000000..7dd8a90a --- /dev/null +++ b/templates/views/npcRollSelection.hbs @@ -0,0 +1,30 @@ + +
+
+
+
+ +
{{this.nrDice}}
+
+
+ + +
+
+
Adv
+
Dis
+
+
+
+ {{#each this.experiences as |experience key|}} +
+ {{experience.name}} + +
+ {{/each}} +
+
+
+ +
+
\ No newline at end of file diff --git a/templates/views/parts/level.hbs b/templates/views/parts/level.hbs new file mode 100644 index 00000000..744f4fe9 --- /dev/null +++ b/templates/views/parts/level.hbs @@ -0,0 +1,40 @@ +
+
+ + {{data.label}} + + +
{{data.info}}
+
{{data.pretext}}
+
+ {{#each data.choices as |choice choiceKey|}} +
+
+ {{#each choice.values as |value valueKey|}} + {{#times choice.cost}} +
+ + {{#if (lt (add this 1) ../../cost)}} + + {{/if}} + {{#if ../locked}} + + {{/if}} +
+ {{/times}} + {{/each}} +
+
{{localize choice.description}}
+
+ {{/each}} +
+
{{data.posttext}}
+
+
\ No newline at end of file diff --git a/templates/views/range-settings.hbs b/templates/views/range-settings.hbs new file mode 100644 index 00000000..fec4f7fb --- /dev/null +++ b/templates/views/range-settings.hbs @@ -0,0 +1,44 @@ +
+
+ +
+ + +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ +
+ + +
+
\ No newline at end of file diff --git a/templates/views/rollSelection.hbs b/templates/views/rollSelection.hbs new file mode 100644 index 00000000..4f90302f --- /dev/null +++ b/templates/views/rollSelection.hbs @@ -0,0 +1,75 @@ +
+
+
+
+ {{#each this.experiences}} + {{#if this.description}} +
+ {{this.description}} + +{{this.value}} +
+ {{/if}} + {{/each}} +
+
+ + +
+ {{!--
+ +
+ +
+
+
+ +
+ +
+
--}} + {{#if (not this.isNpc)}} +
+ +
+ +
+
+
+ +
+ +
+
+ {{/if}} + {{#each this.bonusDamage as |damage index|}} +
+ +
+ + + {{#if (and damage.initiallySelected damage.hopeIncrease)}} + + +
+ +
{{damage.hopeUses}}
+ +
+ {{/if}} +
+
+ {{/each}} +
+
+ +
+
+
\ No newline at end of file diff --git a/tools/pullYMLtoLDB.mjs b/tools/pullYMLtoLDB.mjs new file mode 100644 index 00000000..e8ab8154 --- /dev/null +++ b/tools/pullYMLtoLDB.mjs @@ -0,0 +1,16 @@ +import { compilePack } from "@foundryvtt/foundryvtt-cli"; +import { promises as fs } from "fs"; + +const MODULE_ID = process.cwd(); +const yaml = false; + +const packs = await fs.readdir("./src/packs"); +for (const pack of packs) { + if (pack === ".gitattributes") continue; + console.log("Packing " + pack); + await compilePack( + `${MODULE_ID}/src/packs/${pack}`, + `${MODULE_ID}/packs/${pack}`, + { yaml }, + ); +} diff --git a/tools/pushLDBtoYML.mjs b/tools/pushLDBtoYML.mjs new file mode 100644 index 00000000..9bc71ddc --- /dev/null +++ b/tools/pushLDBtoYML.mjs @@ -0,0 +1,42 @@ +import { extractPack } from "@foundryvtt/foundryvtt-cli"; +import { promises as fs } from "fs"; +import path from "path"; + +const MODULE_ID = process.cwd(); +const yaml = false; + +const packs = await fs.readdir("./packs"); +for (const pack of packs) { + if (pack === ".gitattributes") continue; + console.log("Unpacking " + pack); + const directory = `./src/packs/${pack}`; + try { + for (const file of await fs.readdir(directory)) { + await fs.unlink(path.join(directory, file)); + } + } catch (error) { + if (error.code === "ENOENT") console.log("No files inside of " + pack); + else console.log(error); + } + await extractPack( + `${MODULE_ID}/packs/${pack}`, + `${MODULE_ID}/src/packs/${pack}`, + { + yaml, + transformName, + }, + ); +} +/** + * Prefaces the document with its type + * @param {object} doc - The document data + */ +function transformName(doc) { + const safeFileName = doc.name.replace(/[^a-zA-Z0-9А-я]/g, "_"); + const type = doc._key.split("!")[1]; + const prefix = ["actors", "items"].includes(type) ? doc.type : type; + + return `${doc.name ? `${prefix}_${safeFileName}_${doc._id}` : doc._id}.${ + yaml ? "yml" : "json" + }`; +}
+// ${tagData[this.settings.tagTextProp] || tagData.value} +// +//