From a5292cf0f2fb3808ab465bb308545b868f373b97 Mon Sep 17 00:00:00 2001 From: ThaumRystra <9525416+ThaumRystra@users.noreply.github.com> Date: Wed, 12 Jun 2024 15:43:56 +0200 Subject: [PATCH] Started fixing action target selection --- .../api/engine/action/EngineActions.ts | 2 +- .../engine/action/functions/applyAction.ts | 14 ++++ .../engine/action/functions/spendResources.ts | 1 + .../functions/userInput/InputProvider.ts | 4 ++ .../getReplayChoicesInputProvider.ts | 3 + .../userInput/inputProviderForTests.testFn.ts | 3 + .../action/tasks/applyItemAsAmmoTask.ts | 2 +- .../api/parenting/parentingFunctions.ts | 9 ++- .../ui/creature/actions/ActionDialog.vue | 16 ++++- .../client/ui/creature/actions/doAction.ts | 1 + .../creature/actions/input/TargetsInput.vue | 66 +++++++++++++++++++ .../ui/creature/creatureList/CreatureList.vue | 6 +- .../client/ui/tabletop/TabletopActionCard.vue | 1 + .../client/ui/tabletop/TabletopComponent.vue | 2 + .../ui/tabletop/TabletopCreatureCard.vue | 5 +- .../SelectedCreatureBar.vue | 15 ++++- .../server/publications/singleCharacter.js | 27 +++++++- 17 files changed, 162 insertions(+), 15 deletions(-) create mode 100644 app/imports/client/ui/creature/actions/input/TargetsInput.vue diff --git a/app/imports/api/engine/action/EngineActions.ts b/app/imports/api/engine/action/EngineActions.ts index cd8160a1..2a04350c 100644 --- a/app/imports/api/engine/action/EngineActions.ts +++ b/app/imports/api/engine/action/EngineActions.ts @@ -35,7 +35,7 @@ const ActionSchema = new SimpleSchema({ }, targetIds: { type: Array, - defaultValue: [], + optional: true, }, 'targetIds.$': { type: String, diff --git a/app/imports/api/engine/action/functions/applyAction.ts b/app/imports/api/engine/action/functions/applyAction.ts index 4d9bcb45..19128715 100644 --- a/app/imports/api/engine/action/functions/applyAction.ts +++ b/app/imports/api/engine/action/functions/applyAction.ts @@ -40,14 +40,28 @@ export default async function applyAction(action: EngineAction, userInput: Input action._isSimulation = simulate; action.taskCount = 0; let task = options?.task; + console.log('task', task, action.targetIds) if (!task) { const prop = await getSingleProperty(action.creatureId, action.rootPropId); if (!prop) throw new Meteor.Error('Not found', 'Root action property could not be found'); + + // If the target ids weren't already set, get them from the user + console.log(action.targetIds, prop); + if (!action.targetIds && ( + prop.target === 'singleTarget' || + prop.target === 'multipleTargets' + )) { + console.log('getting targetIds'); + action.targetIds = await (userInput.targetIds(prop.targets)); + console.log('got targetIds', action.targetIds); + } + task = { prop, targetIds: action.targetIds || [], } } + await applyTask(action, task, userInput); return action; } diff --git a/app/imports/api/engine/action/functions/spendResources.ts b/app/imports/api/engine/action/functions/spendResources.ts index b002d180..7879cba6 100644 --- a/app/imports/api/engine/action/functions/spendResources.ts +++ b/app/imports/api/engine/action/functions/spendResources.ts @@ -63,6 +63,7 @@ export default async function spendResources( !quantity || !isFinite(quantity) ) continue; + await applyTask(action, { prop, targetIds, diff --git a/app/imports/api/engine/action/functions/userInput/InputProvider.ts b/app/imports/api/engine/action/functions/userInput/InputProvider.ts index 87235fdf..9d564b7e 100644 --- a/app/imports/api/engine/action/functions/userInput/InputProvider.ts +++ b/app/imports/api/engine/action/functions/userInput/InputProvider.ts @@ -1,6 +1,10 @@ import Task from '/imports/api/engine/action/tasks/Task'; type InputProvider = { + /** + * Get the ids of the creatures being targeted + */ + targetIds(target: 'singleTarget' | 'multipleTargets', currentTargetIds?: string[]): Promise; /** * Show the user the next property or task to apply and wait for input to continue */ diff --git a/app/imports/api/engine/action/functions/userInput/getReplayChoicesInputProvider.ts b/app/imports/api/engine/action/functions/userInput/getReplayChoicesInputProvider.ts index de9fe161..ae6a706b 100644 --- a/app/imports/api/engine/action/functions/userInput/getReplayChoicesInputProvider.ts +++ b/app/imports/api/engine/action/functions/userInput/getReplayChoicesInputProvider.ts @@ -8,6 +8,9 @@ export default function getReplayChoicesInputProvider(actionId: string, decision const decisionStack = [...decisions].reverse(); const dRoller = getDeterministicDiceRoller(actionId); const replaySavedInput: InputProvider = { + targetIds() { + return Promise.resolve(decisionStack.pop()); + }, nextStep() { return Promise.resolve(); }, diff --git a/app/imports/api/engine/action/functions/userInput/inputProviderForTests.testFn.ts b/app/imports/api/engine/action/functions/userInput/inputProviderForTests.testFn.ts index 3067fb27..54a71378 100644 --- a/app/imports/api/engine/action/functions/userInput/inputProviderForTests.testFn.ts +++ b/app/imports/api/engine/action/functions/userInput/inputProviderForTests.testFn.ts @@ -1,6 +1,9 @@ import InputProvider from '/imports/api/engine/action/functions/userInput/InputProvider'; const inputProviderForTests: InputProvider = { + async targetIds(target, currentTargetIds = []) { + return currentTargetIds; + }, /** * For testing, randomness is hard to deal with * rollDice function returns the average roll for every dice rolled diff --git a/app/imports/api/engine/action/tasks/applyItemAsAmmoTask.ts b/app/imports/api/engine/action/tasks/applyItemAsAmmoTask.ts index fd57645b..51d69405 100644 --- a/app/imports/api/engine/action/tasks/applyItemAsAmmoTask.ts +++ b/app/imports/api/engine/action/tasks/applyItemAsAmmoTask.ts @@ -47,7 +47,7 @@ export default async function applyItemAsAmmoTask(task: ItemAsAmmoTask, action: type: 'item', }], // Log the item name as a heading if it has child properties to apply - ...itemChildren.length && { + ...itemChildren.length && !task.params.skipChildren && { contents: [{ name: getPropertyTitle(item) || 'Ammo', inline: false, diff --git a/app/imports/api/parenting/parentingFunctions.ts b/app/imports/api/parenting/parentingFunctions.ts index 81c31a1b..21856923 100644 --- a/app/imports/api/parenting/parentingFunctions.ts +++ b/app/imports/api/parenting/parentingFunctions.ts @@ -651,8 +651,12 @@ export function hasAncestorRelationship(propA: TreeDoc, propB: TreeDoc): boolean if (propA.root.id !== propB.root.id) { return false; } - // Return if there is an ancestor relationship in either direction - return isAncestor(propA, propB) || isAncestor(propB, propA); + // Return if there is an parent relationship in either direction + return propA.parentId === propB._id + || propB.parentId === propA._id + // or an ancestor relationship in either direction + || isAncestor(propA, propB) + || isAncestor(propB, propA); } /** @@ -856,4 +860,5 @@ function writeBulkOperations(collection: Mongo.Collection, operations) } }); } + return Promise.resolve(); } diff --git a/app/imports/client/ui/creature/actions/ActionDialog.vue b/app/imports/client/ui/creature/actions/ActionDialog.vue index 337bc13f..1e90f211 100644 --- a/app/imports/client/ui/creature/actions/ActionDialog.vue +++ b/app/imports/client/ui/creature/actions/ActionDialog.vue @@ -86,7 +86,8 @@ import ChoiceInput from '/imports/client/ui/creature/actions/input/ChoiceInput.v import DialogBase from '/imports/client/ui/dialogStack/DialogBase.vue'; import EngineActions from '/imports/api/engine/action/EngineActions'; import LogContent from '/imports/client/ui/log/LogContent.vue'; -import RollInput from '/imports/client/ui/creature/actions/input/RollInput.vue'; +//import RollInput from '/imports/client/ui/creature/actions/input/RollInput.vue'; +import TargetsInput from '/imports/client/ui/creature/actions/input/TargetsInput.vue'; export default { components: { @@ -95,7 +96,8 @@ export default { ChoiceInput, DialogBase, LogContent, - RollInput, + //RollInput, + TargetsInput, }, props: { actionId: { @@ -203,6 +205,16 @@ export default { this.$store.dispatch('popDialogStack'); }, // inputProvider methods + async targetIds(target) { + console.log('input provider UI targetIds') + this.userInput = []; + this.activeInputParams = { + target, + tabletopId: this.action.tabletopId, + }; + this.activeInput = 'targets-input' + return this.promiseInput(); + }, async rollDice(dice) { return Promise.resolve(this.deterministicDiceRoller(dice)); /* Dice Animation and user control goes here: diff --git a/app/imports/client/ui/creature/actions/doAction.ts b/app/imports/client/ui/creature/actions/doAction.ts index c07b3a48..16d3d7b8 100644 --- a/app/imports/client/ui/creature/actions/doAction.ts +++ b/app/imports/client/ui/creature/actions/doAction.ts @@ -79,6 +79,7 @@ const throwInputRequestedError = () => { function getErrorOnInputRequestProvider(actionId) { const errorOnInputRequest: InputProvider = { + targetIds: throwInputRequestedError, nextStep: throwInputRequestedError, rollDice: getDeterministicDiceRoller(actionId), choose: throwInputRequestedError, diff --git a/app/imports/client/ui/creature/actions/input/TargetsInput.vue b/app/imports/client/ui/creature/actions/input/TargetsInput.vue new file mode 100644 index 00000000..98124a2c --- /dev/null +++ b/app/imports/client/ui/creature/actions/input/TargetsInput.vue @@ -0,0 +1,66 @@ + + + \ No newline at end of file diff --git a/app/imports/client/ui/creature/creatureList/CreatureList.vue b/app/imports/client/ui/creature/creatureList/CreatureList.vue index 875b51c7..45420ad2 100644 --- a/app/imports/client/ui/creature/creatureList/CreatureList.vue +++ b/app/imports/client/ui/creature/creatureList/CreatureList.vue @@ -16,7 +16,7 @@ class="creature" :model="creature" :selection="selection" - :is-selected="selectedCreature === creature._id" + :is-selected="selectedCreature === creature._id || selectedCreatures.has(creature._id)" v-bind="selection ? {} : {to: creature.url}" :dense="dense" :data-id="dense ? undefined : creature._id" @@ -50,6 +50,10 @@ type: String, default: undefined, }, + selectedCreatures: { + type: Set, + default: () => new Set(), + }, dense: Boolean, }, data(){return { diff --git a/app/imports/client/ui/tabletop/TabletopActionCard.vue b/app/imports/client/ui/tabletop/TabletopActionCard.vue index bd4012d3..bb32390e 100644 --- a/app/imports/client/ui/tabletop/TabletopActionCard.vue +++ b/app/imports/client/ui/tabletop/TabletopActionCard.vue @@ -216,6 +216,7 @@ export default { }, doAction() { this.doActionLoading = true; + this.$emit('close-menu') doAction(this.model, this.$store, this.model._id).catch((e) => { console.error(e); snackbar({ text: e.message || e.reason || e.toString() }); diff --git a/app/imports/client/ui/tabletop/TabletopComponent.vue b/app/imports/client/ui/tabletop/TabletopComponent.vue index 9e9dff75..50ab3fa1 100644 --- a/app/imports/client/ui/tabletop/TabletopComponent.vue +++ b/app/imports/client/ui/tabletop/TabletopComponent.vue @@ -89,6 +89,7 @@ @@ -167,6 +168,7 @@ export default { }, moreTargets(){ const activeAction = CreatureProperties.findOne(this.activeActionId); + console.log(this.activeActionId, activeAction) if (!activeAction) return; if (activeAction.target === 'singleTarget') { return this.targets.length === 0; diff --git a/app/imports/client/ui/tabletop/TabletopCreatureCard.vue b/app/imports/client/ui/tabletop/TabletopCreatureCard.vue index bf64fb75..5048decd 100644 --- a/app/imports/client/ui/tabletop/TabletopCreatureCard.vue +++ b/app/imports/client/ui/tabletop/TabletopCreatureCard.vue @@ -1,6 +1,6 @@