Zuletzt aktiv 3 weeks ago

gistfile1.txt Originalformat
1function formatCharRow(entry: VoteEntry, showNationEmoji = false, nationHasRank = false): string {
2 const cfgFormat = cfg("charDisplayFormat");
3 const nation = entry.characterNation;
4 const wRankEntry = entry.characterName && entry.characterNation
5 ? WRank.entry(entry.characterName, entry.characterNation)
6 : null;
7
8 let wrank = "";
9 if (wRankEntry) {
10 const wRankGoal = cfg("wRankGoal");
11 wrank = format.wrank.full(wRankEntry, { goal: wRankGoal, brackets: true });
12 } else if (nationHasRank) {
13 wrank = format.wrank.noRank();
14 }
15
16 const classStr = entry.characterClass
17 ? (Emoji.class(entry.characterClass) || entry.characterClass)
18 : "";
19
20 const levelStr = entry.characterLevel && cfg("showLevelInMessages" as any)
21 ? `${entry.characterLevel}`
22 : "";
23
24 let row = cfgFormat
25 .replace("{wrank}", wrank)
26 .replace("{class}", classStr)
27 .replace("{level}", levelStr)
28 .replace("{name}", entry.characterName ?? entry.displayName ?? "")
29 .replace(/\s+/g, " ")
30 .trim();
31
32 // Bringer title — independent of W.Rank so override always shows
33 if (nation && entry.userKey) {
34 const bringer = Bringer.get({ nation });
35
36 if (bringer && bringer === entry.characterName) {
37 row += ` · ${format.bringer(nation)}`;
38 }
39 }
40
41 if (entry.borrowedFrom) {
42 row += ` ${Emoji.get("borrowed") || "🔗"}`;
43 }
44
45 if (showNationEmoji && nation) row = `${Emoji.nation(nation)} ${row}`;
46
47 return row;
48}
49
50export function buildEmbed(state: PollState, overrideLockMsg?: string): EmbedBuilder {
51 const yesByNation = { Capella: [] as VoteEntry[], Procyon: [] as VoteEntry[] };
52 const noVoters: VoteEntry[] = [];
53 const allMessages: { entry: VoteEntry; voteType: "yes" | "no" }[] = [];
54 const showNoInline = (cfg as any)("showNoInNationField") ?? false;
55
56 for (const entry of state.yes.values()) {
57 const nation = entry.characterNation ?? Nation.Capella;
58 yesByNation[nation].push(entry);
59 allMessages.push({ entry, voteType: "yes" });
60 }
61 for (const entry of state.no.values()) {
62 noVoters.push(entry);
63 allMessages.push({ entry, voteType: "no" });
64 }
65
66 const capellaEmoji = Emoji.get("capella");
67 const procyonEmoji = Emoji.get("procyon");
68
69 const formatNationField = (nation: Nation): string => {
70 const yesEntries = yesByNation[nation];
71 const hasRank = yesEntries.some((e) => e.characterName && WRank.entry(e.characterName, nation) !== null);
72 const noEntries = showNoInline
73 ? noVoters.filter((e) => e.characterNation === nation)
74 : [];
75 const lines = [
76 ...yesEntries.map((e) => formatCharRow(e, false, hasRank)),
77 ...noEntries.map((e) => `❌ ${formatCharRow(e, false, hasRank)}`),
78 ];
79 return lines.length > 0 ? lines.join("\n") : "—";
80 };
81
82 const formatMessages = (): string => {
83 if (allMessages.length === 0) return "";
84 return allMessages
85 .map((m) => {
86 const name = m.entry.characterName ?? m.entry.displayName;
87 const prefix = m.voteType === "no" ? "✗ " : "✓ ";
88 const msg = m.entry.publicMessage ? ` — ${m.entry.publicMessage}` : "";
89 return `${prefix}${name} · ${m.entry.votedAt}${msg}`;
90 })
91 .join("\n");
92 };
93
94 const locked = state.locked;
95 const confirmed = state.confirmed;
96
97 const color =
98 confirmed === "yes" ? 0x57f287 :
99 confirmed === "no" ? 0xed4245 :
100 locked ? 0x888888 :
101 0xe8a317;
102
103 // Title with nation + no counts (hidden when confirmed or locked)
104 const counts = !locked && confirmed === null
105 ? ` ${capellaEmoji} ${yesByNation.Capella.length} ${procyonEmoji} ${yesByNation.Procyon.length}`
106 : "";
107 const statusSuffix =
108 locked ? " 🔒" :
109 confirmed === "yes" ? " ✅" :
110 confirmed === "no" ? " ❌" : "";
111
112 const title = `⚔️ TG — ${state.slot}:00${counts}${statusSuffix}`;
113
114 const embed = new EmbedBuilder()
115 .setTitle(title)
116 .setColor(color)
117 .addFields(
118 { name: `${capellaEmoji} Capella (${yesByNation[Nation.Capella].length})`, value: formatNationField(Nation.Capella), inline: false },
119 { name: "\u200b", value: "\u200b", inline: false },
120 { name: `${procyonEmoji} Procyon (${yesByNation[Nation.Procyon].length})`, value: formatNationField(Nation.Procyon), inline: false },
121 )
122 .setTimestamp();
123
124 const msgSection = formatMessages();
125 if (msgSection) {
126 embed.addFields({ name: "\u200b", value: msgSection, inline: false });
127 }
128
129 let footer: string;
130 if (confirmed === "yes") footer = cfg("confirmYesMessage");
131 else if (confirmed === "no") footer = cfg("confirmNoMessage");
132 else if (locked) footer = overrideLockMsg ?? cfg("lockMessage");
133 else footer = `❌ ${noVoters.length} • Vote updates live • Anyone can vote • /tg switch to change character`;
134 embed.setFooter({ text: footer });
135
136 return embed;
137}