diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyDamage.js b/app/imports/api/engine/actions/applyPropertyByType/applyDamage.js
index c35546de..f1c0c832 100644
--- a/app/imports/api/engine/actions/applyPropertyByType/applyDamage.js
+++ b/app/imports/api/engine/actions/applyPropertyByType/applyDamage.js
@@ -1,6 +1,6 @@
import { some, intersection, difference, remove, includes } from 'lodash';
import applyProperty from '../applyProperty.js';
-import {insertCreatureLog} from '/imports/api/creature/log/CreatureLogs.js';
+import { insertCreatureLog } from '/imports/api/creature/log/CreatureLogs.js';
import resolve, { Context, toString } from '/imports/parser/resolve.js';
import logErrors from './shared/logErrors.js';
import applyEffectsToCalculationParseNode from '/imports/api/engine/actions/applyPropertyByType/shared/applyEffectsToCalculationParseNode.js';
@@ -10,9 +10,9 @@ import {
} from '/imports/api/engine/loadCreatures.js';
import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js';
-export default function applyDamage(node, actionContext){
+export default function applyDamage(node, actionContext) {
applyNodeTriggers(node, 'before', actionContext);
- const applyChildren = function(){
+ const applyChildren = function () {
applyNodeTriggers(node, 'after', actionContext);
node.children.forEach(child => applyProperty(child, actionContext));
};
@@ -28,10 +28,10 @@ export default function applyDamage(node, actionContext){
// Determine if the hit is critical
let criticalHit = scope['$criticalHit']?.value &&
prop.damageType !== 'healing' // Can't critically heal
- ;
+ ;
// Double the damage rolls if the hit is critical
let context = new Context({
- options: {doubleRolls: criticalHit},
+ options: { doubleRolls: criticalHit },
});
// Gather all the lines we need to log into an array
@@ -40,8 +40,8 @@ export default function applyDamage(node, actionContext){
// roll the dice only and store that string
applyEffectsToCalculationParseNode(prop.amount, actionContext.log);
- const {result: rolled} = resolve('roll', prop.amount.parseNode, scope, context);
- if (rolled.parseType !== 'constant'){
+ const { result: rolled } = resolve('roll', prop.amount.parseNode, scope, context);
+ if (rolled.parseType !== 'constant') {
logValue.push(toString(rolled));
}
logErrors(context.errors, actionContext);
@@ -50,13 +50,13 @@ export default function applyDamage(node, actionContext){
context.errors = [];
// Resolve the roll to a final value
- const {result: reduced} = resolve('reduce', rolled, scope, context);
+ const { result: reduced } = resolve('reduce', rolled, scope, context);
logErrors(context.errors, actionContext);
// Store the result
- if (reduced.parseType === 'constant'){
+ if (reduced.parseType === 'constant') {
prop.amount.value = reduced.value;
- } else if (reduced.parseType === 'error'){
+ } else if (reduced.parseType === 'error') {
prop.amount.value = null;
} else {
prop.amount.value = toString(reduced);
@@ -64,7 +64,7 @@ export default function applyDamage(node, actionContext){
let damage = +reduced.value;
// If we didn't end up with a constant of finite amount, give up
- if (reduced?.parseType !== 'constant' || !isFinite(reduced.value)){
+ if (reduced?.parseType !== 'constant' || !isFinite(reduced.value)) {
return applyChildren();
}
@@ -83,7 +83,7 @@ export default function applyDamage(node, actionContext){
// Memoise the damage suffix for the log
let suffix = (criticalHit ? ' critical ' : ' ') +
prop.damageType +
- (prop.damageType !== 'healing' ? ' damage ': '');
+ (prop.damageType !== 'healing' ? ' damage ' : '');
if (damageTargets && damageTargets.length) {
// Iterate through all the targets
@@ -107,7 +107,7 @@ export default function applyDamage(node, actionContext){
});
// Log the damage done
- if (target._id === actionContext.creature._id){
+ if (target._id === actionContext.creature._id) {
// Target is same as self, log damage as such
logValue.push(`**${damageDealt}** ${suffix} to self`);
} else {
@@ -136,33 +136,33 @@ export default function applyDamage(node, actionContext){
return applyChildren();
}
-function applyDamageMultipliers({target, damage, damageProp, logValue}){
+function applyDamageMultipliers({ target, damage, damageProp, logValue }) {
const damageType = damageProp?.damageType;
if (!damageType) return damage;
const multiplier = target?.variables?.[damageType];
if (!multiplier) return damage;
- const damageTypeText = damageType == 'healing' ? 'healing': `${damageType} damage`;
+ const damageTypeText = damageType == 'healing' ? 'healing' : `${damageType} damage`;
if (
multiplier.immunity &&
some(multiplier.immunities, multiplierAppliesTo(damageProp, 'immunity'))
- ){
+ ) {
logValue.push(`Immune to ${damageTypeText}`);
return 0;
} else {
if (
multiplier.resistance &&
some(multiplier.resistances, multiplierAppliesTo(damageProp, 'resistance'))
- ){
+ ) {
logValue.push(`Resistant to ${damageTypeText}`);
damage = Math.floor(damage / 2);
}
if (
multiplier.vulnerability &&
some(multiplier.vulnerabilities, multiplierAppliesTo(damageProp, 'vulnerability'))
- ){
+ ) {
logValue.push(`Vulnerable to ${damageTypeText}`);
damage = Math.floor(damage * 2);
}
@@ -170,7 +170,7 @@ function applyDamageMultipliers({target, damage, damageProp, logValue}){
return damage;
}
-function multiplierAppliesTo(damageProp, multiplierType){
+function multiplierAppliesTo(damageProp, multiplierType) {
return multiplier => {
// Apply the default 'ignore x' tags
if (includes(damageProp.tags, `ignore ${multiplierType}`)) return false;
@@ -187,7 +187,7 @@ function multiplierAppliesTo(damageProp, multiplierType){
}
}
-function dealDamage({target, damageType, amount, actionContext}){
+function dealDamage({ target, damageType, amount, actionContext }) {
// Get all the health bars and do damage to them
let healthBars = getPropertiesOfType(target._id, 'attribute');
@@ -239,6 +239,14 @@ function dealDamage({target, damageType, amount, actionContext}){
actionContext
});
damageLeft -= damageAdded;
+ // Prevent overflow
+ if (
+ damageType === 'healing' ?
+ healthBar.healthBarNoHealingOverflow :
+ healthBar.healthBarNoDamageOverflow
+ ) {
+ damageLeft = 0;
+ }
});
return totalDamage;
}
diff --git a/app/imports/api/properties/Attributes.js b/app/imports/api/properties/Attributes.js
index a2681d33..1052e2e5 100644
--- a/app/imports/api/properties/Attributes.js
+++ b/app/imports/api/properties/Attributes.js
@@ -69,6 +69,16 @@ let AttributeSchema = createPropertySchema({
type: Boolean,
optional: true,
},
+ // Control how the health bar handles overflow
+ healthBarNoDamageOverflow: {
+ type: Boolean,
+ optional: true,
+ },
+ healthBarNoHealingOverflow: {
+ type: Boolean,
+ optional: true,
+ },
+ // Control when the health bar takes damage or healing
healthBarDamageOrder: {
type: SimpleSchema.Integer,
optional: true,
diff --git a/app/imports/ui/properties/forms/AttributeForm.vue b/app/imports/ui/properties/forms/AttributeForm.vue
index 4dc36f07..1d76e1a0 100644
--- a/app/imports/ui/properties/forms/AttributeForm.vue
+++ b/app/imports/ui/properties/forms/AttributeForm.vue
@@ -106,10 +106,17 @@
/>
+
+
-