@rpg-engine/long-bow 0.8.203 → 0.8.205
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/dist/components/Item/Inventory/ErrorBoundary.d.ts +2 -0
- package/dist/components/Marketplace/BuyOrderPanel.d.ts +2 -2
- package/dist/components/Marketplace/BuyOrderRows.d.ts +4 -4
- package/dist/components/Marketplace/HistoryPanel.d.ts +2 -2
- package/dist/components/Marketplace/MarketplaceRows.d.ts +2 -0
- package/dist/components/shared/MMORPGNumber.d.ts +6 -0
- package/dist/long-bow.cjs.development.js +465 -34317
- package/dist/long-bow.cjs.development.js.map +1 -1
- package/dist/long-bow.cjs.production.min.js +1 -1
- package/dist/long-bow.cjs.production.min.js.map +1 -1
- package/dist/long-bow.esm.js +466 -34318
- package/dist/long-bow.esm.js.map +1 -1
- package/dist/utils/numberUtils.d.ts +7 -0
- package/package.json +1 -1
- package/src/components/DCWallet/DCWalletContent.tsx +5 -3
- package/src/components/Item/Inventory/ErrorBoundary.tsx +25 -8
- package/src/components/Item/Inventory/ItemPropertyColorSelector.tsx +3 -1
- package/src/components/Marketplace/BuyOrderPanel.tsx +2 -2
- package/src/components/Marketplace/BuyOrderRows.tsx +13 -7
- package/src/components/Marketplace/CharacterDetailModal.tsx +99 -17
- package/src/components/Marketplace/CharacterListingModal.tsx +2 -1
- package/src/components/Marketplace/GroupedRowContainer.tsx +10 -10
- package/src/components/Marketplace/HistoryPanel.tsx +5 -5
- package/src/components/Marketplace/MarketplaceBuyModal.tsx +4 -4
- package/src/components/Marketplace/MarketplaceRows.tsx +13 -7
- package/src/components/Marketplace/__test__/CharacterDetailModal.spec.tsx +137 -0
- package/src/components/Store/CartView.tsx +2 -1
- package/src/components/Store/FeaturedBanner.tsx +1 -0
- package/src/components/Store/PaymentMethodModal.tsx +11 -3
- package/src/components/Store/StoreCharacterSkinRow.tsx +9 -3
- package/src/components/Store/StoreItemDetails.tsx +9 -1
- package/src/components/Store/StoreItemRow.tsx +13 -3
- package/src/components/Store/sections/StorePacksSection.tsx +7 -0
- package/src/components/Store/sections/StoreRedeemSection.tsx +2 -1
- package/src/components/shared/DCRateStrip.tsx +3 -2
- package/src/components/shared/MMORPGNumber.tsx +22 -0
- package/src/stories/Features/marketplace/CharacterDetailModal.stories.tsx +69 -15
- package/src/stories/Features/marketplace/CharacterMarketplace.stories.tsx +105 -11
- package/src/stories/Features/store/Store.stories.tsx +125 -35
- package/src/stories/Features/trading/Marketplace.stories.tsx +8 -4
- package/src/utils/__test__/atlasUtils.spec.ts +15 -0
- package/src/utils/atlasUtils.ts +78 -0
- package/src/utils/numberUtils.ts +31 -0
|
@@ -37,8 +37,24 @@ const mockCharacterListings: ICharacterListing[] = [
|
|
|
37
37
|
mode: 'Hardcore',
|
|
38
38
|
skills: { sword: 10, shield: 8 },
|
|
39
39
|
equipment: [
|
|
40
|
-
{
|
|
41
|
-
|
|
40
|
+
{
|
|
41
|
+
slot: 'rightHand',
|
|
42
|
+
itemName: 'Broad Sword',
|
|
43
|
+
itemKey: 'broad-sword',
|
|
44
|
+
rarity: 'Common',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
slot: 'armor',
|
|
48
|
+
itemName: 'Jacket',
|
|
49
|
+
itemKey: 'jacket',
|
|
50
|
+
rarity: 'Rare',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
slot: 'head',
|
|
54
|
+
itemName: 'Iron Helmet',
|
|
55
|
+
itemKey: 'iron-helmet',
|
|
56
|
+
rarity: 'Uncommon',
|
|
57
|
+
},
|
|
42
58
|
],
|
|
43
59
|
textureKey: 'black-knight',
|
|
44
60
|
},
|
|
@@ -61,7 +77,24 @@ const mockCharacterListings: ICharacterListing[] = [
|
|
|
61
77
|
mode: 'Standard',
|
|
62
78
|
skills: { fireball: 15, frostbolt: 12 },
|
|
63
79
|
equipment: [
|
|
64
|
-
{
|
|
80
|
+
{
|
|
81
|
+
slot: 'rightHand',
|
|
82
|
+
itemName: 'Fire Staff',
|
|
83
|
+
itemKey: 'fire-staff',
|
|
84
|
+
rarity: 'Epic',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
slot: 'armor',
|
|
88
|
+
itemName: 'Mystic Cape',
|
|
89
|
+
itemKey: 'mystic-cape',
|
|
90
|
+
rarity: 'Legendary',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
slot: 'neck',
|
|
94
|
+
itemName: 'Bandana',
|
|
95
|
+
itemKey: 'bandana',
|
|
96
|
+
rarity: 'Rare',
|
|
97
|
+
},
|
|
65
98
|
],
|
|
66
99
|
textureKey: 'pink-mage-1',
|
|
67
100
|
},
|
|
@@ -84,7 +117,18 @@ const mockCharacterListings: ICharacterListing[] = [
|
|
|
84
117
|
mode: 'Hardcore',
|
|
85
118
|
skills: { stealth: 10, backstab: 12 },
|
|
86
119
|
equipment: [
|
|
87
|
-
{
|
|
120
|
+
{
|
|
121
|
+
slot: 'rightHand',
|
|
122
|
+
itemName: 'Dagger',
|
|
123
|
+
itemKey: 'dagger',
|
|
124
|
+
rarity: 'Uncommon',
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
slot: 'neck',
|
|
128
|
+
itemName: 'Bandana',
|
|
129
|
+
itemKey: 'bandana',
|
|
130
|
+
rarity: 'Common',
|
|
131
|
+
},
|
|
88
132
|
],
|
|
89
133
|
textureKey: 'redhair-girl-1',
|
|
90
134
|
},
|
|
@@ -107,8 +151,24 @@ const mockCharacterListings: ICharacterListing[] = [
|
|
|
107
151
|
mode: 'Standard',
|
|
108
152
|
skills: { holy: 20, shield: 15 },
|
|
109
153
|
equipment: [
|
|
110
|
-
{
|
|
111
|
-
|
|
154
|
+
{
|
|
155
|
+
slot: 'rightHand',
|
|
156
|
+
itemName: 'Angelic Sword',
|
|
157
|
+
itemKey: 'angelic-sword',
|
|
158
|
+
rarity: 'Legendary',
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
slot: 'armor',
|
|
162
|
+
itemName: 'Leather Jacket',
|
|
163
|
+
itemKey: 'leather-jacket',
|
|
164
|
+
rarity: 'Epic',
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
slot: 'head',
|
|
168
|
+
itemName: 'Iron Helmet',
|
|
169
|
+
itemKey: 'iron-helmet',
|
|
170
|
+
rarity: 'Rare',
|
|
171
|
+
},
|
|
112
172
|
],
|
|
113
173
|
textureKey: 'dragon-knight',
|
|
114
174
|
},
|
|
@@ -131,7 +191,18 @@ const mockCharacterListings: ICharacterListing[] = [
|
|
|
131
191
|
mode: 'Standard',
|
|
132
192
|
skills: { archery: 12, tracking: 8 },
|
|
133
193
|
equipment: [
|
|
134
|
-
{
|
|
194
|
+
{
|
|
195
|
+
slot: 'rightHand',
|
|
196
|
+
itemName: 'Redwood Longbow',
|
|
197
|
+
itemKey: 'redwood-longbow',
|
|
198
|
+
rarity: 'Rare',
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
slot: 'head',
|
|
202
|
+
itemName: 'Hunters Cap',
|
|
203
|
+
itemKey: 'hunters-cap',
|
|
204
|
+
rarity: 'Uncommon',
|
|
205
|
+
},
|
|
135
206
|
],
|
|
136
207
|
textureKey: 'pink-hair-girl-1',
|
|
137
208
|
},
|
|
@@ -157,7 +228,18 @@ const mockMyCharacterListings: ICharacterListing[] = [
|
|
|
157
228
|
mode: 'Standard',
|
|
158
229
|
skills: { sword: 18, shield: 16 },
|
|
159
230
|
equipment: [
|
|
160
|
-
{
|
|
231
|
+
{
|
|
232
|
+
slot: 'rightHand',
|
|
233
|
+
itemName: 'Knights Sword',
|
|
234
|
+
itemKey: 'knights-sword',
|
|
235
|
+
rarity: 'Epic',
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
slot: 'armor',
|
|
239
|
+
itemName: 'Leather Jacket',
|
|
240
|
+
itemKey: 'leather-jacket',
|
|
241
|
+
rarity: 'Rare',
|
|
242
|
+
},
|
|
161
243
|
],
|
|
162
244
|
textureKey: 'black-knight',
|
|
163
245
|
},
|
|
@@ -180,7 +262,18 @@ const mockMyCharacterListings: ICharacterListing[] = [
|
|
|
180
262
|
mode: 'Standard',
|
|
181
263
|
skills: { fireball: 8 },
|
|
182
264
|
equipment: [
|
|
183
|
-
{
|
|
265
|
+
{
|
|
266
|
+
slot: 'rightHand',
|
|
267
|
+
itemName: 'Wooden Staff',
|
|
268
|
+
itemKey: 'wooden-staff',
|
|
269
|
+
rarity: 'Common',
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
slot: 'neck',
|
|
273
|
+
itemName: 'Bandana',
|
|
274
|
+
itemKey: 'bandana',
|
|
275
|
+
rarity: 'Common',
|
|
276
|
+
},
|
|
184
277
|
],
|
|
185
278
|
textureKey: 'red-mage-1',
|
|
186
279
|
},
|
|
@@ -277,7 +370,7 @@ CharacterBrowseEmpty.storyName = 'Empty State';
|
|
|
277
370
|
export const CharacterBrowseFiltered: Story = () => (
|
|
278
371
|
<RPGUIRoot>
|
|
279
372
|
<CharacterMarketplacePanel
|
|
280
|
-
characterListings={mockCharacterListings.filter(l =>
|
|
373
|
+
characterListings={mockCharacterListings.filter((l) =>
|
|
281
374
|
l.characterSnapshot.name.toLowerCase().includes('warrior')
|
|
282
375
|
)}
|
|
283
376
|
totalCount={2}
|
|
@@ -359,7 +452,8 @@ export const MyCharacterListingsNoEligible: Story = () => (
|
|
|
359
452
|
</RPGUIRoot>
|
|
360
453
|
);
|
|
361
454
|
|
|
362
|
-
MyCharacterListingsNoEligible.storyName =
|
|
455
|
+
MyCharacterListingsNoEligible.storyName =
|
|
456
|
+
'My Listings - No eligible chars to list';
|
|
363
457
|
|
|
364
458
|
export const CharacterListingPending: Story = () => (
|
|
365
459
|
<RPGUIRoot>
|
|
@@ -155,23 +155,99 @@ const characterSkinItems: IProductBlueprint[] = [
|
|
|
155
155
|
}
|
|
156
156
|
];
|
|
157
157
|
|
|
158
|
-
//
|
|
159
|
-
const
|
|
158
|
+
// Showcase items for large number formatting
|
|
159
|
+
const largePriceItems: IProductBlueprint[] = [
|
|
160
|
+
{
|
|
161
|
+
key: 'mega-booster',
|
|
162
|
+
name: 'Mega Booster',
|
|
163
|
+
description: 'A massive boost for high-end players.',
|
|
164
|
+
price: 15.00,
|
|
165
|
+
currency: PaymentCurrency.USD,
|
|
166
|
+
texturePath: 'items/angelic_sword_1.png',
|
|
167
|
+
textureAtlas: 'items',
|
|
168
|
+
textureKey: 'items/angelic_sword_1.png',
|
|
169
|
+
type: PurchaseType.Item,
|
|
170
|
+
dcPrice: 150000, // 150k
|
|
171
|
+
onPurchase: async () => { },
|
|
172
|
+
itemType: ItemType.Other,
|
|
173
|
+
itemSubType: ItemSubType.Other,
|
|
174
|
+
rarity: ItemRarities.Rare,
|
|
175
|
+
weight: 0,
|
|
176
|
+
isStackable: true,
|
|
177
|
+
maxStackSize: 99,
|
|
178
|
+
isUsable: true,
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
key: 'galactic-throne',
|
|
182
|
+
name: 'Galactic Throne',
|
|
183
|
+
description: 'The ultimate symbol of wealth.',
|
|
184
|
+
price: 99.99,
|
|
185
|
+
currency: PaymentCurrency.USD,
|
|
186
|
+
texturePath: 'items/throne.png',
|
|
187
|
+
textureAtlas: 'items',
|
|
188
|
+
textureKey: 'items/throne.png',
|
|
189
|
+
type: PurchaseType.Item,
|
|
190
|
+
dcPrice: 2500000, // 2.5M
|
|
191
|
+
onPurchase: async () => { },
|
|
192
|
+
itemType: ItemType.Other,
|
|
193
|
+
itemSubType: ItemSubType.Other,
|
|
194
|
+
rarity: ItemRarities.Epic,
|
|
195
|
+
weight: 10,
|
|
196
|
+
isStackable: false,
|
|
197
|
+
maxStackSize: 1,
|
|
198
|
+
isUsable: true,
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
key: 'godly-artifact',
|
|
202
|
+
name: 'Godly Artifact',
|
|
203
|
+
description: 'Relic from ancient times.',
|
|
204
|
+
price: 1000.00,
|
|
205
|
+
currency: PaymentCurrency.USD,
|
|
206
|
+
texturePath: 'items/staff_1.png',
|
|
207
|
+
textureAtlas: 'items',
|
|
208
|
+
textureKey: 'items/staff_1.png',
|
|
209
|
+
type: PurchaseType.Item,
|
|
210
|
+
dcPrice: 1600000000, // 1.6B
|
|
211
|
+
onPurchase: async () => { },
|
|
212
|
+
itemType: ItemType.Other,
|
|
213
|
+
itemSubType: ItemSubType.Other,
|
|
214
|
+
rarity: ItemRarities.Legendary,
|
|
215
|
+
weight: 0,
|
|
216
|
+
isStackable: false,
|
|
217
|
+
maxStackSize: 1,
|
|
218
|
+
isUsable: true,
|
|
219
|
+
}
|
|
220
|
+
];
|
|
221
|
+
|
|
222
|
+
// Create Social Crystal item
|
|
223
|
+
const socialCrystalItem: IProductBlueprint = {
|
|
224
|
+
key: 'social-crystal',
|
|
225
|
+
name: 'Social Crystal',
|
|
226
|
+
description: 'A mysterious crystal that resonates with social energy. Use it to unlock community rewards!',
|
|
227
|
+
price: 4.99,
|
|
228
|
+
currency: PaymentCurrency.USD,
|
|
229
|
+
texturePath: 'books/soul-crystal.png',
|
|
230
|
+
textureAtlas: 'items',
|
|
231
|
+
textureKey: 'books/soul-crystal.png',
|
|
232
|
+
type: PurchaseType.Item,
|
|
233
|
+
dcPrice: 250,
|
|
234
|
+
onPurchase: async () => { },
|
|
235
|
+
itemType: ItemType.Other,
|
|
236
|
+
itemSubType: ItemSubType.Other,
|
|
237
|
+
rarity: ItemRarities.Rare,
|
|
238
|
+
weight: 0,
|
|
239
|
+
isStackable: true,
|
|
240
|
+
maxStackSize: 99,
|
|
241
|
+
isUsable: true,
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
// Cleaned up items list without "junk" duplicates
|
|
245
|
+
const allStoreItems: IProductBlueprint[] = [
|
|
160
246
|
...storeItems,
|
|
161
247
|
characterNameChangeItem,
|
|
162
248
|
...characterSkinItems,
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
key: `copy1-${item.key}-${index}`,
|
|
166
|
-
})),
|
|
167
|
-
...storeItems.map((item, index) => ({
|
|
168
|
-
...item,
|
|
169
|
-
key: `copy2-${item.key}-${index}`,
|
|
170
|
-
})),
|
|
171
|
-
...storeItems.map((item, index) => ({
|
|
172
|
-
...item,
|
|
173
|
-
key: `copy3-${item.key}-${index}`,
|
|
174
|
-
})),
|
|
249
|
+
socialCrystalItem,
|
|
250
|
+
...largePriceItems,
|
|
175
251
|
];
|
|
176
252
|
|
|
177
253
|
// Mock packs data
|
|
@@ -227,7 +303,7 @@ const mockPacks: IItemPack[] = [
|
|
|
227
303
|
export const Default: Story = {
|
|
228
304
|
render: () => (
|
|
229
305
|
<Store
|
|
230
|
-
items={
|
|
306
|
+
items={allStoreItems}
|
|
231
307
|
packs={mockPacks}
|
|
232
308
|
userAccountType={UserAccountTypes.Free}
|
|
233
309
|
onPurchase={(purchase: Partial<IPurchase>) => {
|
|
@@ -235,7 +311,7 @@ export const Default: Story = {
|
|
|
235
311
|
return Promise.resolve(true);
|
|
236
312
|
}}
|
|
237
313
|
customWalletContent={<DCWalletContent
|
|
238
|
-
dcBalance={
|
|
314
|
+
dcBalance={150000000} // 150M
|
|
239
315
|
historyData={{ transactions: [], totalPages: 1, currentPage: 1 }}
|
|
240
316
|
historyLoading={false}
|
|
241
317
|
onRequestHistory={() => {}}
|
|
@@ -274,7 +350,9 @@ export const Default: Story = {
|
|
|
274
350
|
'original-greater-life-potion-0': { originalPrice: 15.00 },
|
|
275
351
|
'character-name-change': { originalPrice: 15.00 },
|
|
276
352
|
'skin-character-customization': { originalPrice: 20.00 },
|
|
277
|
-
'starter-pack': { originalPrice: 9.99 }
|
|
353
|
+
'starter-pack': { originalPrice: 9.99 },
|
|
354
|
+
'mega-booster': { originalPrice: 200000 },
|
|
355
|
+
'godly-artifact': { originalPrice: 2500000000 }
|
|
278
356
|
}}
|
|
279
357
|
/>
|
|
280
358
|
),
|
|
@@ -284,7 +362,7 @@ export const Default: Story = {
|
|
|
284
362
|
export const BRL: Story = {
|
|
285
363
|
render: () => (
|
|
286
364
|
<Store
|
|
287
|
-
items={
|
|
365
|
+
items={allStoreItems}
|
|
288
366
|
packs={mockPacks}
|
|
289
367
|
userAccountType={UserAccountTypes.Free}
|
|
290
368
|
onPurchase={(purchase: Partial<IPurchase>) => {
|
|
@@ -292,7 +370,7 @@ export const BRL: Story = {
|
|
|
292
370
|
return Promise.resolve(true);
|
|
293
371
|
}}
|
|
294
372
|
customWalletContent={<DCWalletContent
|
|
295
|
-
dcBalance={
|
|
373
|
+
dcBalance={150000000} // 150M
|
|
296
374
|
historyData={{ transactions: [], totalPages: 1, currentPage: 1 }}
|
|
297
375
|
historyLoading={false}
|
|
298
376
|
onRequestHistory={() => {}}
|
|
@@ -331,7 +409,9 @@ export const BRL: Story = {
|
|
|
331
409
|
'original-greater-life-potion-0': { originalPrice: 15.00 },
|
|
332
410
|
'character-name-change': { originalPrice: 15.00 },
|
|
333
411
|
'skin-character-customization': { originalPrice: 20.00 },
|
|
334
|
-
'starter-pack': { originalPrice: 9.99 }
|
|
412
|
+
'starter-pack': { originalPrice: 9.99 },
|
|
413
|
+
'mega-booster': { originalPrice: 200000 },
|
|
414
|
+
'godly-artifact': { originalPrice: 2500000000 }
|
|
335
415
|
}}
|
|
336
416
|
/>
|
|
337
417
|
),
|
|
@@ -341,7 +421,7 @@ export const BRL: Story = {
|
|
|
341
421
|
export const EUR: Story = {
|
|
342
422
|
render: () => (
|
|
343
423
|
<Store
|
|
344
|
-
items={
|
|
424
|
+
items={allStoreItems}
|
|
345
425
|
packs={mockPacks}
|
|
346
426
|
userAccountType={UserAccountTypes.Free}
|
|
347
427
|
onPurchase={(purchase: Partial<IPurchase>) => {
|
|
@@ -349,7 +429,7 @@ export const EUR: Story = {
|
|
|
349
429
|
return Promise.resolve(true);
|
|
350
430
|
}}
|
|
351
431
|
customWalletContent={<DCWalletContent
|
|
352
|
-
dcBalance={
|
|
432
|
+
dcBalance={150000000} // 150M
|
|
353
433
|
historyData={{ transactions: [], totalPages: 1, currentPage: 1 }}
|
|
354
434
|
historyLoading={false}
|
|
355
435
|
onRequestHistory={() => {}}
|
|
@@ -388,7 +468,9 @@ export const EUR: Story = {
|
|
|
388
468
|
'original-greater-life-potion-0': { originalPrice: 15.00 },
|
|
389
469
|
'character-name-change': { originalPrice: 15.00 },
|
|
390
470
|
'skin-character-customization': { originalPrice: 20.00 },
|
|
391
|
-
'starter-pack': { originalPrice: 9.99 }
|
|
471
|
+
'starter-pack': { originalPrice: 9.99 },
|
|
472
|
+
'mega-booster': { originalPrice: 200000 },
|
|
473
|
+
'godly-artifact': { originalPrice: 2500000000 }
|
|
392
474
|
}}
|
|
393
475
|
/>
|
|
394
476
|
),
|
|
@@ -398,7 +480,7 @@ export const EUR: Story = {
|
|
|
398
480
|
export const GBP: Story = {
|
|
399
481
|
render: () => (
|
|
400
482
|
<Store
|
|
401
|
-
items={
|
|
483
|
+
items={allStoreItems}
|
|
402
484
|
packs={mockPacks}
|
|
403
485
|
userAccountType={UserAccountTypes.Free}
|
|
404
486
|
onPurchase={(purchase: Partial<IPurchase>) => {
|
|
@@ -406,7 +488,7 @@ export const GBP: Story = {
|
|
|
406
488
|
return Promise.resolve(true);
|
|
407
489
|
}}
|
|
408
490
|
customWalletContent={<DCWalletContent
|
|
409
|
-
dcBalance={
|
|
491
|
+
dcBalance={150000000} // 150M
|
|
410
492
|
historyData={{ transactions: [], totalPages: 1, currentPage: 1 }}
|
|
411
493
|
historyLoading={false}
|
|
412
494
|
onRequestHistory={() => {}}
|
|
@@ -445,7 +527,9 @@ export const GBP: Story = {
|
|
|
445
527
|
'original-greater-life-potion-0': { originalPrice: 15.00 },
|
|
446
528
|
'character-name-change': { originalPrice: 15.00 },
|
|
447
529
|
'skin-character-customization': { originalPrice: 20.00 },
|
|
448
|
-
'starter-pack': { originalPrice: 9.99 }
|
|
530
|
+
'starter-pack': { originalPrice: 9.99 },
|
|
531
|
+
'mega-booster': { originalPrice: 200000 },
|
|
532
|
+
'godly-artifact': { originalPrice: 2500000000 }
|
|
449
533
|
}}
|
|
450
534
|
/>
|
|
451
535
|
),
|
|
@@ -455,7 +539,7 @@ export const GBP: Story = {
|
|
|
455
539
|
export const JPY: Story = {
|
|
456
540
|
render: () => (
|
|
457
541
|
<Store
|
|
458
|
-
items={
|
|
542
|
+
items={allStoreItems}
|
|
459
543
|
packs={mockPacks}
|
|
460
544
|
userAccountType={UserAccountTypes.Free}
|
|
461
545
|
onPurchase={(purchase: Partial<IPurchase>) => {
|
|
@@ -463,7 +547,7 @@ export const JPY: Story = {
|
|
|
463
547
|
return Promise.resolve(true);
|
|
464
548
|
}}
|
|
465
549
|
customWalletContent={<DCWalletContent
|
|
466
|
-
dcBalance={
|
|
550
|
+
dcBalance={150000000} // 150M
|
|
467
551
|
historyData={{ transactions: [], totalPages: 1, currentPage: 1 }}
|
|
468
552
|
historyLoading={false}
|
|
469
553
|
onRequestHistory={() => {}}
|
|
@@ -502,7 +586,9 @@ export const JPY: Story = {
|
|
|
502
586
|
'original-greater-life-potion-0': { originalPrice: 15.00 },
|
|
503
587
|
'character-name-change': { originalPrice: 15.00 },
|
|
504
588
|
'skin-character-customization': { originalPrice: 20.00 },
|
|
505
|
-
'starter-pack': { originalPrice: 9.99 }
|
|
589
|
+
'starter-pack': { originalPrice: 9.99 },
|
|
590
|
+
'mega-booster': { originalPrice: 200000 },
|
|
591
|
+
'godly-artifact': { originalPrice: 2500000000 }
|
|
506
592
|
}}
|
|
507
593
|
/>
|
|
508
594
|
),
|
|
@@ -512,7 +598,7 @@ export const JPY: Story = {
|
|
|
512
598
|
export const INR: Story = {
|
|
513
599
|
render: () => (
|
|
514
600
|
<Store
|
|
515
|
-
items={
|
|
601
|
+
items={allStoreItems}
|
|
516
602
|
packs={mockPacks}
|
|
517
603
|
userAccountType={UserAccountTypes.Free}
|
|
518
604
|
onPurchase={(purchase: Partial<IPurchase>) => {
|
|
@@ -520,7 +606,7 @@ export const INR: Story = {
|
|
|
520
606
|
return Promise.resolve(true);
|
|
521
607
|
}}
|
|
522
608
|
customWalletContent={<DCWalletContent
|
|
523
|
-
dcBalance={
|
|
609
|
+
dcBalance={150000000} // 150M
|
|
524
610
|
historyData={{ transactions: [], totalPages: 1, currentPage: 1 }}
|
|
525
611
|
historyLoading={false}
|
|
526
612
|
onRequestHistory={() => {}}
|
|
@@ -559,7 +645,9 @@ export const INR: Story = {
|
|
|
559
645
|
'original-greater-life-potion-0': { originalPrice: 15.00 },
|
|
560
646
|
'character-name-change': { originalPrice: 15.00 },
|
|
561
647
|
'skin-character-customization': { originalPrice: 20.00 },
|
|
562
|
-
'starter-pack': { originalPrice: 9.99 }
|
|
648
|
+
'starter-pack': { originalPrice: 9.99 },
|
|
649
|
+
'mega-booster': { originalPrice: 200000 },
|
|
650
|
+
'godly-artifact': { originalPrice: 2500000000 }
|
|
563
651
|
}}
|
|
564
652
|
/>
|
|
565
653
|
),
|
|
@@ -568,7 +656,7 @@ export const INR: Story = {
|
|
|
568
656
|
export const WithRedeemTab: Story = {
|
|
569
657
|
render: () => (
|
|
570
658
|
<Store
|
|
571
|
-
items={
|
|
659
|
+
items={allStoreItems}
|
|
572
660
|
packs={mockPacks}
|
|
573
661
|
userAccountType={UserAccountTypes.Free}
|
|
574
662
|
onPurchase={(purchase: Partial<IPurchase>) => {
|
|
@@ -583,7 +671,7 @@ export const WithRedeemTab: Story = {
|
|
|
583
671
|
return { success: false, error: 'Invalid voucher code.' };
|
|
584
672
|
}}
|
|
585
673
|
customWalletContent={<DCWalletContent
|
|
586
|
-
dcBalance={
|
|
674
|
+
dcBalance={150000000} // 150M
|
|
587
675
|
historyData={{ transactions: [], totalPages: 1, currentPage: 1 }}
|
|
588
676
|
historyLoading={false}
|
|
589
677
|
onRequestHistory={() => {}}
|
|
@@ -621,7 +709,9 @@ export const WithRedeemTab: Story = {
|
|
|
621
709
|
'original-greater-life-potion-0': { originalPrice: 15.00 },
|
|
622
710
|
'character-name-change': { originalPrice: 15.00 },
|
|
623
711
|
'skin-character-customization': { originalPrice: 20.00 },
|
|
624
|
-
'starter-pack': { originalPrice: 9.99 }
|
|
712
|
+
'starter-pack': { originalPrice: 9.99 },
|
|
713
|
+
'mega-booster': { originalPrice: 200000 },
|
|
714
|
+
'godly-artifact': { originalPrice: 2500000000 }
|
|
625
715
|
}}
|
|
626
716
|
/>
|
|
627
717
|
),
|
|
@@ -42,6 +42,9 @@ const mockYourBuyOrders: IMarketplaceBuyOrderItem[] = [
|
|
|
42
42
|
{ _id: 'bo-1', owner: 'player-1', itemBlueprintKey: 'items/abyssal-edge', itemRarity: 'Rare', maxPrice: 500, escrowedGold: 500, fee: 25, status: MarketplaceBuyOrderStatus.Active, createdAt: daysAgo(3), updatedAt: daysAgo(3) },
|
|
43
43
|
{ _id: 'bo-2', owner: 'player-1', itemBlueprintKey: 'items/angelic-sword', maxPrice: 2000, escrowedGold: 2000, fee: 100, status: MarketplaceBuyOrderStatus.Fulfilled, fulfilledBy: 'DarkKnight42', createdAt: daysAgo(14), updatedAt: daysAgo(1) },
|
|
44
44
|
{ _id: 'bo-3', owner: 'player-1', itemBlueprintKey: 'items/leather-armor', maxPrice: 300, escrowedGold: 0, fee: 15, status: MarketplaceBuyOrderStatus.Expired, createdAt: daysAgo(35), updatedAt: daysAgo(7) },
|
|
45
|
+
{ _id: 'bo-mega', owner: 'player-1', itemBlueprintKey: 'items/dragon-scale', maxPrice: 2500000, escrowedGold: 2500000, fee: 125000, status: MarketplaceBuyOrderStatus.Active, createdAt: daysAgo(1), updatedAt: daysAgo(1) },
|
|
46
|
+
{ _id: 'bo-godly', owner: 'player-1', itemBlueprintKey: 'items/phoenix-feather', maxPrice: 1500000000, escrowedGold: 1500000000, fee: 7500000, status: MarketplaceBuyOrderStatus.Active, createdAt: daysAgo(0), updatedAt: daysAgo(0) },
|
|
47
|
+
{ _id: 'bo-bugfix', owner: 'player-1', itemBlueprintKey: 'missing-blueprint-key', itemRarity: 'Epic', maxPrice: 150000, escrowedGold: 150000, fee: 7500, status: MarketplaceBuyOrderStatus.Active, createdAt: daysAgo(2), updatedAt: daysAgo(2), itemTexturePath: 'swords/angelic-sword.png' } as any,
|
|
45
48
|
];
|
|
46
49
|
|
|
47
50
|
const ITEM_KEYS = [
|
|
@@ -58,11 +61,12 @@ const RARITIES = ['Common', 'Uncommon', 'Rare', 'Epic', 'Legendary'] as const;
|
|
|
58
61
|
const allMockOpenBuyOrders: IMarketplaceBuyOrderItem[] = Array.from({ length: 100 }, (_, i) => ({
|
|
59
62
|
_id: `obo-${i + 1}`,
|
|
60
63
|
owner: `player-${(i % 20) + 2}`,
|
|
61
|
-
itemBlueprintKey: ITEM_KEYS[i % ITEM_KEYS.length],
|
|
64
|
+
itemBlueprintKey: i === 0 ? 'missing-key-for-test' : ITEM_KEYS[i % ITEM_KEYS.length],
|
|
62
65
|
itemRarity: RARITIES[i % RARITIES.length] as any,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
...(i === 0 ? { itemTexturePath: 'potions/greater-life-potion.png' } : {}),
|
|
67
|
+
maxPrice: i === 0 ? 3000000 : Math.round((100 + i * 47) / 10) * 10,
|
|
68
|
+
escrowedGold: i === 0 ? 3000000 : Math.round((100 + i * 47) / 10) * 10,
|
|
69
|
+
fee: i === 0 ? 150000 : Math.round((100 + i * 47) / 10) * 10 * 0.05,
|
|
66
70
|
status: MarketplaceBuyOrderStatus.Active,
|
|
67
71
|
createdAt: daysAgo(i % 30),
|
|
68
72
|
updatedAt: daysAgo(i % 30),
|
|
@@ -33,6 +33,21 @@ describe('resolveAtlasSpriteKey', () => {
|
|
|
33
33
|
expect(resolveAtlasSpriteKey(atlasJSON, 'silver-arrow')).toBe(
|
|
34
34
|
'ranged-weapons/silvermoon-arrow.png'
|
|
35
35
|
);
|
|
36
|
+
expect(resolveAtlasSpriteKey(atlasJSON, 'social-crystal')).toBe(
|
|
37
|
+
'crafting-resources/tile049.png'
|
|
38
|
+
);
|
|
39
|
+
expect(resolveAtlasSpriteKey(atlasJSON, 'bloodroot-blossom-flower')).toBe(
|
|
40
|
+
'crafting-resources/bloodroot-blossom.png'
|
|
41
|
+
);
|
|
42
|
+
expect(resolveAtlasSpriteKey(atlasJSON, 'sunspire-lotus-flower')).toBe(
|
|
43
|
+
'crafting-resources/sunspire-lotus.png'
|
|
44
|
+
);
|
|
45
|
+
expect(resolveAtlasSpriteKey(atlasJSON, 'mana-shield-tome')).toBe(
|
|
46
|
+
'spell-tomes/spell-tome-blue-4.png'
|
|
47
|
+
);
|
|
48
|
+
expect(resolveAtlasSpriteKey(atlasJSON, 'entangling-roots-tome')).toBe(
|
|
49
|
+
'spell-tomes/spell-tome-green-2.png'
|
|
50
|
+
);
|
|
36
51
|
});
|
|
37
52
|
|
|
38
53
|
it('returns null when no atlas sprite can be resolved', () => {
|
package/src/utils/atlasUtils.ts
CHANGED
|
@@ -3,6 +3,84 @@ export const NO_IMAGE_SPRITE_KEY = 'others/no-image.png';
|
|
|
3
3
|
const atlasSpriteAliases = new Map<string, string>([
|
|
4
4
|
['mysticstaff', 'staffs/mystic-lightning-staff.png'],
|
|
5
5
|
['silverarrow', 'ranged-weapons/silvermoon-arrow.png'],
|
|
6
|
+
// Runtime blueprint keys whose atlas filenames do not match their item ids.
|
|
7
|
+
['arcaneexplosiontome', 'spell-tomes/spell-tome-special-blue-2.png'],
|
|
8
|
+
['arrowcreationspelltome', 'spell-tomes/spell-tome-gray-4.png'],
|
|
9
|
+
['arrowstormtome', 'spell-tomes/spell-tome-gray-5.png'],
|
|
10
|
+
['berserkerbloodthirsttome', 'spell-tomes/spell-tome-special-red-3.png'],
|
|
11
|
+
['berserkerexecutiontome', 'spell-tomes/spell-tome-brown-5.png'],
|
|
12
|
+
['berserkerfrenzytome', 'spell-tomes/spell-tome-special-red-2.png'],
|
|
13
|
+
['berserkerragetome', 'spell-tomes/spell-tome-red-6.png'],
|
|
14
|
+
['blankrunecreationspelltome', 'spell-tomes/spell-tome-gray-4.png'],
|
|
15
|
+
['bleedingedgetome', 'spell-tomes/spell-tome-brown-4.png'],
|
|
16
|
+
['blizzardtome', 'spell-tomes/spell-tome-special-blue-1.png'],
|
|
17
|
+
['bloodrootblossomflower', 'crafting-resources/bloodroot-blossom.png'],
|
|
18
|
+
['boltcreationspelltome', 'spell-tomes/spell-tome-blue-6.png'],
|
|
19
|
+
['bombcreationtome', 'spell-tomes/spell-tome-red-4.png'],
|
|
20
|
+
['chefsdelighttome', 'spell-tomes/spell-tome-brown-2.png'],
|
|
21
|
+
['cleavingstomptome', 'spell-tomes/spell-tome-brown-6.png'],
|
|
22
|
+
['corruptionbolttome', 'spell-tomes/spell-tome-dark-1.png'],
|
|
23
|
+
['corruptionrunecreationspelltome', 'spell-tomes/spell-tome-dark-3.png'],
|
|
24
|
+
['corruptionwavetome', 'spell-tomes/spell-tome-dark-2.png'],
|
|
25
|
+
['crimsonarrowcreationtome', 'spell-tomes/spell-tome-red-6.png'],
|
|
26
|
+
['curseofweaknesstome', 'spell-tomes/spell-tome-dark-6.png'],
|
|
27
|
+
['darkrunecreationspelltome', 'spell-tomes/spell-tome-dark-3.png'],
|
|
28
|
+
['dispelmagictome', 'spell-tomes/spell-tome-blue-4.png'],
|
|
29
|
+
['druidshapeshifttome', 'spell-tomes/spell-tome-special-green-2.png'],
|
|
30
|
+
['druidsilencetome', 'spell-tomes/spell-tome-green-3.png'],
|
|
31
|
+
['duskwispherbflower', 'crafting-resources/duskwisp-herb.png'],
|
|
32
|
+
['dwarfstoneformtome', 'spell-tomes/spell-tome-brown-5.png'],
|
|
33
|
+
['elvenarrowtome', 'spell-tomes/spell-tome-green-5.png'],
|
|
34
|
+
['emeraldarrowcreationtome', 'spell-tomes/spell-tome-green-4.png'],
|
|
35
|
+
['energyboltrunecreationspelltome', 'spell-tomes/spell-tome-blue-6.png'],
|
|
36
|
+
['energywavetome', 'spell-tomes/spell-tome-blue-5.png'],
|
|
37
|
+
['entanglingrootstome', 'spell-tomes/spell-tome-green-2.png'],
|
|
38
|
+
['fireboltcreationspelltome', 'spell-tomes/spell-tome-red-2.png'],
|
|
39
|
+
['fireboltrunecreationspelltome', 'spell-tomes/spell-tome-red-4.png'],
|
|
40
|
+
['firebolttome', 'spell-tomes/spell-tome-red-1.png'],
|
|
41
|
+
['firerunecreationspelltome', 'spell-tomes/spell-tome-red-3.png'],
|
|
42
|
+
['firestormtome', 'spell-tomes/spell-tome-special-red-1.png'],
|
|
43
|
+
['focusswifttome', 'spell-tomes/spell-tome-gray-3.png'],
|
|
44
|
+
['focustome', 'spell-tomes/spell-tome-gray-2.png'],
|
|
45
|
+
['foodcreationspelltome', 'spell-tomes/spell-tome-brown-1.png'],
|
|
46
|
+
['fortifydefensetome', 'spell-tomes/spell-tome-brown-5.png'],
|
|
47
|
+
['frostarrowcreationtome', 'spell-tomes/spell-tome-blue-2.png'],
|
|
48
|
+
['frostbolttome', 'spell-tomes/spell-tome-blue-1.png'],
|
|
49
|
+
['greaterhealingspelltome', 'spell-tomes/spell-tome-special-yellow-2.png'],
|
|
50
|
+
['healingrunecreationspelltome', 'spell-tomes/spell-tome-gray-1.png'],
|
|
51
|
+
['hunterexecutiontome', 'spell-tomes/spell-tome-special-gray-2.png'],
|
|
52
|
+
['hunterquickfiretome', 'spell-tomes/spell-tome-gray-6.png'],
|
|
53
|
+
['ironwilltome', 'spell-tomes/spell-tome-special-yellow-1.png'],
|
|
54
|
+
['magicshurikentome', 'spell-tomes/spell-tome-blue-7.png'],
|
|
55
|
+
['manadraintome', 'spell-tomes/spell-tome-blue-3.png'],
|
|
56
|
+
['manashieldtome', 'spell-tomes/spell-tome-blue-4.png'],
|
|
57
|
+
['masshealingtome', 'spell-tomes/spell-tome-special-yellow-3.png'],
|
|
58
|
+
['minotaurbullstrengthtome', 'spell-tomes/spell-tome-brown-6.png'],
|
|
59
|
+
['naturesrevengetome', 'spell-tomes/spell-tome-special-green-1.png'],
|
|
60
|
+
['pickpockettome', 'spell-tomes/spell-tome-gray-3.png'],
|
|
61
|
+
['poisonarrowcreationspelltome', 'spell-tomes/spell-tome-green-5.png'],
|
|
62
|
+
['poisonrunecreationspelltome', 'spell-tomes/spell-tome-green-6.png'],
|
|
63
|
+
['powerstriketome', 'spell-tomes/spell-tome-brown-1.png'],
|
|
64
|
+
['rogueexecutiontome', 'spell-tomes/spell-tome-special-gray-1.png'],
|
|
65
|
+
['roguestealthspelltome', 'spell-tomes/spell-tome-gray-2.png'],
|
|
66
|
+
['selfhastespelltome', 'spell-tomes/spell-tome-gray-1.png'],
|
|
67
|
+
['selfhealingspelltome', 'spell-tomes/spell-tome-special-yellow-1.png'],
|
|
68
|
+
['shieldbashtome', 'spell-tomes/spell-tome-brown-2.png'],
|
|
69
|
+
['smallwoodensticks', 'crafting-resources/small-wood-sticks.png'],
|
|
70
|
+
['socialcrystal', 'crafting-resources/tile049.png'],
|
|
71
|
+
['spelldivineprotectiontome', 'spell-tomes/spell-tome-special-yellow-1.png'],
|
|
72
|
+
['spelleagleeyestome', 'spell-tomes/spell-tome-gray-7.png'],
|
|
73
|
+
['spellphysicalshieldtome', 'spell-tomes/spell-tome-brown-3.png'],
|
|
74
|
+
['spellpolymorphtome', 'spell-tomes/spell-tome-special-blue-2.png'],
|
|
75
|
+
['sunspirelotusflower', 'crafting-resources/sunspire-lotus.png'],
|
|
76
|
+
['teleporttome', 'spell-tomes/spell-tome-special-blue-1.png'],
|
|
77
|
+
['thunderrunecreationspelltome', 'spell-tomes/spell-tome-blue-7.png'],
|
|
78
|
+
['vampiricstormtome', 'spell-tomes/spell-tome-dark-4.png'],
|
|
79
|
+
['veilofundeathtome', 'spell-tomes/spell-tome-dark-5.png'],
|
|
80
|
+
['vinegrasptome', 'spell-tomes/spell-tome-green-1.png'],
|
|
81
|
+
['warriorexecutiontome', 'spell-tomes/spell-tome-special-brown-1.png'],
|
|
82
|
+
['warriorstuntargettome', 'spell-tomes/spell-tome-brown-3.png'],
|
|
83
|
+
['wildfirevolleytome', 'spell-tomes/spell-tome-red-5.png'],
|
|
6
84
|
]);
|
|
7
85
|
|
|
8
86
|
const atlasBaseNameLookupCache = new WeakMap<object, Map<string, string>>();
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formats a number using modern gaming standards (k for thousands, M for millions, B for billions).
|
|
3
|
+
* @param num The number to format
|
|
4
|
+
* @param useKNotation Whether to use the k/M/B notation
|
|
5
|
+
* @returns Formatted string
|
|
6
|
+
*/
|
|
7
|
+
export const formatMMORPGNumber = (num: number, useKNotation: boolean = true): string => {
|
|
8
|
+
if (!useKNotation || num < 1000) {
|
|
9
|
+
return num.toLocaleString();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Billions (B)
|
|
13
|
+
if (num >= 1000000000) {
|
|
14
|
+
const value = num / 1000000000;
|
|
15
|
+
return value.toFixed(value % 1 === 0 ? 0 : 1) + 'B';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Millions (M)
|
|
19
|
+
if (num >= 1000000) {
|
|
20
|
+
const value = num / 1000000;
|
|
21
|
+
return value.toFixed(value % 1 === 0 ? 0 : 1) + 'M';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Thousands (k)
|
|
25
|
+
if (num >= 1000) {
|
|
26
|
+
const value = num / 1000;
|
|
27
|
+
return value.toFixed(value % 1 === 0 ? 0 : 1) + 'k';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return num.toLocaleString();
|
|
31
|
+
};
|