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,
|
||||
chaosFilter,
|
||||
addReactions,
|
||||
removeReactions,
|
||||
setHighestCoins,
|
||||
definitelyShuffle,
|
||||
getCompletedSquadgradeNames,
|
||||
|
@ -29,6 +30,10 @@ const {
|
|||
const { nfts, squad, users, horrors, stonkMarket, pet } = game
|
||||
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 buyableItems = require('./buyableItems')
|
||||
const upgrades = require('./upgrades')
|
||||
|
@ -38,6 +43,7 @@ const prestige = require('./prestige')
|
|||
const lore = require('./lore')
|
||||
const { getChaos, quackStore } = require('./quackstore')
|
||||
const settings = require('./settings')
|
||||
const https = require('https')
|
||||
|
||||
// const readline = require('readline').createInterface({
|
||||
// input: process.stdin,
|
||||
|
@ -74,6 +80,7 @@ const upgradeText = (user, showOwned = false) => {
|
|||
const hasUpgrade = (user, upgrade, upgradeName) => !!user.upgrades[upgrade.type]?.includes(upgradeName)
|
||||
|
||||
const alwaysAccessible = () => true
|
||||
const alwaysAlwaysAccessible = () => true
|
||||
const adminOnly = {
|
||||
hidden: true,
|
||||
condition: ({ event, say }) => {
|
||||
|
@ -115,7 +122,7 @@ let shortCommandHelpText = 'Use `!help full` to show details for all commands, o
|
|||
const defaultAccess = { hidden: false, condition: alwaysAccessible }
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param {[string]} commandNames
|
||||
* @param {string} helpText
|
||||
* @param {function({ event, say, trueSay, words, args, commandName, user, userId: event.user, haunted })} action: boolean
|
||||
|
@ -167,6 +174,147 @@ const getHorrorMessageOdds = (offset = 0) => {
|
|||
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(
|
||||
['!odds'],
|
||||
'Show shuffle odds re: !horror',
|
||||
|
@ -188,6 +336,16 @@ command(
|
|||
)
|
||||
}, 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(
|
||||
['!shuffle'],
|
||||
'!shuffle daysFromNow message',
|
||||
|
@ -239,7 +397,7 @@ const horrorMessages = [
|
|||
|
||||
const buildHorrorSay = ({ say, event, commandName, c }) => async message => {
|
||||
const shuffleOdds = getShuffleOdds(99)
|
||||
|
||||
|
||||
if (typeof message === 'string' && commandName !== '!n' && commandName !== '!nfts' && c.condition !== adminOnly.condition) {
|
||||
let shuffled = shufflePercent(message, shuffleOdds)
|
||||
if (shuffled.length > 100 && Math.random() < getShuffleOdds()) {
|
||||
|
@ -373,7 +531,7 @@ const messageHandler = async ({ event, say, isRecycle = false, skipCounting }) =
|
|||
const [commandName, ...args] = words
|
||||
const c = commands.get(commandName)
|
||||
let user = getUser(event.user)
|
||||
if (user.isDisabled) {
|
||||
if (user.isDisabled && c.condition !== alwaysAlwaysAccessible) {
|
||||
return
|
||||
}
|
||||
user.name = slack.users[event.user]
|
||||
|
@ -382,13 +540,13 @@ const messageHandler = async ({ event, say, isRecycle = false, skipCounting }) =
|
|||
user.commandCounts[words[0]] ??= 0
|
||||
user.commandCounts[words[0]] += 1
|
||||
}
|
||||
|
||||
|
||||
if (!c && words[0]?.startsWith('!') && event.user !== slack.users.Admin) {
|
||||
if (!slack.pollTriggers.includes(words[0])) {
|
||||
return slack.messageAdmin(`${slack.users[event.user]} tried to use \`${event.text}\`, if you wanted to add that.`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const trueSay = say
|
||||
|
||||
say = buildSayWithPayload({ say: trueSay, event })
|
||||
|
@ -421,7 +579,7 @@ const messageHandler = async ({ event, say, isRecycle = false, skipCounting }) =
|
|||
})
|
||||
say = async msg => {
|
||||
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])
|
||||
}
|
||||
trueSay({
|
||||
|
@ -951,7 +1109,6 @@ const doMine = async ({ user, userId, say }) => {
|
|||
} else {
|
||||
const miningUpgrades = (user.upgrades.mining || []).map(name => upgrades[name])
|
||||
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`
|
||||
}
|
||||
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(
|
||||
['!as'],
|
||||
'Run commands as another user.',
|
||||
|
@ -985,23 +1150,6 @@ command(
|
|||
users[event.user].isDisabled = isDisabled
|
||||
}, 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(
|
||||
['!enable'],
|
||||
'Enable the given user',
|
||||
|
@ -1041,7 +1189,7 @@ command(
|
|||
}
|
||||
const argText = args.join(' ')
|
||||
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) {
|
||||
return say(`Invalid number '${argText}'`)
|
||||
}
|
||||
|
@ -1103,6 +1251,7 @@ command(
|
|||
return say(`Argument must be a single emoji!`)
|
||||
}
|
||||
user.lostBetMessage = emoji
|
||||
say(`Set!`)
|
||||
}, {hidden: true})
|
||||
|
||||
command(
|
||||
|
@ -1114,6 +1263,7 @@ command(
|
|||
return say(`Argument must be a single emoji!`)
|
||||
}
|
||||
user.wonBetMessage = emoji
|
||||
say(`Set!`)
|
||||
}, {hidden: true})
|
||||
|
||||
command(
|
||||
|
@ -1373,30 +1523,59 @@ command(
|
|||
['!gift', '!give', '!gi'],
|
||||
'Donate coins to a fellow player\n' +
|
||||
' Send coins by saying \'!gift @player coin_amount\'',
|
||||
async ({ args, say, user, haunted }) => {
|
||||
async ({ event, args, say, user, haunted }) => {
|
||||
if (haunted) {
|
||||
return say(`!give doesn't work while you're haunted.`)
|
||||
}
|
||||
let [target, ...amountText] = args
|
||||
amountText = amountText.join(' ')
|
||||
const amount = parseAll(amountText, user.coins, user)
|
||||
const targetId = idFromWord(target)
|
||||
if (!amount || amount < 0) {
|
||||
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)
|
||||
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!')
|
||||
}
|
||||
if (!targetId) {
|
||||
return say('Target must be a valid @')
|
||||
}
|
||||
if (user.coins < amount) {
|
||||
if (user.coins < totalAmount) {
|
||||
return say(`You don't have that many coins! You have ${commas(user.coins)} HVAC.`)
|
||||
}
|
||||
if (amountText === 'all' && slack.users.Tyler === targetId) {
|
||||
addAchievement(user, 'walmartGiftCard', say)
|
||||
let gifted = []
|
||||
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)
|
||||
user.coins -= amount
|
||||
targetUser.coins += amount
|
||||
await say(`Gifted ${commas(amount)} HVAC to <@${targetId}>`)
|
||||
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 ??= {}
|
||||
await say(generateLeaderboard({ args })).then(({ channel, ts }) => {
|
||||
addAchievement(user, 'leaderBoardViewer', say)
|
||||
if (args[0] === 'all') {
|
||||
return
|
||||
}
|
||||
game.leaderboardChannels[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('!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('!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!>')
|
||||
|
||||
command(
|
||||
|
@ -1675,9 +1858,6 @@ command(
|
|||
)
|
||||
}, adminOnly)
|
||||
|
||||
const exec = require('child_process').exec
|
||||
const { createReadStream } = require('fs')
|
||||
|
||||
command(
|
||||
['!steal', '!sagesteal'],
|
||||
'Highly illegal',
|
||||
|
@ -1688,6 +1868,7 @@ command(
|
|||
return
|
||||
}
|
||||
let targetId = idFromWord(target)
|
||||
console.log({ user: event.user, target, targetId })
|
||||
if (event.user === targetId) {
|
||||
return say('What, are you trying to steal from yourself? What, are you stupid?')
|
||||
}
|
||||
|
@ -1881,7 +2062,7 @@ const updateStonkPrices = () => {
|
|||
console.log('set lastPrice')
|
||||
stonk.lastPrice = stonk.price
|
||||
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++
|
||||
if (stonk.index >= stonkPatterns[stonk.pattern]?.length) {
|
||||
stonk.index = 0
|
||||
|
@ -1935,6 +2116,7 @@ command(
|
|||
['!stonks', '!stonk', '!st'],
|
||||
stonkHelp,
|
||||
async ({ user, args, say }) => {
|
||||
return say(`Stonks are busted atm but thank you for trying!`)
|
||||
updateStonkPrices()
|
||||
let msg = `Market values:\n`
|
||||
Object.entries(stonkMarket.stonks).forEach(([name, stonk]) => {
|
||||
|
@ -2042,6 +2224,39 @@ command(
|
|||
{ 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()
|
||||
|
||||
module.exports = {
|
||||
|
|
|
@ -3,6 +3,7 @@ const fs = require('fs')
|
|||
const achievements = require('./achievements')
|
||||
const buyableItems = require('./buyableItems')
|
||||
const { quackStore, getChaos } = require('./quackstore')
|
||||
const slack = require("../../slack");
|
||||
|
||||
let upgrades
|
||||
const setUpgrades = upg => {
|
||||
|
@ -88,6 +89,9 @@ const maybeNews = say => {
|
|||
}
|
||||
|
||||
const idFromWord = word => {
|
||||
if (word?.startsWith('<#') && word.endsWith('>')) {
|
||||
return word.replace(/<#([^|]*)|.*/g, '$1')
|
||||
}
|
||||
if (!word?.startsWith('<@') || !word.endsWith('>')) {
|
||||
return getIdFromName(word)
|
||||
} else {
|
||||
|
@ -111,6 +115,11 @@ const bigNumberWords = [
|
|||
['trillion', 1_000_000_000_000],
|
||||
['billion', 1_000_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) => {
|
||||
|
@ -139,6 +148,8 @@ const parseAll = (str, allNum, user) => {
|
|||
|
||||
switch (str) {
|
||||
case 'all':
|
||||
case 'all in':
|
||||
case 'everything':
|
||||
case 'sugma':
|
||||
case 'ligma':
|
||||
case 'pulma':
|
||||
|
@ -148,6 +159,7 @@ const parseAll = (str, allNum, user) => {
|
|||
return allNum
|
||||
case 'sex':
|
||||
case 'sex number':
|
||||
case 'nice':
|
||||
return 69_000_000
|
||||
case ':maple_leaf:':
|
||||
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 today = new Date().getTime()
|
||||
const epoch = new Date(0).getTime()
|
||||
|
@ -570,6 +597,7 @@ module.exports = {
|
|||
getRandomFromArray,
|
||||
chaosFilter,
|
||||
addReactions,
|
||||
removeReactions,
|
||||
getCompletedSquadgradeNames,
|
||||
game,
|
||||
dayOfYear,
|
||||
|
|
|
@ -12,9 +12,9 @@ const pollingPeriod = 1000 * 60 * pollingMinutes
|
|||
const MAX_POLLS = 3
|
||||
const HOURS_PER_WINDOW = 2
|
||||
|
||||
const colderEmoji = 'snowflake'
|
||||
const hotterEmoji = 'fire'
|
||||
const goodEmoji = '+1'
|
||||
const colderEmoji = '3d-penguin'
|
||||
const hotterEmoji = 'heat'
|
||||
const goodEmoji = 'theworm'
|
||||
|
||||
const app = new SlackApp({
|
||||
token: config.slackBotToken,
|
||||
|
@ -27,7 +27,7 @@ const app = new SlackApp({
|
|||
// 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 sendHelp = async (say, prefix) => {
|
||||
|
@ -136,7 +136,7 @@ app.event('message', async ({ event, context, client, say }) => {
|
|||
return
|
||||
}
|
||||
|
||||
if (!pollTriggers.includes(eventText) || event.user === users.John) {
|
||||
if (!pollTriggers.includes(eventText)) {
|
||||
if (halfTriggers.includes(eventText)) {
|
||||
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 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) {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -284,9 +284,8 @@ const tempChangeListeners = []
|
|||
const messageListeners = []
|
||||
const reactionListeners = []
|
||||
|
||||
const requestTempChange = change => {
|
||||
const requestTempChange = change =>
|
||||
tempChangeListeners.forEach(listener => listener(change))
|
||||
}
|
||||
|
||||
// noinspection HttpUrlsUsage
|
||||
const encodeData = (key, data) =>
|
||||
|
|