From a417d87661601858a0b621023b7201eabc079be4 Mon Sep 17 00:00:00 2001 From: holzmaster Date: Sat, 15 Nov 2025 15:02:00 +0100 Subject: [PATCH 1/4] Migrate LootAttributeClass --- src/commands/gegenstand.ts | 2 +- src/service/lootData.ts | 35 ++++++++++---------- src/service/lootDrop.ts | 6 ++-- src/storage/migrations/10-loot-attributes.ts | 4 +-- src/storage/migrations/16-nutri-score.ts | 10 +++--- 5 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/commands/gegenstand.ts b/src/commands/gegenstand.ts index 20d41fe55..cf26c3ac3 100644 --- a/src/commands/gegenstand.ts +++ b/src/commands/gegenstand.ts @@ -265,7 +265,7 @@ export default class GegenstandCommand implements ApplicationCommand { const nutriScoreColor = lootDataService.getAttributesByClass( otherAttributes, - lootDataService.LootAttributeClassId.NUTRI_SCORE, + lootDataService.LootAttributeClass.NUTRI_SCORE, )[0]?.color; await interaction.reply({ diff --git a/src/service/lootData.ts b/src/service/lootData.ts index 78a794f52..618854e21 100644 --- a/src/service/lootData.ts +++ b/src/service/lootData.ts @@ -63,11 +63,12 @@ export enum LootKindId { BABYBEL_EXODIA = 50, } -export enum LootAttributeClassId { - OTHER = 0, - RARITY = 1, - NUTRI_SCORE = 2, -} +export const LootAttributeClass = Object.freeze({ + OTHER: 0, + RARITY: 1, + NUTRI_SCORE: 2, +}); +export type LootAttributeClassId = (typeof LootAttributeClass)[keyof typeof LootAttributeClass]; export enum LootAttributeKindId { RARITY_NORMAL = 0, @@ -767,69 +768,69 @@ export const lootTemplates: LootTemplate[] = Object.values(lootTemplateMap); export const lootAttributeTemplates: LootAttributeTemplate[] = [ { id: LootAttributeKindId.RARITY_NORMAL, - classId: LootAttributeClassId.RARITY, + classId: LootAttributeClass.RARITY, displayName: "Normal", shortDisplay: "", initialDropWeight: 90, }, { id: LootAttributeKindId.RARITY_RARE, - classId: LootAttributeClassId.RARITY, + classId: LootAttributeClass.RARITY, displayName: "Selten", shortDisplay: "⭐", initialDropWeight: 10, }, { id: LootAttributeKindId.RARITY_VERY_RARE, - classId: LootAttributeClassId.RARITY, + classId: LootAttributeClass.RARITY, displayName: "Sehr Selten", shortDisplay: "🌟", initialDropWeight: 1, }, { id: LootAttributeKindId.RADIOACTIVE, - classId: LootAttributeClassId.OTHER, + classId: LootAttributeClass.OTHER, displayName: "Verstrahlt", shortDisplay: "☢️", color: 0xff_ff_ff, }, { id: LootAttributeKindId.SWEET, - classId: LootAttributeClassId.OTHER, + classId: LootAttributeClass.OTHER, displayName: "Süß", shortDisplay: "🍬", }, { id: LootAttributeKindId.NUTRI_SCORE_A, - classId: LootAttributeClassId.NUTRI_SCORE, + classId: LootAttributeClass.NUTRI_SCORE, displayName: "Nutri-Score A", shortDisplay: "🟩", color: 0x00_ff_00, }, { id: LootAttributeKindId.NUTRI_SCORE_B, - classId: LootAttributeClassId.NUTRI_SCORE, + classId: LootAttributeClass.NUTRI_SCORE, displayName: "Nutri-Score B", shortDisplay: "🟨", color: 0x99_ff_00, }, { id: LootAttributeKindId.NUTRI_SCORE_C, - classId: LootAttributeClassId.NUTRI_SCORE, + classId: LootAttributeClass.NUTRI_SCORE, displayName: "Nutri-Score C", shortDisplay: "🟧", color: 0xff_ff_00, }, { id: LootAttributeKindId.NUTRI_SCORE_D, - classId: LootAttributeClassId.NUTRI_SCORE, + classId: LootAttributeClass.NUTRI_SCORE, displayName: "Nutri-Score D", shortDisplay: "🟥", color: 0xff_99_00, }, { id: LootAttributeKindId.NUTRI_SCORE_E, - classId: LootAttributeClassId.NUTRI_SCORE, + classId: LootAttributeClass.NUTRI_SCORE, displayName: "Nutri-Score E", shortDisplay: "🟥", color: 0xff_00_00, @@ -859,14 +860,14 @@ export function getAttributesByClass( export function extractRarityAttribute( attributes: readonly Readonly[], ): Readonly | undefined { - const rarities = getAttributesByClass(attributes, LootAttributeClassId.RARITY); + const rarities = getAttributesByClass(attributes, LootAttributeClass.RARITY); return rarities[0] ?? undefined; } export function extractNonRarityAttributes( attributes: readonly Readonly[], ): Readonly[] { - return attributes.filter(a => a.attributeClassId !== LootAttributeClassId.RARITY); + return attributes.filter(a => a.attributeClassId !== LootAttributeClass.RARITY); } export function itemHasAttribute( diff --git a/src/service/lootDrop.ts b/src/service/lootDrop.ts index 09e8a7ebc..f887507f0 100644 --- a/src/service/lootDrop.ts +++ b/src/service/lootDrop.ts @@ -27,7 +27,7 @@ import { randomBoolean, randomEntry, randomEntryWeighted } from "#service/random import * as lootService from "#service/loot.ts"; import { - LootAttributeClassId, + LootAttributeClass, lootAttributeTemplates, LootKindId, lootTemplates, @@ -160,7 +160,7 @@ export async function postLootDrop( const template = randomEntryWeighted(lootTemplates, weights); - const rarities = lootAttributeTemplates.filter(a => a.classId === LootAttributeClassId.RARITY); + const rarities = lootAttributeTemplates.filter(a => a.classId === LootAttributeClass.RARITY); const rarityWeights = rarities.map(a => a.initialDropWeight ?? 0); const rarityAttribute = @@ -322,7 +322,7 @@ export async function createDropTakenContent( const lootAttributes = await lootService.getLootAttributes(claimedLoot.id); const rarityAttribute = lootAttributes.filter( - a => a.attributeClassId === LootAttributeClassId.RARITY, + a => a.attributeClassId === LootAttributeClass.RARITY, )[0]; if (rarityAttribute) { diff --git a/src/storage/migrations/10-loot-attributes.ts b/src/storage/migrations/10-loot-attributes.ts index a8a872b5c..a3ccc6e31 100644 --- a/src/storage/migrations/10-loot-attributes.ts +++ b/src/storage/migrations/10-loot-attributes.ts @@ -37,7 +37,7 @@ export async function up(db: Kysely) { .insertInto("lootAttribute") .values({ lootId: id, - attributeClassId: 1, // LootAttributeClassId.RARITY + attributeClassId: 1, // LootAttributeClass.RARITY attributeKindId: 0, // LootAttributeKindId.RARITY_NORMAL displayName: "Normal", shortDisplay: "", @@ -52,7 +52,7 @@ export async function up(db: Kysely) { .insertInto("lootAttribute") .values({ lootId: id, - attributeClassId: 0, // LootAttributeClassId.OTHER + attributeClassId: 0, // LootAttributeClass.OTHER attributeKindId: 4, // LootAttributeKindId.SWEET displayName: "Süß", shortDisplay: "🍬", diff --git a/src/storage/migrations/16-nutri-score.ts b/src/storage/migrations/16-nutri-score.ts index 72cfe4056..30c831845 100644 --- a/src/storage/migrations/16-nutri-score.ts +++ b/src/storage/migrations/16-nutri-score.ts @@ -11,7 +11,7 @@ export async function up(db: Kysely): Promise { .values({ lootId: loot.id, attributeKindId: 5, // LootAttributeKindId.NUTRI_SCORE_A, - attributeClassId: 2, // LootAttributeClassId.NUTRI_SCORE, + attributeClassId: 2, // LootAttributeClass.NUTRI_SCORE, displayName: "Nutri-Score A", shortDisplay: "🟩", color: 0x00_ff_00, @@ -26,7 +26,7 @@ export async function up(db: Kysely): Promise { .values({ lootId: loot.id, attributeKindId: 6, // LootAttributeKindId.NUTRI_SCORE_B, - attributeClassId: 2, // LootAttributeClassId.NUTRI_SCORE, + attributeClassId: 2, // LootAttributeClass.NUTRI_SCORE, displayName: "Nutri-Score B", shortDisplay: "🟨", color: 0x99_ff_00, @@ -41,7 +41,7 @@ export async function up(db: Kysely): Promise { .values({ lootId: loot.id, attributeKindId: 7, // LootAttributeKindId.NUTRI_SCORE_C, - attributeClassId: 2, // LootAttributeClassId.NUTRI_SCORE, + attributeClassId: 2, // LootAttributeClass.NUTRI_SCORE, displayName: "Nutri-Score C", shortDisplay: "🟧", color: 0xff_ff_00, @@ -58,7 +58,7 @@ export async function up(db: Kysely): Promise { .values({ lootId: loot.id, attributeKindId: 8, // LootAttributeKindId.NUTRI_SCORE_D, - attributeClassId: 2, // LootAttributeClassId.NUTRI_SCORE, + attributeClassId: 2, // LootAttributeClass.NUTRI_SCORE, displayName: "Nutri-Score D", shortDisplay: "🟥", color: 0xff_99_00, @@ -73,7 +73,7 @@ export async function up(db: Kysely): Promise { .values({ lootId: loot.id, attributeKindId: 9, // LootAttributeKindId.NUTRI_SCORE_E, - attributeClassId: 2, // LootAttributeClassId.NUTRI_SCORE, + attributeClassId: 2, // LootAttributeClass.NUTRI_SCORE, displayName: "Nutri-Score E", shortDisplay: "🟥", From 70495b0d995e4f76185aeee3285d29ae986acfc3 Mon Sep 17 00:00:00 2001 From: holzmaster Date: Sat, 15 Nov 2025 15:11:44 +0100 Subject: [PATCH 2/4] Migrate LootKindId --- src/commands/gegenstand.ts | 4 +- src/service/birthday.ts | 2 +- src/service/hatching.ts | 18 +- src/service/loot.ts | 5 +- src/service/lootData.ts | 321 ++++++++++--------- src/service/lootDegradation.ts | 14 +- src/service/lootDrop.ts | 12 +- src/service/lootRoles.ts | 4 +- src/service/pet.ts | 16 +- src/storage/db/model.ts | 5 +- src/storage/loot.ts | 17 +- src/storage/migrations/10-loot-attributes.ts | 2 +- src/storage/migrations/16-nutri-score.ts | 14 +- 13 files changed, 223 insertions(+), 211 deletions(-) diff --git a/src/commands/gegenstand.ts b/src/commands/gegenstand.ts index cf26c3ac3..5d4348422 100644 --- a/src/commands/gegenstand.ts +++ b/src/commands/gegenstand.ts @@ -23,7 +23,7 @@ import { ensureChatInputCommand } from "#utils/interactionUtils.ts"; import * as imageService from "#service/image.ts"; import * as lootDataService from "#service/lootData.ts"; -import { LootAttributeKindId, LootKindId } from "#service/lootData.ts"; +import { LootAttributeKindId, LootKind } from "#service/lootData.ts"; import log from "#log"; @@ -156,7 +156,7 @@ export default class GegenstandCommand implements ApplicationCommand { const wasteContents = await lootService.getUserLootsByTypeId( interaction.user.id, - LootKindId.RADIOACTIVE_WASTE, + LootKind.RADIOACTIVE_WASTE, ); if (wasteContents.length === 0) { diff --git a/src/service/birthday.ts b/src/service/birthday.ts index 6d78c78be..cf46b8603 100644 --- a/src/service/birthday.ts +++ b/src/service/birthday.ts @@ -103,7 +103,7 @@ ${userString} ${gotPresents ? "Zum Geurtstag habt ihr ein Geschenk erhalten" : " } async function awardBirthdayPresents(users: GuildMember[]) { - const present = lootDataService.resolveLootTemplate(lootDataService.LootKindId.GESCHENK); + const present = lootDataService.resolveLootTemplate(lootDataService.LootKind.GESCHENK); if (!present) { throw new Error("Could not resolve loot template"); } diff --git a/src/service/hatching.ts b/src/service/hatching.ts index d106f750b..e3e9905b8 100644 --- a/src/service/hatching.ts +++ b/src/service/hatching.ts @@ -7,7 +7,7 @@ import type { Loot } from "#storage/db/model.ts"; import log from "#log"; import * as time from "#utils/time.ts"; import * as lootService from "#service/loot.ts"; -import { LootKindId, resolveLootTemplate } from "./lootData.ts"; +import { LootKind, resolveLootTemplate } from "./lootData.ts"; import * as randomService from "./random.ts"; export async function hatchEggs(context: BotContext) { @@ -15,7 +15,7 @@ export async function hatchEggs(context: BotContext) { const now = Date.now(); const maxEggAge = time.days(30); - const eggs = await lootService.getLootsByKindId(LootKindId.EI); + const eggs = await lootService.getLootsByKindId(LootKind.EI); for (const e of eggs) { const itemAge = now - new Date(e.claimedAt).getTime(); @@ -34,15 +34,15 @@ export async function hatchEggs(context: BotContext) { } async function hatchEgg(context: BotContext, egg: Loot) { - console.assert(egg.lootKindId === LootKindId.EI, "Can only hatch eggs"); + console.assert(egg.lootKindId === LootKind.EI, "Can only hatch eggs"); const hatchCandidates = [ - LootKindId.KADSE, - LootKindId.BIBER, - LootKindId.FERRIS, - LootKindId.OETTINGER, - LootKindId.THUNFISCHSHAKE, - LootKindId.EI, + LootKind.KADSE, + LootKind.BIBER, + LootKind.FERRIS, + LootKind.OETTINGER, + LootKind.THUNFISCHSHAKE, + LootKind.EI, ]; const hatchWeights = [10, 10, 10, 1, 1, 5]; diff --git a/src/service/loot.ts b/src/service/loot.ts index d875416d6..a9dc17ca7 100644 --- a/src/service/loot.ts +++ b/src/service/loot.ts @@ -32,7 +32,10 @@ export async function getLootAttributes(id: LootId) { return await loot.getLootAttributes(id); } -export async function getUserLootCountById(userId: Snowflake, lootTypeId: number): Promise { +export async function getUserLootCountById( + userId: Snowflake, + lootTypeId: LootKindId, +): Promise { return (await loot.getUserLootsByTypeId(userId, lootTypeId)).length; } diff --git a/src/service/lootData.ts b/src/service/lootData.ts index 618854e21..09f6022fa 100644 --- a/src/service/lootData.ts +++ b/src/service/lootData.ts @@ -9,65 +9,66 @@ import type { Loot, LootAttribute } from "#storage/db/model.ts"; const ACHTUNG_NICHT_DROPBAR_WEIGHT_KG = 0; -export enum LootKindId { - NICHTS = 0, - KADSE = 1, - MESSERBLOCK = 2, - KUEHLSCHRANK = 3, - DOENER = 4, - KINN = 5, - KRANKSCHREIBUNG = 6, - WUERFELWURF = 7, - GESCHENK = 8, - AYRAN = 9, - PKV = 10, - TRICHTER = 11, - GRAFIKKARTE = 12, - HAENDEDRUCK = 13, - ERLEUCHTUNG = 14, - BAN = 15, - OETTINGER = 16, - ACHIEVEMENT = 17, - GME_AKTIE = 18, - FERRIS = 19, - HOMEPOD = 20, - RADIOACTIVE_WASTE = 21, - SAHNE = 22, - AEHRE = 23, - CROWDSTRIKE = 24, - POWERADE_BLAU = 25, - GAULOISES_BLAU = 26, - MAXWELL = 27, - SCHICHTBEGINN_ASSE_2 = 28, - DRECK = 29, - EI = 30, - BRAVO = 31, - VERSCHIMMELTER_DOENER = 32, - THUNFISCHSHAKE = 33, - KAFFEEMUEHLE = 34, - AWS_RECHNUNG = 35, - BIBER = 36, - BLEI = 37, - USV = 38, - BAHNCARD_25 = 39, - BAHNCARD_50 = 40, - BAHNCARD_100 = 41, - LABUBU = 42, - BABYBEL_ORIGINAL = 43, - BABYBEL_LIGHT = 44, - BABYBEL_CHEDDAR = 45, - BABYBEL_EMMENTALER = 46, - BABYBEL_PROTEIN = 47, - BABYBEL_GOUDA = 48, - BABYBEL_VEGAN = 49, - BABYBEL_EXODIA = 50, -} +export const LootKind = Object.freeze({ + NICHTS: 0, + KADSE: 1, + MESSERBLOCK: 2, + KUEHLSCHRANK: 3, + DOENER: 4, + KINN: 5, + KRANKSCHREIBUNG: 6, + WUERFELWURF: 7, + GESCHENK: 8, + AYRAN: 9, + PKV: 10, + TRICHTER: 11, + GRAFIKKARTE: 12, + HAENDEDRUCK: 13, + ERLEUCHTUNG: 14, + BAN: 15, + OETTINGER: 16, + ACHIEVEMENT: 17, + GME_AKTIE: 18, + FERRIS: 19, + HOMEPOD: 20, + RADIOACTIVE_WASTE: 21, + SAHNE: 22, + AEHRE: 23, + CROWDSTRIKE: 24, + POWERADE_BLAU: 25, + GAULOISES_BLAU: 26, + MAXWELL: 27, + SCHICHTBEGINN_ASSE_2: 28, + DRECK: 29, + EI: 30, + BRAVO: 31, + VERSCHIMMELTER_DOENER: 32, + THUNFISCHSHAKE: 33, + KAFFEEMUEHLE: 34, + AWS_RECHNUNG: 35, + BIBER: 36, + BLEI: 37, + USV: 38, + BAHNCARD_25: 39, + BAHNCARD_50: 40, + BAHNCARD_100: 41, + LABUBU: 42, + BABYBEL_ORIGINAL: 43, + BABYBEL_LIGHT: 44, + BABYBEL_CHEDDAR: 45, + BABYBEL_EMMENTALER: 46, + BABYBEL_PROTEIN: 47, + BABYBEL_GOUDA: 48, + BABYBEL_VEGAN: 49, + BABYBEL_EXODIA: 50, +} as const); +export type LootKindId = (typeof LootKind)[keyof typeof LootKind]; export const LootAttributeClass = Object.freeze({ OTHER: 0, RARITY: 1, NUTRI_SCORE: 2, -}); +} as const); export type LootAttributeClassId = (typeof LootAttributeClass)[keyof typeof LootAttributeClass]; export enum LootAttributeKindId { @@ -84,8 +85,8 @@ export enum LootAttributeKindId { } export const lootTemplateMap: Record = { - [LootKindId.NICHTS]: { - id: LootKindId.NICHTS, + [LootKind.NICHTS]: { + id: LootKind.NICHTS, weight: 24, displayName: "Nichts", titleText: "✨Nichts✨", @@ -96,8 +97,8 @@ export const lootTemplateMap: Record = { excludeFromInventory: true, excludeFromDoubleDrops: true, }, - [LootKindId.KADSE]: { - id: LootKindId.KADSE, + [LootKind.KADSE]: { + id: LootKind.KADSE, weight: 4, displayName: "Niedliche Kadse", titleText: "Eine niedliche Kadse", @@ -109,8 +110,8 @@ export const lootTemplateMap: Record = { [LootAttributeKindId.RADIOACTIVE]: "assets/loot/attributes/01-kadse-verstrahlt.jpg", }, }, - [LootKindId.MESSERBLOCK]: { - id: LootKindId.MESSERBLOCK, + [LootKind.MESSERBLOCK]: { + id: LootKind.MESSERBLOCK, weight: 1, displayName: "Messerblock", titleText: "Einen Messerblock", @@ -118,8 +119,8 @@ export const lootTemplateMap: Record = { emote: "🔪", asset: "assets/loot/02-messerblock.jpg", }, - [LootKindId.KUEHLSCHRANK]: { - id: LootKindId.KUEHLSCHRANK, + [LootKind.KUEHLSCHRANK]: { + id: LootKind.KUEHLSCHRANK, weight: 1, displayName: "Sehr teurer Kühlschrank", titleText: "Ein sehr teurer Kühlschrank", @@ -129,8 +130,8 @@ export const lootTemplateMap: Record = { asset: "assets/loot/03-kuehlschrank.jpg", effects: ["Lässt Essen nicht schimmeln"], }, - [LootKindId.DOENER]: { - id: LootKindId.DOENER, + [LootKind.DOENER]: { + id: LootKind.DOENER, weight: 5, displayName: "Döner", titleText: "Einen Döner", @@ -139,8 +140,8 @@ export const lootTemplateMap: Record = { asset: "assets/loot/04-doener.jpg", initialAttributes: [LootAttributeKindId.NUTRI_SCORE_C], }, - [LootKindId.KINN]: { - id: LootKindId.KINN, + [LootKind.KINN]: { + id: LootKind.KINN, weight: 0.5, displayName: "Kinn", titleText: "Ein Kinn", @@ -148,8 +149,8 @@ export const lootTemplateMap: Record = { emote: "👶", asset: "assets/loot/05-kinn.jpg", }, - [LootKindId.KRANKSCHREIBUNG]: { - id: LootKindId.KRANKSCHREIBUNG, + [LootKind.KRANKSCHREIBUNG]: { + id: LootKind.KRANKSCHREIBUNG, weight: 0.5, displayName: "Arbeitsunfähigkeitsbescheinigung", titleText: "Einen gelben Urlaubsschein", @@ -181,8 +182,8 @@ export const lootTemplateMap: Record = { return false; }, }, - [LootKindId.WUERFELWURF]: { - id: LootKindId.WUERFELWURF, + [LootKind.WUERFELWURF]: { + id: LootKind.WUERFELWURF, weight: 4, displayName: "Würfelwurf", titleText: "Einen Wurf mit einem Würfel", @@ -196,8 +197,8 @@ export const lootTemplateMap: Record = { await rollService.rollInChannel(winner.user, channel, 1, 6); }, }, - [LootKindId.GESCHENK]: { - id: LootKindId.GESCHENK, + [LootKind.GESCHENK]: { + id: LootKind.GESCHENK, weight: 2, displayName: "Geschenk", titleText: "Ein Geschenk", @@ -214,8 +215,8 @@ export const lootTemplateMap: Record = { return false; }, }, - [LootKindId.AYRAN]: { - id: LootKindId.AYRAN, + [LootKind.AYRAN]: { + id: LootKind.AYRAN, weight: 1, displayName: "Ayran", titleText: "Einen Ayran", @@ -224,8 +225,8 @@ export const lootTemplateMap: Record = { asset: "assets/loot/09-ayran.png", initialAttributes: [LootAttributeKindId.NUTRI_SCORE_D], // Ref: https://de.openfoodfacts.org/produkt/4388860730685/ayran-ja }, - [LootKindId.PKV]: { - id: LootKindId.PKV, + [LootKind.PKV]: { + id: LootKind.PKV, weight: 1, displayName: "Private Krankenversicherung", titleText: "Eine private Krankenversicherung", @@ -234,8 +235,8 @@ export const lootTemplateMap: Record = { asset: "assets/loot/10-pkv.jpg", effects: ["` +100% ` Chance auf AU 🟢"], }, - [LootKindId.TRICHTER]: { - id: LootKindId.TRICHTER, + [LootKind.TRICHTER]: { + id: LootKind.TRICHTER, weight: 1, displayName: "Trichter", titleText: "Einen Trichter", @@ -243,8 +244,8 @@ export const lootTemplateMap: Record = { emote: ":trichter:", asset: "assets/loot/11-trichter.png", }, - [LootKindId.GRAFIKKARTE]: { - id: LootKindId.GRAFIKKARTE, + [LootKind.GRAFIKKARTE]: { + id: LootKind.GRAFIKKARTE, weight: 1, displayName: "Grafikkarte aus der Zukunft", titleText: "Eine Grafikkarte aus der Zukunft", @@ -252,8 +253,8 @@ export const lootTemplateMap: Record = { emote: "🖥️", asset: "assets/loot/12-grafikkarte.png", }, - [LootKindId.HAENDEDRUCK]: { - id: LootKindId.HAENDEDRUCK, + [LootKind.HAENDEDRUCK]: { + id: LootKind.HAENDEDRUCK, weight: 1, displayName: "Feuchter Händedruck", titleText: "Einen feuchten Händedruck", @@ -262,8 +263,8 @@ export const lootTemplateMap: Record = { asset: "assets/loot/13-haendedruck.jpg", excludeFromInventory: true, }, - [LootKindId.ERLEUCHTUNG]: { - id: LootKindId.ERLEUCHTUNG, + [LootKind.ERLEUCHTUNG]: { + id: LootKind.ERLEUCHTUNG, weight: 1, displayName: "Erleuchtung", titleText: "Eine Erleuchtung", @@ -283,8 +284,8 @@ export const lootTemplateMap: Record = { }); }, }, - [LootKindId.BAN]: { - id: LootKindId.BAN, + [LootKind.BAN]: { + id: LootKind.BAN, weight: 1, displayName: "Willkürban", titleText: "Einen Ban aus reiner Willkür", @@ -305,8 +306,8 @@ export const lootTemplateMap: Record = { ); }, }, - [LootKindId.OETTINGER]: { - id: LootKindId.OETTINGER, + [LootKind.OETTINGER]: { + id: LootKind.OETTINGER, weight: 1, displayName: "Oettinger", titleText: "Ein warmes Oettinger", @@ -315,8 +316,8 @@ export const lootTemplateMap: Record = { asset: "assets/loot/16-oettinger.png", initialAttributes: [LootAttributeKindId.NUTRI_SCORE_B], // Ref: https://archive.is/aonnZ }, - [LootKindId.ACHIEVEMENT]: { - id: LootKindId.ACHIEVEMENT, + [LootKind.ACHIEVEMENT]: { + id: LootKind.ACHIEVEMENT, weight: 1, displayName: "Achievement", titleText: "Ein Achievement", @@ -324,8 +325,8 @@ export const lootTemplateMap: Record = { emote: "🏆", asset: "assets/loot/17-achievement.png", }, - [LootKindId.GME_AKTIE]: { - id: LootKindId.GME_AKTIE, + [LootKind.GME_AKTIE]: { + id: LootKind.GME_AKTIE, weight: 5, displayName: "Wertlose GME-Aktie", titleText: "Eine wertlose GME-Aktie", @@ -333,8 +334,8 @@ export const lootTemplateMap: Record = { emote: "📉", asset: "assets/loot/18-gme.jpg", }, - [LootKindId.FERRIS]: { - id: LootKindId.FERRIS, + [LootKind.FERRIS]: { + id: LootKind.FERRIS, weight: 3, displayName: "Ferris", titleText: "Einen Ferris - Die Krabbe", @@ -342,8 +343,8 @@ export const lootTemplateMap: Record = { emote: "🦀", asset: "assets/loot/19-ferris.png", }, - [LootKindId.HOMEPOD]: { - id: LootKindId.HOMEPOD, + [LootKind.HOMEPOD]: { + id: LootKind.HOMEPOD, weight: 3, displayName: "HomePod", titleText: "Einen Apple:registered: HomePod:copyright:", @@ -351,8 +352,8 @@ export const lootTemplateMap: Record = { emote: "🍎", asset: "assets/loot/20-homepod.jpg", }, - [LootKindId.RADIOACTIVE_WASTE]: { - id: LootKindId.RADIOACTIVE_WASTE, + [LootKind.RADIOACTIVE_WASTE]: { + id: LootKind.RADIOACTIVE_WASTE, weight: 1, displayName: "Radioaktiver Müll", titleText: "Radioaktiver Müll", @@ -362,8 +363,8 @@ export const lootTemplateMap: Record = { asset: "assets/loot/21-radioaktiver-muell.jpg", effects: ["` +5% ` Chance auf leeres Geschenk 🔴"], }, - [LootKindId.SAHNE]: { - id: LootKindId.SAHNE, + [LootKind.SAHNE]: { + id: LootKind.SAHNE, weight: 1, displayName: "Sprühsahne", titleText: "Sprühsahne", @@ -372,8 +373,8 @@ export const lootTemplateMap: Record = { asset: "assets/loot/22-sahne.png", initialAttributes: [LootAttributeKindId.NUTRI_SCORE_D], // Ref: https://de.openfoodfacts.org/produkt/4311501745663/spr%C3%BChsahne-gut-g%C3%BCnstig }, - [LootKindId.AEHRE]: { - id: LootKindId.AEHRE, + [LootKind.AEHRE]: { + id: LootKind.AEHRE, weight: 1, displayName: "Ehre", titleText: "Ehre aus Mitleid", @@ -387,8 +388,8 @@ export const lootTemplateMap: Record = { await ehre.addPoints(winner.id, 1); }, }, - [LootKindId.CROWDSTRIKE]: { - id: LootKindId.CROWDSTRIKE, + [LootKind.CROWDSTRIKE]: { + id: LootKind.CROWDSTRIKE, weight: 1, displayName: "Crowdstrike Falcon", titleText: "Crowdstrike Falcon Installation", @@ -396,8 +397,8 @@ export const lootTemplateMap: Record = { emote: "🦅", asset: "assets/loot/24-crowdstrike.jpg", }, - [LootKindId.POWERADE_BLAU]: { - id: LootKindId.POWERADE_BLAU, + [LootKind.POWERADE_BLAU]: { + id: LootKind.POWERADE_BLAU, weight: 1, displayName: "Blaue Powerade", titleText: "Blaue Powerade", @@ -406,8 +407,8 @@ export const lootTemplateMap: Record = { emote: ":powerade:", initialAttributes: [LootAttributeKindId.NUTRI_SCORE_D], // Ref: https://de.openfoodfacts.org/produkt/90357350/powerrade-mountain-blast-blue-coca-cola }, - [LootKindId.GAULOISES_BLAU]: { - id: LootKindId.GAULOISES_BLAU, + [LootKind.GAULOISES_BLAU]: { + id: LootKind.GAULOISES_BLAU, weight: 1, displayName: "Gauloises Blau", titleText: "Eine Schachtel Gauloises Blau", @@ -416,8 +417,8 @@ export const lootTemplateMap: Record = { emote: "🚬", asset: "assets/loot/26-gauloises-blau.png", }, - [LootKindId.MAXWELL]: { - id: LootKindId.MAXWELL, + [LootKind.MAXWELL]: { + id: LootKind.MAXWELL, weight: 1, displayName: "Maxwell", titleText: "Einen Maxwell", @@ -425,8 +426,8 @@ export const lootTemplateMap: Record = { emote: "😸", asset: "assets/loot/27-maxwell.gif", }, - [LootKindId.SCHICHTBEGINN_ASSE_2]: { - id: LootKindId.SCHICHTBEGINN_ASSE_2, + [LootKind.SCHICHTBEGINN_ASSE_2]: { + id: LootKind.SCHICHTBEGINN_ASSE_2, weight: 4, displayName: "Wärter Asse II", titleText: "Den Schichtbeginn in der Asse II", @@ -440,8 +441,8 @@ export const lootTemplateMap: Record = { await lootRoles.startAsseGuardShift(context, winner, channel); }, }, - [LootKindId.DRECK]: { - id: LootKindId.DRECK, + [LootKind.DRECK]: { + id: LootKind.DRECK, weight: 2, displayName: "Ein Glas Dreck", titleText: "Ein Glas Dreck", @@ -449,8 +450,8 @@ export const lootTemplateMap: Record = { emote: "🫙", asset: "assets/loot/29-dreck.jpg", }, - [LootKindId.EI]: { - id: LootKindId.EI, + [LootKind.EI]: { + id: LootKind.EI, weight: 3, displayName: "Ei", titleText: "Ein Ei", @@ -459,8 +460,8 @@ export const lootTemplateMap: Record = { emote: "🥚", asset: "assets/loot/30-ei.png", }, - [LootKindId.BRAVO]: { - id: LootKindId.BRAVO, + [LootKind.BRAVO]: { + id: LootKind.BRAVO, weight: 2, displayName: "Bravo", titleText: "Eine Bravo vom Dachboden", @@ -468,8 +469,8 @@ export const lootTemplateMap: Record = { emote: "🗞️", asset: "assets/loot/31-bravo.jpg", }, - [LootKindId.VERSCHIMMELTER_DOENER]: { - id: LootKindId.VERSCHIMMELTER_DOENER, + [LootKind.VERSCHIMMELTER_DOENER]: { + id: LootKind.VERSCHIMMELTER_DOENER, weight: ACHTUNG_NICHT_DROPBAR_WEIGHT_KG, displayName: "Verschimmelter Döner", titleText: "Einen verschimmelten Döner", @@ -478,8 +479,8 @@ export const lootTemplateMap: Record = { asset: null, initialAttributes: [LootAttributeKindId.NUTRI_SCORE_E], }, - [LootKindId.THUNFISCHSHAKE]: { - id: LootKindId.THUNFISCHSHAKE, + [LootKind.THUNFISCHSHAKE]: { + id: LootKind.THUNFISCHSHAKE, weight: 2, displayName: "Thunfischshake", titleText: "Ein Thunfischshake, serviert von Markus Rühl persönlich", @@ -488,8 +489,8 @@ export const lootTemplateMap: Record = { asset: "assets/loot/33-thunfischshake.jpg", initialAttributes: [LootAttributeKindId.NUTRI_SCORE_A], }, - [LootKindId.KAFFEEMUEHLE]: { - id: LootKindId.KAFFEEMUEHLE, + [LootKind.KAFFEEMUEHLE]: { + id: LootKind.KAFFEEMUEHLE, weight: 1, displayName: "Kaffeemühle", titleText: "Eine Kaffeemühle für 400€", @@ -497,8 +498,8 @@ export const lootTemplateMap: Record = { emote: "☕", asset: "assets/loot/34-kaffeemuehle.png", }, - [LootKindId.AWS_RECHNUNG]: { - id: LootKindId.AWS_RECHNUNG, + [LootKind.AWS_RECHNUNG]: { + id: LootKind.AWS_RECHNUNG, weight: 1, displayName: "AWS-Rechnung", titleText: "Ne dicke AWS-Rechnung", @@ -506,8 +507,8 @@ export const lootTemplateMap: Record = { emote: "📦", asset: "assets/loot/35-aws-rechnung.png", }, - [LootKindId.BIBER]: { - id: LootKindId.BIBER, + [LootKind.BIBER]: { + id: LootKind.BIBER, weight: 2, displayName: "Süßer Biber", titleText: "Bóbr", @@ -516,8 +517,8 @@ export const lootTemplateMap: Record = { asset: "assets/loot/36-biber.jpg", initialAttributes: [LootAttributeKindId.SWEET], }, - [LootKindId.BLEI]: { - id: LootKindId.BLEI, + [LootKind.BLEI]: { + id: LootKind.BLEI, weight: ACHTUNG_NICHT_DROPBAR_WEIGHT_KG, displayName: "Blei", titleText: "Einen Block Blei", @@ -526,8 +527,8 @@ export const lootTemplateMap: Record = { asset: "assets/loot/37-blei.png", initialAttributes: [], }, - [LootKindId.USV]: { - id: LootKindId.USV, + [LootKind.USV]: { + id: LootKind.USV, weight: 2, displayName: "USV", titleText: "Eine kaputte USV", @@ -536,8 +537,8 @@ export const lootTemplateMap: Record = { asset: "assets/loot/38-usv.png", initialAttributes: [], }, - [LootKindId.BAHNCARD_25]: { - id: LootKindId.BAHNCARD_25, + [LootKind.BAHNCARD_25]: { + id: LootKind.BAHNCARD_25, weight: 6, displayName: "BahnCard 25", titleText: "Eine BahnCard 25", @@ -556,7 +557,7 @@ export const lootTemplateMap: Record = { ), onDuplicateDrop: async (context, winner, loot, dropMessage) => { // biome-ignore lint/style/noNonNullAssertion: :shrug: - const newBc = resolveLootTemplate(LootKindId.BAHNCARD_50)!; + const newBc = resolveLootTemplate(LootKind.BAHNCARD_50)!; const newLoot = await lootService.replaceLoot( loot.id, @@ -575,7 +576,7 @@ export const lootTemplateMap: Record = { const newContent = await lootDropService.createDropTakenContent( context, - lootTemplateMap[LootKindId.BAHNCARD_50], + lootTemplateMap[LootKind.BAHNCARD_50], newLoot, winner.user, [ @@ -587,8 +588,8 @@ export const lootTemplateMap: Record = { return false; }, }, - [LootKindId.BAHNCARD_50]: { - id: LootKindId.BAHNCARD_50, + [LootKind.BAHNCARD_50]: { + id: LootKind.BAHNCARD_50, weight: 3, displayName: "BahnCard 50", titleText: "Eine BahnCard 50", @@ -607,7 +608,7 @@ export const lootTemplateMap: Record = { ), onDuplicateDrop: async (context, winner, loot, dropMessage) => { // biome-ignore lint/style/noNonNullAssertion: :shrug: - const newBc = resolveLootTemplate(LootKindId.BAHNCARD_100)!; + const newBc = resolveLootTemplate(LootKind.BAHNCARD_100)!; const newLoot = await lootService.replaceLoot( loot.id, @@ -626,7 +627,7 @@ export const lootTemplateMap: Record = { const newContent = await lootDropService.createDropTakenContent( context, - lootTemplateMap[LootKindId.BAHNCARD_100], + lootTemplateMap[LootKind.BAHNCARD_100], newLoot, winner.user, [ @@ -638,9 +639,9 @@ export const lootTemplateMap: Record = { return false; }, }, - [LootKindId.BAHNCARD_100]: { + [LootKind.BAHNCARD_100]: { // Not droppable, only via duplicate BahnCard 50 - id: LootKindId.BAHNCARD_100, + id: LootKind.BAHNCARD_100, weight: ACHTUNG_NICHT_DROPBAR_WEIGHT_KG, displayName: "BahnCard 100", titleText: "Eine BahnCard 100", @@ -651,8 +652,8 @@ export const lootTemplateMap: Record = { drawCustomAsset: (context, owner, template, loot) => bahnCardService.drawBahncardImage(context, owner, template, loot, true, owner.id), }, - [LootKindId.LABUBU]: { - id: LootKindId.LABUBU, + [LootKind.LABUBU]: { + id: LootKind.LABUBU, weight: 1, displayName: "Labubu", titleText: "Einen Labubu", @@ -660,8 +661,8 @@ export const lootTemplateMap: Record = { emote: "🦦", asset: "assets/loot/42-labubu.jpg", }, - [LootKindId.BABYBEL_ORIGINAL]: { - id: LootKindId.BABYBEL_ORIGINAL, + [LootKind.BABYBEL_ORIGINAL]: { + id: LootKind.BABYBEL_ORIGINAL, weight: 3, displayName: "Mini Babybel® Original", titleText: "Ein Babybel® Original", @@ -671,8 +672,8 @@ export const lootTemplateMap: Record = { asset: "assets/loot/43-bb-original.png", initialAttributes: [LootAttributeKindId.NUTRI_SCORE_C], }, - [LootKindId.BABYBEL_LIGHT]: { - id: LootKindId.BABYBEL_LIGHT, + [LootKind.BABYBEL_LIGHT]: { + id: LootKind.BABYBEL_LIGHT, weight: 2, displayName: "Mini Babybel® Light", titleText: "Ein Babybel® Light", @@ -681,8 +682,8 @@ export const lootTemplateMap: Record = { asset: "assets/loot/44-bb-light.png", initialAttributes: [LootAttributeKindId.NUTRI_SCORE_C], }, - [LootKindId.BABYBEL_CHEDDAR]: { - id: LootKindId.BABYBEL_CHEDDAR, + [LootKind.BABYBEL_CHEDDAR]: { + id: LootKind.BABYBEL_CHEDDAR, weight: 1, displayName: "Mini Babybel® Cheddar-Geschmack", titleText: "Ein Babybel® Cheddar-Geschmack", @@ -692,8 +693,8 @@ export const lootTemplateMap: Record = { asset: "assets/loot/45-bb-cheddar.png", initialAttributes: [LootAttributeKindId.NUTRI_SCORE_D], }, - [LootKindId.BABYBEL_EMMENTALER]: { - id: LootKindId.BABYBEL_EMMENTALER, + [LootKind.BABYBEL_EMMENTALER]: { + id: LootKind.BABYBEL_EMMENTALER, weight: 1, displayName: "Mini Babybel® Emmentaler-Geschmack", titleText: "Ein Babybel® Emmentaler-Geschmack", @@ -703,8 +704,8 @@ export const lootTemplateMap: Record = { asset: "assets/loot/46-bb-emmentaler.png", initialAttributes: [LootAttributeKindId.NUTRI_SCORE_D], }, - [LootKindId.BABYBEL_PROTEIN]: { - id: LootKindId.BABYBEL_PROTEIN, + [LootKind.BABYBEL_PROTEIN]: { + id: LootKind.BABYBEL_PROTEIN, weight: 1, displayName: "Mini Babybel® High Protein", titleText: "Ein Babybel® High Protein", @@ -714,8 +715,8 @@ export const lootTemplateMap: Record = { asset: "assets/loot/47-bb-protein.png", initialAttributes: [LootAttributeKindId.NUTRI_SCORE_C], }, - [LootKindId.BABYBEL_GOUDA]: { - id: LootKindId.BABYBEL_GOUDA, + [LootKind.BABYBEL_GOUDA]: { + id: LootKind.BABYBEL_GOUDA, weight: 1, displayName: "Mini Babybel® Unser Würziger", titleText: "Ein Babybel® Unser Würziger", @@ -725,8 +726,8 @@ export const lootTemplateMap: Record = { asset: "assets/loot/48-bb-gouda.png", initialAttributes: [LootAttributeKindId.NUTRI_SCORE_D], }, - [LootKindId.BABYBEL_VEGAN]: { - id: LootKindId.BABYBEL_VEGAN, + [LootKind.BABYBEL_VEGAN]: { + id: LootKind.BABYBEL_VEGAN, weight: 1, displayName: "Mini Babybel® Vegan", titleText: "Ein Babybel® Vegan", @@ -736,8 +737,8 @@ export const lootTemplateMap: Record = { asset: "assets/loot/49-bb-vegan.png", initialAttributes: [LootAttributeKindId.NUTRI_SCORE_E], }, - [LootKindId.BABYBEL_EXODIA]: { - id: LootKindId.BABYBEL_EXODIA, + [LootKind.BABYBEL_EXODIA]: { + id: LootKind.BABYBEL_EXODIA, weight: ACHTUNG_NICHT_DROPBAR_WEIGHT_KG, displayName: "Mini Babybel® Exodia", titleText: "Mini Babybel® Exodia", diff --git a/src/service/lootDegradation.ts b/src/service/lootDegradation.ts index 97a4a97b9..33697599d 100644 --- a/src/service/lootDegradation.ts +++ b/src/service/lootDegradation.ts @@ -3,7 +3,7 @@ import type { BotContext } from "#context.ts"; import * as time from "#utils/time.ts"; import * as lootService from "#service/loot.ts"; -import { LootAttributeKindId, LootKindId, resolveLootTemplate } from "#service/lootData.ts"; +import { LootAttributeKindId, LootKind, resolveLootTemplate } from "#service/lootData.ts"; import log from "#log"; import { randomEntry } from "#service/random.ts"; @@ -12,7 +12,7 @@ export async function degradeItems(_context: BotContext) { const now = Date.now(); const maxKebabAge = time.days(3); - const kebabs = await lootService.getLootsByKindId(LootKindId.DOENER); + const kebabs = await lootService.getLootsByKindId(LootKind.DOENER); for (const k of kebabs) { const itemAge = now - new Date(k.claimedAt).getTime(); @@ -20,7 +20,7 @@ export async function degradeItems(_context: BotContext) { continue; } - const fridges = await lootService.getUserLootsByTypeId(k.winnerId, LootKindId.KUEHLSCHRANK); + const fridges = await lootService.getUserLootsByTypeId(k.winnerId, LootKind.KUEHLSCHRANK); if (fridges.length > 0) { // user has a fridge, don't verschimmel döner @@ -31,7 +31,7 @@ export async function degradeItems(_context: BotContext) { k.id, { displayName: "Verschimmelter Döner", - lootKindId: LootKindId.VERSCHIMMELTER_DOENER, + lootKindId: LootKind.VERSCHIMMELTER_DOENER, winnerId: k.winnerId, claimedAt: k.claimedAt, guildId: k.guildId, @@ -55,7 +55,7 @@ export async function exposeWithRadiation(context: BotContext) { const wasteItems = await lootService.getUserLootsByTypeId( targetLoot.winnerId, - LootKindId.RADIOACTIVE_WASTE, + LootKind.RADIOACTIVE_WASTE, ); if (wasteItems.length === 0) { return; @@ -86,7 +86,7 @@ export async function runHalfLife(context: BotContext) { logger.info("Running half life"); - const allWaste = await lootService.getLootsByKindId(LootKindId.RADIOACTIVE_WASTE); + const allWaste = await lootService.getLootsByKindId(LootKind.RADIOACTIVE_WASTE); // See: https://github.com/NullDev/CSZ-Bot/issues/470 const targetWasteCount = Math.ceil(allWaste.length / 2); @@ -103,7 +103,7 @@ export async function runHalfLife(context: BotContext) { return; } - const leadTemplate = resolveLootTemplate(LootKindId.BLEI); + const leadTemplate = resolveLootTemplate(LootKind.BLEI); if (!leadTemplate) { logger.error("Could not resolve loot template for lead."); return; diff --git a/src/service/lootDrop.ts b/src/service/lootDrop.ts index f887507f0..902e52477 100644 --- a/src/service/lootDrop.ts +++ b/src/service/lootDrop.ts @@ -29,7 +29,7 @@ import * as lootService from "#service/loot.ts"; import { LootAttributeClass, lootAttributeTemplates, - LootKindId, + LootKind, lootTemplates, } from "#service/lootData.ts"; @@ -164,7 +164,7 @@ export async function postLootDrop( const rarityWeights = rarities.map(a => a.initialDropWeight ?? 0); const rarityAttribute = - template.id === LootKindId.NICHTS ? null : randomEntryWeighted(rarities, rarityWeights); + template.id === LootKind.NICHTS ? null : randomEntryWeighted(rarities, rarityWeights); const claimedLoot = await lootService.createLoot( template, @@ -368,7 +368,7 @@ async function getDropWeightAdjustments( user: User, weights: readonly number[], ): Promise { - const waste = await lootService.getUserLootCountById(user.id, LootKindId.RADIOACTIVE_WASTE); + const waste = await lootService.getUserLootCountById(user.id, LootKind.RADIOACTIVE_WASTE); const messages = []; let wasteFactor = 1; @@ -380,7 +380,7 @@ async function getDropWeightAdjustments( ); } - const pkv = await lootService.getUserLootCountById(user.id, LootKindId.PKV); + const pkv = await lootService.getUserLootCountById(user.id, LootKind.PKV); let pkvFactor = 1; if (pkv > 0) { pkvFactor = 2; @@ -388,8 +388,8 @@ async function getDropWeightAdjustments( } const newWeights = [...weights]; - newWeights[LootKindId.NICHTS] = Math.ceil(weights[LootKindId.NICHTS] * wasteFactor) | 0; - newWeights[LootKindId.KRANKSCHREIBUNG] = (weights[LootKindId.KRANKSCHREIBUNG] * pkvFactor) | 0; + newWeights[LootKind.NICHTS] = Math.ceil(weights[LootKind.NICHTS] * wasteFactor) | 0; + newWeights[LootKind.KRANKSCHREIBUNG] = (weights[LootKind.KRANKSCHREIBUNG] * pkvFactor) | 0; return { messages, diff --git a/src/service/lootRoles.ts b/src/service/lootRoles.ts index b0cdf60fb..85ef95ec8 100644 --- a/src/service/lootRoles.ts +++ b/src/service/lootRoles.ts @@ -2,7 +2,7 @@ import type { GuildChannel, GuildMember, TextChannel } from "discord.js"; import type { BotContext } from "#context.ts"; -import { LootKindId } from "#service/lootData.ts"; +import { LootKind } from "#service/lootData.ts"; import * as lootService from "#service/loot.ts"; import log from "#log"; @@ -42,7 +42,7 @@ export async function checkExpiredShifts(context: BotContext) { for (const m of currentGuards.values()) { const drops = await lootService.getUserLootsByTypeId( m.user.id, - LootKindId.SCHICHTBEGINN_ASSE_2, + LootKind.SCHICHTBEGINN_ASSE_2, ); log.info({ member: m.id, drops: drops.length }, "Checking AsseGuard shift"); diff --git a/src/service/pet.ts b/src/service/pet.ts index 66b34292d..55da2df37 100644 --- a/src/service/pet.ts +++ b/src/service/pet.ts @@ -1,21 +1,23 @@ import type { User } from "discord.js"; import * as lootService from "#service/loot.ts"; -import { LootKindId } from "./lootData.ts"; +import { LootKind } from "./lootData.ts"; import * as pet from "#storage/pet.ts"; import * as lootData from "#service/lootData.ts"; const petCandidates = new Set([ - LootKindId.KADSE, - LootKindId.BIBER, - LootKindId.FERRIS, - LootKindId.OETTINGER, - LootKindId.MAXWELL, + LootKind.KADSE, + LootKind.BIBER, + LootKind.FERRIS, + LootKind.OETTINGER, + LootKind.MAXWELL, ]); export async function getPetCandidates(user: User) { + type ValidPets = typeof petCandidates extends Set ? U : never; + const inventory = await lootService.getInventoryContents(user); - return inventory.filter(i => petCandidates.has(i.lootKindId)); + return inventory.filter(i => petCandidates.has(i.lootKindId as ValidPets)); } export async function setPet(user: User, lootId: number, petName: string) { diff --git a/src/storage/db/model.ts b/src/storage/db/model.ts index ee13af82d..6e13597ff 100644 --- a/src/storage/db/model.ts +++ b/src/storage/db/model.ts @@ -1,3 +1,4 @@ +import type { LootAttributeClassId, LootKindId } from "#service/lootData.ts"; import type { Snowflake } from "discord.js"; import type { ColumnType, Generated, GeneratedAlways, Insertable, Selectable } from "kysely"; @@ -248,7 +249,7 @@ export interface LootTable extends AuditedTable { id: GeneratedAlways; displayName: string; - lootKindId: number; + lootKindId: LootKindId; winnerId: string; /** Different from createdAt. If the item is replaced, this may be copied form the previous loot item */ claimedAt: ColumnType; // TODO: Date is not supported by the DB driver @@ -272,7 +273,7 @@ export interface LootAttributeTable extends AuditedTable { lootId: LootId; attributeKindId: number; - attributeClassId: number; + attributeClassId: LootAttributeClassId; displayName: string; shortDisplay: string; diff --git a/src/storage/loot.ts b/src/storage/loot.ts index 58292bd50..e88e0a9fc 100644 --- a/src/storage/loot.ts +++ b/src/storage/loot.ts @@ -20,14 +20,19 @@ import type { } from "./db/model.ts"; import db from "#db"; -import { resolveLootAttributeTemplate, type LootAttributeKindId } from "#service/lootData.ts"; +import { + type LootKindId, + resolveLootAttributeTemplate, + type LootAttributeKindId, + type LootAttributeClassId, +} from "#service/lootData.ts"; export type LootUseCommandInteraction = ChatInputCommandInteraction & { channel: GuildTextBasedChannel; }; export interface LootTemplate { - id: number; + id: LootKindId; weight: number; displayName: string; titleText: string; @@ -83,7 +88,7 @@ export interface LootTemplate { export interface LootAttributeTemplate { id: number; - classId: number; + classId: LootAttributeClassId; displayName: string; shortDisplay: string; color?: number; @@ -197,7 +202,7 @@ export async function findOfMessage(message: Message, ctx = db()) { .executeTakeFirst(); } -export async function getUserLootsByTypeId(userId: User["id"], lootKindId: number, ctx = db()) { +export async function getUserLootsByTypeId(userId: User["id"], lootKindId: LootKindId, ctx = db()) { return await ctx .selectFrom("loot") .where("winnerId", "=", userId) @@ -209,7 +214,7 @@ export async function getUserLootsByTypeId(userId: User["id"], lootKindId: numbe export async function getUserLootsWithAttribute( userId: User["id"], - attributeKindId: number, + attributeKindId: LootKindId, ctx = db(), ) { return await ctx @@ -231,7 +236,7 @@ export async function getUserLootById(userId: User["id"], lootId: LootId, ctx = .executeTakeFirst(); } -export async function getLootsByKindId(lootKindId: number, ctx = db()) { +export async function getLootsByKindId(lootKindId: LootKindId, ctx = db()) { return await ctx .selectFrom("loot") .where("lootKindId", "=", lootKindId) diff --git a/src/storage/migrations/10-loot-attributes.ts b/src/storage/migrations/10-loot-attributes.ts index a3ccc6e31..5d4e0713c 100644 --- a/src/storage/migrations/10-loot-attributes.ts +++ b/src/storage/migrations/10-loot-attributes.ts @@ -47,7 +47,7 @@ export async function up(db: Kysely) { .returningAll() .executeTakeFirstOrThrow(); - if (lootKindId === 1 /* LootKindId.KADSE */ || lootKindId === 36 /* LootKindId.BIBER */) { + if (lootKindId === 1 /* LootKind.KADSE */ || lootKindId === 36 /* LootKind.BIBER */) { await db .insertInto("lootAttribute") .values({ diff --git a/src/storage/migrations/16-nutri-score.ts b/src/storage/migrations/16-nutri-score.ts index 30c831845..f09ee56d3 100644 --- a/src/storage/migrations/16-nutri-score.ts +++ b/src/storage/migrations/16-nutri-score.ts @@ -4,7 +4,7 @@ export async function up(db: Kysely): Promise { const allLoots = await db.selectFrom("loot").selectAll().execute(); for (const loot of allLoots) { switch (loot.lootKindId) { - case 33: // LootKindId.THUNFISCHSHAKE: + case 33: // LootKind.THUNFISCHSHAKE: await db .insertInto("lootAttribute") .orIgnore() @@ -19,7 +19,7 @@ export async function up(db: Kysely): Promise { }) .execute(); break; - case 16: // LootKindId.OETTINGER: + case 16: // LootKind.OETTINGER: await db .insertInto("lootAttribute") .orIgnore() @@ -34,7 +34,7 @@ export async function up(db: Kysely): Promise { }) .execute(); break; - case 4: // LootKindId.DOENER: + case 4: // LootKind.DOENER: await db .insertInto("lootAttribute") .orIgnore() @@ -49,9 +49,9 @@ export async function up(db: Kysely): Promise { }) .execute(); break; - case 25: // LootKindId.POWERADE_BLAU: - case 22: // LootKindId.SAHNE: - case 9: // LootKindId.AYRAN: + case 25: // LootKind.POWERADE_BLAU: + case 22: // LootKind.SAHNE: + case 9: // LootKind.AYRAN: await db .insertInto("lootAttribute") .orIgnore() @@ -66,7 +66,7 @@ export async function up(db: Kysely): Promise { }) .execute(); break; - case 32: // LootKindId.VERSCHIMMELTER_DOENER: + case 32: // LootKind.VERSCHIMMELTER_DOENER: await db .insertInto("lootAttribute") .orIgnore() From dd5a109354671ab6d4ccff75ed3367aab2bb5c8c Mon Sep 17 00:00:00 2001 From: holzmaster Date: Sat, 15 Nov 2025 15:16:16 +0100 Subject: [PATCH 3/4] Migrate LootAttributeKindId --- src/commands/gegenstand.ts | 9 +-- src/commands/inventar.ts | 4 +- src/service/birthday.ts | 4 +- src/service/lootData.ts | 81 ++++++++++---------- src/service/lootDegradation.ts | 6 +- src/storage/db/model.ts | 4 +- src/storage/loot.ts | 25 +++--- src/storage/migrations/10-loot-attributes.ts | 4 +- src/storage/migrations/16-nutri-score.ts | 10 +-- 9 files changed, 73 insertions(+), 74 deletions(-) diff --git a/src/commands/gegenstand.ts b/src/commands/gegenstand.ts index 5d4348422..c4e33bdbc 100644 --- a/src/commands/gegenstand.ts +++ b/src/commands/gegenstand.ts @@ -23,7 +23,7 @@ import { ensureChatInputCommand } from "#utils/interactionUtils.ts"; import * as imageService from "#service/image.ts"; import * as lootDataService from "#service/lootData.ts"; -import { LootAttributeKindId, LootKind } from "#service/lootData.ts"; +import { LootAttributeKind, LootKind } from "#service/lootData.ts"; import log from "#log"; @@ -168,7 +168,7 @@ export default class GegenstandCommand implements ApplicationCommand { const sweetContent = await lootService.getUserLootsWithAttribute( interaction.user.id, - LootAttributeKindId.SWEET, + LootAttributeKind.SWEET, ); if (sweetContent.length === 0) { @@ -222,7 +222,7 @@ export default class GegenstandCommand implements ApplicationCommand { const rarity = lootDataService.extractRarityAttribute(attributes) ?? - lootDataService.lootAttributeTemplates[LootAttributeKindId.RARITY_NORMAL]; + lootDataService.lootAttributeTemplates[LootAttributeKind.RARITY_NORMAL]; const otherAttributes = lootDataService.extractNonRarityAttributes(attributes); @@ -233,8 +233,7 @@ export default class GegenstandCommand implements ApplicationCommand { let assetPath = template.asset; if (template.attributeAsset) { for (const attribute of otherAttributes) { - const asset = - template.attributeAsset[attribute.attributeKindId as LootAttributeKindId]; + const asset = template.attributeAsset[attribute.attributeKindId]; if (asset) { assetPath = asset; break; diff --git a/src/commands/inventar.ts b/src/commands/inventar.ts index e017fef58..95b552744 100644 --- a/src/commands/inventar.ts +++ b/src/commands/inventar.ts @@ -12,7 +12,7 @@ import type { ApplicationCommand } from "#commands/command.ts"; import * as lootService from "#service/loot.ts"; import { ensureChatInputCommand } from "#utils/interactionUtils.ts"; import * as lootDataService from "#service/lootData.ts"; -import { LootAttributeKindId } from "#service/lootData.ts"; +import { LootAttributeKind } from "#service/lootData.ts"; import log from "#log"; @@ -58,7 +58,7 @@ export default class InventarCommand implements ApplicationCommand { const rarityAttribute = lootDataService.extractRarityAttribute(item.attributes); const rarity = rarityAttribute && - rarityAttribute.attributeKindId !== LootAttributeKindId.RARITY_NORMAL + rarityAttribute.attributeKindId !== LootAttributeKind.RARITY_NORMAL ? ` (${rarityAttribute.displayName})` : ""; diff --git a/src/service/birthday.ts b/src/service/birthday.ts index cf46b8603..404c20756 100644 --- a/src/service/birthday.ts +++ b/src/service/birthday.ts @@ -115,9 +115,7 @@ async function awardBirthdayPresents(users: GuildMember[]) { null, "birthday", null, - lootDataService.lootAttributeTemplates[ - lootDataService.LootAttributeKindId.RARITY_NORMAL - ], + lootDataService.lootAttributeTemplates[lootDataService.LootAttributeKind.RARITY_NORMAL], ); } } diff --git a/src/service/lootData.ts b/src/service/lootData.ts index 09f6022fa..0df0f28c5 100644 --- a/src/service/lootData.ts +++ b/src/service/lootData.ts @@ -71,18 +71,19 @@ export const LootAttributeClass = Object.freeze({ } as const); export type LootAttributeClassId = (typeof LootAttributeClass)[keyof typeof LootAttributeClass]; -export enum LootAttributeKindId { - RARITY_NORMAL = 0, - RARITY_RARE = 1, - RARITY_VERY_RARE = 2, - RADIOACTIVE = 3, - SWEET = 4, - NUTRI_SCORE_A = 5, - NUTRI_SCORE_B = 6, - NUTRI_SCORE_C = 7, - NUTRI_SCORE_D = 8, - NUTRI_SCORE_E = 9, -} +export const LootAttributeKind = Object.freeze({ + RARITY_NORMAL: 0, + RARITY_RARE: 1, + RARITY_VERY_RARE: 2, + RADIOACTIVE: 3, + SWEET: 4, + NUTRI_SCORE_A: 5, + NUTRI_SCORE_B: 6, + NUTRI_SCORE_C: 7, + NUTRI_SCORE_D: 8, + NUTRI_SCORE_E: 9, +} as const); +export type LootAttributeKindId = (typeof LootAttributeKind)[keyof typeof LootAttributeKind]; export const lootTemplateMap: Record = { [LootKind.NICHTS]: { @@ -105,9 +106,9 @@ export const lootTemplateMap: Record = { dropDescription: "Awww", emote: "🐈", asset: "assets/loot/01-kadse.jpg", - initialAttributes: [LootAttributeKindId.SWEET], + initialAttributes: [LootAttributeKind.SWEET], attributeAsset: { - [LootAttributeKindId.RADIOACTIVE]: "assets/loot/attributes/01-kadse-verstrahlt.jpg", + [LootAttributeKind.RADIOACTIVE]: "assets/loot/attributes/01-kadse-verstrahlt.jpg", }, }, [LootKind.MESSERBLOCK]: { @@ -138,7 +139,7 @@ export const lootTemplateMap: Record = { dropDescription: "Bewahre ihn gut als Geldanlage auf!", emote: "🥙", asset: "assets/loot/04-doener.jpg", - initialAttributes: [LootAttributeKindId.NUTRI_SCORE_C], + initialAttributes: [LootAttributeKind.NUTRI_SCORE_C], }, [LootKind.KINN]: { id: LootKind.KINN, @@ -223,7 +224,7 @@ export const lootTemplateMap: Record = { dropDescription: "Der gute von Müller", emote: "🥛", asset: "assets/loot/09-ayran.png", - initialAttributes: [LootAttributeKindId.NUTRI_SCORE_D], // Ref: https://de.openfoodfacts.org/produkt/4388860730685/ayran-ja + initialAttributes: [LootAttributeKind.NUTRI_SCORE_D], // Ref: https://de.openfoodfacts.org/produkt/4388860730685/ayran-ja }, [LootKind.PKV]: { id: LootKind.PKV, @@ -314,7 +315,7 @@ export const lootTemplateMap: Record = { dropDescription: "Ja dann Prost ne!", emote: "🍺", asset: "assets/loot/16-oettinger.png", - initialAttributes: [LootAttributeKindId.NUTRI_SCORE_B], // Ref: https://archive.is/aonnZ + initialAttributes: [LootAttributeKind.NUTRI_SCORE_B], // Ref: https://archive.is/aonnZ }, [LootKind.ACHIEVEMENT]: { id: LootKind.ACHIEVEMENT, @@ -371,7 +372,7 @@ export const lootTemplateMap: Record = { dropDescription: "Fürs Frühstück oder so", emote: ":sahne:", asset: "assets/loot/22-sahne.png", - initialAttributes: [LootAttributeKindId.NUTRI_SCORE_D], // Ref: https://de.openfoodfacts.org/produkt/4311501745663/spr%C3%BChsahne-gut-g%C3%BCnstig + initialAttributes: [LootAttributeKind.NUTRI_SCORE_D], // Ref: https://de.openfoodfacts.org/produkt/4311501745663/spr%C3%BChsahne-gut-g%C3%BCnstig }, [LootKind.AEHRE]: { id: LootKind.AEHRE, @@ -405,7 +406,7 @@ export const lootTemplateMap: Record = { dropDescription: "Erfrischend erquickend. Besonders mit Vodka. Oder Korn.", asset: "assets/loot/25-powerade-blau.jpg", emote: ":powerade:", - initialAttributes: [LootAttributeKindId.NUTRI_SCORE_D], // Ref: https://de.openfoodfacts.org/produkt/90357350/powerrade-mountain-blast-blue-coca-cola + initialAttributes: [LootAttributeKind.NUTRI_SCORE_D], // Ref: https://de.openfoodfacts.org/produkt/90357350/powerrade-mountain-blast-blue-coca-cola }, [LootKind.GAULOISES_BLAU]: { id: LootKind.GAULOISES_BLAU, @@ -477,7 +478,7 @@ export const lootTemplateMap: Record = { dropDescription: "Du hättest ihn früher essen sollen", emote: "🥙", asset: null, - initialAttributes: [LootAttributeKindId.NUTRI_SCORE_E], + initialAttributes: [LootAttributeKind.NUTRI_SCORE_E], }, [LootKind.THUNFISCHSHAKE]: { id: LootKind.THUNFISCHSHAKE, @@ -487,7 +488,7 @@ export const lootTemplateMap: Record = { dropDescription: "Nach Rezept zubereitet, bestehend aus Thunfisch und Reiswaffeln", emote: "🍼", asset: "assets/loot/33-thunfischshake.jpg", - initialAttributes: [LootAttributeKindId.NUTRI_SCORE_A], + initialAttributes: [LootAttributeKind.NUTRI_SCORE_A], }, [LootKind.KAFFEEMUEHLE]: { id: LootKind.KAFFEEMUEHLE, @@ -515,7 +516,7 @@ export const lootTemplateMap: Record = { dropDescription: "Bóbr kurwa! Ja pierdolę! Jakie bydlę!", emote: "🦫", asset: "assets/loot/36-biber.jpg", - initialAttributes: [LootAttributeKindId.SWEET], + initialAttributes: [LootAttributeKind.SWEET], }, [LootKind.BLEI]: { id: LootKind.BLEI, @@ -670,7 +671,7 @@ export const lootTemplateMap: Record = { "Schon seit 1977 erobert unser roter Superstar die Herzen aller Snack-Liebhaber. Er ist nicht nur praktisch, lecker und immer für eine gute Portion Spaß zu haben, sondern auch ohne Gentechnik und ohne Zusatz von Konservierungsstoffen. Dank der natürlichen Reifung in seiner Wachshülle ist er außerdem laktosefrei sowie reich an Protein und Kalzium.", emote: "🧀", asset: "assets/loot/43-bb-original.png", - initialAttributes: [LootAttributeKindId.NUTRI_SCORE_C], + initialAttributes: [LootAttributeKind.NUTRI_SCORE_C], }, [LootKind.BABYBEL_LIGHT]: { id: LootKind.BABYBEL_LIGHT, @@ -680,7 +681,7 @@ export const lootTemplateMap: Record = { dropDescription: "Der kleine Käse mit der roten Wachsverpackung, mit weniger Fett!", emote: "🧀", asset: "assets/loot/44-bb-light.png", - initialAttributes: [LootAttributeKindId.NUTRI_SCORE_C], + initialAttributes: [LootAttributeKind.NUTRI_SCORE_C], }, [LootKind.BABYBEL_CHEDDAR]: { id: LootKind.BABYBEL_CHEDDAR, @@ -691,7 +692,7 @@ export const lootTemplateMap: Record = { "Mini Babybel® mit Cheddar-Geschmack erfreut Groß und Klein und bringt Abwechslung in die Lunch-Box.\n\nFür Vegetarier geeignet.", emote: "🧀", asset: "assets/loot/45-bb-cheddar.png", - initialAttributes: [LootAttributeKindId.NUTRI_SCORE_D], + initialAttributes: [LootAttributeKind.NUTRI_SCORE_D], }, [LootKind.BABYBEL_EMMENTALER]: { id: LootKind.BABYBEL_EMMENTALER, @@ -702,7 +703,7 @@ export const lootTemplateMap: Record = { "Mini Babybel® mit feinem Emmentaler-Geschmack sorgt für herzhafte Snack-Momente und bereitet viel Vergnügen bei Groß und Klein.", emote: "🧀", asset: "assets/loot/46-bb-emmentaler.png", - initialAttributes: [LootAttributeKindId.NUTRI_SCORE_D], + initialAttributes: [LootAttributeKind.NUTRI_SCORE_D], }, [LootKind.BABYBEL_PROTEIN]: { id: LootKind.BABYBEL_PROTEIN, @@ -713,7 +714,7 @@ export const lootTemplateMap: Record = { "Lecker Käse in rotem Wachs. Genau der gleiche wie der blaue, aber für echte Männer.", emote: "🧀", asset: "assets/loot/47-bb-protein.png", - initialAttributes: [LootAttributeKindId.NUTRI_SCORE_C], + initialAttributes: [LootAttributeKind.NUTRI_SCORE_C], }, [LootKind.BABYBEL_GOUDA]: { id: LootKind.BABYBEL_GOUDA, @@ -724,7 +725,7 @@ export const lootTemplateMap: Record = { "Babybel® Unser Würziger ist eine Varietät des klassischen Babybel® Original. Er vereint alle Vorteile eines leckeren Käse-Snacks mit einem würzig-nussigen Geschmack (wir wollten es nicht einfach nur Gouda nennen) und sorgt auf diese Weise für ein etwas intensiveres Babybel®-Erlebnis.\n\nDurch seinen intensiv-herzhaften Geschmack eignet sich der würzig-leckere Snack sehr gut für den kleinen Hunger zwischendurch und bietet damit auch Käseliebhabern mit einem intensiveren Käsegeschmack eine optimale Ergänzung zur klassischen Variante.", emote: "🧀", asset: "assets/loot/48-bb-gouda.png", - initialAttributes: [LootAttributeKindId.NUTRI_SCORE_D], + initialAttributes: [LootAttributeKind.NUTRI_SCORE_D], }, [LootKind.BABYBEL_VEGAN]: { id: LootKind.BABYBEL_VEGAN, @@ -735,7 +736,7 @@ export const lootTemplateMap: Record = { "Den beliebten Babybel® gibt es jetzt auch als vegane Käsealternative, ganz ohne Milch und schnell erkennbar dank seiner grünen Wachshülle. Mit seinem milden Geschmack und der cremigen Textur ist der vegane Babybel® eine leckere und praktische Alternative als Snack für zuhause oder unterwegs.\n\nDer vegane Babybel® ist erhältlich im praktischen, recyclebaren Papierbeutel und ist eigentlich nur ein Block Kokosfett mit Salz.", emote: "🧀", asset: "assets/loot/49-bb-vegan.png", - initialAttributes: [LootAttributeKindId.NUTRI_SCORE_E], + initialAttributes: [LootAttributeKind.NUTRI_SCORE_E], }, [LootKind.BABYBEL_EXODIA]: { id: LootKind.BABYBEL_EXODIA, @@ -745,7 +746,7 @@ export const lootTemplateMap: Record = { dropDescription: "Du hast das Spiel gewonnen.", emote: "🧀", asset: "assets/loot/50-bb-exodia.png", - initialAttributes: [LootAttributeKindId.NUTRI_SCORE_E], + initialAttributes: [LootAttributeKind.NUTRI_SCORE_E], }, } as const; @@ -768,69 +769,69 @@ export const lootTemplates: LootTemplate[] = Object.values(lootTemplateMap); */ export const lootAttributeTemplates: LootAttributeTemplate[] = [ { - id: LootAttributeKindId.RARITY_NORMAL, + id: LootAttributeKind.RARITY_NORMAL, classId: LootAttributeClass.RARITY, displayName: "Normal", shortDisplay: "", initialDropWeight: 90, }, { - id: LootAttributeKindId.RARITY_RARE, + id: LootAttributeKind.RARITY_RARE, classId: LootAttributeClass.RARITY, displayName: "Selten", shortDisplay: "⭐", initialDropWeight: 10, }, { - id: LootAttributeKindId.RARITY_VERY_RARE, + id: LootAttributeKind.RARITY_VERY_RARE, classId: LootAttributeClass.RARITY, displayName: "Sehr Selten", shortDisplay: "🌟", initialDropWeight: 1, }, { - id: LootAttributeKindId.RADIOACTIVE, + id: LootAttributeKind.RADIOACTIVE, classId: LootAttributeClass.OTHER, displayName: "Verstrahlt", shortDisplay: "☢️", color: 0xff_ff_ff, }, { - id: LootAttributeKindId.SWEET, + id: LootAttributeKind.SWEET, classId: LootAttributeClass.OTHER, displayName: "Süß", shortDisplay: "🍬", }, { - id: LootAttributeKindId.NUTRI_SCORE_A, + id: LootAttributeKind.NUTRI_SCORE_A, classId: LootAttributeClass.NUTRI_SCORE, displayName: "Nutri-Score A", shortDisplay: "🟩", color: 0x00_ff_00, }, { - id: LootAttributeKindId.NUTRI_SCORE_B, + id: LootAttributeKind.NUTRI_SCORE_B, classId: LootAttributeClass.NUTRI_SCORE, displayName: "Nutri-Score B", shortDisplay: "🟨", color: 0x99_ff_00, }, { - id: LootAttributeKindId.NUTRI_SCORE_C, + id: LootAttributeKind.NUTRI_SCORE_C, classId: LootAttributeClass.NUTRI_SCORE, displayName: "Nutri-Score C", shortDisplay: "🟧", color: 0xff_ff_00, }, { - id: LootAttributeKindId.NUTRI_SCORE_D, + id: LootAttributeKind.NUTRI_SCORE_D, classId: LootAttributeClass.NUTRI_SCORE, displayName: "Nutri-Score D", shortDisplay: "🟥", color: 0xff_99_00, }, { - id: LootAttributeKindId.NUTRI_SCORE_E, + id: LootAttributeKind.NUTRI_SCORE_E, classId: LootAttributeClass.NUTRI_SCORE, displayName: "Nutri-Score E", shortDisplay: "🟥", diff --git a/src/service/lootDegradation.ts b/src/service/lootDegradation.ts index 33697599d..b10e0c576 100644 --- a/src/service/lootDegradation.ts +++ b/src/service/lootDegradation.ts @@ -3,7 +3,7 @@ import type { BotContext } from "#context.ts"; import * as time from "#utils/time.ts"; import * as lootService from "#service/loot.ts"; -import { LootAttributeKindId, LootKind, resolveLootTemplate } from "#service/lootData.ts"; +import { LootAttributeKind, LootKind, resolveLootTemplate } from "#service/lootData.ts"; import log from "#log"; import { randomEntry } from "#service/random.ts"; @@ -46,7 +46,7 @@ export async function degradeItems(_context: BotContext) { export async function exposeWithRadiation(context: BotContext) { // currently also includes sweets that are already radioactive - const sweets = await lootService.getLootsWithAttribute(LootAttributeKindId.SWEET); + const sweets = await lootService.getLootsWithAttribute(LootAttributeKind.SWEET); const targetLoot = randomEntry(sweets); if (!targetLoot) { @@ -63,7 +63,7 @@ export async function exposeWithRadiation(context: BotContext) { const attributeAdded = await lootService.addLootAttributeIfNotPresent( targetLoot.id, - LootAttributeKindId.RADIOACTIVE, + LootAttributeKind.RADIOACTIVE, ); if (!attributeAdded) { return; diff --git a/src/storage/db/model.ts b/src/storage/db/model.ts index 6e13597ff..75f1a13dd 100644 --- a/src/storage/db/model.ts +++ b/src/storage/db/model.ts @@ -1,4 +1,4 @@ -import type { LootAttributeClassId, LootKindId } from "#service/lootData.ts"; +import type { LootAttributeClassId, LootAttributeKindId, LootKindId } from "#service/lootData.ts"; import type { Snowflake } from "discord.js"; import type { ColumnType, Generated, GeneratedAlways, Insertable, Selectable } from "kysely"; @@ -272,7 +272,7 @@ export interface LootAttributeTable extends AuditedTable { id: GeneratedAlways; lootId: LootId; - attributeKindId: number; + attributeKindId: LootAttributeKindId; attributeClassId: LootAttributeClassId; displayName: string; diff --git a/src/storage/loot.ts b/src/storage/loot.ts index e88e0a9fc..7d45748ad 100644 --- a/src/storage/loot.ts +++ b/src/storage/loot.ts @@ -87,7 +87,7 @@ export interface LootTemplate { } export interface LootAttributeTemplate { - id: number; + id: LootAttributeKindId; classId: LootAttributeClassId; displayName: string; shortDisplay: string; @@ -98,15 +98,16 @@ export interface LootAttributeTemplate { const notDeleted = (eb: ExpressionBuilder) => eb.or([eb("deletedAt", "is", null), eb("deletedAt", ">", sql`current_timestamp`)]); -const hasAttribute = (attributeKindId: number) => (eb: ExpressionBuilder) => - eb( - "id", - "in", - eb - .selectFrom("lootAttribute") - .where("attributeKindId", "=", attributeKindId) - .select("lootId"), - ); +const hasAttribute = + (attributeKindId: LootAttributeKindId) => (eb: ExpressionBuilder) => + eb( + "id", + "in", + eb + .selectFrom("lootAttribute") + .where("attributeKindId", "=", attributeKindId) + .select("lootId"), + ); export async function createLoot( template: LootTemplate, @@ -214,7 +215,7 @@ export async function getUserLootsByTypeId(userId: User["id"], lootKindId: LootK export async function getUserLootsWithAttribute( userId: User["id"], - attributeKindId: LootKindId, + attributeKindId: LootAttributeKindId, ctx = db(), ) { return await ctx @@ -245,7 +246,7 @@ export async function getLootsByKindId(lootKindId: LootKindId, ctx = db()) { .execute(); } -export async function getLootsWithAttribute(attributeKindId: number, ctx = db()) { +export async function getLootsWithAttribute(attributeKindId: LootAttributeKindId, ctx = db()) { return await ctx .selectFrom("loot") .where(notDeleted) diff --git a/src/storage/migrations/10-loot-attributes.ts b/src/storage/migrations/10-loot-attributes.ts index 5d4e0713c..7007919af 100644 --- a/src/storage/migrations/10-loot-attributes.ts +++ b/src/storage/migrations/10-loot-attributes.ts @@ -38,7 +38,7 @@ export async function up(db: Kysely) { .values({ lootId: id, attributeClassId: 1, // LootAttributeClass.RARITY - attributeKindId: 0, // LootAttributeKindId.RARITY_NORMAL + attributeKindId: 0, // LootAttributeKind.RARITY_NORMAL displayName: "Normal", shortDisplay: "", color: null, @@ -53,7 +53,7 @@ export async function up(db: Kysely) { .values({ lootId: id, attributeClassId: 0, // LootAttributeClass.OTHER - attributeKindId: 4, // LootAttributeKindId.SWEET + attributeKindId: 4, // LootAttributeKind.SWEET displayName: "Süß", shortDisplay: "🍬", color: null, diff --git a/src/storage/migrations/16-nutri-score.ts b/src/storage/migrations/16-nutri-score.ts index f09ee56d3..91e188860 100644 --- a/src/storage/migrations/16-nutri-score.ts +++ b/src/storage/migrations/16-nutri-score.ts @@ -10,7 +10,7 @@ export async function up(db: Kysely): Promise { .orIgnore() .values({ lootId: loot.id, - attributeKindId: 5, // LootAttributeKindId.NUTRI_SCORE_A, + attributeKindId: 5, // LootAttributeKind.NUTRI_SCORE_A, attributeClassId: 2, // LootAttributeClass.NUTRI_SCORE, displayName: "Nutri-Score A", shortDisplay: "🟩", @@ -25,7 +25,7 @@ export async function up(db: Kysely): Promise { .orIgnore() .values({ lootId: loot.id, - attributeKindId: 6, // LootAttributeKindId.NUTRI_SCORE_B, + attributeKindId: 6, // LootAttributeKind.NUTRI_SCORE_B, attributeClassId: 2, // LootAttributeClass.NUTRI_SCORE, displayName: "Nutri-Score B", shortDisplay: "🟨", @@ -40,7 +40,7 @@ export async function up(db: Kysely): Promise { .orIgnore() .values({ lootId: loot.id, - attributeKindId: 7, // LootAttributeKindId.NUTRI_SCORE_C, + attributeKindId: 7, // LootAttributeKind.NUTRI_SCORE_C, attributeClassId: 2, // LootAttributeClass.NUTRI_SCORE, displayName: "Nutri-Score C", shortDisplay: "🟧", @@ -57,7 +57,7 @@ export async function up(db: Kysely): Promise { .orIgnore() .values({ lootId: loot.id, - attributeKindId: 8, // LootAttributeKindId.NUTRI_SCORE_D, + attributeKindId: 8, // LootAttributeKind.NUTRI_SCORE_D, attributeClassId: 2, // LootAttributeClass.NUTRI_SCORE, displayName: "Nutri-Score D", shortDisplay: "🟥", @@ -72,7 +72,7 @@ export async function up(db: Kysely): Promise { .orIgnore() .values({ lootId: loot.id, - attributeKindId: 9, // LootAttributeKindId.NUTRI_SCORE_E, + attributeKindId: 9, // LootAttributeKind.NUTRI_SCORE_E, attributeClassId: 2, // LootAttributeClass.NUTRI_SCORE, displayName: "Nutri-Score E", From 59c8b7c1b4b4f4f4e6c80bac62c44da856b6937f Mon Sep 17 00:00:00 2001 From: holzmaster Date: Sat, 15 Nov 2025 15:18:59 +0100 Subject: [PATCH 4/4] erasableSyntaxOnly --- tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/tsconfig.json b/tsconfig.json index a8a8639c7..ae053eda6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,6 +6,7 @@ "lib": ["esnext"], "allowImportingTsExtensions": true, + "erasableSyntaxOnly": true, // Additional Checks // "noUnusedLocals": true,