Card APIs, new poll triggers, and other small additions

This commit is contained in:
Sage Vaillancourt 2023-12-05 20:24:34 -05:00
parent 969a6b900b
commit 7c70ae80cb
70 changed files with 294 additions and 52 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
playingCards/2_of_clubs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
playingCards/3_of_clubs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
playingCards/4_of_clubs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
playingCards/5_of_clubs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
playingCards/6_of_clubs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
playingCards/7_of_clubs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
playingCards/8_of_clubs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
playingCards/9_of_clubs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

BIN
playingCards/red_joker.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -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
const targetId = idFromWord(target) if (target === 'everyone') {
if (!amount || amount < 0) { 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)
targets = [targetId]
if (targetId === event?.user) {
return say(':thonk:')
}
if (!targetId) {
return say('Target must be a valid @')
}
if (amountText === 'all' && slack.users.Tyler === targetId) {
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!') return say('Amount must be a positive integer!')
} }
if (!targetId) { if (user.coins < totalAmount) {
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.`) return say(`You don't have that many coins! You have ${commas(user.coins)} HVAC.`)
} }
if (amountText === 'all' && slack.users.Tyler === targetId) { let gifted = []
addAchievement(user, 'walmartGiftCard', say) for (const targetId of targets) {
const targetUser = getUser(targetId)
user.coins -= individualAmount
if (user.coinsAllTime < 10000) {
// return say('Let \'em play for a bit, ay?')
continue
}
gifted.push(targetId)
targetUser.coins += individualAmount
} }
const targetUser = getUser(targetId) let recipients
user.coins -= amount if (gifted.length > 1) {
targetUser.coins += amount const last = gifted.pop()
await say(`Gifted ${commas(amount)} HVAC to <@${targetId}>`) 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 = {

View File

@ -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,

View File

@ -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) =>