713 lines
19 KiB
JavaScript
713 lines
19 KiB
JavaScript
const { Pool } = require('pg')
|
|
const fs = require('fs')
|
|
const config = require('../../config')
|
|
const achievements = require('./achievements')
|
|
const buyableItems = require('./buyableItems')
|
|
const { quackStore, getChaos } = require('./quackstore')
|
|
|
|
const dbPool = new Pool(config.postgres)
|
|
|
|
let jokes
|
|
let slackUsers
|
|
const setSlackUsers = users => {
|
|
slackUsers = users
|
|
}
|
|
let upgrades
|
|
const setUpgrades = upg => {
|
|
upgrades = upg
|
|
}
|
|
|
|
const saveFile = 'hvacoins.json'
|
|
const saveDir = '/hvacker-saves/'
|
|
|
|
const logError = msg => msg ? console.error('logError: ', msg) : () => { /* Don't log empty message */ }
|
|
|
|
const loadGame = () => {
|
|
const game = parseOr(fs.readFileSync(saveDir + saveFile, 'utf-8'),
|
|
() => ({
|
|
users: {},
|
|
nfts: [],
|
|
squad: {},
|
|
horrors: {}
|
|
}))
|
|
game.horrors ??= {}
|
|
return game
|
|
}
|
|
|
|
const chaosFilter = (num, odds, user, max = Infinity, min = -Infinity) => {
|
|
const userQuackgrades = user.quackUpgrades?.cps || []
|
|
const hasChaos = userQuackgrades.includes('chaos')
|
|
if (!hasChaos || Math.random() < odds || !num) {
|
|
return num
|
|
}
|
|
const chaosed = num * getChaos(user)
|
|
if (chaosed > max) {
|
|
return max
|
|
}
|
|
if (chaosed < min) {
|
|
return min
|
|
}
|
|
return chaosed
|
|
}
|
|
|
|
const parseOr = (parseable, fallback) => {
|
|
try {
|
|
if (typeof parseable === 'function') {
|
|
parseable = parseable()
|
|
}
|
|
return JSON.parse(parseable)
|
|
} catch (e) {
|
|
logError(e)
|
|
return fallback()
|
|
}
|
|
}
|
|
|
|
let lastBackupTs = 0
|
|
const makeBackup = force => {
|
|
const currentTs = Date.now()
|
|
if (lastBackupTs > (currentTs - 60000) && !force) {
|
|
return
|
|
}
|
|
lastBackupTs = currentTs
|
|
const cleanNowString = new Date().toLocaleString().replace(/[^a-z0-9]/gi, '_')
|
|
const fileName = `${saveDir}backups/${cleanNowString}-${saveFile}`
|
|
console.log(`Making backup file: ${fileName}`)
|
|
fs.writeFileSync(fileName, JSON.stringify(game))
|
|
}
|
|
|
|
const saveUser = async (userId, user, after) => {
|
|
const name = user.name || userId
|
|
if (after) {
|
|
console.log(`SAVING ${name} after ${after}`)
|
|
} else {
|
|
console.log(`SAVING ${name}`, user)
|
|
}
|
|
return await dbPool.query(`
|
|
INSERT INTO hvacker_user (slack_id, name, data)
|
|
VALUES ($1, $2, $3)
|
|
ON CONFLICT (slack_id) DO UPDATE
|
|
SET data = EXCLUDED.data`
|
|
, [userId, user.name, user])
|
|
.catch(console.error)
|
|
}
|
|
|
|
const saveAllUsers = () => Promise.all(
|
|
Object.entries(game.users).map(async ([userId, user]) =>
|
|
await saveUser(userId, user)
|
|
)
|
|
).then(() => {
|
|
console.log('All users updated in the DB')
|
|
})
|
|
|
|
let saves = 0
|
|
const saveGame = (after, force = true, skipLog = false) => {
|
|
if (saves % 20 === 0) {
|
|
makeBackup()
|
|
saveAllUsers().catch(console.error)
|
|
}
|
|
saves += 1
|
|
if (force || saves % 10 === 0) {
|
|
if (!skipLog) {
|
|
if (after) {
|
|
console.log(`SAVING GAME after ${after}`)
|
|
} else {
|
|
console.log('SAVING GAME')
|
|
}
|
|
}
|
|
|
|
fs.writeFileSync(saveDir + saveFile, JSON.stringify(game, null, 2))
|
|
}
|
|
}
|
|
|
|
const maybeNews = say => {
|
|
const random = Math.random()
|
|
if (random > 0.98) {
|
|
const prefixedSay = msg => console.log(`Sent news update: '${msg}'`) || say('_Breaking news:_\n' + msg)
|
|
setTimeout(() => jokes.newsAlert(prefixedSay).catch(logError), 3000)
|
|
} else if (random > 0.96) {
|
|
setTimeout(async () => say('_Say have you heard this one?_'), 3000)
|
|
setTimeout(() => jokes.tellJoke(say).catch(logError), 4000)
|
|
}
|
|
}
|
|
|
|
const idFromWord = word => {
|
|
if (word?.startsWith('<#') && word.endsWith('>')) {
|
|
return word.replace(/<#([^|]*)|.*/g, '$1')
|
|
}
|
|
if (!word?.startsWith('<@') || !word.endsWith('>')) {
|
|
return getIdFromName(word)
|
|
} else {
|
|
return word.substring(2, word.length - 1)
|
|
}
|
|
}
|
|
|
|
const getSeconds = () => new Date().getTime() / 1000
|
|
|
|
const bigNumberWords = [
|
|
['tredecillion', 1_000_000_000_000_000_000_000_000_000_000_000_000_000_000],
|
|
['duodecillion', 1_000_000_000_000_000_000_000_000_000_000_000_000_000],
|
|
['undecillion', 1_000_000_000_000_000_000_000_000_000_000_000_000],
|
|
['decillion', 1_000_000_000_000_000_000_000_000_000_000_000],
|
|
['nonillion', 1_000_000_000_000_000_000_000_000_000_000],
|
|
['octillion', 1_000_000_000_000_000_000_000_000_000],
|
|
['septillion', 1_000_000_000_000_000_000_000_000],
|
|
['sextillion', 1_000_000_000_000_000_000_000],
|
|
['quintillion', 1_000_000_000_000_000_000],
|
|
['quadrillion', 1_000_000_000_000_000],
|
|
['trillion', 1_000_000_000_000],
|
|
['billion', 1_000_000_000],
|
|
['million', 1_000_000],
|
|
['qt', 1_000_000_000_000_000_000],
|
|
['qd', 1_000_000_000_000_000],
|
|
['tr', 1_000_000_000_000],
|
|
['b', 1_000_000_000],
|
|
['m', 1_000_000],
|
|
]
|
|
|
|
const commas = (num, precise = false, skipWords = false) => {
|
|
num = Math.round(num)
|
|
if (num === 1) {
|
|
return 'one'
|
|
}
|
|
const bigNum = bigNumberWords.find(([, base]) => num >= base)
|
|
if (bigNum && !precise) {
|
|
const [name, base] = bigNum
|
|
const nummed = (num / base).toPrecision(3)
|
|
if (skipWords) {
|
|
return nummed
|
|
}
|
|
return `${nummed} ${name}`
|
|
}
|
|
return num.toLocaleString()
|
|
}
|
|
|
|
const parseAll = (str, allNum, user) => {
|
|
if (!str) {
|
|
return NaN
|
|
}
|
|
|
|
str = str?.toLowerCase()?.replace(/,/g, '') || '1'
|
|
|
|
switch (str) {
|
|
case 'all':
|
|
case 'all in':
|
|
case 'everything':
|
|
case 'sugma':
|
|
case 'ligma':
|
|
case 'pulma':
|
|
case 'deez':
|
|
case 'max_int':
|
|
case 'my soul':
|
|
return allNum
|
|
case 'sex':
|
|
case 'sex number':
|
|
case 'nice':
|
|
return 69_000_000
|
|
case ':maple_leaf:':
|
|
case ':herb:':
|
|
case 'weed':
|
|
case 'weed number':
|
|
return 420_000_000
|
|
case 'a milli':
|
|
return 1_000_000
|
|
case 'a band':
|
|
return 1000
|
|
case ':100:':
|
|
case 'one hunna':
|
|
return 100
|
|
}
|
|
if (user && buyableItems[str]) {
|
|
return calculateCost({ itemName: str, user, quantity: 1 })
|
|
}
|
|
|
|
console.log('STR', str)
|
|
if (str.match(/^\d+$/)) {
|
|
return parseInt(str)
|
|
}
|
|
if (allNum && str.match(/^some$/)) {
|
|
return Math.floor(Math.random() * allNum)
|
|
}
|
|
if (allNum && str.match(/^\d+%$/)) {
|
|
const percent = parseFloat(str) / 100
|
|
if (percent > 1 || percent < 0) {
|
|
return NaN
|
|
}
|
|
return Math.round(percent * allNum)
|
|
}
|
|
|
|
if (str.match(/^\d+\.\d+$/)) {
|
|
return Math.round(parseFloat(str))
|
|
}
|
|
|
|
const bigNum = bigNumberWords.find(([name]) => str.endsWith(name))
|
|
if (bigNum && str.match(/^\d+(\.\d+)?/)) {
|
|
return Math.round(parseFloat(str) * bigNum[1])
|
|
}
|
|
|
|
return NaN
|
|
}
|
|
|
|
const calculateCost = ({ itemName, user, quantity = 1 }) => {
|
|
let currentlyOwned = user.items[itemName] || 0
|
|
let realCost = 0
|
|
for (let i = 0; i < quantity; i++) {
|
|
realCost += Math.ceil(buyableItems[itemName].baseCost * Math.pow(1.15, currentlyOwned || 0))
|
|
currentlyOwned += 1
|
|
}
|
|
return realCost
|
|
}
|
|
|
|
const game = loadGame()
|
|
let { users, nfts, squad } = game
|
|
|
|
const getAllUsers = async () => {
|
|
const result = await dbPool.query(`
|
|
SELECT slack_id, data
|
|
FROM hvacker_user
|
|
`).catch(console.error)
|
|
return Object.fromEntries(result.rows.map(
|
|
({ slack_id: slackId, data }) => [slackId, data]))
|
|
}
|
|
// getAllUsers().then(collection => {
|
|
// game.users = (users = collection)
|
|
// })
|
|
|
|
const setHighestCoins = userId => {
|
|
const prevMax = users[userId].highestEver || 0
|
|
if (prevMax < users[userId].coins) {
|
|
users[userId].highestEver = users[userId].coins
|
|
}
|
|
}
|
|
|
|
const addAchievement = (user, achievementName, say) => {
|
|
if (!achievements[achievementName]) {
|
|
logError(`Achievement ${achievementName} does not exist!`)
|
|
return
|
|
}
|
|
if (user.achievements[achievementName]) {
|
|
return
|
|
}
|
|
setTimeout(async () => {
|
|
user.achievements[achievementName] = true
|
|
saveGame(`${user.name} earned ${achievementName}`)
|
|
await say(`You earned the achievement ${achievements[achievementName].name}!`)
|
|
}, 500)
|
|
}
|
|
|
|
const fuzzyMatcher = string => new RegExp((string?.toLowerCase() || '').split('').join('.*'), 'i')
|
|
|
|
let knownUsers = {}
|
|
const getIdFromName = name => {
|
|
const matcher = fuzzyMatcher(name?.toLowerCase())
|
|
const found = Object.entries(knownUsers).find(([id, knownName]) => matcher.test(knownName?.toLowerCase()))
|
|
if (found) {
|
|
return found[0]
|
|
}
|
|
return null;
|
|
}
|
|
|
|
const fetchUser = async (userId, updateCoins = false) => {
|
|
const result = await dbPool.query(`
|
|
SELECT data
|
|
FROM hvacker_user
|
|
WHERE slack_id = $1`
|
|
, [userId])
|
|
.catch(console.error)
|
|
return result.rows[0]?.data
|
|
}
|
|
|
|
const getUser = async (userId, updateCoins = false) => {
|
|
// users[userId] = await fetchUser(userId)
|
|
// console.log('USER', users[userId])
|
|
//users[userId] = await fetchUser(userId)
|
|
return getUserSync(userId, updateCoins)
|
|
}
|
|
|
|
const getUserSync = (userId, updateCoins = false) => {
|
|
users[userId] ??= {}
|
|
users[userId].coins ??= 0
|
|
users[userId].items ??= {}
|
|
users[userId].upgrades ??= {}
|
|
users[userId].achievements ??= {}
|
|
users[userId].coinsAllTime ??= users[userId].coins
|
|
users[userId].prestige ??= 0
|
|
users[userId].startDate ??= new Date()
|
|
// users[userId].name ??= slack.users[userId]
|
|
if (updateCoins) {
|
|
users[userId].coins = getCoins(userId, users[userId])
|
|
}
|
|
saveGame('getUserSync()', true, true)
|
|
return users[userId]
|
|
}
|
|
|
|
const addCoins = (user, add) => {
|
|
user.coins += add
|
|
user.coinsAllTime += add
|
|
user.coinsAllTime = Math.floor(user.coinsAllTime)
|
|
user.coins = Math.floor(user.coins)
|
|
}
|
|
|
|
const getCoins = (userId, user) => {
|
|
user = user || getUserSync(userId)
|
|
const currentTime = getSeconds()
|
|
const lastCheck = user.lastCheck || currentTime
|
|
const secondsPassed = currentTime - lastCheck
|
|
|
|
addCoins(user, getCPS(user) * secondsPassed)
|
|
|
|
user.lastCheck = currentTime
|
|
setHighestCoins(userId)
|
|
//saveGame()
|
|
return user.coins
|
|
}
|
|
|
|
const getCPS = user => {
|
|
const userItems = user?.items || {}
|
|
return Math.round(Object.keys(userItems).reduce((total, itemName) => total + getItemCps(user, itemName), 0))
|
|
}
|
|
|
|
const getItemCps = (user, itemName) => (user.items[itemName] || 0) * singleItemCps(user, itemName)
|
|
|
|
const squadUpgrades = {
|
|
tastyKeyboards: {
|
|
name: 'Tasty Keyboards',
|
|
description: 'Delicious and sticky. Boosts CPS by 20% for everyone.',
|
|
|
|
effect: cps => cps * 1.2,
|
|
cost: 10_000_000_000_000,
|
|
emoji: 'keyboard'
|
|
},
|
|
copyPasteMacro: {
|
|
name: 'Copy-Paste Macro.',
|
|
description: 'Don\'t actually use this. Boosts CPS by 20% for everyone.',
|
|
effect: cps => cps * 1.2,
|
|
cost: 100_000_000_000_000,
|
|
emoji: 'printer'
|
|
},
|
|
discardHumanMorals: {
|
|
name: 'Neglect human decency',
|
|
description: `Unlocks a new tier of upgrades, but at what cost?`,
|
|
effect: cps => cps * 1.1,
|
|
cost: 100_000_000_000_000_000,
|
|
emoji: 'hole'
|
|
},
|
|
redemption: {
|
|
name: 'Redemption',
|
|
description: 'Can you return from the depths of depravity and save your soul?',
|
|
effect: cps => cps * 1.1,
|
|
cost: 1_000_000_000_000_000_000,
|
|
emoji: 'people_hugging'
|
|
}
|
|
}
|
|
|
|
const squadHas = ([name]) => squad.upgrades[name] === true
|
|
const squadIsMissing = name => !squadHas(name)
|
|
|
|
const getCompletedSquadgrades = () =>
|
|
Object.entries(squadUpgrades)
|
|
.filter(squadHas)
|
|
.map(([, upgrade]) => upgrade)
|
|
|
|
const getCompletedSquadgradeNames = () =>
|
|
Object.entries(squadUpgrades)
|
|
.filter(squadHas)
|
|
.map(([name]) => name)
|
|
|
|
const prestigeMultiplier = user => 1 + ((user.prestige || 0) * 0.01)
|
|
|
|
const quackGradeMultiplier = user => {
|
|
const userQuackgrades = user.quackUpgrades?.cps || []
|
|
return userQuackgrades.reduce((total, upgrade) => quackStore[upgrade].effect(total, user), 1)
|
|
}
|
|
|
|
const petQuackGradeMultiplier = user => {
|
|
const userQuackgrades = user.quackUpgrades?.pet || []
|
|
return userQuackgrades.reduce((total, upgrade) => quackStore[upgrade].effect(total, user), petBoost())
|
|
}
|
|
|
|
const singleItemCps = (user, itemName) => {
|
|
const baseCps = buyableItems[itemName].earning
|
|
// console.log('')
|
|
// console.log(`${itemName} CPS:`)
|
|
// console.log('baseCps', baseCps)
|
|
|
|
const itemUpgrades = (user.upgrades[itemName] || []).map(name => upgrades[name])
|
|
const itemUpgradeCps = itemUpgrades.reduce((totalCps, upgrade) => upgrade.effect(totalCps, user), 1)
|
|
// console.log('itemUpgradeCps', itemUpgradeCps)
|
|
|
|
user.upgrades.general ??= []
|
|
const userGeneralUpgrades = user.upgrades.general
|
|
const generalUpgradeCps = Object.entries(userGeneralUpgrades).reduce((total, [, upgradeName]) => upgrades[upgradeName].effect(total, user), 1)
|
|
// console.log('generalUpgradeCps', generalUpgradeCps)
|
|
|
|
const achievementCount = Object.keys(user.achievements || {}).length
|
|
const achievementMultiplier = Math.pow(1.01, achievementCount)
|
|
// console.log('achievementMultiplier', achievementMultiplier)
|
|
|
|
const quackGrade = quackGradeMultiplier(user)
|
|
// console.log('quackgrade', quackGrade)
|
|
|
|
const pMult = prestigeMultiplier(user)
|
|
// console.log('prestigeMultiplier', pMult)
|
|
|
|
const squadGradeMultiplier = getCompletedSquadgrades().reduce((cps, upgrade) => upgrade.effect(cps), 1)
|
|
// console.log('squadGradeMultiplier', squadGradeMultiplier)
|
|
|
|
const petMultiplier = petQuackGradeMultiplier(user)
|
|
//console.log('petMultiplier', petMultiplier)
|
|
|
|
const total =
|
|
baseCps *
|
|
achievementMultiplier *
|
|
itemUpgradeCps *
|
|
generalUpgradeCps *
|
|
quackGrade *
|
|
pMult *
|
|
squadGradeMultiplier *
|
|
petMultiplier
|
|
|
|
// console.log('Single Item CPS:', total)
|
|
|
|
return total
|
|
}
|
|
|
|
const shuffle = str => str.split('').sort(() => 0.5 - Math.random()).join('')
|
|
|
|
const shufflePercent = (str, percentOdds) => {
|
|
const shuffled = shuffle(str)
|
|
let partiallyShuffled = ''
|
|
const shuffleChar = () => Math.random() < percentOdds
|
|
|
|
let isEmoji = false
|
|
for (let i = 0; i < str.length; i++) {
|
|
if (str[i] === ':') {
|
|
isEmoji = !isEmoji
|
|
}
|
|
if (isEmoji) { // Less likely to shuffle emojis
|
|
partiallyShuffled += (shuffleChar() && shuffleChar()) ? shuffled[i] : str[i]
|
|
} else {
|
|
partiallyShuffled += shuffleChar() ? shuffled[i] : str[i]
|
|
}
|
|
}
|
|
|
|
return partiallyShuffled
|
|
}
|
|
|
|
const definitelyShuffle = (str, percentOdds) => {
|
|
if (!str || str.length === 1) {
|
|
return str
|
|
}
|
|
if (!percentOdds) {
|
|
percentOdds = 0.01
|
|
}
|
|
let shuffled = str
|
|
while (shuffled === str) {
|
|
shuffled = shufflePercent(str, percentOdds)
|
|
console.log('Shuffling... "' + shuffled + '"')
|
|
}
|
|
return shuffled
|
|
}
|
|
|
|
const getRandomFromArray = array => array[Math.floor(Math.random() * array.length)]
|
|
|
|
/**
|
|
* Adds reactions to the given message, in order.
|
|
* If adding any reaction is a failure, it will continue on to the next.
|
|
*
|
|
* @param app The slack bolt app
|
|
* @param channelId The id of the channel the message is in
|
|
* @param timestamp The timestamp of the message
|
|
* @param reactions An array of reactions to add
|
|
* @returns {Promise<void>}
|
|
*/
|
|
const addReactions = async ({ app, channelId, timestamp, reactions }) => {
|
|
for (const reaction of reactions) {
|
|
try {
|
|
await app.client.reactions.add({
|
|
channel: channelId,
|
|
timestamp,
|
|
name: reaction
|
|
})
|
|
} catch (e) {
|
|
logError(e)
|
|
}
|
|
}
|
|
}
|
|
|
|
const removeReactions = async ({ app, channelId, timestamp, reactions }) => {
|
|
for (const reaction of reactions) {
|
|
try {
|
|
await app.client.reactions.remove({
|
|
channel: channelId,
|
|
timestamp,
|
|
name: reaction
|
|
})
|
|
} catch (e) {
|
|
logError(e)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
const daysSinceEpoch = () => {
|
|
const today = new Date().getTime()
|
|
const epoch = new Date(0).getTime()
|
|
return Math.floor((today - epoch) / (1000 * 60 * 60 * 24))
|
|
}
|
|
|
|
const dayOfYear = () => {
|
|
const date = new Date()
|
|
return ((Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) - Date.UTC(date.getFullYear(), 0, 0)) / 24 / 60 / 60 / 1000)
|
|
}
|
|
|
|
game.stonkMarket ??= {
|
|
lastDay: daysSinceEpoch(),
|
|
stonks: {
|
|
duk: {
|
|
pattern: "duk",
|
|
index: 0,
|
|
price: 1_410_911_983_728
|
|
},
|
|
quak: {
|
|
pattern: "quak",
|
|
index: 0,
|
|
price: 5_111_242_778_696
|
|
},
|
|
honk: {
|
|
pattern: "honk",
|
|
index: 0,
|
|
price: 511_915_144_009
|
|
},
|
|
}
|
|
}
|
|
|
|
const userHasCheckedQuackgrade = (user, quackGrade) => (user.quackUpgrades?.checked || []).includes(quackGrade)
|
|
|
|
const petBoost = () => {
|
|
// game.pet ??= makePet()
|
|
const stats = Object.values(game.pet)
|
|
const hasTerribleStat = stats.filter(value => value < 1).length > 0
|
|
const averageStat = stats.reduce((total, current) => total + current, 0) / stats.length
|
|
|
|
if (hasTerribleStat && averageStat < 3) {
|
|
return 0.9
|
|
}
|
|
|
|
if (averageStat === 10) {
|
|
return 1.3
|
|
}
|
|
|
|
if (!hasTerribleStat && averageStat > 8) {
|
|
return 1.1
|
|
}
|
|
|
|
return 1
|
|
}
|
|
|
|
game.channelMaps ??= {}
|
|
let slackAppClientChatUpdate
|
|
|
|
/**
|
|
*
|
|
* @param name String name for this channel map
|
|
* @param text String of to send. Passed into slack.app.client.chat.update
|
|
* @param blocks Slack blocks object to send. Passed into slack.app.client.chat.update
|
|
* @param channel An (optional) new channel to add to the given map
|
|
* @param ts The timestamp of the message in the new channel to update
|
|
*/
|
|
const updateAll = async ({ name, text, blocks, add: { channel, ts } = {} }) => {
|
|
const channelMap = (game.channelMaps[name] ??= {})
|
|
// if (channel && ts && !channelMap[channel]) {
|
|
// }
|
|
if (channel && ts) {
|
|
channelMap[channel] = ts
|
|
console.log({ channelMap })
|
|
}
|
|
if (text || blocks) {
|
|
await Promise.all(Object.entries(channelMap).map(async ([channel, ts]) =>
|
|
slackAppClientChatUpdate({
|
|
channel,
|
|
ts,
|
|
text,
|
|
blocks
|
|
}).catch(e => {
|
|
console.error(e)
|
|
if (e.toString().includes('message_not_found')) {
|
|
delete channelMap[channel]
|
|
saveGame(`removing message ${channel}::${ts} from the ${name} list`)
|
|
}
|
|
})
|
|
))
|
|
}
|
|
|
|
// // const alreadyHas = !!channelMap[channel]
|
|
// if (channel && ts) {
|
|
// channelMap[channel] = ts
|
|
// console.log({ channelMap })
|
|
// }
|
|
// // return alreadyHas
|
|
}
|
|
|
|
const logMemoryUsage = name => {
|
|
const formatMemoryUsage = (data) => `${Math.round(data / 1024 / 1024 * 100) / 100} MB`;
|
|
|
|
const memoryData = process.memoryUsage();
|
|
const formattedData = {
|
|
rss: `${formatMemoryUsage(memoryData.rss)} -> Resident Set Size - total memory allocated for the process execution`,
|
|
// heapTotal: `${formatMemoryUsage(memoryData.heapTotal)} -> total size of the allocated heap`,
|
|
// heapUsed: `${formatMemoryUsage(memoryData.heapUsed)} -> actual memory used during the execution`,
|
|
// external: `${formatMemoryUsage(memoryData.external)} -> V8 external memory`,
|
|
}
|
|
if (name) {
|
|
console.log(name, formattedData)
|
|
} else {
|
|
console.log(formattedData)
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
saveGame,
|
|
saveUser,
|
|
makeBackup,
|
|
logError,
|
|
parseOr,
|
|
maybeNews,
|
|
idFromWord,
|
|
commas,
|
|
setHighestCoins,
|
|
addAchievement,
|
|
getCoins,
|
|
getUser,
|
|
getUserSync,
|
|
singleItemCps,
|
|
getCPS,
|
|
getItemCps,
|
|
squadUpgrades,
|
|
squadIsMissing,
|
|
prestigeMultiplier,
|
|
quackGradeMultiplier,
|
|
shufflePercent,
|
|
definitelyShuffle,
|
|
parseAll,
|
|
getRandomFromArray,
|
|
chaosFilter,
|
|
addReactions,
|
|
removeReactions,
|
|
getCompletedSquadgradeNames,
|
|
game,
|
|
dayOfYear,
|
|
daysSinceEpoch,
|
|
userHasCheckedQuackgrade,
|
|
fuzzyMatcher,
|
|
addCoins,
|
|
calculateCost,
|
|
setKnownUsers: users => knownUsers = users,
|
|
petBoost,
|
|
updateAll,
|
|
setSlackAppClientChatUpdate: update => slackAppClientChatUpdate = update,
|
|
setUpgrades,
|
|
setSlackUsers,
|
|
setJokes: _jokes => jokes = _jokes,
|
|
logMemoryUsage
|
|
}
|