Hvacker/src/games/hvacoins/utils.js

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
}