function formatCharRow(entry: VoteEntry, showNationEmoji = false, nationHasRank = false): string { const cfgFormat = cfg("charDisplayFormat"); const nation = entry.characterNation; const wRankEntry = entry.characterName && entry.characterNation ? WRank.entry(entry.characterName, entry.characterNation) : null; let wrank = ""; if (wRankEntry) { const wRankGoal = cfg("wRankGoal"); wrank = format.wrank.full(wRankEntry, { goal: wRankGoal, brackets: true }); } else if (nationHasRank) { wrank = format.wrank.noRank(); } const classStr = entry.characterClass ? (Emoji.class(entry.characterClass) || entry.characterClass) : ""; const levelStr = entry.characterLevel && cfg("showLevelInMessages" as any) ? `${entry.characterLevel}` : ""; let row = cfgFormat .replace("{wrank}", wrank) .replace("{class}", classStr) .replace("{level}", levelStr) .replace("{name}", entry.characterName ?? entry.displayName ?? "") .replace(/\s+/g, " ") .trim(); // Bringer title โ€” independent of W.Rank so override always shows if (nation && entry.userKey) { const bringer = Bringer.get({ nation }); if (bringer && bringer === entry.characterName) { row += ` ยท ${format.bringer(nation)}`; } } if (entry.borrowedFrom) { row += ` ${Emoji.get("borrowed") || "๐Ÿ”—"}`; } if (showNationEmoji && nation) row = `${Emoji.nation(nation)} ${row}`; return row; } export function buildEmbed(state: PollState, overrideLockMsg?: string): EmbedBuilder { const yesByNation = { Capella: [] as VoteEntry[], Procyon: [] as VoteEntry[] }; const noVoters: VoteEntry[] = []; const allMessages: { entry: VoteEntry; voteType: "yes" | "no" }[] = []; const showNoInline = (cfg as any)("showNoInNationField") ?? false; for (const entry of state.yes.values()) { const nation = entry.characterNation ?? Nation.Capella; yesByNation[nation].push(entry); allMessages.push({ entry, voteType: "yes" }); } for (const entry of state.no.values()) { noVoters.push(entry); allMessages.push({ entry, voteType: "no" }); } const capellaEmoji = Emoji.get("capella"); const procyonEmoji = Emoji.get("procyon"); const formatNationField = (nation: Nation): string => { const yesEntries = yesByNation[nation]; const hasRank = yesEntries.some((e) => e.characterName && WRank.entry(e.characterName, nation) !== null); const noEntries = showNoInline ? noVoters.filter((e) => e.characterNation === nation) : []; const lines = [ ...yesEntries.map((e) => formatCharRow(e, false, hasRank)), ...noEntries.map((e) => `โŒ ${formatCharRow(e, false, hasRank)}`), ]; return lines.length > 0 ? lines.join("\n") : "โ€”"; }; const formatMessages = (): string => { if (allMessages.length === 0) return ""; return allMessages .map((m) => { const name = m.entry.characterName ?? m.entry.displayName; const prefix = m.voteType === "no" ? "โœ— " : "โœ“ "; const msg = m.entry.publicMessage ? ` โ€” ${m.entry.publicMessage}` : ""; return `${prefix}${name} ยท ${m.entry.votedAt}${msg}`; }) .join("\n"); }; const locked = state.locked; const confirmed = state.confirmed; const color = confirmed === "yes" ? 0x57f287 : confirmed === "no" ? 0xed4245 : locked ? 0x888888 : 0xe8a317; // Title with nation + no counts (hidden when confirmed or locked) const counts = !locked && confirmed === null ? ` ${capellaEmoji} ${yesByNation.Capella.length} ${procyonEmoji} ${yesByNation.Procyon.length}` : ""; const statusSuffix = locked ? " ๐Ÿ”’" : confirmed === "yes" ? " โœ…" : confirmed === "no" ? " โŒ" : ""; const title = `โš”๏ธ TG โ€” ${state.slot}:00${counts}${statusSuffix}`; const embed = new EmbedBuilder() .setTitle(title) .setColor(color) .addFields( { name: `${capellaEmoji} Capella (${yesByNation[Nation.Capella].length})`, value: formatNationField(Nation.Capella), inline: false }, { name: "\u200b", value: "\u200b", inline: false }, { name: `${procyonEmoji} Procyon (${yesByNation[Nation.Procyon].length})`, value: formatNationField(Nation.Procyon), inline: false }, ) .setTimestamp(); const msgSection = formatMessages(); if (msgSection) { embed.addFields({ name: "\u200b", value: msgSection, inline: false }); } let footer: string; if (confirmed === "yes") footer = cfg("confirmYesMessage"); else if (confirmed === "no") footer = cfg("confirmNoMessage"); else if (locked) footer = overrideLockMsg ?? cfg("lockMessage"); else footer = `โŒ ${noVoters.length} โ€ข Vote updates live โ€ข Anyone can vote โ€ข /tg switch to change character`; embed.setFooter({ text: footer }); return embed; }