@rpg-engine/long-bow 0.8.46 → 0.8.48

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.
Files changed (35) hide show
  1. package/dist/components/DailyTasks/DailyRewardsTooltip.d.ts +11 -0
  2. package/dist/components/DailyTasks/DailyTaskItem.d.ts +13 -0
  3. package/dist/components/DailyTasks/DailyTasks.d.ts +13 -0
  4. package/dist/components/DailyTasks/GlobalDailyProgress.d.ts +8 -0
  5. package/dist/components/DailyTasks/TaskProgress.d.ts +11 -0
  6. package/dist/components/DailyTasks/TaskProgressDetails.d.ts +7 -0
  7. package/dist/components/DailyTasks/utils/dailyTasks.utils.d.ts +8 -0
  8. package/dist/components/ReadOnlyCheckItem.d.ts +7 -0
  9. package/dist/constants/uiColors.d.ts +1 -0
  10. package/dist/index.d.ts +1 -1
  11. package/dist/long-bow.cjs.development.js +611 -85
  12. package/dist/long-bow.cjs.development.js.map +1 -1
  13. package/dist/long-bow.cjs.production.min.js +1 -1
  14. package/dist/long-bow.cjs.production.min.js.map +1 -1
  15. package/dist/long-bow.esm.js +611 -86
  16. package/dist/long-bow.esm.js.map +1 -1
  17. package/dist/mocks/dailyTasks.mocks.d.ts +2 -0
  18. package/dist/stories/Features/dailyTasks/DailyTasks.stories.d.ts +1 -0
  19. package/package.json +2 -2
  20. package/src/components/DailyTasks/DailyRewardsTooltip.tsx +158 -0
  21. package/src/components/DailyTasks/DailyTaskItem.tsx +161 -0
  22. package/src/components/DailyTasks/DailyTasks.tsx +151 -0
  23. package/src/components/DailyTasks/GlobalDailyProgress.tsx +132 -0
  24. package/src/components/DailyTasks/TaskProgress.tsx +92 -0
  25. package/src/components/DailyTasks/TaskProgressDetails.tsx +128 -0
  26. package/src/components/DailyTasks/utils/dailyTasks.utils.ts +96 -0
  27. package/src/components/ReadOnlyCheckItem.tsx +43 -0
  28. package/src/constants/uiColors.ts +1 -0
  29. package/src/index.tsx +1 -1
  30. package/src/mocks/dailyTasks.mocks.ts +212 -0
  31. package/src/stories/Features/dailyTasks/DailyTasks.stories.tsx +145 -0
  32. package/dist/components/Character/CharacterSkinSelectionModal.d.ts +0 -13
  33. package/dist/stories/Character/character/CharacterSkinSelectionModal.stories.d.ts +0 -5
  34. package/src/components/Character/CharacterSkinSelectionModal.tsx +0 -157
  35. package/src/stories/Character/character/CharacterSkinSelectionModal.stories.tsx +0 -49
@@ -0,0 +1,92 @@
1
+ import { ICharacterDailyTask } from '@rpg-engine/shared';
2
+ import React from 'react';
3
+ import styled from 'styled-components';
4
+ import { uiColors } from '../../constants/uiColors';
5
+ import { DailyRewardsTooltip } from './DailyRewardsTooltip';
6
+ import { TaskProgressDetails } from './TaskProgressDetails';
7
+ import { formatDifficulty, getStatusInfo } from './utils/dailyTasks.utils';
8
+
9
+ interface TaskProgressProps {
10
+ task: ICharacterDailyTask;
11
+ itemsAtlasJSON: Record<string, any>;
12
+ itemsAtlasIMG: string;
13
+ iconAtlasJSON?: Record<string, any>;
14
+ iconAtlasIMG?: string;
15
+ }
16
+
17
+ export const TaskProgress: React.FC<TaskProgressProps> = ({
18
+ task,
19
+ itemsAtlasJSON,
20
+ itemsAtlasIMG,
21
+ iconAtlasJSON,
22
+ iconAtlasIMG,
23
+ }) => {
24
+ const { difficulty } = task;
25
+
26
+ return (
27
+ <ProgressContainer>
28
+ <ProgressList>
29
+ <ProgressItem>
30
+ <ProgressLabel>Difficulty:</ProgressLabel>
31
+ <TaskDifficulty difficulty={difficulty}>
32
+ {formatDifficulty(difficulty)}
33
+ </TaskDifficulty>
34
+ </ProgressItem>
35
+
36
+ <ProgressItem>
37
+ <ProgressLabel>Status:</ProgressLabel>
38
+ <StatusText color={getStatusInfo(task).color}>
39
+ {getStatusInfo(task).text}
40
+ </StatusText>
41
+ </ProgressItem>
42
+
43
+ <TaskProgressDetails task={task} />
44
+
45
+ {task.rewards && task.rewards.length > 0 && (
46
+ <ProgressItem>
47
+ <DailyRewardsTooltip
48
+ rewards={task.rewards}
49
+ itemsAtlasJSON={itemsAtlasJSON}
50
+ itemsAtlasIMG={itemsAtlasIMG}
51
+ iconAtlasJSON={iconAtlasJSON}
52
+ iconAtlasIMG={iconAtlasIMG}
53
+ />
54
+ </ProgressItem>
55
+ )}
56
+ </ProgressList>
57
+ </ProgressContainer>
58
+ );
59
+ };
60
+
61
+ const ProgressContainer = styled.div`
62
+ width: 100%;
63
+ position: relative;
64
+ `;
65
+
66
+ const ProgressList = styled.div`
67
+ display: flex;
68
+ flex-direction: column;
69
+ gap: 6px;
70
+ `;
71
+
72
+ const ProgressItem = styled.div`
73
+ display: flex;
74
+ justify-content: space-between;
75
+ align-items: center;
76
+ `;
77
+
78
+ const ProgressLabel = styled.span`
79
+ color: ${uiColors.white} !important;
80
+ `;
81
+
82
+ const TaskDifficulty = styled.span<{ difficulty: string }>`
83
+ color: ${props =>
84
+ props.difficulty.toLowerCase() === 'challenge'
85
+ ? uiColors.red
86
+ : uiColors.lightGray} !important;
87
+ `;
88
+
89
+ const StatusText = styled.span<{ color: string }>`
90
+ color: ${props => props.color} !important;
91
+ font-weight: bold;
92
+ `;
@@ -0,0 +1,128 @@
1
+ import {
2
+ ICharacterDailyTask,
3
+ ICollectItemsRequirement,
4
+ ICollectProgress,
5
+ ICraftProgress,
6
+ ICraftRequirement,
7
+ IKillMobsProgress,
8
+ IKillMobsRequirement,
9
+ IMapVisitProgress,
10
+ TaskType,
11
+ } from '@rpg-engine/shared';
12
+ import React from 'react';
13
+ import styled from 'styled-components';
14
+ import { uiColors } from '../../constants/uiColors';
15
+ import { ReadOnlyCheckItem } from '../ReadOnlyCheckItem';
16
+ import { formatTaskKey } from './utils/dailyTasks.utils';
17
+
18
+ interface ITaskProgressDetailsProps {
19
+ task: ICharacterDailyTask;
20
+ }
21
+
22
+ export const TaskProgressDetails: React.FC<ITaskProgressDetailsProps> = ({
23
+ task,
24
+ }) => {
25
+ const { progress, type } = task;
26
+
27
+ const progressRenderers = {
28
+ [TaskType.KillMobs]: () => {
29
+ return (
30
+ (progress as IKillMobsProgress).kills &&
31
+ Object.entries((progress as IKillMobsProgress).kills).map(
32
+ ([key, value], index) => (
33
+ <ProgressItem key={index}>
34
+ <span>{formatTaskKey(key)}:</span>
35
+ <ProgressCount>
36
+ {value}/
37
+ {(task.requirements as IKillMobsRequirement).targets.find(
38
+ t => t.key === key
39
+ )?.quantity || 0}
40
+ </ProgressCount>
41
+ </ProgressItem>
42
+ )
43
+ )
44
+ );
45
+ },
46
+
47
+ [TaskType.CollectItems]: () => {
48
+ return Object.entries((progress as ICollectProgress).collected || {}).map(
49
+ ([key, value], index) => (
50
+ <ProgressItem key={index}>
51
+ <span>{key}:</span>
52
+ <ProgressCount>
53
+ {value}/
54
+ {(task.requirements as ICollectItemsRequirement).targets.find(
55
+ t => t.key === key
56
+ )?.quantity || 0}
57
+ </ProgressCount>
58
+ </ProgressItem>
59
+ )
60
+ );
61
+ },
62
+
63
+ [TaskType.CraftItems]: () => {
64
+ return Object.entries((progress as ICraftProgress).crafted || {}).map(
65
+ ([key, value], index) => (
66
+ <ProgressItem key={index}>
67
+ <span>{formatTaskKey(key)}:</span>
68
+ <ProgressCount>
69
+ {value}/
70
+ {(task.requirements as ICraftRequirement).targets.find(
71
+ t => t.key === key
72
+ )?.quantity || 0}
73
+ </ProgressCount>
74
+ </ProgressItem>
75
+ )
76
+ );
77
+ },
78
+
79
+ [TaskType.MapVisit]: () => {
80
+ return Object.entries(
81
+ (progress as IMapVisitProgress).visitedMaps || {}
82
+ ).map(([mapName, visited], index) => (
83
+ <ProgressItem key={index}>
84
+ <CheckItemWrapper>
85
+ <ReadOnlyCheckItem
86
+ labelLeft={formatTaskKey(mapName)}
87
+ checked={visited}
88
+ />
89
+ </CheckItemWrapper>
90
+ </ProgressItem>
91
+ ));
92
+ },
93
+ };
94
+
95
+ return (
96
+ <ProgressList>
97
+ {progressRenderers[type] ? progressRenderers[type]() : null}
98
+ </ProgressList>
99
+ );
100
+ };
101
+
102
+ const ProgressList = styled.div`
103
+ display: flex;
104
+ flex-direction: column;
105
+ gap: 8px;
106
+ `;
107
+
108
+ const ProgressItem = styled.div`
109
+ display: flex;
110
+ justify-content: space-between;
111
+ align-items: center;
112
+ `;
113
+
114
+ const ProgressCount = styled.span`
115
+ color: ${uiColors.white} !important;
116
+ `;
117
+
118
+ const CheckItemWrapper = styled.div`
119
+ display: flex;
120
+ justify-content: center;
121
+ width: 100%;
122
+ height: 20px;
123
+
124
+ input.rpgui-checkbox + label {
125
+ margin: 0 !important;
126
+ padding-left: 23px !important;
127
+ }
128
+ `;
@@ -0,0 +1,96 @@
1
+ import { ICharacterDailyTask, ICollectProgress, ICraftProgress, IKillMobsProgress, IMapVisitProgress, TaskStatus, TaskType } from '@rpg-engine/shared';
2
+ import { uiColors } from '../../../constants/uiColors';
3
+
4
+ export const formatTaskKey = (key: string): string => {
5
+ let formatted = key.replace(/[-_]/g, ' ');
6
+ formatted = formatted.replace(/([A-Z])/g, ' $1');
7
+ formatted = formatted.trim();
8
+ return formatted
9
+ .split(' ')
10
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
11
+ .join(' ');
12
+ };
13
+
14
+ export const getTaskIcon = (taskType: TaskType, difficulty?: string): string => {
15
+ const MapIcon = 'map-2.png';
16
+ const KillMobsIconRegular = 'white-skull.png';
17
+ const KillMobsIconChallenge = 'red-skull.png';
18
+ const CollectItemIcon = 'inventory-2.png';
19
+ const CraftItemIcon = 'crafting.png';
20
+
21
+ switch (taskType) {
22
+ case TaskType.KillMobs:
23
+ return difficulty === 'Challenge'
24
+ ? KillMobsIconChallenge
25
+ : KillMobsIconRegular;
26
+ case TaskType.CollectItems:
27
+ return CollectItemIcon;
28
+ case TaskType.MapVisit:
29
+ return MapIcon;
30
+ case TaskType.CraftItems:
31
+ return CraftItemIcon;
32
+ default:
33
+ return 'check.png';
34
+ }
35
+ };
36
+
37
+ export const getStatusInfo = (
38
+ task: ICharacterDailyTask
39
+ ): { text: string; color: string } => {
40
+ if (task.status === TaskStatus.Completed) {
41
+ return { text: 'Completed', color: uiColors.lightGreen };
42
+ }
43
+
44
+ if (task.claimed) {
45
+ return { text: 'Claimed', color: uiColors.yellow };
46
+ }
47
+
48
+ const isTaskNotStarted = (() => {
49
+ switch (task.type) {
50
+ case TaskType.KillMobs:
51
+ return (
52
+ task.type === TaskType.KillMobs &&
53
+ Object.values((task.progress as IKillMobsProgress).kills || {}).every(
54
+ kill => kill === 0
55
+ )
56
+ );
57
+
58
+ case TaskType.CollectItems:
59
+ return (
60
+ task.type === TaskType.CollectItems &&
61
+ Object.values(
62
+ (task.progress as ICollectProgress).collected || {}
63
+ ).every(quantity => quantity === 0)
64
+ );
65
+
66
+ case TaskType.CraftItems:
67
+ return (
68
+ task.type === TaskType.CraftItems &&
69
+ Object.values((task.progress as ICraftProgress).crafted || {}).every(
70
+ quantity => quantity === 0
71
+ )
72
+ );
73
+
74
+ case TaskType.MapVisit:
75
+ return (
76
+ task.type === TaskType.MapVisit &&
77
+ Object.values(
78
+ (task.progress as IMapVisitProgress).visitedMaps || {}
79
+ ).every(visited => !visited)
80
+ );
81
+
82
+ default:
83
+ return false;
84
+ }
85
+ })();
86
+
87
+ if (isTaskNotStarted) {
88
+ return { text: 'Not Started', color: uiColors.lightGray };
89
+ }
90
+
91
+ return { text: 'In Progress', color: uiColors.blue };
92
+ };
93
+
94
+ export const formatDifficulty = (difficulty: string): string => {
95
+ return difficulty.charAt(0).toUpperCase() + difficulty.slice(1).toLowerCase();
96
+ };
@@ -0,0 +1,43 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ export interface IReadOnlyCheckItemProps {
5
+ labelLeft?: string;
6
+ labelRight?: string;
7
+ checked: boolean;
8
+ }
9
+
10
+ export const ReadOnlyCheckItem: React.FC<IReadOnlyCheckItemProps> = ({
11
+ labelLeft,
12
+ labelRight,
13
+ checked,
14
+ }) => {
15
+ return (
16
+ <Container>
17
+ {labelLeft && <Label>{labelLeft}</Label>}
18
+ <div className="rpgui-checkbox-container">
19
+ <CheckBox
20
+ className="rpgui-checkbox"
21
+ type="checkbox"
22
+ checked={checked}
23
+ readOnly
24
+ />
25
+ <label></label>
26
+ </div>
27
+ {labelRight && <Label isRight>{labelRight}</Label>}
28
+ </Container>
29
+ );
30
+ };
31
+
32
+ const Container = styled.div`
33
+ display: flex;
34
+ align-items: center;
35
+ width: 100%;
36
+ height: 20px;
37
+ `;
38
+
39
+ const Label = styled.span<{ isRight?: boolean }>`
40
+ ${({ isRight }) => (isRight ? 'margin-left: auto;' : 'margin-right: auto;')}
41
+ `;
42
+
43
+ const CheckBox = styled.input.attrs({ type: 'checkbox' })``;
@@ -16,6 +16,7 @@ export const uiColors = {
16
16
  darkBlue: '#30346D',
17
17
  brown: '#854C30',
18
18
  lightGreen: '#66cd1c',
19
+ green: '#4CAF50',
19
20
  brownGreen: '#346524',
20
21
  white: '#fff'
21
22
  };
package/src/index.tsx CHANGED
@@ -2,7 +2,6 @@ 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';
6
5
  export * from './components/Chat/Chat';
7
6
  export * from './components/Chatdeprecated/ChatDeprecated';
8
7
  export * from './components/ChatRevamp/ChatRevamp';
@@ -10,6 +9,7 @@ export * from './components/CheckButton';
10
9
  export * from './components/CheckItem';
11
10
  export * from './components/CircularController/CircularController';
12
11
  export * from './components/CraftBook/CraftBook';
12
+ export * from './components/DailyTasks/DailyTasks';
13
13
  export * from './components/DPad/JoystickDPad';
14
14
  export * from './components/DraggableContainer';
15
15
  export * from './components/Dropdown';
@@ -0,0 +1,212 @@
1
+ import { DailyTaskBlueprintChallenge, DailyTaskBlueprintRegular, ICharacterDailyTask, RewardType, TaskDifficulty, TaskStatus, TaskType } from "@rpg-engine/shared";
2
+
3
+ export const mockTasks: ICharacterDailyTask[] = [
4
+ {
5
+ key: DailyTaskBlueprintRegular.HuntRats,
6
+ name: 'Kill Rats',
7
+ description: 'Eliminate 5 rats in the forest',
8
+ type: TaskType.KillMobs,
9
+ difficulty: TaskDifficulty.Regular,
10
+ claimed: false,
11
+ status: TaskStatus.Completed,
12
+ requirements: {
13
+ type: TaskType.KillMobs,
14
+ targets: [
15
+ {
16
+ key: 'Rats',
17
+ quantity: 5
18
+ }
19
+ ]
20
+ },
21
+ progress: {
22
+ kills: { 'Rats': 5 },
23
+ },
24
+ rewards: [
25
+ {
26
+ type: RewardType.Item,
27
+ key: "angelic-sword",
28
+ texturePath: "swords/angelic-sword.png",
29
+ quantity: 50
30
+ },
31
+ {
32
+ type: RewardType.Item,
33
+ key: 'wolf-tooth-chain',
34
+ texturePath: 'accessories/wolf-tooth-chain.png',
35
+ quantity: 1
36
+ },
37
+ {
38
+ type: RewardType.Experience,
39
+ key: 'exp',
40
+ quantity: 100
41
+ }
42
+ ]
43
+ },
44
+ {
45
+ key: DailyTaskBlueprintRegular.GatherResources,
46
+ name: 'Gather Resources',
47
+ description: 'Collect 10 pieces of wood',
48
+ type: TaskType.CollectItems,
49
+ difficulty: TaskDifficulty.Regular,
50
+ requirements: {
51
+ type: TaskType.CollectItems,
52
+ targets: [
53
+ {
54
+ key: 'Wood',
55
+ quantity: 10
56
+ }
57
+ ]
58
+ },
59
+ progress: {
60
+ collected: { 'Wood': 7 },
61
+ },
62
+ rewards: [
63
+ {
64
+ type: RewardType.Gold,
65
+ key: 'gold-coin',
66
+ quantity: 100
67
+ },
68
+ {
69
+ type: RewardType.Item,
70
+ key: 'wooden-log',
71
+ texturePath: 'crafting-resources/wooden-log.png',
72
+ quantity: 10
73
+ },
74
+ {
75
+ type: RewardType.Experience,
76
+ key: 'exp',
77
+ quantity: 250
78
+ }
79
+ ],
80
+ status: TaskStatus.InProgress,
81
+ claimed: false
82
+ },
83
+ {
84
+ key: DailyTaskBlueprintChallenge.HuntEloraTheQueen,
85
+ name: 'Slay the Dragon',
86
+ description: 'Defeat the Queen Dragon',
87
+ type: TaskType.KillMobs,
88
+ difficulty: TaskDifficulty.Challenge,
89
+ requirements: {
90
+ type: TaskType.KillMobs,
91
+ targets: [
92
+ {
93
+ key: 'QueenDragon',
94
+ quantity: 1
95
+ }
96
+ ]
97
+ },
98
+ progress: {
99
+ kills: { 'QueenDragon': 0 },
100
+ },
101
+ rewards: [
102
+ {
103
+ type: RewardType.Gold,
104
+ key: 'gold-coin',
105
+ quantity: 1000
106
+ },
107
+ {
108
+ type: RewardType.Item,
109
+ key: 'dragonscale-cleaver-club',
110
+ texturePath: 'maces/dragonscale-cleaver-club.png',
111
+ quantity: 5
112
+ },
113
+ {
114
+ type: RewardType.Experience,
115
+ key: 'exp',
116
+ quantity: 1000
117
+ }
118
+ ],
119
+ status: TaskStatus.NotStarted,
120
+ claimed: false
121
+ },
122
+ {
123
+ key: DailyTaskBlueprintRegular.ExploreVillage,
124
+ name: "Village Ilya Explorer",
125
+ description: "Visit the key locations in the ilya village",
126
+ difficulty: TaskDifficulty.Regular,
127
+ type: TaskType.MapVisit,
128
+ requirements: {
129
+ type: TaskType.MapVisit,
130
+ mapKeys: ["ilya", "isle_of_origins", "ilya-village-sewer", "dungeon-ilya-01"],
131
+ },
132
+ rewards: [
133
+ {
134
+ type: RewardType.Experience,
135
+ key: 'exp',
136
+ texturePath: 'others/royal-chalice.png',
137
+ quantity: 10000
138
+ },
139
+ {
140
+ type: RewardType.Gold,
141
+ key: 'gold-coin',
142
+ quantity: 1000
143
+ },
144
+ {
145
+ type: RewardType.Item,
146
+ key: 'light-life-potion',
147
+ texturePath: 'potions/light-life-potion.png',
148
+ quantity: 20
149
+ },
150
+ {
151
+ type: RewardType.Item,
152
+ key: 'light-mana-potion',
153
+ texturePath: 'potions/light-mana-potion.png',
154
+ quantity: 20
155
+ },
156
+ ],
157
+ progress: {
158
+ visitedMaps: { 'ilya': true, 'isle_of_origins': false, 'ilya-village-sewer': false, 'dungeon-ilya-01': true },
159
+ },
160
+ status: TaskStatus.InProgress,
161
+ claimed: false
162
+ },
163
+ {
164
+ key: DailyTaskBlueprintRegular.CraftPotions,
165
+ name: 'Craft Potions',
166
+ description: 'Craft 5 health potions for the local alchemist',
167
+ type: TaskType.CraftItems,
168
+ difficulty: TaskDifficulty.Regular,
169
+ requirements: {
170
+ type: TaskType.CraftItems,
171
+ targets: [
172
+ {
173
+ key: 'life-potion',
174
+ quantity: 5
175
+ }
176
+ ],
177
+ materials: [
178
+ {
179
+ key: 'foods/apple.png',
180
+ quantity: 10
181
+ },
182
+ {
183
+ key: 'foods/banana.png',
184
+ quantity: 5
185
+ }
186
+ ]
187
+ },
188
+ progress: {
189
+ crafted: { 'life-potion': 2 },
190
+ },
191
+ rewards: [
192
+ {
193
+ type: RewardType.Item,
194
+ key: 'light-mana-potion',
195
+ texturePath: 'potions/light-mana-potion.png',
196
+ quantity: 10
197
+ },
198
+ {
199
+ type: RewardType.Gold,
200
+ key: 'gold-coin',
201
+ quantity: 150
202
+ },
203
+ {
204
+ type: RewardType.Experience,
205
+ key: 'exp',
206
+ quantity: 200
207
+ }
208
+ ],
209
+ status: TaskStatus.InProgress,
210
+ claimed: false
211
+ },
212
+ ];