Files
aurorabot/bot/modules/inventory/inventory.view.ts
syntaxbullet 5e8683a19f
All checks were successful
Deploy to Production / test (push) Successful in 42s
feat: Implement structured lootbox results with image support and display referenced items in shop listings.
2026-02-08 16:07:13 +01:00

141 lines
5.3 KiB
TypeScript

import { EmbedBuilder, AttachmentBuilder } from "discord.js";
import type { ItemUsageData } from "@shared/lib/types";
import { EffectType } from "@shared/lib/constants";
import { resolveAssetUrl, isLocalAssetUrl } from "@shared/lib/assets";
import { join } from "path";
import { existsSync } from "fs";
/**
* Inventory entry with item details
*/
interface InventoryEntry {
quantity: bigint | null;
item: {
id: number;
name: string;
[key: string]: any;
};
}
/**
* Creates an embed displaying a user's inventory
*/
export function getInventoryEmbed(items: InventoryEntry[], username: string): EmbedBuilder {
const description = items.map(entry => {
return `**${entry.item.name}** x${entry.quantity}`;
}).join("\n");
return new EmbedBuilder()
.setTitle(`📦 ${username}'s Inventory`)
.setDescription(description)
.setColor(0x3498db); // Blue
}
/**
* Creates an embed showing the results of using an item
*/
export function getItemUseResultEmbed(results: any[], item?: { name: string, iconUrl: string | null, usageData: any }): { embed: EmbedBuilder, files: AttachmentBuilder[] } {
const embed = new EmbedBuilder();
const files: AttachmentBuilder[] = [];
const otherMessages: string[] = [];
let lootResult: any = null;
for (const res of results) {
if (typeof res === 'object' && res.type === 'LOOTBOX_RESULT') {
lootResult = res;
} else {
otherMessages.push(typeof res === 'string' ? `${res}` : `${JSON.stringify(res)}`);
}
}
// Default Configuration
const isLootbox = item?.usageData?.effects?.some((e: any) => e.type === EffectType.LOOTBOX);
embed.setColor(isLootbox ? 0xFFD700 : 0x2ecc71); // Gold for lootbox, Green otherwise by default
embed.setTimestamp();
if (lootResult) {
embed.setTitle(`🎁 ${item?.name || "Lootbox"} Opened!`);
if (lootResult.rewardType === 'ITEM' && lootResult.item) {
const i = lootResult.item;
const amountStr = lootResult.amount > 1 ? `x${lootResult.amount}` : '';
// Rarity Colors
const rarityColors: Record<string, number> = {
'C': 0x95A5A6, // Gray
'R': 0x3498DB, // Blue
'SR': 0x9B59B6, // Purple
'SSR': 0xF1C40F // Gold
};
const rarityKey = i.rarity || 'C';
if (rarityKey in rarityColors) {
embed.setColor(rarityColors[rarityKey] ?? 0x95A5A6);
} else {
embed.setColor(0x95A5A6);
}
if (i.image) {
if (isLocalAssetUrl(i.image)) {
const imagePath = join(process.cwd(), "bot/assets/graphics", i.image.replace(/^\/?assets\//, ""));
if (existsSync(imagePath)) {
const imageName = defaultName(i.image);
if (!files.find(f => f.name === imageName)) {
files.push(new AttachmentBuilder(imagePath, { name: imageName }));
}
embed.setImage(`attachment://${imageName}`);
}
} else {
const imgUrl = resolveAssetUrl(i.image);
if (imgUrl) embed.setImage(imgUrl);
}
}
embed.setDescription(`**You found ${i.name} ${amountStr}!**\n${i.description || '_'}`);
embed.addFields({ name: 'Rarity', value: rarityKey, inline: true });
} else if (lootResult.rewardType === 'CURRENCY') {
embed.setColor(0xF1C40F);
embed.setDescription(`**You found ${lootResult.amount.toLocaleString()} 🪙 AU!**`);
} else if (lootResult.rewardType === 'XP') {
embed.setColor(0x2ECC71); // Green
embed.setDescription(`**You gained ${lootResult.amount.toLocaleString()} XP!**`);
} else {
// Nothing or Message
embed.setDescription(lootResult.message);
embed.setColor(0x95A5A6); // Gray
}
} else {
// Standard item usage
embed.setTitle(item ? `✅ Used ${item.name}` : "✅ Item Used!");
embed.setDescription(otherMessages.join("\n") || "Effect applied.");
if (isLootbox && item && item.iconUrl) {
if (isLocalAssetUrl(item.iconUrl)) {
const iconPath = join(process.cwd(), "bot/assets/graphics", item.iconUrl.replace(/^\/?assets\//, ""));
if (existsSync(iconPath)) {
const iconName = defaultName(item.iconUrl);
if (!files.find(f => f.name === iconName)) {
files.push(new AttachmentBuilder(iconPath, { name: iconName }));
}
embed.setThumbnail(`attachment://${iconName}`);
}
} else {
const resolvedIconUrl = resolveAssetUrl(item.iconUrl);
if (resolvedIconUrl) embed.setThumbnail(resolvedIconUrl);
}
}
}
if (otherMessages.length > 0 && lootResult) {
embed.addFields({ name: "Other Effects", value: otherMessages.join("\n") });
}
return { embed, files };
}
function defaultName(path: string): string {
return path.split("/").pop() || "image.png";
}