Dernière activité 3 weeks ago

nuno a révisé ce gist 3 weeks ago. Aller à la révision

1 file changed, 149 insertions

wrank.ts(fichier créé)

@@ -0,0 +1,149 @@
1 + import { Character, CharacterClass, Nation } from "@src/types";
2 + import { Emoji } from "@systems/emojis";
3 + import { WRankEntry } from "@systems/wrank";
4 +
5 + // ─── Individual formatters ────────────────────────────────────────────────────
6 +
7 + export interface CharDisplayOptions {
8 + emoji?: boolean; // show class emoji (default: true)
9 + level?: boolean; // show level (default: true)
10 + }
11 +
12 + function charButton(c: Character, options?: { shared?: boolean }): string {
13 + const sharedMark = options?.shared ? " 🔗" : "";
14 + return `${c.level} ${c.name}${sharedMark}`;
15 + }
16 +
17 + /**
18 + * Format a character for display in embeds and messages.
19 + * Output: <:class:> 79 «Flash»
20 + */
21 + function char(c: Character, options?: CharDisplayOptions): string {
22 + const showEmoji = options?.emoji ?? true;
23 + const showLevel = options?.level ?? true;
24 + const classKey = c.class.key;
25 + const classStr = showEmoji ? (Emoji.class(classKey) || classKey) : classKey;
26 + const levelStr = showLevel ? `${c.level} ` : "";
27 + return `${classStr} ${levelStr}${c.name}`.trim();
28 + }
29 +
30 + /**
31 + * Format a nation name with its emoji.
32 + * Output: <:capella:> Capella
33 + */
34 + function nation(n: Nation): string {
35 + const emoji = Emoji.nation(n);
36 + return emoji ? `${emoji} ${n}` : n;
37 + }
38 +
39 + /**
40 + * Format a score line.
41 + * Output: <:score:> 3000 <:kd:> 32/18
42 + */
43 + function score(pts: number, k?: number, d?: number): string {
44 + const scoreEmoji = Emoji.get("score") || "📊";
45 + const kdEmoji = Emoji.get("kd") || "⚔️";
46 + const kdStr = k !== undefined && d !== undefined ? ` ${kdEmoji} ${k}/${d}` : "";
47 + return `${scoreEmoji} ${pts}${kdStr}`;
48 + }
49 +
50 + /**
51 + * Parse a Discord custom emoji string to an object for ButtonBuilder.setEmoji()
52 + * Input: "<:fb:1511020923510194428>"
53 + * Output: { name: "fb", id: "1511020923510194428" }
54 + */
55 + function emoji(emojiStr: string): { name: string; id: string } | string | null {
56 + if (!emojiStr) return null;
57 + const match = emojiStr.match(/^<:(\w+):(\d+)>$/);
58 + if (match) return { name: match[1], id: match[2] };
59 + return emojiStr;
60 + }
61 +
62 + // ─── W.Rank formatters ────────────────────────────────────────────────────────
63 +
64 + export interface WRankDisplayOptions {
65 + goal: number;
66 + brackets?: boolean; // wrap delta in parentheses (default: true)
67 + }
68 +
69 + /**
70 + * Format the rank indicator for a wrank entry.
71 + * Output: <:wrank_1_gold:> or <:wrank_1:> or bold/plain number fallback
72 + */
73 + function wrankRank(entry: WRankEntry, goal: number): string {
74 + const isDone = entry.tgCount >= goal;
75 + const rankKey = isDone ? `wrank_${entry.currentRank}_gold` : `wrank_${entry.currentRank}`;
76 + return Emoji.get(rankKey) || (isDone ? `**${entry.currentRank}**` : `${entry.currentRank}`);
77 + }
78 +
79 + /**
80 + * Format the delta indicator for a wrank entry.
81 + * Output: <:wrank_up:><:wrank_up_2:> or ↑2, empty string if no change
82 + */
83 + function wrankDelta(entry: WRankEntry, options?: { brackets?: boolean }): string {
84 + const brackets = options?.brackets ?? true;
85 + const prev = entry.previousRank;
86 + const delta = prev !== undefined ? entry.currentRank - prev : 0;
87 +
88 + if (delta === 0 && prev === undefined) return "";
89 +
90 + let inner: string;
91 + if (delta < 0) {
92 + const abs = Math.abs(delta);
93 + const numEmoji = Emoji.get(`wrank_up_${abs}`);
94 + inner = (Emoji.get("wrank_up") || "↑") + (numEmoji || abs);
95 + } else if (delta > 0) {
96 + const numEmoji = Emoji.get(`wrank_down_${delta}`);
97 + inner = (Emoji.get("wrank_down") || "↓") + (numEmoji || delta);
98 + } else {
99 + inner = (Emoji.get("wrank_no_dash") || "·") + (Emoji.get("wrank_neutral_0") || "0");
100 + }
101 +
102 + return brackets ? ` (${inner})` : ` ${inner}`;
103 + }
104 +
105 + /**
106 + * Format a full wrank display string: rank + delta.
107 + * Output: <:wrank_1_gold:> (<:wrank_up:><:wrank_up_2:>)
108 + */
109 + function wrankFull(entry: WRankEntry, options: WRankDisplayOptions): string {
110 + return wrankRank(entry, options.goal) + wrankDelta(entry, { brackets: options.brackets });
111 + }
112 +
113 + /**
114 + * Placeholder for characters with no W.Rank when others in their nation have one.
115 + * Output: — ( — 0 )
116 + */
117 + function wrankNoRank(): string {
118 + const norank = Emoji.get("wrank_no_dash") || "—";
119 + const dash = Emoji.get("wrank_no_rank_delta") || "—";
120 + const square = Emoji.get("wrank_no_dash") || "■";
121 + return `${norank} (${square}${dash})`;
122 + }
123 +
124 + // ─── Bringer formatters ────────────────────────────────────────────────────────
125 +
126 + function bringerDisplay(n: Nation): string {
127 + const bringerMap: Record<Nation, string> = {
128 + Capella: Emoji.get("luminous_bringer") || "🔆 Luminous Bringer",
129 + Procyon: Emoji.get("storm_bringer") || "⚡ Storm Bringer",
130 + };
131 + return bringerMap[n];
132 + }
133 +
134 + // ─── Namespace export ─────────────────────────────────────────────────────────
135 +
136 + export const format = {
137 + char,
138 + charButton,
139 + nation,
140 + score,
141 + emoji,
142 + wrank: {
143 + rank: wrankRank,
144 + delta: wrankDelta,
145 + full: wrankFull,
146 + noRank: wrankNoRank,
147 + },
148 + bringer: bringerDisplay,
149 + };
Plus récent Plus ancien