const { game, getUser, saveGame, petBoost, getCoins, updateAll, getCPS, addCoins, commas} = require('./utils') const slack = require('../../slack') const maxValue = 10 const makePet = () => ({ food: 0, fun: 0, }) const bad = (text = '') => ` _^__^_ / x x \\${text && ` "${text}"`} >\\ o /< ---- ` const normal = (text = '') => ` _^__^_ / o o \\${text && ` "${text}"`} >\\ __ /< ---- ` const great = (text = '') => ` _^__^_ / ^ ^ \\${text && ` "${text}"`} >\\ \\__/ /< ---- ` const makeBar = (name, value) => { const left = '#'.repeat(value) const right = ' '.repeat(maxValue - value) return `${name}:`.padEnd(6) + `[${left}${right}]` } const buildBlocks = ({text}) => [ { type: 'section', text: { type: 'mrkdwn', text } }, { type: 'actions', elements: [ buildBlock('Feed'), buildBlock('Play'), ] }] const buildBlock = actionName => ( { type: 'button', text: { type: 'plain_text', text: actionName, emoji: true }, value: actionName, action_id: actionName } ) // game.channelPets ??= {} const petToText = (pet, additional, say) => { const stats = Object.values(pet) const hasTerribleStat = stats.filter(value => value < 1).length > 0 const averageStat = stats.reduce((total, current) => total + current, 0) / stats.length let pic if (hasTerribleStat && averageStat < 3) { pic = bad } else if (!hasTerribleStat && averageStat > 8) { pic = great } else { pic = normal } let speech if (pic === bad || Math.random() < 0.5) { speech = pic() } else { speech = pic('Mrow') } additional ??= '' if (additional) { additional = `\n${additional}\n` } const text = '```\n' + `Current HVAC Multiplier: ${petBoost()}x\n` + `${makeBar('Food', pet.food)}` + `\n${makeBar('Fun', pet.fun)}` + '\n' + speech + '```' + additional saveGame('pet generation') const ret = ({ text, blocks: buildBlocks({text}) }) // If there's a say() this is a new message, otherwise, we're editing. if (say) { say(ret).then(({ channel, ts }) => { // game.channelPets[channel] = ts return updateAll({ name: 'pet', add: { channel, ts }}) }).catch(console.error) } return ret } const updateEveryone = async additional => updateAll({ name: 'pet', ...petToText(game.pet, additional) }) const statDown = () => { const pet = (game.pet ??= makePet()) pet.food = Math.max(pet.food - 1, 0) pet.fun = Math.max(pet.fun - 1, 0) updateEveryone().catch(console.error) setTimeout(() => { Object.entries(game.users).forEach(([id, u]) => u.coins = getCoins(id)) statDown() }, 1000 * 60 * 90) // Every 90 minutes } statDown() const addInteraction = ({ actionId, perform }) => slack.app.action(actionId, async ({ body, ack, say, payload }) => { try { await ack() game.pet ??= makePet() const [everyone, local] = perform(game.pet, await getUser(body.user.id)) await updateEveryone(everyone) if (local) { await say(local) } } catch (e) { console.error(e) } }) const oneMinuteOfCps = user => Math.floor(getCPS(user) * 60) addInteraction({ actionId: 'Feed', perform: (pet, user) => { if (pet.food >= 10) { return [`I'm too full to eat more, ${user.name}!`] } const oneMinute = oneMinuteOfCps(user) addCoins(user, oneMinute) pet.food += 1 return [`Thanks for the grub, ${user.name}!`, `Earned ${commas(oneMinute)} HVAC for feeding our pet!`] } }) addInteraction({ actionId: 'Play', perform: (pet, user) => { if (pet.fun >= 10) { return [`I'm too tired for more games, ${user.name}.`] } const oneMinute = oneMinuteOfCps(user) addCoins(user, oneMinute) pet.fun += 1 return [`Thanks for playing, ${user.name}!`, `Earned ${commas(oneMinute)} HVAC for playing with our pet!`] }}) module.exports = { makePet, petToText }