194 lines
5.3 KiB
JavaScript
194 lines
5.3 KiB
JavaScript
const fs = require('fs')
|
|
const jokes = require('../jokes')
|
|
const achievements = require('./achievements');
|
|
const buyableItems = require("./buyableItems");
|
|
const upgrades = require("./upgrades");
|
|
const quackStore = require("./quackstore");
|
|
|
|
const saveFile = 'hvacoins.json'
|
|
|
|
const logError = msg => msg ? console.error(msg) : () => { /* Don't log empty message */ }
|
|
|
|
const loadGame = () => parseOr(fs.readFileSync('./' + saveFile, 'utf-8'),
|
|
() => ({
|
|
users: {},
|
|
nfts: [],
|
|
squad: {}
|
|
}))
|
|
|
|
const parseOr = (parseable, orFunc) => {
|
|
try {
|
|
return JSON.parse(parseable)
|
|
} catch (e) {
|
|
logError(e)
|
|
return orFunc()
|
|
}
|
|
}
|
|
|
|
let saves = 0
|
|
const saveGame = () => {
|
|
if (saves % 100 === 0) {
|
|
fs.writeFileSync('./backups/' + saveFile + new Date().toLocaleString().replace(/[^a-z0-9]/gi, '_'), JSON.stringify(game))
|
|
}
|
|
saves += 1
|
|
fs.writeFileSync('./' + 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 null
|
|
}
|
|
return word.substring(2, word.length - 1)
|
|
}
|
|
|
|
const getSeconds = () => new Date().getTime() / 1000
|
|
|
|
const commas = num => num.toLocaleString()
|
|
|
|
const game = loadGame()
|
|
const { users, nfts, squad } = game
|
|
|
|
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()
|
|
await say(`You earned the achievement ${achievements[achievementName].name}!`)
|
|
}, 500)
|
|
}
|
|
|
|
const getUser = userId => {
|
|
if (!users[userId]) {
|
|
users[userId] = {
|
|
coins: 0,
|
|
items: {},
|
|
upgrades: {},
|
|
achievements: {},
|
|
coinsAllTime: 0,
|
|
prestige: 0
|
|
}
|
|
} else {
|
|
users[userId].items ??= {}
|
|
users[userId].upgrades ??= {}
|
|
users[userId].achievements ??= {}
|
|
users[userId].coinsAllTime ??= users[userId].coins
|
|
users[userId].prestige ??= 0
|
|
}
|
|
return users[userId]
|
|
}
|
|
|
|
const getCoins = userId => {
|
|
const user = getUser(userId)
|
|
const currentTime = getSeconds()
|
|
const lastCheck = user.lastCheck || currentTime
|
|
const secondsPassed = currentTime - lastCheck
|
|
|
|
const increase = getCPS(userId) * secondsPassed
|
|
user.coins += increase
|
|
user.coinsAllTime += increase
|
|
user.coins = Math.floor(user.coins)
|
|
|
|
user.lastCheck = currentTime
|
|
setHighestCoins(userId)
|
|
saveGame()
|
|
return user.coins
|
|
}
|
|
|
|
const getCPS = userId => {
|
|
const user = getUser(userId)
|
|
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 => Math.ceil(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 => Math.ceil(cps * 1.2),
|
|
cost: 100_000_000_000_000,
|
|
emoji: 'printer'
|
|
}
|
|
}
|
|
|
|
const squadHas = ([name]) => squad.upgrades[name] === true
|
|
const squadIsMissing = name => !squadHas(name)
|
|
|
|
const getCompletedSquadgrades = () =>
|
|
Object.entries(squadUpgrades)
|
|
.filter(squadHas)
|
|
.map(([, upgrade]) => upgrade)
|
|
|
|
const singleItemCps = (user, itemName) => {
|
|
const baseCps = buyableItems[itemName].earning
|
|
|
|
const itemUpgrades = (user.upgrades[itemName] || []).map(name => upgrades[name])
|
|
const itemUpgradeCps = itemUpgrades.reduce((totalCps, upgrade) => upgrade.effect(totalCps, user), baseCps)
|
|
|
|
const userGeneralUpgrades = user.upgrades.general || []
|
|
const generalUpgradeCps = Object.entries(userGeneralUpgrades).reduce((total, [, upgradeName]) => upgrades[upgradeName].effect(total, user), itemUpgradeCps)
|
|
|
|
const achievementCount = Object.keys(user.achievements || {}).length
|
|
const achievementMultiplier = Math.pow(1.01, achievementCount)
|
|
|
|
const userQuackgrades = user.quackUpgrades?.cps || []
|
|
const quackMultiplier = userQuackgrades.reduce((total, upgrade) => quackStore[upgrade].effect(total, user), 1)
|
|
|
|
const prestigeMultiplier = 1 + ((user.prestige || 0) * 0.01)
|
|
|
|
return achievementMultiplier *
|
|
quackMultiplier *
|
|
prestigeMultiplier *
|
|
getCompletedSquadgrades().reduce((cps, upgrade) => upgrade.effect(cps), generalUpgradeCps)
|
|
}
|
|
|
|
module.exports = {
|
|
saveGame,
|
|
logError,
|
|
parseOr,
|
|
maybeNews,
|
|
idFromWord,
|
|
commas,
|
|
setHighestCoins,
|
|
addAchievement,
|
|
getCoins,
|
|
getUser,
|
|
singleItemCps,
|
|
getCPS,
|
|
getItemCps,
|
|
squadUpgrades,
|
|
squadIsMissing,
|
|
game
|
|
} |