Switch to new command() routing.
This commit is contained in:
parent
a3c838438e
commit
b4ce41eb6a
|
@ -5,9 +5,31 @@ const buyableItems = require('./buyableItems')
|
|||
const upgrades = require('./upgrades')
|
||||
const achievements = require('./achievements')
|
||||
|
||||
const saveFile = './hvacoins.json'
|
||||
const saveFile = 'hvacoins.json'
|
||||
|
||||
const logError = msg => msg ? console.error(msg) : undefined
|
||||
const parseOr = (parseable, orFunc) => {
|
||||
try {
|
||||
return JSON.parse(parseable)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
return orFunc()
|
||||
}
|
||||
}
|
||||
|
||||
const game = parseOr(fs.readFileSync('./' + saveFile, 'utf-8'),
|
||||
() => ({ users: {}, nfts: [] }))
|
||||
const { users, nfts } = game
|
||||
|
||||
const logError = msg => msg ? console.error(msg) : () => {}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
const maybeNews = say => {
|
||||
const random = Math.random()
|
||||
|
@ -35,15 +57,27 @@ const helpText = (highestCoins, user) => Object.entries(buyableItems)
|
|||
'\n\nNote: Listed prices are _base costs_ and will increase as you buy more.'
|
||||
|
||||
const getUpgradeEmoji = upgrade => upgrade.emoji || buyableItems[upgrade.type].emoji
|
||||
const upgradeText = user =>
|
||||
(!user ? '' : '\n\n' + Object.entries(upgrades).filter(([upgradeName, upgrade]) => !hasUpgrade(user, upgrade, upgradeName)).filter(([, upgrade]) => upgrade.condition(user)).map(([key, value]) => `:${getUpgradeEmoji(value)}: *${key}* - ${commas(value.cost)}\n_${value.description}_`).join('\n\n')) +
|
||||
const upgradeText = user => {
|
||||
return (!user ? '' : '\n\n' + Object.entries(upgrades).filter(([upgradeName, upgrade]) => !hasUpgrade(user, upgrade, upgradeName)).filter(([, upgrade]) => upgrade.condition(user)).map(([key, value]) => `:${getUpgradeEmoji(value)}: *${key}* - ${commas(value.cost)}\n_${value.description}_`).join('\n\n')) +
|
||||
'\n\n:grey_question::grey_question::grey_question:' +
|
||||
'\n\nJust type \'!upgrade upgrade_name\' to purchase'
|
||||
}
|
||||
|
||||
const game = JSON.parse(fs.readFileSync(saveFile, 'utf-8'))
|
||||
const { users, nfts } = game
|
||||
|
||||
const saveGame = () => fs.writeFile(saveFile, JSON.stringify(game), logError)
|
||||
const getUser = userId => {
|
||||
if (!users[userId]) {
|
||||
users[userId] = {
|
||||
coins: 0,
|
||||
items: {},
|
||||
upgrades: {},
|
||||
achievements: {}
|
||||
}
|
||||
} else {
|
||||
users[userId].items ??= {}
|
||||
users[userId].upgrades ??= {}
|
||||
users[userId].achievements ??= {}
|
||||
}
|
||||
return users[userId]
|
||||
}
|
||||
|
||||
const getSeconds = () => new Date().getTime() / 1000
|
||||
|
||||
|
@ -65,33 +99,33 @@ const addAchievement = async (user, achievementName, say) => {
|
|||
await say(`You earned the achievement ${achievements[achievementName].name}!`)
|
||||
}
|
||||
|
||||
// I'm super not confident this will stay
|
||||
// What's nice is that it centralizes
|
||||
// * calling with event,say,words
|
||||
// * checking for words[1]==='help'
|
||||
const alwaysAccessible = () => true
|
||||
const adminOnly = userId => userId === slack.sageUserId
|
||||
|
||||
const commands = new Map()
|
||||
const command = (commandNames, helpText, action, condition) => {
|
||||
let commandHelpText = ''
|
||||
const command = (commandNames, helpText, action, hidden = false, condition = alwaysAccessible) => {
|
||||
if (!hidden) {
|
||||
commandHelpText += `\n${commandNames.toString().replace(/,/g, ', ')} - ${helpText}\n`
|
||||
}
|
||||
commandNames.forEach(name => commands.set(name, {
|
||||
commandNames,
|
||||
helpText,
|
||||
action,
|
||||
condition: condition || (() => true)
|
||||
condition,
|
||||
hidden
|
||||
}))
|
||||
}
|
||||
|
||||
command( // I don't like that command() is at the highest indentation level instead of the route name
|
||||
['!t', '!test'],
|
||||
'HelpText: Testing out new routing functionality',
|
||||
async ({ event, say, words }) => {// This extra indendation sucks
|
||||
await say('This is the route acton') // Also the function can't go after command() - not initialized
|
||||
}
|
||||
command(
|
||||
['!help', '!h'],
|
||||
'List available commands',
|
||||
async ({ say }) => await say('```' + commandHelpText + '```')
|
||||
)
|
||||
|
||||
slack.onMessage(async ({ event, say }) => {
|
||||
const words = event?.text?.split(/\s+/) || []
|
||||
const c = commands.get(words[0])
|
||||
if (event.user !== slack.sageUserId) {
|
||||
return // Don't do anything while this is incubating
|
||||
}
|
||||
if (!c?.condition(event.user)) {
|
||||
await say(`Command '${words[0]} not found'`)
|
||||
return
|
||||
|
@ -102,9 +136,11 @@ slack.onMessage(async ({ event, say }) => {
|
|||
}
|
||||
await c.action({ event, say, words })
|
||||
})
|
||||
// End of new command action
|
||||
|
||||
const listAchievements = async ({ event, say }) => {
|
||||
command(
|
||||
['!a', '!ach', '!achievements'],
|
||||
'List your glorious achievements',
|
||||
async ({ event, say }) => {
|
||||
const user = getUser(event.user)
|
||||
|
||||
const achievementCount = Object.keys(user.achievements).length
|
||||
|
@ -117,6 +153,7 @@ const listAchievements = async ({ event, say }) => {
|
|||
const postfix = achievementCount ? `\n\n_Achievements are boosting your CPS by ${mult.toPrecision(3)}%_` : ''
|
||||
await say(prefix + list + postfix)
|
||||
}
|
||||
)
|
||||
|
||||
const getItemCps = (user, itemName) => {
|
||||
const achievements = Object.keys(user.achievements || {}).length
|
||||
|
@ -143,7 +180,7 @@ const getCPS = userId => {
|
|||
}
|
||||
|
||||
const getCoins = userId => {
|
||||
const user = users[userId]
|
||||
const user = getUser(userId)
|
||||
const currentTime = getSeconds()
|
||||
const lastCheck = user.lastCheck || currentTime
|
||||
const secondsPassed = currentTime - lastCheck
|
||||
|
@ -156,13 +193,15 @@ const getCoins = userId => {
|
|||
return user.coins
|
||||
}
|
||||
|
||||
const mineCoinHelp = 'Mine HVAC coins: `!coin` or `!c`'
|
||||
const mineCoin = async ({ event, say, words }) => {
|
||||
command(['!cps'], 'Display your current Coins Per Second', async ({ event, say }) => {
|
||||
await say(`You are currently earning \`${commas(getCPS(event.user))}\` HVAC Coin per second.`)
|
||||
})
|
||||
|
||||
command(
|
||||
['!c', '!coin', '!mine'],
|
||||
'Mine HVAC coins',
|
||||
async ({ event, say }) => {
|
||||
const user = getUser(event.user)
|
||||
if (words[1] === 'help') {
|
||||
await say(mineCoinHelp)
|
||||
return
|
||||
}
|
||||
maybeNews(say)
|
||||
const random = Math.random()
|
||||
const c = getCoins(event.user)
|
||||
|
@ -191,50 +230,47 @@ const mineCoin = async ({ event, say, words }) => {
|
|||
await say(`${prefix}You now have ${commas(user.coins)} HVAC coin` + (c !== 0 ? 's' : '') + '. Spend wisely.')
|
||||
saveGame()
|
||||
}
|
||||
)
|
||||
|
||||
command(
|
||||
['!g', '!gamble'],
|
||||
'Gamble away your HVAC\n' +
|
||||
' To use, say \'gamble coin_amount\' or \'!gamble all\'',
|
||||
async ({ event, say, words }) => {
|
||||
getCoins(event.user) // Update coin counts
|
||||
const user = getUser(event.user)
|
||||
|
||||
const gambleCoinHelp = 'Gamble away your HVAC: `!gamble` or `!g`\n'+
|
||||
'To use, say `!gamble coin_amount` or `!gamble all`'
|
||||
const gambleCoin = async ({ event, say, words }) => {
|
||||
if (words[1] === 'help') {
|
||||
await say(gambleCoinHelp)
|
||||
return
|
||||
}
|
||||
if (!users[event.user]) {
|
||||
users[event.user] = {
|
||||
coins: 0
|
||||
}
|
||||
}
|
||||
let n
|
||||
let currentCoins = getCoins(event.user)
|
||||
if (words[1].toLowerCase() === 'all') {
|
||||
if (currentCoins === 0) {
|
||||
if (user.coins === 0) {
|
||||
await say('You don\'t have any coins!')
|
||||
return
|
||||
}
|
||||
n = currentCoins
|
||||
n = user.coins
|
||||
} else {
|
||||
n = parseInt(event.text.substring(7))
|
||||
n = parseInt(words[1])
|
||||
}
|
||||
if (!n || n < 0) {
|
||||
await say(`Invalid number '${n}'`)
|
||||
return
|
||||
}
|
||||
if (currentCoins < n) {
|
||||
await say(`You don\'t have that many coins! You have ${commas(currentCoins)}.`)
|
||||
if (user.coins < n) {
|
||||
await say(`You don\'t have that many coins! You have ${commas(user.coins)}.`)
|
||||
return
|
||||
}
|
||||
users[event.user].coins -= n
|
||||
user.coins -= n
|
||||
let outcome
|
||||
if (Math.random() > 0.5) {
|
||||
users[event.user].coins += (2 * n)
|
||||
user.coins += (2 * n)
|
||||
outcome = 'won'
|
||||
} else {
|
||||
outcome = 'lost'
|
||||
}
|
||||
console.log(`They ${outcome}`)
|
||||
await say(`You bet ${commas(n)} coins and ${outcome}! You now have ${commas(users[event.user].coins)}.`)
|
||||
await say(`You bet ${commas(n)} coins and ${outcome}! You now have ${commas(user.coins)}.`)
|
||||
saveGame()
|
||||
}
|
||||
)
|
||||
|
||||
const calculateCost = ({ itemName, user, quantity = 1 }) => {
|
||||
let currentlyOwned = user.items[itemName] || 0
|
||||
|
@ -246,16 +282,14 @@ const calculateCost = ({ itemName, user, quantity = 1 }) => {
|
|||
return realCost
|
||||
}
|
||||
|
||||
const buyNftHelp = 'Acquire high-quality art: `!buynft`\n'+
|
||||
'To use, say `!buynft nft_name`'
|
||||
const buyNft = async ({ event, say, words }) => {
|
||||
if (words[1] === 'help') {
|
||||
await say(buyNftHelp)
|
||||
return
|
||||
}
|
||||
command(
|
||||
['!buynft', '!bn'],
|
||||
'Acquire high-quality art\n' +
|
||||
' To use, say \'!buynft nft_name\'',
|
||||
async ({ event, say, words }) => {
|
||||
const nft = nfts.find(n => n.name.toLowerCase() === words[1])
|
||||
if (!nft) {
|
||||
const suffix = words[1].match(/[^a-z0-9]/i) ? '. And I\'m unhackable, so cut it out.' : ''
|
||||
const suffix = words[1]?.match(/[^a-z0-9]/i) ? '. And I\'m unhackable, so cut it out.' : ''
|
||||
await say('No NFT with that name found' + suffix)
|
||||
return
|
||||
}
|
||||
|
@ -274,30 +308,13 @@ const buyNft = async ({ event, say, words }) => {
|
|||
saveGame()
|
||||
await say('You bought ' + nft.name + '!')
|
||||
}
|
||||
)
|
||||
|
||||
const getUser = userId => {
|
||||
if (!users[userId]) {
|
||||
users[userId] = {
|
||||
coins: 0,
|
||||
items: {},
|
||||
upgrades: {},
|
||||
achievements: {}
|
||||
}
|
||||
} else {
|
||||
users[userId].items ??= {}
|
||||
users[userId].upgrades ??= {}
|
||||
users[userId].achievements ??= {}
|
||||
}
|
||||
return users[userId]
|
||||
}
|
||||
|
||||
const buyUpgradeHelp = 'Improve the performance of your HVAC-generators. `!upgrade` or `!u`\n'+
|
||||
'Say `!upgrade` to list available upgrades, or `!upgrade upgrade_name` to purchase.'
|
||||
const buyUpgrade = async ({ userId, say, words }) => {
|
||||
if (words[1] === 'help') {
|
||||
await say(buyUpgradeHelp)
|
||||
return
|
||||
}
|
||||
command(
|
||||
['!upgrade', '!u'],
|
||||
'Improve the performance of your HVAC-generators.\n' +
|
||||
' Say \'!upgrade\' to list available upgrades, or \'!upgrade upgrade_name\' to purchase.',
|
||||
async ({ userId, say, words }) => {
|
||||
const user = getUser(userId)
|
||||
const upgradeName = words[1]
|
||||
if (!upgradeName) {
|
||||
|
@ -330,14 +347,14 @@ const buyUpgrade = async ({ userId, say, words }) => {
|
|||
await saveGame()
|
||||
await say(`You bought ${upgradeName}!`)
|
||||
}
|
||||
)
|
||||
|
||||
const buyItemHelp = 'Buy new items to earn HVAC with: `!buy` or `!b`\n'+
|
||||
'Use `!buy` to list available items, and `!buy item_name optional_quantity` to get \'em.'
|
||||
const buyItem = async ({ event, say, words }) => {
|
||||
if (words[1] === 'help') {
|
||||
await say(buyItemHelp)
|
||||
return
|
||||
}
|
||||
command(
|
||||
['!buy', '!b'],
|
||||
'Buy new items to earn HVAC with\n' +
|
||||
' Use without arguments to list all available items.\n' +
|
||||
' Say \'!buy item_name optional_quantity\' to make your purchase.',
|
||||
async ({ event, say, words }) => {
|
||||
const user = getUser(event.user)
|
||||
const buying = words[1]
|
||||
const quantity = parseInt(words[2] || '1')
|
||||
|
@ -376,8 +393,13 @@ const buyItem = async ({ event, say, words }) => {
|
|||
}
|
||||
saveGame()
|
||||
}
|
||||
)
|
||||
|
||||
const getCoinCommand = async ({ target, say }) => {
|
||||
|
||||
command(
|
||||
['!check', '!ch'],
|
||||
'Check how many coins another player has',
|
||||
async ({ target, say }) => {
|
||||
if (!target?.startsWith('<@') || !target.endsWith('>')) {
|
||||
await say('Target must be a valid @')
|
||||
return
|
||||
|
@ -392,8 +414,15 @@ const getCoinCommand = async ({ target, say }) => {
|
|||
await say(`Hvacker owns ${humanMembers.length} souls.`)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const gift = async ({ userId, words, say }) => {
|
||||
|
||||
command(
|
||||
['!gift', '!give', '!gi'],
|
||||
'Donate coins to a fellow player\n' +
|
||||
' Send coins by saying \'!gift @player coin_amount\'',
|
||||
async ({ event, words, say }) => {
|
||||
const userId = event.user
|
||||
const user = getUser(userId)
|
||||
const [, target, amountText] = words
|
||||
const amount = amountText === 'all' ? (getCoins(userId)) : parseInt(amountText)
|
||||
|
@ -415,73 +444,66 @@ const gift = async ({ userId, words, say }) => {
|
|||
targetUser.coins += amount
|
||||
await say(`Gifted ${commas(amount)} HVAC to <@${targetId}>`)
|
||||
}
|
||||
)
|
||||
|
||||
slack.onMessage(async ({ event, say }) => {
|
||||
// if (event?.text?.startsWith('!') && event.user !== slack.sageUserId) {
|
||||
// await say('Hvacker is taking a quick nap.')
|
||||
// return
|
||||
// }
|
||||
const words = event?.text?.split(/\s+/) || []
|
||||
console.log(event?.text, 'by', slack?.ourUsers[event?.user], 'at', new Date().toLocaleTimeString())
|
||||
switch (words[0]) {
|
||||
case '!c':
|
||||
case '!coin':
|
||||
return mineCoin({ event, say, words })
|
||||
case '!g':
|
||||
case '!gamble':
|
||||
return gambleCoin({ event, say, words })
|
||||
case '!b':
|
||||
case '!buy': {
|
||||
return buyItem({event, say, words})
|
||||
}
|
||||
case '!u':
|
||||
case '!upgrade':
|
||||
return buyUpgrade({userId: event.user, say, words})
|
||||
case '!cps':
|
||||
return say(`You are currently earning \`${commas(getCPS(event.user))}\` HVAC Coin per second.`)
|
||||
case '!gift':
|
||||
case '!give':
|
||||
return gift({userId: event.user, words, say})
|
||||
case '!check':
|
||||
return getCoinCommand({target: words[1], say})
|
||||
case '!s':
|
||||
case '!status':
|
||||
return say(
|
||||
command(
|
||||
['!status', '!s'],
|
||||
'Print your current CPS, HVAC balance, and owned items',
|
||||
async ({ event, say }) => {
|
||||
await say(
|
||||
`You are currently earning \`${commas(getCPS(event.user))}\` HVAC Coin per second.\n\n` +
|
||||
`You currently have ${commas(getCoins(event.user))} HVAC Coins\n\n` +
|
||||
`${collection(event.user)}\n\n`
|
||||
)
|
||||
case '!a':
|
||||
return listAchievements({ event, say })
|
||||
case '!nfts':
|
||||
}
|
||||
)
|
||||
|
||||
command(
|
||||
['!nfts', '!nft', '!n'],
|
||||
'Show NFTs in the museum\n' +
|
||||
' Call with no arguments to list all NFTs, or \'!nft nft_name\' to show a particular one.',
|
||||
async ({ say, words }) => {
|
||||
const owner = nft => `Owner: *${slack.ourUsers[nft.owner] || 'NONE'}*`
|
||||
const nftDisplay = nft => `_"${nft.name}"_\n\n${nft.description}\n\n${commas(nft.price)} HVAC.\n\n${nft.picture}\n\n${owner(nft)}`
|
||||
|
||||
const filter = words[1] ? nft => words[1]?.toLowerCase() === nft.name : null
|
||||
|
||||
return say(nfts
|
||||
await say(nfts
|
||||
.filter(filter || (() => true))
|
||||
.map(nftDisplay)
|
||||
.join('\n-------------------------\n') || (filter ? 'No NFTs with that name exist' : 'No NFTs currently exist.')
|
||||
)
|
||||
case '!lb':
|
||||
}
|
||||
)
|
||||
|
||||
command(
|
||||
['!leaderboard', '!lb'],
|
||||
'Show the top HVAC-earners, ranked by CPS',
|
||||
async ({ event, say }) => {
|
||||
const user = getUser(event.user)
|
||||
return say('```' +
|
||||
await say('```' +
|
||||
Object.entries(users)
|
||||
.filter(([id]) => getCPS(id) !== 0)
|
||||
.sort(([id], [id2]) => getCPS(id) > getCPS(id2) ? -1 : 1)
|
||||
.map(([id]) => `${slack.ourUsers[id] || '???'} - ${commas(getCPS(id))} CPS - ${commas(getCoins(id))} HVAC`)
|
||||
.join('\n') + '```').then(() => addAchievement(user, 'leaderBoardViewer', say))
|
||||
case '!buynft':
|
||||
return buyNft({event, say, words})
|
||||
case '!ligma':
|
||||
return say(':hvacker_angery:')
|
||||
case '!pog':
|
||||
return say('<https://i.imgur.com/XCg7WDz.png|poggers>')
|
||||
}
|
||||
if (event.user === slack.sageUserId) {
|
||||
const firstWord = words[0]
|
||||
if (firstWord === '!addnft') {
|
||||
)
|
||||
|
||||
command(['!pog'], 'Displays a poggers hvacker', async ({ say }) => {
|
||||
await say('<https://i.imgur.com/XCg7WDz.png|poggers>')
|
||||
}, true)
|
||||
|
||||
command(['!ligma'], 'GRRRR', async ({ say }) => {
|
||||
await say(':hvacker_angery:')
|
||||
}, true)
|
||||
|
||||
command(
|
||||
['!addnft'],
|
||||
'Arguments 1 and 2 should be on the first line as name (one word!) and integer price.\n' +
|
||||
' The second line should be the description of the pieces\n' +
|
||||
' the picture is everything after the second line',
|
||||
async ({ event }) => {
|
||||
const [, name, price] = event.text.substring(0, event.text.indexOf('\n')).split(' ')
|
||||
const rest = event.text.substring(event.text.indexOf('\n') + 1)
|
||||
const desc = rest.substring(0, rest.indexOf('\n'))
|
||||
|
@ -496,19 +518,17 @@ slack.onMessage(async ({ event, say }) => {
|
|||
nfts.push(newNft)
|
||||
console.log('addedNft', newNft)
|
||||
return saveGame()
|
||||
} else if (firstWord === '!s') {
|
||||
}, true, adminOnly)
|
||||
|
||||
command(
|
||||
['!ss'],
|
||||
'Show the status for another player: !ss @player',
|
||||
async ({ words, say }) => {
|
||||
const target = words[1]
|
||||
const targetId = target.substring(2, target.length - 1)
|
||||
maybeNews(say)
|
||||
return say(
|
||||
await say(
|
||||
`${target} are currently earning \`${commas(getCPS(targetId))}\` HVAC Coin per second.\n\n` +
|
||||
`They currently have ${commas(getCoins(targetId))} HVAC Coins\n\n` +
|
||||
`${collection(targetId)}\n\n`
|
||||
)
|
||||
} else if (firstWord === '!updatenft') {
|
||||
const nft = nfts.find(n => n.name.toLowerCase() === 'quackers')
|
||||
nft.price *= 100
|
||||
return saveGame()
|
||||
}
|
||||
}
|
||||
})
|
||||
}, true, adminOnly)
|
Loading…
Reference in New Issue