From 8b3e95e1aed4ac7cdc455e5ecb846324beb5325c Mon Sep 17 00:00:00 2001 From: ThaumRystra <9525416+ThaumRystra@users.noreply.github.com> Date: Tue, 30 Apr 2024 12:47:24 +0200 Subject: [PATCH 01/14] Fixed property trees in detail dialogs not showing any props --- app/client/game-icons.css | 4 +- .../api/parenting/parentingFunctions.ts | 33 ++++---- .../DescendantPropertiesTree.vue | 78 +++++++++++++++++++ .../client/ui/properties/PropertyForm.vue | 9 ++- .../ui/properties/shared/PropertyViewer.vue | 8 +- 5 files changed, 106 insertions(+), 26 deletions(-) create mode 100644 app/imports/client/ui/creature/creatureProperties/DescendantPropertiesTree.vue diff --git a/app/client/game-icons.css b/app/client/game-icons.css index 8a28a3c4..d694ff66 100644 --- a/app/client/game-icons.css +++ b/app/client/game-icons.css @@ -5,8 +5,8 @@ @font-face { font-family: "game-icons"; src: url("/fonts/game-icons.eot?817af6e52c83163eb30ece54d9f7d16d?#iefix") format("embedded-opentype"), -url("/fonts/game-icons.woff?817af6e52c83163eb30ece54d9f7d16d") format("woff"), -url("/fonts/game-icons.ttf?817af6e52c83163eb30ece54d9f7d16d") format("truetype"); + url("/fonts/game-icons.woff?817af6e52c83163eb30ece54d9f7d16d") format("woff"), + url("/fonts/game-icons.ttf?817af6e52c83163eb30ece54d9f7d16d") format("truetype"); } .game-icon { diff --git a/app/imports/api/parenting/parentingFunctions.ts b/app/imports/api/parenting/parentingFunctions.ts index 758aaf13..6dc3d219 100644 --- a/app/imports/api/parenting/parentingFunctions.ts +++ b/app/imports/api/parenting/parentingFunctions.ts @@ -93,16 +93,16 @@ type FilteredDoc = { export function filterToForest( collection: Mongo.Collection, rootId: string, - filter?: Mongo.Query, + filter?: Mongo.Selector, { - options = >{}, + options = >{}, includeFilteredDocAncestors = false, includeFilteredDocDescendants = false } = {} ): TreeNode[] { if (!Meteor.isClient) throw 'Only available on the client'; // Setup the filter - let collectionFilter: Mongo.Query = { + let collectionFilter: Mongo.Selector = { 'root.id': rootId, 'removed': { $ne: true }, }; @@ -113,16 +113,17 @@ export function filterToForest( } } // Set up the options - let collectionSort = { + let collectionSort: Mongo.Options['sort'] = { left: 1 }; - if (options && options.sort) { + if (options.sort) { collectionSort = { ...collectionSort, + // @ts-expect-error go home typescript you're drunk ...options.sort, } } - let collectionOptions: Mongo.Options = { + let collectionOptions: Mongo.Options = { sort: collectionSort, } if (options) { @@ -671,8 +672,8 @@ export function setDocToLastOrder(collection: Mongo.Collection, doc: Tr doc.left = Number.MAX_SAFE_INTEGER; } -export async function rebuildNestedSets(collection: Mongo.Collection, rootId: string) { - const docs = await collection.find({ +export function rebuildNestedSets(collection: Mongo.Collection, rootId: string) { + const docs = collection.find({ 'root.id': rootId, removed: { $ne: true } }, { @@ -681,13 +682,13 @@ export async function rebuildNestedSets(collection: Mongo.Collection, r //Reverse sorting so that arrays can be used as stacks with the first item on top left: 1, }, - }).fetchAsync(); + }).fetch(); const operations = calculateNestedSetOperations(docs); return writeBulkOperations(collection, operations); } -export async function rebuildCreatureNestedSets(creatureId) { +export function rebuildCreatureNestedSets(creatureId) { const docs = getProperties(creatureId); const operations = calculateNestedSetOperations(docs); return writeBulkOperations(CreatureProperties as Mongo.Collection, operations); @@ -823,8 +824,9 @@ export function applyNestedSetProperties(docs: T[]): Forest */ -async function writeBulkOperations(collection: Mongo.Collection, operations) { - if (Meteor.isServer && operations.length) { +function writeBulkOperations(collection: Mongo.Collection, operations) { + if (Meteor.isServer) { + if (!operations.length) return Promise.resolve(); return new Promise((resolve, reject) => { collection.rawCollection().bulkWrite( operations, @@ -841,20 +843,19 @@ async function writeBulkOperations(collection: Mongo.Collection, operat } else { // Don't do latency compensation if there are too many operations, it just causes client // lag without much benefit - const promises = operations.map(op => { + operations.forEach(op => { if (op.updateOne) { - return collection.updateAsync( + collection.update( op.updateOne.filter, op.updateOne.update, ); } else if (op.updateMany) { - return collection.updateAsync( + collection.update( op.updateMany.filter, op.updateMany.update, { multi: true }, ) } }); - return Promise.all(promises); } } diff --git a/app/imports/client/ui/creature/creatureProperties/DescendantPropertiesTree.vue b/app/imports/client/ui/creature/creatureProperties/DescendantPropertiesTree.vue new file mode 100644 index 00000000..9fa92021 --- /dev/null +++ b/app/imports/client/ui/creature/creatureProperties/DescendantPropertiesTree.vue @@ -0,0 +1,78 @@ + + + diff --git a/app/imports/client/ui/properties/PropertyForm.vue b/app/imports/client/ui/properties/PropertyForm.vue index 7e1664e9..c0643a44 100644 --- a/app/imports/client/ui/properties/PropertyForm.vue +++ b/app/imports/client/ui/properties/PropertyForm.vue @@ -167,10 +167,11 @@ style="width: 100%" class="pa-2 no-hover" > - @@ -225,7 +226,7 @@ import InlineComputationField from '/imports/client/ui/properties/forms/shared/I import FormSection, { FormSections } from '/imports/client/ui/properties/forms/shared/FormSection.vue'; import propertyFormIndex from '/imports/client/ui/properties/forms/shared/propertyFormIndex'; import IconColorMenu from '/imports/client/ui/properties/forms/shared/IconColorMenu.vue'; -import CreaturePropertiesTree from '/imports/client/ui/creature/creatureProperties/CreaturePropertiesTree.vue'; +import DescendantPropertiesTree from '/imports/client/ui/creature/creatureProperties/DescendantPropertiesTree.vue'; import OutlinedInput from '/imports/client/ui/properties/viewers/shared/OutlinedInput.vue'; import { getSuggestedChildren } from '/imports/constants/PROPERTIES'; import PROPERTIES from '/imports/constants/PROPERTIES'; @@ -243,7 +244,7 @@ export default { FormSection, FormSections, IconColorMenu, - CreaturePropertiesTree, + DescendantPropertiesTree, OutlinedInput, ...propertyFormIndex, }, diff --git a/app/imports/client/ui/properties/shared/PropertyViewer.vue b/app/imports/client/ui/properties/shared/PropertyViewer.vue index 525354b3..e4340bdc 100644 --- a/app/imports/client/ui/properties/shared/PropertyViewer.vue +++ b/app/imports/client/ui/properties/shared/PropertyViewer.vue @@ -134,9 +134,9 @@ name="Child properties" :cols="{cols: 12}" > - Date: Tue, 30 Apr 2024 12:47:53 +0200 Subject: [PATCH 02/14] Improved action dialog style --- .../ui/creature/actions/ActionDialog.vue | 175 +++++++++++++----- .../creature/actions/input/AdvantageInput.vue | 1 - 2 files changed, 126 insertions(+), 50 deletions(-) diff --git a/app/imports/client/ui/creature/actions/ActionDialog.vue b/app/imports/client/ui/creature/actions/ActionDialog.vue index 7f5b30d2..3d56b33a 100644 --- a/app/imports/client/ui/creature/actions/ActionDialog.vue +++ b/app/imports/client/ui/creature/actions/ActionDialog.vue @@ -1,57 +1,85 @@ - + + diff --git a/app/imports/client/ui/creature/actions/input/AdvantageInput.vue b/app/imports/client/ui/creature/actions/input/AdvantageInput.vue index 1d46ad7e..b1bd1dd4 100644 --- a/app/imports/client/ui/creature/actions/input/AdvantageInput.vue +++ b/app/imports/client/ui/creature/actions/input/AdvantageInput.vue @@ -52,7 +52,6 @@ export default { methods: { emitInput(e) { e = e || 0; - console.log(e); this.$emit('input', e) } } From e62f536749cae9e4243e16589c945139af1d0dd6 Mon Sep 17 00:00:00 2001 From: ThaumRystra <9525416+ThaumRystra@users.noreply.github.com> Date: Tue, 30 Apr 2024 12:51:34 +0200 Subject: [PATCH 03/14] replaced all sorting by `order` with sorting by `left` --- .../creatureFolders/methods.js/insertCreatureFolder.js | 2 +- .../methods.js/reorderCreatureFolder.js | 2 +- .../creatureProperties/methods/duplicateProperty.js | 2 +- .../creatureProperties/methods/getParentRefByTag.js | 2 +- .../methods/insertPropertyFromLibraryNode.js | 2 +- app/imports/api/docs/Docs.js | 2 +- app/imports/api/engine/loadCreatures.ts | 4 ++-- app/imports/api/library/methods/copyLibraryNodeTo.js | 2 +- .../api/library/methods/duplicateLibraryNode.js | 2 +- .../client/ui/creature/archive/ArchiveDialog.vue | 4 ++-- .../creature/character/characterSheetTabs/BuildTab.vue | 4 ++-- .../character/characterSheetTabs/FeaturesTab.vue | 2 +- .../character/characterSheetTabs/InventoryTab.vue | 8 ++++---- .../character/characterSheetTabs/JournalTab.vue | 2 +- .../character/characterSheetTabs/SpellsTab.vue | 4 ++-- .../creature/character/characterSheetTabs/StatsTab.vue | 4 ++-- .../printedCharacterSheet/CharacterSheetPrinted.vue | 4 ++-- .../printedCharacterSheet/PrintedInventory.vue | 10 +++++----- .../character/printedCharacterSheet/PrintedSpells.vue | 4 ++-- .../character/printedCharacterSheet/PrintedStats.vue | 4 ++-- .../printedCharacterSheet/components/PrintedAction.vue | 2 +- app/imports/client/ui/docs/DocsRightDrawer.vue | 2 +- app/imports/client/ui/layouts/Sidebar.vue | 2 +- app/imports/client/ui/library/LibraryEditDialog.vue | 2 +- app/imports/client/ui/pages/CharacterList.vue | 2 +- app/imports/client/ui/pages/DocsPage.vue | 6 +++--- .../ui/properties/components/actions/ActionCard.vue | 2 +- .../components/actions/SelectItemToConsume.vue | 2 +- .../components/attributes/HealthBarCardContainer.vue | 2 +- .../properties/components/folders/FolderGroupCard.vue | 2 +- .../folderGroupComponents/FolderGroupChildren.vue | 2 +- .../folders/folderGroupComponents/SlotBuildTree.vue | 4 ++-- .../properties/components/inventory/ContainerCard.vue | 2 +- .../components/spells/CastSpellWithSlotDialog.vue | 2 +- .../forms/shared/lists/createListOfProperties.js | 2 +- .../client/ui/properties/viewers/SkillViewer.vue | 2 +- app/imports/client/ui/tabletop/TabletopActionCard.vue | 2 +- app/imports/client/ui/tabletop/TabletopComponent.vue | 2 +- .../selectedCreatureBar/SelectedCreatureBar.vue | 2 +- app/imports/server/publications/library.js | 6 +++--- 40 files changed, 60 insertions(+), 60 deletions(-) diff --git a/app/imports/api/creature/creatureFolders/methods.js/insertCreatureFolder.js b/app/imports/api/creature/creatureFolders/methods.js/insertCreatureFolder.js index 497943b4..ebae17f4 100644 --- a/app/imports/api/creature/creatureFolders/methods.js/insertCreatureFolder.js +++ b/app/imports/api/creature/creatureFolders/methods.js/insertCreatureFolder.js @@ -22,7 +22,7 @@ const insertCreatureFolder = new ValidatedMethod({ owner: userId }, { fields: { order: 1 }, - sort: { order: -1 } + sort: { left: -1 } }); if (existingFolders.count() >= 50) { throw new Meteor.Error('creatureFolders.methods.insert.denied', diff --git a/app/imports/api/creature/creatureFolders/methods.js/reorderCreatureFolder.js b/app/imports/api/creature/creatureFolders/methods.js/reorderCreatureFolder.js index 3cdc7c5a..f57aaa8a 100644 --- a/app/imports/api/creature/creatureFolders/methods.js/reorderCreatureFolder.js +++ b/app/imports/api/creature/creatureFolders/methods.js/reorderCreatureFolder.js @@ -31,7 +31,7 @@ const reorderCreatureFolder = new ValidatedMethod({ owner: userId }, { fields: { order: 1, }, - sort: { order: -1 } + sort: { left: -1 } }).forEach((folder, index) => { if (folder.order !== index) { CreatureFolders.update(_id, { $set: { order: index } }) diff --git a/app/imports/api/creature/creatureProperties/methods/duplicateProperty.js b/app/imports/api/creature/creatureProperties/methods/duplicateProperty.js index ad5665c3..7c1b1aa7 100644 --- a/app/imports/api/creature/creatureProperties/methods/duplicateProperty.js +++ b/app/imports/api/creature/creatureProperties/methods/duplicateProperty.js @@ -55,7 +55,7 @@ const duplicateProperty = new ValidatedMethod({ removed: { $ne: true }, }, { limit: DUPLICATE_CHILDREN_LIMIT + 1, - sort: { order: 1 }, + sort: { left: 1 }, }).fetch(); // Alert the user if the limit was hit diff --git a/app/imports/api/creature/creatureProperties/methods/getParentRefByTag.js b/app/imports/api/creature/creatureProperties/methods/getParentRefByTag.js index 1c664692..cda68469 100644 --- a/app/imports/api/creature/creatureProperties/methods/getParentRefByTag.js +++ b/app/imports/api/creature/creatureProperties/methods/getParentRefByTag.js @@ -8,7 +8,7 @@ export default function getParentRefByTag(creatureId, tag) { inactive: { $ne: true }, tags: tag, }, { - sort: { order: 1 }, + sort: { left: 1 }, }); return prop && { id: prop._id, collection: 'creatureProperties' }; } diff --git a/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js b/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js index f582ad29..87fc681a 100644 --- a/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js +++ b/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js @@ -159,7 +159,7 @@ function reifyNodeReferences(nodes, visitedRefs = new Set(), depth = 0) { ...getFilter.descendants(referencedNode), removed: { $ne: true }, }, { - sort: { order: 1 }, + sort: { left: 1 }, }).fetch(); // We are adding the referenced node and its descendants diff --git a/app/imports/api/docs/Docs.js b/app/imports/api/docs/Docs.js index 4cfa992c..291c045b 100644 --- a/app/imports/api/docs/Docs.js +++ b/app/imports/api/docs/Docs.js @@ -103,7 +103,7 @@ const insertDoc = new ValidatedMethod({ doc.parentId = parentId; - const lastOrder = Docs.find({}, { sort: { order: -1 } }).fetch()[0]?.order || 0; + const lastOrder = Docs.find({}, { sort: { left: -1 } }).fetch()[0]?.order || 0; doc.order = lastOrder + 1; doc.urlName = 'new-doc-' + (lastOrder + 1); diff --git a/app/imports/api/engine/loadCreatures.ts b/app/imports/api/engine/loadCreatures.ts index 4e091553..d8ac1cab 100644 --- a/app/imports/api/engine/loadCreatures.ts +++ b/app/imports/api/engine/loadCreatures.ts @@ -207,7 +207,7 @@ export function getPropertyChildren(creatureId, property) { 'parentId': property._id, removed: { $ne: true }, }, { - sort: { order: 1 }, + sort: { left: 1 }, }).fetch(); } } @@ -238,7 +238,7 @@ class LoadedCreature { 'root.id': creatureId, removed: { $ne: true }, }, { - sort: { order: 1 }, + sort: { left: 1 }, }).observeChanges({ added(id, fields) { fields._id = id; diff --git a/app/imports/api/library/methods/copyLibraryNodeTo.js b/app/imports/api/library/methods/copyLibraryNodeTo.js index 5c703253..a77f8d39 100644 --- a/app/imports/api/library/methods/copyLibraryNodeTo.js +++ b/app/imports/api/library/methods/copyLibraryNodeTo.js @@ -58,7 +58,7 @@ const copyLibraryNodeTo = new ValidatedMethod({ removed: { $ne: true }, }, { limit: DUPLICATE_CHILDREN_LIMIT + 1, - sort: { order: 1 }, + sort: { left: 1 }, }).fetch(); if (decendants.length > DUPLICATE_CHILDREN_LIMIT) { diff --git a/app/imports/api/library/methods/duplicateLibraryNode.js b/app/imports/api/library/methods/duplicateLibraryNode.js index 0983f97b..ee8116b9 100644 --- a/app/imports/api/library/methods/duplicateLibraryNode.js +++ b/app/imports/api/library/methods/duplicateLibraryNode.js @@ -47,7 +47,7 @@ const duplicateLibraryNode = new ValidatedMethod({ removed: { $ne: true }, }, { limit: DUPLICATE_CHILDREN_LIMIT + 1, - sort: { order: 1 }, + sort: { left: 1 }, }).fetch(); if (nodes.length > DUPLICATE_CHILDREN_LIMIT) { diff --git a/app/imports/client/ui/creature/archive/ArchiveDialog.vue b/app/imports/client/ui/creature/archive/ArchiveDialog.vue index d834c604..8113ac42 100644 --- a/app/imports/client/ui/creature/archive/ArchiveDialog.vue +++ b/app/imports/client/ui/creature/archive/ArchiveDialog.vue @@ -155,7 +155,7 @@ export default { const userId = Meteor.userId(); let folders = CreatureFolders.find( {owner: userId, archived: {$ne: true}}, - {sort: {order: 1}}, + {sort: {left: 1}}, ).map(folder => { folder.creatures = Creatures.find( { @@ -189,7 +189,7 @@ export default { const userId = Meteor.userId(); let folders = CreatureFolders.find( {owner: userId}, - {sort: {order: 1}}, + {sort: {left: 1}}, ).map(folder => { folder.creatures = ArchiveCreatureFiles.find( { diff --git a/app/imports/client/ui/creature/character/characterSheetTabs/BuildTab.vue b/app/imports/client/ui/creature/character/characterSheetTabs/BuildTab.vue index b4e1bf74..68cdb813 100644 --- a/app/imports/client/ui/creature/character/characterSheetTabs/BuildTab.vue +++ b/app/imports/client/ui/creature/character/characterSheetTabs/BuildTab.vue @@ -319,7 +319,7 @@ export default { removed: {$ne: true}, inactive: {$ne: true}, }, { - sort: {order: 1} + sort: {left: 1} }).fetch(); }, classLevels() { @@ -331,7 +331,7 @@ export default { removed: {$ne: true}, inactive: {$ne: true}, }, { - sort: {order: 1} + sort: {left: 1} }); }, slotBuildTree(){ diff --git a/app/imports/client/ui/creature/character/characterSheetTabs/FeaturesTab.vue b/app/imports/client/ui/creature/character/characterSheetTabs/FeaturesTab.vue index 3a127733..9f4f752a 100644 --- a/app/imports/client/ui/creature/character/characterSheetTabs/FeaturesTab.vue +++ b/app/imports/client/ui/creature/character/characterSheetTabs/FeaturesTab.vue @@ -76,7 +76,7 @@ export default { removed: { $ne: true }, inactive: { $ne: true }, }, { - sort: { order: 1 } + sort: { left: 1 } }); }, }, diff --git a/app/imports/client/ui/creature/character/characterSheetTabs/InventoryTab.vue b/app/imports/client/ui/creature/character/characterSheetTabs/InventoryTab.vue index c660367c..13655b90 100644 --- a/app/imports/client/ui/creature/character/characterSheetTabs/InventoryTab.vue +++ b/app/imports/client/ui/creature/character/characterSheetTabs/InventoryTab.vue @@ -163,7 +163,7 @@ export default { removed: { $ne: true }, inactive: { $ne: true }, }, { - sort: { order: 1 }, + sort: { left: 1 }, }).fetch(); }, creature() { @@ -188,7 +188,7 @@ export default { removed: { $ne: true }, inactive: { $ne: true }, }, { - sort: { order: 1 }, + sort: { left: 1 }, }); }, carriedItems() { @@ -204,7 +204,7 @@ export default { deactivatedByAncestor: { $ne: true }, deactivatedByToggle: { $ne: true }, }, { - sort: { order: 1 }, + sort: { left: 1 }, }); }, equippedItems() { @@ -215,7 +215,7 @@ export default { removed: { $ne: true }, inactive: { $ne: true }, }, { - sort: { order: 1 }, + sort: { left: 1 }, }); }, equipmentParentRef() { diff --git a/app/imports/client/ui/creature/character/characterSheetTabs/JournalTab.vue b/app/imports/client/ui/creature/character/characterSheetTabs/JournalTab.vue index bd53a20e..7ea6007c 100644 --- a/app/imports/client/ui/creature/character/characterSheetTabs/JournalTab.vue +++ b/app/imports/client/ui/creature/character/characterSheetTabs/JournalTab.vue @@ -90,7 +90,7 @@ export default { ...getFilter.descendantsOfRoot(this.creatureId), $nor: [getFilter.descendantsOfAll(allNotes)], }, { - sort: {order: 1}, + sort: {left: 1}, }); }, creature(){ diff --git a/app/imports/client/ui/creature/character/characterSheetTabs/SpellsTab.vue b/app/imports/client/ui/creature/character/characterSheetTabs/SpellsTab.vue index cfba26e8..a84c9872 100644 --- a/app/imports/client/ui/creature/character/characterSheetTabs/SpellsTab.vue +++ b/app/imports/client/ui/creature/character/characterSheetTabs/SpellsTab.vue @@ -115,7 +115,7 @@ export default { { hideWhenValueZero: true, value: 0 }, ], }, { - sort: { order: 1 } + sort: { left: 1 } }); }, spellLists() { @@ -168,7 +168,7 @@ export default { removed: { $ne: true }, inactive: { $ne: true }, }, { - sort: { order: 1 } + sort: { left: 1 } }); }, }, diff --git a/app/imports/client/ui/creature/character/characterSheetTabs/StatsTab.vue b/app/imports/client/ui/creature/character/characterSheetTabs/StatsTab.vue index e2e819e1..d3c34203 100644 --- a/app/imports/client/ui/creature/character/characterSheetTabs/StatsTab.vue +++ b/app/imports/client/ui/creature/character/characterSheetTabs/StatsTab.vue @@ -557,7 +557,7 @@ export default { if (creature.settings.hideUnusedStats) { filter.hide = { $ne: true }; } - const allProps = CreatureProperties.find(filter, { sort: { order: -1 } }).fetch(); + const allProps = CreatureProperties.find(filter, { sort: { left: -1 } }).fetch(); const forest = docsToForest(allProps); const properties = { folder: {}, attribute: {}, skill: {} }; walkDown(forest, node => { @@ -593,7 +593,7 @@ export default { deactivatedByToggle: { $ne: true }, showUI: true, }, { - sort: { order: 1 } + sort: { left: 1 } }); }, }, diff --git a/app/imports/client/ui/creature/character/printedCharacterSheet/CharacterSheetPrinted.vue b/app/imports/client/ui/creature/character/printedCharacterSheet/CharacterSheetPrinted.vue index 47fd6bcf..445c5675 100644 --- a/app/imports/client/ui/creature/character/printedCharacterSheet/CharacterSheetPrinted.vue +++ b/app/imports/client/ui/creature/character/printedCharacterSheet/CharacterSheetPrinted.vue @@ -212,7 +212,7 @@ export default { removed: {$ne: true}, inactive: {$ne: true}, }, { - sort: {order: 1} + sort: {left: 1} }).fetch(); }, classLevels() { @@ -224,7 +224,7 @@ export default { removed: {$ne: true}, inactive: {$ne: true}, }, { - sort: {order: 1} + sort: {left: 1} }); }, editPermission() { diff --git a/app/imports/client/ui/creature/character/printedCharacterSheet/PrintedInventory.vue b/app/imports/client/ui/creature/character/printedCharacterSheet/PrintedInventory.vue index 1baafe46..a11ffc0f 100644 --- a/app/imports/client/ui/creature/character/printedCharacterSheet/PrintedInventory.vue +++ b/app/imports/client/ui/creature/character/printedCharacterSheet/PrintedInventory.vue @@ -111,7 +111,7 @@ export default { removed: { $ne: true }, inactive: { $ne: true }, }, { - sort: { order: 1 }, + sort: { left: 1 }, }); }, creature() { @@ -133,7 +133,7 @@ export default { removed: { $ne: true }, inactive: { $ne: true }, }, { - sort: { order: 1 }, + sort: { left: 1 }, }).map(c => { c.items = CreatureProperties.find({ 'parentId': c._id, @@ -143,7 +143,7 @@ export default { deactivatedByAncestor: { $ne: true }, deactivatedByToggle: { $ne: true }, }, { - sort: { order: 1 }, + sort: { left: 1 }, }).fetch(); return c; }); @@ -158,7 +158,7 @@ export default { deactivatedByAncestor: { $ne: true }, deactivatedByToggle: { $ne: true }, }, { - sort: { order: 1 }, + sort: { left: 1 }, }); }, equippedItems() { @@ -169,7 +169,7 @@ export default { removed: { $ne: true }, inactive: { $ne: true }, }, { - sort: { order: 1 }, + sort: { left: 1 }, }); }, equipmentParentRef() { diff --git a/app/imports/client/ui/creature/character/printedCharacterSheet/PrintedSpells.vue b/app/imports/client/ui/creature/character/printedCharacterSheet/PrintedSpells.vue index d02c246d..2e1d8e62 100644 --- a/app/imports/client/ui/creature/character/printedCharacterSheet/PrintedSpells.vue +++ b/app/imports/client/ui/creature/character/printedCharacterSheet/PrintedSpells.vue @@ -70,7 +70,7 @@ export default { removed: { $ne: true }, inactive: { $ne: true }, }, { - sort: { order: 1 } + sort: { left: 1 } }).fetch(); }, spellsWithoutList() { @@ -96,7 +96,7 @@ export default { removed: { $ne: true }, inactive: { $ne: true }, }, { - sort: { order: 1 } + sort: { left: 1 } }).map(sl => { sl.spells = CreatureProperties.find({ ...getFilter.descendants(sl), diff --git a/app/imports/client/ui/creature/character/printedCharacterSheet/PrintedStats.vue b/app/imports/client/ui/creature/character/printedCharacterSheet/PrintedStats.vue index f83647f8..e558770a 100644 --- a/app/imports/client/ui/creature/character/printedCharacterSheet/PrintedStats.vue +++ b/app/imports/client/ui/creature/character/printedCharacterSheet/PrintedStats.vue @@ -363,7 +363,7 @@ import { uniqBy } from 'lodash'; import { getFilter } from '/imports/api/parenting/parentingFunctions'; const getProperties = function (creature, filter, options = { - sort: { order: 1 } + sort: { left: 1 } }) { if (!creature) return; if (creature.settings.hideUnusedStats) { @@ -434,7 +434,7 @@ export default { deactivatedByToggle: { $ne: true }, showUI: true, }, { - sort: { order: 1 } + sort: { left: 1 } }); }, healthBars() { diff --git a/app/imports/client/ui/creature/character/printedCharacterSheet/components/PrintedAction.vue b/app/imports/client/ui/creature/character/printedCharacterSheet/components/PrintedAction.vue index e3c2c69d..7f7bd0c1 100644 --- a/app/imports/client/ui/creature/character/printedCharacterSheet/components/PrintedAction.vue +++ b/app/imports/client/ui/creature/character/printedCharacterSheet/components/PrintedAction.vue @@ -175,7 +175,7 @@ export default { 'ancestors.id': this.model._id, 'removed': { $ne: true }, }, { - sort: {order: 1} + sort: {left: 1} }).map(prop => { // Get all the props we don't want to show the decendants of and // where they might appear in the ancestor list diff --git a/app/imports/client/ui/docs/DocsRightDrawer.vue b/app/imports/client/ui/docs/DocsRightDrawer.vue index 01831f79..c63f6bc7 100644 --- a/app/imports/client/ui/docs/DocsRightDrawer.vue +++ b/app/imports/client/ui/docs/DocsRightDrawer.vue @@ -47,7 +47,7 @@ export default { return Session.get('editingDocs'); }, docs() { - const docs = Docs.find({ removed: {$ne: true} }, { sort: {order: 1} }).fetch(); + const docs = Docs.find({ removed: {$ne: true} }, { sort: {left: 1} }).fetch(); return docsToForest(docs); }, }, diff --git a/app/imports/client/ui/layouts/Sidebar.vue b/app/imports/client/ui/layouts/Sidebar.vue index 8d371f7d..7ab264bd 100644 --- a/app/imports/client/ui/layouts/Sidebar.vue +++ b/app/imports/client/ui/layouts/Sidebar.vue @@ -113,7 +113,7 @@ export default { const userId = Meteor.userId(); let folders = CreatureFolders.find( { owner: userId, archived: { $ne: true } }, - { sort: { order: 1 } }, + { sort: { left: 1 } }, ).map(folder => { folder.creatures = Creatures.find( { diff --git a/app/imports/client/ui/library/LibraryEditDialog.vue b/app/imports/client/ui/library/LibraryEditDialog.vue index 1ef7f63a..43a0d08e 100644 --- a/app/imports/client/ui/library/LibraryEditDialog.vue +++ b/app/imports/client/ui/library/LibraryEditDialog.vue @@ -190,7 +190,7 @@ export default { removed: true, removedWith: { $exists: false }, }, { - sort: { order: 1 }, + sort: { left: 1 }, }); }, isOwner() { diff --git a/app/imports/client/ui/pages/CharacterList.vue b/app/imports/client/ui/pages/CharacterList.vue index 9a976b5a..f8b1ef46 100644 --- a/app/imports/client/ui/pages/CharacterList.vue +++ b/app/imports/client/ui/pages/CharacterList.vue @@ -112,7 +112,7 @@ export default { const userId = Meteor.userId(); let folders = CreatureFolders.find( { owner: userId, archived: { $ne: true } }, - { sort: { order: 1 } }, + { sort: { left: 1 } }, ).map(folder => { folder.creatures = Creatures.find( { diff --git a/app/imports/client/ui/pages/DocsPage.vue b/app/imports/client/ui/pages/DocsPage.vue index 51dd9014..10779948 100644 --- a/app/imports/client/ui/pages/DocsPage.vue +++ b/app/imports/client/ui/pages/DocsPage.vue @@ -113,13 +113,13 @@ export default { 'parent': undefined, removed: { $ne: true }, }, { - sort: { order: 1 } + sort: { left: 1 } }); return Docs.find({ 'parentId': this.doc._id, removed: { $ne: true }, }, { - sort: { order: 1 } + sort: { left: 1 } }) }, siblingDocs() { @@ -128,7 +128,7 @@ export default { 'parentId': this.doc.parent?.id, removed: { $ne: true }, }, { - sort: { order: 1 } + sort: { left: 1 } }); }, editing() { diff --git a/app/imports/client/ui/properties/components/actions/ActionCard.vue b/app/imports/client/ui/properties/components/actions/ActionCard.vue index f2bdf8ea..d64bb514 100644 --- a/app/imports/client/ui/properties/components/actions/ActionCard.vue +++ b/app/imports/client/ui/properties/components/actions/ActionCard.vue @@ -198,7 +198,7 @@ export default { 'ancestors.id': this.model._id, 'removed': { $ne: true }, }, { - sort: {order: 1} + sort: {left: 1} }).map(prop => { // Get all the props we don't want to show the decendants of and // where they might appear in the ancestor list diff --git a/app/imports/client/ui/properties/components/actions/SelectItemToConsume.vue b/app/imports/client/ui/properties/components/actions/SelectItemToConsume.vue index d1c042b9..1e307984 100644 --- a/app/imports/client/ui/properties/components/actions/SelectItemToConsume.vue +++ b/app/imports/client/ui/properties/components/actions/SelectItemToConsume.vue @@ -46,7 +46,7 @@ export default { removed: {$ne: true}, inactive: {$ne: true}, }, { - sort: {order: 1}, + sort: {left: 1}, fields: {equipped: false}, }); } diff --git a/app/imports/client/ui/properties/components/attributes/HealthBarCardContainer.vue b/app/imports/client/ui/properties/components/attributes/HealthBarCardContainer.vue index 51dc33e8..00fddff2 100644 --- a/app/imports/client/ui/properties/components/attributes/HealthBarCardContainer.vue +++ b/app/imports/client/ui/properties/components/attributes/HealthBarCardContainer.vue @@ -51,7 +51,7 @@ export default { filter.hide = { $ne: true }; } return CreatureProperties.find(filter, { - sort: { order: 1 } + sort: { left: 1 } }); }, }, diff --git a/app/imports/client/ui/properties/components/folders/FolderGroupCard.vue b/app/imports/client/ui/properties/components/folders/FolderGroupCard.vue index 3074024b..4523d7bd 100644 --- a/app/imports/client/ui/properties/components/folders/FolderGroupCard.vue +++ b/app/imports/client/ui/properties/components/folders/FolderGroupCard.vue @@ -61,7 +61,7 @@ export default { { hideWhenValueZero: true, value: 0 }, ], }, { - sort: { order: 1 }, + sort: { left: 1 }, }).forEach(prop => { if (propComponents[prop.type]) { props.push(prop); diff --git a/app/imports/client/ui/properties/components/folders/folderGroupComponents/FolderGroupChildren.vue b/app/imports/client/ui/properties/components/folders/folderGroupComponents/FolderGroupChildren.vue index abfdbcdb..30cfd16d 100644 --- a/app/imports/client/ui/properties/components/folders/folderGroupComponents/FolderGroupChildren.vue +++ b/app/imports/client/ui/properties/components/folders/folderGroupComponents/FolderGroupChildren.vue @@ -54,7 +54,7 @@ export default { { hideWhenValueZero: true, value: 0 }, ], }, { - sort: { order: 1 }, + sort: { left: 1 }, }).forEach(prop => { if (propComponents[prop.type]) { props.push(prop); diff --git a/app/imports/client/ui/properties/components/folders/folderGroupComponents/SlotBuildTree.vue b/app/imports/client/ui/properties/components/folders/folderGroupComponents/SlotBuildTree.vue index 60f9d455..49e9df68 100644 --- a/app/imports/client/ui/properties/components/folders/folderGroupComponents/SlotBuildTree.vue +++ b/app/imports/client/ui/properties/components/folders/folderGroupComponents/SlotBuildTree.vue @@ -48,14 +48,14 @@ export default { removed: { $ne: true }, inactive: { $ne: true }, }, { - sort: { order: 1 } + sort: { left: 1 } }); const slotIds = slots.map(s => s._id); const slotChildren = CreatureProperties.find({ 'parentId': { $in: slotIds }, removed: { $ne: true }, }, { - sort: { order: 1 }, + sort: { left: 1 }, }); const tree = nodeArrayToTree([ ...slots.fetch(), diff --git a/app/imports/client/ui/properties/components/inventory/ContainerCard.vue b/app/imports/client/ui/properties/components/inventory/ContainerCard.vue index a9d8ecc9..734cde9b 100644 --- a/app/imports/client/ui/properties/components/inventory/ContainerCard.vue +++ b/app/imports/client/ui/properties/components/inventory/ContainerCard.vue @@ -101,7 +101,7 @@ export default { deactivatedByAncestor: { $ne: true }, deactivatedByToggle: { $ne: true }, }, { - sort: { order: 1 }, + sort: { left: 1 }, }); }, } diff --git a/app/imports/client/ui/properties/components/spells/CastSpellWithSlotDialog.vue b/app/imports/client/ui/properties/components/spells/CastSpellWithSlotDialog.vue index 0651be34..4788c219 100644 --- a/app/imports/client/ui/properties/components/spells/CastSpellWithSlotDialog.vue +++ b/app/imports/client/ui/properties/components/spells/CastSpellWithSlotDialog.vue @@ -403,7 +403,7 @@ export default { }; } return CreatureProperties.find(filter, { - sort: { order: 1 } + sort: { left: 1 } }); }, spellSlots() { diff --git a/app/imports/client/ui/properties/forms/shared/lists/createListOfProperties.js b/app/imports/client/ui/properties/forms/shared/lists/createListOfProperties.js index 84e242f5..9282281b 100644 --- a/app/imports/client/ui/properties/forms/shared/lists/createListOfProperties.js +++ b/app/imports/client/ui/properties/forms/shared/lists/createListOfProperties.js @@ -15,7 +15,7 @@ export default function createListOfProperties(filter = {}, getNamesWithValues) }); } } - let options = { sort: { order: 1, variableName: 1 } } + let options = { sort: { left: 1, variableName: 1 } } CreatureProperties.find(filter, options).forEach(addUniquePropertys); LibraryNodes.find(filter, options).forEach(addUniquePropertys); if (getNamesWithValues) return propertyList; diff --git a/app/imports/client/ui/properties/viewers/SkillViewer.vue b/app/imports/client/ui/properties/viewers/SkillViewer.vue index b7385750..a9604589 100644 --- a/app/imports/client/ui/properties/viewers/SkillViewer.vue +++ b/app/imports/client/ui/properties/viewers/SkillViewer.vue @@ -193,7 +193,7 @@ export default { return CreatureProperties.find({ _id: {$in: this.model.proficiencyIds}, }, { - sort: {order: 1} + sort: {left: 1} }).fetch(); }, ability() { diff --git a/app/imports/client/ui/tabletop/TabletopActionCard.vue b/app/imports/client/ui/tabletop/TabletopActionCard.vue index cd84216f..70450776 100644 --- a/app/imports/client/ui/tabletop/TabletopActionCard.vue +++ b/app/imports/client/ui/tabletop/TabletopActionCard.vue @@ -248,7 +248,7 @@ export default { 'ancestors.id': this.model._id, 'removed': { $ne: true }, }, { - sort: {order: 1} + sort: {left: 1} }).map(prop => { // Get all the props we don't want to show the decendants of and // where they might appear in the ancestor list diff --git a/app/imports/client/ui/tabletop/TabletopComponent.vue b/app/imports/client/ui/tabletop/TabletopComponent.vue index 432d45f9..cb51f8b3 100644 --- a/app/imports/client/ui/tabletop/TabletopComponent.vue +++ b/app/imports/client/ui/tabletop/TabletopComponent.vue @@ -149,7 +149,7 @@ const getProperties = function (creatureId, selector = {}) { ], ...selector, }, { - sort: { order: 1 } + sort: { left: 1 } }); } diff --git a/app/imports/client/ui/tabletop/selectedCreatureBar/SelectedCreatureBar.vue b/app/imports/client/ui/tabletop/selectedCreatureBar/SelectedCreatureBar.vue index 0e8cb681..f57db9ee 100644 --- a/app/imports/client/ui/tabletop/selectedCreatureBar/SelectedCreatureBar.vue +++ b/app/imports/client/ui/tabletop/selectedCreatureBar/SelectedCreatureBar.vue @@ -327,7 +327,7 @@ export default { const propsById = {}; const props = []; CreatureProperties.find(filter, { - sort: { order: -1 }, + sort: { left: -1 }, fields: { _id: 1, type: 1 }, }).forEach(prop => { props.push(prop); diff --git a/app/imports/server/publications/library.js b/app/imports/server/publications/library.js index 9d69ec3f..2466617c 100644 --- a/app/imports/server/publications/library.js +++ b/app/imports/server/publications/library.js @@ -243,7 +243,7 @@ Meteor.publish('libraryNodes', function (libraryId, extraFields) { LibraryNodes.find({ 'root.id': libraryId, }, { - sort: { order: 1 }, + sort: { left: 1 }, fields, }), ]; @@ -288,7 +288,7 @@ Meteor.publish('softRemovedLibraryNodes', function (libraryId) { removed: true, removedWith: { $exists: false }, }, { - sort: { order: 1 }, + sort: { left: 1 }, }), ]; }); @@ -309,7 +309,7 @@ Meteor.publish('descendantLibraryNodes', function (nodeId) { LibraryNodes.find({ 'ancestors.id': nodeId, }, { - sort: { order: 1 }, + sort: { left: 1 }, }), ]; }); From 3483a6d34f4810ef7b5d0e2fa1475e211d9dc36b Mon Sep 17 00:00:00 2001 From: ThaumRystra <9525416+ThaumRystra@users.noreply.github.com> Date: Tue, 30 Apr 2024 13:03:33 +0200 Subject: [PATCH 04/14] Fixed actions using their own parent as ammo creating an infinite loop --- .../action/applyProperties/applyDamageProperty.ts | 8 ++++---- .../api/engine/action/functions/spendResources.ts | 6 +++++- app/imports/api/engine/action/tasks/Task.ts | 1 + .../api/engine/action/tasks/applyItemAsAmmoTask.ts | 11 ++++++++--- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/app/imports/api/engine/action/applyProperties/applyDamageProperty.ts b/app/imports/api/engine/action/applyProperties/applyDamageProperty.ts index eb6cccf0..db469c60 100644 --- a/app/imports/api/engine/action/applyProperties/applyDamageProperty.ts +++ b/app/imports/api/engine/action/applyProperties/applyDamageProperty.ts @@ -42,7 +42,7 @@ export default async function applyDamageProperty( // roll the dice only and store that string recalculateCalculation(prop.amount, action, 'compile', inputProvider); - const { result: rolled } = await resolve('roll', prop.amount.valueNode, scope, context); + const { result: rolled } = await resolve('roll', prop.amount.valueNode, scope, context, inputProvider); if (rolled.parseType !== 'constant') { logValue.push(toString(rolled)); } @@ -52,7 +52,7 @@ export default async function applyDamageProperty( context.errors = []; // Resolve the roll to a final value - const { result: reduced } = await resolve('reduce', rolled, scope, context); + const { result: reduced } = await resolve('reduce', rolled, scope, context, inputProvider); result.appendParserContextErrors(context, damageTargets); // Store the result @@ -102,11 +102,11 @@ export default async function applyDamageProperty( recalculateCalculation(prop.save.damageFunction, action, 'compile', inputProvider); context.errors = []; const { result: saveDamageRolled } = await resolve( - 'roll', prop.save.damageFunction.valueNode, scope, context + 'roll', prop.save.damageFunction.valueNode, scope, context, inputProvider ); saveRoll = toString(saveDamageRolled); const { result: saveDamageResult } = await resolve( - 'reduce', saveDamageRolled, scope, context + 'reduce', saveDamageRolled, scope, context, inputProvider ); result.appendParserContextErrors(context, damageTargets); // If we didn't end up with a constant of finite amount, give up diff --git a/app/imports/api/engine/action/functions/spendResources.ts b/app/imports/api/engine/action/functions/spendResources.ts index 66f6310a..b002d180 100644 --- a/app/imports/api/engine/action/functions/spendResources.ts +++ b/app/imports/api/engine/action/functions/spendResources.ts @@ -5,6 +5,7 @@ import recalculateCalculation from '/imports/api/engine/action/functions/recalcu import TaskResult from '/imports/api/engine/action/tasks/TaskResult'; import applyTask from '/imports/api/engine/action/tasks/applyTask'; import { getSingleProperty } from '/imports/api/engine/loadCreatures'; +import { hasAncestorRelationship } from '/imports/api/parenting/parentingFunctions'; export default async function spendResources( action: EngineAction, prop, targetIds: string[], result: TaskResult, userInput @@ -69,8 +70,11 @@ export default async function spendResources( params: { value: quantity, item, + // If the item is an ancestor or descendant of this prop, skip the item's children to avoid + // an infinite loop + skipChildren: hasAncestorRelationship(item, prop), }, }, userInput); } } -} \ No newline at end of file +} diff --git a/app/imports/api/engine/action/tasks/Task.ts b/app/imports/api/engine/action/tasks/Task.ts index eb920ec5..18328870 100644 --- a/app/imports/api/engine/action/tasks/Task.ts +++ b/app/imports/api/engine/action/tasks/Task.ts @@ -31,6 +31,7 @@ export type ItemAsAmmoTask = BaseTask & { params: { value: number; item: any; + skipChildren: boolean; }; } diff --git a/app/imports/api/engine/action/tasks/applyItemAsAmmoTask.ts b/app/imports/api/engine/action/tasks/applyItemAsAmmoTask.ts index 6a178f65..092b6321 100644 --- a/app/imports/api/engine/action/tasks/applyItemAsAmmoTask.ts +++ b/app/imports/api/engine/action/tasks/applyItemAsAmmoTask.ts @@ -1,6 +1,6 @@ import { EngineAction } from '/imports/api/engine/action/EngineActions'; import { - applyDefaultAfterPropTasks, applyTriggers + applyDefaultAfterPropTasks, applyAfterTasksSkipChildren, applyTriggers } from '/imports/api/engine/action/functions/applyTaskGroups'; import { getEffectiveActionScope @@ -31,7 +31,7 @@ export default async function applyItemAsAmmoTask(task: ItemAsAmmoTask, action: }; value = scope['~ammoConsumed']?.value || 0; - const itemChildren = await getPropertyChildren(action.creatureId, item); + const itemChildren = task.params.skipChildren ? [] : await getPropertyChildren(action.creatureId, item); // Do the quantity adjustment // Check if property has quantity @@ -53,5 +53,10 @@ export default async function applyItemAsAmmoTask(task: ItemAsAmmoTask, action: }); await applyTriggers(action, item, [action.creatureId], 'ammo.after', userInput); - return applyDefaultAfterPropTasks(action, item, task.targetIds, userInput); + + if (task.params.skipChildren) { + return applyAfterTasksSkipChildren(action, item, task.targetIds, userInput); + } else { + return applyDefaultAfterPropTasks(action, item, task.targetIds, userInput); + } } \ No newline at end of file From 19669e729c095426f5866dd276bd103c4d4364f6 Mon Sep 17 00:00:00 2001 From: ThaumRystra <9525416+ThaumRystra@users.noreply.github.com> Date: Tue, 30 Apr 2024 13:12:24 +0200 Subject: [PATCH 05/14] Updated Meteor packages --- app/.meteor/versions | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/.meteor/versions b/app/.meteor/versions index 4332f7f0..3405fc33 100644 --- a/app/.meteor/versions +++ b/app/.meteor/versions @@ -45,7 +45,7 @@ geojson-utils@1.0.11 google-oauth@1.4.4 hot-code-push@1.0.4 html-tools@1.1.4 -htmljs@1.2.0 +htmljs@1.2.1 http@2.0.0 id-map@1.1.1 inter-process-messaging@0.1.1 @@ -72,7 +72,7 @@ mobile-status-bar@1.1.0 modern-browsers@0.1.10 modules@0.20.0 modules-runtime@0.13.1 -mongo@1.16.8 +mongo@1.16.9 mongo-decimal@0.1.3 mongo-dev-server@1.1.0 mongo-id@1.0.8 @@ -80,7 +80,7 @@ npm-mongo@4.17.2 oauth@2.2.1 oauth2@1.3.2 ordered-dict@1.1.0 -ostrio:cookies@2.8.0 +ostrio:cookies@2.8.1 ostrio:files@2.3.3 patreon-oauth@0.1.0 peerlibrary:assert@0.3.0 @@ -112,7 +112,7 @@ shell-server@0.5.0 simple:json-routes@2.3.1 simple:rest@1.2.1 simple:rest-bearer-token-parser@1.1.1 -simple:rest-json-error-handler@1.1.1 +simple:rest-json-error-handler@1.1.3 simple:rest-method-mixin@1.1.0 socket-stream-client@0.5.2 spacebars-compiler@1.3.2 @@ -128,4 +128,4 @@ webapp@1.13.8 webapp-hashing@1.1.1 zer0th:meteor-vuetify-loader@0.1.41 zodern:fix-async-stubs@1.0.2 -zodern:types@1.0.11 +zodern:types@1.0.13 From 9cd6ca5c6e6fef22f4c67e54cda0fc54acb154cc Mon Sep 17 00:00:00 2001 From: ThaumRystra <9525416+ThaumRystra@users.noreply.github.com> Date: Tue, 30 Apr 2024 14:54:16 +0200 Subject: [PATCH 06/14] Choice branch UI working! --- .../ui/creature/actions/ActionDialog.vue | 52 ++++++----- .../ui/creature/actions/input/ChoiceInput.vue | 87 +++++++++++++++++++ .../DescendantPropertiesTree.vue | 3 +- 3 files changed, 118 insertions(+), 24 deletions(-) create mode 100644 app/imports/client/ui/creature/actions/input/ChoiceInput.vue diff --git a/app/imports/client/ui/creature/actions/ActionDialog.vue b/app/imports/client/ui/creature/actions/ActionDialog.vue index 3d56b33a..7da6f82d 100644 --- a/app/imports/client/ui/creature/actions/ActionDialog.vue +++ b/app/imports/client/ui/creature/actions/ActionDialog.vue @@ -14,19 +14,16 @@
-
-
- -
+
+
\ No newline at end of file diff --git a/app/imports/client/ui/creature/creatureProperties/DescendantPropertiesTree.vue b/app/imports/client/ui/creature/creatureProperties/DescendantPropertiesTree.vue index 9fa92021..26944a83 100644 --- a/app/imports/client/ui/creature/creatureProperties/DescendantPropertiesTree.vue +++ b/app/imports/client/ui/creature/creatureProperties/DescendantPropertiesTree.vue @@ -1,6 +1,6 @@ - - From 927fea9e8c03f322b3432dfabb4cd65717bd1dac Mon Sep 17 00:00:00 2001 From: ThaumRystra <9525416+ThaumRystra@users.noreply.github.com> Date: Thu, 2 May 2024 20:41:26 +0200 Subject: [PATCH 08/14] Fixed characters not recalculating on action --- .../action/functions/writeActionResults.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/app/imports/api/engine/action/functions/writeActionResults.ts b/app/imports/api/engine/action/functions/writeActionResults.ts index 2c862f92..5b3f51b6 100644 --- a/app/imports/api/engine/action/functions/writeActionResults.ts +++ b/app/imports/api/engine/action/functions/writeActionResults.ts @@ -5,12 +5,14 @@ import { union } from 'lodash'; import CreatureLogs from '/imports/api/creature/log/CreatureLogs'; import bulkWrite from '/imports/api/engine/shared/bulkWrite'; import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; +import Creatures from '/imports/api/creature/creatures/Creatures'; export default async function writeActionResults(action: EngineAction) { if (!action._id) throw new Meteor.Error('type-error', 'Action does not have an _id'); - EngineActions.remove(action._id); + const engineActionPromise = EngineActions.removeAsync(action._id); const creaturePropUpdates: any[] = []; const logContents: any[] = []; + // Collect all the updates and log content action.results.forEach(result => { result.mutations.forEach(mutation => { @@ -18,7 +20,7 @@ export default async function writeActionResults(action: EngineAction) { logContents.push(...mutationToLogUpdates(mutation)); }); }); - const allTargetIds = union(...logContents.map(c => c.targetIds)); + const allTargetIds: string[] = union(...logContents.map(c => c.targetIds)); // Write the log const logPromise = CreatureLogs.insertAsync({ @@ -30,5 +32,14 @@ export default async function writeActionResults(action: EngineAction) { // Write the bulk updates const bulkWritePromise = bulkWrite(creaturePropUpdates, CreatureProperties); - return Promise.all([logPromise, bulkWritePromise]); + // Mark the creatures as dirty + const creaturePromise = Creatures.updateAsync({ + _id: { $in: [action.creatureId, ...allTargetIds] }, + }, { + $set: { dirty: true }, + }, { + multi: true, + }); + + return Promise.all([engineActionPromise, logPromise, bulkWritePromise, creaturePromise]); } From 445c2bb9c7b0aa3b53585f47dc6742583861b047 Mon Sep 17 00:00:00 2001 From: ThaumRystra <9525416+ThaumRystra@users.noreply.github.com> Date: Thu, 2 May 2024 20:41:52 +0200 Subject: [PATCH 09/14] Fixed action cards briefly flashing dialog that wasn't needed --- .../client/ui/creature/actions/doAction.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/app/imports/client/ui/creature/actions/doAction.ts b/app/imports/client/ui/creature/actions/doAction.ts index a04df490..c07b3a48 100644 --- a/app/imports/client/ui/creature/actions/doAction.ts +++ b/app/imports/client/ui/creature/actions/doAction.ts @@ -5,6 +5,7 @@ import EngineActions, { EngineAction } from '/imports/api/engine/action/EngineAc import InputProvider from '/imports/api/engine/action/functions/userInput/InputProvider'; import applyAction from '/imports/api/engine/action/functions/applyAction'; import { runAction } from '/imports/api/engine/action/methods/runAction'; +import getDeterministicDiceRoller from '/imports/api/engine/action/functions/userInput/getDeterministicDiceRoller'; /** * Apply an action on the client that first creates the action on both the client and server, then @@ -44,7 +45,7 @@ export default async function doAction( // Either way, call the action method afterwards try { const finishedAction = await applyAction( - action, errorOnInputRequest, { simulate: true, task } + action, getErrorOnInputRequestProvider(action._id), { simulate: true, task } ); return callActionMethod(finishedAction, task); } catch (e) { @@ -76,10 +77,13 @@ const throwInputRequestedError = () => { throw 'input-requested'; } -const errorOnInputRequest: InputProvider = { - nextStep: throwInputRequestedError, - rollDice: throwInputRequestedError, - choose: throwInputRequestedError, - advantage: throwInputRequestedError, - check: throwInputRequestedError, +function getErrorOnInputRequestProvider(actionId) { + const errorOnInputRequest: InputProvider = { + nextStep: throwInputRequestedError, + rollDice: getDeterministicDiceRoller(actionId), + choose: throwInputRequestedError, + advantage: throwInputRequestedError, + check: throwInputRequestedError, + } + return errorOnInputRequest; } From de1eb642857a361fb8faeba25ba854e65ff70724 Mon Sep 17 00:00:00 2001 From: ThaumRystra <9525416+ThaumRystra@users.noreply.github.com> Date: Thu, 2 May 2024 20:42:03 +0200 Subject: [PATCH 10/14] Fixed action card not loading on action --- .../ui/properties/components/actions/ActionCard.vue | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/imports/client/ui/properties/components/actions/ActionCard.vue b/app/imports/client/ui/properties/components/actions/ActionCard.vue index d64bb514..cdc56e37 100644 --- a/app/imports/client/ui/properties/components/actions/ActionCard.vue +++ b/app/imports/client/ui/properties/components/actions/ActionCard.vue @@ -106,7 +106,6 @@ import ActionConditionView from '/imports/client/ui/properties/components/action import AttributeConsumedView from '/imports/client/ui/properties/components/actions/AttributeConsumedView.vue'; import ItemConsumedView from '/imports/client/ui/properties/components/actions/ItemConsumedView.vue'; import PropertyIcon from '/imports/client/ui/properties/shared/PropertyIcon.vue'; -import RollPopup from '/imports/client/ui/components/RollPopup.vue'; import MarkdownText from '/imports/client/ui/components/MarkdownText.vue'; import CardHighlight from '/imports/client/ui/components/CardHighlight.vue'; import TreeNodeList from '/imports/client/ui/components/tree/TreeNodeList.vue'; @@ -121,7 +120,6 @@ export default { ItemConsumedView, MarkdownText, PropertyIcon, - RollPopup, CardHighlight, TreeNodeList, }, @@ -225,7 +223,12 @@ export default { this.$emit('click', e); }, doAction() { - doAction(this.model, this.$store, this.model._id); + this.doActionLoading = true; + doAction(this.model, this.$store, this.model._id).catch((e) => { + console.error(e); + }).finally(() => { + this.doActionLoading = false; + }); }, } } From 982897897fca61f2ce8cf902fed1b2d4666cc627 Mon Sep 17 00:00:00 2001 From: ThaumRystra <9525416+ThaumRystra@users.noreply.github.com> Date: Fri, 3 May 2024 14:29:42 +0200 Subject: [PATCH 11/14] Fixed Incrementing props from stats tab --- .../action/tasks/applyDamagePropTask.ts | 4 +- .../character/characterSheetTabs/StatsTab.vue | 29 ++++--- .../components/attributes/HealthBarCard.vue | 27 ------- .../attributes/HealthBarCardContainer.vue | 75 ------------------- 4 files changed, 19 insertions(+), 116 deletions(-) delete mode 100644 app/imports/client/ui/properties/components/attributes/HealthBarCard.vue delete mode 100644 app/imports/client/ui/properties/components/attributes/HealthBarCardContainer.vue diff --git a/app/imports/api/engine/action/tasks/applyDamagePropTask.ts b/app/imports/api/engine/action/tasks/applyDamagePropTask.ts index 65162120..3408fca9 100644 --- a/app/imports/api/engine/action/tasks/applyDamagePropTask.ts +++ b/app/imports/api/engine/action/tasks/applyDamagePropTask.ts @@ -124,8 +124,8 @@ export default async function applyDamagePropTask( type: targetProp.type, }], contents: [{ - name: 'Attribute damaged', - value: `${numberToSignedString(-value)} ${getPropertyTitle(targetProp)}`, + name: increment >= 0 ? 'Attribute damaged' : 'Attribute restored', + value: `${numberToSignedString(-increment)} ${getPropertyTitle(targetProp)}`, inline: true, ...prop.silent && { silenced: true }, }] diff --git a/app/imports/client/ui/creature/character/characterSheetTabs/StatsTab.vue b/app/imports/client/ui/creature/character/characterSheetTabs/StatsTab.vue index d3c34203..93d7f09e 100644 --- a/app/imports/client/ui/creature/character/characterSheetTabs/StatsTab.vue +++ b/app/imports/client/ui/creature/character/characterSheetTabs/StatsTab.vue @@ -392,7 +392,6 @@ - - diff --git a/app/imports/client/ui/properties/components/attributes/HealthBarCard.vue b/app/imports/client/ui/properties/components/attributes/HealthBarCard.vue deleted file mode 100644 index 54d82d48..00000000 --- a/app/imports/client/ui/properties/components/attributes/HealthBarCard.vue +++ /dev/null @@ -1,27 +0,0 @@ - - - diff --git a/app/imports/client/ui/properties/components/attributes/HealthBarCardContainer.vue b/app/imports/client/ui/properties/components/attributes/HealthBarCardContainer.vue deleted file mode 100644 index 00fddff2..00000000 --- a/app/imports/client/ui/properties/components/attributes/HealthBarCardContainer.vue +++ /dev/null @@ -1,75 +0,0 @@ - - - From c5f6ce81bd3e145b855a6bbfaca07f5e46316e83 Mon Sep 17 00:00:00 2001 From: ThaumRystra <9525416+ThaumRystra@users.noreply.github.com> Date: Sat, 4 May 2024 10:37:25 +0200 Subject: [PATCH 12/14] Replaced damageProperty with new action engine --- .../creatureProperties/methods/index.js | 1 - .../api/creature/creatures/methods/index.js | 1 - .../creatures/methods/restCreature.js | 169 ------------------ .../character/characterSheetTabs/StatsTab.vue | 5 +- .../CreaturePropertyDialog.vue | 24 ++- .../components/attributes/HealthBar.vue | 5 +- .../attributes/SpellSlotListTile.vue | 29 ++- .../AttributeGroupComponent.vue | 43 +++-- .../ui/properties/viewers/AttributeViewer.vue | 29 +-- 9 files changed, 93 insertions(+), 213 deletions(-) delete mode 100644 app/imports/api/creature/creatures/methods/restCreature.js diff --git a/app/imports/api/creature/creatureProperties/methods/index.js b/app/imports/api/creature/creatureProperties/methods/index.js index e66019cc..05aba1ce 100644 --- a/app/imports/api/creature/creatureProperties/methods/index.js +++ b/app/imports/api/creature/creatureProperties/methods/index.js @@ -1,6 +1,5 @@ import '/imports/api/creature/creatureProperties/methods/adjustQuantity'; import '/imports/api/creature/creatureProperties/methods/copyPropertyToLibrary'; -import '/imports/api/creature/creatureProperties/methods/damageProperty'; import '/imports/api/creature/creatureProperties/methods/duplicateProperty'; import '/imports/api/creature/creatureProperties/methods/equipItem'; import '/imports/api/creature/creatureProperties/methods/insertProperty'; diff --git a/app/imports/api/creature/creatures/methods/index.js b/app/imports/api/creature/creatures/methods/index.js index 3e8073b6..25715c2c 100644 --- a/app/imports/api/creature/creatures/methods/index.js +++ b/app/imports/api/creature/creatures/methods/index.js @@ -1,5 +1,4 @@ import '/imports/api/creature/creatures/methods/insertCreature'; import '/imports/api/creature/creatures/methods/removeCreature'; -import '/imports/api/creature/creatures/methods/restCreature'; import '/imports/api/creature/creatures/methods/updateCreature'; import '/imports/api/creature/creatures/methods/changeAllowedLibraries'; diff --git a/app/imports/api/creature/creatures/methods/restCreature.js b/app/imports/api/creature/creatures/methods/restCreature.js deleted file mode 100644 index e8768b33..00000000 --- a/app/imports/api/creature/creatures/methods/restCreature.js +++ /dev/null @@ -1,169 +0,0 @@ -import SimpleSchema from 'simpl-schema'; -import { ValidatedMethod } from 'meteor/mdg:validated-method'; -import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; -import { assertEditPermission } from '/imports/api/creature/creatures/creaturePermissions'; -import { union } from 'lodash'; -import { damagePropertyWork } from '/imports/api/creature/creatureProperties/methods/damageProperty'; -import { getFilter } from '/imports/api/parenting/parentingFunctions'; - -const restCreature = new ValidatedMethod({ - name: 'creature.methods.rest', - validate: new SimpleSchema({ - creatureId: { - type: String, - regEx: SimpleSchema.RegEx.Id, - }, - restType: { - type: String, - allowedValues: ['shortRest', 'longRest'], - }, - }).validator(), - mixins: [RateLimiterMixin], - rateLimit: { - numRequests: 5, - timeInterval: 5000, - }, - run({ creatureId, restType }) { - // Get action context - const actionContext = new ActionContext(creatureId, [creatureId], this); - // Check permissions - assertEditPermission(actionContext.creature, this.userId); - - // Join, sort, and apply before triggers - const beforeTriggers = union( - actionContext.triggers.anyRest?.before, actionContext.triggers[restType]?.before - ).sort((a, b) => a.order - b.order); - applyTriggers(beforeTriggers, null, actionContext); - - // Rest - actionContext.addLog({ - name: restType === 'shortRest' ? 'Short rest' : 'Long rest', - }); - doRestWork(restType, actionContext); - - // Join, sort, and apply after triggers - const afterTriggers = union( - actionContext.triggers.anyRest?.after, actionContext.triggers[restType]?.after - ).sort((a, b) => a.order - b.order); - applyTriggers(afterTriggers, null, actionContext); - - // Insert log - actionContext.writeLog(); - }, -}); - -function doRestWork(restType, actionContext) { - const creatureId = actionContext.creature._id; - // Long rests reset short rest properties as well - let resetFilter; - if (restType === 'shortRest') { - resetFilter = 'shortRest' - } else { - resetFilter = { $in: ['shortRest', 'longRest'] } - } - resetProperties(creatureId, resetFilter, actionContext); - - // Reset half hit dice on a long rest, starting with the highest dice - if (restType === 'longRest') { - resetHitDice(creatureId, actionContext); - } -} - -export function resetProperties(creatureId, resetFilter, actionContext) { - // Only apply to active properties - const filter = { - ...getFilter.descendantsOfRoot(creatureId), - reset: resetFilter, - removed: { $ne: true }, - inactive: { $ne: true }, - }; - // update all attribute's damage - const attributeFilter = { - ...filter, - type: 'attribute', - damage: { $nin: [0, undefined] }, - } - CreatureProperties.find(attributeFilter).forEach(prop => { - damagePropertyWork({ - prop, - operation: 'increment', - value: -prop.damage ?? 0, - actionContext, - logFunction(increment) { - actionContext.addLog({ - name: prop.name, - value: increment < 0 ? `Restored ${-increment}` : `Removed ${-increment}` - }); - } - }); - }); - // Update all action-like properties' usesUsed - const actionFilter = { - ...filter, - type: { - $in: ['action', 'spell'] - }, - usesUsed: { $nin: [0, undefined] }, - }; - CreatureProperties.find(actionFilter, { - fields: { name: 1, usesUsed: 1 } - }).forEach(prop => { - actionContext.addLog({ - name: prop.name, - value: prop.usesUsed >= 0 ? `Restored ${prop.usesUsed} uses` : `Removed ${-prop.usesUsed} uses` - }); - }); - CreatureProperties.update(actionFilter, { - $set: { - usesUsed: 0, - dirty: true, - } - }, { - selector: { type: 'action' }, - multi: true, - }); -} - -function resetHitDice(creatureId, actionContext) { - let hitDice = CreatureProperties.find({ - ...getFilter.descendantsOfRoot(creatureId), - type: 'attribute', - attributeType: 'hitDice', - removed: { $ne: true }, - inactive: { $ne: true }, - }).fetch(); - // Use a collator to do sorting in natural order - let collator = new Intl.Collator('en', { - numeric: true, sensitivity: 'base' - }); - // Get the hit dice in decending order of hitDiceSize - let compare = (a, b) => collator.compare(b.hitDiceSize, a.hitDiceSize) - hitDice.sort(compare); - // Get the total number of hit dice that can be recovered this rest - let totalHd = hitDice.reduce((sum, hd) => sum + (hd.total || 0), 0); - let resetMultiplier = actionContext.creature.settings.hitDiceResetMultiplier || 0.5; - let recoverableHd = Math.max(Math.floor(totalHd * resetMultiplier), 1); - // recover each hit dice in turn until the recoverable amount is used up - let amountToRecover; - hitDice.forEach(hd => { - if (!recoverableHd) return; - amountToRecover = Math.min(recoverableHd, hd.damage ?? 0); - if (!amountToRecover) return; - recoverableHd -= amountToRecover; - damagePropertyWork({ - prop: hd, - operation: 'increment', - value: -amountToRecover, - actionContext, - logFunction(increment) { - actionContext.addLog({ - name: hd.name, - value: increment < 0 ? `Restored ${-increment} hit dice` : `Removed ${increment} hit dice` - }); - } - }); - }); -} - -export default restCreature; diff --git a/app/imports/client/ui/creature/character/characterSheetTabs/StatsTab.vue b/app/imports/client/ui/creature/character/characterSheetTabs/StatsTab.vue index 93d7f09e..ba3b253d 100644 --- a/app/imports/client/ui/creature/character/characterSheetTabs/StatsTab.vue +++ b/app/imports/client/ui/creature/character/characterSheetTabs/StatsTab.vue @@ -12,7 +12,7 @@ v-for="healthBar in properties.attribute.healthBar" :key="healthBar._id" :model="healthBar" - @change="({ type, value }) => incrementChange(healthBar._id, { type, value: -value })" + @change="({ type, value }) => incrementChange(healthBar._id, { type, value })" @click="clickProperty({_id: healthBar._id})" /> @@ -614,6 +614,7 @@ export default { }, incrementChange(_id, { type, value, ack }) { const model = CreatureProperties.findOne(_id); + if (type === 'increment') value = -value; doAction(model, this.$store, model._id, { subtaskFn: 'damageProp', prop: model, @@ -621,7 +622,7 @@ export default { params: { title: getPropertyTitle(model), operation: type, - value: -value, + value, targetProp: model, } }).then(() =>{ diff --git a/app/imports/client/ui/creature/creatureProperties/CreaturePropertyDialog.vue b/app/imports/client/ui/creature/creatureProperties/CreaturePropertyDialog.vue index 8b6ef6b8..08b53237 100644 --- a/app/imports/client/ui/creature/creatureProperties/CreaturePropertyDialog.vue +++ b/app/imports/client/ui/creature/creatureProperties/CreaturePropertyDialog.vue @@ -72,7 +72,6 @@ diff --git a/app/imports/client/ui/properties/viewers/AttributeViewer.vue b/app/imports/client/ui/properties/viewers/AttributeViewer.vue index c8776279..7867969c 100644 --- a/app/imports/client/ui/properties/viewers/AttributeViewer.vue +++ b/app/imports/client/ui/properties/viewers/AttributeViewer.vue @@ -141,12 +141,13 @@ import propertyViewerMixin from '/imports/client/ui/properties/viewers/shared/propertyViewerMixin' import numberToSignedString from '../../../../api/utility/numberToSignedString'; import AttributeEffect from '/imports/client/ui/properties/components/attributes/AttributeEffect.vue'; - import damageProperty from '/imports/api/creature/creatureProperties/methods/damageProperty'; import IncrementButton from '/imports/client/ui/components/IncrementButton.vue'; import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import getProficiencyIcon from '/imports/client/ui/utility/getProficiencyIcon'; import {snackbar} from '/imports/client/ui/components/snackbars/SnackbarQueue'; import sortEffects from '/imports/client/ui/utility/sortEffects'; +import doAction from '/imports/client/ui/creature/actions/doAction'; +import getPropertyTitle from '/imports/client/ui/properties/shared/getPropertyTitle'; export default { components: { @@ -208,18 +209,24 @@ data: {_id: id}, }); }, - damageProperty({type, value}) { + damageProperty({ type, value }) { + const model = this.model; this.damagePropertyLoading = true; - damageProperty.call({ - _id: this.model._id, - operation: type, - value: value - }, error => { - this.damagePropertyLoading = false; - if (error){ - snackbar({text: error.reason}); - console.error(error); + doAction(model, this.$store, model._id, { + subtaskFn: 'damageProp', + prop: model, + targetIds: [model.root.id], + params: { + title: getPropertyTitle(model), + operation: type, + value, + targetProp: model, } + }).catch((error) => { + snackbar({ text: error.reason || error.message || error.toString() }); + console.error(error); + }).finally(() => { + this.damagePropertyLoading = false; }); }, }, From c11013eddb6f72070800fad09778212f745058aa Mon Sep 17 00:00:00 2001 From: ThaumRystra <9525416+ThaumRystra@users.noreply.github.com> Date: Sat, 4 May 2024 18:57:56 +0200 Subject: [PATCH 13/14] Fixed soft-remove of props and library props --- .../methods/restoreProperty.js | 8 +-- .../methods/softRemoveProperty.js | 2 +- app/imports/api/library/LibraryNodes.js | 4 +- .../api/parenting/parentingFunctions.ts | 2 +- app/imports/api/parenting/softRemove.ts | 66 +++++++++++-------- 5 files changed, 44 insertions(+), 38 deletions(-) diff --git a/app/imports/api/creature/creatureProperties/methods/restoreProperty.js b/app/imports/api/creature/creatureProperties/methods/restoreProperty.js index 37713d56..05e0a316 100644 --- a/app/imports/api/creature/creatureProperties/methods/restoreProperty.js +++ b/app/imports/api/creature/creatureProperties/methods/restoreProperty.js @@ -23,13 +23,7 @@ const restoreProperty = new ValidatedMethod({ assertEditPermission(rootCreature, this.userId); // Do work - restore({ - _id, - collection: CreatureProperties, - extraUpdates: { - $set: { dirty: true } - }, - }); + restore(CreatureProperties, property, { $set: { dirty: true } }); } }); diff --git a/app/imports/api/creature/creatureProperties/methods/softRemoveProperty.js b/app/imports/api/creature/creatureProperties/methods/softRemoveProperty.js index 7c0753bc..3d62655a 100644 --- a/app/imports/api/creature/creatureProperties/methods/softRemoveProperty.js +++ b/app/imports/api/creature/creatureProperties/methods/softRemoveProperty.js @@ -23,7 +23,7 @@ const softRemoveProperty = new ValidatedMethod({ assertEditPermission(rootCreature, this.userId); // Do work - softRemove({ _id, collection: CreatureProperties }); + softRemove(CreatureProperties, property); } }); diff --git a/app/imports/api/library/LibraryNodes.js b/app/imports/api/library/LibraryNodes.js index 56373c55..b31333ca 100644 --- a/app/imports/api/library/LibraryNodes.js +++ b/app/imports/api/library/LibraryNodes.js @@ -284,7 +284,7 @@ const softRemoveLibraryNode = new ValidatedMethod({ run({ _id }) { let node = LibraryNodes.findOne(_id); assertNodeEditPermission(node, this.userId); - softRemove({ _id, collection: LibraryNodes }); + softRemove(LibraryNodes, node); } }); @@ -303,7 +303,7 @@ const restoreLibraryNode = new ValidatedMethod({ let node = LibraryNodes.findOne(_id); assertNodeEditPermission(node, this.userId); // Do work - restore(LibraryNodes, _id); + restore(LibraryNodes, node); } }); diff --git a/app/imports/api/parenting/parentingFunctions.ts b/app/imports/api/parenting/parentingFunctions.ts index 6dc3d219..96398e53 100644 --- a/app/imports/api/parenting/parentingFunctions.ts +++ b/app/imports/api/parenting/parentingFunctions.ts @@ -5,7 +5,7 @@ import CreatureProperties from '/imports/api/creature/creatureProperties/Creatur import { Mongo } from 'meteor/mongo'; export function getCollectionByName(name: string): Mongo.Collection { - const collection = Mongo.Collection.get(name) + const collection: Mongo.Collection = Mongo.Collection.get(name) if (!collection) { throw new Meteor.Error('bad-collection-reference', `Parent references collection ${name}, which does not exist` diff --git a/app/imports/api/parenting/softRemove.ts b/app/imports/api/parenting/softRemove.ts index 10c49523..3783a3b5 100644 --- a/app/imports/api/parenting/softRemove.ts +++ b/app/imports/api/parenting/softRemove.ts @@ -1,19 +1,28 @@ import { getCollectionByName, getFilter } from '/imports/api/parenting/parentingFunctions'; import { TreeDoc } from '/imports/api/parenting/ChildSchema'; -export async function softRemove(collection: Mongo.Collection | string, doc?: TreeDoc | string) { +export function softRemove(collectionOrName: Mongo.Collection | string, docOrId?: TreeDoc | string) { const removalDate = new Date(); - if (typeof collection === 'string') { - collection = getCollectionByName(collection); + + let collection: Mongo.Collection; + if (typeof collectionOrName === 'string') { + collection = getCollectionByName(collectionOrName); + } else { + collection = collectionOrName; } - if (typeof doc === 'string') { - doc = await collection.findOneAsync(doc); + + let doc: TreeDoc | undefined; + if (typeof docOrId === 'string') { + doc = collection.findOne(docOrId); + } else { + doc = docOrId } if (!doc) { throw new Meteor.Error('not found', 'The document to remove was not found'); } + // Remove this document - const removeDocPromise = collection.updateAsync( + collection.update( doc._id, { $set: { @@ -23,13 +32,11 @@ export async function softRemove(collection: Mongo.Collection | string, $unset: { removedWith: 1, } - }, { - selector: { type: 'any' }, - }, + } ); // Remove all the descendants that have not yet been removed, and set them to be // removed with this document - const removeDescendantsPromise = collection.updateAsync({ + collection.update({ ...getFilter.descendants(doc), removed: { $ne: true }, }, { @@ -39,10 +46,8 @@ export async function softRemove(collection: Mongo.Collection | string, removedWith: doc._id, } }, { - selector: { type: 'any' }, multi: true, }); - return Promise.all([removeDocPromise, removeDescendantsPromise]); } const restoreError = function () { @@ -51,18 +56,26 @@ const restoreError = function () { ); }; -export async function restore(collection: Mongo.Collection | string, doc: TreeDoc | string, extraUpdates?) { - if (typeof collection === 'string') { - collection = getCollectionByName(collection); +export function restore(collectionOrName: Mongo.Collection | string, docOrId: TreeDoc | string, extraUpdates?) { + + let collection: Mongo.Collection; + if (typeof collectionOrName === 'string') { + collection = getCollectionByName(collectionOrName); + } else { + collection = collectionOrName; } - if (typeof doc === 'string') { - const foundDoc = await collection.findOneAsync(doc) - if (!foundDoc) { - throw new Meteor.Error('not found', 'The document to remove was not found'); - } - doc = foundDoc; + + let doc: TreeDoc | undefined; + if (typeof docOrId === 'string') { + doc = collection.findOne(docOrId); + } else { + doc = docOrId } - const numUpdated: number = await collection.updateAsync({ + if (!doc) { + throw new Meteor.Error('not found', 'The document to remove was not found'); + } + + const numUpdated: number = collection.update({ _id: doc._id, removedWith: { $exists: false } }, { @@ -71,11 +84,11 @@ export async function restore(collection: Mongo.Collection | string, do removedAt: 1, }, ...extraUpdates - }, { - selector: { type: 'any' }, }); + if (numUpdated === 0) restoreError(); - return collection.updateAsync({ + + return collection.update({ removedWith: doc._id, }, { $unset: { @@ -84,7 +97,6 @@ export async function restore(collection: Mongo.Collection | string, do removedWith: 1, } }, { - selector: { type: 'any' }, multi: true, - }); + }) + 1; } From 9a6cb4b23f7c9e1fa3eb5afe4af5da05b269382e Mon Sep 17 00:00:00 2001 From: ThaumRystra <9525416+ThaumRystra@users.noreply.github.com> Date: Sat, 4 May 2024 19:25:38 +0200 Subject: [PATCH 14/14] Started removing old action engine methods --- .../applySavingThrowProperty.ts | 8 +- .../functions/userInput/InputProvider.ts | 4 +- .../api/engine/action/methods/doCheck.js | 139 ------------------ .../client/ui/components/RollPopup.vue | 122 --------------- .../client/ui/components/rolls/Check.vue | 99 ------------- .../components/attributes/AbilityListTile.vue | 43 +++--- .../attributes/AttributeCardContent.vue | 43 +++--- .../components/skills/SkillListTile.vue | 12 +- .../spells/CastSpellWithSlotDialog.vue | 15 -- .../client/ui/tabletop/TabletopActionCard.vue | 31 ---- 10 files changed, 51 insertions(+), 465 deletions(-) delete mode 100644 app/imports/api/engine/action/methods/doCheck.js delete mode 100644 app/imports/client/ui/components/RollPopup.vue delete mode 100644 app/imports/client/ui/components/rolls/Check.vue diff --git a/app/imports/api/engine/action/applyProperties/applySavingThrowProperty.ts b/app/imports/api/engine/action/applyProperties/applySavingThrowProperty.ts index e8c53c96..8f76dddc 100644 --- a/app/imports/api/engine/action/applyProperties/applySavingThrowProperty.ts +++ b/app/imports/api/engine/action/applyProperties/applySavingThrowProperty.ts @@ -4,7 +4,6 @@ import InputProvider from '/imports/api/engine/action/functions/userInput/InputP import { applyDefaultAfterPropTasks } from '/imports/api/engine/action/functions/applyTaskGroups'; import { getEffectiveActionScope } from '/imports/api/engine/action/functions/getEffectiveActionScope'; import recalculateCalculation from '/imports/api/engine/action/functions/recalculateCalculation'; -import { applyUnresolvedEffects } from '/imports/api/engine/action/methods/doCheck'; import { PropTask } from '/imports/api/engine/action/tasks/Task'; import TaskResult from '/imports/api/engine/action/tasks/TaskResult'; import { getVariables } from '/imports/api/engine/loadCreatures'; @@ -64,11 +63,8 @@ export default async function applySavingThrowProperty( applyDefaultAfterPropTasks(action, prop, [targetId], inputProvider); } - let rollModifierText = numberToSignedString(save.value, true); - let rollModifier = save.value - const { effectBonus, effectString } = applyUnresolvedEffects(save, scope) - rollModifierText += effectString; - rollModifier += effectBonus; + const rollModifierText = numberToSignedString(save.value, true); + const rollModifier = save.value; let value, resultPrefix; if (save.advantage === 1) { diff --git a/app/imports/api/engine/action/functions/userInput/InputProvider.ts b/app/imports/api/engine/action/functions/userInput/InputProvider.ts index 51244a25..87235fdf 100644 --- a/app/imports/api/engine/action/functions/userInput/InputProvider.ts +++ b/app/imports/api/engine/action/functions/userInput/InputProvider.ts @@ -37,8 +37,8 @@ export type Advantage = 0 | 1 | -1; export type CheckParams = { advantage: Advantage; - skillVariableName: string; - abilityVariableName: string; + skillVariableName?: string; + abilityVariableName?: string; dc: number | null; contest?: true; targetSkillVariableName?: string; diff --git a/app/imports/api/engine/action/methods/doCheck.js b/app/imports/api/engine/action/methods/doCheck.js deleted file mode 100644 index efdb352d..00000000 --- a/app/imports/api/engine/action/methods/doCheck.js +++ /dev/null @@ -1,139 +0,0 @@ -import SimpleSchema from 'simpl-schema'; -import { ValidatedMethod } from 'meteor/mdg:validated-method'; -import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; -import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; -import { assertEditPermission } from '/imports/api/creature/creatures/creaturePermissions'; -import rollDice from '/imports/parser/rollDice'; -import numberToSignedString from '/imports/api/utility/numberToSignedString'; -import { getSingleProperty } from '/imports/api/engine/loadCreatures'; - -// TODO Migrate this to the new action engine - -const doCheck = new ValidatedMethod({ - name: 'creatureProperties.doCheck', - validate: new SimpleSchema({ - propId: SimpleSchema.RegEx.Id, - scope: { - type: Object, - blackbox: true, - }, - }).validator(), - mixins: [RateLimiterMixin], - rateLimit: { - numRequests: 10, - timeInterval: 5000, - }, - run({ propId, scope }) { - console.warn('do check not implemented'); - return; - const prop = CreatureProperties.findOne(propId); - if (!prop) throw new Meteor.Error('not-found', 'The property was not found'); - const creatureId = prop.root.id; - const actionContext = new ActionContext(creatureId, [creatureId], this); - Object.assign(actionContext.scope, scope); - actionContext.scope[`#${prop.type}`] = prop; - - // Check permissions - assertEditPermission(actionContext.creature, this.userId); - - // Do the check - doCheckWork({ prop, actionContext }); - }, -}); - -export default doCheck; - -export function doCheckWork({ prop, actionContext }) { - - applyTriggers(actionContext.triggers.check?.before, prop, actionContext); - rollCheck(prop, actionContext); - applyTriggers(actionContext.triggers.check?.after, prop, actionContext); - - // Insert the log - actionContext.writeLog(); -} - -function rollCheck(prop, actionContext) { - const scope = actionContext.scope; - // get the modifier for the roll - let rollModifier; - let logName = `${prop.name} check`; - if (prop.type === 'skill') { - rollModifier = prop.value; - if (prop.skillType === 'save') { - if (prop.name.match(/save/i)) { - logName = prop.name; - } else { - logName = prop.name ? `${prop.name} save` : 'Saving Throw'; - } - } - } else if (prop.type === 'attribute') { - if (prop.attributeType === 'ability') { - rollModifier = prop.modifier; - } else { - rollModifier = prop.value; - } - } else { - throw (`${prop.type} not supported for checks`); - } - - let rollModifierText = numberToSignedString(rollModifier, true); - - const { effectBonus, effectString } = applyUnresolvedEffects(prop, actionContext) - rollModifierText += effectString; - rollModifier += effectBonus; - - let value, values, resultPrefix; - if (scope['~checkAdvantage']?.value === 1) { - logName += ' (Advantage)'; - const [a, b] = rollDice(2, 20); - if (a >= b) { - value = a; - resultPrefix = `1d20 [ ${a}, ~~${b}~~ ] ${rollModifierText} = `; - } else { - value = b; - resultPrefix = `1d20 [ ~~${a}~~, ${b} ] ${rollModifierText} = `; - } - } else if (scope['~checkAdvantage']?.value === -1) { - logName += ' (Disadvantage)'; - const [a, b] = rollDice(2, 20); - if (a <= b) { - value = a; - resultPrefix = `1d20 [ ${a}, ~~${b}~~ ] ${rollModifierText} = `; - } else { - value = b; - resultPrefix = `1d20 [ ~~${a}~~, ${b} ] ${rollModifierText} = `; - } - } else { - values = rollDice(1, 20); - value = values[0]; - resultPrefix = `1d20 [ ${value} ] ${rollModifierText} = ` - } - const result = (value + rollModifier) || 0; - scope['~checkDiceRoll'] = { value }; - scope['~checkRoll'] = { value: result }; - scope['~checkModifier'] = { value: rollModifier }; - actionContext.addLog({ - name: logName, - value: `${resultPrefix} **${result}**`, - }); -} - -// TODO replace this with recalculating and then rolling/reducing the value node -export function applyUnresolvedEffects(prop, actionContext) { - let effectBonus = 0; - let effectString = ''; - if (!prop.effectIds) { - return { effectBonus, effectString }; - } - prop.effectIds.forEach(id => { - const effect = getSingleProperty(actionContext.creature._id, id); - if (!effect.amount?.parseNode) return; - if (effect.operation !== 'add') return; - recalculateCalculation(effect.amount, actionContext, undefined, 'reduce'); - if (typeof effect.amount?.value !== 'number') return; - effectBonus += effect.amount.value; - effectString += ` ${effect.amount.value < 0 ? '-' : '+'} [${effect.amount.calculation}] ${Math.abs(effect.amount.value)}` - }); - return { effectBonus, effectString }; -} diff --git a/app/imports/client/ui/components/RollPopup.vue b/app/imports/client/ui/components/RollPopup.vue deleted file mode 100644 index 0aaca754..00000000 --- a/app/imports/client/ui/components/RollPopup.vue +++ /dev/null @@ -1,122 +0,0 @@ - - - - - diff --git a/app/imports/client/ui/components/rolls/Check.vue b/app/imports/client/ui/components/rolls/Check.vue deleted file mode 100644 index 78500a7b..00000000 --- a/app/imports/client/ui/components/rolls/Check.vue +++ /dev/null @@ -1,99 +0,0 @@ - - - - - diff --git a/app/imports/client/ui/properties/components/attributes/AbilityListTile.vue b/app/imports/client/ui/properties/components/attributes/AbilityListTile.vue index ffb0df15..5732e261 100644 --- a/app/imports/client/ui/properties/components/attributes/AbilityListTile.vue +++ b/app/imports/client/ui/properties/components/attributes/AbilityListTile.vue @@ -7,16 +7,14 @@ class="ma-0" style="min-width: 40px;" > -
@@ -40,7 +38,7 @@
-
+ @@ -64,15 +62,11 @@