jaml-ui 0.14.4 → 0.17.0
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/DESIGN.md +9 -11
- package/dist/assets.d.ts +7 -0
- package/dist/assets.js +11 -0
- package/dist/components/AnalyzerExplorer.d.ts +4 -1
- package/dist/components/AnalyzerExplorer.js +14 -48
- package/dist/components/GameCard.js +8 -7
- package/dist/components/JamlAestheticSelector.d.ts +4 -0
- package/dist/components/JamlAestheticSelector.js +6 -19
- package/dist/components/JamlAnalyzerFullscreen.d.ts +7 -1
- package/dist/components/JamlAnalyzerFullscreen.js +18 -47
- package/dist/components/JamlIde.js +12 -24
- package/dist/components/JamlIdeVisual.js +3 -56
- package/dist/components/JamlMapPreview.d.ts +6 -1
- package/dist/components/JamlMapPreview.js +99 -21
- package/dist/components/JamlSeedInput.d.ts +5 -0
- package/dist/components/JamlSeedInput.js +11 -14
- package/dist/components/MotelyVersionBadge.d.ts +1 -3
- package/dist/components/MotelyVersionBadge.js +4 -16
- package/dist/components/jamlMap/JamlMapEditorDemo.d.ts +8 -0
- package/dist/components/jamlMap/JamlMapEditorDemo.js +170 -0
- package/dist/components/jamlMap/JokerPicker.d.ts +7 -0
- package/dist/components/jamlMap/JokerPicker.js +258 -0
- package/dist/components/jamlMap/MysterySlot.d.ts +32 -0
- package/dist/components/jamlMap/MysterySlot.js +109 -0
- package/dist/components/jamlMap/index.d.ts +3 -0
- package/dist/components/jamlMap/index.js +3 -0
- package/dist/core.d.ts +0 -2
- package/dist/core.js +0 -2
- package/dist/decode/motelyItemDecoder.d.ts +10 -23
- package/dist/decode/motelyItemDecoder.js +103 -248
- package/dist/decode/motelySprite.d.ts +19 -0
- package/dist/decode/motelySprite.js +84 -0
- package/dist/hooks/analyzerStreamRegistry.js +30 -82
- package/dist/hooks/useAnalyzer.d.ts +10 -3
- package/dist/hooks/useAnalyzer.js +11 -6
- package/dist/hooks/useIntersectionObserver.d.ts +14 -0
- package/dist/hooks/useIntersectionObserver.js +50 -0
- package/dist/index.d.ts +3 -8
- package/dist/index.js +2 -7
- package/dist/motely.d.ts +2 -1
- package/dist/motely.js +2 -1
- package/dist/motelyDisplay.d.ts +4 -623
- package/dist/motelyDisplay.js +26 -165
- package/dist/r3f/Card3D.d.ts +2 -2
- package/dist/r3f/Card3D.js +13 -46
- package/dist/r3f/JimboBillboard.d.ts +10 -0
- package/dist/r3f/JimboBillboard.js +29 -0
- package/dist/r3f/JimboText3D.d.ts +9 -0
- package/dist/r3f/JimboText3D.js +8 -0
- package/dist/r3f.d.ts +2 -0
- package/dist/r3f.js +2 -0
- package/dist/render/CanvasRenderer.js +7 -171
- package/dist/sprites/spriteData.d.ts +1 -0
- package/dist/sprites/spriteData.js +1 -0
- package/dist/sprites/spriteMapper.d.ts +78 -1
- package/dist/sprites/spriteMapper.js +52 -0
- package/dist/ui/JimboBadge.d.ts +13 -0
- package/dist/ui/JimboBadge.js +8 -0
- package/dist/ui/JimboFloating.d.ts +8 -0
- package/dist/ui/JimboFloating.js +17 -0
- package/dist/ui/JimboToggleList.d.ts +11 -0
- package/dist/ui/JimboToggleList.js +5 -0
- package/dist/ui/codeBlock.js +2 -3
- package/dist/ui/footer.d.ts +4 -0
- package/dist/ui/footer.js +6 -4
- package/dist/ui/hooks.d.ts +89 -0
- package/dist/ui/hooks.js +551 -0
- package/dist/ui/jimboBackground.js +2 -131
- package/dist/ui/jimboCopyRow.d.ts +4 -0
- package/dist/ui/jimboCopyRow.js +5 -22
- package/dist/ui/jimboFilterBar.d.ts +1 -4
- package/dist/ui/jimboFilterBar.js +2 -61
- package/dist/ui/jimboFlankNav.d.ts +1 -2
- package/dist/ui/jimboFlankNav.js +5 -30
- package/dist/ui/jimboTabs.d.ts +1 -5
- package/dist/ui/jimboTabs.js +6 -41
- package/dist/ui/jimboText.d.ts +1 -1
- package/dist/ui/jimboText.js +15 -32
- package/dist/ui/jimboTooltip.d.ts +1 -12
- package/dist/ui/jimboTooltip.js +6 -82
- package/dist/ui/panel.d.ts +3 -1
- package/dist/ui/panel.js +11 -47
- package/dist/ui/showcase.d.ts +4 -0
- package/dist/ui/showcase.js +9 -36
- package/dist/ui/sprites.d.ts +14 -0
- package/dist/ui/sprites.js +54 -13
- package/dist/ui.d.ts +4 -0
- package/dist/ui.js +5 -0
- package/package.json +130 -122
- package/dist/components/JamlSpeedometer.d.ts +0 -11
- package/dist/components/JamlSpeedometer.js +0 -54
- package/dist/decode/packedBalatroItem.d.ts +0 -13
- package/dist/decode/packedBalatroItem.js +0 -26
- package/dist/hooks/loadMotelyWasm.d.ts +0 -7
- package/dist/hooks/loadMotelyWasm.js +0 -16
- package/dist/utils/itemUtils.d.ts +0 -11
- package/dist/utils/itemUtils.js +0 -71
|
@@ -1,290 +1,145 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Motely item decoder.
|
|
3
|
-
*
|
|
4
|
-
* MotelyItem.Value is a packed integer. The MotelyItemType enum
|
|
5
|
-
* uses packed integers where the top nibble encodes category:
|
|
6
|
-
* 0x1000 = Standardcard, 0x2000 = Spectral, 0x3000 = Tarot,
|
|
7
|
-
* 0x4000 = Planet, 0x5000 = Joker, 0xF000 = Invalid
|
|
2
|
+
* Motely item decoder — thin wrapper over motely-wasm runtime enums.
|
|
3
|
+
* No hand-rolled bitmask tables. The WASM enum IS the source of truth.
|
|
8
4
|
*/
|
|
9
5
|
import { Motely } from "motely-wasm";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
6
|
+
// ─── Helpers using motely-wasm runtime enums directly ────────────────────────
|
|
7
|
+
function enumKey(e, value) {
|
|
8
|
+
const k = e[String(value)];
|
|
9
|
+
return typeof k === "string" ? k : null;
|
|
10
|
+
}
|
|
11
|
+
function spaceSplit(value) {
|
|
12
|
+
return value.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2");
|
|
13
|
+
}
|
|
14
|
+
const CATEGORY_MAP = {
|
|
15
|
+
[Motely.MotelyItemTypeCategory.Standardcard]: "playing",
|
|
16
|
+
[Motely.MotelyItemTypeCategory.SpectralCard]: "spectral",
|
|
17
|
+
[Motely.MotelyItemTypeCategory.TarotCard]: "tarot",
|
|
18
|
+
[Motely.MotelyItemTypeCategory.PlanetCard]: "planet",
|
|
19
|
+
[Motely.MotelyItemTypeCategory.Joker]: "joker",
|
|
23
20
|
};
|
|
24
|
-
// ───
|
|
25
|
-
const _itemTypeToName = new Map();
|
|
26
|
-
function ensureItemTypeMap() {
|
|
27
|
-
if (_itemTypeToName.size > 0)
|
|
28
|
-
return;
|
|
29
|
-
const e = Motely.MotelyItemType;
|
|
30
|
-
for (const [key, val] of Object.entries(e)) {
|
|
31
|
-
if (typeof val === "number" && typeof key === "string" && !/^\d+$/.test(key)) {
|
|
32
|
-
_itemTypeToName.set(val, key);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
function asRuntimeItem(input) {
|
|
37
|
-
return input !== null && typeof input === "object" ? input : null;
|
|
38
|
-
}
|
|
39
|
-
function finiteNumber(value) {
|
|
40
|
-
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
41
|
-
}
|
|
42
|
-
function runtimeEnumName(enumObject, value) {
|
|
43
|
-
if (value === null || !enumObject || typeof enumObject !== "object")
|
|
44
|
-
return null;
|
|
45
|
-
const enumKey = enumObject[String(value)];
|
|
46
|
-
return typeof enumKey === "string" && enumKey.length > 0 ? enumKey : null;
|
|
47
|
-
}
|
|
48
|
-
function parseStandardcardEnumKey(enumKey) {
|
|
49
|
-
const match = /^([CDHS])(10|[2-9JQKA])$/.exec(enumKey);
|
|
50
|
-
if (!match)
|
|
51
|
-
return null;
|
|
52
|
-
const suitMap = {
|
|
53
|
-
C: "Clubs",
|
|
54
|
-
D: "Diamonds",
|
|
55
|
-
H: "Hearts",
|
|
56
|
-
S: "Spades",
|
|
57
|
-
};
|
|
58
|
-
const rankMap = {
|
|
59
|
-
J: "Jack",
|
|
60
|
-
Q: "Queen",
|
|
61
|
-
K: "King",
|
|
62
|
-
A: "Ace",
|
|
63
|
-
};
|
|
64
|
-
return {
|
|
65
|
-
rank: rankMap[match[2]] ?? match[2],
|
|
66
|
-
suit: suitMap[match[1]],
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
function rankNameFromEnum(enumKey) {
|
|
70
|
-
if (!enumKey)
|
|
71
|
-
return null;
|
|
72
|
-
const rankMap = {
|
|
73
|
-
Two: "2",
|
|
74
|
-
Three: "3",
|
|
75
|
-
Four: "4",
|
|
76
|
-
Five: "5",
|
|
77
|
-
Six: "6",
|
|
78
|
-
Seven: "7",
|
|
79
|
-
Eight: "8",
|
|
80
|
-
Nine: "9",
|
|
81
|
-
Ten: "10",
|
|
82
|
-
Jack: "Jack",
|
|
83
|
-
Queen: "Queen",
|
|
84
|
-
King: "King",
|
|
85
|
-
Ace: "Ace",
|
|
86
|
-
};
|
|
87
|
-
return rankMap[enumKey] ?? null;
|
|
88
|
-
}
|
|
21
|
+
// ─── Core decoder ────────────────────────────────────────────────────────────
|
|
89
22
|
function resolvePackedValue(input) {
|
|
23
|
+
if (input == null)
|
|
24
|
+
return null;
|
|
90
25
|
if (typeof input === "number")
|
|
91
26
|
return Number.isFinite(input) ? input : null;
|
|
92
|
-
|
|
93
|
-
return finiteNumber(runtimeItem?.value);
|
|
27
|
+
return input.value ?? input.type ?? null;
|
|
94
28
|
}
|
|
95
|
-
function
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
if (direct !== null)
|
|
99
|
-
return direct;
|
|
100
|
-
const packedValue = resolvePackedValue(input);
|
|
101
|
-
return packedValue !== null ? packedValue & VALUE_EDITION_MASK : null;
|
|
102
|
-
}
|
|
103
|
-
function resolveSealValue(input) {
|
|
104
|
-
const runtimeItem = asRuntimeItem(input);
|
|
105
|
-
const direct = finiteNumber(runtimeItem?.seal);
|
|
106
|
-
if (direct !== null)
|
|
107
|
-
return direct;
|
|
108
|
-
const packedValue = resolvePackedValue(input);
|
|
109
|
-
return packedValue !== null ? packedValue & VALUE_SEAL_MASK : null;
|
|
29
|
+
export function resolveMotelyItemType(input) {
|
|
30
|
+
const val = resolvePackedValue(input);
|
|
31
|
+
return val !== null ? val & 0xffff : null;
|
|
110
32
|
}
|
|
111
|
-
function
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const packedValue = resolvePackedValue(input);
|
|
117
|
-
return packedValue !== null ? packedValue & VALUE_ENHANCEMENT_MASK : null;
|
|
33
|
+
export function motelyItemTypeName(input) {
|
|
34
|
+
const itemType = resolveMotelyItemType(input);
|
|
35
|
+
if (itemType === null)
|
|
36
|
+
return "Unknown";
|
|
37
|
+
return enumKey(Motely.MotelyItemType, itemType) ?? `item#${itemType}`;
|
|
118
38
|
}
|
|
119
|
-
export function
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
const runtimeItem = asRuntimeItem(input);
|
|
123
|
-
const directType = finiteNumber(runtimeItem?.type);
|
|
124
|
-
if (directType !== null)
|
|
125
|
-
return directType & VALUE_TYPE_MASK;
|
|
126
|
-
const packedValue = finiteNumber(runtimeItem?.value);
|
|
127
|
-
return packedValue !== null ? packedValue & VALUE_TYPE_MASK : null;
|
|
39
|
+
export function motelyItemCategory(itemType) {
|
|
40
|
+
const catValue = (itemType >> 12) & 0xf;
|
|
41
|
+
return CATEGORY_MAP[catValue] ?? "unknown";
|
|
128
42
|
}
|
|
129
43
|
export function motelyItemRenderCategory(input) {
|
|
130
|
-
const
|
|
131
|
-
|
|
44
|
+
const itemType = resolveMotelyItemType(input);
|
|
45
|
+
if (itemType === null)
|
|
46
|
+
return "unknown";
|
|
47
|
+
return motelyItemCategory(itemType);
|
|
48
|
+
}
|
|
49
|
+
export function motelyItemDisplayName(input) {
|
|
50
|
+
return spaceSplit(motelyItemTypeName(input));
|
|
132
51
|
}
|
|
133
52
|
export function motelyItemEditionName(input) {
|
|
134
|
-
|
|
135
|
-
|
|
53
|
+
if (input == null)
|
|
54
|
+
return null;
|
|
55
|
+
const val = typeof input === "number" ? input : input.edition;
|
|
56
|
+
if (val == null)
|
|
57
|
+
return null;
|
|
58
|
+
const key = enumKey(Motely.MotelyItemEdition, typeof val === "number" ? val : 0);
|
|
59
|
+
if (!key || key === "None")
|
|
60
|
+
return null;
|
|
61
|
+
return key;
|
|
136
62
|
}
|
|
137
63
|
export function motelyItemSealName(input) {
|
|
138
|
-
|
|
139
|
-
|
|
64
|
+
if (input == null)
|
|
65
|
+
return null;
|
|
66
|
+
const val = typeof input === "number" ? null : input.seal;
|
|
67
|
+
if (val == null)
|
|
68
|
+
return null;
|
|
69
|
+
const key = enumKey(Motely.MotelyItemSeal, val);
|
|
70
|
+
if (!key || key === "None")
|
|
71
|
+
return null;
|
|
72
|
+
return key;
|
|
140
73
|
}
|
|
141
74
|
export function motelyItemEnhancementName(input) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
const
|
|
148
|
-
if (
|
|
149
|
-
return
|
|
150
|
-
|
|
151
|
-
const parsed = parseStandardcardEnumKey(motelyItemTypeName(input));
|
|
152
|
-
return parsed?.suit ?? null;
|
|
75
|
+
if (input == null)
|
|
76
|
+
return null;
|
|
77
|
+
const val = typeof input === "number" ? null : input.enhancement;
|
|
78
|
+
if (val == null)
|
|
79
|
+
return null;
|
|
80
|
+
const key = enumKey(Motely.MotelyItemEnhancement, val);
|
|
81
|
+
if (!key || key === "None")
|
|
82
|
+
return null;
|
|
83
|
+
return key;
|
|
153
84
|
}
|
|
154
85
|
export function motelyStandardcardRankName(input) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
const
|
|
158
|
-
if (
|
|
159
|
-
return
|
|
160
|
-
|
|
161
|
-
return parsed?.rank ?? null;
|
|
162
|
-
}
|
|
163
|
-
/** Get the enum key name for a MotelyItemType value. */
|
|
164
|
-
export function motelyItemTypeName(input) {
|
|
165
|
-
const itemType = resolveMotelyItemType(input);
|
|
166
|
-
if (itemType === null)
|
|
167
|
-
return "Unknown";
|
|
168
|
-
ensureItemTypeMap();
|
|
169
|
-
return _itemTypeToName.get(itemType) ?? "Unknown";
|
|
86
|
+
if (input == null)
|
|
87
|
+
return null;
|
|
88
|
+
const val = typeof input === "number" ? null : input.rank;
|
|
89
|
+
if (val == null)
|
|
90
|
+
return null;
|
|
91
|
+
return enumKey(Motely.MotelyStandardcardRank, val);
|
|
170
92
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
return "Standard card";
|
|
179
|
-
if (renderCategory === "spectral")
|
|
180
|
-
return "Spectral";
|
|
181
|
-
if (renderCategory === "tarot")
|
|
182
|
-
return "Tarot";
|
|
183
|
-
if (renderCategory === "planet")
|
|
184
|
-
return "Planet";
|
|
185
|
-
if (renderCategory === "joker")
|
|
186
|
-
return "Joker";
|
|
187
|
-
return CATEGORY_TO_TYPE[itemType & CATEGORY_MASK] ?? "Unknown";
|
|
93
|
+
export function motelyStandardcardSuitName(input) {
|
|
94
|
+
if (input == null)
|
|
95
|
+
return null;
|
|
96
|
+
const val = typeof input === "number" ? null : input.suit;
|
|
97
|
+
if (val == null)
|
|
98
|
+
return null;
|
|
99
|
+
return enumKey(Motely.MotelyStandardcardSuit, val);
|
|
188
100
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const enumKey = motelyItemTypeName(input);
|
|
192
|
-
return enumKey === "Unknown" ? "Unknown" : getItemDisplayName(enumKey);
|
|
101
|
+
export function decodeMotelyItemName(input) {
|
|
102
|
+
return motelyItemTypeName(input);
|
|
193
103
|
}
|
|
194
|
-
// ─── Module-level cache ──────────────────────────────────────────────────────
|
|
195
|
-
const _cache = new Map();
|
|
196
|
-
const _decodedBaseCache = new Map();
|
|
197
104
|
export function decodeMotelyItem(input) {
|
|
198
105
|
const itemType = resolveMotelyItemType(input);
|
|
199
106
|
if (itemType === null)
|
|
200
107
|
return null;
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
const rank = motelyStandardcardRankName(itemType);
|
|
210
|
-
const suit = motelyStandardcardSuitName(itemType);
|
|
211
|
-
base = {
|
|
212
|
-
itemType,
|
|
213
|
-
enumKey,
|
|
214
|
-
displayName: category === "playing" && rank && suit ? `${rank} of ${suit}` : getItemDisplayName(enumKey),
|
|
215
|
-
category,
|
|
216
|
-
rank,
|
|
217
|
-
suit,
|
|
218
|
-
};
|
|
219
|
-
_decodedBaseCache.set(itemType, base);
|
|
220
|
-
}
|
|
221
|
-
if (!base)
|
|
222
|
-
return null;
|
|
223
|
-
const decoded = {
|
|
224
|
-
...base,
|
|
108
|
+
const enumKeyStr = enumKey(Motely.MotelyItemType, itemType) ?? `Unknown_${itemType}`;
|
|
109
|
+
const category = motelyItemCategory(itemType);
|
|
110
|
+
const displayName = spaceSplit(enumKeyStr);
|
|
111
|
+
return {
|
|
112
|
+
itemType,
|
|
113
|
+
enumKey: enumKeyStr,
|
|
114
|
+
displayName,
|
|
115
|
+
category,
|
|
225
116
|
edition: motelyItemEditionName(input),
|
|
226
117
|
seal: motelyItemSealName(input),
|
|
227
118
|
enhancement: motelyItemEnhancementName(input),
|
|
119
|
+
rank: motelyStandardcardRankName(input),
|
|
120
|
+
suit: motelyStandardcardSuitName(input),
|
|
228
121
|
};
|
|
229
|
-
return decoded;
|
|
230
122
|
}
|
|
231
|
-
export function decodeMotelyItemToJamlCard(input, scale
|
|
123
|
+
export function decodeMotelyItemToJamlCard(input, scale) {
|
|
232
124
|
const decoded = decodeMotelyItem(input);
|
|
233
|
-
if (!decoded
|
|
125
|
+
if (!decoded)
|
|
234
126
|
return null;
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
return {
|
|
239
|
-
type: "playing",
|
|
240
|
-
card: {
|
|
241
|
-
name: `${decoded.rank} of ${decoded.suit}`,
|
|
242
|
-
edition: decoded.edition ?? undefined,
|
|
243
|
-
seal: decoded.seal ? `${decoded.seal} Seal` : undefined,
|
|
244
|
-
enhancements: decoded.enhancement ? [decoded.enhancement] : undefined,
|
|
245
|
-
rank: decoded.rank,
|
|
246
|
-
suit: decoded.suit,
|
|
247
|
-
scale,
|
|
248
|
-
},
|
|
249
|
-
};
|
|
250
|
-
}
|
|
127
|
+
const type = decoded.category === "joker" ? "joker"
|
|
128
|
+
: decoded.category === "playing" ? "playing"
|
|
129
|
+
: "consumable";
|
|
251
130
|
return {
|
|
252
|
-
type
|
|
131
|
+
type,
|
|
253
132
|
card: {
|
|
254
133
|
name: decoded.displayName,
|
|
255
134
|
edition: decoded.edition ?? undefined,
|
|
135
|
+
seal: decoded.seal ?? undefined,
|
|
136
|
+
enhancements: decoded.enhancement ? [decoded.enhancement] : undefined,
|
|
137
|
+
rank: decoded.rank ?? undefined,
|
|
138
|
+
suit: decoded.suit ?? undefined,
|
|
256
139
|
scale,
|
|
257
140
|
},
|
|
258
141
|
};
|
|
259
142
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
*/
|
|
264
|
-
export function decodeMotelyItemName(input) {
|
|
265
|
-
const itemType = resolveMotelyItemType(input);
|
|
266
|
-
if (itemType === null)
|
|
267
|
-
return null;
|
|
268
|
-
if (_cache.has(itemType))
|
|
269
|
-
return _cache.get(itemType) ?? null;
|
|
270
|
-
const category = motelyItemCategory(itemType);
|
|
271
|
-
if (category === "Unknown") {
|
|
272
|
-
_cache.set(itemType, null);
|
|
273
|
-
return null;
|
|
274
|
-
}
|
|
275
|
-
const decoded = decodeMotelyItem(input);
|
|
276
|
-
const name = decoded?.displayName ?? motelyItemDisplayName(itemType);
|
|
277
|
-
_cache.set(itemType, name);
|
|
278
|
-
return name;
|
|
279
|
-
}
|
|
280
|
-
/** Warm the cache for a batch of item type values. */
|
|
281
|
-
export function warmMotelyItemCache(itemTypes) {
|
|
282
|
-
for (const t of itemTypes) {
|
|
283
|
-
decodeMotelyItemName(t);
|
|
284
|
-
decodeMotelyItem(t);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
/** Number of unique items decoded so far. */
|
|
288
|
-
export function motelyItemCacheSize() {
|
|
289
|
-
return _cache.size;
|
|
290
|
-
}
|
|
143
|
+
// Cache warming is now a no-op since we use runtime enums directly
|
|
144
|
+
export function warmMotelyItemCache() { }
|
|
145
|
+
export function motelyItemCacheSize() { return 0; }
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type MotelyRenderableCategory } from "./motelyItemDecoder.js";
|
|
2
|
+
export interface MotelySpriteData {
|
|
3
|
+
atlasPath: string;
|
|
4
|
+
gridCol: number;
|
|
5
|
+
gridRow: number;
|
|
6
|
+
gridCols: number;
|
|
7
|
+
gridRows: number;
|
|
8
|
+
displayName: string;
|
|
9
|
+
category: MotelyRenderableCategory;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Given a raw motely-wasm item value (which may be a bitpacked integer or raw MotelyItemType),
|
|
13
|
+
* resolves it to a sprite atlas path and grid coordinates for rendering.
|
|
14
|
+
*/
|
|
15
|
+
export declare function motelyItemToSprite(rawValue: number): MotelySpriteData | null;
|
|
16
|
+
/**
|
|
17
|
+
* Resolves a sprite by name and category without needing a Motely integer.
|
|
18
|
+
*/
|
|
19
|
+
export declare function getMotelySpriteByName(name: string, category?: MotelyRenderableCategory): MotelySpriteData | null;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { decodeMotelyItem } from "./motelyItemDecoder.js";
|
|
2
|
+
import { getSpriteData, SHEET_META } from "../sprites/spriteMapper.js";
|
|
3
|
+
import { RANK_MAP, SUIT_MAP } from "../sprites/spriteData.js";
|
|
4
|
+
import { resolveJamlAssetUrl } from "../assets.js";
|
|
5
|
+
/**
|
|
6
|
+
* Given a raw motely-wasm item value (which may be a bitpacked integer or raw MotelyItemType),
|
|
7
|
+
* resolves it to a sprite atlas path and grid coordinates for rendering.
|
|
8
|
+
*/
|
|
9
|
+
export function motelyItemToSprite(rawValue) {
|
|
10
|
+
const decoded = decodeMotelyItem(rawValue);
|
|
11
|
+
if (!decoded)
|
|
12
|
+
return null;
|
|
13
|
+
if (decoded.category === "playing" && decoded.rank && decoded.suit) {
|
|
14
|
+
const col = RANK_MAP[decoded.rank];
|
|
15
|
+
const row = SUIT_MAP[decoded.suit];
|
|
16
|
+
if (col !== undefined && row !== undefined) {
|
|
17
|
+
return {
|
|
18
|
+
atlasPath: resolveJamlAssetUrl('deck'),
|
|
19
|
+
gridCol: col,
|
|
20
|
+
gridRow: row,
|
|
21
|
+
gridCols: 13,
|
|
22
|
+
gridRows: 4,
|
|
23
|
+
displayName: decoded.displayName,
|
|
24
|
+
category: "playing"
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const sprite = getSpriteData(decoded.displayName);
|
|
29
|
+
if (!sprite)
|
|
30
|
+
return null;
|
|
31
|
+
const meta = SHEET_META[sprite.type];
|
|
32
|
+
if (!meta)
|
|
33
|
+
return null;
|
|
34
|
+
return {
|
|
35
|
+
atlasPath: resolveJamlAssetUrl(meta.assetKey),
|
|
36
|
+
gridCol: sprite.pos.x,
|
|
37
|
+
gridRow: sprite.pos.y,
|
|
38
|
+
gridCols: meta.cols,
|
|
39
|
+
gridRows: meta.rows,
|
|
40
|
+
displayName: decoded.displayName,
|
|
41
|
+
category: decoded.category
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Resolves a sprite by name and category without needing a Motely integer.
|
|
46
|
+
*/
|
|
47
|
+
export function getMotelySpriteByName(name, category = "unknown") {
|
|
48
|
+
if (category === "playing") {
|
|
49
|
+
// Attempt to parse "Rank of Suit"
|
|
50
|
+
const match = /^(.*?)\s+of\s+(.*?)$/i.exec(name);
|
|
51
|
+
if (match) {
|
|
52
|
+
const rank = match[1];
|
|
53
|
+
const suit = match[2];
|
|
54
|
+
const col = RANK_MAP[rank];
|
|
55
|
+
const row = SUIT_MAP[suit];
|
|
56
|
+
if (col !== undefined && row !== undefined) {
|
|
57
|
+
return {
|
|
58
|
+
atlasPath: resolveJamlAssetUrl('deck'),
|
|
59
|
+
gridCol: col,
|
|
60
|
+
gridRow: row,
|
|
61
|
+
gridCols: 13,
|
|
62
|
+
gridRows: 4,
|
|
63
|
+
displayName: name,
|
|
64
|
+
category: "playing"
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const sprite = getSpriteData(name);
|
|
70
|
+
if (!sprite)
|
|
71
|
+
return null;
|
|
72
|
+
const meta = SHEET_META[sprite.type];
|
|
73
|
+
if (!meta)
|
|
74
|
+
return null;
|
|
75
|
+
return {
|
|
76
|
+
atlasPath: resolveJamlAssetUrl(meta.assetKey),
|
|
77
|
+
gridCol: sprite.pos.x,
|
|
78
|
+
gridRow: sprite.pos.y,
|
|
79
|
+
gridCols: meta.cols,
|
|
80
|
+
gridRows: meta.rows,
|
|
81
|
+
displayName: name,
|
|
82
|
+
category
|
|
83
|
+
};
|
|
84
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
2
|
import { motelyItemDisplayNameFromValue } from "../motelyDisplay.js";
|
|
4
3
|
export const ANALYZER_STREAM_META = {
|
|
5
4
|
shop: { key: "shop", label: "Shop", tone: "default", defaultEnabled: true },
|
|
@@ -28,120 +27,69 @@ export function buildStreamHandle(live, ante, key) {
|
|
|
28
27
|
const ctx = live.ctx;
|
|
29
28
|
const Motely = live.Motely;
|
|
30
29
|
const runState = live.runStates[ante];
|
|
31
|
-
let stream = null;
|
|
32
30
|
let cursor = 0;
|
|
33
31
|
const idBase = `${ante}-${key}`;
|
|
34
32
|
function nameFromValue(value) {
|
|
35
33
|
return motelyItemDisplayNameFromValue(value);
|
|
36
34
|
}
|
|
37
|
-
function
|
|
35
|
+
function streamHandle(createStream, getNextValue) {
|
|
36
|
+
let stream = null;
|
|
38
37
|
return {
|
|
39
38
|
initStream: () => {
|
|
40
|
-
stream =
|
|
39
|
+
stream = createStream();
|
|
41
40
|
cursor = 0;
|
|
42
41
|
},
|
|
43
42
|
nextItem: () => {
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
if (stream === null)
|
|
44
|
+
throw new Error(`Analyzer stream ${key} was read before initialization.`);
|
|
45
|
+
const value = getNextValue(stream);
|
|
46
46
|
const id = `${idBase}-${cursor++}`;
|
|
47
47
|
return { id, name: nameFromValue(value), value };
|
|
48
48
|
},
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
|
-
function
|
|
52
|
-
return
|
|
53
|
-
initStream: () => {
|
|
54
|
-
stream = ctx[streamFactoryName](ante, Motely.MotelyJokerFixedRarityStreamFlags.Default);
|
|
55
|
-
cursor = 0;
|
|
56
|
-
},
|
|
57
|
-
nextItem: () => {
|
|
58
|
-
const r = ctx[nextName](stream);
|
|
59
|
-
const value = r.joker?.value ?? 0;
|
|
60
|
-
const id = `${idBase}-${cursor++}`;
|
|
61
|
-
return { id, name: nameFromValue(value), value };
|
|
62
|
-
},
|
|
63
|
-
};
|
|
51
|
+
function joker(createStream, getNext) {
|
|
52
|
+
return streamHandle(createStream, (stream) => getNext(stream).item.value);
|
|
64
53
|
}
|
|
65
|
-
function
|
|
66
|
-
return
|
|
67
|
-
initStream: () => {
|
|
68
|
-
stream = ctx[streamFactoryName](ante);
|
|
69
|
-
cursor = 0;
|
|
70
|
-
},
|
|
71
|
-
nextItem: () => {
|
|
72
|
-
const r = ctx[nextName](stream);
|
|
73
|
-
const value = r.tarot?.value ?? r.item?.value ?? 0;
|
|
74
|
-
const id = `${idBase}-${cursor++}`;
|
|
75
|
-
return { id, name: nameFromValue(value), value };
|
|
76
|
-
},
|
|
77
|
-
};
|
|
54
|
+
function fixedRarityJoker(createStream, getNext) {
|
|
55
|
+
return streamHandle(createStream, (stream) => getNext(stream).item.value);
|
|
78
56
|
}
|
|
79
|
-
function
|
|
80
|
-
return
|
|
81
|
-
initStream: () => {
|
|
82
|
-
stream = ctx[streamFactoryName](ante);
|
|
83
|
-
cursor = 0;
|
|
84
|
-
},
|
|
85
|
-
nextItem: () => {
|
|
86
|
-
const r = ctx[nextName](stream);
|
|
87
|
-
const value = r.planet?.value ?? 0;
|
|
88
|
-
const id = `${idBase}-${cursor++}`;
|
|
89
|
-
return { id, name: nameFromValue(value), value };
|
|
90
|
-
},
|
|
91
|
-
};
|
|
57
|
+
function tarot(createStream, getNext) {
|
|
58
|
+
return streamHandle(createStream, (stream) => getNext(stream).item.value);
|
|
92
59
|
}
|
|
93
|
-
function
|
|
94
|
-
return
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
},
|
|
99
|
-
nextItem: () => {
|
|
100
|
-
const r = ctx[nextName](stream);
|
|
101
|
-
const value = r.spectral?.value ?? 0;
|
|
102
|
-
const id = `${idBase}-${cursor++}`;
|
|
103
|
-
return { id, name: nameFromValue(value), value };
|
|
104
|
-
},
|
|
105
|
-
};
|
|
60
|
+
function planet(createStream, getNext) {
|
|
61
|
+
return streamHandle(createStream, (stream) => getNext(stream).item.value);
|
|
62
|
+
}
|
|
63
|
+
function spectral(createStream, getNext) {
|
|
64
|
+
return streamHandle(createStream, (stream) => getNext(stream).item.value);
|
|
106
65
|
}
|
|
107
66
|
switch (key) {
|
|
108
67
|
case "shop":
|
|
109
|
-
return
|
|
110
|
-
initStream: () => {
|
|
111
|
-
stream = ctx.createShopItemStream(ante, runState, Motely.MotelyShopStreamFlags.Default, Motely.MotelyJokerStreamFlags.Default);
|
|
112
|
-
cursor = 0;
|
|
113
|
-
},
|
|
114
|
-
nextItem: () => {
|
|
115
|
-
const r = ctx.getNextShopItem(stream);
|
|
116
|
-
const value = r.item.value;
|
|
117
|
-
const id = `${idBase}-${cursor++}`;
|
|
118
|
-
return { id, name: nameFromValue(value), value };
|
|
119
|
-
},
|
|
120
|
-
};
|
|
68
|
+
return streamHandle(() => ctx.createShopItemStream(ante, runState, Motely.MotelyShopStreamFlags.Default, Motely.MotelyJokerStreamFlags.Default), (stream) => ctx.getNextShopItem(stream).item.value);
|
|
121
69
|
case "shopJoker":
|
|
122
|
-
return joker(
|
|
70
|
+
return joker(() => ctx.createShopJokerStream(ante, Motely.MotelyJokerStreamFlags.Default), (stream) => ctx.getNextShopJoker(stream));
|
|
123
71
|
case "soulJoker":
|
|
124
|
-
return fixedRarityJoker(
|
|
72
|
+
return fixedRarityJoker(() => ctx.createSoulJokerStream(ante, Motely.MotelyJokerFixedRarityStreamFlags.Default), (stream) => ctx.getNextSoulJoker(stream));
|
|
125
73
|
case "rareTagJoker":
|
|
126
|
-
return fixedRarityJoker(
|
|
74
|
+
return fixedRarityJoker(() => ctx.createRareTagJokerStream(ante, Motely.MotelyJokerFixedRarityStreamFlags.Default), (stream) => ctx.getNextRareTagJoker(stream));
|
|
127
75
|
case "uncommonTagJoker":
|
|
128
|
-
return fixedRarityJoker(
|
|
76
|
+
return fixedRarityJoker(() => ctx.createUncommonTagJokerStream(ante, Motely.MotelyJokerFixedRarityStreamFlags.Default), (stream) => ctx.getNextUncommonTagJoker(stream));
|
|
129
77
|
case "riffRaffJoker":
|
|
130
|
-
return fixedRarityJoker(
|
|
78
|
+
return fixedRarityJoker(() => ctx.createRiffRaffJokerStream(ante, Motely.MotelyJokerFixedRarityStreamFlags.Default), (stream) => ctx.getNextRiffRaffJoker(stream));
|
|
131
79
|
case "buffoonJoker":
|
|
132
|
-
return joker(
|
|
80
|
+
return joker(() => ctx.createBuffoonPackJokerStream(ante, Motely.MotelyJokerStreamFlags.Default), (stream) => ctx.getNextBuffoonPackJoker(stream));
|
|
133
81
|
case "judgementJoker":
|
|
134
|
-
return joker(
|
|
82
|
+
return joker(() => ctx.createJudgementJokerStream(ante, Motely.MotelyJokerStreamFlags.Default), (stream) => ctx.getNextJudgementJoker(stream));
|
|
135
83
|
case "wraithJoker":
|
|
136
|
-
return joker(
|
|
84
|
+
return joker(() => ctx.createWraithJokerStream(ante, Motely.MotelyJokerStreamFlags.Default), (stream) => ctx.getNextWraithJoker(stream));
|
|
137
85
|
case "shopTarot":
|
|
138
|
-
return tarot(
|
|
86
|
+
return tarot(() => ctx.createShopTarotStream(ante), (stream) => ctx.getNextShopTarot(stream));
|
|
139
87
|
case "shopPlanet":
|
|
140
|
-
return planet(
|
|
88
|
+
return planet(() => ctx.createShopPlanetStream(ante), (stream) => ctx.getNextShopPlanet(stream));
|
|
141
89
|
case "shopSpectral":
|
|
142
|
-
return spectral(
|
|
90
|
+
return spectral(() => ctx.createShopSpectralStream(ante), (stream) => ctx.getNextShopSpectral(stream));
|
|
143
91
|
case "purpleSealTarot":
|
|
144
|
-
return tarot(
|
|
92
|
+
return tarot(() => ctx.createPurpleSealTarotStream(ante), (stream) => ctx.getNextPurpleSealTarot(stream));
|
|
145
93
|
default:
|
|
146
94
|
return null;
|
|
147
95
|
}
|