@mauricode/token-derby 2.12.4 → 2.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/dist/bin.js +323 -146
- package/dist/bin.js.map +1 -1
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -152,48 +152,52 @@ function hatById(id) {
|
|
|
152
152
|
}
|
|
153
153
|
var HATS = [
|
|
154
154
|
// ── COMMON (18) ────────────────────────────────────────────────────────
|
|
155
|
-
{ id: "flat_cap", name: "Flat Cap", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...........", "....AAAA...", "...AAAAAA..", "..AAAAAAA.."], variants: [{ A: "#8B6914" }, { A: "#12301b" }, { A: "#aab5cb" }, { A: "#bdcbaa" }] },
|
|
156
|
-
{ id: "bucket_hat", name: "Bucket Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...QQQQQ...", "...AAAAA...", "...AAAAA...", ".AAAAAAAAA."], variants: [{ A: "#CC2200", Q: "#FFFFFF" }, { A: "#0007cc", Q: "#FFFFFF" }, { A: "#becc00", Q: "#4d3dc7" }, { A: "#cc00c5", Q: "#d6d6dc" }] },
|
|
157
|
-
{ id: "beanie", name: "Beanie", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "....AAA....", "...AAAAA...", "...AAAAA...", "..AAAAAAA.."], variants: [{ A: "#4A7C59" }, { A: "#b21f35" }, { A: "#ec9418" }, { A: "#3a17e6" }] },
|
|
158
|
-
{ id: "stetson", name: "Stetson", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...AA.AA...", "...AAAAA...", "...AAAAA...", "A..AAAAA..A", "AAAAAAAAAAA", "AAAAAAAAAAA"], variants: [{ A: "#C49A00" }, { A: "#272004" }, { A: "#040404" }, { A: "#373606" }] },
|
|
159
|
-
{ id: "party_hat", name: "Party Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", ".....A.....", "....AAA....", "....AQA....", "...AQAQA...", "...AAAAA..."], variants: [{ A: "#FF69B4", Q: "#FFD700" }, { A: "#c46bff", Q: "#ff000d" }, { A: "#fdff6b", Q: "#0400ff" }, { A: "#6bff97", Q: "#05050a" }] },
|
|
160
|
-
{ id: "fez", name: "Fez", rarity: "common", width: 11, anchor_x: 22, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "....Q......", "....AAA....", "....AAA....", "....AAA...."], variants: [{ A: "#CC0000", Q: "#8B0000" }, { A: "#CC0000", Q: "#f5e5e5" }, { A: "#CC0000", Q: "#f1e209" }, { A: "#CC0000", Q: "#0956f1" }] },
|
|
161
|
-
{ id: "sailor_hat", name: "Sailor Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...QQQQQ...", "..AAAAAAA..", "..QQQQQQQ..", "..AAAAAAA.."], variants: [{ A: "#FFFFFF", Q: "#000080" }, { A: "#FFFFFF", Q: "#c0c0ed" }, { A: "#FFFFFF", Q: "#00000a" }, { A: "#FFFFFF", Q: "#0505ef" }] },
|
|
162
|
-
{ id: "newsboy_cap", name: "Newsboy Cap", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...AAAAA...", "..AAAQAAA..", "..AAAAAAA..", "..AAAAAA..."], variants: [{ A: "#5C4033", Q: "#3D2B1F" }, { A: "#e96020", Q: "#131211" }, { A: "#342c28", Q: "#131211" }, { A: "#0a0300", Q: "#ddab78" }] },
|
|
163
|
-
{ id: "tam_o_shanter", name: "Tam O'Shanter", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", ".....Q.....", "....AAA....", "..AAAAAAA..", "..AAAAAAA..", "...AAAAA..."], variants: [{ A: "#006400", Q: "#FF0000" }, { A: "#ff0000", Q: "#016400" }] },
|
|
164
|
-
{ id: "trucker_cap", name: "Trucker Cap", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...AAQQ....", "...AAQQ....", "..AAQQQAA..", "..AAQQQAA.."], variants: [{ A: "#2196F3", Q: "#FFFFFF" }, { A: "#f41fe3", Q: "#FFFFFF" }, { A: "#1ff45f", Q: "#FFFFFF" }] },
|
|
165
|
-
{ id: "hard_hat", name: "Hard Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "....AAA....", "...AAAAA...", "..AAAAAAA..", "..AAAAAAAAA"], variants: [{ A: "#FFD600" }, { A: "#d74c1d" }] },
|
|
166
|
-
{ id: "chef_toque", name: "Chef's Toque", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...AAAAA...", "..AAQAQAA..", "...AQAQA...", "...AQAQA...", "...AQAQA...", "...AAAAA..."], variants: [{ A: "#FFFFFF", Q: "#f9f9f9" }] },
|
|
167
|
-
{ id: "bobble_hat", name: "Bobble Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", ".....Q.....", "...AAAAA...", "...AAAAA...", "..AAAAAAA.."], variants: [{ A: "#C62828", Q: "#FFFFFF" }, { A: "#293bc7", Q: "#FFFFFF" }, { A: "#29c775", Q: "#231f1f" }, { A: "#a529c7", Q: "#d50707" }] },
|
|
168
|
-
{ id: "cowboy_hat", name: "Cowboy Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...AAAAA...", "...AAAAA...", "A.AAAAAAA.A", ".AAAAAAAAA."], variants: [{ A: "#8B4513" }, { A: "#0a0400" }, { A: "#956c50" }] },
|
|
169
|
-
{ id: "baseball_cap", name: "Baseball Cap", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...AAAAA...", "..AAAAAA...", "..AAAAAAA..", "..AAAAAAAAA"], variants: [{ A: "#1565C0" }, { A: "#8515c1" }, { A: "#15c157" }, { A: "#ef2d0b" }] },
|
|
170
|
-
{ id: "tinfoil_hat", name: "Tinfoil Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", ".....A.....", "....AAA....", "...AAAAA...", "..AAAAAAA.."], variants: [{ A: "#B0BEC5" }, { A: "#6a6c6c" }] },
|
|
171
|
-
{ id: "dunce_cap", name: "Dunce Cap", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", ".....Q.....", "....QAQ....", "...QAAAQ...", "...QAAAQ...", "..QAAAAAQ..", "..AAAAAAA.."], variants: [{ A: "#F8F8F8", Q: "#F44336" }] },
|
|
172
|
-
{ id: "mini_top_hat", name: "Mini Top Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...AAAAA...", "...AAAAA...", "...AAAAA...", "..AAAAAAA..", "..AAAAAAA.."], variants: [{ A: "#212121" }, { A: "#626060" }] },
|
|
155
|
+
{ id: "flat_cap", name: "Flat Cap", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...........", "....AAAA...", "...AAAAAA..", "..AAAAAAA.."], variants: [{ A: "#8B6914" }, { A: "#12301b" }, { A: "#aab5cb" }, { A: "#bdcbaa" }], rollable: true },
|
|
156
|
+
{ id: "bucket_hat", name: "Bucket Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...QQQQQ...", "...AAAAA...", "...AAAAA...", ".AAAAAAAAA."], variants: [{ A: "#CC2200", Q: "#FFFFFF" }, { A: "#0007cc", Q: "#FFFFFF" }, { A: "#becc00", Q: "#4d3dc7" }, { A: "#cc00c5", Q: "#d6d6dc" }], rollable: true },
|
|
157
|
+
{ id: "beanie", name: "Beanie", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "....AAA....", "...AAAAA...", "...AAAAA...", "..AAAAAAA.."], variants: [{ A: "#4A7C59" }, { A: "#b21f35" }, { A: "#ec9418" }, { A: "#3a17e6" }], rollable: true },
|
|
158
|
+
{ id: "stetson", name: "Stetson", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...AA.AA...", "...AAAAA...", "...AAAAA...", "A..AAAAA..A", "AAAAAAAAAAA", "AAAAAAAAAAA"], variants: [{ A: "#C49A00" }, { A: "#272004" }, { A: "#040404" }, { A: "#373606" }], rollable: true },
|
|
159
|
+
{ id: "party_hat", name: "Party Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", ".....A.....", "....AAA....", "....AQA....", "...AQAQA...", "...AAAAA..."], variants: [{ A: "#FF69B4", Q: "#FFD700" }, { A: "#c46bff", Q: "#ff000d" }, { A: "#fdff6b", Q: "#0400ff" }, { A: "#6bff97", Q: "#05050a" }], rollable: true },
|
|
160
|
+
{ id: "fez", name: "Fez", rarity: "common", width: 11, anchor_x: 22, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "....Q......", "....AAA....", "....AAA....", "....AAA...."], variants: [{ A: "#CC0000", Q: "#8B0000" }, { A: "#CC0000", Q: "#f5e5e5" }, { A: "#CC0000", Q: "#f1e209" }, { A: "#CC0000", Q: "#0956f1" }], rollable: true },
|
|
161
|
+
{ id: "sailor_hat", name: "Sailor Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...QQQQQ...", "..AAAAAAA..", "..QQQQQQQ..", "..AAAAAAA.."], variants: [{ A: "#FFFFFF", Q: "#000080" }, { A: "#FFFFFF", Q: "#c0c0ed" }, { A: "#FFFFFF", Q: "#00000a" }, { A: "#FFFFFF", Q: "#0505ef" }], rollable: true },
|
|
162
|
+
{ id: "newsboy_cap", name: "Newsboy Cap", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...AAAAA...", "..AAAQAAA..", "..AAAAAAA..", "..AAAAAA..."], variants: [{ A: "#5C4033", Q: "#3D2B1F" }, { A: "#e96020", Q: "#131211" }, { A: "#342c28", Q: "#131211" }, { A: "#0a0300", Q: "#ddab78" }], rollable: true },
|
|
163
|
+
{ id: "tam_o_shanter", name: "Tam O'Shanter", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", ".....Q.....", "....AAA....", "..AAAAAAA..", "..AAAAAAA..", "...AAAAA..."], variants: [{ A: "#006400", Q: "#FF0000" }, { A: "#ff0000", Q: "#016400" }], rollable: true },
|
|
164
|
+
{ id: "trucker_cap", name: "Trucker Cap", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...AAQQ....", "...AAQQ....", "..AAQQQAA..", "..AAQQQAA.."], variants: [{ A: "#2196F3", Q: "#FFFFFF" }, { A: "#f41fe3", Q: "#FFFFFF" }, { A: "#1ff45f", Q: "#FFFFFF" }], rollable: true },
|
|
165
|
+
{ id: "hard_hat", name: "Hard Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "....AAA....", "...AAAAA...", "..AAAAAAA..", "..AAAAAAAAA"], variants: [{ A: "#FFD600" }, { A: "#d74c1d" }], rollable: true },
|
|
166
|
+
{ id: "chef_toque", name: "Chef's Toque", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...AAAAA...", "..AAQAQAA..", "...AQAQA...", "...AQAQA...", "...AQAQA...", "...AAAAA..."], variants: [{ A: "#FFFFFF", Q: "#f9f9f9" }], rollable: true },
|
|
167
|
+
{ id: "bobble_hat", name: "Bobble Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", ".....Q.....", "...AAAAA...", "...AAAAA...", "..AAAAAAA.."], variants: [{ A: "#C62828", Q: "#FFFFFF" }, { A: "#293bc7", Q: "#FFFFFF" }, { A: "#29c775", Q: "#231f1f" }, { A: "#a529c7", Q: "#d50707" }], rollable: true },
|
|
168
|
+
{ id: "cowboy_hat", name: "Cowboy Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...AAAAA...", "...AAAAA...", "A.AAAAAAA.A", ".AAAAAAAAA."], variants: [{ A: "#8B4513" }, { A: "#0a0400" }, { A: "#956c50" }], rollable: true },
|
|
169
|
+
{ id: "baseball_cap", name: "Baseball Cap", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...AAAAA...", "..AAAAAA...", "..AAAAAAA..", "..AAAAAAAAA"], variants: [{ A: "#1565C0" }, { A: "#8515c1" }, { A: "#15c157" }, { A: "#ef2d0b" }], rollable: true },
|
|
170
|
+
{ id: "tinfoil_hat", name: "Tinfoil Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", ".....A.....", "....AAA....", "...AAAAA...", "..AAAAAAA.."], variants: [{ A: "#B0BEC5" }, { A: "#6a6c6c" }], rollable: true },
|
|
171
|
+
{ id: "dunce_cap", name: "Dunce Cap", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", ".....Q.....", "....QAQ....", "...QAAAQ...", "...QAAAQ...", "..QAAAAAQ..", "..AAAAAAA.."], variants: [{ A: "#F8F8F8", Q: "#F44336" }], rollable: true },
|
|
172
|
+
{ id: "mini_top_hat", name: "Mini Top Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...AAAAA...", "...AAAAA...", "...AAAAA...", "..AAAAAAA..", "..AAAAAAA.."], variants: [{ A: "#212121" }, { A: "#626060" }], rollable: true },
|
|
173
173
|
// ── RARE (10) ──────────────────────────────────────────────────────────
|
|
174
|
-
{ id: "bicorne", name: "Bicorne", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "..AAAQQQQ..", "..AAAAAAA..", "..AAAAAAA..", "...QQQQQ..."], variants: [{ A: "#1A237E", Q: "#FFD700" }, { A: "#01052d", Q: "#544803" }] },
|
|
175
|
-
{ id: "viking_helmet", name: "Viking Helmet", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "..A.AAA.A..", "..AAAAAAA..", "..AAAAAAA..", "..AQQQQQA.."], variants: [{ A: "#9E9E9E", Q: "#8D6E63" }, { A: "#dcdbdb", Q: "#bf3908" }] },
|
|
176
|
-
{ id: "jesters_cap", name: "Jester's Cap", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "..AQAQAQA..", "..AQAQAQA..", "...AAAAA...", "...AAAAA..."], variants: [{ A: "#E53935", Q: "#FFD600" }, { A: "#e5a434", Q: "#0040ff" }, { A: "#34e537", Q: "#eeff00" }, { A: "#e234e5", Q: "#00ff40" }] },
|
|
177
|
-
{ id: "plague_doctor", name: "Plague Doctor Beak", rarity: "rare", width: 11, anchor_x: 24, rows: ["...........", "...........", "...........", "...........", "....QQQ....", "...QAAAQQ..", "...QQQQQQQ.", "..QQQQQ.QQQ", "..QQQQ....Q", "..QQQQ....."], variants: [{ A: "#F5F5F5", Q: "#795548" }, { A: "#e1dbdb", Q: "#080707" }] },
|
|
178
|
-
{ id: "morion", name: "Conquistador Morion", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", ".....Q.....", "...QQQQQ...", "...QAAAQ...", ".A..AAA..A.", "..AAQQQAA.."], variants: [{ A: "#B0BEC5", Q: "#FFD600" }, { A: "#0a4768", Q: "#e6c10a" }] },
|
|
179
|
-
{ id: "shako", name: "Shako", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "........Q..", "........Q..", "........Q..", "........Q..", "..AAAAAAA..", "..AAAAAAA..", "..AAAAAAA..", "..AQQQQQA.."], variants: [{ A: "#45464f", Q: "#00ff2a" }, { A: "#45464f", Q: "#ff4d00" }, { A: "#45464f", Q: "#ff0019" }, { A: "#45464f", Q: "#fff700" }] },
|
|
180
|
-
{ id: "centurion_helm", name: "Centurion Helm", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "....QQQ....", "...QQQQQQ..", "..QQQQQQQQ.", ".QQ..A...Q.", ".Q..AAA....", "...AAAAA...", "..AAAAAAA..", "..AAAAAAA.."], variants: [{ A: "#B0BEC5", Q: "#C62828" }, { A: "#2f3131", Q: "#C62828" }] },
|
|
181
|
-
{ id: "papal_mitre", name: "Papal Mitre", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "....QQQ....", "...QQQQQ...", "...QAAAQ...", "..AAAAAAA.."], variants: [{ A: "#FFFFFF", Q: "#FFD700" }] },
|
|
182
|
-
{ id: "headdress", name: "Headdress", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "..AQAQAQA..", "..AQAQAQA..", "..AAAAAAA..", "...QQQQQ..."], variants: [{ A: "#FF8F00", Q: "#1565C0" }] },
|
|
183
|
-
{ id: "sombrero", name: "Sombrero", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", ".....A.....", "....AAA....", "...AAAAA...", "...AQAQA...", "AAAAAAAAAAA"], variants: [{ A: "#F57F17", Q: "#BF360C" }, { A: "#f8b377", Q: "#3e1204" }, { A: "#d6f877", Q: "#04133e" }, { A: "#d6f877", Q: "#04133e" }] },
|
|
174
|
+
{ id: "bicorne", name: "Bicorne", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "..AAAQQQQ..", "..AAAAAAA..", "..AAAAAAA..", "...QQQQQ..."], variants: [{ A: "#1A237E", Q: "#FFD700" }, { A: "#01052d", Q: "#544803" }], rollable: true },
|
|
175
|
+
{ id: "viking_helmet", name: "Viking Helmet", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "..A.AAA.A..", "..AAAAAAA..", "..AAAAAAA..", "..AQQQQQA.."], variants: [{ A: "#9E9E9E", Q: "#8D6E63" }, { A: "#dcdbdb", Q: "#bf3908" }], rollable: true },
|
|
176
|
+
{ id: "jesters_cap", name: "Jester's Cap", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "..AQAQAQA..", "..AQAQAQA..", "...AAAAA...", "...AAAAA..."], variants: [{ A: "#E53935", Q: "#FFD600" }, { A: "#e5a434", Q: "#0040ff" }, { A: "#34e537", Q: "#eeff00" }, { A: "#e234e5", Q: "#00ff40" }], rollable: true },
|
|
177
|
+
{ id: "plague_doctor", name: "Plague Doctor Beak", rarity: "rare", width: 11, anchor_x: 24, rows: ["...........", "...........", "...........", "...........", "....QQQ....", "...QAAAQQ..", "...QQQQQQQ.", "..QQQQQ.QQQ", "..QQQQ....Q", "..QQQQ....."], variants: [{ A: "#F5F5F5", Q: "#795548" }, { A: "#e1dbdb", Q: "#080707" }], rollable: true },
|
|
178
|
+
{ id: "morion", name: "Conquistador Morion", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", ".....Q.....", "...QQQQQ...", "...QAAAQ...", ".A..AAA..A.", "..AAQQQAA.."], variants: [{ A: "#B0BEC5", Q: "#FFD600" }, { A: "#0a4768", Q: "#e6c10a" }], rollable: true },
|
|
179
|
+
{ id: "shako", name: "Shako", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "........Q..", "........Q..", "........Q..", "........Q..", "..AAAAAAA..", "..AAAAAAA..", "..AAAAAAA..", "..AQQQQQA.."], variants: [{ A: "#45464f", Q: "#00ff2a" }, { A: "#45464f", Q: "#ff4d00" }, { A: "#45464f", Q: "#ff0019" }, { A: "#45464f", Q: "#fff700" }], rollable: true },
|
|
180
|
+
{ id: "centurion_helm", name: "Centurion Helm", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "....QQQ....", "...QQQQQQ..", "..QQQQQQQQ.", ".QQ..A...Q.", ".Q..AAA....", "...AAAAA...", "..AAAAAAA..", "..AAAAAAA.."], variants: [{ A: "#B0BEC5", Q: "#C62828" }, { A: "#2f3131", Q: "#C62828" }], rollable: true },
|
|
181
|
+
{ id: "papal_mitre", name: "Papal Mitre", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "....QQQ....", "...QQQQQ...", "...QAAAQ...", "..AAAAAAA.."], variants: [{ A: "#FFFFFF", Q: "#FFD700" }], rollable: true },
|
|
182
|
+
{ id: "headdress", name: "Headdress", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "..AQAQAQA..", "..AQAQAQA..", "..AAAAAAA..", "...QQQQQ..."], variants: [{ A: "#FF8F00", Q: "#1565C0" }], rollable: true },
|
|
183
|
+
{ id: "sombrero", name: "Sombrero", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", ".....A.....", "....AAA....", "...AAAAA...", "...AQAQA...", "AAAAAAAAAAA"], variants: [{ A: "#F57F17", Q: "#BF360C" }, { A: "#f8b377", Q: "#3e1204" }, { A: "#d6f877", Q: "#04133e" }, { A: "#d6f877", Q: "#04133e" }], rollable: true },
|
|
184
184
|
// ── EPIC (6) ───────────────────────────────────────────────────────────
|
|
185
|
-
{ id: "papal_tiara", name: "Papal Tiara", rarity: "epic", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "....QQ.....", "...QQQQQ...", "...QAAQQ...", "...QQQQQ...", "..AAAAAAA..", "..AQQQQQA.."], variants: [{ A: "#FFFFFF", Q: "#FFD700" }, { A: "#b18e10", Q: "#f3f3f1" }] },
|
|
186
|
-
{ id: "samurai_kabuto", name: "Samurai Kabuto", rarity: "epic", width: 11, anchor_x: 23, rows: ["....Q...Q..", "....QQ.QQ..", ".....QQQ...", ".......Q...", "...AAAAQ...", "..AAAAAQQ..", "..AAAAAQQ..", ".AAAAAAAQ..", "AAAAAAAAQ..", "AAAAAAAAQ.."], variants: [{ A: "#B0BEC5", Q: "#C62828" }, { A: "#050505", Q: "#C62828" }, { A: "#675f5f", Q: "#c4c729" }] },
|
|
187
|
-
{ id: "gladiator_galea", name: "Gladiator Galea", rarity: "epic", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "....QQQQQQ.", "...QQQQQ...", "...QQQQQ...", "...QAAA....", "..AAAAAAA..", "..AAAAAAA..", "..AQQQQQA.."], variants: [{ A: "#B0BEC5", Q: "#C62828" }, { A: "#ffe907", Q: "#C62828" }] },
|
|
188
|
-
{ id: "pharaoh_nemes", name: "Pharaoh Nemes", rarity: "epic", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "..AAAAAAA..", "..AAQAQAA..", "..QAQAQAQ..", "..QAQAQAQ..", "..QQAAAQQ..", "..QQAAAAA..", "...QAQA...."], variants: [{ A: "#FFD700", Q: "#1565C0" }, { A: "#8d342a", Q: "#63686e" }] },
|
|
189
|
-
{ id: "spartan_helmet", name: "Spartan Helmet", rarity: "epic", width: 11, anchor_x: 23, rows: ["...........", "........Q..", ".......QQ..", ".....QQQQ..", "....QQQQQ..", "..QQQQQQ...", ".QQQAA.....", "QQAAAAAAA..", "Q.AAAAAAA..", "..AQQQQQA.."], variants: [{ A: "#B0BEC5", Q: "#B71C1C" }, { A: "#B0BEC5", Q: "#b2b51c" }, { A: "#B0BEC5", Q: "#b5611c" }] },
|
|
190
|
-
{ id: "conquistador_full", name: "Conquistador Helm", rarity: "epic", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", ".....A.....", "....AAA....", "...AAAAA...", "..AAAAAAA..", "...AQQQA...", "...AQQQA..."], variants: [{ A: "#B0BEC5", Q: "#FFD700" }, { A: "#B0BEC5", Q: "#0040ff" }, { A: "#B0BEC5", Q: "#36123b" }] },
|
|
185
|
+
{ id: "papal_tiara", name: "Papal Tiara", rarity: "epic", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "....QQ.....", "...QQQQQ...", "...QAAQQ...", "...QQQQQ...", "..AAAAAAA..", "..AQQQQQA.."], variants: [{ A: "#FFFFFF", Q: "#FFD700" }, { A: "#b18e10", Q: "#f3f3f1" }], rollable: true },
|
|
186
|
+
{ id: "samurai_kabuto", name: "Samurai Kabuto", rarity: "epic", width: 11, anchor_x: 23, rows: ["....Q...Q..", "....QQ.QQ..", ".....QQQ...", ".......Q...", "...AAAAQ...", "..AAAAAQQ..", "..AAAAAQQ..", ".AAAAAAAQ..", "AAAAAAAAQ..", "AAAAAAAAQ.."], variants: [{ A: "#B0BEC5", Q: "#C62828" }, { A: "#050505", Q: "#C62828" }, { A: "#675f5f", Q: "#c4c729" }], rollable: true },
|
|
187
|
+
{ id: "gladiator_galea", name: "Gladiator Galea", rarity: "epic", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "....QQQQQQ.", "...QQQQQ...", "...QQQQQ...", "...QAAA....", "..AAAAAAA..", "..AAAAAAA..", "..AQQQQQA.."], variants: [{ A: "#B0BEC5", Q: "#C62828" }, { A: "#ffe907", Q: "#C62828" }], rollable: true },
|
|
188
|
+
{ id: "pharaoh_nemes", name: "Pharaoh Nemes", rarity: "epic", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "..AAAAAAA..", "..AAQAQAA..", "..QAQAQAQ..", "..QAQAQAQ..", "..QQAAAQQ..", "..QQAAAAA..", "...QAQA...."], variants: [{ A: "#FFD700", Q: "#1565C0" }, { A: "#8d342a", Q: "#63686e" }], rollable: true },
|
|
189
|
+
{ id: "spartan_helmet", name: "Spartan Helmet", rarity: "epic", width: 11, anchor_x: 23, rows: ["...........", "........Q..", ".......QQ..", ".....QQQQ..", "....QQQQQ..", "..QQQQQQ...", ".QQQAA.....", "QQAAAAAAA..", "Q.AAAAAAA..", "..AQQQQQA.."], variants: [{ A: "#B0BEC5", Q: "#B71C1C" }, { A: "#B0BEC5", Q: "#b2b51c" }, { A: "#B0BEC5", Q: "#b5611c" }], rollable: true },
|
|
190
|
+
{ id: "conquistador_full", name: "Conquistador Helm", rarity: "epic", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", ".....A.....", "....AAA....", "...AAAAA...", "..AAAAAAA..", "...AQQQA...", "...AQQQA..."], variants: [{ A: "#B0BEC5", Q: "#FFD700" }, { A: "#B0BEC5", Q: "#0040ff" }, { A: "#B0BEC5", Q: "#36123b" }], rollable: true },
|
|
191
191
|
// ── LEGENDARY (5) ──────────────────────────────────────────────────────
|
|
192
|
-
{ id: "rainbow_crown", name: "Rainbow Crown", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "...........", ".....A.....", "....AAA....", "....AQA....", "....AAA....", "...AAQAA...", "...AAAAA...", "..AAAQAAA..", "..AAAAAAA.."], colors: { A: "#FFD700", Q: "#553f3f" }, animation: { type: "cycle", frames: ["#FF0000", "#FF7F00", "#FFFF00", "#00FF00", "#0000FF", "#8B00FF"], fps: 8 } },
|
|
193
|
-
{ id: "inferno_cap", name: "Inferno Cap", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "....AAA....", "...AAAAA...", "....AAA....", ".....Q.....", "A....Q....A", "A...QQQ...A", ".A..QQQ..A.", "..AAAAAAA..", "..AAAAAAA.."], colors: { A: "#FF4500", Q: "#FFD700" }, animation: { type: "cycle", frames: ["#FF0000", "#FF2200", "#FF4500", "#FF6600", "#FF8C00", "#FFA500"], fps: 12 } },
|
|
194
|
-
{ id: "void_hood", name: "Void Hood", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...AAA.....", "..AAAAAA...", ".AAAAAAA...", ".AAAAAAAA..", "AAAAAAAAA..", "AAAAQQQAA..", "AAAAQQQAA.."], colors: { A: "#1A0033", Q: "#d9cfe3" }, animation: { type: "cycle", frames: ["#0D0019", "#1A0033", "#2D004D", "#3D0066", "#2D004D", "#1A0033"], fps: 3 } },
|
|
195
|
-
{ id: "prismatic_jester", name: "Prismatic Jester", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "..Q.Q.Q.Q..", "Q..A.A.A..Q", ".Q.A.A.A.Q.", "..AQAQAQA..", "..AQAQAQA..", "..AAAAAAA..", "..AAAAAAA..", "..AAAAAAA..", "..AAAAAAA.."], colors: { A: "#FF0000", Q: "#0000FF" }, animation: { type: "cycle", frames: ["#FF0000", "#FF7F00", "#FFFF00", "#00FF00", "#0000FF", "#8B00FF", "#FF00FF", "#00FFFF"], fps: 15 } },
|
|
196
|
-
{ id: "aurora_helm", name: "Aurora Helm", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...QQQQQ...", "...QQQQQ...", "..AAAAAAA..", "..AAAAAAA..", "..AQAAAQA..", "..AQAAAQA.."], colors: { A: "#00CED1", Q: "#00FF7F" }, animation: { type: "cycle", frames: ["#0000FF", "#0066FF", "#00BFFF", "#00CED1", "#00FF7F", "#7CFC00", "#00FF7F", "#00CED1"], fps: 4 } }
|
|
192
|
+
{ id: "rainbow_crown", name: "Rainbow Crown", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "...........", ".....A.....", "....AAA....", "....AQA....", "....AAA....", "...AAQAA...", "...AAAAA...", "..AAAQAAA..", "..AAAAAAA.."], colors: { A: "#FFD700", Q: "#553f3f" }, animation: { type: "cycle", frames: ["#FF0000", "#FF7F00", "#FFFF00", "#00FF00", "#0000FF", "#8B00FF"], fps: 8 }, rollable: true },
|
|
193
|
+
{ id: "inferno_cap", name: "Inferno Cap", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "....AAA....", "...AAAAA...", "....AAA....", ".....Q.....", "A....Q....A", "A...QQQ...A", ".A..QQQ..A.", "..AAAAAAA..", "..AAAAAAA.."], colors: { A: "#FF4500", Q: "#FFD700" }, animation: { type: "cycle", frames: ["#FF0000", "#FF2200", "#FF4500", "#FF6600", "#FF8C00", "#FFA500"], fps: 12 }, rollable: true },
|
|
194
|
+
{ id: "void_hood", name: "Void Hood", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...AAA.....", "..AAAAAA...", ".AAAAAAA...", ".AAAAAAAA..", "AAAAAAAAA..", "AAAAQQQAA..", "AAAAQQQAA.."], colors: { A: "#1A0033", Q: "#d9cfe3" }, animation: { type: "cycle", frames: ["#0D0019", "#1A0033", "#2D004D", "#3D0066", "#2D004D", "#1A0033"], fps: 3 }, rollable: true },
|
|
195
|
+
{ id: "prismatic_jester", name: "Prismatic Jester", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "..Q.Q.Q.Q..", "Q..A.A.A..Q", ".Q.A.A.A.Q.", "..AQAQAQA..", "..AQAQAQA..", "..AAAAAAA..", "..AAAAAAA..", "..AAAAAAA..", "..AAAAAAA.."], colors: { A: "#FF0000", Q: "#0000FF" }, animation: { type: "cycle", frames: ["#FF0000", "#FF7F00", "#FFFF00", "#00FF00", "#0000FF", "#8B00FF", "#FF00FF", "#00FFFF"], fps: 15 }, rollable: true },
|
|
196
|
+
{ id: "aurora_helm", name: "Aurora Helm", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...QQQQQ...", "...QQQQQ...", "..AAAAAAA..", "..AAAAAAA..", "..AQAAAQA..", "..AQAAAQA.."], colors: { A: "#00CED1", Q: "#00FF7F" }, animation: { type: "cycle", frames: ["#0000FF", "#0066FF", "#00BFFF", "#00CED1", "#00FF7F", "#7CFC00", "#00FF7F", "#00CED1"], fps: 4 }, rollable: true },
|
|
197
|
+
// Claim-only: awarded by an admin, never from a roll. Only the A channel cycles,
|
|
198
|
+
// so the inset motif shifts colour while the cap body stays a static rust brown.
|
|
199
|
+
// The body colour is kept out of the frame list so the motif never merges into it.
|
|
200
|
+
{ id: "contributor_cap", name: "Contributor Cap", rarity: "legendary", width: 11, anchor_x: 23, rows: [".....Q.....", "....QQQ....", "...QQQQQ...", "..QAAAQQQ..", "..QQAQQQQ..", ".QQQAQAAQQ.", ".QQQAQAQAQ.", ".QQQQQAQAQ.", ".QQQQQAAQQ.", ".QQQQQQQQQ."], colors: { A: "#21138b", Q: "#6f2801" }, animation: { type: "cycle", frames: ["#FF8C42", "#E0457B", "#8B5CF6", "#3B82F6", "#22D3EE", "#34D399", "#A3E635", "#FBBF24"], fps: 6 }, rollable: false }
|
|
197
201
|
];
|
|
198
202
|
|
|
199
203
|
// ../shared/dist/series-transform.js
|
|
@@ -252,6 +256,39 @@ function toTag(c, y) {
|
|
|
252
256
|
}
|
|
253
257
|
}
|
|
254
258
|
|
|
259
|
+
// ../shared/dist/scoring.js
|
|
260
|
+
function scoredOf(horse) {
|
|
261
|
+
return horse.scored_tokens ?? horse.current_tokens;
|
|
262
|
+
}
|
|
263
|
+
var STAMINA = {
|
|
264
|
+
SUSTAINABLE_PACE: 4e3,
|
|
265
|
+
DRAIN_PER_MIN: 4,
|
|
266
|
+
MAX_DRAIN_PER_MIN: 6,
|
|
267
|
+
RECOVER_PER_MIN: 2,
|
|
268
|
+
RECOVER_TICK_CAP_MS: 9e4,
|
|
269
|
+
TAPER_FLOOR: 25,
|
|
270
|
+
TIRED_MULTIPLIER: 0.5
|
|
271
|
+
};
|
|
272
|
+
function resolveStaminaConfig(race) {
|
|
273
|
+
const c = race.stamina_config ?? {};
|
|
274
|
+
return {
|
|
275
|
+
sustainable_pace: c.sustainable_pace ?? STAMINA.SUSTAINABLE_PACE,
|
|
276
|
+
drain_per_min: c.drain_per_min ?? STAMINA.DRAIN_PER_MIN,
|
|
277
|
+
max_drain_per_min: c.max_drain_per_min ?? STAMINA.MAX_DRAIN_PER_MIN,
|
|
278
|
+
recover_per_min: c.recover_per_min ?? STAMINA.RECOVER_PER_MIN,
|
|
279
|
+
taper_floor: c.taper_floor ?? STAMINA.TAPER_FLOOR,
|
|
280
|
+
tired_multiplier: c.tired_multiplier ?? STAMINA.TIRED_MULTIPLIER
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
var STAMINA_PARAM_BOUNDS = {
|
|
284
|
+
sustainable_pace: { min: 1e3, max: 2e4, step: 250, default: STAMINA.SUSTAINABLE_PACE },
|
|
285
|
+
drain_per_min: { min: 1, max: 12, step: 1, default: STAMINA.DRAIN_PER_MIN },
|
|
286
|
+
max_drain_per_min: { min: 2, max: 20, step: 1, default: STAMINA.MAX_DRAIN_PER_MIN },
|
|
287
|
+
recover_per_min: { min: 1, max: 8, step: 1, default: STAMINA.RECOVER_PER_MIN },
|
|
288
|
+
taper_floor: { min: 10, max: 60, step: 5, default: STAMINA.TAPER_FLOOR },
|
|
289
|
+
tired_multiplier: { min: 0.2, max: 0.9, step: 0.05, default: STAMINA.TIRED_MULTIPLIER }
|
|
290
|
+
};
|
|
291
|
+
|
|
255
292
|
// src/ui/HorseSprite.tsx
|
|
256
293
|
import { Box, Text } from "ink";
|
|
257
294
|
|
|
@@ -788,8 +825,8 @@ var HEARTBEAT_RETRY_DELAYS_MS = [1e3, 2e3, 4e3, 8e3, 15e3];
|
|
|
788
825
|
// src/version.ts
|
|
789
826
|
import { createRequire } from "module";
|
|
790
827
|
function readVersion() {
|
|
791
|
-
if ("2.
|
|
792
|
-
return "2.
|
|
828
|
+
if ("2.13.1".length > 0) {
|
|
829
|
+
return "2.13.1";
|
|
793
830
|
}
|
|
794
831
|
try {
|
|
795
832
|
const req = createRequire(import.meta.url);
|
|
@@ -991,6 +1028,12 @@ function equipHat(stableHorseId, body) {
|
|
|
991
1028
|
function createWebSession() {
|
|
992
1029
|
return request("POST", "/web-sessions", void 0, void 0);
|
|
993
1030
|
}
|
|
1031
|
+
function probeClaim(code) {
|
|
1032
|
+
return request("GET", `/claims/${encodeURIComponent(code)}`, void 0, void 0);
|
|
1033
|
+
}
|
|
1034
|
+
function redeemClaim(code, body) {
|
|
1035
|
+
return request("POST", `/claims/${encodeURIComponent(code)}/redeem`, body, void 0);
|
|
1036
|
+
}
|
|
994
1037
|
|
|
995
1038
|
// src/commands/stable-create.ts
|
|
996
1039
|
async function stableCreateCommand() {
|
|
@@ -1130,7 +1173,7 @@ import { render as render3 } from "ink";
|
|
|
1130
1173
|
import { useState as useState3 } from "react";
|
|
1131
1174
|
import { Box as Box5, Text as Text5, useInput as useInput2 } from "ink";
|
|
1132
1175
|
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1133
|
-
function HorsePicker({ horses, onPick, onCancel }) {
|
|
1176
|
+
function HorsePicker({ horses, onPick, onCancel, prompt = "Pick a horse to race:" }) {
|
|
1134
1177
|
const [idx, setIdx] = useState3(0);
|
|
1135
1178
|
useInput2((input, key) => {
|
|
1136
1179
|
if (key.escape) {
|
|
@@ -1158,7 +1201,7 @@ function HorsePicker({ horses, onPick, onCancel }) {
|
|
|
1158
1201
|
] });
|
|
1159
1202
|
}
|
|
1160
1203
|
return /* @__PURE__ */ jsxs3(Box5, { flexDirection: "column", children: [
|
|
1161
|
-
/* @__PURE__ */ jsx5(Text5, { children:
|
|
1204
|
+
/* @__PURE__ */ jsx5(Text5, { children: prompt }),
|
|
1162
1205
|
horses.map((h, i) => /* @__PURE__ */ jsxs3(Box5, { flexDirection: "column", children: [
|
|
1163
1206
|
/* @__PURE__ */ jsx5(Box5, { flexDirection: "row", children: /* @__PURE__ */ jsxs3(Text5, { children: [
|
|
1164
1207
|
i === idx ? "\u25BA" : " ",
|
|
@@ -1326,6 +1369,8 @@ async function createRaceCommand(organisationName) {
|
|
|
1326
1369
|
const counts_input = countInputRaw === "y" || countInputRaw === "yes";
|
|
1327
1370
|
const top5Raw = (await rl.question("Count only each racer's 5 most-active conversations toward their primary model's score? [y/N]: ")).trim().toLowerCase();
|
|
1328
1371
|
const primary_top5 = top5Raw === "y" || top5Raw === "yes";
|
|
1372
|
+
const staminaRaw = (await rl.question("Stamina \u2014 horses that run flat out tire and score less until they recover? [y/N]: ")).trim().toLowerCase();
|
|
1373
|
+
const stamina = staminaRaw === "y" || staminaRaw === "yes";
|
|
1329
1374
|
const resp = await createRace({
|
|
1330
1375
|
name,
|
|
1331
1376
|
start_time: start,
|
|
@@ -1334,7 +1379,8 @@ async function createRaceCommand(organisationName) {
|
|
|
1334
1379
|
...max !== void 0 ? { max_participants: max } : {},
|
|
1335
1380
|
...org ? { organisation_name: org } : {},
|
|
1336
1381
|
...counts_input ? { counts_input: true } : {},
|
|
1337
|
-
...primary_top5 ? { primary_top5: true } : {}
|
|
1382
|
+
...primary_top5 ? { primary_top5: true } : {},
|
|
1383
|
+
...stamina ? { stamina: true } : {}
|
|
1338
1384
|
});
|
|
1339
1385
|
console.log("");
|
|
1340
1386
|
console.log(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557");
|
|
@@ -1353,6 +1399,9 @@ async function createRaceCommand(organisationName) {
|
|
|
1353
1399
|
if (primary_top5) {
|
|
1354
1400
|
console.log(" Primary score counts only each racer's top 5 conversations per beat.");
|
|
1355
1401
|
}
|
|
1402
|
+
if (stamina) {
|
|
1403
|
+
console.log(" Stamina on \u2014 horses running above a sustainable pace will tire.");
|
|
1404
|
+
}
|
|
1356
1405
|
console.log(` Share with participants: token-derby join ${resp.join_code}`);
|
|
1357
1406
|
return 0;
|
|
1358
1407
|
} catch (e) {
|
|
@@ -1442,8 +1491,10 @@ function StatusScreen(props) {
|
|
|
1442
1491
|
const divisionField = own?.division === void 0 ? [] : race.horses.filter((h) => h.division === own.division);
|
|
1443
1492
|
const divisionRank = own ? divisionField.indexOf(own) + 1 : 0;
|
|
1444
1493
|
const showDivision = (race.league_division_names?.length ?? 0) > 0 && divisionRank > 0;
|
|
1494
|
+
const staminaRow = race.stamina === true ? staminaLine(own, race) : null;
|
|
1445
1495
|
const rows = [
|
|
1446
|
-
{ label: "Tokens (race):", value: String(own?.
|
|
1496
|
+
{ label: "Tokens (race):", value: String(own?.final_scored_tokens ?? (own ? scoredOf(own) : 0)) },
|
|
1497
|
+
...staminaRow ? [staminaRow] : [],
|
|
1447
1498
|
{ label: "Position:", value: `${own?.rank ?? "\u2014"} of ${race.horses.length}` },
|
|
1448
1499
|
...showDivision ? [{ label: "Position (Division):", value: `${divisionRank} of ${divisionField.length}` }] : [],
|
|
1449
1500
|
{ label: "Leader:", value: leaderText(leader) },
|
|
@@ -1514,7 +1565,7 @@ function StatLines(props) {
|
|
|
1514
1565
|
}
|
|
1515
1566
|
function leaderText(h) {
|
|
1516
1567
|
if (!h) return "\u2014";
|
|
1517
|
-
return `${h.name}${h.user_name ? ` (${h.user_name})` : ""} \u2014 ${h.
|
|
1568
|
+
return `${h.name}${h.user_name ? ` (${h.user_name})` : ""} \u2014 ${h.final_scored_tokens ?? scoredOf(h)}`;
|
|
1518
1569
|
}
|
|
1519
1570
|
function elapsed(race) {
|
|
1520
1571
|
const start = new Date(race.start_time).getTime();
|
|
@@ -1528,6 +1579,22 @@ function bar(pct, width) {
|
|
|
1528
1579
|
const filled = Math.round(pct * width);
|
|
1529
1580
|
return "\u2593".repeat(filled) + "\u2591".repeat(width - filled);
|
|
1530
1581
|
}
|
|
1582
|
+
function staminaLine(own, race) {
|
|
1583
|
+
const stamina = own?.stamina ?? 100;
|
|
1584
|
+
const cfg = resolveStaminaConfig(race);
|
|
1585
|
+
const floor = cfg.taper_floor;
|
|
1586
|
+
const band = stamina > 50 ? "green" : stamina >= floor ? "amber" : "red";
|
|
1587
|
+
const color = band === "green" ? "green" : band === "amber" ? "yellow" : "red";
|
|
1588
|
+
const pct = Math.max(0, Math.min(1, stamina / 100));
|
|
1589
|
+
const multiplier = band === "red" ? cfg.tired_multiplier + (1 - cfg.tired_multiplier) * (stamina / floor) : null;
|
|
1590
|
+
return {
|
|
1591
|
+
label: "Stamina:",
|
|
1592
|
+
value: /* @__PURE__ */ jsxs5(Text7, { color, children: [
|
|
1593
|
+
`${Math.round(stamina)}% ${bar(pct, 20)}`,
|
|
1594
|
+
multiplier !== null ? ` \xD7${multiplier.toFixed(2)}` : ""
|
|
1595
|
+
] })
|
|
1596
|
+
};
|
|
1597
|
+
}
|
|
1531
1598
|
function statusColor(status) {
|
|
1532
1599
|
if (status === "live") return "green";
|
|
1533
1600
|
if (status === "pending") return "yellow";
|
|
@@ -2732,30 +2799,108 @@ function runNpmUpgrade(spawnImpl) {
|
|
|
2732
2799
|
}
|
|
2733
2800
|
|
|
2734
2801
|
// src/commands/roll.ts
|
|
2802
|
+
import React14 from "react";
|
|
2803
|
+
import { render as render6 } from "ink";
|
|
2804
|
+
|
|
2805
|
+
// src/ui/RollHorsePicker.tsx
|
|
2806
|
+
import { useState as useState6 } from "react";
|
|
2807
|
+
import { Box as Box9, Text as Text9, useInput as useInput4 } from "ink";
|
|
2808
|
+
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2809
|
+
function RollHorsePicker({ horses, onPick, onCancel }) {
|
|
2810
|
+
const [idx, setIdx] = useState6(0);
|
|
2811
|
+
useInput4((input, key) => {
|
|
2812
|
+
if (key.escape) {
|
|
2813
|
+
onCancel();
|
|
2814
|
+
return;
|
|
2815
|
+
}
|
|
2816
|
+
if (horses.length === 0) return;
|
|
2817
|
+
if (key.upArrow) {
|
|
2818
|
+
setIdx((idx - 1 + horses.length) % horses.length);
|
|
2819
|
+
return;
|
|
2820
|
+
}
|
|
2821
|
+
if (key.downArrow) {
|
|
2822
|
+
setIdx((idx + 1) % horses.length);
|
|
2823
|
+
return;
|
|
2824
|
+
}
|
|
2825
|
+
if (key.return) {
|
|
2826
|
+
onPick(horses[idx]);
|
|
2827
|
+
return;
|
|
2828
|
+
}
|
|
2829
|
+
});
|
|
2830
|
+
return /* @__PURE__ */ jsxs7(Box9, { flexDirection: "column", children: [
|
|
2831
|
+
/* @__PURE__ */ jsx9(Text9, { children: "Pick a horse to roll for:" }),
|
|
2832
|
+
horses.map((h, i) => /* @__PURE__ */ jsxs7(Box9, { flexDirection: "column", children: [
|
|
2833
|
+
/* @__PURE__ */ jsx9(Box9, { flexDirection: "row", children: /* @__PURE__ */ jsxs7(Text9, { children: [
|
|
2834
|
+
i === idx ? "\u25BA" : " ",
|
|
2835
|
+
" ",
|
|
2836
|
+
h.name,
|
|
2837
|
+
" ",
|
|
2838
|
+
/* @__PURE__ */ jsxs7(Text9, { color: "cyan", children: [
|
|
2839
|
+
"[Lvl. ",
|
|
2840
|
+
levelFromXp(h.xp),
|
|
2841
|
+
"]"
|
|
2842
|
+
] }),
|
|
2843
|
+
" ",
|
|
2844
|
+
/* @__PURE__ */ jsxs7(Text9, { color: "yellow", children: [
|
|
2845
|
+
"\u2014 ",
|
|
2846
|
+
h.pending,
|
|
2847
|
+
" roll",
|
|
2848
|
+
h.pending === 1 ? "" : "s"
|
|
2849
|
+
] })
|
|
2850
|
+
] }) }),
|
|
2851
|
+
/* @__PURE__ */ jsxs7(Box9, { flexDirection: "row", children: [
|
|
2852
|
+
/* @__PURE__ */ jsx9(Text9, { children: " " }),
|
|
2853
|
+
/* @__PURE__ */ jsx9(HorseSprite, { sprite: MINI_SPRITE, colors: h.colors })
|
|
2854
|
+
] })
|
|
2855
|
+
] }, h.stable_horse_id)),
|
|
2856
|
+
/* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "\u2191/\u2193 choose \xB7 Enter pick \xB7 Esc cancel" }) })
|
|
2857
|
+
] });
|
|
2858
|
+
}
|
|
2859
|
+
|
|
2860
|
+
// src/ui/prompt.ts
|
|
2861
|
+
async function promptYesNo(question) {
|
|
2862
|
+
resetStdinAfterInk();
|
|
2863
|
+
const readline6 = await import("readline/promises");
|
|
2864
|
+
const rl = readline6.createInterface({ input: process.stdin, output: process.stdout });
|
|
2865
|
+
const a = (await rl.question(question)).trim().toLowerCase();
|
|
2866
|
+
rl.close();
|
|
2867
|
+
return a === "" || a === "y" || a === "yes";
|
|
2868
|
+
}
|
|
2869
|
+
function resetStdinAfterInk() {
|
|
2870
|
+
if (process.stdin.isTTY && typeof process.stdin.setRawMode === "function") {
|
|
2871
|
+
process.stdin.setRawMode(false);
|
|
2872
|
+
}
|
|
2873
|
+
while (process.stdin.read() !== null) {
|
|
2874
|
+
}
|
|
2875
|
+
process.stdin.pause();
|
|
2876
|
+
process.stdin.ref();
|
|
2877
|
+
}
|
|
2878
|
+
|
|
2879
|
+
// src/ui/reveal.ts
|
|
2735
2880
|
import React13 from "react";
|
|
2736
2881
|
import { render as render5 } from "ink";
|
|
2737
2882
|
|
|
2738
2883
|
// src/ui/RollReveal.tsx
|
|
2739
|
-
import { useState as
|
|
2740
|
-
import { Box as
|
|
2884
|
+
import { useState as useState8, useEffect as useEffect4, useMemo } from "react";
|
|
2885
|
+
import { Box as Box11, Text as Text11 } from "ink";
|
|
2741
2886
|
|
|
2742
2887
|
// src/ui/HatSprite.tsx
|
|
2743
|
-
import { useEffect as useEffect3, useState as
|
|
2744
|
-
import { Box as
|
|
2745
|
-
import { jsx as
|
|
2888
|
+
import { useEffect as useEffect3, useState as useState7 } from "react";
|
|
2889
|
+
import { Box as Box10, Text as Text10 } from "ink";
|
|
2890
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
2746
2891
|
function HatSprite({ hat, variant, centerIn }) {
|
|
2747
2892
|
const colors = hatColorsFor2(hat, variant ?? 0);
|
|
2748
2893
|
const grid = makeHatGrid(hat, colors, centerIn);
|
|
2749
2894
|
const lines = hexGridToHalfBlocks(grid);
|
|
2750
|
-
return /* @__PURE__ */
|
|
2895
|
+
return /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", children: lines.map((line, i) => /* @__PURE__ */ jsx10(Text10, { children: line }, i)) });
|
|
2751
2896
|
}
|
|
2752
2897
|
function AnimatedHatSprite({ hat, variant, centerIn }) {
|
|
2753
2898
|
if (hat.rarity !== "legendary") {
|
|
2754
|
-
return /* @__PURE__ */
|
|
2899
|
+
return /* @__PURE__ */ jsx10(HatSprite, { hat, variant, centerIn });
|
|
2755
2900
|
}
|
|
2756
2901
|
const frames = hat.animation.frames;
|
|
2757
2902
|
const fps = hat.animation.fps;
|
|
2758
|
-
const [idx, setIdx] =
|
|
2903
|
+
const [idx, setIdx] = useState7(0);
|
|
2759
2904
|
useEffect3(() => {
|
|
2760
2905
|
if (frames.length <= 1) return;
|
|
2761
2906
|
const interval = setInterval(
|
|
@@ -2765,7 +2910,7 @@ function AnimatedHatSprite({ hat, variant, centerIn }) {
|
|
|
2765
2910
|
return () => clearInterval(interval);
|
|
2766
2911
|
}, [frames.length, fps]);
|
|
2767
2912
|
const framed = { ...hat, colors: { ...hat.colors, A: frames[idx] } };
|
|
2768
|
-
return /* @__PURE__ */
|
|
2913
|
+
return /* @__PURE__ */ jsx10(HatSprite, { hat: framed, variant, centerIn });
|
|
2769
2914
|
}
|
|
2770
2915
|
function hatColorsFor2(hat, variantIdx) {
|
|
2771
2916
|
if (hat.rarity === "legendary") return hat.colors;
|
|
@@ -2792,7 +2937,7 @@ function makeHatGrid(hat, colors, centerIn) {
|
|
|
2792
2937
|
}
|
|
2793
2938
|
|
|
2794
2939
|
// src/ui/RollReveal.tsx
|
|
2795
|
-
import { jsx as
|
|
2940
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
2796
2941
|
var RESET3 = "\x1B[0m";
|
|
2797
2942
|
var BOX_COLOR = "#E5C76B";
|
|
2798
2943
|
var TIER_PALETTE = {
|
|
@@ -2861,7 +3006,7 @@ var BOX_EMPTY = [
|
|
|
2861
3006
|
""
|
|
2862
3007
|
].map(pad);
|
|
2863
3008
|
function GiftBox({ frame, color }) {
|
|
2864
|
-
return /* @__PURE__ */
|
|
3009
|
+
return /* @__PURE__ */ jsx11(Box11, { flexDirection: "column", children: frame.map((line, i) => /* @__PURE__ */ jsx11(Text11, { children: line ? ansiFg(color) + line + RESET3 : line }, i)) });
|
|
2865
3010
|
}
|
|
2866
3011
|
function spawnParticles(tier, count, cx, cy) {
|
|
2867
3012
|
const palette = TIER_PALETTE[tier];
|
|
@@ -2884,7 +3029,7 @@ function ConfettiBurst({ tier }) {
|
|
|
2884
3029
|
const cx = Math.floor(SCENE_W / 2);
|
|
2885
3030
|
const cy = Math.floor(SCENE_H / 2);
|
|
2886
3031
|
const particles = useMemo(() => spawnParticles(tier, 36, cx, cy), [tier, cx, cy]);
|
|
2887
|
-
const [tick, setTick] =
|
|
3032
|
+
const [tick, setTick] = useState8(0);
|
|
2888
3033
|
useEffect4(() => {
|
|
2889
3034
|
const i = setInterval(() => setTick((t) => t + 1), 70);
|
|
2890
3035
|
return () => clearInterval(i);
|
|
@@ -2897,13 +3042,13 @@ function ConfettiBurst({ tier }) {
|
|
|
2897
3042
|
grid[y][x] = ansiFg(p.color) + p.char + RESET3;
|
|
2898
3043
|
}
|
|
2899
3044
|
}
|
|
2900
|
-
return /* @__PURE__ */
|
|
3045
|
+
return /* @__PURE__ */ jsx11(Box11, { flexDirection: "column", children: grid.map((row, y) => /* @__PURE__ */ jsx11(Text11, { children: row.join("") }, y)) });
|
|
2901
3046
|
}
|
|
2902
3047
|
var CLOSED_HOLD_MS = 3e3;
|
|
2903
3048
|
function RollReveal({ outcome, onDone }) {
|
|
2904
3049
|
const isNoHat = outcome.kind === "no_hat";
|
|
2905
3050
|
const isLegendary = outcome.kind !== "no_hat" && outcome.hat.rarity === "legendary";
|
|
2906
|
-
const [phase, setPhase] =
|
|
3051
|
+
const [phase, setPhase] = useState8("closed");
|
|
2907
3052
|
useEffect4(() => {
|
|
2908
3053
|
const timers = [];
|
|
2909
3054
|
timers.push(setTimeout(() => setPhase("open1"), CLOSED_HOLD_MS));
|
|
@@ -2918,95 +3063,18 @@ function RollReveal({ outcome, onDone }) {
|
|
|
2918
3063
|
}
|
|
2919
3064
|
return () => timers.forEach(clearTimeout);
|
|
2920
3065
|
}, [isNoHat, isLegendary, onDone]);
|
|
2921
|
-
if (phase === "closed") return /* @__PURE__ */
|
|
2922
|
-
if (phase === "open1") return /* @__PURE__ */
|
|
2923
|
-
if (phase === "open2") return /* @__PURE__ */
|
|
2924
|
-
if (phase === "empty") return /* @__PURE__ */
|
|
3066
|
+
if (phase === "closed") return /* @__PURE__ */ jsx11(GiftBox, { frame: BOX_CLOSED, color: BOX_COLOR });
|
|
3067
|
+
if (phase === "open1") return /* @__PURE__ */ jsx11(GiftBox, { frame: BOX_OPENING_1, color: BOX_COLOR });
|
|
3068
|
+
if (phase === "open2") return /* @__PURE__ */ jsx11(GiftBox, { frame: BOX_OPENING_2, color: BOX_COLOR });
|
|
3069
|
+
if (phase === "empty") return /* @__PURE__ */ jsx11(GiftBox, { frame: BOX_EMPTY, color: BOX_COLOR });
|
|
2925
3070
|
if (phase === "burst" && outcome.kind !== "no_hat") {
|
|
2926
|
-
return /* @__PURE__ */
|
|
3071
|
+
return /* @__PURE__ */ jsx11(ConfettiBurst, { tier: outcome.hat.rarity });
|
|
2927
3072
|
}
|
|
2928
|
-
if (outcome.kind === "no_hat") return /* @__PURE__ */
|
|
2929
|
-
return outcome.hat.rarity === "legendary" ? /* @__PURE__ */
|
|
2930
|
-
}
|
|
2931
|
-
|
|
2932
|
-
// src/ui/RollHorsePicker.tsx
|
|
2933
|
-
import { useState as useState8 } from "react";
|
|
2934
|
-
import { Box as Box11, Text as Text11, useInput as useInput4 } from "ink";
|
|
2935
|
-
import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2936
|
-
function RollHorsePicker({ horses, onPick, onCancel }) {
|
|
2937
|
-
const [idx, setIdx] = useState8(0);
|
|
2938
|
-
useInput4((input, key) => {
|
|
2939
|
-
if (key.escape) {
|
|
2940
|
-
onCancel();
|
|
2941
|
-
return;
|
|
2942
|
-
}
|
|
2943
|
-
if (horses.length === 0) return;
|
|
2944
|
-
if (key.upArrow) {
|
|
2945
|
-
setIdx((idx - 1 + horses.length) % horses.length);
|
|
2946
|
-
return;
|
|
2947
|
-
}
|
|
2948
|
-
if (key.downArrow) {
|
|
2949
|
-
setIdx((idx + 1) % horses.length);
|
|
2950
|
-
return;
|
|
2951
|
-
}
|
|
2952
|
-
if (key.return) {
|
|
2953
|
-
onPick(horses[idx]);
|
|
2954
|
-
return;
|
|
2955
|
-
}
|
|
2956
|
-
});
|
|
2957
|
-
return /* @__PURE__ */ jsxs7(Box11, { flexDirection: "column", children: [
|
|
2958
|
-
/* @__PURE__ */ jsx11(Text11, { children: "Pick a horse to roll for:" }),
|
|
2959
|
-
horses.map((h, i) => /* @__PURE__ */ jsxs7(Box11, { flexDirection: "column", children: [
|
|
2960
|
-
/* @__PURE__ */ jsx11(Box11, { flexDirection: "row", children: /* @__PURE__ */ jsxs7(Text11, { children: [
|
|
2961
|
-
i === idx ? "\u25BA" : " ",
|
|
2962
|
-
" ",
|
|
2963
|
-
h.name,
|
|
2964
|
-
" ",
|
|
2965
|
-
/* @__PURE__ */ jsxs7(Text11, { color: "cyan", children: [
|
|
2966
|
-
"[Lvl. ",
|
|
2967
|
-
levelFromXp(h.xp),
|
|
2968
|
-
"]"
|
|
2969
|
-
] }),
|
|
2970
|
-
" ",
|
|
2971
|
-
/* @__PURE__ */ jsxs7(Text11, { color: "yellow", children: [
|
|
2972
|
-
"\u2014 ",
|
|
2973
|
-
h.pending,
|
|
2974
|
-
" roll",
|
|
2975
|
-
h.pending === 1 ? "" : "s"
|
|
2976
|
-
] })
|
|
2977
|
-
] }) }),
|
|
2978
|
-
/* @__PURE__ */ jsxs7(Box11, { flexDirection: "row", children: [
|
|
2979
|
-
/* @__PURE__ */ jsx11(Text11, { children: " " }),
|
|
2980
|
-
/* @__PURE__ */ jsx11(HorseSprite, { sprite: MINI_SPRITE, colors: h.colors })
|
|
2981
|
-
] })
|
|
2982
|
-
] }, h.stable_horse_id)),
|
|
2983
|
-
/* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "\u2191/\u2193 choose \xB7 Enter pick \xB7 Esc cancel" }) })
|
|
2984
|
-
] });
|
|
3073
|
+
if (outcome.kind === "no_hat") return /* @__PURE__ */ jsx11(GiftBox, { frame: BOX_EMPTY, color: BOX_COLOR });
|
|
3074
|
+
return outcome.hat.rarity === "legendary" ? /* @__PURE__ */ jsx11(AnimatedHatSprite, { hat: outcome.hat, centerIn: { w: SCENE_W, h: SCENE_H } }) : /* @__PURE__ */ jsx11(HatSprite, { hat: outcome.hat, variant: outcome.variant, centerIn: { w: SCENE_W, h: SCENE_H } });
|
|
2985
3075
|
}
|
|
2986
3076
|
|
|
2987
|
-
// src/
|
|
2988
|
-
function pendingFor(horse) {
|
|
2989
|
-
const level = levelFromXp(horse.xp);
|
|
2990
|
-
const lastRolled = horse.last_rolled_level ?? Math.max(1, level - 1);
|
|
2991
|
-
return level - lastRolled;
|
|
2992
|
-
}
|
|
2993
|
-
async function promptYesNo(question) {
|
|
2994
|
-
resetStdinAfterInk();
|
|
2995
|
-
const readline6 = await import("readline/promises");
|
|
2996
|
-
const rl = readline6.createInterface({ input: process.stdin, output: process.stdout });
|
|
2997
|
-
const a = (await rl.question(question)).trim().toLowerCase();
|
|
2998
|
-
rl.close();
|
|
2999
|
-
return a === "" || a === "y" || a === "yes";
|
|
3000
|
-
}
|
|
3001
|
-
function resetStdinAfterInk() {
|
|
3002
|
-
if (process.stdin.isTTY && typeof process.stdin.setRawMode === "function") {
|
|
3003
|
-
process.stdin.setRawMode(false);
|
|
3004
|
-
}
|
|
3005
|
-
while (process.stdin.read() !== null) {
|
|
3006
|
-
}
|
|
3007
|
-
process.stdin.pause();
|
|
3008
|
-
process.stdin.ref();
|
|
3009
|
-
}
|
|
3077
|
+
// src/ui/reveal.ts
|
|
3010
3078
|
async function runReveal(outcome) {
|
|
3011
3079
|
await new Promise((resolve) => {
|
|
3012
3080
|
const app = render5(React13.createElement(RollReveal, {
|
|
@@ -3018,6 +3086,13 @@ async function runReveal(outcome) {
|
|
|
3018
3086
|
}));
|
|
3019
3087
|
});
|
|
3020
3088
|
}
|
|
3089
|
+
|
|
3090
|
+
// src/commands/roll.ts
|
|
3091
|
+
function pendingFor(horse) {
|
|
3092
|
+
const level = levelFromXp(horse.xp);
|
|
3093
|
+
const lastRolled = horse.last_rolled_level ?? Math.max(1, level - 1);
|
|
3094
|
+
return level - lastRolled;
|
|
3095
|
+
}
|
|
3021
3096
|
async function rollCommand() {
|
|
3022
3097
|
let stable;
|
|
3023
3098
|
try {
|
|
@@ -3035,7 +3110,7 @@ async function rollCommand() {
|
|
|
3035
3110
|
return 0;
|
|
3036
3111
|
}
|
|
3037
3112
|
const picked = await new Promise((resolve) => {
|
|
3038
|
-
const app =
|
|
3113
|
+
const app = render6(React14.createElement(RollHorsePicker, {
|
|
3039
3114
|
horses: eligible,
|
|
3040
3115
|
onPick: (h) => {
|
|
3041
3116
|
app.unmount();
|
|
@@ -3117,6 +3192,105 @@ No hat this time. +${result.xp_awarded} XP toward your next level.
|
|
|
3117
3192
|
}
|
|
3118
3193
|
}
|
|
3119
3194
|
|
|
3195
|
+
// src/commands/claim.ts
|
|
3196
|
+
import React15 from "react";
|
|
3197
|
+
import { render as render7 } from "ink";
|
|
3198
|
+
async function claimCommand(token) {
|
|
3199
|
+
if (!token) {
|
|
3200
|
+
console.error("Usage: token-derby claim <token>");
|
|
3201
|
+
return 2;
|
|
3202
|
+
}
|
|
3203
|
+
try {
|
|
3204
|
+
await probeClaim(token);
|
|
3205
|
+
} catch (e) {
|
|
3206
|
+
if (e instanceof ApiError) {
|
|
3207
|
+
console.error(`Error: ${e.code} ${e.message}`);
|
|
3208
|
+
return 1;
|
|
3209
|
+
}
|
|
3210
|
+
throw e;
|
|
3211
|
+
}
|
|
3212
|
+
let stable;
|
|
3213
|
+
try {
|
|
3214
|
+
stable = await listStable();
|
|
3215
|
+
} catch (e) {
|
|
3216
|
+
if (e instanceof ApiError) {
|
|
3217
|
+
console.error(`Error: ${e.code} ${e.message}`);
|
|
3218
|
+
return 1;
|
|
3219
|
+
}
|
|
3220
|
+
throw e;
|
|
3221
|
+
}
|
|
3222
|
+
if (stable.horses.length === 0) {
|
|
3223
|
+
console.error("No horses in your stable. Run `token-derby stable create` first.");
|
|
3224
|
+
return 1;
|
|
3225
|
+
}
|
|
3226
|
+
console.log("\n\u{1F381} A cosmetic has been awarded to you.\n");
|
|
3227
|
+
const picked = await new Promise((resolve) => {
|
|
3228
|
+
const app = render7(React15.createElement(HorsePicker, {
|
|
3229
|
+
horses: stable.horses,
|
|
3230
|
+
prompt: "Which horse should receive it?",
|
|
3231
|
+
onPick: (h) => {
|
|
3232
|
+
app.unmount();
|
|
3233
|
+
resolve(h);
|
|
3234
|
+
},
|
|
3235
|
+
onCancel: () => {
|
|
3236
|
+
app.unmount();
|
|
3237
|
+
resolve(null);
|
|
3238
|
+
}
|
|
3239
|
+
}));
|
|
3240
|
+
});
|
|
3241
|
+
if (!picked) {
|
|
3242
|
+
console.log("Cancelled. Your token is unspent.");
|
|
3243
|
+
return 0;
|
|
3244
|
+
}
|
|
3245
|
+
let result;
|
|
3246
|
+
try {
|
|
3247
|
+
result = await redeemClaim(token, { stable_horse_id: picked.stable_horse_id });
|
|
3248
|
+
} catch (e) {
|
|
3249
|
+
if (e instanceof ApiError) {
|
|
3250
|
+
console.error(`Error: ${e.code} ${e.message}`);
|
|
3251
|
+
return 1;
|
|
3252
|
+
}
|
|
3253
|
+
throw e;
|
|
3254
|
+
}
|
|
3255
|
+
const outcome = (() => {
|
|
3256
|
+
if (result.result === "hat") {
|
|
3257
|
+
const hat3 = hatById(result.collected.id);
|
|
3258
|
+
return hat3 ? { kind: "hat", hat: hat3, variant: result.collected.variant } : null;
|
|
3259
|
+
}
|
|
3260
|
+
const hat2 = hatById(result.hat_id);
|
|
3261
|
+
return hat2 ? { kind: "duplicate", hat: hat2, variant: result.variant } : null;
|
|
3262
|
+
})();
|
|
3263
|
+
if (!outcome) {
|
|
3264
|
+
console.error("Server returned an unknown hat id \u2014 catalog mismatch.");
|
|
3265
|
+
return 1;
|
|
3266
|
+
}
|
|
3267
|
+
await runReveal(outcome);
|
|
3268
|
+
if (result.result === "hat") {
|
|
3269
|
+
const hat2 = hatById(result.collected.id);
|
|
3270
|
+
const variantSuffix2 = hat2.rarity !== "legendary" && result.collected.variant !== void 0 ? ` #${result.collected.variant + 1}` : "";
|
|
3271
|
+
console.log(`
|
|
3272
|
+
\u2728 ${hat2.name}${variantSuffix2} [${hat2.rarity.toUpperCase()}]
|
|
3273
|
+
`);
|
|
3274
|
+
if (await promptYesNo("Equip now? [Y/n] ")) {
|
|
3275
|
+
try {
|
|
3276
|
+
await equipHat(picked.stable_horse_id, { hat_index: result.hat_index });
|
|
3277
|
+
console.log(`Equipped on ${picked.name}.`);
|
|
3278
|
+
} catch (e) {
|
|
3279
|
+
if (e instanceof ApiError) {
|
|
3280
|
+
console.error(`Equip failed: ${e.code} ${e.message}`);
|
|
3281
|
+
} else throw e;
|
|
3282
|
+
}
|
|
3283
|
+
}
|
|
3284
|
+
return 0;
|
|
3285
|
+
}
|
|
3286
|
+
const hat = hatById(result.hat_id);
|
|
3287
|
+
const variantSuffix = result.variant !== void 0 ? ` #${result.variant + 1}` : "";
|
|
3288
|
+
console.log(`
|
|
3289
|
+
${picked.name} already has ${hat?.name ?? result.hat_id}${variantSuffix}. +${result.xp_awarded} XP.
|
|
3290
|
+
`);
|
|
3291
|
+
return 0;
|
|
3292
|
+
}
|
|
3293
|
+
|
|
3120
3294
|
// src/commands/org-join.ts
|
|
3121
3295
|
async function orgJoinCommand(token) {
|
|
3122
3296
|
if (!token) {
|
|
@@ -3242,6 +3416,8 @@ Races:
|
|
|
3242
3416
|
Cosmetics:
|
|
3243
3417
|
token-derby roll Spend a pending roll to try for a hat.
|
|
3244
3418
|
Earn rolls by leveling up horses.
|
|
3419
|
+
token-derby claim <token> Redeem a claim token for a cosmetic
|
|
3420
|
+
awarded to you by an admin.
|
|
3245
3421
|
|
|
3246
3422
|
Environment:
|
|
3247
3423
|
token-derby env Show the active environment (prod|staging)
|
|
@@ -3297,6 +3473,7 @@ async function main() {
|
|
|
3297
3473
|
if (cmd === "join") return joinCommand(argv[1], argv.slice(2));
|
|
3298
3474
|
if (cmd === "end") return endCommand(argv[1]);
|
|
3299
3475
|
if (cmd === "roll") return rollCommand();
|
|
3476
|
+
if (cmd === "claim") return claimCommand(argv[1]);
|
|
3300
3477
|
if (cmd === "web") return webCommand();
|
|
3301
3478
|
console.error(`Unknown command: ${cmd}`);
|
|
3302
3479
|
console.error(HELP);
|