Started removing old action engine methods

This commit is contained in:
ThaumRystra
2024-05-04 19:25:38 +02:00
parent c11013eddb
commit 9a6cb4b23f
10 changed files with 51 additions and 465 deletions

View File

@@ -4,7 +4,6 @@ import InputProvider from '/imports/api/engine/action/functions/userInput/InputP
import { applyDefaultAfterPropTasks } from '/imports/api/engine/action/functions/applyTaskGroups'; import { applyDefaultAfterPropTasks } from '/imports/api/engine/action/functions/applyTaskGroups';
import { getEffectiveActionScope } from '/imports/api/engine/action/functions/getEffectiveActionScope'; import { getEffectiveActionScope } from '/imports/api/engine/action/functions/getEffectiveActionScope';
import recalculateCalculation from '/imports/api/engine/action/functions/recalculateCalculation'; 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 { PropTask } from '/imports/api/engine/action/tasks/Task';
import TaskResult from '/imports/api/engine/action/tasks/TaskResult'; import TaskResult from '/imports/api/engine/action/tasks/TaskResult';
import { getVariables } from '/imports/api/engine/loadCreatures'; import { getVariables } from '/imports/api/engine/loadCreatures';
@@ -64,11 +63,8 @@ export default async function applySavingThrowProperty(
applyDefaultAfterPropTasks(action, prop, [targetId], inputProvider); applyDefaultAfterPropTasks(action, prop, [targetId], inputProvider);
} }
let rollModifierText = numberToSignedString(save.value, true); const rollModifierText = numberToSignedString(save.value, true);
let rollModifier = save.value const rollModifier = save.value;
const { effectBonus, effectString } = applyUnresolvedEffects(save, scope)
rollModifierText += effectString;
rollModifier += effectBonus;
let value, resultPrefix; let value, resultPrefix;
if (save.advantage === 1) { if (save.advantage === 1) {

View File

@@ -37,8 +37,8 @@ export type Advantage = 0 | 1 | -1;
export type CheckParams = { export type CheckParams = {
advantage: Advantage; advantage: Advantage;
skillVariableName: string; skillVariableName?: string;
abilityVariableName: string; abilityVariableName?: string;
dc: number | null; dc: number | null;
contest?: true; contest?: true;
targetSkillVariableName?: string; targetSkillVariableName?: string;

View File

@@ -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 };
}

View File

@@ -1,122 +0,0 @@
<template lang="html">
<div>
<v-menu
v-model="open"
origin="center center"
transition="scale-transition"
nudge-left="100px"
nudge-top="100px"
:close-on-content-click="false"
>
<template #activator="{ on }">
<v-btn
v-bind="$attrs"
:class="buttonClass"
v-on="noClick ? {} : on"
@click="e => { if (!noClick) e.stopPropagation(); }"
>
<slot />
</v-btn>
</template>
<v-sheet class="d-flex flex-column align-center justify-center">
<v-btn-toggle
v-model="dataAdvantage"
color="accent"
>
<v-btn :value="-1">
Disadvantage
</v-btn>
<v-btn :value="1">
Advantage
</v-btn>
</v-btn-toggle>
<div class="ma-1 text-subtitle-2">
{{ name }}
</div>
<div>
<v-scale-transition
origin="center center"
>
<vertical-hex
v-if="dataAdvantage"
style="position:absolute; transition: margin-left 0.3s ease;"
:style="{marginLeft: dataAdvantage == 1 ? '24px' : '-24px'}"
disable-hover
/>
</v-scale-transition>
<vertical-hex @click="roll">
<div>
Roll
</div>
<div v-if="rollText">
{{ rollText }}
</div>
</vertical-hex>
</div>
<v-btn
text
color="primary"
style="align-self: end"
@click="close"
>
Cancel
</v-btn>
</v-sheet>
</v-menu>
</div>
</template>
<script lang="js">
import VerticalHex from '/imports/client/ui/components/VerticalHex.vue';
export default {
components: {
VerticalHex
},
props: {
name: {
type: String,
default: undefined,
},
rollText: {
type: String,
default: undefined,
},
buttonClass: {
type: String,
default: undefined,
},
advantage: {
type: Number,
default: undefined,
},
noClick: Boolean,
},
data(){return {
open: false,
dataAdvantage: this.advantage,
}},
watch: {
advantage(val){
this.dataAdvantage = val;
},
open(val){
if(!val){
this.dataAdvantage = this.advantage;
}
},
},
methods: {
roll(){
this.$emit('roll', {advantage: this.dataAdvantage});
this.open = false;
},
close(){
this.open = false;
}
},
}
</script>
<style lang="css" scoped>
</style>

View File

@@ -1,99 +0,0 @@
<template lang="html">
<v-card>
<template v-if="!result">
<v-btn-toggle v-model="advantage">
<v-btn text>
Advantage
</v-btn>
<v-btn text>
Disadvantage
</v-btn>
</v-btn-toggle>
<v-card-text>
<div class="layout justify-center align-center">
<v-btn
large
fab
outlined
@click="makeRoll"
>
<div class="text-h4">
{{ numberToSignedString(bonus) }}
</div>
</v-btn>
</div>
</v-card-text>
</template>
<template v-else>
<div>
<div class="text-h6">
<span
v-for="(roll, index) of rolls"
:key="index"
class="roll"
:class="{strikethrough: index !== chosenRollIndex}"
>
{{ roll }}
</span>
<span class="ml-1">
{{ numberToSignedString(bonus) }}
</span>
</div>
<div class="text-h4">
{{ result }}
</div>
</div>
</template>
</v-card>
</template>
<script lang="js">
import numberToSignedString from '../../../../api/utility/numberToSignedString';
export default {
props: {
attributeVarName: {
type: String,
default: '',
},
attributeName: {
type: String,
default: '',
},
creatureId: {
type: String,
default: '',
},
bonus: {
type: Number,
required: true,
},
},
data(){return {
advantage: undefined,
result: undefined,
rolls: undefined,
chosenRoll: undefined,
chosenRollIndex: undefined,
}},
methods: {
makeRoll(){
//let {rolls, bonus, chosenRoll, result} = doCheckWork.call();
this.rolls = [12, 8];
if (this.advantage === 1){
this.chosenRoll = 8;
} else {
this.chosenRoll = 12;
}
this.result = this.chosenRoll + this.bonus;
this.chosenRollIndex = this.rolls.indexOf(this.chosenRoll);
},
numberToSignedString,
}
}
</script>
<style lang="css" scoped>
.strikethrough {
text-decoration: line-through;
}
</style>

View File

@@ -7,16 +7,14 @@
class="ma-0" class="ma-0"
style="min-width: 40px;" style="min-width: 40px;"
> >
<roll-popup <v-btn
button-class="mr-4 py-2" class="mr-4 py-2"
text text
height="82" height="82"
:roll-text="numberToSignedString(model.modifier)" :data-id="`check-btn-${model._id}`"
:name="model.name"
:advantage="model.advantage"
:loading="checkLoading" :loading="checkLoading"
:disabled="!context.editPermission" :disabled="!context.editPermission"
@roll="check" @click.stop="check"
> >
<div> <div>
<div class="text-h4 mod"> <div class="text-h4 mod">
@@ -40,7 +38,7 @@
</template> </template>
</div> </div>
</div> </div>
</roll-popup> </v-btn>
</v-list-item-action> </v-list-item-action>
<v-list-item-content> <v-list-item-content>
@@ -64,15 +62,11 @@
</template> </template>
<script lang="js"> <script lang="js">
import doCheck from '/imports/api/engine/action/methods/doCheck';
import numberToSignedString from '/imports/api/utility/numberToSignedString'; import numberToSignedString from '/imports/api/utility/numberToSignedString';
import RollPopup from '/imports/client/ui/components/RollPopup.vue';
import { snackbar } from '/imports/client/ui/components/snackbars/SnackbarQueue'; import { snackbar } from '/imports/client/ui/components/snackbars/SnackbarQueue';
import doAction from '/imports/client/ui/creature/actions/doAction';
export default { export default {
components: {
RollPopup,
},
inject: { inject: {
context: { context: {
default: {}, default: {},
@@ -96,19 +90,21 @@ export default {
click(e) { click(e) {
this.$emit('click', e); this.$emit('click', e);
}, },
check({ advantage }) { check() {
this.checkLoading = true; this.checkLoading = true;
doCheck.call({ doAction(this.model, this.$store, `check-btn-${this.model._id}`, {
propId: this.model._id, subtaskFn: 'check',
scope: { prop: this.model,
'~checkAdvantage': { value: advantage }, targetIds: [this.model.root.id],
}, advantage: this.model.advantage,
}, error => { skillVariableName: undefined,
abilityVariableName: this.model.variableName,
dc: null,
}).catch(error => {
snackbar({ text: error.reason || error.message || error.toString() });
console.error(error);
}).finally(() => {
this.checkLoading = false; this.checkLoading = false;
if (error) {
console.error(error);
snackbar({ text: error.reason });
}
}); });
}, },
}, },
@@ -153,4 +149,3 @@ export default {
min-width: 42px; min-width: 42px;
} }
</style> </style>
../../../../../api/engine/action/methods/doCheck

View File

@@ -5,23 +5,20 @@
@mouseover="$emit('mouseover')" @mouseover="$emit('mouseover')"
@mouseleave="$emit('mouseleave')" @mouseleave="$emit('mouseleave')"
> >
<roll-popup <v-btn
v-if="model.attributeType === 'modifier' || model.type === 'skill'" v-if="model.attributeType === 'modifier' || model.type === 'skill'"
button-class="px-0" class="px-0"
text text
height="70" height="70"
min-width="72" min-width="72"
:roll-text="computedValue && computedValue.toString()"
:name="model.name"
:advantage="model.advantage"
:loading="checkLoading" :loading="checkLoading"
:disabled="!context.editPermission" :disabled="!context.editPermission"
@roll="check" @click.stop="check"
> >
<v-card-title class="value text-h4 flex-shrink-0"> <v-card-title class="value text-h4 flex-shrink-0">
{{ computedValue }} {{ computedValue }}
</v-card-title> </v-card-title>
</roll-popup> </v-btn>
<v-card-title <v-card-title
v-else v-else
class="value text-h4 flex-shrink-0" class="value text-h4 flex-shrink-0"
@@ -47,15 +44,11 @@
</template> </template>
<script lang="js"> <script lang="js">
import RollPopup from '/imports/client/ui/components/RollPopup.vue';
import doCheck from '/imports/api/engine/action/methods/doCheck.js';
import {snackbar} from '/imports/client/ui/components/snackbars/SnackbarQueue'; import {snackbar} from '/imports/client/ui/components/snackbars/SnackbarQueue';
import numberToSignedString from '/imports/api/utility/numberToSignedString'; import numberToSignedString from '/imports/api/utility/numberToSignedString';
import doAction from '/imports/client/ui/creature/actions/doAction';
export default { export default {
components: {
RollPopup,
},
inject: { inject: {
context: { context: {
default: {}, default: {},
@@ -82,19 +75,21 @@ export default {
}, },
methods: { methods: {
signed: numberToSignedString, signed: numberToSignedString,
check({advantage}){ check(){
this.checkLoading = true; this.checkLoading = true;
doCheck.call({ doAction(this.model, this.$store, `check-btn-${this.model._id}`, {
propId: this.model._id, subtaskFn: 'check',
scope: { prop: this.model,
'~checkAdvantage': { value: advantage }, targetIds: [this.model.root.id],
}, advantage: this.model.advantage,
}, error => { skillVariableName: this.model.variableName,
abilityVariableName: this.model.ability,
dc: null,
}).catch(error => {
snackbar({ text: error.reason || error.message || error.toString() });
console.error(error);
}).finally(() => {
this.checkLoading = false; this.checkLoading = false;
if (error){
console.error(error);
snackbar({text: error.reason});
}
}); });
}, },
}, },
@@ -106,4 +101,4 @@ export default {
min-width: 72px; min-width: 72px;
justify-content: center; justify-content: center;
} }
</style>../../../../../api/engine/action/methods/doCheck </style>

View File

@@ -10,6 +10,7 @@
v-if="!hideModifier" v-if="!hideModifier"
text text
tile tile
:loading="checkLoading"
:disabled="!context.editPermission" :disabled="!context.editPermission"
:data-id="`check-btn-${model._id}`" :data-id="`check-btn-${model._id}`"
class="pl-3 pr-2 prof-mod mr-1 flex-shrink-0" class="pl-3 pr-2 prof-mod mr-1 flex-shrink-0"
@@ -58,6 +59,7 @@
import ProficiencyIcon from '/imports/client/ui/properties/shared/ProficiencyIcon.vue'; import ProficiencyIcon from '/imports/client/ui/properties/shared/ProficiencyIcon.vue';
import numberToSignedString from '/imports/api/utility/numberToSignedString'; import numberToSignedString from '/imports/api/utility/numberToSignedString';
import doAction from '/imports/client/ui/creature/actions/doAction'; import doAction from '/imports/client/ui/creature/actions/doAction';
import { snackbar } from '/imports/client/ui/components/snackbars/SnackbarQueue';
export default { export default {
components: { components: {
@@ -101,6 +103,7 @@ export default {
this.$emit('click', e); this.$emit('click', e);
}, },
check() { check() {
this.checkLoading = true;
doAction(this.model, this.$store, `check-btn-${this.model._id}`, { doAction(this.model, this.$store, `check-btn-${this.model._id}`, {
subtaskFn: 'check', subtaskFn: 'check',
prop: this.model, prop: this.model,
@@ -109,9 +112,12 @@ export default {
skillVariableName: this.model.variableName, skillVariableName: this.model.variableName,
abilityVariableName: this.model.ability, abilityVariableName: this.model.ability,
dc: null, dc: null,
}).catch(e => { }).catch(error => {
console.error(e); snackbar({ text: error.reason || error.message || error.toString() });
}) console.error(error);
}).finally(() => {
this.checkLoading = false;
});
}, },
} }
} }

View File

@@ -159,20 +159,7 @@
> >
Cancel Cancel
</v-btn> </v-btn>
<roll-popup
v-if="selectedSpell && selectedSpell.attackRoll"
text
color="primary"
class="mx-2"
:disabled="!canCast"
:name="selectedSpell.name"
:advantage="selectedSpell.attackRoll && selectedSpell.attackRoll.advantage"
@roll="cast"
>
Cast
</roll-popup>
<v-btn <v-btn
v-else
text text
:disabled="!canCast" :disabled="!canCast"
class="mx-2 px-4" class="mx-2 px-4"
@@ -192,7 +179,6 @@ import CreatureProperties from '/imports/api/creature/creatureProperties/Creatur
import spellsWithSubheaders from '/imports/client/ui/properties/components/spells/spellsWithSubheaders'; import spellsWithSubheaders from '/imports/client/ui/properties/components/spells/spellsWithSubheaders';
import SpellSlotListTile from '/imports/client/ui/properties/components/attributes/SpellSlotListTile.vue'; import SpellSlotListTile from '/imports/client/ui/properties/components/attributes/SpellSlotListTile.vue';
import SpellListTile from '/imports/client/ui/properties/components/spells/SpellListTile.vue'; import SpellListTile from '/imports/client/ui/properties/components/spells/SpellListTile.vue';
import RollPopup from '/imports/client/ui/components/RollPopup.vue';
import { find } from 'lodash'; import { find } from 'lodash';
const slotFilter = { const slotFilter = {
@@ -207,7 +193,6 @@ const slotFilter = {
export default { export default {
components: { components: {
DialogBase, DialogBase,
RollPopup,
SplitListLayout, SplitListLayout,
SpellSlotListTile, SpellSlotListTile,
SpellListTile, SpellListTile,

View File

@@ -10,36 +10,7 @@
class="avatar" class="avatar"
:style="{ opacity: active ? '' : '0.5'}" :style="{ opacity: active ? '' : '0.5'}"
> >
<roll-popup
v-if="rollBonus"
:icon="!active"
:outlined="!active"
:fab="active"
style="letter-spacing: normal;"
class="mr-2"
:no-click="!active"
:style="{
fontSize: active ? '24px' : '16px'
}"
:large="active"
:color="model.color || 'primary'"
:loading="doActionLoading"
:disabled="model.insufficientResources || !context.editPermission || !!targetingError"
:roll-text="rollBonus"
:name="model.name"
:advantage="model.attackRoll && model.attackRoll.advantage"
@roll="doAction"
>
<template v-if="rollBonus && !rollBonusTooLong">
{{ rollBonus }}
</template>
<property-icon
v-else
:model="model"
/>
</roll-popup>
<v-btn <v-btn
v-else
:icon="!active" :icon="!active"
:outlined="!active" :outlined="!active"
:fab="active" :fab="active"
@@ -157,7 +128,6 @@ import numberToSignedString from '/imports/api/utility/numberToSignedString.js';
import AttributeConsumedView from '/imports/client/ui/properties/components/actions/AttributeConsumedView.vue'; import AttributeConsumedView from '/imports/client/ui/properties/components/actions/AttributeConsumedView.vue';
import ItemConsumedView from '/imports/client/ui/properties/components/actions/ItemConsumedView.vue'; import ItemConsumedView from '/imports/client/ui/properties/components/actions/ItemConsumedView.vue';
import PropertyIcon from '/imports/client/ui/properties/shared/PropertyIcon.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 MarkdownText from '/imports/client/ui/components/MarkdownText.vue';
import { snackbar } from '/imports/client/ui/components/snackbars/SnackbarQueue.js'; import { snackbar } from '/imports/client/ui/components/snackbars/SnackbarQueue.js';
import CardHighlight from '/imports/client/ui/components/CardHighlight.vue'; import CardHighlight from '/imports/client/ui/components/CardHighlight.vue';
@@ -172,7 +142,6 @@ export default {
ItemConsumedView, ItemConsumedView,
MarkdownText, MarkdownText,
PropertyIcon, PropertyIcon,
RollPopup,
CardHighlight, CardHighlight,
TreeNodeList, TreeNodeList,
}, },