Added UI for action branches

This commit is contained in:
Stefan Zermatten
2022-02-09 16:47:38 +02:00
parent 2bdd60b5e8
commit 15ead403a5
16 changed files with 219 additions and 9 deletions

View File

@@ -39,7 +39,6 @@ const dealDamage = new ValidatedMethod({
});
export function dealDamageWork({creature, damageType, amount}){
console.log({damageType, amount})
// Get all the health bars and do damage to them
let healthBars = CreatureProperties.find({
'ancestors.id': creature._id,

View File

@@ -54,9 +54,24 @@ function applyAttackWithoutTarget({prop, scope, log}){
scope['$attackRoll'] = {value};
let criticalHitTarget = scope.criticalHitTarget?.value || 20;
let criticalHit = value >= criticalHitTarget;
if (criticalHit) scope['$criticalHit'] = {value: true};
if (criticalHit){
scope['$criticalHit'] = {value: true};
scope['$attackHit'] = {value: true};
} else {
let criticalMiss = value === 1;
if (criticalMiss){
scope['$criticalMiss'] = 1;
log.content.push({
name: 'Critical Miss!',
});
scope['$attackMiss'] = {value: true};
} else {
// Untargeted attacks hit by default
scope['$attackHit'] = {value: true}
}
}
let result = value + prop.attackRoll.value;
scope['$toHit'] = {value: result};
scope['$attackRoll'] = {value: result};
log.content.push({
name: criticalHit ? 'Critical Hit!' : 'To Hit',
value: `1d20 [${value}] + ${prop.attackRoll.value} = ` + result,

View File

@@ -1,5 +1,6 @@
import applyProperty from '../applyProperty.js';
import recalculateCalculation from './shared/recalculateCalculation.js';
import rollDice from '/imports/parser/rollDice.js';
export default function applyBranch(node, {
creature, targets, scope, log
@@ -27,6 +28,14 @@ export default function applyBranch(node, {
case 'successfulSave':
if (scope['$saveSucceeded']?.value) applyChildren();
break;
case 'random':
if (node.children.length){
let index = rollDice(1, node.children.length)[0] - 1;
applyProperty(node.children[index], {
creature, targets, scope, log
});
}
break;
case 'eachTarget':
if (targets.length){
targets.forEach(target => {

View File

@@ -16,11 +16,14 @@ let BranchSchema = createPropertySchema({
'successfulSave',
// Iterate through targets
'eachTarget',
// Pick one child at random
'random',
// if it has option children, asks to select one
// Otherwise presents its own text with yes/no
//'choice',
//'option',
],
defaultValue: 'if',
},
text: {
type: String,

View File

@@ -3,6 +3,7 @@ import { ComputedOnlyActionSchema } from '/imports/api/properties/Actions.js';
import { ComputedOnlyAdjustmentSchema } from '/imports/api/properties/Adjustments.js';
import { ComputedOnlyAttributeSchema } from '/imports/api/properties/Attributes.js';
import { ComputedOnlyBuffSchema } from '/imports/api/properties/Buffs.js';
import { ComputedOnlyBranchSchema } from '/imports/api/properties/Branches.js';
import { ComputedOnlyClassSchema } from '/imports/api/properties/Classes.js';
import { ComputedOnlyClassLevelSchema } from '/imports/api/properties/ClassLevels.js';
import { ComputedOnlyConstantSchema } from '/imports/api/properties/Constants.js';
@@ -30,6 +31,7 @@ const propertySchemasIndex = {
adjustment: ComputedOnlyAdjustmentSchema,
attribute: ComputedOnlyAttributeSchema,
buff: ComputedOnlyBuffSchema,
branch: ComputedOnlyBranchSchema,
class: ComputedOnlyClassSchema,
classLevel: ComputedOnlyClassLevelSchema,
constant: ComputedOnlyConstantSchema,

View File

@@ -3,6 +3,7 @@ import { ComputedActionSchema } from '/imports/api/properties/Actions.js';
import { ComputedAdjustmentSchema } from '/imports/api/properties/Adjustments.js';
import { ComputedAttributeSchema } from '/imports/api/properties/Attributes.js';
import { ComputedBuffSchema } from '/imports/api/properties/Buffs.js';
import { ComputedBranchSchema } from '/imports/api/properties/Branches.js';
import { ComputedClassSchema } from '/imports/api/properties/Classes.js';
import { ComputedClassLevelSchema } from '/imports/api/properties/ClassLevels.js';
import { ConstantSchema } from '/imports/api/properties/Constants.js';
@@ -30,6 +31,7 @@ const propertySchemasIndex = {
adjustment: ComputedAdjustmentSchema,
attribute: ComputedAttributeSchema,
buff: ComputedBuffSchema,
branch: ComputedBranchSchema,
class: ComputedClassSchema,
classLevel: ComputedClassLevelSchema,
constant: ConstantSchema,

View File

@@ -3,6 +3,7 @@ import { ActionSchema } from '/imports/api/properties/Actions.js';
import { AdjustmentSchema } from '/imports/api/properties/Adjustments.js';
import { AttributeSchema } from '/imports/api/properties/Attributes.js';
import { BuffSchema } from '/imports/api/properties/Buffs.js';
import { BranchSchema } from '/imports/api/properties/Branches.js';
import { ClassSchema } from '/imports/api/properties/Classes.js';
import { ClassLevelSchema } from '/imports/api/properties/ClassLevels.js';
import { ConstantSchema } from '/imports/api/properties/Constants.js';
@@ -30,6 +31,7 @@ const propertySchemasIndex = {
adjustment: AdjustmentSchema,
attribute: AttributeSchema,
buff: BuffSchema,
branch: BranchSchema,
class: ClassSchema,
classLevel: ClassLevelSchema,
constant: ConstantSchema,

View File

@@ -16,12 +16,18 @@ const PROPERTIES = Object.freeze({
icon: '$vuetify.icons.attribute_damage',
name: 'Attribute damage',
helpText: 'Attribute damage reduces the current value of an attribute when it is applied by an action. A negative value causes the attribute to increase instead, up to its normal maximum.',
suggestedParents: ['action', 'attack', 'savingThrow', 'spell'],
suggestedParents: ['action', 'attack', 'savingThrow', 'spell', 'branch'],
},
buff: {
icon: '$vuetify.icons.buff',
name: 'Buff',
helpText: 'When a buff is activated as a child of an action, it will copy the properties under itself onto a target character.',
suggestedParents: ['action', 'attack', 'savingThrow', 'spell', 'branch'],
},
branch: {
icon: 'mdi-file-tree',
name: 'Branch',
helpText: 'When a branch is activated as a child of an action, it can control which of its children get activated.',
suggestedParents: ['action', 'attack', 'savingThrow', 'spell'],
},
class: {
@@ -53,7 +59,7 @@ const PROPERTIES = Object.freeze({
icon: '$vuetify.icons.damage',
name: 'Damage',
helpText: 'When damage is activated by an action it reduces the hit points of the target creature by the calculated amount.',
suggestedParents: ['action', 'attack', 'savingThrow', 'spell'],
suggestedParents: ['action', 'attack', 'savingThrow', 'spell', 'branch'],
},
damageMultiplier: {
icon: '$vuetify.icons.damage_multiplier',
@@ -102,7 +108,7 @@ const PROPERTIES = Object.freeze({
icon: '$vuetify.icons.roll',
name: 'Roll',
helpText: 'When activated by an action, rolls perform a calculation and temporarily store the result for other properties under the same action to use',
suggestedParents: ['action', 'attack', 'savingThrow', 'spell'],
suggestedParents: ['action', 'attack', 'savingThrow', 'spell', 'branch'],
},
reference: {
icon: 'mdi-vector-link',

View File

@@ -1 +1 @@
import './v1/dbv1.js';
import './dbv1/dbv1.js';

View File

@@ -0,0 +1,75 @@
<template lang="html">
<div class="buff-form">
<smart-select
label="Branch Type"
:items="typeOptions"
:hint="typeHint"
:value="model.branchType"
:error-messages="errors.branchType"
:menu-props="{auto: true, lazy: true}"
@change="change('branchType', ...arguments)"
/>
<v-expand-transition>
<computed-field
v-if="model.branchType === 'if'"
label="Condition"
hint="If this resolved to a true value, the child properties will be applied"
:model="model.condition"
:error-messages="errors.condition"
@change="({path, value, ack}) =>
$emit('change', {path: ['condition', ...path], value, ack})"
/>
</v-expand-transition>
<smart-combobox
label="Tags"
multiple
chips
deletable-chips
hint="Used to let slots find this property in a library, should otherwise be left blank"
:value="model.tags"
@change="change('tags', ...arguments)"
/>
</div>
</template>
<script lang="js">
import propertyFormMixin from '/imports/ui/properties/forms/shared/propertyFormMixin.js';
export default {
mixins: [propertyFormMixin],
props: {
parentTarget: {
type: String,
default: undefined,
},
},
data(){return {
typeOptions: [
{value: 'if', text: 'If condition is true'},
{value: 'hit', text: 'Attack hit'},
{value: 'miss', text: 'Attack miss'},
{value: 'failedSave', text: 'Save failed'},
{value: 'successfulSave', text: 'Save succeeded'},
{value: 'eachTarget', text: 'Apply to each target'},
{value: 'random', text: 'Random'},
],
}},
computed: {
typeHint(){
switch(this.model.branchType){
case 'if': return 'If the condition is true, the child properties are applied';
case 'hit': return 'If the parent attack hits, the child properties are applied';
case 'miss': return 'If the parent attack misses, the child properties are applied';
case 'failedSave': return 'If the parent save is failed, the child properties are applied';
case 'successfulSave': return 'If the parent save is made, the child properties are applied';
case 'eachTarget': return 'Applies each child property once per target';
case 'random': return 'Chooses one child property at random and applies it';
default: return '';
}
}
}
}
</script>
<style lang="css" scoped>
</style>

View File

@@ -3,6 +3,7 @@ const AdjustmentForm = () => import('/imports/ui/properties/forms/AdjustmentForm
const AttackForm = () => import('/imports/ui/properties/forms/AttackForm.vue');
const AttributeForm = () => import('/imports/ui/properties/forms/AttributeForm.vue');
const BuffForm = () => import('/imports/ui/properties/forms/BuffForm.vue');
const BranchForm = () => import('/imports/ui/properties/forms/BranchForm.vue');
const ClassLevelForm = () => import('/imports/ui/properties/forms/ClassLevelForm.vue');
const ConstantForm = () => import('/imports/ui/properties/forms/ConstantForm.vue');
const ContainerForm = () => import('/imports/ui/properties/forms/ContainerForm.vue');
@@ -30,6 +31,7 @@ export default {
attack: AttackForm,
attribute: AttributeForm,
buff: BuffForm,
branch: BranchForm,
constant: ConstantForm,
container: ContainerForm,
classLevel: ClassLevelForm,

View File

@@ -0,0 +1,36 @@
<template lang="html">
<div class="layout align-center justify-start">
<property-icon
v-if="!hideIcon"
class="mr-2"
:model="model"
:color="model.color"
:class="selected && 'primary--text'"
/>
<div class="text-no-wrap text-truncate">
{{ name }}
</div>
</div>
</template>
<script lang="js">
import treeNodeViewMixin from '/imports/ui/properties/treeNodeViews/treeNodeViewMixin.js';
export default {
mixins: [treeNodeViewMixin],
computed: {
name(){
switch(this.model.branchType){
case 'if': return 'On condition';
case 'hit': return 'On hit';
case 'miss': return 'On miss';
case 'failedSave': return 'On failed save';
case 'successfulSave': return 'On save';
case 'eachTarget': return 'Each target';
case 'random': return 'Pick one at random';
default: return '';
}
}
}
}
</script>

View File

@@ -1,5 +1,6 @@
import DefaultTreeNode from '/imports/ui/properties/treeNodeViews/DefaultTreeNode.vue';
import AdjustmentTreeNode from '/imports/ui/properties/treeNodeViews/AdjustmentTreeNode.vue';
import BranchTreeNode from '/imports/ui/properties/treeNodeViews/BranchTreeNode.vue';
import ItemTreeNode from '/imports/ui/properties/treeNodeViews/ItemTreeNode.vue';
import DamageTreeNode from '/imports/ui/properties/treeNodeViews/DamageTreeNode.vue';
import EffectTreeNode from '/imports/ui/properties/treeNodeViews/EffectTreeNode.vue';
@@ -10,6 +11,7 @@ import ReferenceTreeNode from '/imports/ui/properties/treeNodeViews/ReferenceTre
export default {
default: DefaultTreeNode,
adjustment: AdjustmentTreeNode,
branch: BranchTreeNode,
classLevel: ClassLevelTreeNode,
damage: DamageTreeNode,
effect: EffectTreeNode,

View File

@@ -0,0 +1,56 @@
<template lang="html">
<div class="branch-viewer">
<v-row dense>
<property-field
name="Branch Type"
:value="name"
/>
<property-field
v-if="model.branchType === 'if'"
name="Condition"
:calculation="model.condition"
/>
</v-row>
</div>
</template>
<script lang="js">
import propertyViewerMixin from '/imports/ui/properties/viewers/shared/propertyViewerMixin.js'
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
export default {
mixins: [propertyViewerMixin],
computed: {
name(){
switch(this.model.branchType){
case 'if': return 'On condition';
case 'hit': return 'On hit';
case 'miss': return 'On miss';
case 'failedSave': return 'On failed save';
case 'successfulSave': return 'On save';
case 'eachTarget': return 'Each target';
case 'random': return 'Pick one at random';
default: return '';
}
}
},
methods: {
numberToSignedString,
}
}
</script>
<style lang="css" scoped>
.ability-value {
font-weight: 600;
font-size: 24px !important;
color: rgba(0, 0, 0, 0.54);
}
.mod, .ability-value {
text-align: center;
width: 100%;
}
.attribute-value {
text-align: center;
}
</style>

View File

@@ -2,6 +2,7 @@ const ActionViewer = () => import ('/imports/ui/properties/viewers/ActionViewer.
const AdjustmentViewer = () => import ('/imports/ui/properties/viewers/AdjustmentViewer.vue');
const AttributeViewer = () => import ('/imports/ui/properties/viewers/AttributeViewer.vue');
const BuffViewer = () => import ('/imports/ui/properties/viewers/BuffViewer.vue');
const BranchViewer = () => import ('/imports/ui/properties/viewers/BranchViewer.vue');
const ContainerViewer = () => import ('/imports/ui/properties/viewers/ContainerViewer.vue');
const ClassLevelViewer = () => import ('/imports/ui/properties/viewers/ClassLevelViewer.vue');
const ConstantViewer = () => import ('/imports/ui/properties/viewers/ConstantViewer.vue');
@@ -28,6 +29,7 @@ export default {
adjustment: AdjustmentViewer,
attribute: AttributeViewer,
buff: BuffViewer,
branch: BranchViewer,
container: ContainerViewer,
class: SlotViewer,
classLevel: ClassLevelViewer,

View File

@@ -269,8 +269,7 @@ RouterFactory.configure(router => {
function redirectIfMaintenance(to, from, next){
if (!MAINTENANCE_MODE) return next();
console.log(to);
if (to?.path === '/admin' || to?.path === '/maintenance') return next();
if (to?.path === '/admin' || to?.path === '/maintenance' || to?.path === '/sign-in') return next();
Tracker.autorun((computation) => {
if (userSubscription.ready()){
computation.stop();