jaml-ui 0.16.0 → 0.17.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/DESIGN.md +9 -11
- package/dist/assets.d.ts +6 -0
- package/dist/assets.js +9 -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/JamlSpeedometer.d.ts +8 -8
- package/dist/components/JamlSpeedometer.js +24 -46
- 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 -272
- package/dist/decode/motelySprite.d.ts +4 -0
- package/dist/decode/motelySprite.js +57 -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 +5 -8
- package/dist/index.js +4 -7
- package/dist/motely.d.ts +2 -2
- package/dist/motely.js +2 -2
- 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 -48
- package/dist/r3f/JimboText3D.js +3 -2
- package/dist/render/CanvasRenderer.js +7 -171
- package/dist/sprites/spriteMapper.d.ts +71 -0
- package/dist/sprites/spriteMapper.js +40 -0
- package/dist/ui/JimboBadge.d.ts +8 -2
- package/dist/ui/JimboBadge.js +6 -22
- package/dist/ui/JimboToggleList.js +2 -7
- 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 +2 -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.js +3 -2
- package/dist/ui.d.ts +1 -0
- package/dist/ui.js +2 -0
- package/package.json +7 -6
- 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,314 +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
|
-
const MOTELY_ITEM_TYPES_STANDARD = [
|
|
27
|
-
"TwoOfClubs", "ThreeOfClubs", "FourOfClubs", "FiveOfClubs", "SixOfClubs", "SevenOfClubs", "EightOfClubs", "NineOfClubs", "TenOfClubs", "JackOfClubs", "QueenOfClubs", "KingOfClubs", "AceOfClubs",
|
|
28
|
-
"TwoOfDiamonds", "ThreeOfDiamonds", "FourOfDiamonds", "FiveOfDiamonds", "SixOfDiamonds", "SevenOfDiamonds", "EightOfDiamonds", "NineOfDiamonds", "TenOfDiamonds", "JackOfDiamonds", "QueenOfDiamonds", "KingOfDiamonds", "AceOfDiamonds",
|
|
29
|
-
"TwoOfHearts", "ThreeOfHearts", "FourOfHearts", "FiveOfHearts", "SixOfHearts", "SevenOfHearts", "EightOfHearts", "NineOfHearts", "TenOfHearts", "JackOfHearts", "QueenOfHearts", "KingOfHearts", "AceOfHearts",
|
|
30
|
-
"TwoOfSpades", "ThreeOfSpades", "FourOfSpades", "FiveOfSpades", "SixOfSpades", "SevenOfSpades", "EightOfSpades", "NineOfSpades", "TenOfSpades", "JackOfSpades", "QueenOfSpades", "KingOfSpades", "AceOfSpades"
|
|
31
|
-
];
|
|
32
|
-
const MOTELY_ITEM_TYPES_SPECTRAL = ["Familiar", "Grim", "Incantation", "Talisman", "Aura", "Wraith", "Sigil", "Ouija", "Ectoplasm", "Immolate", "Ankh", "DejaVu", "Hex", "Trance", "Medium", "Cryptid", "TheSoul", "BlackHole"];
|
|
33
|
-
const MOTELY_ITEM_TYPES_TAROT = ["TheFool", "TheMagician", "TheHighPriestess", "TheEmpress", "TheEmperor", "TheHierophant", "TheLovers", "TheChariot", "Justice", "TheHermit", "TheWheelOfFortune", "Strength", "TheHangedMan", "Death", "Temperance", "TheDevil", "TheTower", "TheStar", "TheMoon", "TheSun", "Judgement", "TheWorld"];
|
|
34
|
-
const MOTELY_ITEM_TYPES_PLANET = ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", "Pluto", "PlanetX", "Ceres", "Eris"];
|
|
35
|
-
const MOTELY_ITEM_TYPES_JOKER = ["Joker", "GreedyJoker", "LustyJoker", "WrathfulJoker", "GluttonousJoker", "JollyJoker", "ZanyJoker", "MadJoker", "CrazyJoker", "DrollJoker", "SlyJoker", "WilyJoker", "CleverJoker", "DeviousJoker", "CraftyJoker", "HalfJoker", "CreditCard", "Banner", "MysticSummit", "EightBall", "Misprint", "RaisedFist", "ChaostheClown", "ScaryFace", "AbstractJoker", "DelayedGratification", "GrosMichel", "EvenSteven", "OddTodd", "Scholar", "BusinessCard", "Supernova", "RideTheBus", "Egg", "Runner", "IceCream", "Splash", "BlueJoker", "FacelessJoker", "GreenJoker", "Superposition", "ToDoList", "Cavendish", "RedCard", "SquareJoker", "RiffRaff", "Photograph", "ReservedParking", "MailInRebate", "Hallucination", "FortuneTeller", "Juggler", "Drunkard", "GoldenJoker", "Popcorn", "WalkieTalkie", "SmileyFace", "GoldenTicket", "Swashbuckler", "HangingChad", "ShootTheMoon", "JokerStencil", "FourFingers", "Mime", "CeremonialDagger", "MarbleJoker", "LoyaltyCard", "Dusk", "Fibonacci", "SteelJoker", "Hack", "Pareidolia", "SpaceJoker", "Burglar", "Blackboard", "SixthSense", "Constellation", "Hiker", "CardSharp", "Madness", "Seance", "Vampire", "Shortcut", "Hologram", "Cloud9", "Rocket", "MidasMask", "Luchador", "GiftCard", "TurtleBean", "Erosion", "ToTheMoon", "StoneJoker", "LuckyCat", "Bull", "DietCola", "TradingCard", "FlashCard", "SpareTrousers", "Ramen", "Seltzer", "Castle", "MrBones", "Acrobat", "SockAndBuskin", "Troubadour", "Certificate", "SmearedJoker", "Throwback", "RoughGem", "Bloodstone", "Arrowhead", "OnyxAgate", "GlassJoker", "Showman", "FlowerPot", "MerryAndy", "OopsAll6s", "TheIdol", "SeeingDouble", "Matador", "Satellite", "Cartomancer", "Astronomer", "Bootstraps", "DNA", "Vagabond", "Baron", "Obelisk", "BaseballCard", "AncientJoker", "Campfire", "Blueprint", "WeeJoker", "HitTheRoad", "TheDuo", "TheTrio", "TheFamily", "TheOrder", "TheTribe", "Stuntman", "InvisibleJoker", "Brainstorm", "DriversLicense", "BurntJoker", "Canio", "Triboulet", "Yorick", "Chicot", "Perkeo"];
|
|
36
|
-
const MOTELY_ITEM_TYPES_INVALID = ["Invalid", "NotImplemented", "JokerExcludedByStream", "PlanetExcludedByStream", "TarotExcludedByStream", "SpectralExcludedByStream"];
|
|
37
|
-
function ensureItemTypeMap() {
|
|
38
|
-
if (_itemTypeToName.size > 0)
|
|
39
|
-
return;
|
|
40
|
-
// Fallback to runtime enum if present (motely-wasm < 14)
|
|
41
|
-
const e = Motely.MotelyItemType;
|
|
42
|
-
if (e && Object.keys(e).length > 0) {
|
|
43
|
-
for (const [key, val] of Object.entries(e)) {
|
|
44
|
-
if (typeof val === "number" && typeof key === "string" && !/^\d+$/.test(key)) {
|
|
45
|
-
_itemTypeToName.set(val, key);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
// Populate using hardcoded categories (motely-wasm 14+)
|
|
51
|
-
_itemTypeToName.set(0, "None"); // Handle 0
|
|
52
|
-
MOTELY_ITEM_TYPES_STANDARD.forEach((name, i) => _itemTypeToName.set(0x1000 + i, name));
|
|
53
|
-
MOTELY_ITEM_TYPES_SPECTRAL.forEach((name, i) => _itemTypeToName.set(0x2000 + i, name));
|
|
54
|
-
MOTELY_ITEM_TYPES_TAROT.forEach((name, i) => _itemTypeToName.set(0x3000 + i, name));
|
|
55
|
-
MOTELY_ITEM_TYPES_PLANET.forEach((name, i) => _itemTypeToName.set(0x4000 + i, name));
|
|
56
|
-
MOTELY_ITEM_TYPES_JOKER.forEach((name, i) => _itemTypeToName.set(0x5000 + i, name));
|
|
57
|
-
MOTELY_ITEM_TYPES_INVALID.forEach((name, i) => _itemTypeToName.set(0xf000 + i, name));
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
function asRuntimeItem(input) {
|
|
61
|
-
return input !== null && typeof input === "object" ? input : null;
|
|
62
|
-
}
|
|
63
|
-
function finiteNumber(value) {
|
|
64
|
-
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
65
|
-
}
|
|
66
|
-
function runtimeEnumName(enumObject, value) {
|
|
67
|
-
if (value === null || !enumObject || typeof enumObject !== "object")
|
|
68
|
-
return null;
|
|
69
|
-
const enumKey = enumObject[String(value)];
|
|
70
|
-
return typeof enumKey === "string" && enumKey.length > 0 ? enumKey : null;
|
|
71
|
-
}
|
|
72
|
-
function parseStandardcardEnumKey(enumKey) {
|
|
73
|
-
const match = /^([CDHS])(10|[2-9JQKA])$/.exec(enumKey);
|
|
74
|
-
if (!match)
|
|
75
|
-
return null;
|
|
76
|
-
const suitMap = {
|
|
77
|
-
C: "Clubs",
|
|
78
|
-
D: "Diamonds",
|
|
79
|
-
H: "Hearts",
|
|
80
|
-
S: "Spades",
|
|
81
|
-
};
|
|
82
|
-
const rankMap = {
|
|
83
|
-
J: "Jack",
|
|
84
|
-
Q: "Queen",
|
|
85
|
-
K: "King",
|
|
86
|
-
A: "Ace",
|
|
87
|
-
};
|
|
88
|
-
return {
|
|
89
|
-
rank: rankMap[match[2]] ?? match[2],
|
|
90
|
-
suit: suitMap[match[1]],
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
function rankNameFromEnum(enumKey) {
|
|
94
|
-
if (!enumKey)
|
|
95
|
-
return null;
|
|
96
|
-
const rankMap = {
|
|
97
|
-
Two: "2",
|
|
98
|
-
Three: "3",
|
|
99
|
-
Four: "4",
|
|
100
|
-
Five: "5",
|
|
101
|
-
Six: "6",
|
|
102
|
-
Seven: "7",
|
|
103
|
-
Eight: "8",
|
|
104
|
-
Nine: "9",
|
|
105
|
-
Ten: "10",
|
|
106
|
-
Jack: "Jack",
|
|
107
|
-
Queen: "Queen",
|
|
108
|
-
King: "King",
|
|
109
|
-
Ace: "Ace",
|
|
110
|
-
};
|
|
111
|
-
return rankMap[enumKey] ?? null;
|
|
112
|
-
}
|
|
21
|
+
// ─── Core decoder ────────────────────────────────────────────────────────────
|
|
113
22
|
function resolvePackedValue(input) {
|
|
23
|
+
if (input == null)
|
|
24
|
+
return null;
|
|
114
25
|
if (typeof input === "number")
|
|
115
26
|
return Number.isFinite(input) ? input : null;
|
|
116
|
-
|
|
117
|
-
return finiteNumber(runtimeItem?.value);
|
|
27
|
+
return input.value ?? input.type ?? null;
|
|
118
28
|
}
|
|
119
|
-
function
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
if (direct !== null)
|
|
123
|
-
return direct;
|
|
124
|
-
const packedValue = resolvePackedValue(input);
|
|
125
|
-
return packedValue !== null ? packedValue & VALUE_EDITION_MASK : null;
|
|
126
|
-
}
|
|
127
|
-
function resolveSealValue(input) {
|
|
128
|
-
const runtimeItem = asRuntimeItem(input);
|
|
129
|
-
const direct = finiteNumber(runtimeItem?.seal);
|
|
130
|
-
if (direct !== null)
|
|
131
|
-
return direct;
|
|
132
|
-
const packedValue = resolvePackedValue(input);
|
|
133
|
-
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;
|
|
134
32
|
}
|
|
135
|
-
function
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const packedValue = resolvePackedValue(input);
|
|
141
|
-
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}`;
|
|
142
38
|
}
|
|
143
|
-
export function
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const runtimeItem = asRuntimeItem(input);
|
|
147
|
-
const directType = finiteNumber(runtimeItem?.type);
|
|
148
|
-
if (directType !== null)
|
|
149
|
-
return directType & VALUE_TYPE_MASK;
|
|
150
|
-
const packedValue = finiteNumber(runtimeItem?.value);
|
|
151
|
-
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";
|
|
152
42
|
}
|
|
153
43
|
export function motelyItemRenderCategory(input) {
|
|
154
|
-
const
|
|
155
|
-
|
|
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));
|
|
156
51
|
}
|
|
157
52
|
export function motelyItemEditionName(input) {
|
|
158
|
-
|
|
159
|
-
|
|
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;
|
|
160
62
|
}
|
|
161
63
|
export function motelyItemSealName(input) {
|
|
162
|
-
|
|
163
|
-
|
|
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;
|
|
164
73
|
}
|
|
165
74
|
export function motelyItemEnhancementName(input) {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const
|
|
172
|
-
if (
|
|
173
|
-
return
|
|
174
|
-
|
|
175
|
-
const parsed = parseStandardcardEnumKey(motelyItemTypeName(input));
|
|
176
|
-
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;
|
|
177
84
|
}
|
|
178
85
|
export function motelyStandardcardRankName(input) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const
|
|
182
|
-
if (
|
|
183
|
-
return
|
|
184
|
-
|
|
185
|
-
return parsed?.rank ?? null;
|
|
186
|
-
}
|
|
187
|
-
/** Get the enum key name for a MotelyItemType value. */
|
|
188
|
-
export function motelyItemTypeName(input) {
|
|
189
|
-
const itemType = resolveMotelyItemType(input);
|
|
190
|
-
if (itemType === null)
|
|
191
|
-
return "Unknown";
|
|
192
|
-
ensureItemTypeMap();
|
|
193
|
-
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);
|
|
194
92
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
return "Standard card";
|
|
203
|
-
if (renderCategory === "spectral")
|
|
204
|
-
return "Spectral";
|
|
205
|
-
if (renderCategory === "tarot")
|
|
206
|
-
return "Tarot";
|
|
207
|
-
if (renderCategory === "planet")
|
|
208
|
-
return "Planet";
|
|
209
|
-
if (renderCategory === "joker")
|
|
210
|
-
return "Joker";
|
|
211
|
-
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);
|
|
212
100
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
const enumKey = motelyItemTypeName(input);
|
|
216
|
-
return enumKey === "Unknown" ? "Unknown" : getItemDisplayName(enumKey);
|
|
101
|
+
export function decodeMotelyItemName(input) {
|
|
102
|
+
return motelyItemTypeName(input);
|
|
217
103
|
}
|
|
218
|
-
// ─── Module-level cache ──────────────────────────────────────────────────────
|
|
219
|
-
const _cache = new Map();
|
|
220
|
-
const _decodedBaseCache = new Map();
|
|
221
104
|
export function decodeMotelyItem(input) {
|
|
222
105
|
const itemType = resolveMotelyItemType(input);
|
|
223
106
|
if (itemType === null)
|
|
224
107
|
return null;
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
const rank = motelyStandardcardRankName(itemType);
|
|
234
|
-
const suit = motelyStandardcardSuitName(itemType);
|
|
235
|
-
base = {
|
|
236
|
-
itemType,
|
|
237
|
-
enumKey,
|
|
238
|
-
displayName: category === "playing" && rank && suit ? `${rank} of ${suit}` : getItemDisplayName(enumKey),
|
|
239
|
-
category,
|
|
240
|
-
rank,
|
|
241
|
-
suit,
|
|
242
|
-
};
|
|
243
|
-
_decodedBaseCache.set(itemType, base);
|
|
244
|
-
}
|
|
245
|
-
if (!base)
|
|
246
|
-
return null;
|
|
247
|
-
const decoded = {
|
|
248
|
-
...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,
|
|
249
116
|
edition: motelyItemEditionName(input),
|
|
250
117
|
seal: motelyItemSealName(input),
|
|
251
118
|
enhancement: motelyItemEnhancementName(input),
|
|
119
|
+
rank: motelyStandardcardRankName(input),
|
|
120
|
+
suit: motelyStandardcardSuitName(input),
|
|
252
121
|
};
|
|
253
|
-
return decoded;
|
|
254
122
|
}
|
|
255
|
-
export function decodeMotelyItemToJamlCard(input, scale
|
|
123
|
+
export function decodeMotelyItemToJamlCard(input, scale) {
|
|
256
124
|
const decoded = decodeMotelyItem(input);
|
|
257
|
-
if (!decoded
|
|
125
|
+
if (!decoded)
|
|
258
126
|
return null;
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
return {
|
|
263
|
-
type: "playing",
|
|
264
|
-
card: {
|
|
265
|
-
name: `${decoded.rank} of ${decoded.suit}`,
|
|
266
|
-
edition: decoded.edition ?? undefined,
|
|
267
|
-
seal: decoded.seal ? `${decoded.seal} Seal` : undefined,
|
|
268
|
-
enhancements: decoded.enhancement ? [decoded.enhancement] : undefined,
|
|
269
|
-
rank: decoded.rank,
|
|
270
|
-
suit: decoded.suit,
|
|
271
|
-
scale,
|
|
272
|
-
},
|
|
273
|
-
};
|
|
274
|
-
}
|
|
127
|
+
const type = decoded.category === "joker" ? "joker"
|
|
128
|
+
: decoded.category === "playing" ? "playing"
|
|
129
|
+
: "consumable";
|
|
275
130
|
return {
|
|
276
|
-
type
|
|
131
|
+
type,
|
|
277
132
|
card: {
|
|
278
133
|
name: decoded.displayName,
|
|
279
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,
|
|
280
139
|
scale,
|
|
281
140
|
},
|
|
282
141
|
};
|
|
283
142
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
*/
|
|
288
|
-
export function decodeMotelyItemName(input) {
|
|
289
|
-
const itemType = resolveMotelyItemType(input);
|
|
290
|
-
if (itemType === null)
|
|
291
|
-
return null;
|
|
292
|
-
if (_cache.has(itemType))
|
|
293
|
-
return _cache.get(itemType) ?? null;
|
|
294
|
-
const category = motelyItemCategory(itemType);
|
|
295
|
-
if (category === "Unknown") {
|
|
296
|
-
_cache.set(itemType, null);
|
|
297
|
-
return null;
|
|
298
|
-
}
|
|
299
|
-
const decoded = decodeMotelyItem(input);
|
|
300
|
-
const name = decoded?.displayName ?? motelyItemDisplayName(itemType);
|
|
301
|
-
_cache.set(itemType, name);
|
|
302
|
-
return name;
|
|
303
|
-
}
|
|
304
|
-
/** Warm the cache for a batch of item type values. */
|
|
305
|
-
export function warmMotelyItemCache(itemTypes) {
|
|
306
|
-
for (const t of itemTypes) {
|
|
307
|
-
decodeMotelyItemName(t);
|
|
308
|
-
decodeMotelyItem(t);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
/** Number of unique items decoded so far. */
|
|
312
|
-
export function motelyItemCacheSize() {
|
|
313
|
-
return _cache.size;
|
|
314
|
-
}
|
|
143
|
+
// Cache warming is now a no-op since we use runtime enums directly
|
|
144
|
+
export function warmMotelyItemCache() { }
|
|
145
|
+
export function motelyItemCacheSize() { return 0; }
|
|
@@ -13,3 +13,7 @@ export interface MotelySpriteData {
|
|
|
13
13
|
* resolves it to a sprite atlas path and grid coordinates for rendering.
|
|
14
14
|
*/
|
|
15
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;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { decodeMotelyItem } from "./motelyItemDecoder.js";
|
|
2
2
|
import { getSpriteData, SHEET_META } from "../sprites/spriteMapper.js";
|
|
3
|
+
import { RANK_MAP, SUIT_MAP } from "../sprites/spriteData.js";
|
|
3
4
|
import { resolveJamlAssetUrl } from "../assets.js";
|
|
4
5
|
/**
|
|
5
6
|
* Given a raw motely-wasm item value (which may be a bitpacked integer or raw MotelyItemType),
|
|
@@ -9,6 +10,21 @@ export function motelyItemToSprite(rawValue) {
|
|
|
9
10
|
const decoded = decodeMotelyItem(rawValue);
|
|
10
11
|
if (!decoded)
|
|
11
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
|
+
}
|
|
12
28
|
const sprite = getSpriteData(decoded.displayName);
|
|
13
29
|
if (!sprite)
|
|
14
30
|
return null;
|
|
@@ -25,3 +41,44 @@ export function motelyItemToSprite(rawValue) {
|
|
|
25
41
|
category: decoded.category
|
|
26
42
|
};
|
|
27
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
|
+
}
|