@rpg-engine/long-bow 0.3.95 → 0.3.97

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpg-engine/long-bow",
3
- "version": "0.3.95",
3
+ "version": "0.3.97",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -83,7 +83,7 @@
83
83
  },
84
84
  "dependencies": {
85
85
  "@rollup/plugin-image": "^2.1.1",
86
- "@rpg-engine/shared": "^0.7.51",
86
+ "@rpg-engine/shared": "^0.7.82",
87
87
  "dayjs": "^1.11.2",
88
88
  "font-awesome": "^4.7.0",
89
89
  "fs-extra": "^10.1.0",
@@ -11,6 +11,7 @@ import styled from 'styled-components';
11
11
  import { uiColors } from '../../constants/uiColors';
12
12
  import { SpriteFromAtlas } from '../shared/SpriteFromAtlas';
13
13
  import { SingleShortcut } from '../Shortcuts/SingleShortcut';
14
+ import { useShortcutCooldown } from '../Shortcuts/useShortcutCooldown';
14
15
 
15
16
  export type CircularControllerProps = {
16
17
  onActionClick: () => void;
@@ -21,6 +22,7 @@ export type CircularControllerProps = {
21
22
  inventory?: IItemContainer | null;
22
23
  atlasIMG: any;
23
24
  atlasJSON: any;
25
+ spellCooldowns?: Record<string, number>;
24
26
  };
25
27
 
26
28
  export const CircularController: React.FC<CircularControllerProps> = ({
@@ -32,7 +34,12 @@ export const CircularController: React.FC<CircularControllerProps> = ({
32
34
  inventory,
33
35
  atlasIMG,
34
36
  atlasJSON,
37
+ spellCooldowns,
35
38
  }) => {
39
+ const { handleShortcutCast, shortcutCooldown } = useShortcutCooldown(
40
+ onShortcutClick
41
+ );
42
+
36
43
  const onTouchStart = (e: React.TouchEvent<HTMLButtonElement>) => {
37
44
  const target = e.target as HTMLButtonElement;
38
45
  target?.classList.add('active');
@@ -50,6 +57,10 @@ export const CircularController: React.FC<CircularControllerProps> = ({
50
57
  };
51
58
 
52
59
  const renderShortcut = (i: number) => {
60
+ const buildClassName = (classBase: string, isOnCooldown: boolean) => {
61
+ return `${classBase} ${isOnCooldown ? 'onCooldown' : ''}`;
62
+ };
63
+
53
64
  let variant = '';
54
65
 
55
66
  if (i === 0) variant = 'top';
@@ -57,9 +68,11 @@ export const CircularController: React.FC<CircularControllerProps> = ({
57
68
 
58
69
  const onShortcutClickBinded =
59
70
  shortcuts[i]?.type !== ShortcutType.None
60
- ? onShortcutClick.bind(null, i)
71
+ ? handleShortcutCast.bind(null, i)
61
72
  : () => {};
62
73
 
74
+ const isOnShortcutCooldown = shortcutCooldown > 0;
75
+
63
76
  if (shortcuts[i]?.type === ShortcutType.Item) {
64
77
  const payload = shortcuts[i]?.payload as IItem | undefined;
65
78
 
@@ -88,6 +101,9 @@ export const CircularController: React.FC<CircularControllerProps> = ({
88
101
  disabled={false}
89
102
  className={variant}
90
103
  >
104
+ {isOnShortcutCooldown && (
105
+ <span className="cooldown">{shortcutCooldown.toFixed(1)}</span>
106
+ )}
91
107
  {payload && (
92
108
  <SpriteFromAtlas
93
109
  atlasIMG={atlasIMG}
@@ -108,13 +124,23 @@ export const CircularController: React.FC<CircularControllerProps> = ({
108
124
  containerStyle={{ pointerEvents: 'none' }}
109
125
  />
110
126
  )}
111
- <span className="qty">{totalQty}</span>
127
+ <span className={buildClassName('qty', isOnShortcutCooldown)}>
128
+ {totalQty}
129
+ </span>
112
130
  </StyledShortcut>
113
131
  );
114
132
  }
115
133
 
116
134
  const payload = shortcuts[i]?.payload as IRawSpell | undefined;
117
135
 
136
+ const spellCooldown = !payload
137
+ ? 0
138
+ : spellCooldowns?.[payload.magicWords.replaceAll(' ', '_')] ??
139
+ shortcutCooldown;
140
+ const cooldown =
141
+ spellCooldown > shortcutCooldown ? spellCooldown : shortcutCooldown;
142
+ const isOnCooldown = cooldown > 0 && !!payload;
143
+
118
144
  return (
119
145
  <StyledShortcut
120
146
  key={i}
@@ -123,7 +149,14 @@ export const CircularController: React.FC<CircularControllerProps> = ({
123
149
  disabled={mana < (payload?.manaCost ?? 0)}
124
150
  className={variant}
125
151
  >
126
- <span className="mana">{payload && payload.manaCost}</span>
152
+ {isOnCooldown && (
153
+ <span className="cooldown">
154
+ {cooldown.toFixed(cooldown < 10 ? 1 : 0)}
155
+ </span>
156
+ )}
157
+ <span className={buildClassName('mana', isOnCooldown)}>
158
+ {payload && payload.manaCost}
159
+ </span>
127
160
  <span className="magicWords">
128
161
  {payload?.magicWords.split(' ').map(word => word[0])}
129
162
  </span>
@@ -99,6 +99,16 @@ export const ItemInfo: React.FC<IItemInfoProps> = ({
99
99
  return statistics;
100
100
  };
101
101
 
102
+ const renderEntityEffects = () => {
103
+ if (!item.entityEffects || !item.entityEffectChance) return null;
104
+
105
+ return item.entityEffects.map((effect, index) => (
106
+ <Statistic key={index} $isSpecial>
107
+ {effect[0].toUpperCase() + effect.slice(1)} ({item.entityEffectChance}%)
108
+ </Statistic>
109
+ ));
110
+ };
111
+
102
112
  const renderAvaibleSlots = () => {
103
113
  if (!item.allowedEquipSlotType) return null;
104
114
 
@@ -130,8 +140,28 @@ export const ItemInfo: React.FC<IItemInfoProps> = ({
130
140
  <AllowedSlots>{renderAvaibleSlots()}</AllowedSlots>
131
141
  </Header>
132
142
 
143
+ {item.minRequirements && (
144
+ <LevelRequirement>
145
+ <div className="title">Requirements:</div>
146
+ <div>- Level: {item.minRequirements.level}</div>
147
+ <div>
148
+ -{' '}
149
+ {item.minRequirements.skill.name[0].toUpperCase() +
150
+ item.minRequirements.skill.name.slice(1)}
151
+ : {item.minRequirements.skill.level}
152
+ </div>
153
+ </LevelRequirement>
154
+ )}
155
+
133
156
  {renderStatistics()}
134
- {item.isTwoHanded && <Statistic>Two handed</Statistic>}
157
+ {renderEntityEffects()}
158
+ {item.usableEffectDescription && (
159
+ <Statistic $isSpecial>{item.usableEffectDescription}</Statistic>
160
+ )}
161
+ {item.equippedBuffDescription && (
162
+ <Statistic $isSpecial>{item.equippedBuffDescription}</Statistic>
163
+ )}
164
+ {item.isTwoHanded && <Statistic $isSpecial>Two handed</Statistic>}
135
165
 
136
166
  <Description>{item.description}</Description>
137
167
 
@@ -159,9 +189,9 @@ const Container = styled.div<{ item: IItem }>`
159
189
  font-size: ${uiFonts.size.small};
160
190
  border: 3px solid ${({ item }) => rarityColor(item) ?? uiColors.lightGray};
161
191
  height: max-content;
162
- width: 15rem;
192
+ width: 18rem;
163
193
 
164
- @media (max-width: 580px) {
194
+ @media (max-width: 640px) {
165
195
  width: 80vw;
166
196
  }
167
197
  `;
@@ -189,9 +219,25 @@ const Type = styled.div`
189
219
  color: ${uiColors.lightGray};
190
220
  `;
191
221
 
192
- const Statistic = styled.div`
222
+ const LevelRequirement = styled.div`
223
+ font-size: ${uiFonts.size.small};
224
+ margin-top: 0.2rem;
225
+ margin-bottom: 1rem;
226
+ color: ${uiColors.orange};
227
+
228
+ .title {
229
+ margin-bottom: 4px;
230
+ }
231
+
232
+ div {
233
+ margin-bottom: 2px;
234
+ }
235
+ `;
236
+
237
+ const Statistic = styled.div<{ $isSpecial?: boolean }>`
193
238
  margin-bottom: 0.4rem;
194
- width: max-content;
239
+ width: 100%;
240
+ color: ${({ $isSpecial }) => ($isSpecial ? uiColors.darkYellow : 'inherit')};
195
241
 
196
242
  .label {
197
243
  display: inline-block;
@@ -66,7 +66,13 @@ export const ItemInfoDisplay: React.FC<IItemInfoDisplayProps> = ({
66
66
  itemSubTypeCamelCase
67
67
  );
68
68
 
69
- const itemFromEquipment = equipmentSet[slotType] as IItem;
69
+ const itemSubTypeFromEquipment = Object.values(equipmentSet).find(
70
+ item => camelCase(item?.subType ?? '') === itemSubTypeCamelCase
71
+ );
72
+
73
+ const itemFromEquipment = itemSubTypeFromEquipment
74
+ ? itemSubTypeFromEquipment
75
+ : (equipmentSet[slotType] as IItem);
70
76
 
71
77
  if (
72
78
  itemFromEquipment &&
@@ -109,8 +115,9 @@ const Flex = styled.div<{ $isMobile?: boolean }>`
109
115
  display: flex;
110
116
  gap: 0.5rem;
111
117
  flex-direction: ${({ $isMobile }) => ($isMobile ? 'row-reverse' : 'row')};
118
+ align-items: center;
112
119
 
113
- @media (max-width: 580px) {
120
+ @media (max-width: 640px) {
114
121
  flex-direction: column-reverse;
115
122
  align-items: center;
116
123
  }
@@ -113,7 +113,7 @@ const Container = styled.div<{ scale: number }>`
113
113
  animation: fadeOut 0.1s forwards;
114
114
  }
115
115
 
116
- @media (max-width: 580px) {
116
+ @media (max-width: 640px) {
117
117
  flex-direction: column;
118
118
  }
119
119
  `;
@@ -124,7 +124,7 @@ const OptionsContainer = styled.div`
124
124
  gap: 0.5rem;
125
125
  flex-wrap: wrap;
126
126
 
127
- @media (max-width: 580px) {
127
+ @media (max-width: 640px) {
128
128
  flex-direction: row;
129
129
  justify-content: center;
130
130
  }
@@ -143,7 +143,7 @@ const Option = styled.button`
143
143
  background-color: #555;
144
144
  }
145
145
 
146
- @media (max-width: 580px) {
146
+ @media (max-width: 640px) {
147
147
  padding: 1rem 0.5rem;
148
148
  }
149
149
  `;
@@ -12,6 +12,7 @@ import { uiColors } from '../../constants/uiColors';
12
12
  import { countItemFromInventory } from '../../libs/itemCounter';
13
13
  import { SpriteFromAtlas } from '../shared/SpriteFromAtlas';
14
14
  import { SingleShortcut } from './SingleShortcut';
15
+ import { useShortcutCooldown } from './useShortcutCooldown';
15
16
 
16
17
  export type ShortcutsProps = {
17
18
  shortcuts: IShortcut[];
@@ -21,6 +22,7 @@ export type ShortcutsProps = {
21
22
  inventory?: IItemContainer | null;
22
23
  atlasJSON: any;
23
24
  atlasIMG: any;
25
+ spellCooldowns?: Record<string, number>;
24
26
  };
25
27
 
26
28
  export const Shortcuts: React.FC<ShortcutsProps> = ({
@@ -31,16 +33,21 @@ export const Shortcuts: React.FC<ShortcutsProps> = ({
31
33
  atlasJSON,
32
34
  atlasIMG,
33
35
  inventory,
36
+ spellCooldowns,
34
37
  }) => {
35
38
  const shortcutsRefs = useRef<HTMLButtonElement[]>([]);
36
39
 
40
+ const { handleShortcutCast, shortcutCooldown } = useShortcutCooldown(
41
+ onShortcutCast
42
+ );
43
+
37
44
  useEffect(() => {
38
45
  const handleKeyDown = (e: KeyboardEvent) => {
39
46
  if (isBlockedCastingByKeyboard) return;
40
47
 
41
48
  const shortcutIndex = Number(e.key) - 1;
42
49
  if (shortcutIndex >= 0 && shortcutIndex <= 5) {
43
- onShortcutCast(shortcutIndex);
50
+ handleShortcutCast(shortcutIndex);
44
51
  shortcutsRefs.current[shortcutIndex]?.classList.add('active');
45
52
  setTimeout(() => {
46
53
  shortcutsRefs.current[shortcutIndex]?.classList.remove('active');
@@ -53,11 +60,17 @@ export const Shortcuts: React.FC<ShortcutsProps> = ({
53
60
  return () => {
54
61
  window.removeEventListener('keydown', handleKeyDown);
55
62
  };
56
- }, [shortcuts, isBlockedCastingByKeyboard]);
63
+ }, [shortcuts, isBlockedCastingByKeyboard, shortcutCooldown]);
57
64
 
58
65
  return (
59
66
  <List>
60
67
  {Array.from({ length: 6 }).map((_, i) => {
68
+ const buildClassName = (classBase: string, isOnCooldown: boolean) => {
69
+ return `${classBase} ${isOnCooldown ? 'onCooldown' : ''}`;
70
+ };
71
+
72
+ const isOnShortcutCooldown = shortcutCooldown > 0;
73
+
61
74
  if (shortcuts[i]?.type === ShortcutType.Item) {
62
75
  const payload = shortcuts[i]?.payload as IItem | undefined;
63
76
 
@@ -81,12 +94,15 @@ export const Shortcuts: React.FC<ShortcutsProps> = ({
81
94
  return (
82
95
  <StyledShortcut
83
96
  key={i}
84
- onPointerDown={onShortcutCast.bind(null, i)}
97
+ onPointerDown={handleShortcutCast.bind(null, i)}
85
98
  disabled={false}
86
99
  ref={el => {
87
100
  if (el) shortcutsRefs.current[i] = el;
88
101
  }}
89
102
  >
103
+ {isOnShortcutCooldown && (
104
+ <span className="cooldown">{shortcutCooldown.toFixed(1)}</span>
105
+ )}
90
106
  {payload && (
91
107
  <SpriteFromAtlas
92
108
  atlasIMG={atlasIMG}
@@ -104,28 +120,51 @@ export const Shortcuts: React.FC<ShortcutsProps> = ({
104
120
  height={32}
105
121
  />
106
122
  )}
107
- <span className="qty">{totalQty}</span>
108
- <span className="keyboard">{i + 1}</span>
123
+ <span className={buildClassName('qty', isOnShortcutCooldown)}>
124
+ {totalQty}
125
+ </span>
126
+ <span
127
+ className={buildClassName('keyboard', isOnShortcutCooldown)}
128
+ >
129
+ {i + 1}
130
+ </span>
109
131
  </StyledShortcut>
110
132
  );
111
133
  }
112
134
 
113
135
  const payload = shortcuts[i]?.payload as IRawSpell | undefined;
114
136
 
137
+ const spellCooldown = !payload
138
+ ? 0
139
+ : spellCooldowns?.[payload.magicWords.replaceAll(' ', '_')] ??
140
+ shortcutCooldown;
141
+ const cooldown =
142
+ spellCooldown > shortcutCooldown ? spellCooldown : shortcutCooldown;
143
+ const isOnCooldown = cooldown > 0 && !!payload;
144
+
115
145
  return (
116
146
  <StyledShortcut
117
147
  key={i}
118
- onPointerDown={onShortcutCast.bind(null, i)}
148
+ onPointerDown={handleShortcutCast.bind(null, i)}
119
149
  disabled={mana < (payload?.manaCost ?? 0)}
120
150
  ref={el => {
121
151
  if (el) shortcutsRefs.current[i] = el;
122
152
  }}
123
153
  >
124
- <span className="mana">{payload && payload.manaCost}</span>
154
+ {isOnCooldown && (
155
+ <span className="cooldown">
156
+ {cooldown.toFixed(cooldown < 10 ? 1 : 0)}
157
+ </span>
158
+ )}
159
+ <span className={buildClassName('mana', isOnCooldown)}>
160
+ {payload && payload.manaCost}
161
+ </span>
125
162
  <span className="magicWords">
126
163
  {payload?.magicWords.split(' ').map(word => word[0])}
127
164
  </span>
128
- <span className="keyboard">{i + 1}</span>
165
+ <span className={buildClassName('keyboard', isOnCooldown)}>
166
+ {i + 1}
167
+ </span>
129
168
  </StyledShortcut>
130
169
  );
131
170
  })}
@@ -46,6 +46,26 @@ export const SingleShortcut = styled.button`
46
46
  color: ${uiColors.yellow};
47
47
  }
48
48
 
49
+ .onCooldown {
50
+ color: ${uiColors.gray};
51
+ }
52
+
53
+ .cooldown {
54
+ position: absolute;
55
+ z-index: 1;
56
+ top: 0;
57
+ left: 0;
58
+ width: 100%;
59
+ height: 100%;
60
+ border-radius: inherit;
61
+ background-color: rgba(0 0 0 / 60%);
62
+ font-size: 0.7rem;
63
+ display: flex;
64
+ align-items: center;
65
+ justify-content: center;
66
+ color: ${uiColors.darkYellow};
67
+ }
68
+
49
69
  &:hover,
50
70
  &:focus {
51
71
  background-color: ${uiColors.darkGray};
@@ -0,0 +1,24 @@
1
+ import { useEffect, useRef, useState } from "react";
2
+
3
+ export const useShortcutCooldown = (onShortcutCast: (index: number) => void) => {
4
+ const [shortcutCooldown, setShortcutCooldown] = useState(0);
5
+ const cooldownTimeout = useRef<NodeJS.Timeout | null>(null);
6
+
7
+ const handleShortcutCast = (index: number) => {
8
+ console.log(shortcutCooldown);
9
+ if (shortcutCooldown <= 0) setShortcutCooldown(1.5);
10
+ onShortcutCast(index);
11
+ };
12
+
13
+ useEffect(() => {
14
+ if (cooldownTimeout.current) clearTimeout(cooldownTimeout.current);
15
+
16
+ if (shortcutCooldown > 0) {
17
+ cooldownTimeout.current = setTimeout(() => {
18
+ setShortcutCooldown(shortcutCooldown - 0.1);
19
+ }, 100);
20
+ }
21
+ }, [shortcutCooldown]);
22
+
23
+ return { shortcutCooldown, handleShortcutCast };
24
+ };
@@ -10,6 +10,7 @@ interface Props extends IRawSpell {
10
10
  onPointerUp?: (spellKey: string) => void;
11
11
  isSettingShortcut?: boolean;
12
12
  spellKey: string;
13
+ activeCooldown?: number;
13
14
  }
14
15
 
15
16
  export const Spell: React.FC<Props> = ({
@@ -23,6 +24,7 @@ export const Spell: React.FC<Props> = ({
23
24
  onPointerUp,
24
25
  isSettingShortcut,
25
26
  minMagicLevelRequired,
27
+ activeCooldown,
26
28
  }) => {
27
29
  const disabled = isSettingShortcut
28
30
  ? charMagicLevel < minMagicLevelRequired
@@ -30,7 +32,7 @@ export const Spell: React.FC<Props> = ({
30
32
 
31
33
  return (
32
34
  <Container
33
- disabled={disabled}
35
+ disabled={disabled || (activeCooldown ?? 0) > 0}
34
36
  onPointerUp={onPointerUp?.bind(null, spellKey)}
35
37
  isSettingShortcut={isSettingShortcut && !disabled}
36
38
  className="spell"
@@ -42,7 +44,14 @@ export const Spell: React.FC<Props> = ({
42
44
  : manaCost > charMana && 'No mana'}
43
45
  </Overlay>
44
46
  )}
45
- <SpellImage>{magicWords.split(' ').map(word => word[0])}</SpellImage>
47
+ <SpellImage>
48
+ {activeCooldown && activeCooldown > 0 ? (
49
+ <span className="cooldown">
50
+ {activeCooldown.toFixed(activeCooldown > 10 ? 0 : 1)}
51
+ </span>
52
+ ) : null}
53
+ {magicWords.split(' ').map(word => word[0])}
54
+ </SpellImage>
46
55
  <Info>
47
56
  <Title>
48
57
  <span>{name}</span>
@@ -110,6 +119,22 @@ const SpellImage = styled.div`
110
119
  justify-content: center;
111
120
  align-items: center;
112
121
  text-transform: uppercase;
122
+ position: relative;
123
+ overflow: hidden;
124
+
125
+ .cooldown {
126
+ position: absolute;
127
+ top: 0;
128
+ left: 0;
129
+ width: 100%;
130
+ height: 100%;
131
+ background-color: rgba(0 0 0 / 20%);
132
+ color: ${uiColors.darkYellow};
133
+ font-weight: bold;
134
+ display: flex;
135
+ justify-content: center;
136
+ align-items: center;
137
+ }
113
138
  `;
114
139
 
115
140
  const Info = styled.span`
@@ -22,6 +22,7 @@ export interface ISpellbookProps {
22
22
  atlasIMG: any;
23
23
  atlasJSON: any;
24
24
  scale?: number;
25
+ spellCooldowns?: Record<string, number>;
25
26
  }
26
27
 
27
28
  export const Spellbook: React.FC<ISpellbookProps> = ({
@@ -38,6 +39,7 @@ export const Spellbook: React.FC<ISpellbookProps> = ({
38
39
  atlasIMG,
39
40
  atlasJSON,
40
41
  scale,
42
+ spellCooldowns,
41
43
  }) => {
42
44
  const [search, setSearch] = useState('');
43
45
  const [settingShortcutIndex, setSettingShortcutIndex] = useState(-1);
@@ -118,6 +120,9 @@ export const Spellbook: React.FC<ISpellbookProps> = ({
118
120
  }
119
121
  spellKey={spell.key}
120
122
  isSettingShortcut={settingShortcutIndex !== -1}
123
+ activeCooldown={
124
+ spellCooldowns?.[spell.magicWords.replaceAll(' ', '_')]
125
+ }
121
126
  {...spell}
122
127
  />
123
128
  </Fragment>
@@ -15,6 +15,6 @@ export const uiColors = {
15
15
  blue: '#597DCE',
16
16
  darkBlue: '#30346D',
17
17
  brown: '#854C30',
18
- lightGreen: '#88ed1c',
18
+ lightGreen: '#66cd1c',
19
19
  brownGreen: '#346524',
20
20
  };
@@ -383,7 +383,7 @@ export const equipmentSetMock: IEquipmentSet = {
383
383
  legs: undefined,
384
384
  boot: items.boot,
385
385
  leftHand: items.leftHand,
386
- rightHand: undefined,
386
+ rightHand: items.rightHand,
387
387
  neck: undefined,
388
388
  ring: undefined,
389
389
  accessory: items.accessory,
@@ -42,6 +42,16 @@ export const items: IItem[] = [
42
42
  createdAt: '2022-06-04T03:18:09.335Z',
43
43
  updatedAt: '2022-06-04T18:16:49.056Z',
44
44
  rarity: ItemRarities.Legendary,
45
+ minRequirements: {
46
+ level: 10,
47
+ skill: {
48
+ name: 'sword',
49
+ level: 5,
50
+ }
51
+ },
52
+ equippedBuffDescription: "Character speed +10%",
53
+ entityEffectChance: 50,
54
+ entityEffects: ['freezing']
45
55
  },
46
56
  {
47
57
  _id: '629acef1c7c8e8002ff73564',
@@ -530,6 +540,37 @@ export const items: IItem[] = [
530
540
  updatedAt: '2022-06-04T18:16:49.056Z',
531
541
  rarity: ItemRarities.Common,
532
542
  },
543
+ {
544
+ "type": ItemType.Consumable,
545
+ "subType": ItemSubType.Food,
546
+ "rarity": "Common",
547
+ "textureAtlas": "items",
548
+ "allowedEquipSlotType": [],
549
+ "maxStackSize": 100,
550
+ "isUsable": false,
551
+ "isStorable": true,
552
+ "isItemContainer": false,
553
+ "isSolid": false,
554
+ "requiredAmmoKeys": [],
555
+ "isTwoHanded": false,
556
+ "hasUseWith": false,
557
+ "entityEffects": [],
558
+ "entityEffectChance": 0,
559
+ "_id": "64529049d45546003b2c6c6d",
560
+ "key": "apple",
561
+ "texturePath": "foods/apple.png",
562
+ textureKey: 'apple',
563
+ isEquipable: false,
564
+ isStackable: true,
565
+ "name": "Apple",
566
+ "description": "A red apple.",
567
+ "weight": 0.05,
568
+ "stackQty": 16,
569
+ "attack": 0,
570
+ "defense": 0,
571
+ fullDescription: "",
572
+ usableEffectDescription: "Regenerates 10 HP and Mana 5 times"
573
+ }
533
574
  ];
534
575
 
535
576
  export const itemContainerMock: IItemContainer = {
@@ -553,6 +594,7 @@ export const itemContainerMock: IItemContainer = {
553
594
  12: items[12],
554
595
  13: items[13],
555
596
  14: items[14],
597
+ 15: items[15],
556
598
  //remaining slots are considered null by default
557
599
  },
558
600
  allowedItemTypes: [],