@rpg-engine/long-bow 0.2.6 → 0.2.8

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.
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { IQuestListProps } from '../components/QuestList';
3
+ declare const _default: {
4
+ title: string;
5
+ component: React.FC<IQuestListProps>;
6
+ };
7
+ export default _default;
8
+ export declare const Default: import("@storybook/csf").AnnotatedStoryFn<import("@storybook/react").ReactFramework, IQuestListProps>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpg-engine/long-bow",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -56,11 +56,11 @@
56
56
  "devDependencies": {
57
57
  "@babel/core": "^7.17.7",
58
58
  "@size-limit/preset-small-lib": "^7.0.8",
59
- "@storybook/addon-essentials": "^6.5.9",
59
+ "@storybook/addon-essentials": "^6.5.10",
60
60
  "@storybook/addon-info": "^5.3.21",
61
- "@storybook/addon-links": "^6.5.9",
62
- "@storybook/addons": "^6.5.9",
63
- "@storybook/react": "^6.5.9",
61
+ "@storybook/addon-links": "^6.5.10",
62
+ "@storybook/addons": "^6.5.10",
63
+ "@storybook/react": "^6.5.10",
64
64
  "@types/react": "^18.0.14",
65
65
  "@types/react-dom": "^18.0.5",
66
66
  "@types/styled-components": "^5.1.24",
@@ -83,7 +83,7 @@
83
83
  },
84
84
  "dependencies": {
85
85
  "@rollup/plugin-image": "^2.1.1",
86
- "@rpg-engine/shared": "^0.4.31",
86
+ "@rpg-engine/shared": "^0.4.40",
87
87
  "dayjs": "^1.11.2",
88
88
  "fs-extra": "^10.1.0",
89
89
  "lodash": "^4.17.21",
@@ -10,55 +10,49 @@ import PropertySelect, {
10
10
  } from '../PropertySelect/PropertySelect';
11
11
 
12
12
  export interface ICharacterProps {
13
- id: string;
14
13
  name: string;
15
- spriteKey: string;
14
+ textureKey: string;
16
15
  }
17
16
 
18
17
  export interface ICharacterSelectionProps {
19
18
  availableCharacters: ICharacterProps[];
20
- onChange: (characterSpriteKey: string) => void;
19
+ onChange: (textureKey: string) => void;
21
20
  }
22
21
 
23
22
  export const CharacterSelection: React.FC<ICharacterSelectionProps> = ({
24
23
  availableCharacters,
25
24
  onChange,
26
25
  }) => {
27
- const getPropertySelectValues = () => {
28
- return availableCharacters.map(item => {
29
- return {
30
- id: item.id,
31
- name: item.name,
32
- };
33
- });
34
- };
35
-
36
- const [propertySelectValues] = useState<IPropertiesProps[]>(
37
- getPropertySelectValues()
38
- );
26
+ const propertySelectValues = availableCharacters.map(item => {
27
+ return {
28
+ id: item.textureKey,
29
+ name: item.name,
30
+ };
31
+ });
39
32
 
33
+ const [selectedValue, setSelectedValue] = useState<IPropertiesProps>();
40
34
  const [selectedSpriteKey, setSelectedSpriteKey] = useState('');
41
- const [selectedValue, setSelectedValue] = useState<IPropertiesProps>(
42
- propertySelectValues[0]
43
- );
44
-
45
- const getSelectedCharacterSpriteKey = () => {
46
- const character = availableCharacters.filter(
47
- item => item.id === selectedValue.id
48
- )[0];
49
- return character ? character.spriteKey : '';
50
- };
51
35
 
52
36
  const onSelectedValueChange = () => {
53
- const spriteKey = getSelectedCharacterSpriteKey();
37
+ const textureKey = selectedValue ? selectedValue.id : '';
38
+ const spriteKey = textureKey ? textureKey + '/down/standing/0.png' : '';
39
+
40
+ if (spriteKey == selectedSpriteKey) {
41
+ return;
42
+ }
43
+
54
44
  setSelectedSpriteKey(spriteKey);
55
- onChange(spriteKey);
45
+ onChange(textureKey);
56
46
  };
57
47
 
58
48
  useEffect(() => {
59
49
  onSelectedValueChange();
60
50
  }, [selectedValue]);
61
51
 
52
+ useEffect(() => {
53
+ setSelectedValue(propertySelectValues[0]);
54
+ }, [availableCharacters]);
55
+
62
56
  return (
63
57
  <Container>
64
58
  {selectedSpriteKey && (
@@ -70,7 +64,7 @@ export const CharacterSelection: React.FC<ICharacterSelectionProps> = ({
70
64
  height={50}
71
65
  width={50}
72
66
  containerStyle={{
73
- padding: '25px 10px 5px 28px',
67
+ padding: '25px 10px 5px 27px',
74
68
  }}
75
69
  />
76
70
  )}
@@ -83,9 +83,23 @@ export const ItemSlot: React.FC<IProps> = observer(
83
83
  return '2.5rem';
84
84
  };
85
85
 
86
+ const getStackInfo = (itemId: string, stackQty: number) => {
87
+ // if (itemToRender?.isStackable && itemToRender?.stackQty) {
88
+ if (stackQty > 1) {
89
+ return (
90
+ <ItemQty left={getLeftPositionValue(stackQty)} key={`qty-${itemId}`}>
91
+ {' '}
92
+ {stackQty}{' '}
93
+ </ItemQty>
94
+ );
95
+ }
96
+ return undefined;
97
+ };
98
+
86
99
  const renderItem = (itemToRender: IItem | null) => {
87
100
  const element = [];
88
101
  if (itemToRender?.texturePath) {
102
+ console.table(itemToRender);
89
103
  element.push(
90
104
  <SpriteFromAtlas
91
105
  key={itemToRender._id}
@@ -96,17 +110,14 @@ export const ItemSlot: React.FC<IProps> = observer(
96
110
  />
97
111
  );
98
112
  }
99
- if (itemToRender?.isStackable && itemToRender?.stackQty) {
100
- element.push(
101
- <ItemQty
102
- left={getLeftPositionValue(itemToRender.stackQty)}
103
- key={`qty-${itemToRender._id}`}
104
- >
105
- {' '}
106
- {itemToRender.stackQty}{' '}
107
- </ItemQty>
108
- );
113
+ const stackInfo = getStackInfo(
114
+ itemToRender?._id ?? '',
115
+ itemToRender?.stackQty ?? 0
116
+ );
117
+ if (stackInfo) {
118
+ element.push(stackInfo);
109
119
  }
120
+
110
121
  return element;
111
122
  };
112
123
 
@@ -115,7 +126,8 @@ export const ItemSlot: React.FC<IProps> = observer(
115
126
  itemToRender?.texturePath &&
116
127
  itemToRender.allowedEquipSlotType?.includes(slotSpriteMask!)
117
128
  ) {
118
- return (
129
+ const element = [];
130
+ element.push(
119
131
  <SpriteFromAtlas
120
132
  key={itemToRender._id}
121
133
  atlasIMG={atlasIMG}
@@ -124,6 +136,14 @@ export const ItemSlot: React.FC<IProps> = observer(
124
136
  imgScale={3}
125
137
  />
126
138
  );
139
+ const stackInfo = getStackInfo(
140
+ itemToRender?._id ?? '',
141
+ itemToRender?.stackQty ?? 0
142
+ );
143
+ if (stackInfo) {
144
+ element.push(stackInfo);
145
+ }
146
+ return element;
127
147
  } else {
128
148
  return (
129
149
  <SpriteFromAtlas
@@ -37,10 +37,18 @@ export const PropertySelect: React.FC<IPropertySelectProps> = ({
37
37
  onChange(availableProperties[currentIndex]);
38
38
  }, [currentIndex]);
39
39
 
40
+ const getCurrentSelectionName = () => {
41
+ const item = availableProperties[currentIndex];
42
+ if (item) {
43
+ return item.name;
44
+ }
45
+ return '';
46
+ };
47
+
40
48
  return (
41
49
  <Container>
42
50
  <TextOverlay>
43
- <Item>{availableProperties[currentIndex].name}</Item>
51
+ <Item>{getCurrentSelectionName()}</Item>
44
52
  </TextOverlay>
45
53
  <div className="rpgui-progress-track"></div>
46
54
  <LeftArrow onClick={onLeftClick}></LeftArrow>
@@ -1,33 +1,45 @@
1
- import React from 'react';
1
+ import { IQuest } from '@rpg-engine/shared';
2
+ import React, { useState } from 'react';
2
3
  import styled from 'styled-components';
3
4
  import { Button, ButtonTypes } from '../Button';
4
5
  import { DraggableContainer } from '../DraggableContainer';
6
+ import LeftArrowClickIcon from '../PropertySelect/img/ui-arrows/arrow01-left-clicked.png';
7
+ import LeftArrowIcon from '../PropertySelect/img/ui-arrows/arrow01-left.png';
8
+ import RightArrowClickIcon from '../PropertySelect/img/ui-arrows/arrow01-right-clicked.png';
9
+ import RightArrowIcon from '../PropertySelect/img/ui-arrows/arrow01-right.png';
5
10
  import { RPGUIContainerTypes } from '../RPGUIContainer';
6
11
  import { Column } from '../shared/Column';
7
-
8
12
  import thumbnailDefault from './img/default.png';
9
13
 
10
14
  export interface IQuestInfoProps {
11
- title: string;
12
- children: React.ReactNode;
13
15
  onClose?: () => void;
14
- button?: Array<IQuestButtonProps>;
15
- thumbnail?: string;
16
+ button?: Array<IQuestsButtonProps>;
17
+ quests: IQuest[];
16
18
  }
17
19
 
18
- export interface IQuestButtonProps {
20
+ export interface IQuestsButtonProps {
19
21
  disabled: boolean;
20
22
  title: string;
21
- onClick: () => void;
23
+ onClick: (QuestId: string, NPCId: string) => void;
22
24
  }
23
25
 
24
26
  export const QuestInfo: React.FC<IQuestInfoProps> = ({
25
- title,
27
+ quests,
26
28
  onClose,
27
29
  button,
28
- thumbnail,
29
- children,
30
30
  }) => {
31
+ const [currentIndex, setCurrentIndex] = useState(0);
32
+ const questsLength = quests.length - 1;
33
+
34
+ const onLeftClick = () => {
35
+ if (currentIndex === 0) setCurrentIndex(questsLength);
36
+ else setCurrentIndex(index => index - 1);
37
+ };
38
+ const onRightClick = () => {
39
+ if (currentIndex === questsLength) setCurrentIndex(0);
40
+ else setCurrentIndex(index => index + 1);
41
+ };
42
+
31
43
  return (
32
44
  <QuestDraggableContainer
33
45
  type={RPGUIContainerTypes.Framed}
@@ -37,32 +49,81 @@ export const QuestInfo: React.FC<IQuestInfoProps> = ({
37
49
  width="730px"
38
50
  cancelDrag=".equipment-container-body"
39
51
  >
40
- {title && (
41
- <TitleContainer className="drag-handler">
42
- <Title>
43
- <Thumbnail src={thumbnail || thumbnailDefault} />
44
- {title}
45
- </Title>
46
- <QuestSplitDiv>
47
- <hr className="golden" />
48
- </QuestSplitDiv>
49
- </TitleContainer>
52
+ {quests.length >= 2 ? (
53
+ <QuestsContainer>
54
+ {currentIndex !== 0 && <LeftArrow onClick={onLeftClick}></LeftArrow>}
55
+ {currentIndex !== quests.length - 1 && (
56
+ <RightArrow onClick={onRightClick}></RightArrow>
57
+ )}
58
+
59
+ <QuestContainer>
60
+ <TitleContainer className="drag-handler">
61
+ <Title>
62
+ <Thumbnail
63
+ src={quests[currentIndex].thumbnail || thumbnailDefault}
64
+ />
65
+ {quests[currentIndex].title}
66
+ </Title>
67
+ <QuestSplitDiv>
68
+ <hr className="golden" />
69
+ </QuestSplitDiv>
70
+ </TitleContainer>
71
+ <Content>
72
+ <p>{quests[currentIndex].description}</p>
73
+ </Content>
74
+ <QuestColumn className="dark-background" justifyContent="flex-end">
75
+ {button &&
76
+ button.map((item, index) => (
77
+ <Button
78
+ key={index}
79
+ onClick={() =>
80
+ item.onClick(
81
+ quests[currentIndex]._id,
82
+ quests[currentIndex].npcId
83
+ )
84
+ }
85
+ disabled={item.disabled}
86
+ buttonType={ButtonTypes.RPGUIButton}
87
+ id={`button-${index}`}
88
+ >
89
+ {item.title}
90
+ </Button>
91
+ ))}
92
+ </QuestColumn>
93
+ </QuestContainer>
94
+ </QuestsContainer>
95
+ ) : (
96
+ <QuestsContainer>
97
+ <QuestContainer>
98
+ <TitleContainer className="drag-handler">
99
+ <Title>
100
+ <Thumbnail src={quests[0].thumbnail || thumbnailDefault} />
101
+ {quests[0].title}
102
+ </Title>
103
+ <QuestSplitDiv>
104
+ <hr className="golden" />
105
+ </QuestSplitDiv>
106
+ </TitleContainer>
107
+ <Content>
108
+ <p>{quests[0].description}</p>
109
+ </Content>
110
+ <QuestColumn className="dark-background" justifyContent="flex-end">
111
+ {button &&
112
+ button.map((item, index) => (
113
+ <Button
114
+ key={index}
115
+ onClick={() => item.onClick(quests[0]._id, quests[0].npcId)}
116
+ disabled={item.disabled}
117
+ buttonType={ButtonTypes.RPGUIButton}
118
+ id={`button-${index}`}
119
+ >
120
+ {item.title}
121
+ </Button>
122
+ ))}
123
+ </QuestColumn>
124
+ </QuestContainer>
125
+ </QuestsContainer>
50
126
  )}
51
- <Content>{children}</Content>
52
- <QuestColumn className="dark-background" justifyContent="flex-end">
53
- {button &&
54
- button.map((item, index) => (
55
- <Button
56
- key={index}
57
- onClick={item.onClick}
58
- disabled={item.disabled}
59
- buttonType={ButtonTypes.RPGUIButton}
60
- id={`button-${index}`}
61
- >
62
- {item.title}
63
- </Button>
64
- ))}
65
- </QuestColumn>
66
127
  </QuestDraggableContainer>
67
128
  );
68
129
  };
@@ -71,7 +132,6 @@ const QuestDraggableContainer = styled(DraggableContainer)`
71
132
  border: 1px solid black;
72
133
  width: 600px;
73
134
  height: 500px;
74
- overflow-y: scroll;
75
135
  padding: 0 0 0 0 !important;
76
136
  .DraggableContainer__TitleContainer-sc-184mpyl-2 {
77
137
  height: auto;
@@ -79,7 +139,7 @@ const QuestDraggableContainer = styled(DraggableContainer)`
79
139
  .container-close {
80
140
  position: sticky;
81
141
  margin-left: auto;
82
- top: 10px;
142
+ top: 20px;
83
143
  padding-right: 5px;
84
144
  }
85
145
  img {
@@ -89,6 +149,16 @@ const QuestDraggableContainer = styled(DraggableContainer)`
89
149
  }
90
150
  `;
91
151
 
152
+ const QuestContainer = styled.div`
153
+ margin-right: 40px;
154
+ margin-left: 40px;
155
+ `;
156
+
157
+ const QuestsContainer = styled.div`
158
+ display: flex;
159
+ align-items: center;
160
+ `;
161
+
92
162
  const Content = styled.div`
93
163
  padding: 18px;
94
164
  h1 {
@@ -113,14 +183,13 @@ const QuestSplitDiv = styled.div`
113
183
  const QuestColumn = styled(Column)`
114
184
  background: #4e4a4e;
115
185
  padding-top: 5px;
116
- position: sticky;
117
- bottom: 0;
186
+ margin-bottom: 20px;
187
+ display: flex;
188
+ justify-content: space-evenly;
118
189
  `;
119
190
 
120
191
  const TitleContainer = styled.div`
121
192
  background: #4e4a4e;
122
- position: sticky;
123
- top: 0;
124
193
  width: 100%;
125
194
  display: flex;
126
195
  flex-wrap: wrap;
@@ -141,3 +210,27 @@ const Thumbnail = styled.img`
141
210
  width: 64px;
142
211
  margin-right: 0.5rem;
143
212
  `;
213
+
214
+ const LeftArrow = styled.div`
215
+ background-image: url(${LeftArrowIcon});
216
+ background-size: 100% 100%;
217
+ left: 0;
218
+ position: absolute;
219
+ width: 40px;
220
+ height: 42px;
221
+ :active {
222
+ background-image: url(${LeftArrowClickIcon});
223
+ }
224
+ `;
225
+
226
+ const RightArrow = styled.div`
227
+ background-image: url(${RightArrowIcon});
228
+ right: 0;
229
+ position: absolute;
230
+ width: 40px;
231
+ background-size: 100% 100%;
232
+ height: 42px;
233
+ :active {
234
+ background-image: url(${RightArrowClickIcon});
235
+ }
236
+ `;
@@ -0,0 +1,124 @@
1
+ import React, { useLayoutEffect, useState } from 'react';
2
+ import styled from 'styled-components';
3
+ import { DraggableContainer } from './DraggableContainer';
4
+ import { ProgressBar } from './ProgressBar';
5
+ import { RPGUIContainerTypes } from './RPGUIContainer';
6
+
7
+ export interface IQuestListProps {
8
+ title: string;
9
+ description: string;
10
+ quests: { title: string; description: string; completed: boolean }[];
11
+ }
12
+
13
+ export const QuestList: React.FC<IQuestListProps> = ({ quests }) => {
14
+ const [completedQuestsPercentage, setCompletedQuestsPercentage] = useState(0);
15
+
16
+ useLayoutEffect(() => {
17
+ const totalQuests = quests.length;
18
+ const completedQuests = quests.filter(({ completed }) => completed).length;
19
+
20
+ const percentage = Math.floor((completedQuests / totalQuests) * 100);
21
+
22
+ setCompletedQuestsPercentage(percentage);
23
+ }, []);
24
+
25
+ return (
26
+ <QuestDraggableContainer
27
+ type={RPGUIContainerTypes.Framed}
28
+ onCloseButton={() => {}}
29
+ width="520px"
30
+ >
31
+ <div style={{ width: '100%' }}>
32
+ <Title>Quests</Title>
33
+ <hr className="golden" />
34
+
35
+ <QuestListContainer>
36
+ {quests.map(({ title, description, completed }, i) => (
37
+ <div className="quest-item" key={i}>
38
+ <span className={`quest-number ${completed ? 'completed' : ''}`}>
39
+ {i + 1}
40
+ </span>
41
+ <div className="quest-detail">
42
+ <p className="quest-detail__title">{title}</p>
43
+ <p className="quest-detail__description">{description}</p>
44
+ </div>
45
+ </div>
46
+ ))}
47
+ </QuestListContainer>
48
+
49
+ <ProgressBar max={100} value={completedQuestsPercentage} color="blue" />
50
+ </div>
51
+ </QuestDraggableContainer>
52
+ );
53
+ };
54
+
55
+ const QuestDraggableContainer = styled(DraggableContainer)`
56
+ .container-close {
57
+ top: 10px;
58
+ right: 10px;
59
+ }
60
+
61
+ .quest-title {
62
+ text-align: left;
63
+ margin-left: 44px;
64
+ margin-top: 20px;
65
+ color: yellow;
66
+ }
67
+
68
+ .quest-desc {
69
+ margin-top: 12px;
70
+ margin-left: 44px;
71
+ }
72
+
73
+ .rpgui-progress {
74
+ min-width: 80%;
75
+ margin: 0 auto;
76
+ }
77
+ `;
78
+
79
+ const Title = styled.h1`
80
+ z-index: 22;
81
+ font-size: 0.6rem;
82
+ color: yellow !important;
83
+ `;
84
+
85
+ const QuestListContainer = styled.div`
86
+ margin-top: 20px;
87
+ margin-bottom: 40px;
88
+ overflow-y: auto;
89
+ max-height: 400px;
90
+
91
+ .quest-item {
92
+ display: flex;
93
+ align-items: flex-start;
94
+ margin-bottom: 12px;
95
+ }
96
+
97
+ .quest-number {
98
+ border-radius: 50%;
99
+ width: 28px;
100
+ height: 28px;
101
+ display: flex;
102
+ align-items: center;
103
+ justify-content: center;
104
+ margin-right: 16px;
105
+ background-color: brown;
106
+ flex-shrink: 0;
107
+ }
108
+
109
+ .quest-number.completed {
110
+ background-color: yellow;
111
+ }
112
+
113
+ p {
114
+ margin: 0;
115
+ }
116
+
117
+ .quest-detail__title {
118
+ color: yellow;
119
+ }
120
+
121
+ .quest-detail__description {
122
+ margin-top: 5px;
123
+ }
124
+ `;
@@ -78,7 +78,7 @@ export const items: any = {
78
78
  isEquipable: false,
79
79
  isStackable: false,
80
80
  maxStackSize: 99,
81
- stackQty: 3,
81
+
82
82
  isUsable: true,
83
83
  isStorable: true,
84
84
  layer: 1,
@@ -140,7 +140,6 @@ export const items: any = {
140
140
  isEquipable: false,
141
141
  isStackable: false,
142
142
  maxStackSize: 999,
143
- stackQty: 171,
144
143
  isUsable: true,
145
144
  isStorable: true,
146
145
  layer: 1,
@@ -171,7 +170,7 @@ export const items: any = {
171
170
  isEquipable: false,
172
171
  isStackable: false,
173
172
  maxStackSize: 999,
174
- stackQty: 32,
173
+
175
174
  isUsable: false,
176
175
  isStorable: true,
177
176
  layer: 1,
@@ -202,7 +201,7 @@ export const items: any = {
202
201
  isEquipable: false,
203
202
  isStackable: false,
204
203
  maxStackSize: 999,
205
- stackQty: 32,
204
+
206
205
  isUsable: false,
207
206
  isStorable: true,
208
207
  layer: 1,
@@ -233,7 +232,7 @@ export const items: any = {
233
232
  isEquipable: false,
234
233
  isStackable: false,
235
234
  maxStackSize: 999,
236
- stackQty: 32,
235
+
237
236
  isUsable: false,
238
237
  isStorable: true,
239
238
  layer: 1,
@@ -264,7 +263,6 @@ export const items: any = {
264
263
  isEquipable: false,
265
264
  isStackable: false,
266
265
  maxStackSize: 999,
267
- stackQty: 171,
268
266
  isUsable: true,
269
267
  isStorable: true,
270
268
  layer: 1,