Started work on character log for rolls to be stored

This commit is contained in:
Stefan Zermatten
2020-09-29 22:34:30 +02:00
parent 75ab43da00
commit a6a96fc19f
12 changed files with 190 additions and 45 deletions

View File

@@ -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({

View File

@@ -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,
});
}

View File

@@ -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,
});
}

View File

@@ -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);

View File

@@ -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};

View File

@@ -0,0 +1,24 @@
import Discord from 'discord.js'
export default function sendWebhook({webhookURL, message}){
//webhookURL = https://discordapp.com/api/webhooks/<id>/<token>
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,
}
});
}

View File

@@ -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);
}

View File

@@ -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},
}),
];
});
});

View File

@@ -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})"
/>
<text-field
label="Alignment"
:value="model.alignment"
:error-messages="errors.alignment"
:debounce-time="debounceTime"
:disabled="disabled"
@change="(value, ack) => $emit('change', {path: ['alignment'], value, ack})"
/>
<text-field
label="Gender"
:value="model.gender"
:error-messages="errors.gender"
:debounce-time="debounceTime"
:disabled="disabled"
@change="(value, ack) => $emit('change', {path: ['gender'], value, ack})"
/>
<text-field
@@ -29,8 +23,6 @@
hint="A link to a high resolution image"
:value="model.picture"
:error-messages="errors.picture"
:debounce-time="debounceTime"
:disabled="disabled"
@change="(value, ack) => $emit('change', {path: ['picture'], value, ack})"
/>
<text-field
@@ -38,8 +30,6 @@
hint="A link to a smaller, square image to use as an avatar"
:value="model.avatarPicture"
:error-messages="errors.avatarPicture"
:debounce-time="debounceTime"
:disabled="disabled"
@change="(value, ack) => $emit('change', {path: ['avatarPicture'], value, ack})"
/>
<form-sections>
@@ -47,7 +37,6 @@
<v-switch
label="Hide redundant stats"
:input-value="model.settings.hideUnusedStats"
:disabled="disabled"
@change="value => $emit('change', {path: ['settings','hideUnusedStats'], value: !!value})"
/>
<text-field
@@ -59,30 +48,32 @@
max="1"
step="0.1"
:value="model.settings.hitDiceResetMultiplier"
:debounce-time="debounceTime"
:disabled="disabled"
@change="(value, ack) => $emit('change', {path: ['settings','hitDiceResetMultiplier'], value, ack})"
/>
<text-field
label="Discord Webhook URL"
hint="This creature's logs will be posted to the discord channel"
placeholder="https://discordapp.com/api/webhooks/<id>/<token>"
:value="model.settings.discordWebhook"
@change="(value, ack) => $emit('change', {path: ['settings','discordWebhook'], value, ack})"
/>
<!--
<v-switch
label="Use variant encumbrance"
:input-value="model.settings.useVariantEncumbrance"
:error-messages="errors.useVariantEncumbrance"
:disabled="disabled"
@change="value => $emit('change', {path: ['settings','useVariantEncumbrance'], value})"
/>
<v-switch
label="Hide spells tab"
:input-value="model.settings.hideSpellcasting"
:error-messages="errors.hideSpellcasting"
:disabled="disabled"
@change="value => $emit('change', {path: ['settings','hideSpellcasting'], value})"
/>
<v-switch
label="Swap ability scores and modifiers"
:input-value="model.settings.swapStatAndModifier"
:error-messages="errors.swapStatAndModifier"
:disabled="disabled"
@change="value => $emit('change', {path: ['settings','swapStatAndModifier'], value})"
/>
-->
@@ -114,7 +105,6 @@ export default {
attackForm: {
type: Boolean,
},
debounceTime: Number,
disabled: Boolean,
},
};

View File

@@ -37,6 +37,9 @@
<v-tabs-items
v-model="activeTab"
>
<v-tab-item>
<log-tab :creature-id="creatureId" />
</v-tab-item>
<v-tab-item>
<stats-tab :creature-id="creatureId" />
</v-tab-item>
@@ -58,6 +61,19 @@
</v-tabs-items>
</div>
</v-fade-transition>
<v-snackbar
v-for="(snackbar, index) in snackbars"
:key="index"
v-model="snackbar.open"
>
{{ snackbar.text }}
<v-btn
flat
@click="snackbar.open = false"
>
Close
</v-btn>
</v-snackbar>
</div>
</template>
@@ -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: {

View File

@@ -91,6 +91,9 @@
max="100px"
@change="e => $emit('input', e)"
>
<v-tab>
Log
</v-tab>
<v-tab>
Stats
</v-tab>

View File

@@ -0,0 +1,36 @@
<template lang="html">
<div class="log layout column reverse">
<div
v-for="log in logs"
:key="log._id"
>
{{ log.text }}
</div>
</div>
</template>
<script>
import CreatureLogs from '/imports/api/creature/log/CreatureLogs.js';
export default {
props: {
creatureId: {
type: String,
required: true,
},
},
meteor: {
logs(){
return CreatureLogs.find({
creatureId: this.creatureId,
}, {
limit: 20,
sort: {date: -1},
});
},
},
}
</script>
<style lang="css" scoped>
</style>