@rpg-engine/long-bow 0.8.48 → 0.8.50
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/Character/CharacterSkinSelectionModal.d.ts +12 -0
- package/dist/components/DailyTasks/DailyTasks.d.ts +2 -1
- package/dist/index.d.ts +1 -0
- package/dist/long-bow.cjs.development.js +201 -101
- 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 +201 -102
- package/dist/long-bow.esm.js.map +1 -1
- package/dist/stories/Character/character/CharacterSkinSelectionModal.stories.d.ts +5 -0
- package/package.json +1 -1
- package/src/components/Character/CharacterSkinSelectionModal.tsx +151 -0
- package/src/components/DailyTasks/DailyRewardsTooltip.tsx +1 -1
- package/src/components/DailyTasks/DailyTasks.tsx +11 -6
- package/src/components/DailyTasks/TaskProgressDetails.tsx +1 -1
- package/src/index.tsx +1 -0
- package/src/mocks/dailyTasks.mocks.ts +1 -7
- package/src/stories/Character/character/CharacterSkinSelectionModal.stories.tsx +52 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Meta } from '@storybook/react';
|
|
2
|
+
import { ICharacterSkinSelectionModalProps } from '../../../components/Character/CharacterSkinSelectionModal';
|
|
3
|
+
declare const meta: Meta;
|
|
4
|
+
export default meta;
|
|
5
|
+
export declare const KnightSkins: import("@storybook/csf").AnnotatedStoryFn<import("@storybook/react").ReactFramework, ICharacterSkinSelectionModalProps>;
|
package/package.json
CHANGED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
import { Button, ButtonTypes } from '../Button';
|
|
4
|
+
import { ErrorBoundary } from '../Item/Inventory/ErrorBoundary';
|
|
5
|
+
import PropertySelect, {
|
|
6
|
+
IPropertiesProps,
|
|
7
|
+
} from '../PropertySelect/PropertySelect';
|
|
8
|
+
import { SpriteFromAtlas } from '../shared/SpriteFromAtlas';
|
|
9
|
+
import { ICharacterProps } from './CharacterSelection';
|
|
10
|
+
|
|
11
|
+
export interface ICharacterSkinSelectionModalProps {
|
|
12
|
+
isOpen: boolean;
|
|
13
|
+
onClose: () => void;
|
|
14
|
+
onConfirm: (textureKey: string) => void;
|
|
15
|
+
availableCharacters: ICharacterProps[];
|
|
16
|
+
atlasJSON: any;
|
|
17
|
+
atlasIMG: any;
|
|
18
|
+
initialSelectedSkin?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const CharacterSkinSelectionModal: React.FC<ICharacterSkinSelectionModalProps> = ({
|
|
22
|
+
isOpen,
|
|
23
|
+
onClose,
|
|
24
|
+
onConfirm,
|
|
25
|
+
availableCharacters,
|
|
26
|
+
atlasJSON,
|
|
27
|
+
atlasIMG,
|
|
28
|
+
initialSelectedSkin = '',
|
|
29
|
+
}) => {
|
|
30
|
+
// Convert availableCharacters to the format used by PropertySelect
|
|
31
|
+
const propertySelectValues = availableCharacters.map(item => ({
|
|
32
|
+
id: item.textureKey,
|
|
33
|
+
name: item.name,
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
// State to store the selected skin and the sprite key
|
|
37
|
+
const [selectedValue, setSelectedValue] = useState<
|
|
38
|
+
IPropertiesProps | undefined
|
|
39
|
+
>();
|
|
40
|
+
const [selectedSpriteKey, setSelectedSpriteKey] = useState('');
|
|
41
|
+
|
|
42
|
+
// Update sprite when the selected value changes
|
|
43
|
+
const updateSelectedSpriteKey = () => {
|
|
44
|
+
const textureKey = selectedValue ? selectedValue.id : '';
|
|
45
|
+
const spriteKey = textureKey ? textureKey + '/down/standing/0.png' : '';
|
|
46
|
+
|
|
47
|
+
if (spriteKey === selectedSpriteKey) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
setSelectedSpriteKey(spriteKey);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// Update sprite when selectedValue changes
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
updateSelectedSpriteKey();
|
|
57
|
+
}, [selectedValue]);
|
|
58
|
+
|
|
59
|
+
// Initialize selectedValue
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (initialSelectedSkin) {
|
|
62
|
+
const initialProperty = propertySelectValues.find(
|
|
63
|
+
prop => prop.id === initialSelectedSkin
|
|
64
|
+
);
|
|
65
|
+
setSelectedValue(initialProperty || propertySelectValues[0]);
|
|
66
|
+
} else if (propertySelectValues.length > 0) {
|
|
67
|
+
setSelectedValue(propertySelectValues[0]);
|
|
68
|
+
}
|
|
69
|
+
}, [initialSelectedSkin, availableCharacters]);
|
|
70
|
+
|
|
71
|
+
// Functions to handle confirmation and cancellation
|
|
72
|
+
const handleConfirm = () => {
|
|
73
|
+
if (selectedValue) {
|
|
74
|
+
onConfirm(selectedValue.id);
|
|
75
|
+
onClose();
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const handleCancel = () => {
|
|
80
|
+
onClose();
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
if (!isOpen) return null;
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<Container>
|
|
87
|
+
{selectedSpriteKey && atlasIMG && atlasJSON && (
|
|
88
|
+
<ErrorBoundary>
|
|
89
|
+
<SpriteFromAtlas
|
|
90
|
+
spriteKey={selectedSpriteKey}
|
|
91
|
+
atlasIMG={atlasIMG}
|
|
92
|
+
atlasJSON={atlasJSON}
|
|
93
|
+
imgScale={4}
|
|
94
|
+
height={80}
|
|
95
|
+
width={64}
|
|
96
|
+
containerStyle={{
|
|
97
|
+
display: 'flex',
|
|
98
|
+
alignItems: 'center',
|
|
99
|
+
paddingBottom: '15px',
|
|
100
|
+
}}
|
|
101
|
+
imgStyle={{
|
|
102
|
+
left: '22px',
|
|
103
|
+
}}
|
|
104
|
+
/>
|
|
105
|
+
</ErrorBoundary>
|
|
106
|
+
)}
|
|
107
|
+
|
|
108
|
+
<PropertySelect
|
|
109
|
+
availableProperties={propertySelectValues}
|
|
110
|
+
onChange={value => {
|
|
111
|
+
setSelectedValue(value);
|
|
112
|
+
}}
|
|
113
|
+
/>
|
|
114
|
+
|
|
115
|
+
<ButtonsContainer>
|
|
116
|
+
<Button buttonType={ButtonTypes.RPGUIButton} onClick={handleCancel}>
|
|
117
|
+
Cancel
|
|
118
|
+
</Button>
|
|
119
|
+
<Button
|
|
120
|
+
buttonType={ButtonTypes.RPGUIButton}
|
|
121
|
+
onClick={handleConfirm}
|
|
122
|
+
disabled={!selectedValue}
|
|
123
|
+
>
|
|
124
|
+
Confirm
|
|
125
|
+
</Button>
|
|
126
|
+
</ButtonsContainer>
|
|
127
|
+
</Container>
|
|
128
|
+
);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
// Styled components
|
|
132
|
+
|
|
133
|
+
const Container = styled.div`
|
|
134
|
+
display: flex;
|
|
135
|
+
flex-direction: column;
|
|
136
|
+
align-items: center;
|
|
137
|
+
image-rendering: pixelated;
|
|
138
|
+
`;
|
|
139
|
+
|
|
140
|
+
const ButtonsContainer = styled.div`
|
|
141
|
+
display: flex;
|
|
142
|
+
justify-content: center;
|
|
143
|
+
gap: 0.8rem;
|
|
144
|
+
width: 100%;
|
|
145
|
+
margin: 3rem 0 0.75rem;
|
|
146
|
+
|
|
147
|
+
button {
|
|
148
|
+
min-width: 95px;
|
|
149
|
+
font-size: 0.9rem;
|
|
150
|
+
}
|
|
151
|
+
`;
|
|
@@ -71,7 +71,7 @@ export const DailyRewardsTooltip: React.FC<IDailyRewardsTooltipProps> = ({
|
|
|
71
71
|
<ItemContent>
|
|
72
72
|
<RewardLabel>
|
|
73
73
|
<Ellipsis maxWidth="100%" maxLines={2}>
|
|
74
|
-
{formatTaskKey(reward.key ??
|
|
74
|
+
{formatTaskKey(reward.key ?? reward.type)}:
|
|
75
75
|
</Ellipsis>
|
|
76
76
|
</RewardLabel>
|
|
77
77
|
</ItemContent>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ICharacterDailyTask,
|
|
3
|
+
ICollectGlobalRewardRequest,
|
|
3
4
|
ITaskIdentifier,
|
|
4
5
|
TaskStatus,
|
|
5
6
|
TaskType,
|
|
@@ -17,6 +18,7 @@ import { getTaskIcon } from './utils/dailyTasks.utils';
|
|
|
17
18
|
export interface IDailyTasksProps {
|
|
18
19
|
tasks: ICharacterDailyTask[];
|
|
19
20
|
onClaimReward: (task: ITaskIdentifier) => void;
|
|
21
|
+
onClaimGlobalReward: (tasks: ICollectGlobalRewardRequest) => void;
|
|
20
22
|
onClose: () => void;
|
|
21
23
|
scale?: number;
|
|
22
24
|
itemsAtlasJSON: Record<string, any>;
|
|
@@ -28,6 +30,7 @@ export interface IDailyTasksProps {
|
|
|
28
30
|
export const DailyTasks: React.FC<IDailyTasksProps> = ({
|
|
29
31
|
tasks,
|
|
30
32
|
onClaimReward,
|
|
33
|
+
onClaimGlobalReward,
|
|
31
34
|
onClose,
|
|
32
35
|
scale = 1,
|
|
33
36
|
itemsAtlasJSON,
|
|
@@ -48,12 +51,14 @@ export const DailyTasks: React.FC<IDailyTasksProps> = ({
|
|
|
48
51
|
};
|
|
49
52
|
|
|
50
53
|
const handleClaimAllRewards = () => {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
const tasksToReward = localTasks
|
|
55
|
+
.filter(task => task.status === TaskStatus.Completed && !task.claimed)
|
|
56
|
+
.map(task => ({
|
|
57
|
+
type: task.type,
|
|
58
|
+
taskKey: task.key,
|
|
59
|
+
}));
|
|
60
|
+
|
|
61
|
+
onClaimGlobalReward({ tasks: tasksToReward });
|
|
57
62
|
};
|
|
58
63
|
|
|
59
64
|
if (!size) return null;
|
|
@@ -48,7 +48,7 @@ export const TaskProgressDetails: React.FC<ITaskProgressDetailsProps> = ({
|
|
|
48
48
|
return Object.entries((progress as ICollectProgress).collected || {}).map(
|
|
49
49
|
([key, value], index) => (
|
|
50
50
|
<ProgressItem key={index}>
|
|
51
|
-
<span>{key}:</span>
|
|
51
|
+
<span>{formatTaskKey(key)}:</span>
|
|
52
52
|
<ProgressCount>
|
|
53
53
|
{value}/
|
|
54
54
|
{(task.requirements as ICollectItemsRequirement).targets.find(
|
package/src/index.tsx
CHANGED
|
@@ -2,6 +2,7 @@ export * from './components/Arrow/SelectArrow';
|
|
|
2
2
|
export * from './components/AsyncDropdown';
|
|
3
3
|
export * from './components/Button';
|
|
4
4
|
export * from './components/Character/CharacterSelection';
|
|
5
|
+
export * from './components/Character/CharacterSkinSelectionModal';
|
|
5
6
|
export * from './components/Chat/Chat';
|
|
6
7
|
export * from './components/Chatdeprecated/ChatDeprecated';
|
|
7
8
|
export * from './components/ChatRevamp/ChatRevamp';
|
|
@@ -36,7 +36,6 @@ export const mockTasks: ICharacterDailyTask[] = [
|
|
|
36
36
|
},
|
|
37
37
|
{
|
|
38
38
|
type: RewardType.Experience,
|
|
39
|
-
key: 'exp',
|
|
40
39
|
quantity: 100
|
|
41
40
|
}
|
|
42
41
|
]
|
|
@@ -51,7 +50,7 @@ export const mockTasks: ICharacterDailyTask[] = [
|
|
|
51
50
|
type: TaskType.CollectItems,
|
|
52
51
|
targets: [
|
|
53
52
|
{
|
|
54
|
-
key: '
|
|
53
|
+
key: 'wooden-log',
|
|
55
54
|
quantity: 10
|
|
56
55
|
}
|
|
57
56
|
]
|
|
@@ -73,7 +72,6 @@ export const mockTasks: ICharacterDailyTask[] = [
|
|
|
73
72
|
},
|
|
74
73
|
{
|
|
75
74
|
type: RewardType.Experience,
|
|
76
|
-
key: 'exp',
|
|
77
75
|
quantity: 250
|
|
78
76
|
}
|
|
79
77
|
],
|
|
@@ -112,7 +110,6 @@ export const mockTasks: ICharacterDailyTask[] = [
|
|
|
112
110
|
},
|
|
113
111
|
{
|
|
114
112
|
type: RewardType.Experience,
|
|
115
|
-
key: 'exp',
|
|
116
113
|
quantity: 1000
|
|
117
114
|
}
|
|
118
115
|
],
|
|
@@ -132,8 +129,6 @@ export const mockTasks: ICharacterDailyTask[] = [
|
|
|
132
129
|
rewards: [
|
|
133
130
|
{
|
|
134
131
|
type: RewardType.Experience,
|
|
135
|
-
key: 'exp',
|
|
136
|
-
texturePath: 'others/royal-chalice.png',
|
|
137
132
|
quantity: 10000
|
|
138
133
|
},
|
|
139
134
|
{
|
|
@@ -202,7 +197,6 @@ export const mockTasks: ICharacterDailyTask[] = [
|
|
|
202
197
|
},
|
|
203
198
|
{
|
|
204
199
|
type: RewardType.Experience,
|
|
205
|
-
key: 'exp',
|
|
206
200
|
quantity: 200
|
|
207
201
|
}
|
|
208
202
|
],
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Meta, Story } from '@storybook/react';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { RPGUIRoot } from '../../..';
|
|
4
|
+
import {
|
|
5
|
+
CharacterSkinSelectionModal,
|
|
6
|
+
ICharacterSkinSelectionModalProps,
|
|
7
|
+
} from '../../../components/Character/CharacterSkinSelectionModal';
|
|
8
|
+
import atlasJSON from '../../../mocks/atlas/entities/entities.json';
|
|
9
|
+
import atlasIMG from '../../../mocks/atlas/entities/entities.png';
|
|
10
|
+
|
|
11
|
+
const meta: Meta = {
|
|
12
|
+
title: 'Character/Character/Skin Selection',
|
|
13
|
+
component: CharacterSkinSelectionModal,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default meta;
|
|
17
|
+
|
|
18
|
+
const Template: Story<ICharacterSkinSelectionModalProps> = (
|
|
19
|
+
args: ICharacterSkinSelectionModalProps
|
|
20
|
+
) => (
|
|
21
|
+
<RPGUIRoot>
|
|
22
|
+
<CharacterSkinSelectionModal {...args} />
|
|
23
|
+
</RPGUIRoot>
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
export const KnightSkins = Template.bind({});
|
|
27
|
+
|
|
28
|
+
// Example of different knight skins
|
|
29
|
+
const knightCharacters = [
|
|
30
|
+
{
|
|
31
|
+
name: 'Black Knight',
|
|
32
|
+
textureKey: 'black-knight',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'Dragon Knight',
|
|
36
|
+
textureKey: 'dragon-knight',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'Senior Knight',
|
|
40
|
+
textureKey: 'senior-knight-1',
|
|
41
|
+
},
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
KnightSkins.args = {
|
|
45
|
+
isOpen: true,
|
|
46
|
+
onClose: () => console.log('Modal closed'),
|
|
47
|
+
onConfirm: (textureKey: string) => console.log('Selected skin:', textureKey),
|
|
48
|
+
availableCharacters: knightCharacters,
|
|
49
|
+
atlasJSON: atlasJSON,
|
|
50
|
+
atlasIMG: atlasIMG,
|
|
51
|
+
initialSelectedSkin: 'black-knight',
|
|
52
|
+
};
|