mirror of
https://github.com/qwerinope/qweribot.git
synced 2025-12-19 05:51:37 +01:00
rework aniv timeouts, fix ghost whisper message, invuln status tweaks
This commit is contained in:
@@ -15,11 +15,12 @@ Admins have the power to destroy the item economy. Be very careful with admin po
|
|||||||
### Invulns
|
### Invulns
|
||||||
|
|
||||||
Invulns, or invulnerable chatters cannot be shot with items and cannot get hit by explosives.
|
Invulns, or invulnerable chatters cannot be shot with items and cannot get hit by explosives.
|
||||||
They can however use items.
|
When an invuln uses an item or a lootbox they lose their invuln status.
|
||||||
The intended use for invulns is for when you need to talk to a chatter, or for using other bots.
|
The intended use for invulns is for when you need to talk to a chatter, or for using other bots.
|
||||||
Invulns don't need moderator or vip status in the channel.
|
Invulns don't need moderator or vip status in the channel.
|
||||||
The chatterbot and streamer always are invuln and cannot be stripped of this status.
|
The chatterbot and streamer always are invuln and cannot be stripped of this status.
|
||||||
Admins can add and remove invulns.
|
Moderators can add and remove invulns.
|
||||||
|
On your first message in chat you will recieve 10 minutes of invuln status.
|
||||||
|
|
||||||
### Commands
|
### Commands
|
||||||
|
|
||||||
@@ -40,7 +41,7 @@ A full list of Commands can be found [here](#commands-1)
|
|||||||
### Timeouts and ghost whispers
|
### Timeouts and ghost whispers
|
||||||
|
|
||||||
If you've been timed out, you can ghost whisper a message to the chatterbot and it will relay your message to the chat.
|
If you've been timed out, you can ghost whisper a message to the chatterbot and it will relay your message to the chat.
|
||||||
You can only send one message every 10 minutes.
|
You can only send one message every 5 minutes.
|
||||||
Try to bargain for your release with the chatter that shot you, or just call them names.
|
Try to bargain for your release with the chatter that shot you, or just call them names.
|
||||||
|
|
||||||
### Leaderboards
|
### Leaderboards
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import { getUserRecord, updateUserRecord } from "db/dbUser";
|
|||||||
import items from "items";
|
import items from "items";
|
||||||
import { buildTimeString } from "lib/dateManager";
|
import { buildTimeString } from "lib/dateManager";
|
||||||
import { timeout } from "lib/timeout";
|
import { timeout } from "lib/timeout";
|
||||||
|
import { isInvuln, removeInvuln } from "lib/invuln";
|
||||||
|
import { streamerUsers } from "main";
|
||||||
|
|
||||||
const COOLDOWN = 10 * 60 * 1000; // 10 mins (ms)
|
const COOLDOWN = 10 * 60 * 1000; // 10 mins (ms)
|
||||||
|
|
||||||
@@ -13,6 +15,7 @@ export default new Command({
|
|||||||
usertype: 'chatter',
|
usertype: 'chatter',
|
||||||
execution: async (msg, user) => {
|
execution: async (msg, user) => {
|
||||||
if (!await redis.exists('streamIsLive')) { await sendMessage(`No loot while stream is offline`, msg.messageId); return; };
|
if (!await redis.exists('streamIsLive')) { await sendMessage(`No loot while stream is offline`, msg.messageId); return; };
|
||||||
|
if (await isInvuln(msg.chatterId) && !streamerUsers.includes(msg.chatterId)) { await sendMessage(`You're no longer an invuln because used a lootbox.`, msg.messageId); await removeInvuln(msg.chatterId); };
|
||||||
if (await user.itemLock()) { await sendMessage(`Cannot get loot (itemlock)`, msg.messageId); return; };
|
if (await user.itemLock()) { await sendMessage(`Cannot get loot (itemlock)`, msg.messageId); return; };
|
||||||
const userData = await getUserRecord(user);
|
const userData = await getUserRecord(user);
|
||||||
const lastlootbox = Date.parse(userData.lastlootbox);
|
const lastlootbox = Date.parse(userData.lastlootbox);
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { redis } from "bun";
|
import { redis } from "bun";
|
||||||
import { Command, sendMessage } from "commands";
|
import { Command, sendMessage } from "commands";
|
||||||
import items from "items";
|
import items from "items";
|
||||||
|
import { isInvuln, removeInvuln } from "lib/invuln";
|
||||||
|
import { streamerUsers } from "main";
|
||||||
|
|
||||||
export default new Command({
|
export default new Command({
|
||||||
name: 'use',
|
name: 'use',
|
||||||
@@ -13,6 +15,7 @@ export default new Command({
|
|||||||
const selection = items.get(messagequery[0].toLowerCase());
|
const selection = items.get(messagequery[0].toLowerCase());
|
||||||
if (!selection) { await sendMessage(`'${messagequery[0]}' is not an item`, msg.messageId); return; };
|
if (!selection) { await sendMessage(`'${messagequery[0]}' is not an item`, msg.messageId); return; };
|
||||||
if (await redis.sismember('disabledcommands', selection.name)) { await sendMessage(`The ${selection.prettyName} item is disabled`, msg.messageId); return; };
|
if (await redis.sismember('disabledcommands', selection.name)) { await sendMessage(`The ${selection.prettyName} item is disabled`, msg.messageId); return; };
|
||||||
|
if (await isInvuln(msg.chatterId) && !streamerUsers.includes(msg.chatterId)) { await sendMessage(`You're no longer an invuln because you used an item.`, msg.messageId); await removeInvuln(msg.chatterId); };
|
||||||
await selection.execute(msg, user);
|
await selection.execute(msg, user);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,10 +7,11 @@ import { isAdmin } from "lib/admins";
|
|||||||
import cheers from "cheers";
|
import cheers from "cheers";
|
||||||
import logger from "lib/logger";
|
import logger from "lib/logger";
|
||||||
import { addMessageToChatWidget } from "web/chatWidget/message";
|
import { addMessageToChatWidget } from "web/chatWidget/message";
|
||||||
import { isInvuln, setTemporaryInvuln } from "lib/invuln";
|
import { isInvuln, removeInvuln, setTemporaryInvuln } from "lib/invuln";
|
||||||
import { getUserRecord } from "db/dbUser";
|
import { getUserRecord } from "db/dbUser";
|
||||||
import { createCheerRecord } from "db/dbCheers";
|
import { createCheerRecord } from "db/dbCheers";
|
||||||
import handleAnivMessage from "lib/handleAnivMessage";
|
import handleAnivMessage from "lib/handleAnivMessage";
|
||||||
|
import { Item } from "items";
|
||||||
|
|
||||||
eventSub.onChannelChatMessage(streamerId, streamerId, parseChatMessage);
|
eventSub.onChannelChatMessage(streamerId, streamerId, parseChatMessage);
|
||||||
|
|
||||||
@@ -50,8 +51,9 @@ async function handleChatMessage(msg: EventSubChannelChatMessageEvent, user: Use
|
|||||||
// Parse commands:
|
// Parse commands:
|
||||||
const selected = selectCommand(msg.messageText);
|
const selected = selectCommand(msg.messageText);
|
||||||
if (!selected) return;
|
if (!selected) return;
|
||||||
const { cmd: selection, activation } = selected;
|
const { cmd: selection, activation, isitem } = selected;
|
||||||
if (await redis.sismember('disabledcommands', selection.name)) return;
|
if (await redis.sismember('disabledcommands', selection.name)) return;
|
||||||
|
if (isitem && await isInvuln(msg.chatterId) && !streamerUsers.includes(msg.chatterId)) { await sendMessage(`You're no longer an invuln because you used an item.`, msg.messageId); await removeInvuln(msg.chatterId); };
|
||||||
|
|
||||||
switch (selection.usertype) {
|
switch (selection.usertype) {
|
||||||
case "admin":
|
case "admin":
|
||||||
@@ -80,15 +82,16 @@ async function handleChatMessage(msg: EventSubChannelChatMessageEvent, user: Use
|
|||||||
type selectedCommand = {
|
type selectedCommand = {
|
||||||
cmd: Command;
|
cmd: Command;
|
||||||
activation: string;
|
activation: string;
|
||||||
|
isitem: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
function selectCommand(message: string): selectedCommand | false {
|
function selectCommand(message: string): selectedCommand | false {
|
||||||
const specialcmdselector = message.trim().toLowerCase().split(' ')[0]!;
|
const specialcmdselector = message.trim().toLowerCase().split(' ')[0]!;
|
||||||
const specialcmd = specialAliasCommands.get(specialcmdselector);
|
const specialcmd = specialAliasCommands.get(specialcmdselector);
|
||||||
if (specialcmd) return { cmd: specialcmd, activation: specialcmdselector };
|
if (specialcmd) return { cmd: specialcmd, activation: specialcmdselector, isitem: specialcmd instanceof Item };
|
||||||
const commandSelector = message.slice(commandPrefix.length).trim().toLowerCase().split(' ')[0]!;
|
const commandSelector = message.slice(commandPrefix.length).trim().toLowerCase().split(' ')[0]!;
|
||||||
const normalcmd = commands.get(commandSelector);
|
const normalcmd = commands.get(commandSelector);
|
||||||
if (normalcmd) return { cmd: normalcmd, activation: commandPrefix + commandSelector };
|
if (normalcmd) return { cmd: normalcmd, activation: commandPrefix + commandSelector, isitem: normalcmd instanceof Item };
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -9,10 +9,11 @@ chatterEventSub.onUserWhisperMessage(chatterId, async msg => {
|
|||||||
if (await redis.ttl(`user:${msg.senderUserId}:timeout`) < 0) return;
|
if (await redis.ttl(`user:${msg.senderUserId}:timeout`) < 0) return;
|
||||||
const cooldown = await redis.expiretime(`user:${msg.senderUserId}:whispercooldown`);
|
const cooldown = await redis.expiretime(`user:${msg.senderUserId}:whispercooldown`);
|
||||||
if (cooldown < 0) {
|
if (cooldown < 0) {
|
||||||
|
if (msg.messageText.length > 200) { await chatterApi.whispers.sendWhisper(chatterId, msg.senderUserId, `Message too long. Please send a shorter one.`); return; };
|
||||||
await redis.set(`user:${msg.senderUserId}:whispercooldown`, '1');
|
await redis.set(`user:${msg.senderUserId}:whispercooldown`, '1');
|
||||||
await redis.expire(`user:${msg.senderUserId}:whispercooldown`, WHISPERCOOLDOWN);
|
await redis.expire(`user:${msg.senderUserId}:whispercooldown`, WHISPERCOOLDOWN);
|
||||||
await sendMessage(`The ghost of ${msg.senderUserDisplayName} whispered: ${msg.messageText}`);
|
await sendMessage(`The ghost of ${msg.senderUserDisplayName} whispered: ${msg.messageText}`);
|
||||||
await chatterApi.whispers.sendWhisper(chatterId, msg.senderUserId, "Message sent. You can send another ghost whisper in 10 minutes.");
|
await chatterApi.whispers.sendWhisper(chatterId, msg.senderUserId, `Message sent. You can send another ghost whisper in ${Math.floor(WHISPERCOOLDOWN / 60)} minutes.`);
|
||||||
} else {
|
} else {
|
||||||
await chatterApi.whispers.sendWhisper(chatterId, msg.senderUserId, `Wait another ${buildTimeString(cooldown * 1000, Date.now())} before sending another ghost whisper.`);
|
await chatterApi.whispers.sendWhisper(chatterId, msg.senderUserId, `Wait another ${buildTimeString(cooldown * 1000, Date.now())} before sending another ghost whisper.`);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ export default new Item({
|
|||||||
await user.setLock();
|
await user.setLock();
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
timeout(target!, `You got hit by ${user.displayName}'s grenade!`, 60),
|
timeout(target!, `You got hit by ${user.displayName}'s grenade!`, 60),
|
||||||
redis.del(selection),
|
|
||||||
sendMessage(`wybuh ${target?.displayName} got hit by ${user.displayName}'s grenade wybuh`),
|
sendMessage(`wybuh ${target?.displayName} got hit by ${user.displayName}'s grenade wybuh`),
|
||||||
changeItemCount(user, userObj, ITEMNAME),
|
changeItemCount(user, userObj, ITEMNAME),
|
||||||
createTimeoutRecord(user, target!, ITEMNAME),
|
createTimeoutRecord(user, target!, ITEMNAME),
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ export default new Item({
|
|||||||
await getUserRecord(target!); // make sure the user record exist in the database
|
await getUserRecord(target!); // make sure the user record exist in the database
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
timeout(target!, `You got hit by ${user.displayName}'s TNT!`, 60),
|
timeout(target!, `You got hit by ${user.displayName}'s TNT!`, 60),
|
||||||
redis.del(`user:${targetid}:vulnerable`),
|
|
||||||
sendMessage(`wybuh ${target?.displayName} got hit by ${user.displayName}'s TNT wybuh`),
|
sendMessage(`wybuh ${target?.displayName} got hit by ${user.displayName}'s TNT wybuh`),
|
||||||
createTimeoutRecord(user, target!, ITEMNAME),
|
createTimeoutRecord(user, target!, ITEMNAME),
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -5,15 +5,45 @@ import { timeout } from "lib/timeout";
|
|||||||
import { sendMessage } from "commands";
|
import { sendMessage } from "commands";
|
||||||
import { createAnivTimeoutRecord } from "db/dbAnivTimeouts";
|
import { createAnivTimeoutRecord } from "db/dbAnivTimeouts";
|
||||||
|
|
||||||
const ANIVNAMES = ['a_n_e_e_v', 'a_n_i_v', 'a_c_a_c'];
|
const ANIVNAMES = ['a_n_e_e_v', 'a_n_i_v'];
|
||||||
|
|
||||||
|
type anivMessageStore = {
|
||||||
|
[key: string]: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type IsAnivMessage = {
|
||||||
|
isAnivMessage: true;
|
||||||
|
message: string;
|
||||||
|
anivbot: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type isNotAnivMessage = {
|
||||||
|
isAnivMessage: false;
|
||||||
|
};
|
||||||
|
|
||||||
|
type anivMessageResult = IsAnivMessage | isNotAnivMessage;
|
||||||
|
|
||||||
|
async function isAnivMessage(message: string): Promise<anivMessageResult> {
|
||||||
|
const data: anivMessageStore = await redis.get('anivmessages').then(a => a === null ? {} : JSON.parse(a));
|
||||||
|
for (const clanker of ANIVNAMES) {
|
||||||
|
const anivmessage = data[clanker];
|
||||||
|
if (!anivmessage) continue;
|
||||||
|
if (anivmessage === message) return { isAnivMessage: true, message, anivbot: clanker };
|
||||||
|
};
|
||||||
|
return { isAnivMessage: false };
|
||||||
|
};
|
||||||
|
|
||||||
export default async function handleMessage(msg: EventSubChannelChatMessageEvent, user: User) {
|
export default async function handleMessage(msg: EventSubChannelChatMessageEvent, user: User) {
|
||||||
if (ANIVNAMES.includes(user.displayName)) {
|
if (ANIVNAMES.includes(user.displayName)) {
|
||||||
await redis.set('lastanivmessage', msg.messageText);
|
const data: anivMessageStore = await redis.get('anivmessages').then(a => a === null ? {} : JSON.parse(a));
|
||||||
await redis.expire('lastanivmessage', 120); // store for 2 minutes
|
data[user.displayName] = msg.messageText;
|
||||||
} else if (msg.messageText === await redis.get('lastanivmessage')) await Promise.all([
|
await redis.set('anivmessages', JSON.stringify(data));
|
||||||
timeout(user, 'copied an aniv message', 30),
|
} else {
|
||||||
sendMessage(`${user.displayName} got timed out for copying an a_n_e_e_v message`),
|
const data = await isAnivMessage(msg.messageText);
|
||||||
createAnivTimeoutRecord(msg.messageText, user, 30)
|
if (data.isAnivMessage) await Promise.all([
|
||||||
]);
|
timeout(user, 'copied an aniv message', 30),
|
||||||
|
sendMessage(`${user.displayName} got timed out for copying an ${data.anivbot} message`),
|
||||||
|
createAnivTimeoutRecord(msg.messageText, user, 30)
|
||||||
|
]);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { redis } from "bun";
|
import { redis } from "bun";
|
||||||
|
import { streamerUsers } from "main";
|
||||||
|
|
||||||
export async function getInvulns() {
|
export async function getInvulns() {
|
||||||
const data = await redis.keys('user:*:invulnerable');
|
const data = await redis.keys('user:*:invulnerable');
|
||||||
@@ -13,6 +14,7 @@ export async function addInvuln(userid: string) {
|
|||||||
return await redis.set(`user:${userid}:invulnerable`, '1');
|
return await redis.set(`user:${userid}:invulnerable`, '1');
|
||||||
};
|
};
|
||||||
export async function removeInvuln(userid: string) {
|
export async function removeInvuln(userid: string) {
|
||||||
|
if (streamerUsers.includes(userid)) return;
|
||||||
return await redis.del(`user:${userid}:invulnerable`);
|
return await redis.del(`user:${userid}:invulnerable`);
|
||||||
};
|
};
|
||||||
export async function setTemporaryInvuln(userid: string, duration = 600) {
|
export async function setTemporaryInvuln(userid: string, duration = 600) {
|
||||||
|
|||||||
Reference in New Issue
Block a user