diff --git a/app/imports/api/creature/Creatures.js b/app/imports/api/creature/Creatures.js index 26d82c54..654270c5 100644 --- a/app/imports/api/creature/Creatures.js +++ b/app/imports/api/creature/Creatures.js @@ -40,7 +40,12 @@ let CreatureSettingsSchema = new SimpleSchema({ optional: true, min: 0, max: 1, - } + }, + discordWebhook: { + type: String, + optional: true, + max: 200, + }, }); let CreatureSchema = new SimpleSchema({ diff --git a/app/imports/api/creature/actions/applyAction.js b/app/imports/api/creature/actions/applyAction.js index 356d85b7..f25a2213 100644 --- a/app/imports/api/creature/actions/applyAction.js +++ b/app/imports/api/creature/actions/applyAction.js @@ -1,5 +1,10 @@ import spendResources from '/imports/api/creature/actions/spendResources.js' +import {insertCreatureLog} from '/imports/api/creature/log/CreatureLogs.js'; -export default function applyAction({prop}){ +export default function applyAction({prop, creature}){ spendResources(prop); + insertCreatureLog({ + log: prop.name, + creature, + }); } diff --git a/app/imports/api/creature/actions/applyAttack.js b/app/imports/api/creature/actions/applyAttack.js index 677d58dc..ba02dc15 100644 --- a/app/imports/api/creature/actions/applyAttack.js +++ b/app/imports/api/creature/actions/applyAttack.js @@ -1,7 +1,5 @@ import math from '/imports/math.js'; -//if (Meteor.isServer){ -// var sendWebhook = require('/imports/server/discord/webhook.js').default; -//} +import {insertCreatureLog} from '/imports/api/creature/log/CreatureLogs.js'; export default function applyAttack({ prop, @@ -11,11 +9,8 @@ export default function applyAttack({ //actionContext }){ let result = math.roll(1, 20) + prop.rollBonusResult; - if (Meteor.isClient){ - console.log(`${creature.name} makes a ${prop.name} attack! Rolls ${result} to hit`); - } - //if (Meteor.isServer) sendWebhook({ - // webhook: creature.webhook, - // message: `${creature.name} makes a ${prop.name} attack! Rolls ${result} to hit`, - //}); + insertCreatureLog({ + log: `${prop.name} attack. ${result} to hit`, + creature, + }); } diff --git a/app/imports/api/creature/actions/applyProperties.js b/app/imports/api/creature/actions/applyProperties.js index 390c91f1..c3c95296 100644 --- a/app/imports/api/creature/actions/applyProperties.js +++ b/app/imports/api/creature/actions/applyProperties.js @@ -19,8 +19,8 @@ function applyProperty(options){ applyAction(options); return true; case 'attack': - applyAttack(options); applyAction(options); + applyAttack(options); return true; case 'damage': applyDamage(options); diff --git a/app/imports/api/creature/log/CreatureLogs.js b/app/imports/api/creature/log/CreatureLogs.js new file mode 100644 index 00000000..8d6d9e6b --- /dev/null +++ b/app/imports/api/creature/log/CreatureLogs.js @@ -0,0 +1,54 @@ +import SimpleSchema from 'simpl-schema'; +if (Meteor.isServer){ + var sendWebhookAsCreature = require('/imports/server/discord/sendWebhook.js').sendWebhookAsCreature; +} + +let CreatureLogs = new Mongo.Collection('creatureLogs'); + +let CreatureLogSchema = new SimpleSchema({ + text: { + type: String, + }, + type: { + type: String, + allowedValues: ['roll', 'change', 'damage', 'info'], + defaultValue: 'info', + }, + // The real-world date that it occured, usually sorted by date + date: { + type: Date, + autoValue: function() { + // If the date isn't set, set it to now + if (!this.isSet) { + return new Date(); + } + }, + index: 1, + }, + creatureId: { + type: String, + regEx: SimpleSchema.RegEx.Id, + index: 1, + }, +}); + +CreatureLogs.attachSchema(CreatureLogSchema); + +// This function should only be called by trusted code. No permission checks +const insertCreatureLog = function({log, creature}){ + if (typeof log === 'string'){ + log = {text: log}; + } + log.creatureId = creature._id; + let id = CreatureLogs.insert(log); + if (Meteor.isServer){ + sendWebhookAsCreature({ + creature, + content: log.text, + }); + } + return id; +}; + +export default CreatureLogs; +export { CreatureLogSchema, insertCreatureLog}; diff --git a/app/imports/server/discord/sendWebhook.js b/app/imports/server/discord/sendWebhook.js new file mode 100644 index 00000000..b89f9981 --- /dev/null +++ b/app/imports/server/discord/sendWebhook.js @@ -0,0 +1,24 @@ +import Discord from 'discord.js' +export default function sendWebhook({webhookURL, message}){ + //webhookURL = https://discordapp.com/api/webhooks// + let urlArray = webhookURL.split('/'); + let token = urlArray.pop(); + let id = urlArray.pop(); + // const hook = new Discord.WebhookClient(webhook.id, webhook.token); + const hook = new Discord.WebhookClient(id, token); + // Send a message using the webhook + hook.send(message); +} + +export function sendWebhookAsCreature({creature, content, embeds}){ + if (!creature || !creature.discordWebhook) return; + sendWebhook({ + webhookURL: creature.discordWebhook, + message: { + username: creature.name, + avatar_url: creature.avatarPicture, + content, + embeds, + } + }); +} diff --git a/app/imports/server/discord/webhook.js b/app/imports/server/discord/webhook.js deleted file mode 100644 index 3c4d1c25..00000000 --- a/app/imports/server/discord/webhook.js +++ /dev/null @@ -1,7 +0,0 @@ -import Discord from 'discord.js' -export default function sendWebhook({webhook, message}){ - // const hook = new Discord.WebhookClient(webhook.id, webhook.token); - const hook = new Discord.WebhookClient('420492135716880394', 'KHmRsf9QHd81C4LZOyQe_cUw5ua4ugSaIlpDMNWo3vcNHs0p0JBOHfeGWtHKqPXMYgkk'); - // Send a message using the webhook - hook.send(message); -} diff --git a/app/imports/server/publications/singleCharacter.js b/app/imports/server/publications/singleCharacter.js index 3f7d5a83..eaeee22e 100644 --- a/app/imports/server/publications/singleCharacter.js +++ b/app/imports/server/publications/singleCharacter.js @@ -1,6 +1,7 @@ import SimpleSchema from 'simpl-schema'; import Creatures from '/imports/api/creature/Creatures.js'; import CreatureProperties from '/imports/api/creature/CreatureProperties.js'; +import CreatureLogs from '/imports/api/creature/log/CreatureLogs.js'; let schema = new SimpleSchema({ creatureId: { @@ -28,6 +29,12 @@ Meteor.publish('singleCharacter', function(creatureId){ CreatureProperties.find({ 'ancestors.id': creatureId, }), + CreatureLogs.find({ + creatureId, + }, { + limit: 20, + sort: {date: -1}, + }), ]; }); }); diff --git a/app/imports/ui/creature/CreatureForm.vue b/app/imports/ui/creature/CreatureForm.vue index 9d2ee14a..303d8a4d 100644 --- a/app/imports/ui/creature/CreatureForm.vue +++ b/app/imports/ui/creature/CreatureForm.vue @@ -4,24 +4,18 @@ label="Name" :value="model.name" :error-messages="errors.name" - :debounce-time="debounceTime" - :disabled="disabled" @change="(value, ack) => $emit('change', {path: ['name'], value, ack})" /> @@ -47,7 +37,6 @@ + @@ -114,7 +105,6 @@ export default { attackForm: { type: Boolean, }, - debounceTime: Number, disabled: Boolean, }, }; diff --git a/app/imports/ui/creature/character/CharacterSheet.vue b/app/imports/ui/creature/character/CharacterSheet.vue index 4ce89b8a..c3eaaa38 100644 --- a/app/imports/ui/creature/character/CharacterSheet.vue +++ b/app/imports/ui/creature/character/CharacterSheet.vue @@ -37,6 +37,9 @@ + + + @@ -58,6 +61,19 @@ + + {{ snackbar.text }} + + Close + + @@ -65,6 +81,7 @@ //TODO add a "no character found" screen if shown on a false address // or on a character the user does not have permission to view import Creatures from '/imports/api/creature/Creatures.js'; + import LogTab from '/imports/ui/creature/character/characterSheetTabs/LogTab.vue'; import StatsTab from '/imports/ui/creature/character/characterSheetTabs/StatsTab.vue'; import FeaturesTab from '/imports/ui/creature/character/characterSheetTabs/FeaturesTab.vue'; import InventoryTab from '/imports/ui/creature/character/characterSheetTabs/InventoryTab.vue'; @@ -72,9 +89,11 @@ import PersonaTab from '/imports/ui/creature/character/characterSheetTabs/PersonaTab.vue'; import TreeTab from '/imports/ui/creature/character/characterSheetTabs/TreeTab.vue'; import { assertEditPermission } from '/imports/api/creature/creaturePermissions.js'; + import CreatureLogs from '/imports/api/creature/log/CreatureLogs.js'; export default { components: { + LogTab, StatsTab, FeaturesTab, InventoryTab, @@ -92,18 +111,13 @@ required: true, }, }, + data(){return { + snackbars: new Set(), + }}, reactiveProvide: { name: 'context', include: ['creature', 'editPermission'], }, - onMounted(){ - this.$store.commit('setPageTitle', this.creature && this.creature.name || 'Character Sheet'); - }, - watch: { - 'creature.name'(value){ - this.$store.commit('setPageTitle', value || 'Character Sheet'); - }, - }, computed: { activeTab: { get(){ @@ -113,6 +127,25 @@ this.$emit('update:tabs', newTab); }, }, + }, + watch: { + 'creature.name'(value){ + this.$store.commit('setPageTitle', value || 'Character Sheet'); + }, + }, + mounted(){ + this.$store.commit('setPageTitle', this.creature && this.creature.name || 'Character Sheet'); + let that = this; + let observer = CreatureLogs.find({ + creatureId: this.creatureId, + }).observe({ + added(doc){ + console.log({added: doc}); + that.snackbars.add(doc); + setTimeout(function(){that.snackbars.remove(doc)}, 8000); + }, + }); + console.log(observer); }, meteor: { $subscribe: { diff --git a/app/imports/ui/creature/character/CharacterSheetToolbar.vue b/app/imports/ui/creature/character/CharacterSheetToolbar.vue index 58f09555..98ba6b9a 100644 --- a/app/imports/ui/creature/character/CharacterSheetToolbar.vue +++ b/app/imports/ui/creature/character/CharacterSheetToolbar.vue @@ -91,6 +91,9 @@ max="100px" @change="e => $emit('input', e)" > + + Log + Stats diff --git a/app/imports/ui/creature/character/characterSheetTabs/LogTab.vue b/app/imports/ui/creature/character/characterSheetTabs/LogTab.vue new file mode 100644 index 00000000..d9e51ea7 --- /dev/null +++ b/app/imports/ui/creature/character/characterSheetTabs/LogTab.vue @@ -0,0 +1,36 @@ + + + + +