Card APIs, new poll triggers, and other small additions
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 47 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 203 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 210 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 255 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 242 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 257 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 260 KiB |
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 273 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 197 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 279 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 191 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 238 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 201 KiB |
After Width: | Height: | Size: 40 KiB |
|
@ -15,6 +15,7 @@ const {
|
||||||
getRandomFromArray,
|
getRandomFromArray,
|
||||||
chaosFilter,
|
chaosFilter,
|
||||||
addReactions,
|
addReactions,
|
||||||
|
removeReactions,
|
||||||
setHighestCoins,
|
setHighestCoins,
|
||||||
definitelyShuffle,
|
definitelyShuffle,
|
||||||
getCompletedSquadgradeNames,
|
getCompletedSquadgradeNames,
|
||||||
|
@ -29,6 +30,10 @@ const {
|
||||||
const { nfts, squad, users, horrors, stonkMarket, pet } = game
|
const { nfts, squad, users, horrors, stonkMarket, pet } = game
|
||||||
const pets = require('./gotcha')
|
const pets = require('./gotcha')
|
||||||
|
|
||||||
|
const exec = require('child_process').exec
|
||||||
|
const { createReadStream, createWriteStream, existsSync, readFileSync} = require('fs')
|
||||||
|
const { readdir } = require('fs/promises')
|
||||||
|
|
||||||
const slack = require('../../slack')
|
const slack = require('../../slack')
|
||||||
const buyableItems = require('./buyableItems')
|
const buyableItems = require('./buyableItems')
|
||||||
const upgrades = require('./upgrades')
|
const upgrades = require('./upgrades')
|
||||||
|
@ -38,6 +43,7 @@ const prestige = require('./prestige')
|
||||||
const lore = require('./lore')
|
const lore = require('./lore')
|
||||||
const { getChaos, quackStore } = require('./quackstore')
|
const { getChaos, quackStore } = require('./quackstore')
|
||||||
const settings = require('./settings')
|
const settings = require('./settings')
|
||||||
|
const https = require('https')
|
||||||
|
|
||||||
// const readline = require('readline').createInterface({
|
// const readline = require('readline').createInterface({
|
||||||
// input: process.stdin,
|
// input: process.stdin,
|
||||||
|
@ -74,6 +80,7 @@ const upgradeText = (user, showOwned = false) => {
|
||||||
const hasUpgrade = (user, upgrade, upgradeName) => !!user.upgrades[upgrade.type]?.includes(upgradeName)
|
const hasUpgrade = (user, upgrade, upgradeName) => !!user.upgrades[upgrade.type]?.includes(upgradeName)
|
||||||
|
|
||||||
const alwaysAccessible = () => true
|
const alwaysAccessible = () => true
|
||||||
|
const alwaysAlwaysAccessible = () => true
|
||||||
const adminOnly = {
|
const adminOnly = {
|
||||||
hidden: true,
|
hidden: true,
|
||||||
condition: ({ event, say }) => {
|
condition: ({ event, say }) => {
|
||||||
|
@ -167,6 +174,147 @@ const getHorrorMessageOdds = (offset = 0) => {
|
||||||
return (shuffleOdds * shuffleOdds) / 3
|
return (shuffleOdds * shuffleOdds) / 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const postCard = async (event, name, fileName) =>
|
||||||
|
slack.app.client.files.upload({
|
||||||
|
channels: event.channel,
|
||||||
|
initial_comment: name,
|
||||||
|
file: createReadStream(fileName)
|
||||||
|
})
|
||||||
|
|
||||||
|
const cardGames = {
|
||||||
|
digimon: {
|
||||||
|
names: ['!digimon', '!digi'],
|
||||||
|
help: 'Search for Digimon cards: !digi <card name>',
|
||||||
|
fetch: async name => `https://digimoncard.io/api-public/search.php?n=${name}`,
|
||||||
|
getCardData: data => data,
|
||||||
|
getCardName: card => card.name,
|
||||||
|
getCardImageUrl: card => card.image_url
|
||||||
|
},
|
||||||
|
pokemon: {
|
||||||
|
names: ['!pokemon', '!poke', '!pok', '!yugioh', '!ygo'],
|
||||||
|
help: 'Search for Pokemon cards: !pok <card name>',
|
||||||
|
fetch: async name => `https://api.pokemontcg.io/v2/cards?q=name:${name}`,
|
||||||
|
getCardData: ({ data }) => data,
|
||||||
|
getCardName: card => card.name,
|
||||||
|
getCardImageUrl: card => card.images.large
|
||||||
|
},
|
||||||
|
yugioh: {
|
||||||
|
names: [],
|
||||||
|
help: 'Search for Yu-Gi-Oh cards: !ygo <card name>',
|
||||||
|
fetch: async name => {
|
||||||
|
const url = `https://db.ygoprodeck.com/api/v7/cardinfo.php?fname=${name}`;
|
||||||
|
console.log('yugioh url', url)
|
||||||
|
return url
|
||||||
|
},
|
||||||
|
getCardData: ({ data }) => data,
|
||||||
|
getCardName: card => card.name,
|
||||||
|
getCardImageUrl: card => card.card_images[0].image_url
|
||||||
|
},
|
||||||
|
lotrOld: {
|
||||||
|
names: ['!lotrOld'],
|
||||||
|
help: 'Search for Lord of the Rings cards: !lotrOld <card name>',
|
||||||
|
cards: async () => JSON.parse(readFileSync('lotrOld/lotr_cards.json').toString()),
|
||||||
|
fetch: async name => ({ json: () => {
|
||||||
|
const matcher = fuzzyMatcher(name?.toLowerCase())
|
||||||
|
const exact = cardGames.lotrOld.cards.filter(card => card.name?.toLowerCase() === name.toLowerCase())
|
||||||
|
if (exact.length) {
|
||||||
|
return exact
|
||||||
|
}
|
||||||
|
return cardGames.lotrOld.cards.filter(card => matcher.test(card.name))
|
||||||
|
} }),
|
||||||
|
getCardData: data => data,
|
||||||
|
getCardName: card => card.name,
|
||||||
|
getCardImageUrl: card => 'https://ringsdb.com' + card.imagesrc
|
||||||
|
},
|
||||||
|
lotr: {
|
||||||
|
names: ['!lotr'],
|
||||||
|
help: 'Search for Lord of the Rings cards: !lotr <card name>',
|
||||||
|
cards: async () => JSON.parse(readFileSync('lotr/cards.json').toString()),
|
||||||
|
fetch: async name => ({ json: () => {
|
||||||
|
const matcher = fuzzyMatcher(name?.toLowerCase())
|
||||||
|
const exact = cardGames.lotr.cards.filter(card => card.name?.toLowerCase() === name.toLowerCase())
|
||||||
|
if (exact.length) {
|
||||||
|
return [exact[0]]
|
||||||
|
}
|
||||||
|
return cardGames.lotr.cards.filter(card => matcher.test(card.name)).filter(card => !card.name.includes('('))
|
||||||
|
} }),
|
||||||
|
getCardData: data => data,
|
||||||
|
getCardName: card => card.name,
|
||||||
|
getCardImageUrl: card => 'https://lotrtcgwiki.com/wiki/_media/cards:' + card.id + '.jpg'
|
||||||
|
},
|
||||||
|
playingCards: {
|
||||||
|
names: ['!playing', '!pc'],
|
||||||
|
help: 'Search for playing cards cards: !pc <card name>',
|
||||||
|
cards: async () => readdir('playingCards')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.entries(cardGames).forEach(async ([gameName, cardGame]) => {
|
||||||
|
if (cardGame.cards) {
|
||||||
|
cardGame.cards = await cardGame.cards()
|
||||||
|
}
|
||||||
|
command(
|
||||||
|
cardGame.names,
|
||||||
|
cardGame.help,
|
||||||
|
async ({ args, event, say }) => {
|
||||||
|
const arg = args?.join(' ')
|
||||||
|
if (!args?.length || !arg) {
|
||||||
|
return say('Please specify a card name!')
|
||||||
|
}
|
||||||
|
if (cardGame.cards && !cardGame.fetch) {
|
||||||
|
const fileName = cardGame.cards.find(name => name?.toLowerCase().replaceAll(/_/g, ' ').startsWith(arg.toLowerCase()))
|
||||||
|
if (fileName) {
|
||||||
|
return postCard(event, fileName.replaceAll(/_/g, ' ').replaceAll('.png', ''), gameName + '/' + fileName)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let response = await cardGame.fetch(arg)
|
||||||
|
if (typeof response === 'string') {
|
||||||
|
response = await fetch(response)
|
||||||
|
}
|
||||||
|
const json = await response.json()
|
||||||
|
const data = cardGame.getCardData(json)
|
||||||
|
if (!data?.length) {
|
||||||
|
return say(`Found no ${gameName} cards named '${arg}'`)
|
||||||
|
}
|
||||||
|
if (!(data.length === 1 || data[0].name.toLowerCase() === arg.toLowerCase())) {
|
||||||
|
const firstFew = data.slice(0, 4)
|
||||||
|
const cardNames = firstFew.map(card => '• ' + cardGame.getCardName(card)).join('\n')
|
||||||
|
if (firstFew.length === data.length) {
|
||||||
|
return say(`Found ${data.length} cards matching '${arg}':\n${cardNames}`)
|
||||||
|
}
|
||||||
|
return say(`Found ${data.length} cards matching '${arg}', including\n${cardNames}`)
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const card = data[0]
|
||||||
|
const name = cardGame.getCardName(card)
|
||||||
|
const fileName = gameName + '/' + name
|
||||||
|
if (existsSync(fileName)) {
|
||||||
|
console.log(`Using cached file: ${fileName}`)
|
||||||
|
return postCard(event, name, fileName)
|
||||||
|
}
|
||||||
|
const file = createWriteStream(fileName)
|
||||||
|
https.get(cardGame.getCardImageUrl(card), response => {
|
||||||
|
response.pipe(file)
|
||||||
|
file.on('finish', async () => {
|
||||||
|
await file.close()
|
||||||
|
console.log(event.channel)
|
||||||
|
await postCard(event, name, fileName)
|
||||||
|
}).on('error', err => {
|
||||||
|
console.error(err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
hidden: false,
|
||||||
|
condition: alwaysAlwaysAccessible
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
command(
|
command(
|
||||||
['!odds'],
|
['!odds'],
|
||||||
'Show shuffle odds re: !horror',
|
'Show shuffle odds re: !horror',
|
||||||
|
@ -188,6 +336,16 @@ command(
|
||||||
)
|
)
|
||||||
}, adminOnly)
|
}, adminOnly)
|
||||||
|
|
||||||
|
command(
|
||||||
|
['!in'],
|
||||||
|
'!in <channel> <message>',
|
||||||
|
async ({ args, event }) => {
|
||||||
|
const channel = idFromWord(args[0])
|
||||||
|
const text = event.text.substring(event.text.indexOf('>') + 1)
|
||||||
|
return slack.app.client.chat.postMessage({ channel, text })
|
||||||
|
}, adminOnly
|
||||||
|
)
|
||||||
|
|
||||||
command(
|
command(
|
||||||
['!shuffle'],
|
['!shuffle'],
|
||||||
'!shuffle daysFromNow message',
|
'!shuffle daysFromNow message',
|
||||||
|
@ -373,7 +531,7 @@ const messageHandler = async ({ event, say, isRecycle = false, skipCounting }) =
|
||||||
const [commandName, ...args] = words
|
const [commandName, ...args] = words
|
||||||
const c = commands.get(commandName)
|
const c = commands.get(commandName)
|
||||||
let user = getUser(event.user)
|
let user = getUser(event.user)
|
||||||
if (user.isDisabled) {
|
if (user.isDisabled && c.condition !== alwaysAlwaysAccessible) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
user.name = slack.users[event.user]
|
user.name = slack.users[event.user]
|
||||||
|
@ -421,7 +579,7 @@ const messageHandler = async ({ event, say, isRecycle = false, skipCounting }) =
|
||||||
})
|
})
|
||||||
say = async msg => {
|
say = async msg => {
|
||||||
let icon_url = userInfo.user.profile.image_original
|
let icon_url = userInfo.user.profile.image_original
|
||||||
if (game.cursedPics[event.user]?.length > 0) {
|
if (game.cursedPics && game.cursedPics[event.user]?.length > 0) {
|
||||||
icon_url = getRandomFromArray(game.cursedPics[event.user])
|
icon_url = getRandomFromArray(game.cursedPics[event.user])
|
||||||
}
|
}
|
||||||
trueSay({
|
trueSay({
|
||||||
|
@ -951,7 +1109,6 @@ const doMine = async ({ user, userId, say }) => {
|
||||||
} else {
|
} else {
|
||||||
const miningUpgrades = (user.upgrades.mining || []).map(name => upgrades[name])
|
const miningUpgrades = (user.upgrades.mining || []).map(name => upgrades[name])
|
||||||
diff = miningUpgrades.reduce((total, upgrade) => upgrade.effect(total, user), 1)
|
diff = miningUpgrades.reduce((total, upgrade) => upgrade.effect(total, user), 1)
|
||||||
console.log({ miningUpgrades, diff, user: user.upgrades.mining })
|
|
||||||
prefix = `You mined ${commas(diff)} HVAC.\n`
|
prefix = `You mined ${commas(diff)} HVAC.\n`
|
||||||
}
|
}
|
||||||
addCoins(user, diff)
|
addCoins(user, diff)
|
||||||
|
@ -971,6 +1128,14 @@ command(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
command(
|
||||||
|
['!save'],
|
||||||
|
'View your savefile',
|
||||||
|
async ({ say, user }) => {
|
||||||
|
say('Look, it\'s you! Formatting is ugly because long texts get split up by Slack :[\n```\n' + JSON.stringify(user) + '\n```')
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
command(
|
command(
|
||||||
['!as'],
|
['!as'],
|
||||||
'Run commands as another user.',
|
'Run commands as another user.',
|
||||||
|
@ -985,23 +1150,6 @@ command(
|
||||||
users[event.user].isDisabled = isDisabled
|
users[event.user].isDisabled = isDisabled
|
||||||
}, adminOnly)
|
}, adminOnly)
|
||||||
|
|
||||||
command(
|
|
||||||
['!react'],
|
|
||||||
'!react <emoji> <timestamp>',
|
|
||||||
async ({ args }) => {
|
|
||||||
const [emoji, timestamp] = args
|
|
||||||
console.log('args:', args)
|
|
||||||
try {
|
|
||||||
await slack.app.client.reactions.add({
|
|
||||||
channel: slack.temperatureChannelId,
|
|
||||||
timestamp,
|
|
||||||
name: emoji.replace(/:/g, '')
|
|
||||||
})
|
|
||||||
} catch (e) {
|
|
||||||
console.error('!react error', e)
|
|
||||||
}
|
|
||||||
}, adminOnly)
|
|
||||||
|
|
||||||
command(
|
command(
|
||||||
['!enable'],
|
['!enable'],
|
||||||
'Enable the given user',
|
'Enable the given user',
|
||||||
|
@ -1041,7 +1189,7 @@ command(
|
||||||
}
|
}
|
||||||
const argText = args.join(' ')
|
const argText = args.join(' ')
|
||||||
const requestedWager = parseAll(argText, user.coins, user)
|
const requestedWager = parseAll(argText, user.coins, user)
|
||||||
const n = (chaosFilter(requestedWager, 0.2, user, user.coins) + requestedWager) / 2
|
const n = requestedWager//(chaosFilter(requestedWager, 0.2, user, user.coins) + requestedWager) / 2
|
||||||
if (!n || n < 0) {
|
if (!n || n < 0) {
|
||||||
return say(`Invalid number '${argText}'`)
|
return say(`Invalid number '${argText}'`)
|
||||||
}
|
}
|
||||||
|
@ -1103,6 +1251,7 @@ command(
|
||||||
return say(`Argument must be a single emoji!`)
|
return say(`Argument must be a single emoji!`)
|
||||||
}
|
}
|
||||||
user.lostBetMessage = emoji
|
user.lostBetMessage = emoji
|
||||||
|
say(`Set!`)
|
||||||
}, {hidden: true})
|
}, {hidden: true})
|
||||||
|
|
||||||
command(
|
command(
|
||||||
|
@ -1114,6 +1263,7 @@ command(
|
||||||
return say(`Argument must be a single emoji!`)
|
return say(`Argument must be a single emoji!`)
|
||||||
}
|
}
|
||||||
user.wonBetMessage = emoji
|
user.wonBetMessage = emoji
|
||||||
|
say(`Set!`)
|
||||||
}, {hidden: true})
|
}, {hidden: true})
|
||||||
|
|
||||||
command(
|
command(
|
||||||
|
@ -1373,30 +1523,59 @@ command(
|
||||||
['!gift', '!give', '!gi'],
|
['!gift', '!give', '!gi'],
|
||||||
'Donate coins to a fellow player\n' +
|
'Donate coins to a fellow player\n' +
|
||||||
' Send coins by saying \'!gift @player coin_amount\'',
|
' Send coins by saying \'!gift @player coin_amount\'',
|
||||||
async ({ args, say, user, haunted }) => {
|
async ({ event, args, say, user, haunted }) => {
|
||||||
if (haunted) {
|
if (haunted) {
|
||||||
return say(`!give doesn't work while you're haunted.`)
|
return say(`!give doesn't work while you're haunted.`)
|
||||||
}
|
}
|
||||||
let [target, ...amountText] = args
|
let [target, ...amountText] = args
|
||||||
amountText = amountText.join(' ')
|
amountText = amountText.join(' ')
|
||||||
const amount = parseAll(amountText, user.coins, user)
|
let targets
|
||||||
|
if (target === 'everyone') {
|
||||||
|
targets = Object.entries(users).filter(([id, user]) => id !== event.user && !user.isDisabled && user.name && user.name !== 'Hvacker').map(([id]) => id)
|
||||||
|
} else {
|
||||||
const targetId = idFromWord(target)
|
const targetId = idFromWord(target)
|
||||||
if (!amount || amount < 0) {
|
targets = [targetId]
|
||||||
return say('Amount must be a positive integer!')
|
if (targetId === event?.user) {
|
||||||
|
return say(':thonk:')
|
||||||
}
|
}
|
||||||
if (!targetId) {
|
if (!targetId) {
|
||||||
return say('Target must be a valid @')
|
return say('Target must be a valid @')
|
||||||
}
|
}
|
||||||
if (user.coins < amount) {
|
|
||||||
return say(`You don't have that many coins! You have ${commas(user.coins)} HVAC.`)
|
|
||||||
}
|
|
||||||
if (amountText === 'all' && slack.users.Tyler === targetId) {
|
if (amountText === 'all' && slack.users.Tyler === targetId) {
|
||||||
addAchievement(user, 'walmartGiftCard', say)
|
addAchievement(user, 'walmartGiftCard', say)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
let individualAmount = parseAll(amountText, user.coins, user)
|
||||||
|
if (individualAmount === user.coins) {
|
||||||
|
individualAmount = user.coins / targets.length
|
||||||
|
}
|
||||||
|
const totalAmount = individualAmount * targets.length
|
||||||
|
|
||||||
|
if (!totalAmount || totalAmount < 0) {
|
||||||
|
return say('Amount must be a positive integer!')
|
||||||
|
}
|
||||||
|
if (user.coins < totalAmount) {
|
||||||
|
return say(`You don't have that many coins! You have ${commas(user.coins)} HVAC.`)
|
||||||
|
}
|
||||||
|
let gifted = []
|
||||||
|
for (const targetId of targets) {
|
||||||
const targetUser = getUser(targetId)
|
const targetUser = getUser(targetId)
|
||||||
user.coins -= amount
|
user.coins -= individualAmount
|
||||||
targetUser.coins += amount
|
if (user.coinsAllTime < 10000) {
|
||||||
await say(`Gifted ${commas(amount)} HVAC to <@${targetId}>`)
|
// return say('Let \'em play for a bit, ay?')
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
gifted.push(targetId)
|
||||||
|
targetUser.coins += individualAmount
|
||||||
|
}
|
||||||
|
let recipients
|
||||||
|
if (gifted.length > 1) {
|
||||||
|
const last = gifted.pop()
|
||||||
|
recipients = gifted.map(t => users[t].name).join(', ') + ', and ' + users[last].name
|
||||||
|
} else {
|
||||||
|
recipients = users[recipients[0]].name
|
||||||
|
}
|
||||||
|
await say(`Gifted ${commas(individualAmount)} HVAC to ${recipients}`)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1544,6 +1723,9 @@ command(
|
||||||
game.leaderboardChannels ??= {}
|
game.leaderboardChannels ??= {}
|
||||||
await say(generateLeaderboard({ args })).then(({ channel, ts }) => {
|
await say(generateLeaderboard({ args })).then(({ channel, ts }) => {
|
||||||
addAchievement(user, 'leaderBoardViewer', say)
|
addAchievement(user, 'leaderBoardViewer', say)
|
||||||
|
if (args[0] === 'all') {
|
||||||
|
return
|
||||||
|
}
|
||||||
game.leaderboardChannels[channel] = ts
|
game.leaderboardChannels[channel] = ts
|
||||||
return updateAllLeaderboards({ channel, ts })
|
return updateAllLeaderboards({ channel, ts })
|
||||||
})
|
})
|
||||||
|
@ -1582,6 +1764,7 @@ oneShot(['!dab', '!dabs'], 'ACTIVATE COOL GUY MODE', '<https://i.imgur.com/FKYde
|
||||||
oneShot('!based', 'Sorry, it\'s a little hard to hear you!', '<https://i.imgur.com/IUX6R26.png|What?>')
|
oneShot('!based', 'Sorry, it\'s a little hard to hear you!', '<https://i.imgur.com/IUX6R26.png|What?>')
|
||||||
oneShot('!shrek', 'Is love and is life.', '<https://i.imgur.com/QwuCQZA.png|Donkey!>')
|
oneShot('!shrek', 'Is love and is life.', '<https://i.imgur.com/QwuCQZA.png|Donkey!>')
|
||||||
oneShot('!sugondese', 'I don\'t like you.', '<https://i.imgur.com/VCvfvdz.png|rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr>')
|
oneShot('!sugondese', 'I don\'t like you.', '<https://i.imgur.com/VCvfvdz.png|rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr>')
|
||||||
|
oneShot('!bofa', 'bofa deez yes yes we get it', ':goorab:')
|
||||||
// oneShot('!imaginedragons', 'The worst part about any group of white people is that they could be Imagine Dragons and you\'d have no way of knowing.', '<https://i.imgur.com/QwuCQZA.png|Donkey!>')
|
// oneShot('!imaginedragons', 'The worst part about any group of white people is that they could be Imagine Dragons and you\'d have no way of knowing.', '<https://i.imgur.com/QwuCQZA.png|Donkey!>')
|
||||||
|
|
||||||
command(
|
command(
|
||||||
|
@ -1675,9 +1858,6 @@ command(
|
||||||
)
|
)
|
||||||
}, adminOnly)
|
}, adminOnly)
|
||||||
|
|
||||||
const exec = require('child_process').exec
|
|
||||||
const { createReadStream } = require('fs')
|
|
||||||
|
|
||||||
command(
|
command(
|
||||||
['!steal', '!sagesteal'],
|
['!steal', '!sagesteal'],
|
||||||
'Highly illegal',
|
'Highly illegal',
|
||||||
|
@ -1688,6 +1868,7 @@ command(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let targetId = idFromWord(target)
|
let targetId = idFromWord(target)
|
||||||
|
console.log({ user: event.user, target, targetId })
|
||||||
if (event.user === targetId) {
|
if (event.user === targetId) {
|
||||||
return say('What, are you trying to steal from yourself? What, are you stupid?')
|
return say('What, are you trying to steal from yourself? What, are you stupid?')
|
||||||
}
|
}
|
||||||
|
@ -1881,7 +2062,7 @@ const updateStonkPrices = () => {
|
||||||
console.log('set lastPrice')
|
console.log('set lastPrice')
|
||||||
stonk.lastPrice = stonk.price
|
stonk.lastPrice = stonk.price
|
||||||
console.log(stonk.pattern, stonkPatterns)
|
console.log(stonk.pattern, stonkPatterns)
|
||||||
stonk.price *= 1 + (stonkPatterns[stonk.pattern][stonk.index] / 100)
|
stonk.price *= 1 + ((stonkPatterns[stonk.pattern] || stonkPatterns.duk)[stonk.index] / 100)
|
||||||
stonk.index++
|
stonk.index++
|
||||||
if (stonk.index >= stonkPatterns[stonk.pattern]?.length) {
|
if (stonk.index >= stonkPatterns[stonk.pattern]?.length) {
|
||||||
stonk.index = 0
|
stonk.index = 0
|
||||||
|
@ -1935,6 +2116,7 @@ command(
|
||||||
['!stonks', '!stonk', '!st'],
|
['!stonks', '!stonk', '!st'],
|
||||||
stonkHelp,
|
stonkHelp,
|
||||||
async ({ user, args, say }) => {
|
async ({ user, args, say }) => {
|
||||||
|
return say(`Stonks are busted atm but thank you for trying!`)
|
||||||
updateStonkPrices()
|
updateStonkPrices()
|
||||||
let msg = `Market values:\n`
|
let msg = `Market values:\n`
|
||||||
Object.entries(stonkMarket.stonks).forEach(([name, stonk]) => {
|
Object.entries(stonkMarket.stonks).forEach(([name, stonk]) => {
|
||||||
|
@ -2042,6 +2224,39 @@ command(
|
||||||
{ hidden: true }
|
{ hidden: true }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const manageReactions = async ({ args, action }) => {
|
||||||
|
const [link, ...reactions] = args
|
||||||
|
const split = link.replace(/.*archives\//, "").split("/")
|
||||||
|
const channelId = split[0]
|
||||||
|
// split[1] ~= 'p1234567890123456'
|
||||||
|
const t = split[1].substring(1).replace(/[^0-9]/g, "")
|
||||||
|
const timestamp = t.substring(0, t.length - 6) + '.' + t.substring(t.length - 6)
|
||||||
|
return action({
|
||||||
|
app: slack.app,
|
||||||
|
channelId,
|
||||||
|
timestamp,
|
||||||
|
reactions: reactions.map(react => react.replace(/:/gi, ""))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
command(
|
||||||
|
['!react', '!addreact'],
|
||||||
|
'!addreact <link> <emojis>',
|
||||||
|
async ({ args }) => {
|
||||||
|
return manageReactions({ args, action: addReactions })
|
||||||
|
},
|
||||||
|
adminOnly
|
||||||
|
)
|
||||||
|
|
||||||
|
command(
|
||||||
|
['!rmreact'],
|
||||||
|
'!rmreact <link> <emojis>',
|
||||||
|
async ({ args }) => {
|
||||||
|
return manageReactions({ args, action: removeReactions })
|
||||||
|
},
|
||||||
|
adminOnly
|
||||||
|
)
|
||||||
|
|
||||||
//webapi.launch()
|
//webapi.launch()
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
@ -3,6 +3,7 @@ const fs = require('fs')
|
||||||
const achievements = require('./achievements')
|
const achievements = require('./achievements')
|
||||||
const buyableItems = require('./buyableItems')
|
const buyableItems = require('./buyableItems')
|
||||||
const { quackStore, getChaos } = require('./quackstore')
|
const { quackStore, getChaos } = require('./quackstore')
|
||||||
|
const slack = require("../../slack");
|
||||||
|
|
||||||
let upgrades
|
let upgrades
|
||||||
const setUpgrades = upg => {
|
const setUpgrades = upg => {
|
||||||
|
@ -88,6 +89,9 @@ const maybeNews = say => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const idFromWord = word => {
|
const idFromWord = word => {
|
||||||
|
if (word?.startsWith('<#') && word.endsWith('>')) {
|
||||||
|
return word.replace(/<#([^|]*)|.*/g, '$1')
|
||||||
|
}
|
||||||
if (!word?.startsWith('<@') || !word.endsWith('>')) {
|
if (!word?.startsWith('<@') || !word.endsWith('>')) {
|
||||||
return getIdFromName(word)
|
return getIdFromName(word)
|
||||||
} else {
|
} else {
|
||||||
|
@ -111,6 +115,11 @@ const bigNumberWords = [
|
||||||
['trillion', 1_000_000_000_000],
|
['trillion', 1_000_000_000_000],
|
||||||
['billion', 1_000_000_000],
|
['billion', 1_000_000_000],
|
||||||
['million', 1_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) => {
|
const commas = (num, precise = false, skipWords = false) => {
|
||||||
|
@ -139,6 +148,8 @@ const parseAll = (str, allNum, user) => {
|
||||||
|
|
||||||
switch (str) {
|
switch (str) {
|
||||||
case 'all':
|
case 'all':
|
||||||
|
case 'all in':
|
||||||
|
case 'everything':
|
||||||
case 'sugma':
|
case 'sugma':
|
||||||
case 'ligma':
|
case 'ligma':
|
||||||
case 'pulma':
|
case 'pulma':
|
||||||
|
@ -148,6 +159,7 @@ const parseAll = (str, allNum, user) => {
|
||||||
return allNum
|
return allNum
|
||||||
case 'sex':
|
case 'sex':
|
||||||
case 'sex number':
|
case 'sex number':
|
||||||
|
case 'nice':
|
||||||
return 69_000_000
|
return 69_000_000
|
||||||
case ':maple_leaf:':
|
case ':maple_leaf:':
|
||||||
case ':herb:':
|
case ':herb:':
|
||||||
|
@ -446,6 +458,21 @@ const addReactions = async ({ app, channelId, timestamp, reactions }) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 daysSinceEpoch = () => {
|
||||||
const today = new Date().getTime()
|
const today = new Date().getTime()
|
||||||
const epoch = new Date(0).getTime()
|
const epoch = new Date(0).getTime()
|
||||||
|
@ -570,6 +597,7 @@ module.exports = {
|
||||||
getRandomFromArray,
|
getRandomFromArray,
|
||||||
chaosFilter,
|
chaosFilter,
|
||||||
addReactions,
|
addReactions,
|
||||||
|
removeReactions,
|
||||||
getCompletedSquadgradeNames,
|
getCompletedSquadgradeNames,
|
||||||
game,
|
game,
|
||||||
dayOfYear,
|
dayOfYear,
|
||||||
|
|
|
@ -12,9 +12,9 @@ const pollingPeriod = 1000 * 60 * pollingMinutes
|
||||||
const MAX_POLLS = 3
|
const MAX_POLLS = 3
|
||||||
const HOURS_PER_WINDOW = 2
|
const HOURS_PER_WINDOW = 2
|
||||||
|
|
||||||
const colderEmoji = 'snowflake'
|
const colderEmoji = '3d-penguin'
|
||||||
const hotterEmoji = 'fire'
|
const hotterEmoji = 'heat'
|
||||||
const goodEmoji = '+1'
|
const goodEmoji = 'theworm'
|
||||||
|
|
||||||
const app = new SlackApp({
|
const app = new SlackApp({
|
||||||
token: config.slackBotToken,
|
token: config.slackBotToken,
|
||||||
|
@ -27,7 +27,7 @@ const app = new SlackApp({
|
||||||
// console.log('techThermostatChannelId', temperatureChannelId)
|
// console.log('techThermostatChannelId', temperatureChannelId)
|
||||||
// })
|
// })
|
||||||
|
|
||||||
const pollTriggers = ['!temp', '!temperature', '!imhot', '!imcold', '!imfreezing', '!idonthavemysweater']
|
const pollTriggers = ['!temp', '!temperature', '!imhot', '!imcold', '!im...cold', '!im...hot', '!im...cold?', '!im...hot?', '!imfreezing', '!idonthavemysweater', '!itsdangtoasty', '!itschilly', '!itsdangchilly']
|
||||||
const halfTriggers = ['change temperature', "i'm cold", "i'm hot", 'quack', 'hvacker', '<@U0344TFA7HQ>']
|
const halfTriggers = ['change temperature', "i'm cold", "i'm hot", 'quack', 'hvacker', '<@U0344TFA7HQ>']
|
||||||
|
|
||||||
const sendHelp = async (say, prefix) => {
|
const sendHelp = async (say, prefix) => {
|
||||||
|
@ -136,7 +136,7 @@ app.event('message', async ({ event, context, client, say }) => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pollTriggers.includes(eventText) || event.user === users.John) {
|
if (!pollTriggers.includes(eventText)) {
|
||||||
if (halfTriggers.includes(eventText)) {
|
if (halfTriggers.includes(eventText)) {
|
||||||
await sendHelp(say, 'It looks like you might want to change the temperature.')
|
await sendHelp(say, 'It looks like you might want to change the temperature.')
|
||||||
}
|
}
|
||||||
|
@ -157,10 +157,10 @@ app.event('message', async ({ event, context, client, say }) => {
|
||||||
|
|
||||||
const pollsInWindow = pollHistory.filter(pollTime => pollTime > windowStart)
|
const pollsInWindow = pollHistory.filter(pollTime => pollTime > windowStart)
|
||||||
const pollText = MAX_POLLS === 1 ? 'poll' : 'polls'
|
const pollText = MAX_POLLS === 1 ? 'poll' : 'polls'
|
||||||
const hourText = HOURS_PER_WINDOW === 1 ? 'hour' : 'hours'
|
const hourText = HOURS_PER_WINDOW === 1 ? 'hour' : `${HOURS_PER_WINDOW} hours`
|
||||||
|
|
||||||
if (pollsInWindow.length >= MAX_POLLS) {
|
if (pollsInWindow.length >= MAX_POLLS) {
|
||||||
await postToTechThermostatChannel({ text: `You have exceeded the limit of ${MAX_POLLS} ${pollText} per ${HOURS_PER_WINDOW} ${hourText}!` })
|
await postToTechThermostatChannel({ text: `You have exceeded the limit of ${MAX_POLLS} ${pollText} per ${hourText}!` })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,9 +284,8 @@ const tempChangeListeners = []
|
||||||
const messageListeners = []
|
const messageListeners = []
|
||||||
const reactionListeners = []
|
const reactionListeners = []
|
||||||
|
|
||||||
const requestTempChange = change => {
|
const requestTempChange = change =>
|
||||||
tempChangeListeners.forEach(listener => listener(change))
|
tempChangeListeners.forEach(listener => listener(change))
|
||||||
}
|
|
||||||
|
|
||||||
// noinspection HttpUrlsUsage
|
// noinspection HttpUrlsUsage
|
||||||
const encodeData = (key, data) =>
|
const encodeData = (key, data) =>
|
||||||
|
|