@rpg-engine/long-bow 0.8.71 → 0.8.72
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/Store/CartView.d.ts +7 -6
- package/dist/components/Store/Store.d.ts +2 -2
- package/dist/components/Store/StoreCharacterSkinRow.d.ts +3 -3
- package/dist/components/Store/StoreItemDetails.d.ts +3 -3
- package/dist/components/Store/StoreItemRow.d.ts +4 -3
- package/dist/components/Store/hooks/useStoreCart.d.ts +5 -3
- package/dist/components/Store/hooks/useStoreMetadata.d.ts +3 -3
- package/dist/components/Store/sections/StoreItemsSection.d.ts +3 -3
- package/dist/long-bow.cjs.development.js +57 -41
- 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 +58 -42
- package/dist/long-bow.esm.js.map +1 -1
- package/package.json +2 -2
- package/src/components/Store/CartView.tsx +9 -6
- package/src/components/Store/Store.tsx +13 -21
- package/src/components/Store/StoreCharacterSkinRow.tsx +4 -4
- package/src/components/Store/StoreItemDetails.tsx +4 -4
- package/src/components/Store/StoreItemRow.tsx +14 -4
- package/src/components/Store/hooks/useStoreCart.ts +14 -9
- package/src/components/Store/hooks/useStoreMetadata.ts +5 -5
- package/src/components/Store/sections/StoreItemsSection.tsx +8 -8
- package/src/stories/Features/store/Store.stories.tsx +28 -68
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rpg-engine/long-bow",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.72",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"dependencies": {
|
|
85
85
|
"@capacitor/core": "^6.1.0",
|
|
86
86
|
"@rollup/plugin-image": "^2.1.1",
|
|
87
|
-
"@rpg-engine/shared": "^0.
|
|
87
|
+
"@rpg-engine/shared": "^0.10.10",
|
|
88
88
|
"dayjs": "^1.11.2",
|
|
89
89
|
"font-awesome": "^4.7.0",
|
|
90
90
|
"fs-extra": "^10.1.0",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IProductBlueprint, MetadataType } from '@rpg-engine/shared';
|
|
2
2
|
import React, { useState } from 'react';
|
|
3
3
|
import { FaInfoCircle, FaShoppingBag, FaTimes, FaTrash } from 'react-icons/fa';
|
|
4
4
|
import styled from 'styled-components';
|
|
@@ -9,12 +9,15 @@ import { SpriteFromAtlas } from '../shared/SpriteFromAtlas';
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
|
|
12
|
+
// Local cart item interface
|
|
13
|
+
interface ICartItem {
|
|
14
|
+
item: IProductBlueprint;
|
|
15
|
+
quantity: number;
|
|
16
|
+
metadata?: Record<string, any>;
|
|
17
|
+
}
|
|
18
|
+
|
|
12
19
|
interface ICartViewProps {
|
|
13
|
-
cartItems:
|
|
14
|
-
item: IStoreItem;
|
|
15
|
-
quantity: number;
|
|
16
|
-
metadata?: Record<string, any>;
|
|
17
|
-
}[];
|
|
20
|
+
cartItems: ICartItem[];
|
|
18
21
|
onRemoveFromCart: (itemKey: string) => void;
|
|
19
22
|
onClose: () => void;
|
|
20
23
|
onPurchase: () => Promise<boolean>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IItemPack, IPurchase,
|
|
1
|
+
import { IItemPack, IPurchase, IProductBlueprint, ItemRarities, ItemSubType, ItemType, UserAccountTypes, PaymentCurrency, PurchaseType } from '@rpg-engine/shared';
|
|
2
2
|
import React, { ReactNode, useMemo, useState } from 'react';
|
|
3
3
|
import { FaHistory, FaShoppingCart } from 'react-icons/fa';
|
|
4
4
|
import styled from 'styled-components';
|
|
@@ -19,7 +19,7 @@ type TabId = 'premium' | 'packs' | 'items';
|
|
|
19
19
|
|
|
20
20
|
// Define IStoreProps locally as a workaround
|
|
21
21
|
export interface IStoreProps {
|
|
22
|
-
items:
|
|
22
|
+
items: IProductBlueprint[];
|
|
23
23
|
packs?: IItemPack[];
|
|
24
24
|
atlasJSON: any;
|
|
25
25
|
atlasIMG: string;
|
|
@@ -71,41 +71,33 @@ export const Store: React.FC<IStoreProps> = ({
|
|
|
71
71
|
isCartOpen,
|
|
72
72
|
} = useStoreCart();
|
|
73
73
|
const [isCollectingMetadata, setIsCollectingMetadata] = useState(false);
|
|
74
|
-
const [currentMetadataItem, setCurrentMetadataItem] = useState<
|
|
74
|
+
const [currentMetadataItem, setCurrentMetadataItem] = useState<IProductBlueprint | null>(null);
|
|
75
75
|
|
|
76
76
|
const handleAddPackToCart = (pack: IItemPack) => {
|
|
77
|
-
const packItem:
|
|
78
|
-
_id: pack.key,
|
|
77
|
+
const packItem: IProductBlueprint = {
|
|
79
78
|
key: pack.key,
|
|
80
79
|
name: pack.title,
|
|
80
|
+
description: pack.description || '',
|
|
81
81
|
price: pack.priceUSD,
|
|
82
|
+
currency: PaymentCurrency.USD,
|
|
82
83
|
texturePath: pack.image.default || pack.image.src,
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
fullDescription: pack.description || '',
|
|
88
|
-
textureAtlas: 'items',
|
|
89
|
-
weight: 0,
|
|
84
|
+
type: PurchaseType.Pack,
|
|
85
|
+
onPurchase: async () => {},
|
|
86
|
+
itemType: ItemType.Consumable,
|
|
87
|
+
itemSubType: ItemSubType.Other,
|
|
90
88
|
rarity: ItemRarities.Common,
|
|
91
|
-
|
|
92
|
-
isEquipable: false,
|
|
89
|
+
weight: 0,
|
|
93
90
|
isStackable: false,
|
|
94
|
-
isTwoHanded: false,
|
|
95
|
-
hasUseWith: false,
|
|
96
91
|
maxStackSize: 1,
|
|
97
92
|
isUsable: false,
|
|
98
|
-
isStorable: true,
|
|
99
|
-
isSolid: false,
|
|
100
|
-
isItemContainer: false,
|
|
101
93
|
};
|
|
102
94
|
handleAddToCart(packItem, 1);
|
|
103
95
|
};
|
|
104
96
|
|
|
105
97
|
const filterItems = (
|
|
106
|
-
itemsToFilter:
|
|
98
|
+
itemsToFilter: IProductBlueprint[],
|
|
107
99
|
type: 'items' | 'premium'
|
|
108
|
-
):
|
|
100
|
+
): IProductBlueprint[] => {
|
|
109
101
|
return itemsToFilter.filter(item => {
|
|
110
102
|
if (type === 'premium') {
|
|
111
103
|
return item.requiredAccountType?.length ?? 0 > 0;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IProductBlueprint, MetadataType, UserAccountTypes } from '@rpg-engine/shared';
|
|
2
2
|
import React, { useEffect, useState } from 'react';
|
|
3
3
|
import { FaCartPlus } from 'react-icons/fa';
|
|
4
4
|
import styled from 'styled-components';
|
|
@@ -8,10 +8,10 @@ import { CTAButton } from '../shared/CTAButton/CTAButton';
|
|
|
8
8
|
import { SpriteFromAtlas } from '../shared/SpriteFromAtlas';
|
|
9
9
|
|
|
10
10
|
interface IStoreCharacterSkinRowProps {
|
|
11
|
-
item:
|
|
11
|
+
item: IProductBlueprint;
|
|
12
12
|
atlasJSON: Record<string, any>;
|
|
13
13
|
atlasIMG: string;
|
|
14
|
-
onAddToCart: (item:
|
|
14
|
+
onAddToCart: (item: IProductBlueprint, quantity: number, metadata?: Record<string, any>) => void;
|
|
15
15
|
userAccountType: UserAccountTypes;
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -36,7 +36,7 @@ export const StoreCharacterSkinRow: React.FC<IStoreCharacterSkinRowProps> = ({
|
|
|
36
36
|
// Effect to reset currentIndex when switching items
|
|
37
37
|
useEffect(() => {
|
|
38
38
|
setCurrentIndex(0);
|
|
39
|
-
}, [item.
|
|
39
|
+
}, [item.key]);
|
|
40
40
|
|
|
41
41
|
const handlePreviousSkin = () => {
|
|
42
42
|
setCurrentIndex((prevIndex) =>
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { IItemPack,
|
|
1
|
+
import { IItemPack, IProductBlueprint } from '@rpg-engine/shared';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { FaArrowLeft, FaCartPlus } from 'react-icons/fa';
|
|
4
4
|
import styled from 'styled-components';
|
|
5
5
|
import { CTAButton } from '../shared/CTAButton/CTAButton';
|
|
6
6
|
|
|
7
7
|
interface IStoreItemDetailsProps {
|
|
8
|
-
item:
|
|
8
|
+
item: IProductBlueprint | (IItemPack & { name: string; texturePath: string });
|
|
9
9
|
imageUrl: string | { src: string; default?: string };
|
|
10
10
|
onBack: () => void;
|
|
11
|
-
onAddToCart: (item:
|
|
11
|
+
onAddToCart: (item: IProductBlueprint) => void;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export const StoreItemDetails: React.FC<IStoreItemDetailsProps> = ({
|
|
@@ -53,7 +53,7 @@ export const StoreItemDetails: React.FC<IStoreItemDetailsProps> = ({
|
|
|
53
53
|
<CTAButton
|
|
54
54
|
icon={<FaCartPlus />}
|
|
55
55
|
label="Add to Cart"
|
|
56
|
-
onClick={() => onAddToCart(item as
|
|
56
|
+
onClick={() => onAddToCart(item as IProductBlueprint)}
|
|
57
57
|
fullWidth
|
|
58
58
|
/>
|
|
59
59
|
</Actions>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IProductBlueprint, UserAccountTypes } from '@rpg-engine/shared';
|
|
2
2
|
import React, { useState } from 'react';
|
|
3
3
|
import { FaCartPlus } from 'react-icons/fa';
|
|
4
4
|
import styled from 'styled-components';
|
|
@@ -7,12 +7,13 @@ import { CTAButton } from '../shared/CTAButton/CTAButton';
|
|
|
7
7
|
import { SpriteFromAtlas } from '../shared/SpriteFromAtlas';
|
|
8
8
|
|
|
9
9
|
interface IStoreItemRowProps {
|
|
10
|
-
item:
|
|
10
|
+
item: IProductBlueprint;
|
|
11
11
|
atlasJSON: Record<string, any>;
|
|
12
12
|
atlasIMG: string;
|
|
13
|
-
onAddToCart: (item:
|
|
13
|
+
onAddToCart: (item: IProductBlueprint, quantity: number, metadata?: Record<string, any>) => void;
|
|
14
14
|
userAccountType: UserAccountTypes;
|
|
15
15
|
showTextInput?: boolean;
|
|
16
|
+
textInputPlaceholder?: string;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
export const StoreItemRow: React.FC<IStoreItemRowProps> = ({
|
|
@@ -22,6 +23,7 @@ export const StoreItemRow: React.FC<IStoreItemRowProps> = ({
|
|
|
22
23
|
onAddToCart,
|
|
23
24
|
userAccountType,
|
|
24
25
|
showTextInput = false,
|
|
26
|
+
textInputPlaceholder = item.inputPlaceholder,
|
|
25
27
|
}) => {
|
|
26
28
|
const [quantity, setQuantity] = useState(1);
|
|
27
29
|
const [textInputValue, setTextInputValue] = useState('');
|
|
@@ -76,6 +78,7 @@ export const StoreItemRow: React.FC<IStoreItemRowProps> = ({
|
|
|
76
78
|
<ItemDetails>
|
|
77
79
|
<ItemName>{item.name}</ItemName>
|
|
78
80
|
<ItemPrice>${item.price}</ItemPrice>
|
|
81
|
+
<ItemDescription>{item.description}</ItemDescription>
|
|
79
82
|
</ItemDetails>
|
|
80
83
|
|
|
81
84
|
<Controls>
|
|
@@ -84,7 +87,7 @@ export const StoreItemRow: React.FC<IStoreItemRowProps> = ({
|
|
|
84
87
|
<TextInput
|
|
85
88
|
type="text"
|
|
86
89
|
value={textInputValue}
|
|
87
|
-
placeholder=
|
|
90
|
+
placeholder={textInputPlaceholder}
|
|
88
91
|
onChange={e => setTextInputValue(e.target.value)}
|
|
89
92
|
className="rpgui-input"
|
|
90
93
|
/>
|
|
@@ -166,6 +169,13 @@ const ItemPrice = styled.div`
|
|
|
166
169
|
color: #fef08a;
|
|
167
170
|
`;
|
|
168
171
|
|
|
172
|
+
const ItemDescription = styled.div`
|
|
173
|
+
font-family: 'Press Start 2P', cursive;
|
|
174
|
+
font-size: 0.625rem;
|
|
175
|
+
color: rgba(255, 255, 255, 0.7);
|
|
176
|
+
line-height: 1.4;
|
|
177
|
+
`;
|
|
178
|
+
|
|
169
179
|
const Controls = styled.div`
|
|
170
180
|
display: flex;
|
|
171
181
|
align-items: center;
|
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
import {
|
|
2
|
-
ICartItem as IBaseCartItem,
|
|
3
2
|
IPurchase,
|
|
4
3
|
IPurchaseUnit,
|
|
5
|
-
|
|
4
|
+
IProductBlueprint,
|
|
6
5
|
MetadataType,
|
|
7
6
|
PurchaseType
|
|
8
7
|
} from '@rpg-engine/shared';
|
|
9
8
|
import { useEffect, useRef, useState } from 'react';
|
|
10
9
|
import { useStoreMetadata } from './useStoreMetadata';
|
|
11
10
|
|
|
12
|
-
//
|
|
13
|
-
interface ICartItem
|
|
11
|
+
// Create local cart item interface that uses IProductBlueprint
|
|
12
|
+
interface ICartItem {
|
|
13
|
+
item: IProductBlueprint;
|
|
14
|
+
quantity: number;
|
|
14
15
|
metadata?: Record<string, any>;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
interface IUseStoreCart {
|
|
18
19
|
cartItems: ICartItem[];
|
|
19
20
|
isCartOpen: boolean;
|
|
20
|
-
handleAddToCart: (item:
|
|
21
|
+
handleAddToCart: (item: IProductBlueprint, quantity: number, metadata?: Record<string, any>) => void;
|
|
21
22
|
handleRemoveFromCart: (itemKey: string) => void;
|
|
22
23
|
handlePurchase: (onPurchase: (purchase: IPurchase) => void) => void;
|
|
23
24
|
openCart: () => void;
|
|
@@ -40,7 +41,7 @@ export const useStoreCart = (): IUseStoreCart => {
|
|
|
40
41
|
|
|
41
42
|
const { collectMetadata, isCollectingMetadata } = useStoreMetadata();
|
|
42
43
|
|
|
43
|
-
const handleAddToCart = async (item:
|
|
44
|
+
const handleAddToCart = async (item: IProductBlueprint, quantity: number, preselectedMetadata?: Record<string, any>) => {
|
|
44
45
|
// If metadata is already provided (from inline selection), use it directly
|
|
45
46
|
if (preselectedMetadata) {
|
|
46
47
|
setCartItems(prevItems => {
|
|
@@ -57,7 +58,7 @@ export const useStoreCart = (): IUseStoreCart => {
|
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
// If item requires metadata but none was provided, collect it before adding to cart
|
|
60
|
-
if (item.metadataType
|
|
61
|
+
if (item.metadataType === MetadataType.CharacterSkin) {
|
|
61
62
|
const metadata = await collectMetadata(item);
|
|
62
63
|
if (!metadata) return; // User cancelled
|
|
63
64
|
|
|
@@ -156,8 +157,12 @@ export const useStoreCart = (): IUseStoreCart => {
|
|
|
156
157
|
};
|
|
157
158
|
|
|
158
159
|
// Helper functions
|
|
159
|
-
function getPurchaseType(item:
|
|
160
|
-
//
|
|
160
|
+
function getPurchaseType(item: IProductBlueprint): PurchaseType {
|
|
161
|
+
// Use the type from IProductBlueprint if available, otherwise infer
|
|
162
|
+
if (item.type) {
|
|
163
|
+
return item.type;
|
|
164
|
+
}
|
|
165
|
+
// Fallback logic for backward compatibility
|
|
161
166
|
if (item.key.startsWith('pack_')) {
|
|
162
167
|
return PurchaseType.Pack;
|
|
163
168
|
} else {
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IProductBlueprint, MetadataType } from "@rpg-engine/shared";
|
|
2
2
|
import { useState } from "react";
|
|
3
3
|
|
|
4
4
|
interface IUseStoreMetadata {
|
|
5
|
-
collectMetadata: (item:
|
|
5
|
+
collectMetadata: (item: IProductBlueprint) => Promise<Record<string, any> | null>;
|
|
6
6
|
isCollectingMetadata: boolean;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export const useStoreMetadata = (): IUseStoreMetadata => {
|
|
10
10
|
const [isCollectingMetadata, setIsCollectingMetadata] = useState(false);
|
|
11
11
|
|
|
12
|
-
const collectMetadata = async (item:
|
|
13
|
-
if (!item.metadataType || item.metadataType
|
|
12
|
+
const collectMetadata = async (item: IProductBlueprint): Promise<Record<string, any> | null> => {
|
|
13
|
+
if (!item.metadataType || item.metadataType !== MetadataType.CharacterSkin) {
|
|
14
14
|
return null;
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -49,7 +49,7 @@ declare global {
|
|
|
49
49
|
interface Window {
|
|
50
50
|
__metadataResolvers?: {
|
|
51
51
|
resolve: (metadata: Record<string, any> | null) => void;
|
|
52
|
-
item:
|
|
52
|
+
item: IProductBlueprint;
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
55
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IProductBlueprint, MetadataType, UserAccountTypes } from '@rpg-engine/shared';
|
|
2
2
|
import React, { useState } from 'react';
|
|
3
3
|
import { ScrollableContent } from '../../shared/ScrollableContent/ScrollableContent';
|
|
4
4
|
import { StoreCharacterSkinRow } from '../StoreCharacterSkinRow';
|
|
@@ -6,8 +6,8 @@ import { StoreItemRow } from '../StoreItemRow';
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
interface IStoreItemsSectionProps {
|
|
9
|
-
items:
|
|
10
|
-
onAddToCart: (item:
|
|
9
|
+
items: IProductBlueprint[];
|
|
10
|
+
onAddToCart: (item: IProductBlueprint, quantity: number, metadata?: Record<string, any>) => void;
|
|
11
11
|
atlasJSON: Record<string, any>;
|
|
12
12
|
atlasIMG: string;
|
|
13
13
|
userAccountType?: UserAccountTypes;
|
|
@@ -28,12 +28,12 @@ export const StoreItemsSection: React.FC<IStoreItemsSectionProps> = ({
|
|
|
28
28
|
item.name.toLowerCase().includes(searchQuery.toLowerCase())
|
|
29
29
|
);
|
|
30
30
|
|
|
31
|
-
const renderStoreItem = (item:
|
|
31
|
+
const renderStoreItem = (item: IProductBlueprint) => {
|
|
32
32
|
// Prefer a specialized character skin row when needed
|
|
33
33
|
if (item.metadataType === MetadataType.CharacterSkin) {
|
|
34
34
|
return (
|
|
35
35
|
<StoreCharacterSkinRow
|
|
36
|
-
key={item.
|
|
36
|
+
key={item.key}
|
|
37
37
|
item={item}
|
|
38
38
|
atlasJSON={atlasJSON}
|
|
39
39
|
atlasIMG={atlasIMG}
|
|
@@ -43,10 +43,10 @@ export const StoreItemsSection: React.FC<IStoreItemsSectionProps> = ({
|
|
|
43
43
|
);
|
|
44
44
|
}
|
|
45
45
|
// Render text input row when configured for this item key
|
|
46
|
-
if (textInputItemKeys.includes(item.key)
|
|
46
|
+
if (textInputItemKeys.includes(item.key)) {
|
|
47
47
|
return (
|
|
48
48
|
<StoreItemRow
|
|
49
|
-
key={item.
|
|
49
|
+
key={item.key}
|
|
50
50
|
item={item}
|
|
51
51
|
atlasJSON={atlasJSON}
|
|
52
52
|
atlasIMG={atlasIMG}
|
|
@@ -59,7 +59,7 @@ export const StoreItemsSection: React.FC<IStoreItemsSectionProps> = ({
|
|
|
59
59
|
// Fallback to standard arrow-based row
|
|
60
60
|
return (
|
|
61
61
|
<StoreItemRow
|
|
62
|
-
key={item.
|
|
62
|
+
key={item.key}
|
|
63
63
|
item={item}
|
|
64
64
|
atlasJSON={atlasJSON}
|
|
65
65
|
atlasIMG={atlasIMG}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IItemPack, IPurchase,
|
|
1
|
+
import { IItemPack, IPurchase, IProductBlueprint, ItemRarities, ItemSubType, ItemType, MetadataType, UserAccountTypes, PaymentCurrency, PurchaseType } from '@rpg-engine/shared';
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { RPGUIRoot } from '../../../components/RPGUI/RPGUIRoot';
|
|
@@ -29,41 +29,24 @@ export default meta;
|
|
|
29
29
|
type Story = StoryObj<typeof Store>;
|
|
30
30
|
|
|
31
31
|
// Create mock items once, with fixed stock values
|
|
32
|
-
const storeItems:
|
|
33
|
-
_id: `original-${item.key}-${index}`,
|
|
32
|
+
const storeItems: IProductBlueprint[] = mockItems.map((item, index) => ({
|
|
34
33
|
key: `original-${item.key}-${index}`,
|
|
35
34
|
name: item.name,
|
|
36
35
|
description: item.description,
|
|
37
|
-
|
|
36
|
+
price: item.basePrice,
|
|
37
|
+
currency: PaymentCurrency.USD,
|
|
38
38
|
texturePath: item.texturePath,
|
|
39
39
|
textureAtlas: 'items',
|
|
40
40
|
textureKey: item.texturePath,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
attack: item.attack || 0,
|
|
46
|
-
defense: item.defense || 0,
|
|
47
|
-
weight: item.weight,
|
|
41
|
+
type: PurchaseType.Item,
|
|
42
|
+
onPurchase: async () => {},
|
|
43
|
+
itemType: item.type,
|
|
44
|
+
itemSubType: item.subType,
|
|
48
45
|
rarity: item.rarity,
|
|
49
|
-
|
|
46
|
+
weight: item.weight,
|
|
50
47
|
isStackable: item.maxStackSize > 1,
|
|
51
|
-
isUsable: true,
|
|
52
|
-
isStorable: true,
|
|
53
|
-
hasUseWith: false,
|
|
54
|
-
isSolid: false,
|
|
55
|
-
isTwoHanded: false,
|
|
56
|
-
isItemContainer: false,
|
|
57
|
-
layer: 1,
|
|
58
|
-
allowedEquipSlotType: item.allowedEquipSlotType || [],
|
|
59
48
|
maxStackSize: item.maxStackSize || 1,
|
|
60
|
-
|
|
61
|
-
canSell: item.canSell ?? true,
|
|
62
|
-
rangeType: item.rangeType,
|
|
63
|
-
entityEffects: item.entityEffects || [],
|
|
64
|
-
entityEffectChance: item.entityEffectChance || 0,
|
|
65
|
-
equippedBuff: item.equippedBuff || [],
|
|
66
|
-
equippedBuffDescription: item.equippedBuffDescription || '',
|
|
49
|
+
isUsable: true,
|
|
67
50
|
requiredAccountType: item.rarity === 'Legendary' ? [UserAccountTypes.PremiumGold] : [],
|
|
68
51
|
}));
|
|
69
52
|
|
|
@@ -87,35 +70,25 @@ const availableCharacters = [
|
|
|
87
70
|
];
|
|
88
71
|
|
|
89
72
|
// Create character skin items
|
|
90
|
-
const characterSkinItems:
|
|
73
|
+
const characterSkinItems: IProductBlueprint[] = [
|
|
91
74
|
{
|
|
92
|
-
_id: 'skin-character-customization',
|
|
93
75
|
key: 'skin-character-customization',
|
|
94
76
|
name: 'Character Skin Customization',
|
|
95
77
|
description: 'Customize your character\'s appearance with a variety of skins',
|
|
96
|
-
|
|
78
|
+
price: 14.99,
|
|
79
|
+
currency: PaymentCurrency.USD,
|
|
97
80
|
texturePath: 'items/character_customization.png',
|
|
98
81
|
textureAtlas: 'items',
|
|
99
82
|
textureKey: 'items/character_customization.png',
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
defense: 0,
|
|
105
|
-
weight: 0,
|
|
83
|
+
type: PurchaseType.Item,
|
|
84
|
+
onPurchase: async () => {},
|
|
85
|
+
itemType: ItemType.Other,
|
|
86
|
+
itemSubType: ItemSubType.Other,
|
|
106
87
|
rarity: ItemRarities.Rare,
|
|
107
|
-
|
|
88
|
+
weight: 0,
|
|
108
89
|
isStackable: false,
|
|
109
|
-
isUsable: true,
|
|
110
|
-
isStorable: true,
|
|
111
|
-
hasUseWith: false,
|
|
112
|
-
isSolid: false,
|
|
113
|
-
isTwoHanded: false,
|
|
114
|
-
isItemContainer: false,
|
|
115
|
-
layer: 1,
|
|
116
|
-
allowedEquipSlotType: [],
|
|
117
90
|
maxStackSize: 1,
|
|
118
|
-
|
|
91
|
+
isUsable: true,
|
|
119
92
|
metadataType: MetadataType.CharacterSkin,
|
|
120
93
|
metadataConfig: {
|
|
121
94
|
availableCharacters,
|
|
@@ -124,34 +97,24 @@ const characterSkinItems: IStoreItem[] = [
|
|
|
124
97
|
},
|
|
125
98
|
},
|
|
126
99
|
{
|
|
127
|
-
_id: 'skin-premium-character-pack',
|
|
128
100
|
key: 'skin-premium-character-pack',
|
|
129
101
|
name: 'Premium Character Skin Pack',
|
|
130
102
|
description: 'A premium collection of exclusive character skins',
|
|
131
|
-
|
|
103
|
+
price: 24.99,
|
|
104
|
+
currency: PaymentCurrency.USD,
|
|
132
105
|
texturePath: 'items/premium_character_pack.png',
|
|
133
106
|
textureAtlas: 'items',
|
|
134
107
|
textureKey: 'items/premium_character_pack.png',
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
defense: 0,
|
|
140
|
-
weight: 0,
|
|
108
|
+
type: PurchaseType.Item,
|
|
109
|
+
onPurchase: async () => {},
|
|
110
|
+
itemType: ItemType.Other,
|
|
111
|
+
itemSubType: ItemSubType.Other,
|
|
141
112
|
rarity: ItemRarities.Epic,
|
|
142
|
-
|
|
113
|
+
weight: 0,
|
|
143
114
|
isStackable: false,
|
|
144
|
-
isUsable: true,
|
|
145
|
-
isStorable: true,
|
|
146
|
-
hasUseWith: false,
|
|
147
|
-
isSolid: false,
|
|
148
|
-
isTwoHanded: false,
|
|
149
|
-
isItemContainer: false,
|
|
150
|
-
layer: 1,
|
|
151
|
-
allowedEquipSlotType: [],
|
|
152
115
|
maxStackSize: 1,
|
|
116
|
+
isUsable: true,
|
|
153
117
|
requiredAccountType: [UserAccountTypes.PremiumSilver],
|
|
154
|
-
// Add metadata type and config with the same character options
|
|
155
118
|
metadataType: MetadataType.CharacterSkin,
|
|
156
119
|
metadataConfig: {
|
|
157
120
|
availableCharacters,
|
|
@@ -162,22 +125,19 @@ const characterSkinItems: IStoreItem[] = [
|
|
|
162
125
|
];
|
|
163
126
|
|
|
164
127
|
// Create duplicated items once with unique keys
|
|
165
|
-
const duplicatedItems:
|
|
128
|
+
const duplicatedItems: IProductBlueprint[] = [
|
|
166
129
|
...storeItems,
|
|
167
130
|
...characterSkinItems,
|
|
168
131
|
...storeItems.map((item, index) => ({
|
|
169
132
|
...item,
|
|
170
|
-
_id: `copy1-${item.key}-${index}`,
|
|
171
133
|
key: `copy1-${item.key}-${index}`,
|
|
172
134
|
})),
|
|
173
135
|
...storeItems.map((item, index) => ({
|
|
174
136
|
...item,
|
|
175
|
-
_id: `copy2-${item.key}-${index}`,
|
|
176
137
|
key: `copy2-${item.key}-${index}`,
|
|
177
138
|
})),
|
|
178
139
|
...storeItems.map((item, index) => ({
|
|
179
140
|
...item,
|
|
180
|
-
_id: `copy3-${item.key}-${index}`,
|
|
181
141
|
key: `copy3-${item.key}-${index}`,
|
|
182
142
|
})),
|
|
183
143
|
];
|