diff --git a/README.md b/README.md index 1503735..03521a2 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,8 @@ ITEM|FUNCTION|ALIASES -|-|- `blaster {target}`|Times the target user out for 60 seconds|`!blast, !blaster` `silverbullet {target}`|Times the target user out for 24 hours|`!execute, !silverbullet` +`revive {target}`|Reduce timeout timer of target by 30 seconds|`!revive, !heal` +`superrevive {target}`|Reduce timeout timer of target by 12|`!superrevive, !superheal` `grenade`|Times a random chatter out for 60 seconds|`!grenade` `tnt`|Times out 1 to 10 chatters for 60 seconds|`!tnt` `lootbox`|Gives the user some qbucks, and possibly some items|`!lootbox` diff --git a/src/commands/itemAliases.ts b/src/commands/itemAliases.ts index d3c7660..6c70ff6 100644 --- a/src/commands/itemAliases.ts +++ b/src/commands/itemAliases.ts @@ -11,6 +11,8 @@ for (const item of items) { switch (item.name) { case 'blaster': case 'silverbullet': + case 'revive': + case 'superrevive': if (params[0] === undefined) { await say('nice miss bro'); return } await item.execute(user!, say, broadcasterId, params[0].replace(/[@]/g, '')) break diff --git a/src/commands/iteminfo.ts b/src/commands/iteminfo.ts index 14a0243..b056123 100644 --- a/src/commands/iteminfo.ts +++ b/src/commands/iteminfo.ts @@ -5,5 +5,5 @@ export default createBotCommand('iteminfo', async (params, { say }) => { if (params[0] === undefined) { await say('No item specified!'); return } const selection = items.find(item => item.aliases.includes(params[0].toLowerCase())) if (!selection) { await say('Item not found'); return } - await say(selection[1].description) + await say(selection.description) }, { aliases: ['item'] }) diff --git a/src/commands/modme.ts b/src/commands/modme.ts index 2a09b6b..273c07c 100644 --- a/src/commands/modme.ts +++ b/src/commands/modme.ts @@ -1,11 +1,9 @@ import { createBotCommand } from "@twurple/easy-bot"; import api, { broadcasterApi } from "../lib/api"; - -const MODS = process.env.MODS -if (!MODS) { console.error("Please set the MODS environment variable."); process.exit(1) } +import { MODS } from "../lib/timeoutHelper"; export default createBotCommand('modme', async (_params, { userName, broadcasterId, userId }) => { - if (!MODS.includes(userName)) return + if (!MODS!.includes(userName)) return if (broadcasterApi) await broadcasterApi.moderation.addModerator(broadcasterId, userId) else await api.moderation.addModerator(broadcasterId, userId) diff --git a/src/commands/use.ts b/src/commands/use.ts index 0532bc0..23eaac1 100644 --- a/src/commands/use.ts +++ b/src/commands/use.ts @@ -13,6 +13,8 @@ export default createBotCommand('use', async (params, { say, broadcasterId, user switch (selection.name) { case 'blaster': case 'silverbullet': + case 'revive': + case 'superrevive': if (params[1] === undefined) { await say('nice miss bro'); return } await selection.execute(user!, say, broadcasterId, params[1].replace(/[@]/g, '')) break diff --git a/src/items/blasters.ts b/src/items/blasters.ts index f8a4ee1..d6fcdec 100644 --- a/src/items/blasters.ts +++ b/src/items/blasters.ts @@ -17,7 +17,7 @@ export const blaster = { if (!itemResult.result && itemResult.reason === 'negative') { await say('You have no blasters!'); return } - const result = await timeout(broadcasterId, target!, 60, `You got blasted by ${user.name}`) + const result = await timeout(broadcasterId, target, 60, `You got blasted by ${user.name}`) if (result.status) { await say(`${targetname} got blasted by ${user.name}! ${user.name} has ${itemResult.count} blaster${itemResult.count === 1 ? '' : 's'} remaining`) await addTimeoutToDB(user, target!, 'blaster') @@ -52,7 +52,7 @@ export const silverbullet = { const itemResult = await changeItemCount(user, 'silverbullet') if (!itemResult.result && itemResult.reason === 'negative') { await say('You have no silver bullets!'); return } - const result = await timeout(broadcasterId, target!, 60 * 60 * 24, `You got hit by a silver bullet fired by ${user.name}`) + const result = await timeout(broadcasterId, target, 60 * 60 * 24, `You got hit by a silver bullet fired by ${user.name}`) if (result.status) { await say(`${target?.name} got deleted.`) await addTimeoutToDB(user, target!, 'silverbullet') diff --git a/src/items/index.ts b/src/items/index.ts index 169e601..85cefdf 100644 --- a/src/items/index.ts +++ b/src/items/index.ts @@ -2,6 +2,7 @@ import { HelixUser } from "@twurple/api" import { blaster, silverbullet } from "./blasters" import { grenade, tnt } from "./explosives" +import { revive, superrevive } from "./revives" import { lootbox } from "./lootbox" import { clipboard } from "./clipboard" @@ -13,6 +14,6 @@ interface item { description: string, execute: (user: HelixUser, say: (args0: string) => Promise, broadcasterId?: string, targetname?: string) => Promise } -const data = [blaster, silverbullet, grenade, tnt, lootbox, clipboard] as item[] +const data = [blaster, silverbullet, grenade, tnt, revive, superrevive, lootbox, clipboard] as item[] export const ITEMS = data.map(item => item.name) export default data diff --git a/src/items/revives.ts b/src/items/revives.ts new file mode 100644 index 0000000..3c5bf84 --- /dev/null +++ b/src/items/revives.ts @@ -0,0 +1,73 @@ +import { HelixUser } from "@twurple/api" +import api from "../lib/api" +import { changeItemCount } from "../lib/items" +import { reviveTarget } from "../lib/timeoutHelper" +import { addUsedItem, updateInventory } from "../lib/userHelper" + +export const revive = { + name: 'revive', + prettyname: 'Revive', + aliases: ['revive', 'heal'], + plural: 's', + description: "Use: revive {target}, Function: Reduce timeout timer of target by 30 seconds. Aliases: !revive, !heal", + execute: async (user: HelixUser, say: (arg0: string) => Promise, broadcasterId: string, targetname: string) => { + const target = await api.users.getUserByName(targetname) + + const itemResult = await changeItemCount(user, 'revive') + if (!itemResult.result) { await say('You have no revives!'); return } + + const reviveResult = await reviveTarget(broadcasterId, target, 30) + if (reviveResult.status) { await updateInventory(user, itemResult.inv!); await addUsedItem(target!, 'revive') } + switch (reviveResult.reason) { + case 'noexist': + await say(`${targetname} does not exist`) + break + case 'notbanned': + await say(`${targetname} doesn't need revives`) + break + case 'unknown': + await say("Something went wrong!") + break + case 'healed': + await say(`${targetname} got healed for 30 seconds by ${user.name}`) + break + case 'revived': + await say(`${targetname} got revived by ${user.name}`) + break + } + } +} + +export const superrevive = { + name: 'superrevive', + prettyname: 'Super Revive', + aliases: ['superrevive', 'superheal'], + plural: 's', + description: "Use: superrevive {target}, Function: Reduce timeout timer of target by 12 hours. Aliases: !superrevive, !superheal", + execute: async (user: HelixUser, say: (arg0: string) => Promise, broadcasterId: string, targetname: string) => { + const target = await api.users.getUserByName(targetname) + + const itemResult = await changeItemCount(user, 'superrevive') + if (!itemResult.result) { await say('You have no revives!'); return } + + const reviveResult = await reviveTarget(broadcasterId, target, 60 * 60 * 12) + if (reviveResult.status) { await updateInventory(user, itemResult.inv!); await addUsedItem(target!, 'superrevive') } + switch (reviveResult.reason) { + case 'noexist': + await say(`${targetname} does not exist`) + break + case 'notbanned': + await say(`${targetname} doesn't need revives`) + break + case 'unknown': + await say("Something went wrong!") + break + case 'healed': + await say(`${targetname} got healed for 12 hours by ${user.name}`) + break + case 'revived': + await say(`${targetname} got revived by ${user.name}`) + break + } + } +} diff --git a/src/lib/timeoutHelper.ts b/src/lib/timeoutHelper.ts index 2d03bd2..713cf52 100644 --- a/src/lib/timeoutHelper.ts +++ b/src/lib/timeoutHelper.ts @@ -3,6 +3,10 @@ import api, { broadcasterApi } from "./api"; import pb from "./pocketbase"; import { DBValidation } from "./userHelper"; +const MODSSTRING = process.env.MODS +if (!MODSSTRING) { console.error("Please set the MODS environment variable."); process.exit(1) } +export const MODS = MODSSTRING.split(',') + type shooter = 'blaster' | 'grenade' | 'silverbullet' | 'tnt' interface statusmessage { @@ -13,7 +17,7 @@ interface statusmessage { /** Ban a specific user out by another user for specified amout of time, with specific reason * If the user does not exist or is already banned return status: false * If the user is a moderator, make sure they get their status back after timeout has elapsed */ -export async function timeout(broadcasterid: string, target: HelixUser, duration: number, reason: string): Promise { +export async function timeout(broadcasterid: string, target: HelixUser|null, duration: number, reason: string): Promise { if (!target) return { status: false, reason: 'noexist' } const tmpapi = broadcasterApi ?? api if (target.name === process.env.BOT_NAME) return { status: false, reason: 'unknown' } @@ -33,6 +37,29 @@ export async function timeout(broadcasterid: string, target: HelixUser, duration } } +/** Revive a specific target for a certain amount of time */ +export async function reviveTarget(broadcasterId: string, target: HelixUser|null, duration: number): Promise { + if (!target) return { status: false, reason: 'noexist' } + const tmpapi = broadcasterApi ?? api + const bandata = await tmpapi.moderation.getBannedUsers(broadcasterId, { userId: target.id }) + if (!bandata.data[0]) return { status: false, reason: 'notbanned' } + const newduration = Math.floor((Date.parse(bandata.data[0].expiryDate?.toString()!) - Date.now()) / 1000 - duration) // (timestamp to freedom - current timestamp) / 1000 (to seconds) - duration + try { + if (newduration < 3) { // If the target is going to be unbanned in duration + 3 seconds, unban them anyway + await tmpapi.moderation.unbanUser(broadcasterId, target) + if (MODS.includes(target.name)) remodMod(broadcasterId, target, 0, tmpapi) + return {status: true, reason: 'revived'} + } else { + await tmpapi.moderation.banUser(broadcasterId, { duration: newduration, reason: bandata.data[0].reason!, user: target }) + if (MODS.includes(target.name)) remodMod(broadcasterId, target, newduration * 1000 , tmpapi) + return { status: true, reason: 'healed' } + } + } catch (err) { + console.error(err) + return { status: false, reason: 'unknown' } + } +} + /** Add an entry to the timeouts table */ export async function addTimeoutToDB(attacker: HelixUser, target: HelixUser, source: shooter) { // This has passed the existance check so there's no need to check if the users exist (twitch)