gistfile1.txt
· 4.8 KiB · Text
原始文件
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;
}
| 1 | function 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 | |
| 50 | export 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 | } |