Implemented checks at least back to 2.0 functionality in new action engine
This commit is contained in:
@@ -266,7 +266,7 @@ function allLogContent(action: EngineAction) {
|
||||
|
||||
let note1Id, folderId, ifTruthyBranchId, ifFalsyBranchId, indexBranchId, choiceBranchId,
|
||||
adjustedStatId, adjustmentIncrementId, adjustmentSetId, rollId, buffId,
|
||||
removeParentBuffId, removeTaggedBuffsId, removeOneTaggedBuffId, taggedBuffId, secondTaggedBuffId, buffAttChildId;
|
||||
removeParentBuffId, removeTaggedBuffsId, removeOneTaggedBuffId, taggedBuffId, secondTaggedBuffId;
|
||||
|
||||
const propForest = [
|
||||
// Apply a simple note
|
||||
@@ -363,7 +363,7 @@ const propForest = [
|
||||
target: 'self',
|
||||
children: [
|
||||
{
|
||||
_id: buffAttChildId = Random.id(),
|
||||
_id: Random.id(),
|
||||
type: 'attribute',
|
||||
attributeType: 'stat',
|
||||
variableName: 'buffStat',
|
||||
|
||||
@@ -10,7 +10,7 @@ import { applyAfterChildrenTriggers, applyAfterTriggers, applyChildren } from '/
|
||||
import recalculateCalculation from '/imports/api/engine/action/functions/recalculateCalculation';
|
||||
import { getEffectiveActionScope } from '/imports/api/engine/action/functions/getEffectiveActionScope';
|
||||
import numberToSignedString from '/imports/api/utility/numberToSignedString';
|
||||
import { getConstantValueFromScope, getNumberFromScope } from '/imports/api/creature/creatures/CreatureVariables';
|
||||
import { getNumberFromScope } from '/imports/api/creature/creatures/CreatureVariables';
|
||||
import InputProvider from '/imports/api/engine/action/functions/userInput/InputProvider';
|
||||
import { CalculatedField } from '/imports/api/properties/subSchemas/computedField';
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ export default async function applyAction(action: EngineAction, userInput: Input
|
||||
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');
|
||||
task = options?.task || {
|
||||
task = {
|
||||
prop,
|
||||
targetIds: action.targetIds || [],
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ type InputProvider = {
|
||||
/**
|
||||
* Get the details of a check or save
|
||||
*/
|
||||
//check(suggestedParams: CheckParams): Promise<CheckParams>;
|
||||
check(suggestedParams: CheckParams): Promise<CheckParams>;
|
||||
}
|
||||
|
||||
export type Advantage = 0 | 1 | -1;
|
||||
|
||||
@@ -5,6 +5,7 @@ import getDeterministicDiceRoller from '/imports/api/engine/action/functions/use
|
||||
// Dice rolls are done fresh, no cheating
|
||||
export default function getReplayChoicesInputProvider(actionId: string, decisions: any[]):
|
||||
InputProvider {
|
||||
const decisionStack = [...decisions].reverse();
|
||||
const dRoller = getDeterministicDiceRoller(actionId);
|
||||
const replaySavedInput: InputProvider = {
|
||||
nextStep() {
|
||||
@@ -12,15 +13,18 @@ export default function getReplayChoicesInputProvider(actionId: string, decision
|
||||
},
|
||||
// To roll dice, ignore the user and use the deterministic dice roller again
|
||||
rollDice(dice) {
|
||||
decisions.pop();
|
||||
decisionStack.pop();
|
||||
return dRoller(dice);
|
||||
},
|
||||
choose() {
|
||||
return Promise.resolve(decisions.pop());
|
||||
return Promise.resolve(decisionStack.pop());
|
||||
},
|
||||
advantage() {
|
||||
return Promise.resolve(decisions.pop());
|
||||
}
|
||||
return Promise.resolve(decisionStack.pop());
|
||||
},
|
||||
check() {
|
||||
return Promise.resolve(decisionStack.pop());
|
||||
},
|
||||
}
|
||||
return replaySavedInput;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,9 @@ const inputProviderForTests: InputProvider = {
|
||||
*/
|
||||
async advantage(suggestedAdvantage) {
|
||||
return suggestedAdvantage;
|
||||
},
|
||||
async check(suggestedParams) {
|
||||
return suggestedParams;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,9 @@ export default function saveInputChoices(action: EngineAction, userInput: InputP
|
||||
for (const key in userInput) {
|
||||
const oldFn = userInput[key];
|
||||
// Make a new function that does the same thing, but saves the result to action._decisions
|
||||
const newFn = (...args) => {
|
||||
const result = oldFn(...args);
|
||||
action._decisions.push(result);
|
||||
const newFn = async (...args) => {
|
||||
const result = await oldFn(...args);
|
||||
action._decisions?.push(result);
|
||||
return result;
|
||||
}
|
||||
newInputProvider[key] = newFn;
|
||||
|
||||
@@ -6,23 +6,12 @@ import { getCreature } from '/imports/api/engine/loadCreatures';
|
||||
import applyAction from '/imports/api/engine/action/functions/applyAction';
|
||||
import writeActionResults from '../functions/writeActionResults';
|
||||
import getReplayChoicesInputProvider from '/imports/api/engine/action/functions/userInput/getReplayChoicesInputProvider';
|
||||
import Task from '/imports/api/engine/action/tasks/Task';
|
||||
|
||||
export const runAction = new ValidatedMethod({
|
||||
name: 'actions.runAction',
|
||||
validate: new SimpleSchema({
|
||||
actionId: {
|
||||
type: String,
|
||||
},
|
||||
decisions: {
|
||||
type: Array,
|
||||
optional: true,
|
||||
},
|
||||
'decisions.$': {
|
||||
type: Object,
|
||||
blackbox: true,
|
||||
},
|
||||
}).validator(),
|
||||
run: async function ({ actionId, decisions = [] }: { actionId: string, decisions?: any[] }) {
|
||||
validate: null, //TODO validate this
|
||||
run: async function ({ actionId, decisions = [], task }: { actionId: string, decisions?: any[], task?: Task }) {
|
||||
// Get the action
|
||||
const action = await EngineActions.findOneAsync(actionId);
|
||||
if (!action) throw new Meteor.Error('not-found', 'Action not found');
|
||||
@@ -34,7 +23,7 @@ export const runAction = new ValidatedMethod({
|
||||
const userInput = getReplayChoicesInputProvider(actionId, decisions);
|
||||
|
||||
// Apply the action
|
||||
applyAction(action, userInput);
|
||||
await applyAction(action, userInput, { task });
|
||||
|
||||
// Persist changes
|
||||
const writePromise = writeActionResults(action);
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
type Task = PropTask | DamagePropTask | ItemAsAmmoTask;
|
||||
import { CheckParams } from '/imports/api/engine/action/functions/userInput/InputProvider';
|
||||
|
||||
type Task = PropTask | DamagePropTask | ItemAsAmmoTask | CheckTask;
|
||||
|
||||
export default Task;
|
||||
|
||||
interface BaseTask {
|
||||
type BaseTask = {
|
||||
prop: { [key: string]: any };
|
||||
targetIds: string[];
|
||||
}
|
||||
|
||||
export interface PropTask extends BaseTask {
|
||||
export type PropTask = BaseTask & {
|
||||
subtaskFn?: undefined,
|
||||
}
|
||||
|
||||
export interface DamagePropTask extends BaseTask {
|
||||
export type DamagePropTask = BaseTask & {
|
||||
subtaskFn: 'damageProp';
|
||||
params: {
|
||||
/**
|
||||
@@ -24,10 +26,14 @@ export interface DamagePropTask extends BaseTask {
|
||||
};
|
||||
}
|
||||
|
||||
export interface ItemAsAmmoTask extends BaseTask {
|
||||
export type ItemAsAmmoTask = BaseTask & {
|
||||
subtaskFn: 'consumeItemAsAmmo';
|
||||
params: {
|
||||
value: number;
|
||||
item: any;
|
||||
};
|
||||
}
|
||||
|
||||
export type CheckTask = BaseTask & CheckParams & {
|
||||
subtaskFn: 'check';
|
||||
}
|
||||
|
||||
@@ -1,50 +1,115 @@
|
||||
import { getFromScope } from '/imports/api/creature/creatures/CreatureVariables';
|
||||
import { EngineAction } from '/imports/api/engine/action/EngineActions';
|
||||
import InputProvider, { CheckParams } from '/imports/api/engine/action/functions/userInput/InputProvider';
|
||||
import { applyDefaultAfterPropTasks } from '/imports/api/engine/action/functions/applyTaskGroups';
|
||||
import { CheckTask } from '/imports/api/engine/action/tasks/Task';
|
||||
import { EngineAction } from '/imports/api/engine/action/EngineActions';
|
||||
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 { getFromScope } from '/imports/api/creature/creatures/CreatureVariables';
|
||||
import { getVariables } from '/imports/api/engine/loadCreatures';
|
||||
import InputProvider, { CheckParams } from '/imports/api/engine/action/functions/userInput/InputProvider';
|
||||
import numberToSignedString from '/imports/api/utility/numberToSignedString';
|
||||
import { isFiniteNode } from '/imports/parser/parseTree/constant';
|
||||
import TaskResult from '/imports/api/engine/action/tasks/TaskResult';
|
||||
|
||||
// TODO implement this
|
||||
/**
|
||||
* A skill property is applied as a check or a saving throw
|
||||
*/
|
||||
export default async function applyCheckTask(
|
||||
task: PropTask, action: EngineAction, result: TaskResult, inputProvider: InputProvider
|
||||
task: CheckTask, action: EngineAction, result: TaskResult, userInput: InputProvider
|
||||
): Promise<void> {
|
||||
|
||||
throw new Meteor.Error('Not implemented', 'This function needs to be implemented');
|
||||
|
||||
const prop = task.prop;
|
||||
const targetIds = task.targetIds;
|
||||
if (targetIds?.length) {
|
||||
throw new Meteor.Error('too-many-targets',
|
||||
'This function is only implemented for zero targets');
|
||||
|
||||
if (task.contest) {
|
||||
throw new Meteor.Error('not-implemented', 'This functionality is not implemented yet');
|
||||
}
|
||||
|
||||
let checkParams: CheckParams = {
|
||||
advantage: 0,
|
||||
skillVariableName: prop.variableName,
|
||||
abilityVariableName: prop.ability,
|
||||
dc: null,
|
||||
for (const targetId of targetIds) {
|
||||
let scope;
|
||||
if (targetId === action.creatureId) {
|
||||
scope = await getEffectiveActionScope(action);
|
||||
} else {
|
||||
scope = getVariables(targetId);
|
||||
}
|
||||
// Get the updated parameters from user input
|
||||
const checkParams = await userInput.check(task);
|
||||
const advantage = checkParams.advantage;
|
||||
|
||||
const skill = checkParams.skillVariableName && getFromScope(checkParams.skillVariableName, scope) || null;
|
||||
const skillBonus = (skill?.value || 0) - (skill?.abilityMod || 0);
|
||||
|
||||
const ability = checkParams.abilityVariableName && getFromScope(checkParams.abilityVariableName, scope) || null;
|
||||
const abilityModifier = ability?.modifier || 0;
|
||||
|
||||
const totalModifier = skillBonus + abilityModifier;
|
||||
const rollModifierText = numberToSignedString(totalModifier);
|
||||
|
||||
// Get the name of the check
|
||||
let checkName = 'Check';
|
||||
if (ability?.name && skill?.name) {
|
||||
checkName = `${ability.name} (${skill.name})`
|
||||
} else if (ability?.name || skill?.name) {
|
||||
checkName = `${ability?.name || skill?.name}`;
|
||||
}
|
||||
|
||||
checkParams = await inputProvider.check(checkParams);
|
||||
let rollName = 'Roll'
|
||||
|
||||
// Append advantage/disadvantage to the check name
|
||||
if (advantage === 1) {
|
||||
rollName += ' (Advantage)'
|
||||
} else if (advantage === -1) {
|
||||
rollName += ' (Disadvantage)'
|
||||
}
|
||||
|
||||
// Print check name and DC if present
|
||||
const dc = checkParams.dc;
|
||||
if (!prop.silent && dc !== null) result.appendLog({
|
||||
name: prop.name,
|
||||
value: `DC **${dc}**`,
|
||||
result.appendLog({
|
||||
name: checkName,
|
||||
inline: true,
|
||||
...prop.silent && { silenced: prop.silent }
|
||||
}, targetIds);
|
||||
const scope = await getEffectiveActionScope(action);
|
||||
...dc !== null && { value: `DC **${dc}**` },
|
||||
...prop?.silent && { silenced: prop.silent }
|
||||
}, [targetId]);
|
||||
|
||||
return applyDefaultAfterPropTasks(action, prop, targetIds, inputProvider);
|
||||
// Roll the dice
|
||||
let rolledValue, resultPrefix;
|
||||
if (advantage === 1) {
|
||||
const [[a, b]] = await userInput.rollDice([{ number: 2, diceSize: 20 }]);
|
||||
if (a >= b) {
|
||||
rolledValue = a;
|
||||
resultPrefix = `1d20 [ ${a}, ~~${b}~~ ] ${rollModifierText}`;
|
||||
} else {
|
||||
rolledValue = b;
|
||||
resultPrefix = `1d20 [ ~~${a}~~, ${b} ] ${rollModifierText}`;
|
||||
}
|
||||
} else if (advantage === -1) {
|
||||
const [[a, b]] = await userInput.rollDice([{ number: 2, diceSize: 20 }]);
|
||||
if (a <= b) {
|
||||
rolledValue = a;
|
||||
resultPrefix = `1d20 [ ${a}, ~~${b}~~ ] ${rollModifierText}`;
|
||||
} else {
|
||||
rolledValue = b;
|
||||
resultPrefix = `1d20 [ ~~${a}~~, ${b} ] ${rollModifierText}`;
|
||||
}
|
||||
} else {
|
||||
[[rolledValue]] = await userInput.rollDice([{ number: 1, diceSize: 20 }]);
|
||||
resultPrefix = `1d20 [${rolledValue}] ${rollModifierText}`
|
||||
}
|
||||
|
||||
const totalValue = rolledValue + totalModifier;
|
||||
|
||||
result.appendLog({
|
||||
name: rollName,
|
||||
value: `${resultPrefix}\n**${totalValue}**`,
|
||||
inline: true,
|
||||
...prop?.silent && { silenced: prop.silent }
|
||||
}, [targetId]);
|
||||
}
|
||||
|
||||
return applyDefaultAfterPropTasks(action, prop, targetIds, userInput);
|
||||
}
|
||||
|
||||
// TODO set these and potentially read them again if triggers can change them
|
||||
/*
|
||||
'~checkAdvantage'
|
||||
'~checkAdvantage'
|
||||
'~checkDiceRoll'
|
||||
'~checkRoll'
|
||||
'~checkModifier'
|
||||
*/
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { EngineAction } from '/imports/api/engine/action/EngineActions';
|
||||
import Task, { DamagePropTask, ItemAsAmmoTask, PropTask } from './Task';
|
||||
import Task, { CheckTask, DamagePropTask, ItemAsAmmoTask, PropTask } from './Task';
|
||||
import TaskResult from '/imports/api/engine/action/tasks/TaskResult';
|
||||
import applyDamagePropTask from '/imports/api/engine/action/tasks/applyDamagePropTask';
|
||||
import applyItemAsAmmoTask from '/imports/api/engine/action/tasks/applyItemAsAmmoTask';
|
||||
import { getSingleProperty } from '/imports/api/engine/loadCreatures';
|
||||
import applyProperties from '/imports/api/engine/action/applyProperties';
|
||||
import InputProvider from '/imports/api/engine/action/functions/userInput/InputProvider';
|
||||
import applyCheckTask from '/imports/api/engine/action/tasks/applyCheckTask';
|
||||
|
||||
// DamagePropTask promises a number of actual damage done
|
||||
export default async function applyTask(
|
||||
@@ -14,7 +15,7 @@ export default async function applyTask(
|
||||
|
||||
// Other tasks promise nothing
|
||||
export default async function applyTask(
|
||||
action: EngineAction, task: PropTask | ItemAsAmmoTask, inputProvider: InputProvider
|
||||
action: EngineAction, task: PropTask | ItemAsAmmoTask | CheckTask, inputProvider: InputProvider
|
||||
): Promise<void>
|
||||
|
||||
export default async function applyTask(
|
||||
@@ -42,6 +43,8 @@ export default async function applyTask(
|
||||
return applyDamagePropTask(task, action, result, inputProvider);
|
||||
case 'consumeItemAsAmmo':
|
||||
return applyItemAsAmmoTask(task, action, result, inputProvider);
|
||||
case 'check':
|
||||
return applyCheckTask(task, action, result, inputProvider);
|
||||
}
|
||||
} else {
|
||||
// Get property
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ValidatedMethod } from 'meteor/mdg:validated-method';
|
||||
import { RateLimiterMixin } from 'ddp-rate-limiter-mixin';
|
||||
import ArchiveCreatureFiles from '/imports/api/creature/archive/ArchiveCreatureFiles';
|
||||
import UserImages from '/imports/api/files/UserImages';
|
||||
import UserImages from '/imports/api/files/userImages/UserImages';
|
||||
const fileCollections = [ArchiveCreatureFiles, UserImages];
|
||||
|
||||
const updateFileStorageUsed = new ValidatedMethod({
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
import UserImages from '/imports/api/files/UserImages';
|
||||
import UserImages from '/imports/api/files/userImages/UserImages';
|
||||
|
||||
export default {
|
||||
data(){return {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
// Modified from https://gitlab.com/tozd/vue/snackbar-que
|
||||
import Vue from 'vue';
|
||||
|
||||
const globalState = Vue.observable({queue: []});
|
||||
const globalState = Vue.observable({ queue: [] });
|
||||
let lastSnackbarId = 0;
|
||||
|
||||
function snackbar(data) {
|
||||
console.log(data);
|
||||
globalState.queue.push({
|
||||
data, //{text OR content, callback, callbackName} // content is logContent
|
||||
id: ++lastSnackbarId,
|
||||
@@ -13,4 +14,4 @@ function snackbar(data) {
|
||||
});
|
||||
}
|
||||
|
||||
export {snackbar, globalState}
|
||||
export { snackbar, globalState }
|
||||
|
||||
@@ -56,6 +56,7 @@ import DialogBase from '/imports/client/ui/dialogStack/DialogBase.vue';
|
||||
import EngineActions from '/imports/api/engine/action/EngineActions';
|
||||
import applyAction from '/imports/api/engine/action/functions/applyAction';
|
||||
import AdvantageInput from '/imports/client/ui/creature/actions/input/AdvantageInput.vue';
|
||||
import CheckInput from '/imports/client/ui/creature/actions/input/CheckInput.vue';
|
||||
import RollInput from '/imports/client/ui/creature/actions/input/RollInput.vue';
|
||||
import getDeterministicDiceRoller from '/imports/api/engine/action/functions/userInput/getDeterministicDiceRoller';
|
||||
import LogContent from '/imports/client/ui/log/LogContent.vue';
|
||||
@@ -64,6 +65,7 @@ export default {
|
||||
components: {
|
||||
DialogBase,
|
||||
AdvantageInput,
|
||||
CheckInput,
|
||||
RollInput,
|
||||
LogContent,
|
||||
},
|
||||
@@ -72,6 +74,10 @@ export default {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
task: {
|
||||
type: Object,
|
||||
default: undefined,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -111,11 +117,6 @@ export default {
|
||||
return EngineActions.findOne(this.actionId);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
resultAction(val) {
|
||||
console.log(val);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.deterministicDiceRoller = getDeterministicDiceRoller(this.actionId);
|
||||
this.startAction({ stepThrough: false });
|
||||
@@ -130,9 +131,8 @@ export default {
|
||||
taskCount: undefined,
|
||||
};
|
||||
applyAction(
|
||||
this.actionResult, this, { simulate: true, stepThrough }
|
||||
this.actionResult, this, { simulate: true, stepThrough, task: this.task}
|
||||
).then(() => {
|
||||
console.log('action is done');
|
||||
this.actionDone = true
|
||||
});
|
||||
},
|
||||
@@ -172,7 +172,6 @@ export default {
|
||||
},
|
||||
// inputProvider methods
|
||||
async rollDice(dice) {
|
||||
console.log('Waiting for dice roll');
|
||||
this.activeInputParams = {
|
||||
deterministicDiceRoller: this.deterministicDiceRoller,
|
||||
dice
|
||||
@@ -181,25 +180,20 @@ export default {
|
||||
return this.promiseInput();
|
||||
},
|
||||
async nextStep(task) {
|
||||
console.log('waiting for next step');
|
||||
console.log({ task });
|
||||
return this.promiseInput();
|
||||
},
|
||||
async choose(choices, quantity) {
|
||||
console.log('Waiting for choice');
|
||||
console.log({choices, quantity});
|
||||
return this.promiseInput();
|
||||
},
|
||||
async advantage(suggestedAdvantage) {
|
||||
console.log('Waiting for advantage');
|
||||
this.userInput = suggestedAdvantage;
|
||||
this.activeInput = 'advantage-input';
|
||||
this.userInputReady = true;
|
||||
return this.promiseInput();
|
||||
},
|
||||
async check(suggestedParams) {
|
||||
console.log('Waiting for check');
|
||||
console.log({ suggestedParams })
|
||||
this.userInput = suggestedParams;
|
||||
this.activeInput = 'check-input';
|
||||
return this.promiseInput();
|
||||
},
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ export default async function doAction(
|
||||
const finishedAction = await applyAction(
|
||||
action, errorOnInputRequest, { simulate: true, task }
|
||||
);
|
||||
return callActionMethod(finishedAction);
|
||||
return callActionMethod(finishedAction, task);
|
||||
} catch (e) {
|
||||
if (e !== 'input-requested') throw e;
|
||||
return new Promise(resolve => {
|
||||
@@ -55,18 +55,21 @@ export default async function doAction(
|
||||
elementId,
|
||||
data: {
|
||||
actionId,
|
||||
task,
|
||||
},
|
||||
async callback(action: EngineAction) {
|
||||
resolve(await callActionMethod(action));
|
||||
callback(action: EngineAction) {
|
||||
resolve(callActionMethod(action, task));
|
||||
return elementId;
|
||||
},
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const callActionMethod = (action: EngineAction) => {
|
||||
const callActionMethod = (action: EngineAction, task?: Task) => {
|
||||
if (!action._id) throw new Meteor.Error('type-error', 'Action must have and _id');
|
||||
return runAction.callAsync({ actionId: action._id, decisions: action._decisions });
|
||||
//@ts-expect-error callAsync not defined in types
|
||||
return runAction.callAsync({ actionId: action._id, decisions: action._decisions, task });
|
||||
}
|
||||
|
||||
const throwInputRequestedError = () => {
|
||||
@@ -78,4 +81,5 @@ const errorOnInputRequest: InputProvider = {
|
||||
rollDice: throwInputRequestedError,
|
||||
choose: throwInputRequestedError,
|
||||
advantage: throwInputRequestedError,
|
||||
check: throwInputRequestedError,
|
||||
}
|
||||
|
||||
59
app/imports/client/ui/creature/actions/input/CheckInput.vue
Normal file
59
app/imports/client/ui/creature/actions/input/CheckInput.vue
Normal file
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<div class="d-flex flex-column justify-center align-center">
|
||||
<v-btn-toggle
|
||||
:value="value.advantage"
|
||||
color="accent"
|
||||
@change="changeAdvantage"
|
||||
>
|
||||
<v-btn :value="-1">
|
||||
Disadvantage
|
||||
</v-btn>
|
||||
<v-btn :value="1">
|
||||
Advantage
|
||||
</v-btn>
|
||||
</v-btn-toggle>
|
||||
<div style="position: relative;">
|
||||
<v-scale-transition
|
||||
origin="center center"
|
||||
>
|
||||
<vertical-hex
|
||||
v-if="value.advantage"
|
||||
id="extra-hex"
|
||||
style="position:absolute; transition: margin-left 0.3s ease;"
|
||||
:style="{marginLeft: value.advantage == 1 ? '24px' : '-24px'}"
|
||||
disable-hover
|
||||
/>
|
||||
</v-scale-transition>
|
||||
<vertical-hex
|
||||
id="roll-hex"
|
||||
@click="$emit('continue')"
|
||||
>
|
||||
<div>
|
||||
Roll
|
||||
</div>
|
||||
</vertical-hex>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
import VerticalHex from '/imports/client/ui/components/VerticalHex.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
VerticalHex
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Object,
|
||||
required: true,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeAdvantage(e) {
|
||||
const newValue = { ...this.value, advantage: e };
|
||||
this.$emit('input', newValue)
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -34,7 +34,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
import removeUserImage from '/imports/api/files/UserImages/methods/removeUserImage';
|
||||
import removeUserImage from '/imports/api/files/userImages/UserImages/methods/removeUserImage';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
|
||||
<script lang="js">
|
||||
import ArchiveCreatureFiles from '/imports/api/creature/archive/ArchiveCreatureFiles';
|
||||
import UserImages from '/imports/api/files/UserImages';
|
||||
import UserImages from '/imports/api/files/userImages/UserImages';
|
||||
import prettyBytes from 'pretty-bytes';
|
||||
import ArchiveFileCard from '/imports/client/ui/files/ArchiveFileCard.vue';
|
||||
import FileStorageStats from '/imports/client/ui/files/FileStorageStats.vue';
|
||||
|
||||
@@ -6,17 +6,14 @@
|
||||
>
|
||||
<v-list-item-content class="py-0">
|
||||
<v-list-item-title class="d-flex align-center">
|
||||
<roll-popup
|
||||
<v-btn
|
||||
v-if="!hideModifier"
|
||||
class="prof-mod mr-1 flex-shrink-0"
|
||||
button-class="pl-3 pr-2"
|
||||
text
|
||||
:roll-text="displayedModifier"
|
||||
:name="model.name"
|
||||
:advantage="model.advantage"
|
||||
:loading="checkLoading"
|
||||
tile
|
||||
:disabled="!context.editPermission"
|
||||
@roll="check"
|
||||
:data-id="`check-btn-${model._id}`"
|
||||
class="pl-3 pr-2 prof-mod mr-1 flex-shrink-0"
|
||||
@click.stop="check"
|
||||
>
|
||||
<proficiency-icon
|
||||
:value="model.proficiency"
|
||||
@@ -37,7 +34,7 @@
|
||||
>
|
||||
mdi-chevron-double-down
|
||||
</v-icon>
|
||||
</roll-popup>
|
||||
</v-btn>
|
||||
<proficiency-icon
|
||||
v-else
|
||||
:value="model.proficiency"
|
||||
@@ -59,15 +56,12 @@
|
||||
|
||||
<script lang="js">
|
||||
import ProficiencyIcon from '/imports/client/ui/properties/shared/ProficiencyIcon.vue';
|
||||
import RollPopup from '/imports/client/ui/components/RollPopup.vue';
|
||||
import { snackbar } from '/imports/client/ui/components/snackbars/SnackbarQueue';
|
||||
import numberToSignedString from '/imports/api/utility/numberToSignedString';
|
||||
import doCheck from '/imports/api/engine/action/methods/doCheck';
|
||||
import doAction from '/imports/client/ui/creature/actions/doAction';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ProficiencyIcon,
|
||||
RollPopup,
|
||||
},
|
||||
inject: {
|
||||
context: {
|
||||
@@ -106,20 +100,18 @@ export default {
|
||||
click(e) {
|
||||
this.$emit('click', e);
|
||||
},
|
||||
check({ advantage }) {
|
||||
this.checkLoading = true;
|
||||
doCheck.call({
|
||||
propId: this.model._id,
|
||||
scope: {
|
||||
'~checkAdvantage': { value: advantage },
|
||||
},
|
||||
}, error => {
|
||||
this.checkLoading = false;
|
||||
if (error) {
|
||||
console.error(error);
|
||||
snackbar({ text: error.reason });
|
||||
}
|
||||
});
|
||||
check() {
|
||||
doAction(this.model, this.$store, `check-btn-${this.model._id}`, {
|
||||
subtaskFn: 'check',
|
||||
prop: this.model,
|
||||
targetIds: [this.model.root.id],
|
||||
advantage: this.model.advantage,
|
||||
skillVariableName: this.model.variableName,
|
||||
abilityVariableName: this.model.ability,
|
||||
dc: null,
|
||||
}).catch(e => {
|
||||
console.error(e);
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -138,4 +130,3 @@ export default {
|
||||
color: rgba(0, 0, 0, 0.54) !important;
|
||||
}
|
||||
</style>
|
||||
../../../../../api/engine/action/methods/doCheck
|
||||
@@ -1,4 +1,4 @@
|
||||
import UserImages from '/imports/api/files/UserImages';
|
||||
import UserImages from '/imports/api/files/userImages/UserImages';
|
||||
|
||||
Meteor.publish('userImages', function () {
|
||||
return UserImages.find({
|
||||
|
||||
Reference in New Issue
Block a user