Added attribute damage and self damage results to actions and log.
This commit is contained in:
@@ -255,6 +255,7 @@ export function damagePropertyWork({property, operation, value}){
|
|||||||
}, {
|
}, {
|
||||||
selector: property
|
selector: property
|
||||||
});
|
});
|
||||||
|
return currentValue - damage;
|
||||||
} else if (operation === 'increment'){
|
} else if (operation === 'increment'){
|
||||||
let currentValue = property.value - (property.damage || 0);
|
let currentValue = property.value - (property.damage || 0);
|
||||||
let currentDamage = property.damage;
|
let currentDamage = property.damage;
|
||||||
@@ -268,9 +269,47 @@ export function damagePropertyWork({property, operation, value}){
|
|||||||
}, {
|
}, {
|
||||||
selector: property
|
selector: property
|
||||||
});
|
});
|
||||||
|
return increment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const damagePropertiesByName = new ValidatedMethod({
|
||||||
|
name: 'CreatureProperties.damagePropertiesByName',
|
||||||
|
validate: new SimpleSchema({
|
||||||
|
creatureId: SimpleSchema.RegEx.Id,
|
||||||
|
variableName: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
operation: {
|
||||||
|
type: String,
|
||||||
|
allowedValues: ['set', 'increment']
|
||||||
|
},
|
||||||
|
value: Number,
|
||||||
|
}).validator(),
|
||||||
|
mixins: [RateLimiterMixin],
|
||||||
|
rateLimit: {
|
||||||
|
numRequests: 20,
|
||||||
|
timeInterval: 5000,
|
||||||
|
},
|
||||||
|
run({creatureId, variableName, operation, value}) {
|
||||||
|
// Check permissions
|
||||||
|
assertEditPermission(creatureId, this.userId);
|
||||||
|
CreatureProperties.find({
|
||||||
|
'ancestors.id': creatureId,
|
||||||
|
variableName,
|
||||||
|
removed: {$ne: false},
|
||||||
|
inactive: {$ne: true},
|
||||||
|
}).forEach(property => {
|
||||||
|
// Check if property can take damage
|
||||||
|
let schema = CreatureProperties.simpleSchema(property);
|
||||||
|
if (!schema.allowsKey('damage')) return;
|
||||||
|
// Damage the property
|
||||||
|
damagePropertyWork({property: property, operation, value})
|
||||||
|
});
|
||||||
|
recomputeCreature.call({charId: creatureId});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const damageProperty = new ValidatedMethod({
|
const damageProperty = new ValidatedMethod({
|
||||||
name: 'creatureProperties.damage',
|
name: 'creatureProperties.damage',
|
||||||
validate: new SimpleSchema({
|
validate: new SimpleSchema({
|
||||||
@@ -303,6 +342,58 @@ const damageProperty = new ValidatedMethod({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const dealDamage = new ValidatedMethod({
|
||||||
|
name: 'creatureProperties.dealDamage',
|
||||||
|
validate: new SimpleSchema({
|
||||||
|
creatureId: SimpleSchema.RegEx.Id,
|
||||||
|
damageType: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
amount: Number,
|
||||||
|
}).validator(),
|
||||||
|
mixins: [RateLimiterMixin],
|
||||||
|
rateLimit: {
|
||||||
|
numRequests: 20,
|
||||||
|
timeInterval: 5000,
|
||||||
|
},
|
||||||
|
run({creatureId, damageType, amount}) {
|
||||||
|
let creature = Creatures.findOne(creatureId, {
|
||||||
|
fields: {
|
||||||
|
damageMultipliers: 1,
|
||||||
|
owner: 1,
|
||||||
|
readers: 1,
|
||||||
|
writers: 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// Check permissions
|
||||||
|
assertEditPermission(creatureId, this.userId);
|
||||||
|
let healthBars = CreatureProperties.find({
|
||||||
|
'ancestors.id': creatureId,
|
||||||
|
type: 'attribute',
|
||||||
|
attributeType:'healthBar',
|
||||||
|
removed: {$ne: true},
|
||||||
|
inactive: {$ne: true},
|
||||||
|
}, {
|
||||||
|
sort: {order: -1},
|
||||||
|
});
|
||||||
|
let multiplier = creature.damageMultipliers[damageType];
|
||||||
|
if (multiplier === undefined) multiplier = 1;
|
||||||
|
let totalDamage = Math.floor(amount * multiplier);
|
||||||
|
let damageLeft = totalDamage;
|
||||||
|
healthBars.forEach(healthBar => {
|
||||||
|
if (damageLeft === 0) return;
|
||||||
|
let damageAdded = damagePropertyWork({
|
||||||
|
property: healthBar,
|
||||||
|
operation: 'increment',
|
||||||
|
value: damageLeft,
|
||||||
|
});
|
||||||
|
damageLeft -= damageAdded;
|
||||||
|
});
|
||||||
|
recomputeCreature.call({charId: creatureId});
|
||||||
|
return totalDamage;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export function adjustQuantityWork({property, operation, value}){
|
export function adjustQuantityWork({property, operation, value}){
|
||||||
// Check if property has quantity
|
// Check if property has quantity
|
||||||
let schema = CreatureProperties.simpleSchema(property);
|
let schema = CreatureProperties.simpleSchema(property);
|
||||||
@@ -476,6 +567,8 @@ export {
|
|||||||
duplicateProperty,
|
duplicateProperty,
|
||||||
insertPropertyFromLibraryNode,
|
insertPropertyFromLibraryNode,
|
||||||
updateProperty,
|
updateProperty,
|
||||||
|
dealDamage,
|
||||||
|
damagePropertiesByName,
|
||||||
damageProperty,
|
damageProperty,
|
||||||
adjustQuantity,
|
adjustQuantity,
|
||||||
selectAmmoItem,
|
selectAmmoItem,
|
||||||
|
|||||||
56
app/imports/api/creature/actions/applyAdjustment.js
Normal file
56
app/imports/api/creature/actions/applyAdjustment.js
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import evaluateString from '/imports/api/creature/computation/afterComputation/evaluateString.js';
|
||||||
|
import {insertCreatureLog} from '/imports/api/creature/log/CreatureLogs.js';
|
||||||
|
import { damagePropertiesByName } from '/imports/api/creature/CreatureProperties.js';
|
||||||
|
|
||||||
|
export default function applyAdjustment({
|
||||||
|
prop,
|
||||||
|
creature,
|
||||||
|
targets,
|
||||||
|
actionContext
|
||||||
|
}){
|
||||||
|
let damageTargets = prop.target === 'self' ? [creature] : targets;
|
||||||
|
let scope = {
|
||||||
|
...creature.variables,
|
||||||
|
...actionContext,
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
var {result, errors} = evaluateString(prop.amount, scope, 'reduce');
|
||||||
|
if (typeof result !== 'number') {
|
||||||
|
return insertCreatureLog.call({ log: {
|
||||||
|
text: errors.join(', ') || 'Something went wrong',
|
||||||
|
creatureId: creature._id,
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
} catch (e){
|
||||||
|
return insertCreatureLog.call({ log: {
|
||||||
|
text: e.toString(),
|
||||||
|
creatureId: creature._id,
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
if (damageTargets) {
|
||||||
|
damageTargets.forEach(target => {
|
||||||
|
if (prop.target === 'each'){
|
||||||
|
result = evaluateString(prop.amount, scope, 'reduce');
|
||||||
|
}
|
||||||
|
damagePropertiesByName.call({
|
||||||
|
creatureId: target._id,
|
||||||
|
variableName: prop.stat,
|
||||||
|
operation: prop.operation || 'increment',
|
||||||
|
value: result
|
||||||
|
});
|
||||||
|
insertCreatureLog.call({
|
||||||
|
log: {
|
||||||
|
text: `${prop.stat} ${prop.operation === 'set' ? 'set to' : ''} ${-result}`,
|
||||||
|
creatureId: target._id,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
insertCreatureLog.call({
|
||||||
|
log: {
|
||||||
|
text: `${prop.stat} ${prop.operation === 'set' ? 'set to' : ''} ${-result}`,
|
||||||
|
creatureId: creature._id,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ export default function applyAttack({
|
|||||||
//targets,
|
//targets,
|
||||||
//actionContext
|
//actionContext
|
||||||
}){
|
}){
|
||||||
let result = roll(1, 20) + prop.rollBonusResult;
|
let result = roll(1, 20)[0] + prop.rollBonusResult;
|
||||||
insertCreatureLog.call({
|
insertCreatureLog.call({
|
||||||
log: {
|
log: {
|
||||||
text: `${prop.name} attack. ${result} to hit`,
|
text: `${prop.name} attack. ${result} to hit`,
|
||||||
|
|||||||
@@ -1,27 +1,63 @@
|
|||||||
import evaluateString from '/imports/api/creature/computation/afterComputation/evaluateString.js';
|
import evaluateString from '/imports/api/creature/computation/afterComputation/evaluateString.js';
|
||||||
|
import {insertCreatureLog} from '/imports/api/creature/log/CreatureLogs.js';
|
||||||
//if (Meteor.isServer){
|
import { dealDamage } from '/imports/api/creature/CreatureProperties.js';
|
||||||
// var sendWebhook = require('/imports/server/discord/webhook.js').default;
|
|
||||||
//}
|
|
||||||
|
|
||||||
export default function applyDamage({
|
export default function applyDamage({
|
||||||
prop,
|
prop,
|
||||||
creature,
|
creature,
|
||||||
//targets,
|
targets,
|
||||||
actionContext
|
actionContext
|
||||||
}){
|
}){
|
||||||
//let damageTargets = prop.target === 'self' ? [creature] : targets;
|
let damageTargets = prop.target === 'self' ? [creature] : targets;
|
||||||
let scope = {
|
let scope = {
|
||||||
...creature.variables,
|
...creature.variables,
|
||||||
...actionContext,
|
...actionContext,
|
||||||
};
|
};
|
||||||
let {result, errors} = evaluateString(prop.amount, scope, 'reduce');
|
try {
|
||||||
if (Meteor.isClient){
|
var {result, errors} = evaluateString(prop.amount, scope, 'reduce');
|
||||||
errors.forEach(e => console.error(e));
|
if (typeof result !== 'number') {
|
||||||
console.log(`${result} ${prop.damageType}${prop.damageType !== 'healing'? ' damage': ''}`);
|
return insertCreatureLog.call({ log: {
|
||||||
|
text: errors.join(', '),
|
||||||
|
creatureId: creature._id,
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
} catch (e){
|
||||||
|
return insertCreatureLog.call({ log: {
|
||||||
|
text: e.toString(),
|
||||||
|
creatureId: creature._id,
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
if (damageTargets) {
|
||||||
|
damageTargets.forEach(target => {
|
||||||
|
if (prop.target === 'each'){
|
||||||
|
result = evaluateString(prop.amount, scope, 'reduce');
|
||||||
|
}
|
||||||
|
let damageDealt = dealDamage.call({
|
||||||
|
creatureId: target._id,
|
||||||
|
damageType: prop.damageType,
|
||||||
|
amount: result,
|
||||||
|
});
|
||||||
|
insertCreatureLog.call({
|
||||||
|
log: {
|
||||||
|
text: `Recieved ${damageDealt} ${prop.damageType}${prop.damageType !== 'healing'? ' damage': ''}`,
|
||||||
|
creatureId: target._id,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (target._id !== creature._id){
|
||||||
|
insertCreatureLog.call({
|
||||||
|
log: {
|
||||||
|
text: `Dealt ${damageDealt} ${prop.damageType}${prop.damageType !== 'healing'? ' damage': ''}`,
|
||||||
|
creatureId: creature._id,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
insertCreatureLog.call({
|
||||||
|
log: {
|
||||||
|
text: `${result} ${prop.damageType}${prop.damageType !== 'healing'? ' damage': ''}`,
|
||||||
|
creatureId: creature._id,
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
//if (Meteor.isServer) sendWebhook({
|
|
||||||
// webhook: creature.webhook,
|
|
||||||
// message: `${result} ${prop.damageType}${prop.damageType !== 'healing'? ' damage': ''}`,
|
|
||||||
//});
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import applyAction from '/imports/api/creature/actions/applyAction.js';
|
import applyAction from '/imports/api/creature/actions/applyAction.js';
|
||||||
|
import applyAdjustment from '/imports/api/creature/actions/applyAdjustment.js';
|
||||||
import applyAttack from '/imports/api/creature/actions/applyAttack.js';
|
import applyAttack from '/imports/api/creature/actions/applyAttack.js';
|
||||||
import applyDamage from '/imports/api/creature/actions/applyDamage.js';
|
import applyDamage from '/imports/api/creature/actions/applyDamage.js';
|
||||||
import applyBuff from '/imports/api/creature/actions/applyBuff.js';
|
import applyBuff from '/imports/api/creature/actions/applyBuff.js';
|
||||||
@@ -26,7 +27,7 @@ function applyProperty(options){
|
|||||||
applyDamage(options);
|
applyDamage(options);
|
||||||
return true;
|
return true;
|
||||||
case 'adjustment':
|
case 'adjustment':
|
||||||
// applyAdjustment(options);
|
applyAdjustment(options);
|
||||||
return true;
|
return true;
|
||||||
case 'buff':
|
case 'buff':
|
||||||
applyBuff(options);
|
applyBuff(options);
|
||||||
|
|||||||
@@ -33,15 +33,15 @@ function combineAttribute(stat, aggregator, memo){
|
|||||||
stat.value = getAggregatorResult(stat, aggregator);
|
stat.value = getAggregatorResult(stat, aggregator);
|
||||||
stat.baseValue = aggregator.statBaseValue;
|
stat.baseValue = aggregator.statBaseValue;
|
||||||
stat.baseValueErrors = aggregator.baseValueErrors;
|
stat.baseValueErrors = aggregator.baseValueErrors;
|
||||||
if (stat.attributeType === 'ability') {
|
|
||||||
stat.modifier = Math.floor((stat.value - 10) / 2);
|
|
||||||
}
|
|
||||||
if (stat.attributeType === 'spellSlot'){
|
if (stat.attributeType === 'spellSlot'){
|
||||||
let {result, context} = evaluateCalculation(stat.spellSlotLevelCalculation, memo);
|
let {result, context} = evaluateCalculation(stat.spellSlotLevelCalculation, memo);
|
||||||
stat.spellSlotLevelValue = result.value;
|
stat.spellSlotLevelValue = result.value;
|
||||||
stat.spellSlotLevelErrors = context.errors;
|
stat.spellSlotLevelErrors = context.errors;
|
||||||
}
|
}
|
||||||
stat.currentValue = stat.value - (stat.damage || 0);
|
stat.currentValue = stat.value - (stat.damage || 0);
|
||||||
|
if (stat.attributeType === 'ability') {
|
||||||
|
stat.modifier = Math.floor((stat.currentValue - 10) / 2);
|
||||||
|
}
|
||||||
stat.hide = aggregator.hasNoEffects &&
|
stat.hide = aggregator.hasNoEffects &&
|
||||||
stat.baseValue === undefined ||
|
stat.baseValue === undefined ||
|
||||||
undefined
|
undefined
|
||||||
|
|||||||
@@ -67,43 +67,28 @@ function computeAction(prop, memo){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeAttack(prop, memo){
|
function computePropertyField(prop, memo, fieldName, fn){
|
||||||
// Roll bonus
|
let {result, context} = evaluateCalculation(prop[fieldName], memo, fn);
|
||||||
let {result, context} = evaluateCalculation(prop.rollBonus, memo);
|
prop[`${fieldName}Result`] = result.value;
|
||||||
prop.rollBonusResult = result.value;
|
|
||||||
if (context.errors.length){
|
if (context.errors.length){
|
||||||
prop.rollBonusErrors = context.errors;
|
prop[`${fieldName}Errors`] = context.errors;
|
||||||
} else {
|
} else {
|
||||||
delete prop.rollBonusErrors;
|
delete prop[`${fieldName}Errors`];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function computeAttack(prop, memo){
|
||||||
|
computePropertyField(prop, memo, 'rollBonus');
|
||||||
|
}
|
||||||
|
|
||||||
function computeSavingThrow(prop, memo){
|
function computeSavingThrow(prop, memo){
|
||||||
let {result, context} = evaluateCalculation(prop.dc, memo);
|
computePropertyField(prop, memo, 'dc');
|
||||||
prop.dcResult = result.value;
|
|
||||||
if (context.errors.length){
|
|
||||||
prop.dcErrors = context.errors;
|
|
||||||
} else {
|
|
||||||
delete prop.dcErrors;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeSpellList(prop, memo){
|
function computeSpellList(prop, memo){
|
||||||
let {result, context} = evaluateCalculation(prop.maxPrepared, memo);
|
computePropertyField(prop, memo, 'maxPrepared');
|
||||||
prop.maxPreparedResult = result.value;
|
|
||||||
if (context.errors.length){
|
|
||||||
prop.maxPreparedErrors = context.errors;
|
|
||||||
} else {
|
|
||||||
delete prop.maxPreparedErrors;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeSlot(prop, memo){
|
function computeSlot(prop, memo){
|
||||||
let {result, context} = evaluateCalculation(prop.slotCondition, memo);
|
computePropertyField(prop, memo, 'slotCondition');
|
||||||
prop.slotConditionResult = result.value;
|
|
||||||
if (context.errors.length){
|
|
||||||
prop.slotConditionErrors = context.errors;
|
|
||||||
} else {
|
|
||||||
delete prop.slotConditionErrors;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ const AdjustmentSchema = new SimpleSchema({
|
|||||||
type: String,
|
type: String,
|
||||||
optional: true,
|
optional: true,
|
||||||
},
|
},
|
||||||
|
operation: {
|
||||||
|
type: String,
|
||||||
|
allowedValues: ['set', 'increment'],
|
||||||
|
defaultValue: 'increment',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export { AdjustmentSchema };
|
export { AdjustmentSchema };
|
||||||
|
|||||||
@@ -6,7 +6,9 @@
|
|||||||
<v-list-tile-action class="mr-4">
|
<v-list-tile-action class="mr-4">
|
||||||
<div class="display-1 mod">
|
<div class="display-1 mod">
|
||||||
<template v-if="swapScoresAndMods">
|
<template v-if="swapScoresAndMods">
|
||||||
{{ model.value }}
|
<span :class="{'primary--text': model.currentValue !== model.value}">
|
||||||
|
{{ model.currentValue }}
|
||||||
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
{{ numberToSignedString(model.modifier) }}
|
{{ numberToSignedString(model.modifier) }}
|
||||||
@@ -17,7 +19,9 @@
|
|||||||
{{ numberToSignedString(model.modifier) }}
|
{{ numberToSignedString(model.modifier) }}
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
{{ model.value }}
|
<span :class="{'primary--text': model.currentValue !== model.value}">
|
||||||
|
{{ model.currentValue }}
|
||||||
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</v-list-tile-action>
|
</v-list-tile-action>
|
||||||
|
|||||||
@@ -19,6 +19,15 @@
|
|||||||
@change="change('amount', ...arguments)"
|
@change="change('amount', ...arguments)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<smart-select
|
||||||
|
label="Operation"
|
||||||
|
class="mx-1"
|
||||||
|
style="flex-basis: 300px;"
|
||||||
|
:items="adjustmentOps"
|
||||||
|
:value="model.operation"
|
||||||
|
:error-messages="errors.operation"
|
||||||
|
@change="change('operation', ...arguments)"
|
||||||
|
/>
|
||||||
<smart-select
|
<smart-select
|
||||||
v-if="parentTarget !== 'self'"
|
v-if="parentTarget !== 'self'"
|
||||||
label="Target"
|
label="Target"
|
||||||
@@ -52,6 +61,12 @@ export default {
|
|||||||
default: undefined,
|
default: undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
data(){return {
|
||||||
|
adjustmentOps: [
|
||||||
|
{text: 'Damage', value: 'increment'},
|
||||||
|
{text: 'Set', value: 'set'},
|
||||||
|
],
|
||||||
|
}},
|
||||||
computed: {
|
computed: {
|
||||||
targetOptions(){
|
targetOptions(){
|
||||||
if (this.parentTarget === 'singleTarget') {
|
if (this.parentTarget === 'singleTarget') {
|
||||||
|
|||||||
Reference in New Issue
Block a user