From c9fb09e36cb06cf85f8654cbb770094c0fc7cd91 Mon Sep 17 00:00:00 2001 From: qwerinope Date: Sat, 11 Oct 2025 18:59:02 +0200 Subject: [PATCH] minor fixes, add superloot cheer --- README.md | 11 +++++- bun.lock | 26 ++++++++------ package.json | 10 +++--- src/cheers/execute.ts | 2 +- src/cheers/superloot.ts | 68 ++++++++++++++++++++++++++++++++++++ src/commands/donateqbucks.ts | 2 +- src/commands/getloot.ts | 4 +-- src/db/dbGetLoot.ts | 7 ++-- src/db/dbUser.ts | 8 ++--- src/db/schema.ts | 3 ++ src/items/index.ts | 4 +-- src/items/silverbullet.ts | 2 +- src/lib/changeBalance.ts | 5 ++- src/lib/dateManager.ts | 2 +- src/lib/parseCommandArgs.ts | 2 +- 15 files changed, 119 insertions(+), 37 deletions(-) create mode 100644 src/cheers/superloot.ts diff --git a/README.md b/README.md index b3ae0f2..2b21923 100644 --- a/README.md +++ b/README.md @@ -90,12 +90,20 @@ ITEM|RATE -|- `grenade`|`1/5` `blaster`|`1/5` -`tnt`|`1/25` +`tnt`|`1/50` `silver bullet`|`1/250` Each of these rates get pulled 3 times, then the result is added to your inventory. It's theoretically possible to get 3 of each item. +As for superloot through the cheer, the qbucks range is 150-400. +Also the lootbox rates are the same, but pulled 15 times instead of 3. + +The chance for superloot to fail is 50%. +There is no cooldown on superloot. + +Any kind of loot is only obtainable while the stream is live. + ### Redeems Redeems will be created automatically when the bot starts. @@ -192,6 +200,7 @@ NAME|AMOUNT|USAGE|FUNCTION -|-|-|- `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 +`superloot`|150|`cheer150`|Get superloot. Details and drop rates can be found [(here)](#lootbox). `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 diff --git a/bun.lock b/bun.lock index c170114..61c2b75 100644 --- a/bun.lock +++ b/bun.lock @@ -99,35 +99,39 @@ "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.9", "", { "os": "win32", "cpu": "x64" }, "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ=="], - "@fontsource/jersey-15": ["@fontsource/jersey-15@5.2.6", "", {}, "sha512-3zkkEnu91esusWLqAK/AN1uc6jNtWT8idfO0UfYLqNlbMBKkbbiIVXtq6UbQsyegxnmRMppVV1J2t1zrJ36VgA=="], + "@fontsource/jersey-15": ["@fontsource/jersey-15@5.2.8", "", {}, "sha512-JwwDch3yuc2pm33mbmNwlsPRKMjD4jSDTCJk9ooW1+ryJFktQPmXvYBbP5wTAXZqNPaBWSYANibP4dd7CEFYZA=="], - "@twurple/api": ["@twurple/api@7.3.0", "", { "dependencies": { "@d-fischer/cache-decorators": "^4.0.0", "@d-fischer/cross-fetch": "^5.0.1", "@d-fischer/detect-node": "^3.0.1", "@d-fischer/logger": "^4.2.1", "@d-fischer/rate-limiter": "^1.1.0", "@d-fischer/shared-utils": "^3.6.1", "@d-fischer/typed-event-emitter": "^3.3.1", "@twurple/api-call": "7.3.0", "@twurple/common": "7.3.0", "retry": "^0.13.1", "tslib": "^2.0.3" }, "peerDependencies": { "@twurple/auth": "7.3.0" } }, "sha512-QtaVgYi50E3AB/Nxivjou/u6w1cuQ6g4R8lzQawYDaQNtlP2Ue8vvYuSp2PfxSpe8vNiKhgV8hZAs+j4V29sxQ=="], + "@twurple/api": ["@twurple/api@7.4.0", "", { "dependencies": { "@d-fischer/cache-decorators": "^4.0.0", "@d-fischer/cross-fetch": "^5.0.1", "@d-fischer/detect-node": "^3.0.1", "@d-fischer/logger": "^4.2.1", "@d-fischer/rate-limiter": "^1.1.0", "@d-fischer/shared-utils": "^3.6.1", "@d-fischer/typed-event-emitter": "^3.3.1", "@twurple/api-call": "7.4.0", "@twurple/common": "7.4.0", "retry": "^0.13.1", "tslib": "^2.0.3" }, "peerDependencies": { "@twurple/auth": "7.4.0" } }, "sha512-RlXLs4ZvS8n0+iIk7YyVDwrjhlwpn+N+h7fX5Q61HoxlmzoCShmnnFo03abYw9i8Cc3deGpbQATOSVmigXM4qg=="], - "@twurple/api-call": ["@twurple/api-call@7.3.0", "", { "dependencies": { "@d-fischer/cross-fetch": "^5.0.1", "@d-fischer/qs": "^7.0.2", "@d-fischer/shared-utils": "^3.6.1", "@twurple/common": "7.3.0", "tslib": "^2.0.3" } }, "sha512-nx389kXjVphAeR3RfnzkRRf7Qa45wqHla067/mr3YxnUICCg4YOFv0Jb5UohQGHkj5h18mDZ3iUu/x2J49c1lA=="], + "@twurple/api-call": ["@twurple/api-call@7.4.0", "", { "dependencies": { "@d-fischer/cross-fetch": "^5.0.1", "@d-fischer/qs": "^7.0.2", "@d-fischer/shared-utils": "^3.6.1", "@twurple/common": "7.4.0", "tslib": "^2.0.3" } }, "sha512-WNxvjp/hMqZREElbvE4rHMyUIrHdGY5cbG8xbqgSM9CESFvJ1wm5BubhyANOyKd1TxABacLddbfbO//Fz9YHgA=="], - "@twurple/auth": ["@twurple/auth@7.3.0", "", { "dependencies": { "@d-fischer/logger": "^4.2.1", "@d-fischer/shared-utils": "^3.6.1", "@d-fischer/typed-event-emitter": "^3.3.1", "@twurple/api-call": "7.3.0", "@twurple/common": "7.3.0", "tslib": "^2.0.3" } }, "sha512-K68nFbQswfaEVCWP2MEPcxhHRR/N8kIHBP6AnRXzgSpmvWxhjOitz9oyP04di5DI1rJE+2NRauv1qFDyYia/qg=="], + "@twurple/auth": ["@twurple/auth@7.4.0", "", { "dependencies": { "@d-fischer/logger": "^4.2.1", "@d-fischer/shared-utils": "^3.6.1", "@d-fischer/typed-event-emitter": "^3.3.1", "@twurple/api-call": "7.4.0", "@twurple/common": "7.4.0", "tslib": "^2.0.3" } }, "sha512-WAQV6nJGkfY7r2BkRYhnzUpdfozLvjNsCxkyNVprl4dCWdJzccnTvqkKTdDRJc5ZJxDVaB9Drzwx9/fCp/gRDA=="], - "@twurple/common": ["@twurple/common@7.3.0", "", { "dependencies": { "@d-fischer/shared-utils": "^3.6.1", "klona": "^2.0.4", "tslib": "^2.0.3" } }, "sha512-BGNniY7PBIohxfpRQ1bsOxUaktZcXZOExq8ojCtnsNBVDlchNEX2fYsere03ZwTLd48XBtxsdaUaeQXbx1aXLw=="], + "@twurple/common": ["@twurple/common@7.4.0", "", { "dependencies": { "@d-fischer/shared-utils": "^3.6.1", "klona": "^2.0.4", "tslib": "^2.0.3" } }, "sha512-lX5cVkYar6jGvni6iLmMYjhxH1oPSl2v7XVeZ4C7U1GbLz/Jwk0L0uldQNGUIf9gpRHPY+TXRlk0UIpz2yo8DA=="], - "@twurple/eventsub-base": ["@twurple/eventsub-base@7.3.0", "", { "dependencies": { "@d-fischer/logger": "^4.2.1", "@d-fischer/shared-utils": "^3.6.1", "@d-fischer/typed-event-emitter": "^3.3.0", "@twurple/api": "7.3.0", "@twurple/auth": "7.3.0", "@twurple/common": "7.3.0", "tslib": "^2.0.3" } }, "sha512-Wc/3qpyFfyvjabk/tQJVjAke+ixp5QWUT7LsuU+kMcCf46jsRQMB3InoXsZMRgX5sD1frBZzxUEJ7ujhxb8Ngw=="], + "@twurple/eventsub-base": ["@twurple/eventsub-base@7.4.0", "", { "dependencies": { "@d-fischer/logger": "^4.2.1", "@d-fischer/shared-utils": "^3.6.1", "@d-fischer/typed-event-emitter": "^3.3.0", "@twurple/api": "7.4.0", "@twurple/auth": "7.4.0", "@twurple/common": "7.4.0", "tslib": "^2.0.3" } }, "sha512-Umx0kNZKxBUTF2/MHAlnnCuNPs8Tl1Aw8EzDJI2AW10tOiWvgeCR889fKCFBPlHXvcMYSEvsItkX+pXeZ8GkeQ=="], - "@twurple/eventsub-ws": ["@twurple/eventsub-ws@7.3.0", "", { "dependencies": { "@d-fischer/connection": "^9.0.0", "@d-fischer/logger": "^4.2.1", "@d-fischer/shared-utils": "^3.6.1", "@d-fischer/typed-event-emitter": "^3.3.0", "@twurple/auth": "7.3.0", "@twurple/common": "7.3.0", "@twurple/eventsub-base": "7.3.0", "tslib": "^2.0.3" }, "peerDependencies": { "@twurple/api": "7.3.0" } }, "sha512-jtIMdW/atTrn5Eo3XGS8Lw0EIsK3GQsZGJDLYRwqw2bCV8ZnQoZ8YaXUJb5Wd+gebUfeBr4j7mvZlGc+Wkp17w=="], + "@twurple/eventsub-ws": ["@twurple/eventsub-ws@7.4.0", "", { "dependencies": { "@d-fischer/connection": "^9.0.0", "@d-fischer/logger": "^4.2.1", "@d-fischer/shared-utils": "^3.6.1", "@d-fischer/typed-event-emitter": "^3.3.0", "@twurple/auth": "7.4.0", "@twurple/common": "7.4.0", "@twurple/eventsub-base": "7.4.0", "tslib": "^2.0.3" }, "peerDependencies": { "@twurple/api": "7.4.0" } }, "sha512-tA5zGmb2kK4w//V0mK5P9WXl+KwNjkXXRTv3YO8AK9sCObFag9rsqJdrBNNyx6G58NJvQzQIDtHI1U2M9q1h5w=="], - "@types/bun": ["@types/bun@1.2.17", "", { "dependencies": { "bun-types": "1.2.17" } }, "sha512-l/BYs/JYt+cXA/0+wUhulYJB6a6p//GTPiJ7nV+QHa8iiId4HZmnu/3J/SowP5g0rTiERY2kfGKXEK5Ehltx4Q=="], + "@types/bun": ["@types/bun@1.3.0", "", { "dependencies": { "bun-types": "1.3.0" } }, "sha512-+lAGCYjXjip2qY375xX/scJeVRmZ5cY0wyHYyCYxNcdEXrQ4AOe3gACgd4iQ8ksOslJtW4VNxBJ8llUwc3a6AA=="], "@types/node": ["@types/node@22.15.18", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-v1DKRfUdyW+jJhZNEI1PYy29S2YRxMV5AOO/x/SjKmW0acCIOqmbj6Haf9eHAhsPmrhlHSxEhv/1WszcLWV4cg=="], + "@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="], + "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], - "bun-types": ["bun-types@1.2.17", "", { "dependencies": { "@types/node": "*" } }, "sha512-ElC7ItwT3SCQwYZDYoAH+q6KT4Fxjl8DtZ6qDulUFBmXA8YB4xo+l54J9ZJN+k2pphfn9vk7kfubeSd5QfTVJQ=="], + "bun-types": ["bun-types@1.3.0", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-u8X0thhx+yJ0KmkxuEo9HAtdfgCBaM/aI9K90VQcQioAmkVp3SG3FkwWGibUFz3WdXAdcsqOcbU40lK7tbHdkQ=="], + + "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], - "drizzle-kit": ["drizzle-kit@0.31.4", "", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.25.4", "esbuild-register": "^3.5.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-tCPWVZWZqWVx2XUsVpJRnH9Mx0ClVOf5YUHerZ5so1OKSlqww4zy1R5ksEdGRcO3tM3zj0PYN6V48TbQCL1RfA=="], + "drizzle-kit": ["drizzle-kit@0.31.5", "", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.25.4", "esbuild-register": "^3.5.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-+CHgPFzuoTQTt7cOYCV6MOw2w8vqEn/ap1yv4bpZOWL03u7rlVRQhUY0WYT3rHsgVTXwYQDZaSUJSQrMBUKuWg=="], - "drizzle-orm": ["drizzle-orm@0.44.5", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-jBe37K7d8ZSKptdKfakQFdeljtu3P2Cbo7tJoJSVZADzIKOBo9IAJPOmMsH2bZl90bZgh8FQlD8BjxXA/zuBkQ=="], + "drizzle-orm": ["drizzle-orm@0.44.6", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-uy6uarrrEOc9K1u5/uhBFJbdF5VJ5xQ/Yzbecw3eAYOunv5FDeYkR2m8iitocdHBOHbvorviKOW5GVw0U1j4LQ=="], "esbuild": ["esbuild@0.25.9", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.9", "@esbuild/android-arm": "0.25.9", "@esbuild/android-arm64": "0.25.9", "@esbuild/android-x64": "0.25.9", "@esbuild/darwin-arm64": "0.25.9", "@esbuild/darwin-x64": "0.25.9", "@esbuild/freebsd-arm64": "0.25.9", "@esbuild/freebsd-x64": "0.25.9", "@esbuild/linux-arm": "0.25.9", "@esbuild/linux-arm64": "0.25.9", "@esbuild/linux-ia32": "0.25.9", "@esbuild/linux-loong64": "0.25.9", "@esbuild/linux-mips64el": "0.25.9", "@esbuild/linux-ppc64": "0.25.9", "@esbuild/linux-riscv64": "0.25.9", "@esbuild/linux-s390x": "0.25.9", "@esbuild/linux-x64": "0.25.9", "@esbuild/netbsd-arm64": "0.25.9", "@esbuild/netbsd-x64": "0.25.9", "@esbuild/openbsd-arm64": "0.25.9", "@esbuild/openbsd-x64": "0.25.9", "@esbuild/openharmony-arm64": "0.25.9", "@esbuild/sunos-x64": "0.25.9", "@esbuild/win32-arm64": "0.25.9", "@esbuild/win32-ia32": "0.25.9", "@esbuild/win32-x64": "0.25.9" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g=="], diff --git a/package.json b/package.json index 7ed85a4..d2b727d 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "module": "src/index.ts", "devDependencies": { "@types/bun": "latest", - "drizzle-kit": "^0.31.4", + "drizzle-kit": "^0.31.5", "pg": "^8.16.3" }, "scripts": { @@ -20,10 +20,10 @@ "private": true, "type": "module", "dependencies": { - "@fontsource/jersey-15": "^5.2.6", - "@twurple/auth": "^7.3.0", - "@twurple/eventsub-ws": "^7.3.0", - "drizzle-orm": "^0.44.5", + "@fontsource/jersey-15": "^5.2.8", + "@twurple/auth": "^7.4.0", + "@twurple/eventsub-ws": "^7.4.0", + "drizzle-orm": "^0.44.6", "kleur": "^4.1.5" } } diff --git a/src/cheers/execute.ts b/src/cheers/execute.ts index 0e57832..b24f1de 100644 --- a/src/cheers/execute.ts +++ b/src/cheers/execute.ts @@ -19,7 +19,7 @@ export default new Cheer('execute', 666, async (msg, user) => { const result = await timeout(target, `You got executed by ${user.displayName}!`, 60 * 30); if (result.status) await Promise.all([ - sendMessage(`${target.displayName} RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO`), + sendMessage(`KEKPOINT KEKPOINT KEKPOINT ${target.displayName.toUpperCase()} RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO`), createTimeoutRecord(user, target, ITEMNAME), createCheerEventRecord(user, ITEMNAME), playAlert({ diff --git a/src/cheers/superloot.ts b/src/cheers/superloot.ts new file mode 100644 index 0000000..802cb53 --- /dev/null +++ b/src/cheers/superloot.ts @@ -0,0 +1,68 @@ +import { Cheer } from "cheers"; +import { sendMessage } from "commands"; +import { getUserRecord, updateUserRecord } from "db/dbUser"; +import itemMap, { type inventory, type items } from "items"; +import { createGetLootRecord } from "db/dbGetLoot"; +import { timeout } from "lib/timeout"; +import { redis } from "bun"; + +export default new Cheer('superloot', 150, async (msg, user) => { + if (!await redis.exists('streamIsLive')) { await sendMessage(`No loot while stream is offline`, msg.messageId); return; }; + if (await user.itemLock()) { await sendMessage(`Cannot get loot (itemlock)`, msg.messageId); return; }; + await user.setLock(); + const userData = await getUserRecord(user); + + await sendMessage("HOLD"); + await new Promise(res => setTimeout(res, 1000 * 5)); + + if (Math.random() > 0.5) { + await Promise.all([ + sendMessage(`SUPERLOOT FAILED!!! KEKPOINT KEKPOINT KEKPOINT ${msg.chatterDisplayName.toUpperCase()} SEE YOU IN 5 MINUTES!!!`), + timeout(user, `RIP BOZO! NO SUPERLOOT FOR YOU`, 60 * 5), + user.clearLock() + ]); + return; + }; + + const gainedqbucks = Math.floor(Math.random() * 250) + 150; // range from 150 to 400 + userData.balance += gainedqbucks; + + const itemDiff: inventory = { + grenade: 0, + blaster: 0, + tnt: 0, + silverbullet: 0 + }; + + for (let i = 0; i < 15; i++) { + if (Math.floor(Math.random() * 5) === 0) itemDiff.grenade! += 1; // 1 in 5 + if (Math.floor(Math.random() * 5) === 0) itemDiff.blaster! += 1; // 1 in 5 + if (Math.floor(Math.random() * 50) === 0) itemDiff.tnt! += 1; // 1 in 50 + if (Math.floor(Math.random() * 250) === 0) itemDiff.silverbullet! += 1; // 1 in 250 + }; + + for (const [item, amount] of Object.entries(itemDiff) as [items, number][]) { + if (userData.inventory[item]) userData.inventory[item] += amount; + else userData.inventory[item] = amount; + }; + + const itemstrings: string[] = [`${gainedqbucks} qbucks`]; + + for (const [item, amount] of Object.entries(itemDiff)) { + if (amount === 0) continue; + const selection = itemMap.get(item); + if (!selection) continue; + itemstrings.push(`${amount} ${selection.prettyName + (amount === 1 ? '' : selection.plural)}`); + }; + + const last = itemstrings.pop(); + const itemstring = itemstrings.length === 0 ? last : itemstrings.join(', ') + " and " + last; + const message = `You got ${itemstring}`; + + await Promise.all([ + updateUserRecord(user, userData), + sendMessage(message, msg.messageId), + createGetLootRecord(user, gainedqbucks, itemDiff, 'superloot'), + user.clearLock() + ]); +}, true); diff --git a/src/commands/donateqbucks.ts b/src/commands/donateqbucks.ts index 0bff8c7..3364eee 100644 --- a/src/commands/donateqbucks.ts +++ b/src/commands/donateqbucks.ts @@ -35,7 +35,7 @@ export default new Command({ await changeBalance(user, userRecord, -amount) ]); - if (!data.includes(false)) { + if (data[0] !== false && data[1] !== false) { const { balance: newamount } = data[0]; await sendMessage(`${user.displayName} gave ${amount} qweribuck${amount === 1 ? '' : 's'} to ${target.displayName}. They now have ${newamount} qweribuck${newamount === 1 ? '' : 's'}`, msg.messageId); } else { diff --git a/src/commands/getloot.ts b/src/commands/getloot.ts index 3084dd6..55ccf12 100644 --- a/src/commands/getloot.ts +++ b/src/commands/getloot.ts @@ -56,7 +56,7 @@ export default new Command({ for (let i = 0; i < 3; i++) { if (Math.floor(Math.random() * 5) === 0) itemDiff.grenade! += 1; // 1 in 5 if (Math.floor(Math.random() * 5) === 0) itemDiff.blaster! += 1; // 1 in 5 - if (Math.floor(Math.random() * 25) === 0) itemDiff.tnt! += 1; // 1 in 25 + if (Math.floor(Math.random() * 50) === 0) itemDiff.tnt! += 1; // 1 in 50 if (Math.floor(Math.random() * 250) === 0) itemDiff.silverbullet! += 1; // 1 in 250 }; @@ -81,7 +81,7 @@ export default new Command({ await Promise.all([ updateUserRecord(user, userData), sendMessage(message, msg.messageId), - createGetLootRecord(user, gainedqbucks, itemDiff), + createGetLootRecord(user, gainedqbucks, itemDiff, 'getloot'), user.clearLock() ]); } diff --git a/src/db/dbGetLoot.ts b/src/db/dbGetLoot.ts index 07ff620..9c20881 100644 --- a/src/db/dbGetLoot.ts +++ b/src/db/dbGetLoot.ts @@ -1,12 +1,13 @@ import db from "db/connection"; -import { getLoots } from "db/schema"; +import { getLoots, type lootTriggers } from "db/schema"; import type { inventory } from "items"; import type User from "user"; -export async function createGetLootRecord(user: User, qbucks: number, inventory: inventory) { +export async function createGetLootRecord(user: User, qbucks: number, inventory: inventory, trigger: lootTriggers) { await db.insert(getLoots).values({ user: parseInt(user.id), qbucks: qbucks, - items: inventory + items: inventory, + trigger }); }; diff --git a/src/db/dbUser.ts b/src/db/dbUser.ts index 9c079be..1fb8ed0 100644 --- a/src/db/dbUser.ts +++ b/src/db/dbUser.ts @@ -2,7 +2,7 @@ import db from "db/connection"; import { timeouts, users } from "db/schema"; import { itemarray, type inventory } from "items"; import type User from "user"; -import { count, desc, eq, inArray, sql, ne, between, and, SQL } from "drizzle-orm"; +import { count, desc, eq, inArray, sql, ne, between, and, SQL, type InferInsertModel, type InferSelectModel } from "drizzle-orm"; /** Use this function to both ensure existance and to retreive data */ export async function getUserRecord(user: User) { @@ -32,11 +32,9 @@ async function createUserRecord(user: User) { }); }; -export type balanceUpdate = { balance: number; }; -export type inventoryUpdate = { inventory: inventory; }; -type updateUser = balanceUpdate | inventoryUpdate; +export type UserRecord = InferSelectModel; -export async function updateUserRecord(user: User, newData: updateUser) { +export async function updateUserRecord(user: User, newData: UserRecord) { await db.update(users).set(newData).where(eq(users.id, parseInt(user.id))); return true; }; diff --git a/src/db/schema.ts b/src/db/schema.ts index 75be4b3..2c31731 100644 --- a/src/db/schema.ts +++ b/src/db/schema.ts @@ -107,11 +107,14 @@ export const anivTimeoutsRelations = relations(anivTimeouts, ({ one }) => ({ }) })); +export type lootTriggers = "getloot" | "superloot"; + export const getLoots = pgTable('getLoots', { id: uuid().defaultRandom().primaryKey(), user: integer().notNull().references(() => users.id), qbucks: integer().notNull(), items: jsonb().$type().notNull(), + trigger: varchar().$type().notNull(), created: timestamp().defaultNow().notNull() }); diff --git a/src/items/index.ts b/src/items/index.ts index f536307..2ed9e05 100644 --- a/src/items/index.ts +++ b/src/items/index.ts @@ -41,7 +41,7 @@ export class Item { }; import { readdir } from 'node:fs/promises'; -import { updateUserRecord, type inventoryUpdate } from "db/dbUser"; +import { updateUserRecord, type UserRecord } from "db/dbUser"; const itemAliasMap = new Map; const itemObjectArray: Item[] = [] const specialAliasItems = new Map; @@ -72,7 +72,7 @@ export type inventory = { [key in items]?: number; }; -export async function changeItemCount(user: User, userRecord: inventoryUpdate, itemname: items, amount = -1): Promise { +export async function changeItemCount(user: User, userRecord: UserRecord, itemname: items, amount = -1): Promise { userRecord.inventory[itemname] = userRecord.inventory[itemname]! += amount; if (userRecord.inventory[itemname] < 0) return false; await updateUserRecord(user, userRecord); diff --git a/src/items/silverbullet.ts b/src/items/silverbullet.ts index a92fc5d..c60d875 100644 --- a/src/items/silverbullet.ts +++ b/src/items/silverbullet.ts @@ -33,7 +33,7 @@ export default new Item({ const result = await timeout(target, `You got blasted by ${user.displayName}!`, 60 * 30); if (result.status) await Promise.all([ - sendMessage(`${target.displayName} RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO`), + sendMessage(`KEKPOINT KEKPOINT KEKPOINT ${target.displayName.toUpperCase()} RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO RIPBOZO`), changeItemCount(user, userObj, ITEMNAME), createTimeoutRecord(user, target, ITEMNAME), createUsedItemRecord(user, ITEMNAME), diff --git a/src/lib/changeBalance.ts b/src/lib/changeBalance.ts index df94e54..1d707cf 100644 --- a/src/lib/changeBalance.ts +++ b/src/lib/changeBalance.ts @@ -1,8 +1,7 @@ -import { updateUserRecord } from "db/dbUser"; -import { type userRecord } from "db/connection"; +import { updateUserRecord, type UserRecord } from "db/dbUser"; import User from "user"; -export async function changeBalance(user: User, userRecord: userRecord, amount: number): Promise { +export async function changeBalance(user: User, userRecord: UserRecord, amount: number): Promise { userRecord.balance = userRecord.balance += amount; if (userRecord.balance < 0) return false; await updateUserRecord(user, userRecord); diff --git a/src/lib/dateManager.ts b/src/lib/dateManager.ts index 8a8ed94..00a1267 100644 --- a/src/lib/dateManager.ts +++ b/src/lib/dateManager.ts @@ -14,4 +14,4 @@ export function buildTimeString(time1: number, time2: number): string { }; const last = stringarray.pop(); return stringarray.length === 0 ? last! : stringarray.join(', ') + " and " + last; -}; +}; \ No newline at end of file diff --git a/src/lib/parseCommandArgs.ts b/src/lib/parseCommandArgs.ts index 90e6b2a..295f79d 100644 --- a/src/lib/parseCommandArgs.ts +++ b/src/lib/parseCommandArgs.ts @@ -17,7 +17,7 @@ export function parseCheerArgs(input: string) { const nice = input.toLowerCase().trim(); // This is for the test command. Remove the command prefix, the command, the whitespace after and the amount of fake bits - if (nice.startsWith(commandPrefix + 'testcheer')) return nice.slice(commandPrefix.length + 'testcheer'.length + 1).replaceAll(/\W/g, '').split(' ').slice(1); + if (nice.startsWith(commandPrefix + 'testcheer')) return nice.slice(commandPrefix.length + 'testcheer'.length + 1).replace(/[^\x00-\x7F]/g, '').split(' ').slice(1); // This is for actual cheers. Remove all 'cheerx' parts of the message return nice.split(' ').filter(a => !/cheer[0-9]+/i.test(a));