Naposledy aktivní 1 month ago

Revize cb347ccde112d0e1f46b8164b0b623747d8f5066

switch.ts Raw
1import { ChatInputCommandInteraction, TextChannel } from "discord.js";
2import { cfg } from "../systems/config";
3import { resolveUser, hasOfficerRole } from "../systems/users";
4import { setActiveCharacter, getActiveCharacter, getCharacterByName } from "../systems/characters";
5import { setSessionBorrow, getSessionBorrow, setPersistentPreference, clearPersistentPreference } from "../systems/borrow";
6import { polls, updatePollMessage } from "../systems/poll";
7import { replyAndDelete } from "../utils";
8import fs from "fs";
9import path from "path";
10
11const CHARS_PATH = path.join(__dirname, "../../data/characters.json");
12
13function findSharedChar(usermapKey: string, charName: string): { ownerKey: string; char: any } | null {
14 try {
15 const chars = JSON.parse(fs.readFileSync(CHARS_PATH, "utf8"));
16 for (const [ownerKey, data] of Object.entries(chars) as [string, any][]) {
17 if (ownerKey === usermapKey) continue;
18 const char = data.characters?.find(
19 (c: any) => c.name.toLowerCase() === charName.toLowerCase() && c.sharedWith?.includes(usermapKey)
20 );
21 if (char) return { ownerKey, char };
22 }
23 } catch {}
24 return null;
25}
26
27// Reverse-lookup: find Discord userId for a usermapKey from current poll voters
28function findUserIdInPoll(state: any, usermapKey: string): string | null {
29 for (const [id, entry] of [...state.yes.entries(), ...state.no.entries()]) {
30 if (entry.usermapKey === usermapKey) return id;
31 }
32 return null;
33}
34
35export async function handleSwitch(interaction: ChatInputCommandInteraction): Promise<void> {
36 const member = await interaction.guild!.members.fetch(interaction.user.id);
37 const isOfficer = hasOfficerRole(member, cfg("officerRoles"));
38 const nameArg = interaction.options.getString("name");
39 const charName = interaction.options.getString("char_name", true);
40
41 let usermapKey: string | null;
42 if (nameArg) {
43 if (!isOfficer) return void replyAndDelete(interaction, "❌ Only officers can switch other players' characters.");
44 usermapKey = nameArg;
45 } else {
46 const user = await resolveUser(member);
47 usermapKey = user.usermapKey;
48 }
49
50 if (!usermapKey) return void replyAndDelete(interaction, "❌ You are not registered in the system.");
51
52 let resolvedChar: any = null;
53 let borrowedFrom: string | null = null;
54
55 // Try own characters first
56 const set = setActiveCharacter(usermapKey, charName);
57 if (set) {
58 clearPersistentPreference(usermapKey);
59 // Also clear any active session borrow so own char takes priority
60 const { clearSessionBorrowForUser } = require("../systems/borrow");
61 clearSessionBorrowForUser(usermapKey);
62 resolvedChar = getActiveCharacter(usermapKey);
63 } else {
64 // Fall back to shared characters
65 const shared = findSharedChar(usermapKey, charName);
66 if (shared) {
67 setSessionBorrow(usermapKey, shared.ownerKey, shared.char.name);
68 setPersistentPreference(usermapKey, shared.ownerKey, shared.char.name);
69 resolvedChar = shared.char;
70 borrowedFrom = shared.ownerKey;
71 }
72 }
73
74 if (!resolvedChar) return void replyAndDelete(interaction, `❌ No character named **${charName}** found.`);
75
76 // Update poll embed if user has voted
77 const slot = [...polls.keys()][0];
78 if (slot !== undefined) {
79 const state = polls.get(slot)!;
80 const userId = nameArg
81 ? findUserIdInPoll(state, usermapKey)
82 : interaction.user.id;
83
84 if (userId && (state.yes.has(userId) || state.no.has(userId))) {
85 const updateEntry = (map: Map<string, any>) => {
86 const entry = map.get(userId);
87 if (entry) {
88 entry.characterName = resolvedChar.name;
89 entry.characterClass = resolvedChar.class;
90 entry.characterLevel = resolvedChar.level;
91 entry.characterNation = resolvedChar.nation;
92 entry.borrowedFrom = borrowedFrom ?? undefined;
93 }
94 };
95 updateEntry(state.yes);
96 updateEntry(state.no);
97
98 const channel = await interaction.client.channels.fetch(cfg("pollChannelId")) as TextChannel;
99 await updatePollMessage(channel, slot);
100 }
101 }
102
103 const borrowNote = borrowedFrom ? ` (shared by **${borrowedFrom}**)` : "";
104 return void replyAndDelete(interaction, `✅ Switched to **${charName}**${borrowNote}.`);
105}