diff --git a/app/imports/api/creature/actions/applyAction.js b/app/imports/api/creature/actions/applyAction.js index 895a01e9..82ea824b 100644 --- a/app/imports/api/creature/actions/applyAction.js +++ b/app/imports/api/creature/actions/applyAction.js @@ -2,23 +2,12 @@ import spendResources from '/imports/api/creature/actions/spendResources.js' import embedInlineCalculations from '/imports/api/creature/computation/afterComputation/embedInlineCalculations.js'; export default function applyAction({prop, log}){ - spendResources(prop); - // If this is not the top level action, we can add its name to the log - if (log.content.length){ - log.content.push({name: prop.name}); - } + let content = { name: prop.name }; if (prop.summary){ - log.content.push({ - description: embedInlineCalculations( - prop.summary, prop.summaryCalculations - ), - }); - } - if (prop.description){ - log.content.push({ - description: embedInlineCalculations( - prop.description, prop.descriptionCalculations - ), - }); + content.description = embedInlineCalculations( + prop.summary, prop.summaryCalculations + ); } + log.content.push(content); + spendResources({prop, log}); } diff --git a/app/imports/api/creature/actions/applyAdjustment.js b/app/imports/api/creature/actions/applyAdjustment.js index ddc792ef..06e664b2 100644 --- a/app/imports/api/creature/actions/applyAdjustment.js +++ b/app/imports/api/creature/actions/applyAdjustment.js @@ -16,10 +16,16 @@ export default function applyAdjustment({ try { var {result, errors} = evaluateString(prop.amount, scope, 'reduce'); if (typeof result !== 'number') { - log.content.push({error: errors.join(', ') || 'Something went wrong'}); + log.content.push({ + name: 'Attribute damage', + error: errors.join(', ') || 'Something went wrong', + }); } } catch (e){ - log.content.push({error: e.toString()}); + log.content.push({ + name: 'Attribute damage', + error: e.toString(), + }); } if (damageTargets) { damageTargets.forEach(target => { @@ -33,12 +39,14 @@ export default function applyAdjustment({ value: result }); log.content.push({ + name: 'Attribute damage', resultPrefix: `${prop.stat} ${prop.operation === 'set' ? 'set to' : ''}`, result: `${-result}`, }); }); } else { log.content.push({ + name: 'Attribute damage', resultPrefix: `${prop.stat} ${prop.operation === 'set' ? 'set to' : ''}`, result: `${-result}`, }); diff --git a/app/imports/api/creature/actions/applyAttack.js b/app/imports/api/creature/actions/applyAttack.js index 99e62ab5..d933976e 100644 --- a/app/imports/api/creature/actions/applyAttack.js +++ b/app/imports/api/creature/actions/applyAttack.js @@ -3,12 +3,14 @@ import roll from '/imports/parser/roll.js'; export default function applyAttack({ prop, log, + actionContext, }){ - let result = roll(1, 20)[0] + prop.rollBonusResult; + let value = roll(1, 20)[0]; + actionContext.attackRoll = {value}; + let result = value + prop.rollBonusResult; log.content.push({ - // If this is not the first item in the log content, give it a name - name: log.content.length ? prop.name + ' attack' : undefined, + name: 'To Hit', + resultPrefix: `1d20 [${value}] + ${prop.rollBonusResult} = `, result, - details: 'to hit', }); } diff --git a/app/imports/api/creature/actions/applyDamage.js b/app/imports/api/creature/actions/applyDamage.js index 11f383bc..713c1a97 100644 --- a/app/imports/api/creature/actions/applyDamage.js +++ b/app/imports/api/creature/actions/applyDamage.js @@ -28,6 +28,9 @@ export default function applyDamage({ } if (damageTargets && damageTargets.length) { damageTargets.forEach(target => { + let name = prop.damageType === 'healing' ? 'Healing' : 'Damage'; + let suffix = prop.damageType + + prop.damageType !== 'healing' ? ' damage': ''; if (prop.target === 'each'){ result = evaluateString(prop.amount, scope, 'reduce'); } @@ -38,25 +41,24 @@ export default function applyDamage({ }); if (target._id === creature._id){ log.content.push({ + name, result: damageDealt, - details: `${prop.damageType}`+ - `${prop.damageType !== 'healing' ? ' damage': ''} to self`, + details: suffix + 'to self', }); } else { log.content.push({ + name, resultPrefix: 'Dealt ', result: damageDealt, - details: `${prop.damageType}` + - `${prop.damageType !== 'healing'? ' damage': ''}` + - `${target.name && ' to '}${target.name}`, + details: suffix + `${target.name && ' to '}${target.name}`, }); insertCreatureLog.call({ log: { content: [{ + name, resultPrefix: 'Recieved ', result: damageDealt, - details: `${prop.damageType}` + - `${prop.damageType !== 'healing'? ' damage': ''}` + details: suffix, }], creatureId: target._id, } @@ -65,6 +67,7 @@ export default function applyDamage({ }); } else { log.content.push({ + name: prop.damageType === 'healing' ? 'Healing' : 'Damage', result, details: `${prop.damageType}${prop.damageType !== 'healing'? ' damage': ''}`, }); diff --git a/app/imports/api/creature/actions/doAction.js b/app/imports/api/creature/actions/doAction.js index 80be4a13..66dbba0f 100644 --- a/app/imports/api/creature/actions/doAction.js +++ b/app/imports/api/creature/actions/doAction.js @@ -3,7 +3,7 @@ import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; import Creatures from '/imports/api/creature/Creatures.js'; -import CreatureLogs, { CreatureLogSchema, insertCreatureLogWork } from '/imports/api/creature/log/CreatureLogs.js'; +import { CreatureLogSchema, insertCreatureLogWork } from '/imports/api/creature/log/CreatureLogs.js'; import getRootCreatureAncestor from '/imports/api/creature/creatureProperties/getRootCreatureAncestor.js'; import { assertEditPermission } from '/imports/api/creature/creaturePermissions.js'; import { recomputeCreatureByDoc } from '/imports/api/creature/computation/methods/recomputeCreature.js'; @@ -60,7 +60,6 @@ export function doActionWork({ }){ // Create the log let log = CreatureLogSchema.clean({ - name: action.name, creatureId: creature._id, creatureName: creature.name, }); diff --git a/app/imports/api/creature/actions/spendResources.js b/app/imports/api/creature/actions/spendResources.js index abfeae1e..5c7c6448 100644 --- a/app/imports/api/creature/actions/spendResources.js +++ b/app/imports/api/creature/actions/spendResources.js @@ -2,28 +2,30 @@ import CreatureProperties from '/imports/api/creature/creatureProperties/Creatur import { adjustQuantityWork } from '/imports/api/creature/creatureProperties/methods/adjustQuantity.js'; import { damagePropertyWork } from '/imports/api/creature/creatureProperties/methods/damageProperty.js'; -export default function spendResources(action){ +export default function spendResources({prop, log}){ // Check Uses - if (action.usesUsed >= action.usesResult){ + if (prop.usesUsed >= prop.usesResult){ throw new Meteor.Error('Insufficient Uses', - 'This action has no uses left'); + 'This prop has no uses left'); } // Resources - if (action.insufficientResources){ + if (prop.insufficientResources){ throw new Meteor.Error('Insufficient Resources', - 'This creature doesn\'t have sufficient resources to perform this action'); + 'This creature doesn\'t have sufficient resources to perform this prop'); } // Items let itemQuantityAdjustments = []; - action.resources.itemsConsumed.forEach(itemConsumed => { + let spendLog = []; + let gainLog = []; + prop.resources.itemsConsumed.forEach(itemConsumed => { if (!itemConsumed.itemId){ throw new Meteor.Error('Ammo not selected', - 'No ammo was selected for this action'); + 'No ammo was selected for this prop'); } let item = CreatureProperties.findOne(itemConsumed.itemId); - if (!item || item.ancestors[0].id !== action.ancestors[0].id){ + if (!item || item.ancestors[0].id !== prop.ancestors[0].id){ throw new Meteor.Error('Ammo not found', - 'The action\'s ammo was not found on the creature'); + 'The prop\'s ammo was not found on the creature'); } if (!item.equipped){ throw new Meteor.Error('Ammo not equipped', @@ -35,19 +37,36 @@ export default function spendResources(action){ operation: 'increment', value: itemConsumed.quantity, }); + let logName = item.name; + if (itemConsumed.quantity > 1 || itemConsumed.quantity < -1){ + logName = item.plural || logName; + } + if (itemConsumed.quantity > 0){ + spendLog.push(logName + ': ' + itemConsumed.quantity); + } else if (itemConsumed.quantity < 0){ + gainLog.push(logName + ': ' + -itemConsumed.quantity); + } }); // No more errors should be thrown after this line // Now that we have confirmed that there are no errors, do actual work //Items itemQuantityAdjustments.forEach(adjustQuantityWork); + // Use uses - CreatureProperties.update(action._id, { - $inc: {usesUsed: 1} - }, { - selector: action - }); + if (prop.usesResult){ + CreatureProperties.update(prop._id, { + $inc: {usesUsed: 1} + }, { + selector: prop + }); + log.content.push({ + name: 'Uses left', + result: prop.usesResult - prop.usesUsed - 1, + }); + } + // Damage stats - action.resources.attributesConsumed.forEach(attConsumed => { + prop.resources.attributesConsumed.forEach(attConsumed => { if (!attConsumed.quantity) return; let stat = CreatureProperties.findOne(attConsumed.statId); damagePropertyWork({ @@ -55,5 +74,20 @@ export default function spendResources(action){ operation: 'increment', value: attConsumed.quantity, }); + if (attConsumed.quantity > 0){ + spendLog.push(stat.name + ': ' + attConsumed.quantity); + } else if (attConsumed.quantity < 0){ + gainLog.push(stat.name + ': ' + -attConsumed.quantity); + } + }); + + // Log all the spending + if (gainLog.length) log.content.push({ + name: 'Gained', + description: gainLog.join('\n'), + }); + if (spendLog.length) log.content.push({ + name: 'Spent', + description: spendLog.join('\n'), }); } diff --git a/app/imports/api/creature/log/CreatureLogs.js b/app/imports/api/creature/log/CreatureLogs.js index a6f027f6..bd20a1b7 100644 --- a/app/imports/api/creature/log/CreatureLogs.js +++ b/app/imports/api/creature/log/CreatureLogs.js @@ -18,13 +18,10 @@ if (Meteor.isServer){ let CreatureLogs = new Mongo.Collection('creatureLogs'); let CreatureLogSchema = new SimpleSchema({ - name: { - type: String, - optional: true, - }, content: { type: Array, defaultValue: [], + maxCount: 25, }, 'content.$': { type: LogContentSchema, @@ -68,11 +65,45 @@ function removeOldLogs(creatureId){ }); } +function logToMessageData(log){ + let embed = { + fields: [], + }; + log.content.forEach(c => { + let field = {}; + let descriptionField = {}; + if (c.name) field.name = c.name; + let valueArray = []; + if (c.error) valueArray.push(`*${c.error}*`); + if (c.resultPrefix) valueArray.push(`${c.resultPrefix}`); + if (c.result) valueArray.push(`\`${c.result}\``); + if (c.details) valueArray.push(c.details); + if (valueArray.length) field.value = valueArray.join(' '); + if (c.description){ + if (!field.value){ + field.value = c.description; + } else { + descriptionField.value = c.description; + } + } + if (field.name || field.value){ + if (!field.name) field.name = '\u200b'; + if (!field.value) field.value = '\u200b'; + embed.fields.push(field); + } + if (descriptionField.value){ + descriptionField.name = '\u200b'; + embed.fields.push(descriptionField); + } + }); + return { embeds: [embed] }; +} + function logWebhook({log, creature}){ if (Meteor.isServer){ sendWebhookAsCreature({ creature, - content: log.text, + data: logToMessageData(log), }); } } diff --git a/app/imports/server/discord/sendWebhook.js b/app/imports/server/discord/sendWebhook.js index 3ca1f4f6..a43594e9 100644 --- a/app/imports/server/discord/sendWebhook.js +++ b/app/imports/server/discord/sendWebhook.js @@ -1,27 +1,25 @@ import Discord from 'discord.js' -export default function sendWebhook({webhookURL, message, options}){ +export default function sendWebhook({webhookURL, data = {}}){ //webhookURL = https://discordapp.com/api/webhooks// let urlArray = webhookURL.split('/'); let token = urlArray.pop(); let id = urlArray.pop(); - + // prevent discord mention exploit - options.disableMentions = 'all'; - + data.disableMentions = 'all'; + const hook = new Discord.WebhookClient(id, token); // Send a message using the webhook - hook.send(message, options) + console.log(JSON.stringify(data, null, 2)); + hook.send(data); } -export function sendWebhookAsCreature({creature, content, embeds}){ +export function sendWebhookAsCreature({creature, data = {}}){ if (!creature || !creature.settings || !creature.settings.discordWebhook) return; + data.username = creature.name; + data.avatarURL = creature.avatarPicture; sendWebhook({ webhookURL: creature.settings.discordWebhook, - message: content, - options: { - username: creature.name, - avatarURL: creature.avatarPicture, - embeds, - }, + data, }); } diff --git a/app/imports/ui/log/LogEntry.vue b/app/imports/ui/log/LogEntry.vue index 82c5ff18..03b2efa9 100644 --- a/app/imports/ui/log/LogEntry.vue +++ b/app/imports/ui/log/LogEntry.vue @@ -1,26 +1,19 @@