feat: auction command

This commit is contained in:
tresabhi committed 2024-12-13 10:58:16 -06:00
1 parent a78543c60f
commit 2f7f2362bb
9 files changed
+166 -1

No files matched your search

+126
View File
@@ -0,0 +1,126 @@
import {
BlitzTankClass,
Region,
regionToRegionSubdomain,
} from '@blitzkit/core';
import { tankDefinitions } from '../core/blitzkit/nonBlockingPromises';
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
import { translator } from '../core/localization/translator';
import { CommandRegistry } from '../events/interactionCreate';
interface Auction {
count: number;
has_next: boolean;
results: Result[];
}
type Result =
| {
id?: number;
type: 'vehicle';
countable?: boolean;
entity?: Entity;
initial_count?: number;
current_count?: number;
saleable?: boolean;
available_from?: Date;
available_before?: Date;
price?: Price;
next_price?: Price | null;
available: true;
display?: boolean;
next_price_datetime?: Date | null;
next_price_timestamp?: number | null;
}
| {
available: false;
type: 'vehicle';
};
interface Entity {
id: number;
name: string;
nation: string;
subnation: string;
use_subnation_flag: boolean;
type_slug: BlitzTankClass;
level: number;
roman_level: string;
user_string: string;
image_url: string;
preview_image_url: string;
is_premium: boolean;
is_collectible: boolean;
}
interface Price {
currency: Currency;
value: number;
}
interface Currency {
name: 'gold';
count: number;
title: 'Gold';
image_url: string;
sizes: unknown;
type: 'currency';
}
export const auctionCommand = new Promise<CommandRegistry>((resolve) => {
resolve({
command: createLocalizedCommand('auction', [
{ subcommand: 'available' },
{ subcommand: 'setup' },
]),
async handler(interaction) {
const awaitedTankDefinitions = await tankDefinitions;
const region: Region = 'com';
const pageSize = 80;
const saleable = true;
const data = await fetch(
`https://${regionToRegionSubdomain(
region,
)}.wotblitz.com/en/api/events/items/auction/?page_size=${
pageSize
}&type[]=vehicle&saleable=${saleable}`,
).then((response) => response.json() as Promise<Auction>);
const seeableTanks = data.results.filter((result) => result.available);
const { t, translate } = translator(interaction.locale);
const title = `# ${t`bot.commands.auction.subcommands.available.body.title`}`;
const subtitle = `-# ${translate(
'bot.commands.auction.subcommands.available.body.available',
[`${seeableTanks.length} / ${data.results.length}`],
)}`;
const body = seeableTanks
.map((data, index) => {
const tank = awaitedTankDefinitions.tanks[data.entity!.id];
if (!tank) return '';
const name = `[${tank.name}](<https://blitzkit.app/tools/tankopedia/${
tank.id
}>)`;
const next = translate(
'bot.commands.auction.subcommands.available.body.next',
[
`<:gold:1317173197082333244> ${data.next_price!.value.toLocaleString(
interaction.locale,
)}`,
],
);
return `${
index + 1
}. ${name} <:gold:1317173197082333244> ${data.price!.value.toLocaleString(
interaction.locale,
)}\n-# ${next}`;
})
.join('\n\n');
return `${title}\n${subtitle}\n\n${body}`;
},
});
});
@@ -15,6 +15,7 @@ import {
SlashCommandSubcommandsOnlyBuilder,
} from 'discord.js';
import { aboutCommand } from '../../commands/about';
import { auctionCommand } from '../../commands/auction';
import { breakdownCommand } from '../../commands/breakdown';
import { debugCommand } from '../../commands/debug';
import { evolutionCommand } from '../../commands/evolution';
@@ -76,6 +77,7 @@ interface CommandRegistryExplicit extends CommandRegistryBase {
export type CommandRegistry = CommandRegistryImplicit | CommandRegistryExplicit;
export const COMMANDS_RAW: Promise<CommandRegistry>[] = [
auctionCommand,
permissionsCommand,
debugCommand,
aboutCommand,
+4
View File
@@ -1,8 +1,12 @@
import { manager } from './core/discord/manager';
console.log('pre manager event listeners and spawn');
manager
.on('shardCreate', (shard) => {
console.log(`🟡 Launching shard ${shard.id}`);
shard.on('ready', () => console.log(`🟢 Launched shard ${shard.id}`));
})
.spawn();
console.log('post manager event listeners and spawn');
+4
View File
@@ -6,4 +6,8 @@ console.log(`🟡 Launching bot ${client.shard?.ids[0]}`);
registerProcesses();
console.log(`post register processes on shard ${client.shard?.ids[0]}`);
client.login(assertSecret(import.meta.env.DISCORD_TOKEN));
console.log(`post client login on shard ${client.shard?.ids[0]}`);
+2
View File
@@ -7,3 +7,5 @@ parentPort?.on('message', async (svg: string) => {
const png = svgToPng(svg);
parentPort?.postMessage(png);
});
console.log(`post render thread parent port on thread ${threadId}`);
+21
View File
@@ -291,6 +291,27 @@
},
"commands": {
"auction": {
"$": "auction",
"description": "Tanks available in the auction",
"subcommands": {
"available": {
"$": "available",
"description": "Tanks available right now in the auction",
"body": {
"title": "Blitz Auction",
"available": "%s available",
"next": "Next price: %s"
}
},
"setup": {
"$": "setup",
"description": "Set up a channel to receive auction updates"
}
}
},
"replay": {
"$": "replay",
"description": "Display replay results"
+5
View File
@@ -0,0 +1,5 @@
export type BlitzTankClass =
| 'lightTank'
| 'mediumTank'
| 'heavyTank'
| 'AT-SPG';
+1
View File
@@ -1,5 +1,6 @@
export * from './canSplash';
export * from './clans';
export * from './classes';
export * from './constants';
export * from './equipmentPrice';
export * from './fetchBlitz';
@@ -1,6 +1,7 @@
import {
Armor,
assertSecret,
BlitzTankClass,
CamouflageDefinitions,
Consumable,
ConsumableDefinitions,
@@ -70,7 +71,6 @@ const blitzTankFilterDefinitionCategoryToBlitzkit: Record<
function vector3TupleToBlitzkit(tuple: Vector3Tuple) {
return { x: tuple[0], y: tuple[1], z: tuple[2] } satisfies Vector3;
}
type BlitzTankClass = 'lightTank' | 'mediumTank' | 'heavyTank' | 'AT-SPG';
const blitzTankClassToBlitzkit: Record<BlitzTankClass, TankClass> = {
lightTank: TankClass.LIGHT,
'AT-SPG': TankClass.TANK_DESTROYER,