add basic redeem handling, nerf silver bullets to 30 minutes

This commit is contained in:
2025-09-24 21:31:36 +02:00
parent 2960ea5242
commit 392c67fb0d
9 changed files with 155 additions and 19 deletions

View File

@@ -161,7 +161,7 @@ COMMAND|FUNCTION|USER|ALIASES|DISABLEABLE
NAME|COMMAND|FUNCTION|ALIASES|COST NAME|COMMAND|FUNCTION|ALIASES|COST
-|-|-|-|- -|-|-|-|-
Blaster|`blaster {target}`|Times targeted user out for 60 seconds|`blaster` `blast`|100 Blaster|`blaster {target}`|Times targeted user out for 60 seconds|`blaster` `blast`|100
Silver Bullet|`silverbullet {target}`|Times targeted user out for 24 hours|`silverbullet` `execute` `{blastin}`|6666 Silver Bullet|`silverbullet {target}`|Times targeted user out for 30 minutes|`silverbullet` `execute` `{blastin}`|666
Grenade|`grenade`|Times a random vulnerable chatter out for 60 seconds|`grenade`|99 Grenade|`grenade`|Times a random vulnerable chatter out for 60 seconds|`grenade`|99
TNT|`tnt`|Give 5-10 random chatters 60 second timeouts|`tnt`|1000 TNT|`tnt`|Give 5-10 random chatters 60 second timeouts|`tnt`|1000
@@ -171,5 +171,5 @@ NAME|AMOUNT|USAGE|FUNCTION
-|-|-|- -|-|-|-
`grenade`|99|`cheer99`|Times a random vulnerable chatter out for 60 seconds. Of failure gives cheerer a grenade `grenade`|99|`cheer99`|Times a random vulnerable chatter out for 60 seconds. Of failure gives cheerer a grenade
`timeout`|100|`cheer100 {target}`|Times specified user out for 1 minute. On failure gives cheerer a blaster `timeout`|100|`cheer100 {target}`|Times specified user out for 1 minute. On failure gives cheerer a blaster
`execute`|666|`cheer666 {target}`|Times specified user out for 30 minutes. On failure gives cheerer a silver bullet
`tnt`|1000|`cheer1000`|Gives 5-10 random vulnerable chatters 60 second timeouts. On failure gives cheerer a TNT `tnt`|1000|`cheer1000`|Gives 5-10 random vulnerable chatters 60 second timeouts. On failure gives cheerer a TNT
`execute`|6666|`cheer6666 {target}`|Times specified user out for 24 hours. On failure gives cheerer a silver bullet

View File

@@ -10,14 +10,14 @@ import { playAlert } from "web/alerts/serverFunctions";
const ITEMNAME = 'silverbullet'; const ITEMNAME = 'silverbullet';
export default new Cheer('execute', 6666, async (msg, user) => { export default new Cheer('execute', 666, async (msg, user) => {
const args = parseCheerArgs(msg.messageText); const args = parseCheerArgs(msg.messageText);
if (!args[0]) { await handleNoTarget(msg, user, ITEMNAME, false); return; }; if (!args[0]) { await handleNoTarget(msg, user, ITEMNAME, false); return; };
const target = await User.initUsername(args[0].toLowerCase()); const target = await User.initUsername(args[0].toLowerCase());
if (!target) { await handleNoTarget(msg, user, ITEMNAME, false); return; }; if (!target) { await handleNoTarget(msg, user, ITEMNAME, false); return; };
await getUserRecord(target); await getUserRecord(target);
const result = await timeout(target, `You got executed by ${user.displayName}!`, 60 * 60 * 24); const result = await timeout(target, `You got executed by ${user.displayName}!`, 60 * 30);
if (result.status) await Promise.all([ if (result.status) await Promise.all([
sendMessage(`${target.displayName} RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO`), sendMessage(`${target.displayName} RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO`),
createTimeoutRecord(user, target, ITEMNAME), createTimeoutRecord(user, target, ITEMNAME),

View File

@@ -10,7 +10,7 @@ export async function connectionCheck() {
pgstatus = true; pgstatus = true;
} catch { }; } catch { };
const tempclient = new RedisClient(undefined, { const tempclient = new RedisClient(undefined, {
connectionTimeout: 100, connectionTimeout: 200,
maxRetries: 1, maxRetries: 1,
}); });
let redisstatus = false; let redisstatus = false;

View File

@@ -0,0 +1,18 @@
import { sendMessage } from "commands";
import logger from "lib/logger";
import { eventSub, streamerId } from "main";
import { activeRedeems } from "pointRedeems";
import User from "user";
eventSub.onChannelRedemptionAdd(streamerId, async msg => {
const selection = activeRedeems.get(msg.rewardId);
if (!selection) { logger.warn(`Can't find the ${msg.rewardTitle} redeem`); return; };
const user = await User.initUsername(msg.userName);
try {
await selection.execute(msg, user!);
await msg.updateStatus('FULFILLED');
} catch (err) {
await sendMessage(`[ERROR]: Something went wrong with ${user?.displayName}'s redeem!`);
logger.err(err as string);
};
});

View File

@@ -12,7 +12,7 @@ import { connectionCheck } from "connectionCheck";
await connectionCheck(); await connectionCheck();
const CHATTERINTENTS = ["user:read:chat", "user:write:chat", "user:bot", "user:manage:whispers"]; const CHATTERINTENTS = ["user:read:chat", "user:write:chat", "user:bot", "user:manage:whispers"];
const STREAMERINTENTS = ["channel:bot", "user:read:chat", "moderation:read", "channel:manage:moderators", "moderator:manage:chat_messages", "moderator:manage:banned_users", "bits:read", "channel:moderate", "moderator:manage:shoutouts", "channel:read:subscriptions"]; const STREAMERINTENTS = ["channel:bot", "user:read:chat", "moderation:read", "channel:manage:moderators", "moderator:manage:chat_messages", "moderator:manage:banned_users", "bits:read", "channel:moderate", "moderator:manage:shoutouts", "channel:read:subscriptions", "channel:manage:redemptions"];
export const singleUserMode = process.env.CHATTER_IS_STREAMER === 'true'; export const singleUserMode = process.env.CHATTER_IS_STREAMER === 'true';
export const chatterId = process.env.CHATTER_ID ?? ""; export const chatterId = process.env.CHATTER_ID ?? "";
@@ -72,4 +72,6 @@ if (streamdata) await redis.set('streamIsLive', '1');
await import("./events"); await import("./events");
await import("./pointRedeems");
await import("./web"); await import("./web");

View File

@@ -14,10 +14,10 @@ export default new Item({
name: ITEMNAME, name: ITEMNAME,
prettyName: 'Silver bullet', prettyName: 'Silver bullet',
plural: 's', plural: 's',
description: 'Times a specific person out for 24 hours', description: 'Times a specific person out for 30 minutes',
aliases: ['execute', 'silverbullet'], aliases: ['execute', 'silverbullet'],
specialaliases: ['blastin'], specialaliases: ['blastin'],
price: 6666, price: 666,
execution: async (msg, user, specialargs) => { execution: async (msg, user, specialargs) => {
const messagequery = parseCommandArgs(msg.messageText, specialargs?.activation); const messagequery = parseCommandArgs(msg.messageText, specialargs?.activation);
if (!messagequery[0]) { await sendMessage('Please specify a target'); return; }; if (!messagequery[0]) { await sendMessage('Please specify a target'); return; };
@@ -31,7 +31,7 @@ export default new Item({
const userObj = await getUserRecord(user); const userObj = await getUserRecord(user);
if (userObj.inventory[ITEMNAME]! < 1) { await sendMessage(`You don't have any silver bullets!`, msg.messageId); await user.clearLock(); return; }; if (userObj.inventory[ITEMNAME]! < 1) { await sendMessage(`You don't have any silver bullets!`, msg.messageId); await user.clearLock(); return; };
const result = await timeout(target, `You got blasted by ${user.displayName}!`, 60 * 60 * 24); const result = await timeout(target, `You got blasted by ${user.displayName}!`, 60 * 30);
if (result.status) await Promise.all([ if (result.status) await Promise.all([
sendMessage(`${target.displayName} RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO`), sendMessage(`${target.displayName} RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO`),
changeItemCount(user, userObj, ITEMNAME), changeItemCount(user, userObj, ITEMNAME),

77
src/pointRedeems/index.ts Normal file
View File

@@ -0,0 +1,77 @@
import { EventSubChannelRedemptionAddEvent } from "@twurple/eventsub-base";
import User from "user";
export type pointRedeemOptions = {
name: string;
title: string;
prompt?: string;
cost: number;
color?: string;
execution: (message: EventSubChannelRedemptionAddEvent, sender: User) => Promise<void>;
};
/** The Command class represents a command */
export default class PointRedeem {
public readonly name: string;
public readonly title: string;
public readonly prompt?: string;
public readonly cost: number;
public readonly color?: string;
public readonly execute: (message: EventSubChannelRedemptionAddEvent, sender: User) => Promise<void>;
constructor(options: pointRedeemOptions) {
this.name = options.name
this.title = options.title;
this.prompt = options.prompt;
this.cost = options.cost;
this.color = options.color;
this.execute = options.execution;
};
};
import { readdir } from 'node:fs/promises';
const pointRedeems = new Map<number, PointRedeem>;
/** A map of all (including inactive) redeems mapped to names */
const namedRedeems = new Map<string, PointRedeem>;
const files = await readdir(import.meta.dir);
for (const file of files) {
if (!file.endsWith('.ts')) continue;
if (file === import.meta.file) continue;
const redeem: PointRedeem = await import(import.meta.dir + '/' + file.slice(0, -3)).then(a => a.default);
pointRedeems.set(redeem.cost, redeem);
namedRedeems.set(redeem.name, redeem);
};
export { namedRedeems };
const activeRedeems = new Map<string, PointRedeem>;
import { streamerApi, streamerId } from "main";
import logger from "lib/logger";
const currentRedeems = new Map<string, string>;
await streamerApi.channelPoints.getCustomRewards(streamerId).then(a => a.map(b => currentRedeems.set(b.title, b.id)));
for (const [_, redeem] of Array.from(pointRedeems)) {
const selection = currentRedeems.get(redeem.title);
if (selection) {
currentRedeems.delete(redeem.title);
activeRedeems.set(selection, redeem);
} else {
const creation = await streamerApi.channelPoints.createCustomReward(streamerId, {
title: redeem.title,
prompt: redeem.prompt,
cost: redeem.cost,
backgroundColor: redeem.color
});
logger.ok(`Created custom point redeem ${redeem.title}`);
activeRedeems.set(creation.id, redeem);
};
};
Array.from(currentRedeems).map(async ([title, redeem]) => { await streamerApi.channelPoints.deleteCustomReward(streamerId, redeem); logger.ok(`Deleted custom point redeem ${title}`); });
logger.ok("Successfully synced all custom point redeems");
export { activeRedeems };

View File

@@ -0,0 +1,16 @@
import { sendMessage } from "commands";
import { getUserRecord } from "db/dbUser";
import { changeBalance } from "lib/changeBalance";
import PointRedeem from "pointRedeems";
export default new PointRedeem({
name: "qbucksredeem",
title: "FREE MONEY",
prompt: "GET 100 QBUCKS!",
color: '#00FF00',
cost: 1000,
execution: async (_msg, user) => {
await changeBalance(user, await getUserRecord(user), 100);
await sendMessage(`${user.displayName} got 100 qbucks for their point redeem`);
}
})

View File

@@ -3,18 +3,41 @@
"compilerOptions": { "compilerOptions": {
"baseUrl": "./src", "baseUrl": "./src",
"paths": { "paths": {
"lib/*": ["./lib/*"], "lib/*": [
"main": ["./index.ts"], "./lib/*"
"user": ["./user.ts"], ],
"commands": ["./commands/index.ts"], "main": [
"items": ["./items/index.ts"], "./index.ts"
"cheers": ["./cheers/index.ts"], ],
"events": ["./events/index.ts"], "user": [
"web/*": ["./web/*"] "./user.ts"
],
"commands": [
"./commands/index.ts"
],
"items": [
"./items/index.ts"
],
"cheers": [
"./cheers/index.ts"
],
"events": [
"./events/index.ts"
],
"web/*": [
"./web/*"
],
"pointRedeems": [
"./pointRedeems/index.ts"
]
} }
}, },
"references": [ "references": [
{ "path": "./tsconfig.bot.json" }, {
{ "path": "./tsconfig.web.json" } "path": "./tsconfig.bot.json"
},
{
"path": "./tsconfig.web.json"
}
] ]
} }