Merge branch 'version-2-dev' into version-2-tabletop
This commit is contained in:
@@ -5,8 +5,9 @@ import applyProperty from '../applyProperty.js';
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||
import { adjustQuantityWork } from '/imports/api/creature/creatureProperties/methods/adjustQuantity.js';
|
||||
import { damagePropertyWork } from '/imports/api/creature/creatureProperties/methods/damageProperty.js';
|
||||
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
|
||||
import numberToSignedString from '/imports/api/utility/numberToSignedString.js';
|
||||
import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js';
|
||||
import { resetProperties } from '/imports/api/creature/creatures/methods/restCreature.js';
|
||||
|
||||
export default function applyAction(node, actionContext) {
|
||||
applyNodeTriggers(node, 'before', actionContext);
|
||||
@@ -16,7 +17,7 @@ export default function applyAction(node, actionContext) {
|
||||
|
||||
// Log the name and summary
|
||||
let content = { name: prop.name };
|
||||
if (prop.summary?.text){
|
||||
if (prop.summary?.text) {
|
||||
recalculateInlineCalculations(prop.summary, actionContext);
|
||||
content.value = prop.summary.value;
|
||||
}
|
||||
@@ -29,24 +30,27 @@ export default function applyAction(node, actionContext) {
|
||||
const attack = prop.attackRoll || prop.attackRollBonus;
|
||||
|
||||
// Attack if there is an attack roll
|
||||
if (attack && attack.calculation){
|
||||
if (targets.length){
|
||||
if (attack && attack.calculation) {
|
||||
if (targets.length) {
|
||||
targets.forEach(target => {
|
||||
applyAttackToTarget({attack, target, actionContext});
|
||||
applyAttackToTarget({ attack, target, actionContext });
|
||||
// Apply the children, but only to the current target
|
||||
actionContext.targets = [target];
|
||||
applyChildren(node, actionContext);
|
||||
});
|
||||
} else {
|
||||
applyAttackWithoutTarget({attack, actionContext});
|
||||
applyAttackWithoutTarget({ attack, actionContext });
|
||||
applyChildren(node, actionContext);
|
||||
}
|
||||
} else {
|
||||
applyChildren(node, actionContext);
|
||||
}
|
||||
if (prop.actionType === 'event' && prop.variableName) {
|
||||
resetProperties(actionContext.creature._id, prop.variableName, actionContext);
|
||||
}
|
||||
}
|
||||
|
||||
function applyAttackWithoutTarget({attack, actionContext}){
|
||||
function applyAttackWithoutTarget({ attack, actionContext }) {
|
||||
delete actionContext.scope['$attackHit'];
|
||||
delete actionContext.scope['$attackMiss'];
|
||||
delete actionContext.scope['$criticalHit'];
|
||||
@@ -62,16 +66,16 @@ function applyAttackWithoutTarget({attack, actionContext}){
|
||||
criticalMiss,
|
||||
} = rollAttack(attack, scope);
|
||||
let name = criticalHit ? 'Critical Hit!' : criticalMiss ? 'Critical Miss!' : 'To Hit';
|
||||
if (scope['$attackAdvantage'] === 1){
|
||||
if (scope['$attackAdvantage'] === 1) {
|
||||
name += ' (Advantage)';
|
||||
} else if(scope['$attackAdvantage'] === -1){
|
||||
} else if (scope['$attackAdvantage'] === -1) {
|
||||
name += ' (Disadvantage)';
|
||||
}
|
||||
if (!criticalMiss){
|
||||
scope['$attackHit'] = {value: true}
|
||||
if (!criticalMiss) {
|
||||
scope['$attackHit'] = { value: true }
|
||||
}
|
||||
if (!criticalHit){
|
||||
scope['$attackMiss'] = {value: true};
|
||||
if (!criticalHit) {
|
||||
scope['$attackMiss'] = { value: true };
|
||||
}
|
||||
|
||||
actionContext.addLog({
|
||||
@@ -81,7 +85,7 @@ function applyAttackWithoutTarget({attack, actionContext}){
|
||||
});
|
||||
}
|
||||
|
||||
function applyAttackToTarget({attack, target, actionContext}){
|
||||
function applyAttackToTarget({ attack, target, actionContext }) {
|
||||
const scope = actionContext.scope;
|
||||
delete scope['$attackHit'];
|
||||
delete scope['$attackMiss'];
|
||||
@@ -99,15 +103,15 @@ function applyAttackToTarget({attack, target, actionContext}){
|
||||
criticalMiss,
|
||||
} = rollAttack(attack, scope);
|
||||
|
||||
if (target.variables.armor){
|
||||
if (target.variables.armor) {
|
||||
const armor = target.variables.armor.value;
|
||||
|
||||
let name = criticalHit ? 'Critical Hit!' :
|
||||
criticalMiss ? 'Critical Miss!' :
|
||||
result > armor ? 'Hit!' : 'Miss!';
|
||||
if (scope['$attackAdvantage'] === 1){
|
||||
result > armor ? 'Hit!' : 'Miss!';
|
||||
if (scope['$attackAdvantage'] === 1) {
|
||||
name += ' (Advantage)';
|
||||
} else if(scope['$attackAdvantage'] === -1){
|
||||
} else if (scope['$attackAdvantage'] === -1) {
|
||||
name += ' (Disadvantage)';
|
||||
}
|
||||
|
||||
@@ -116,15 +120,15 @@ function applyAttackToTarget({attack, target, actionContext}){
|
||||
value: `${resultPrefix}\n**${result}**`,
|
||||
inline: true,
|
||||
});
|
||||
if (criticalMiss || result < armor){
|
||||
scope['$attackMiss'] = {value: true};
|
||||
if (criticalMiss || result < armor) {
|
||||
scope['$attackMiss'] = { value: true };
|
||||
} else {
|
||||
scope['$attackHit'] = {value: true};
|
||||
scope['$attackHit'] = { value: true };
|
||||
}
|
||||
} else {
|
||||
actionContext.addLog({
|
||||
name: 'Error',
|
||||
value:'Target has no `armor`',
|
||||
value: 'Target has no `armor`',
|
||||
});
|
||||
actionContext.addLog({
|
||||
name: criticalHit ? 'Critical Hit!' : criticalMiss ? 'Critical Miss!' : 'To Hit',
|
||||
@@ -134,10 +138,10 @@ function applyAttackToTarget({attack, target, actionContext}){
|
||||
}
|
||||
}
|
||||
|
||||
function rollAttack(attack, scope){
|
||||
function rollAttack(attack, scope) {
|
||||
const rollModifierText = numberToSignedString(attack.value, true);
|
||||
let value, resultPrefix;
|
||||
if (scope['$attackAdvantage'] === 1){
|
||||
if (scope['$attackAdvantage'] === 1) {
|
||||
const [a, b] = rollDice(2, 20);
|
||||
if (a >= b) {
|
||||
value = a;
|
||||
@@ -146,7 +150,7 @@ function rollAttack(attack, scope){
|
||||
value = b;
|
||||
resultPrefix = `1d20 [ ~~${a}~~, ${b} ] ${rollModifierText}`;
|
||||
}
|
||||
} else if (scope['$attackAdvantage'] === -1){
|
||||
} else if (scope['$attackAdvantage'] === -1) {
|
||||
const [a, b] = rollDice(2, 20);
|
||||
if (a <= b) {
|
||||
value = a;
|
||||
@@ -159,25 +163,26 @@ function rollAttack(attack, scope){
|
||||
value = rollDice(1, 20)[0];
|
||||
resultPrefix = `1d20 [${value}] ${rollModifierText}`
|
||||
}
|
||||
scope['$attackRoll'] = {value};
|
||||
scope['$attackDiceRoll'] = { value };
|
||||
const result = value + attack.value;
|
||||
const {criticalHit, criticalMiss} = applyCrits(value, scope);
|
||||
return {resultPrefix, result, value, criticalHit, criticalMiss};
|
||||
scope['$attackRoll'] = { result };
|
||||
const { criticalHit, criticalMiss } = applyCrits(value, scope);
|
||||
return { resultPrefix, result, value, criticalHit, criticalMiss };
|
||||
}
|
||||
|
||||
function applyCrits(value, scope){
|
||||
function applyCrits(value, scope) {
|
||||
let criticalHitTarget = scope.criticalHitTarget?.value || 20;
|
||||
let criticalHit = value >= criticalHitTarget;
|
||||
let criticalMiss;
|
||||
if (criticalHit){
|
||||
scope['$criticalHit'] = {value: true};
|
||||
if (criticalHit) {
|
||||
scope['$criticalHit'] = { value: true };
|
||||
} else {
|
||||
criticalMiss = value === 1;
|
||||
if (criticalMiss){
|
||||
scope['$criticalMiss'] = {value: true};
|
||||
if (criticalMiss) {
|
||||
scope['$criticalMiss'] = { value: true };
|
||||
}
|
||||
}
|
||||
return {criticalHit, criticalMiss};
|
||||
return { criticalHit, criticalMiss };
|
||||
}
|
||||
|
||||
function applyChildren(node, actionContext) {
|
||||
@@ -185,9 +190,9 @@ function applyChildren(node, actionContext) {
|
||||
node.children.forEach(child => applyProperty(child, actionContext));
|
||||
}
|
||||
|
||||
function spendResources(prop, actionContext){
|
||||
function spendResources(prop, actionContext) {
|
||||
// Check Uses
|
||||
if (prop.usesLeft <= 0){
|
||||
if (prop.usesLeft <= 0) {
|
||||
if (!prop.silent) actionContext.addLog({
|
||||
name: 'Error',
|
||||
value: `${prop.name || 'action'} does not have enough uses left`,
|
||||
@@ -195,7 +200,7 @@ function spendResources(prop, actionContext){
|
||||
return true;
|
||||
}
|
||||
// Resources
|
||||
if (prop.insufficientResources){
|
||||
if (prop.insufficientResources) {
|
||||
if (!prop.silent) actionContext.addLog({
|
||||
name: 'Error',
|
||||
value: 'This creature doesn\'t have sufficient resources to perform this action',
|
||||
@@ -209,14 +214,14 @@ function spendResources(prop, actionContext){
|
||||
try {
|
||||
prop.resources.itemsConsumed.forEach(itemConsumed => {
|
||||
recalculateCalculation(itemConsumed.quantity, actionContext);
|
||||
if (!itemConsumed.itemId){
|
||||
if (!itemConsumed.itemId) {
|
||||
throw 'No ammo was selected for this prop';
|
||||
}
|
||||
let item = CreatureProperties.findOne(itemConsumed.itemId);
|
||||
if (!item || item.ancestors[0].id !== prop.ancestors[0].id){
|
||||
if (!item || item.ancestors[0].id !== prop.ancestors[0].id) {
|
||||
throw 'The prop\'s ammo was not found on the creature';
|
||||
}
|
||||
if (!item.equipped){
|
||||
if (!item.equipped) {
|
||||
throw 'The selected ammo is not equipped';
|
||||
}
|
||||
if (
|
||||
@@ -229,16 +234,16 @@ function spendResources(prop, actionContext){
|
||||
value: itemConsumed.quantity.value,
|
||||
});
|
||||
let logName = item.name;
|
||||
if (itemConsumed.quantity.value > 1 || itemConsumed.quantity.value < -1){
|
||||
if (itemConsumed.quantity.value > 1 || itemConsumed.quantity.value < -1) {
|
||||
logName = item.plural || logName;
|
||||
}
|
||||
if (itemConsumed.quantity.value > 0){
|
||||
if (itemConsumed.quantity.value > 0) {
|
||||
spendLog.push(logName + ': ' + itemConsumed.quantity.value);
|
||||
} else if (itemConsumed.quantity.value < 0){
|
||||
} else if (itemConsumed.quantity.value < 0) {
|
||||
gainLog.push(logName + ': ' + -itemConsumed.quantity.value);
|
||||
}
|
||||
});
|
||||
} catch (e){
|
||||
} catch (e) {
|
||||
actionContext.addLog({
|
||||
name: 'Error',
|
||||
value: e,
|
||||
@@ -251,9 +256,9 @@ function spendResources(prop, actionContext){
|
||||
itemQuantityAdjustments.forEach(adjustQuantityWork);
|
||||
|
||||
// Use uses
|
||||
if (prop.usesLeft){
|
||||
if (prop.usesLeft) {
|
||||
CreatureProperties.update(prop._id, {
|
||||
$inc: {usesUsed: 1}
|
||||
$inc: { usesUsed: 1 }
|
||||
}, {
|
||||
selector: prop
|
||||
});
|
||||
@@ -270,7 +275,7 @@ function spendResources(prop, actionContext){
|
||||
|
||||
if (!attConsumed.quantity?.value) return;
|
||||
let stat = actionContext.scope[attConsumed.variableName];
|
||||
if (!stat){
|
||||
if (!stat) {
|
||||
spendLog.push(stat.name + ': ' + ' not found');
|
||||
return;
|
||||
}
|
||||
@@ -280,9 +285,9 @@ function spendResources(prop, actionContext){
|
||||
value: attConsumed.quantity.value,
|
||||
actionContext,
|
||||
});
|
||||
if (attConsumed.quantity.value > 0){
|
||||
if (attConsumed.quantity.value > 0) {
|
||||
spendLog.push(stat.name + ': ' + attConsumed.quantity.value);
|
||||
} else if (attConsumed.quantity.value < 0){
|
||||
} else if (attConsumed.quantity.value < 0) {
|
||||
gainLog.push(stat.name + ': ' + -attConsumed.quantity.value);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -14,6 +14,7 @@ import { insertCreatureLog } from '/imports/api/creature/log/CreatureLogs.js';
|
||||
import cyrb53 from '/imports/api/engine/computation/utility/cyrb53.js';
|
||||
import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js';
|
||||
import INLINE_CALCULATION_REGEX from '/imports/constants/INLINE_CALCULTION_REGEX.js';
|
||||
import recalculateInlineCalculations from './shared/recalculateInlineCalculations.js';
|
||||
|
||||
export default function applyBuff(node, actionContext) {
|
||||
applyNodeTriggers(node, 'before', actionContext);
|
||||
@@ -46,12 +47,17 @@ export default function applyBuff(node, actionContext) {
|
||||
copyNodeListToTarget(propList, target, oldParent);
|
||||
|
||||
//Log the buff
|
||||
let logValue = prop.description?.value
|
||||
if (prop.description?.text) {
|
||||
recalculateInlineCalculations(prop.description, actionContext);
|
||||
logValue = prop.description?.value;
|
||||
}
|
||||
if ((prop.name || prop.description?.value) && !prop.silent) {
|
||||
if (target._id === actionContext.creature._id) {
|
||||
// Targeting self
|
||||
actionContext.addLog({
|
||||
name: prop.name,
|
||||
value: prop.description?.value,
|
||||
value: logValue,
|
||||
});
|
||||
} else {
|
||||
// Targeting other
|
||||
@@ -60,7 +66,7 @@ export default function applyBuff(node, actionContext) {
|
||||
creatureId: target._id,
|
||||
content: [{
|
||||
name: prop.name,
|
||||
value: prop.description?.value,
|
||||
value: logValue,
|
||||
}],
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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';
|
||||
@@ -9,10 +9,11 @@ import {
|
||||
getPropertiesOfType
|
||||
} from '/imports/api/engine/loadCreatures.js';
|
||||
import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js';
|
||||
import getEffectivePropTags from '/imports/api/engine/computation/utility/getEffectivePropTags.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 +29,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 +41,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 +51,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 +65,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 +84,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 +108,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 {
|
||||
@@ -135,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);
|
||||
}
|
||||
@@ -169,24 +170,25 @@ 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;
|
||||
const effectiveTags = getEffectivePropTags(damageProp);
|
||||
if (includes(effectiveTags, `ignore ${multiplierType}`)) return false;
|
||||
|
||||
const hasRequiredTags = difference(
|
||||
multiplier.includeTags, damageProp.tags
|
||||
multiplier.includeTags, effectiveTags
|
||||
).length === 0;
|
||||
|
||||
const hasNoExcludedTags = intersection(
|
||||
multiplier.excludeTags, damageProp.tags
|
||||
multiplier.excludeTags, effectiveTags
|
||||
).length === 0;
|
||||
|
||||
return hasRequiredTags && hasNoExcludedTags;
|
||||
}
|
||||
}
|
||||
|
||||
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');
|
||||
|
||||
@@ -238,6 +240,14 @@ function dealDamage({target, damageType, amount, actionContext}){
|
||||
actionContext
|
||||
});
|
||||
damageLeft -= damageAdded;
|
||||
// Prevent overflow
|
||||
if (
|
||||
damageType === 'healing' ?
|
||||
healthBar.healthBarNoHealingOverflow :
|
||||
healthBar.healthBarNoDamageOverflow
|
||||
) {
|
||||
damageLeft = 0;
|
||||
}
|
||||
});
|
||||
return totalDamage;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import rollDice from '/imports/parser/rollDice.js';
|
||||
import recalculateCalculation from './shared/recalculateCalculation.js';
|
||||
import applyProperty from '../applyProperty.js';
|
||||
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
|
||||
import numberToSignedString from '/imports/api/utility/numberToSignedString.js';
|
||||
import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js';
|
||||
import { applyUnresolvedEffects } from '/imports/api/engine/actions/doCheck.js';
|
||||
|
||||
export default function applySavingThrow(node, actionContext){
|
||||
export default function applySavingThrow(node, actionContext) {
|
||||
applyNodeTriggers(node, 'before', actionContext);
|
||||
const prop = node.node;
|
||||
|
||||
@@ -13,7 +14,7 @@ export default function applySavingThrow(node, actionContext){
|
||||
recalculateCalculation(prop.dc, actionContext);
|
||||
|
||||
const dc = (prop.dc?.value);
|
||||
if (!isFinite(dc)){
|
||||
if (!isFinite(dc)) {
|
||||
actionContext.addLog({
|
||||
name: 'Error',
|
||||
value: 'Saving throw requires a DC',
|
||||
@@ -29,8 +30,8 @@ export default function applySavingThrow(node, actionContext){
|
||||
|
||||
// If there are no save targets, apply all children as if the save both
|
||||
// succeeeded and failed
|
||||
if (!saveTargets?.length){
|
||||
scope['$saveFailed'] = {value: true};
|
||||
if (!saveTargets?.length) {
|
||||
scope['$saveFailed'] = { value: true };
|
||||
scope['$saveSucceeded'] = { value: true };
|
||||
applyNodeTriggers(node, 'after', actionContext);
|
||||
return node.children.forEach(child => applyProperty(child, actionContext));
|
||||
@@ -51,7 +52,7 @@ export default function applySavingThrow(node, actionContext){
|
||||
|
||||
const save = target.variables[prop.stat];
|
||||
|
||||
if (!save){
|
||||
if (!save) {
|
||||
actionContext.addLog({
|
||||
name: 'Saving throw error',
|
||||
value: 'No saving throw found: ' + prop.stat,
|
||||
@@ -59,10 +60,14 @@ export default function applySavingThrow(node, actionContext){
|
||||
return applyChildren();
|
||||
}
|
||||
|
||||
const rollModifierText = numberToSignedString(save.value, true);
|
||||
let rollModifierText = numberToSignedString(save.value, true);
|
||||
let rollModifier = save.value
|
||||
const { effectBonus, effectString } = applyUnresolvedEffects(save, scope)
|
||||
rollModifierText += effectString;
|
||||
rollModifier += effectBonus;
|
||||
|
||||
let value, values, resultPrefix;
|
||||
if (save.advantage === 1){
|
||||
if (save.advantage === 1) {
|
||||
const [a, b] = rollDice(2, 20);
|
||||
if (a >= b) {
|
||||
value = a;
|
||||
@@ -71,7 +76,7 @@ export default function applySavingThrow(node, actionContext){
|
||||
value = b;
|
||||
resultPrefix = `Advantage\n1d20 [ ~~${a}~~, ${b} ] ${rollModifierText}`;
|
||||
}
|
||||
} else if (save.advantage === -1){
|
||||
} else if (save.advantage === -1) {
|
||||
const [a, b] = rollDice(2, 20);
|
||||
if (a <= b) {
|
||||
value = a;
|
||||
@@ -85,14 +90,14 @@ export default function applySavingThrow(node, actionContext){
|
||||
value = values[0];
|
||||
resultPrefix = `1d20 [ ${value} ] ${rollModifierText}`
|
||||
}
|
||||
scope['$saveDiceRoll'] = {value};
|
||||
const result = value + save.value || 0;
|
||||
scope['$saveRoll'] = {value: result};
|
||||
scope['$saveDiceRoll'] = { value };
|
||||
const result = value + rollModifier || 0;
|
||||
scope['$saveRoll'] = { value: result };
|
||||
const saveSuccess = result >= dc;
|
||||
if (saveSuccess){
|
||||
scope['$saveSucceeded'] = {value: true};
|
||||
if (saveSuccess) {
|
||||
scope['$saveSucceeded'] = { value: true };
|
||||
} else {
|
||||
scope['$saveFailed'] = {value: true};
|
||||
scope['$saveFailed'] = { value: true };
|
||||
}
|
||||
if (!prop.silent) actionContext.addLog({
|
||||
name: saveSuccess ? 'Successful save' : 'Failed save',
|
||||
|
||||
@@ -4,7 +4,7 @@ import { RateLimiterMixin } from 'ddp-rate-limiter-mixin';
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||
import { assertEditPermission } from '/imports/api/creature/creatures/creaturePermissions.js';
|
||||
import rollDice from '/imports/parser/rollDice.js';
|
||||
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
|
||||
import numberToSignedString from '/imports/api/utility/numberToSignedString.js';
|
||||
import { applyTriggers } from '/imports/api/engine/actions/applyTriggers.js';
|
||||
import ActionContext from '/imports/api/engine/actions/ActionContext.js';
|
||||
import evaluateCalculation from '/imports/api/engine/computation/utility/evaluateCalculation.js';
|
||||
@@ -28,6 +28,7 @@ const doCheck = new ValidatedMethod({
|
||||
const creatureId = prop.ancestors[0].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);
|
||||
@@ -115,7 +116,7 @@ function rollCheck(prop, actionContext) {
|
||||
});
|
||||
}
|
||||
|
||||
function applyUnresolvedEffects(prop, scope) {
|
||||
export function applyUnresolvedEffects(prop, scope) {
|
||||
let effectBonus = 0;
|
||||
let effectString = '';
|
||||
if (!prop.effects) {
|
||||
|
||||
Reference in New Issue
Block a user