Остання активність 1 week ago

gistfile1.txt Неформатований
1import { ChatInputCommandInteraction } from "discord.js";
2import { Config } from "@systems/config";
3import { resolveUser, hasOfficerRole } from "@systems/users";
4import { submitScore, detectSlot, normalizeSlot } from "@systems/scores";
5import { getEffectiveCharacter } from "@systems/borrow";
6import { replyAndDelete } from "@utils";
7import { Emoji } from "@systems/emojis";
8import { Discord } from "@discord";
9import { User } from "@systems/users";
10import { Logger } from "@systems/logger";
11const log = Logger.for("score-set");
12
13export async function handleScoreSet(interaction: ChatInputCommandInteraction): Promise<void> {
14 const options = Discord.Interaction.options<ChatInputCommandInteraction>(interaction);
15
16 const member = await interaction.guild!.members.fetch(interaction.user.id);
17 const isOfficer = User.hasOfficerRole({
18 member: member,
19 officerRoles: Config.get({ section: "roles", key: "officer"
20 })});
21 const nameArg = options.string({ key: "name" });
22 const ptsArg = options.integer({ key: "pts", required: true });
23 const slotArg = options.string({ key: "slot" });
24 const k = options.integer({ key: "k" }) ?? undefined;
25 const d = options.integer({ key: "d" }) ?? undefined;
26 const atk = options.integer({ key: "atk" }) ?? undefined;
27 const def = options.integer({ key: "def" }) ?? undefined;
28 const heal = options.integer({ key: "heal" }) ?? undefined;
29
30 let userKey: string | null;
31 if (nameArg) {
32 if (!isOfficer) return void replyAndDelete(interaction, "❌ Only officers can submit scores for other players.");
33 userKey = nameArg;
34 } else {
35 const user = await resolveUser(member);
36 userKey = user.userKey;
37 }
38
39 if (!userKey) return void replyAndDelete(interaction, "❌ You are not registered in the system.");
40
41 const { char, borrowedFrom } = getEffectiveCharacter(userKey);
42 if (!char) return void replyAndDelete(interaction, "❌ No active character found. Use `/tg char set-active` first.");
43
44 let slot: number | null = null;
45 if (slotArg) {
46 slot = normalizeSlot(slotArg);
47 if (slot === null) return void replyAndDelete(interaction, `❌ Could not parse slot "${slotArg}".`);
48 } else {
49 slot = detectSlot() ?? Config.get({ section: "poll", key: "slots" }).find((s) => s.active)?.tgHour ?? 20;
50 }
51
52 log.debug(`Submitting score: slot=${slot} (type: ${typeof slot}) date=${new Date().toISOString().slice(0,10)}`);
53
54 await submitScore({
55 userKey: borrowedFrom ?? userKey,
56 playedBy: borrowedFrom ? userKey : undefined,
57 characterName: char.name,
58 cls: char.class.key,
59 nation: char.nation,
60 pts: ptsArg!,
61 k,
62 d,
63 slot,
64 atk,
65 def,
66 heal,
67 submittedByOfficer: isOfficer && !!nameArg,
68 });
69
70 const scoreEmoji = Emoji.get("score") || "📊";
71 const kdEmoji = Emoji.get("kd") || "⚔️";
72 const borrowNote = borrowedFrom ? ` *(borrowed from ${borrowedFrom})*` : "";
73 const kdNote = k !== undefined && d !== undefined ? `\n${kdEmoji} ${k}/${d}` : "";
74 const statsNote = [
75 atk !== undefined ? `ATK: ${atk}` : null,
76 def !== undefined ? `DEF: ${def}` : null,
77 heal !== undefined ? `HEAL: ${heal}` : null,
78 ].filter(Boolean).join(" · ");
79
80 return void replyAndDelete(interaction,
81 `✅ ${scoreEmoji} **${ptsArg}** submitted for **${char.name}**${borrowNote} (${slot}:00 TG)${kdNote}${statsNote ? `\n${statsNote}` : ""}`,
82 true
83 );
84}