Added UI for action branches
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -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,
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -1 +1 @@
|
||||
import './v1/dbv1.js';
|
||||
import './dbv1/dbv1.js';
|
||||
|
||||
75
app/imports/ui/properties/forms/BranchForm.vue
Normal file
75
app/imports/ui/properties/forms/BranchForm.vue
Normal 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>
|
||||
@@ -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,
|
||||
|
||||
36
app/imports/ui/properties/treeNodeViews/BranchTreeNode.vue
Normal file
36
app/imports/ui/properties/treeNodeViews/BranchTreeNode.vue
Normal 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>
|
||||
@@ -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,
|
||||
|
||||
56
app/imports/ui/properties/viewers/BranchViewer.vue
Normal file
56
app/imports/ui/properties/viewers/BranchViewer.vue
Normal 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>
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user