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] 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; }); }, },