@hytopia.com/examples 1.0.12 → 1.0.13
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/frontiers-rpg-game/assets/icons/items/leather-boots.png +0 -0
- package/frontiers-rpg-game/assets/icons/items/leather-bracers.png +0 -0
- package/frontiers-rpg-game/assets/icons/items/leather-helmet.png +0 -0
- package/frontiers-rpg-game/assets/icons/items/leather-leggings.png +0 -0
- package/frontiers-rpg-game/assets/icons/items/leather-vest.png +0 -0
- package/frontiers-rpg-game/assets/icons/items/spiked-club.png +0 -0
- package/frontiers-rpg-game/assets/icons/skills/crafting.png +0 -0
- package/frontiers-rpg-game/assets/models/weapons/.optimized/mace/baseColor.png +0 -0
- package/frontiers-rpg-game/assets/models/weapons/.optimized/mace/mace-named-nodes.bin +0 -0
- package/frontiers-rpg-game/assets/models/weapons/.optimized/mace/mace-named-nodes.gltf +653 -0
- package/frontiers-rpg-game/assets/models/weapons/.optimized/mace/mace.bin +0 -0
- package/frontiers-rpg-game/assets/models/weapons/.optimized/mace/mace.gltf +135 -0
- package/frontiers-rpg-game/assets/models/weapons/.optimized/mace/mace.gltf.md5 +1 -0
- package/frontiers-rpg-game/assets/models/weapons/.optimized/spiked-club/baseColor.png +0 -0
- package/frontiers-rpg-game/assets/models/weapons/.optimized/spiked-club/spiked-club-named-nodes.bin +0 -0
- package/frontiers-rpg-game/assets/models/weapons/.optimized/spiked-club/spiked-club-named-nodes.gltf +840 -0
- package/frontiers-rpg-game/assets/models/weapons/.optimized/spiked-club/spiked-club.bin +0 -0
- package/frontiers-rpg-game/assets/models/weapons/.optimized/spiked-club/spiked-club.gltf +141 -0
- package/frontiers-rpg-game/assets/models/weapons/.optimized/spiked-club/spiked-club.gltf.md5 +1 -0
- package/frontiers-rpg-game/assets/models/weapons/mace.gltf +1 -0
- package/frontiers-rpg-game/assets/ui/build.js +2 -0
- package/frontiers-rpg-game/assets/ui/index.html +1328 -64
- package/frontiers-rpg-game/assets/ui/menus/crafting.html +976 -0
- package/frontiers-rpg-game/assets/ui/menus/quests.html +70 -2
- package/frontiers-rpg-game/assets/ui/shared/item-stats.html +224 -0
- package/frontiers-rpg-game/assets/ui/shared/item-tooltips.html +72 -81
- package/frontiers-rpg-game/dev/persistence/player-player-1.json +121 -12
- package/frontiers-rpg-game/src/GamePlayer.ts +53 -0
- package/frontiers-rpg-game/src/GamePlayerEntity.ts +9 -2
- package/frontiers-rpg-game/src/config.ts +7 -0
- package/frontiers-rpg-game/src/entities/BaseCraftingEntity.ts +115 -0
- package/frontiers-rpg-game/src/entities/enemies/RatkinBruteEntity.ts +2 -0
- package/frontiers-rpg-game/src/entities/enemies/RatkinRangerEntity.ts +2 -0
- package/frontiers-rpg-game/src/entities/enemies/RatkinSpellcasterEntity.ts +2 -0
- package/frontiers-rpg-game/src/entities/enemies/RatkinWarriorEntity.ts +2 -0
- package/frontiers-rpg-game/src/entities/enemies/TaintedRatkinBruteEntity.ts +2 -0
- package/frontiers-rpg-game/src/entities/enemies/TaintedRatkinRangerEntity.ts +2 -1
- package/frontiers-rpg-game/src/entities/enemies/TaintedRatkinSpellcasterEntity.ts +2 -0
- package/frontiers-rpg-game/src/entities/enemies/TaintedRatkinWarriorEntity.ts +2 -0
- package/frontiers-rpg-game/src/entities/forageables/DecayingPileEntity.ts +2 -2
- package/frontiers-rpg-game/src/entities/forageables/RottenLogEntity.ts +2 -2
- package/frontiers-rpg-game/src/items/ItemClasses.ts +14 -2
- package/frontiers-rpg-game/src/items/materials/RawHideItem.ts +10 -0
- package/frontiers-rpg-game/src/items/weapons/DullSwordItem.ts +5 -4
- package/frontiers-rpg-game/src/items/weapons/IronDaggerItem.ts +1 -1
- package/frontiers-rpg-game/src/items/weapons/IronLongSwordItem.ts +5 -4
- package/frontiers-rpg-game/src/items/weapons/SpikedClubItem.ts +26 -0
- package/frontiers-rpg-game/src/items/weapons/TrainingSwordItem.ts +5 -4
- package/frontiers-rpg-game/src/items/wearables/LeatherBootsItem.ts +14 -0
- package/frontiers-rpg-game/src/items/wearables/LeatherBracersItem.ts +14 -0
- package/frontiers-rpg-game/src/items/wearables/LeatherHelmetItem.ts +14 -0
- package/frontiers-rpg-game/src/items/wearables/LeatherLeggingsItem.ts +14 -0
- package/frontiers-rpg-game/src/items/wearables/LeatherVestItem.ts +14 -0
- package/frontiers-rpg-game/src/quests/BaseQuest.ts +1 -2
- package/frontiers-rpg-game/src/quests/QuestClasses.ts +2 -0
- package/frontiers-rpg-game/src/quests/side/FungalForagingQuest.ts +1 -23
- package/frontiers-rpg-game/src/quests/side/HammersAndCraftingQuest.ts +139 -0
- package/frontiers-rpg-game/src/regions/stalkhaven/StalkhavenRegion.ts +2 -0
- package/frontiers-rpg-game/src/regions/stalkhaven/npcs/BlacksmithArdenEntity.ts +114 -0
- package/frontiers-rpg-game/src/systems/QuestLog.ts +2 -5
- package/package.json +1 -1
- package/frontiers-rpg-game/dev/persistence/player-player-2.json +0 -31
- package/frontiers-rpg-game/dev/persistence/player-player-3.json +0 -25
- package/frontiers-rpg-game/dev/persistence/player-player-4.json +0 -31
- package/frontiers-rpg-game/src/items/materials/MonsterHideItem.ts +0 -10
- /package/frontiers-rpg-game/assets/icons/items/{monster-hide.png → raw-hide.png} +0 -0
- /package/frontiers-rpg-game/assets/models/weapons/{club.gltf → spiked-club.gltf} +0 -0
|
@@ -15,6 +15,7 @@ import Levels from './systems/Levels';
|
|
|
15
15
|
import QuestLog from './systems/QuestLog';
|
|
16
16
|
import Storage from './systems/Storage';
|
|
17
17
|
import Wearables from './systems/Wearables';
|
|
18
|
+
import type BaseCraftingEntity from './entities/BaseCraftingEntity';
|
|
18
19
|
import type BaseEntity from './entities/BaseEntity';
|
|
19
20
|
import type BaseMerchantEntity from './entities/BaseMerchantEntity';
|
|
20
21
|
import type BaseItem from './items/BaseItem';
|
|
@@ -60,6 +61,7 @@ export default class GamePlayer {
|
|
|
60
61
|
public readonly storage: Storage;
|
|
61
62
|
public readonly wearables: Wearables
|
|
62
63
|
|
|
64
|
+
private _currentCraftingEntity: BaseCraftingEntity | undefined;
|
|
63
65
|
private _currentDialogueEntity: BaseEntity | undefined;
|
|
64
66
|
private _currentMerchantEntity: BaseMerchantEntity | undefined;
|
|
65
67
|
private _currentEntity: GamePlayerEntity | undefined;
|
|
@@ -124,6 +126,10 @@ export default class GamePlayer {
|
|
|
124
126
|
}
|
|
125
127
|
|
|
126
128
|
// Getters
|
|
129
|
+
public get currentCraftingEntity(): BaseCraftingEntity | undefined {
|
|
130
|
+
return this._currentCraftingEntity;
|
|
131
|
+
}
|
|
132
|
+
|
|
127
133
|
public get currentDialogueEntity(): BaseEntity | undefined {
|
|
128
134
|
return this._currentDialogueEntity;
|
|
129
135
|
}
|
|
@@ -188,6 +194,10 @@ export default class GamePlayer {
|
|
|
188
194
|
});
|
|
189
195
|
}
|
|
190
196
|
|
|
197
|
+
public addHeldItem(itemClass: typeof BaseItem, quantity: number = 1): boolean {
|
|
198
|
+
return this.hotbar.addItem(itemClass.create({ quantity })) || this.backpack.addItem(itemClass.create({ quantity }));
|
|
199
|
+
}
|
|
200
|
+
|
|
191
201
|
// Game state methods
|
|
192
202
|
public adjustHealth(amount: number): void {
|
|
193
203
|
const willDie = this._health > 0 && this._health + amount <= 0;
|
|
@@ -315,6 +325,15 @@ export default class GamePlayer {
|
|
|
315
325
|
return this._skillExperience.get(skillId) ?? 0;
|
|
316
326
|
}
|
|
317
327
|
|
|
328
|
+
public hasHeldItem(itemClass: typeof BaseItem, quantity: number = 1): boolean {
|
|
329
|
+
const totalBackpackItems = this.backpack.getItemQuantityByClass(itemClass);
|
|
330
|
+
const totalHotbarItems = this.hotbar.getItemQuantityByClass(itemClass);
|
|
331
|
+
|
|
332
|
+
return totalBackpackItems + totalHotbarItems >= quantity;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
|
|
318
337
|
public joinRegion(region: GameRegion, facingAngle: number, spawnPoint: Vector3Like): void {
|
|
319
338
|
this.setCurrentRegion(region);
|
|
320
339
|
this.setCurrentRegionSpawnFacingAngle(facingAngle);
|
|
@@ -351,6 +370,28 @@ export default class GamePlayer {
|
|
|
351
370
|
});
|
|
352
371
|
}
|
|
353
372
|
|
|
373
|
+
public removeHeldItem(itemClass: typeof BaseItem, quantity: number = 1): boolean {
|
|
374
|
+
if (!this.hasHeldItem(itemClass, quantity)) return false;
|
|
375
|
+
|
|
376
|
+
// Remove from backpack first
|
|
377
|
+
for (const item of this.backpack.getItemsByClass(itemClass)) {
|
|
378
|
+
if (quantity <= 0) break;
|
|
379
|
+
const toRemove = Math.min(item.quantity, quantity);
|
|
380
|
+
this.adjustInventoryItemQuantityByReference(this.backpack, item, -toRemove);
|
|
381
|
+
quantity -= toRemove;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Remove from hotbar last
|
|
385
|
+
for (const item of this.hotbar.getItemsByClass(itemClass)) {
|
|
386
|
+
if (quantity <= 0) break;
|
|
387
|
+
const toRemove = Math.min(item.quantity, quantity);
|
|
388
|
+
this.adjustInventoryItemQuantityByReference(this.hotbar, item, -toRemove);
|
|
389
|
+
quantity -= toRemove;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
return true;
|
|
393
|
+
}
|
|
394
|
+
|
|
354
395
|
public respawn(): void {
|
|
355
396
|
if (!this._isDead || !this._currentEntity) return;
|
|
356
397
|
|
|
@@ -370,6 +411,10 @@ export default class GamePlayer {
|
|
|
370
411
|
}
|
|
371
412
|
}
|
|
372
413
|
|
|
414
|
+
public setCurrentCraftingEntity(entity: BaseCraftingEntity): void {
|
|
415
|
+
this._currentCraftingEntity = entity;
|
|
416
|
+
}
|
|
417
|
+
|
|
373
418
|
public setCurrentDialogueEntity(entity: BaseEntity): void {
|
|
374
419
|
this._currentDialogueEntity = entity;
|
|
375
420
|
}
|
|
@@ -497,6 +542,14 @@ export default class GamePlayer {
|
|
|
497
542
|
}
|
|
498
543
|
}
|
|
499
544
|
|
|
545
|
+
if (data.type === 'craftItem') {
|
|
546
|
+
const { recipeIndex } = data;
|
|
547
|
+
|
|
548
|
+
if (this._currentCraftingEntity && this._currentEntity) {
|
|
549
|
+
this._currentCraftingEntity.craftItem(this._currentEntity, recipeIndex);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
500
553
|
if (data.type === 'dropItem') {
|
|
501
554
|
const fromType = data.fromType;
|
|
502
555
|
const fromIndex = parseInt(data.fromIndex);
|
|
@@ -16,6 +16,9 @@ import CustomCollisionGroup from './physics/CustomCollisionGroup';
|
|
|
16
16
|
import GameClock from './GameClock';
|
|
17
17
|
import GamePlayer from './GamePlayer';
|
|
18
18
|
import Levels from './systems/Levels';
|
|
19
|
+
import type BaseCraftingEntity from './entities/BaseCraftingEntity';
|
|
20
|
+
import type BaseEntity from './entities/BaseEntity';
|
|
21
|
+
import type BaseMerchantEntity from './entities/BaseMerchantEntity';
|
|
19
22
|
import type GameRegion from './GameRegion';
|
|
20
23
|
import type IDamageable from './interfaces/IDamageable';
|
|
21
24
|
import type { NotificationType } from './GamePlayer';
|
|
@@ -150,11 +153,15 @@ export default class GamePlayerEntity extends DefaultPlayerEntity implements IDa
|
|
|
150
153
|
this._gamePlayer.joinRegion(region, facingAngle, spawnPoint);
|
|
151
154
|
}
|
|
152
155
|
|
|
153
|
-
public
|
|
156
|
+
public setCurrentCraftingEntity(entity: BaseCraftingEntity): void {
|
|
157
|
+
this._gamePlayer.setCurrentCraftingEntity(entity);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
public setCurrentDialogueEntity(entity: BaseEntity): void {
|
|
154
161
|
this._gamePlayer.setCurrentDialogueEntity(entity);
|
|
155
162
|
}
|
|
156
163
|
|
|
157
|
-
public setCurrentMerchantEntity(entity:
|
|
164
|
+
public setCurrentMerchantEntity(entity: BaseMerchantEntity): void {
|
|
158
165
|
this._gamePlayer.setCurrentMerchantEntity(entity);
|
|
159
166
|
}
|
|
160
167
|
|
|
@@ -13,6 +13,7 @@ export enum SkillId {
|
|
|
13
13
|
AGILITY = 'agility',
|
|
14
14
|
BARTERING = 'bartering',
|
|
15
15
|
COMBAT = 'combat',
|
|
16
|
+
CRAFTING = 'crafting',
|
|
16
17
|
EXPLORATION = 'exploration',
|
|
17
18
|
FARMING = 'farming',
|
|
18
19
|
FORAGING = 'foraging',
|
|
@@ -37,6 +38,12 @@ export const skills: Skill[] = [
|
|
|
37
38
|
description: 'Purchase and sell items with merchants to gain XP.<br/><br/>Increases merchant discount and unlocks new merchant items.',
|
|
38
39
|
iconAssetUri: 'icons/skills/bartering.png'
|
|
39
40
|
},
|
|
41
|
+
{
|
|
42
|
+
id: SkillId.CRAFTING,
|
|
43
|
+
name: 'Crafting',
|
|
44
|
+
description: 'Craft items from to gain XP.<br/><br/>Unlocks new craftable items and perks.',
|
|
45
|
+
iconAssetUri: 'icons/skills/crafting.png'
|
|
46
|
+
},
|
|
40
47
|
{
|
|
41
48
|
id: SkillId.COMBAT,
|
|
42
49
|
name: 'Combat',
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import BaseEntity, { BaseEntityOptions } from './BaseEntity';
|
|
2
|
+
import { ItemUIDataHelper } from '../items/ItemUIDataHelper';
|
|
3
|
+
import { SkillId } from '../config';
|
|
4
|
+
import type { ItemClass } from '../items/BaseItem';
|
|
5
|
+
import type { BaseEntityDialogueOption } from './BaseEntity';
|
|
6
|
+
import type GamePlayerEntity from '../GamePlayerEntity';
|
|
7
|
+
|
|
8
|
+
export enum BaseCraftingEntityPlayerEvent {
|
|
9
|
+
CRAFT_ITEM = 'BaseCraftingEntity.CRAFT_ITEM',
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type BaseCraftingEntityPlayerEventPayloads = {
|
|
13
|
+
[BaseCraftingEntityPlayerEvent.CRAFT_ITEM]: { crafter: BaseCraftingEntity, craftingRecipeIndex: number }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type CraftingRecipe = {
|
|
17
|
+
craftedItemClass: ItemClass;
|
|
18
|
+
requirements: {
|
|
19
|
+
itemClass: ItemClass;
|
|
20
|
+
quantity: number;
|
|
21
|
+
}[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type BaseCraftingEntityOptions = {
|
|
25
|
+
additionalDialogueOptions?: BaseEntityDialogueOption[];
|
|
26
|
+
craftingRecipes: CraftingRecipe[];
|
|
27
|
+
dialogueAvatarImageUri: string;
|
|
28
|
+
dialogueTitle: string;
|
|
29
|
+
} & BaseEntityOptions;
|
|
30
|
+
|
|
31
|
+
export default class BaseCraftingEntity extends BaseEntity {
|
|
32
|
+
public readonly craftingRecipes: CraftingRecipe[];
|
|
33
|
+
|
|
34
|
+
public constructor(options: BaseCraftingEntityOptions) {
|
|
35
|
+
super({
|
|
36
|
+
...options,
|
|
37
|
+
dialogue: {
|
|
38
|
+
avatarImageUri: options.dialogueAvatarImageUri,
|
|
39
|
+
title: options.dialogueTitle,
|
|
40
|
+
dialogue: {
|
|
41
|
+
text: 'Good to see you! What can I help you with?',
|
|
42
|
+
options: [
|
|
43
|
+
{
|
|
44
|
+
text: `Craft items.`,
|
|
45
|
+
onSelect: (interactor: GamePlayerEntity) => this.openCraftMenu(interactor),
|
|
46
|
+
dismiss: true,
|
|
47
|
+
},
|
|
48
|
+
...(options.additionalDialogueOptions ?? []),
|
|
49
|
+
{
|
|
50
|
+
text: `Nevermind, thanks!`,
|
|
51
|
+
dismiss: true,
|
|
52
|
+
pureExit: true,
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
this.craftingRecipes = options.craftingRecipes;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
public craftItem(interactor: GamePlayerEntity, craftingRecipeIndex: number): void {
|
|
64
|
+
const craftingRecipe = this.craftingRecipes[craftingRecipeIndex];
|
|
65
|
+
|
|
66
|
+
if (!craftingRecipe) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Check if the player has the required items to craft the item
|
|
71
|
+
let hasRequirements = true;
|
|
72
|
+
|
|
73
|
+
for (const requirement of craftingRecipe.requirements) {
|
|
74
|
+
if (!interactor.gamePlayer.hasHeldItem(requirement.itemClass, requirement.quantity)) {
|
|
75
|
+
hasRequirements = false;
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!hasRequirements) {
|
|
81
|
+
return interactor.showNotification(`You don't have the required items to craft this item.`, 'error');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Remove the required items from the player's inventory and give the crafted item
|
|
85
|
+
for (const requirement of craftingRecipe.requirements) {
|
|
86
|
+
interactor.gamePlayer.removeHeldItem(requirement.itemClass, requirement.quantity);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
interactor.gamePlayer.addHeldItem(craftingRecipe.craftedItemClass);
|
|
90
|
+
this._awardCraftingSkillExperience(interactor, craftingRecipe.craftedItemClass);
|
|
91
|
+
interactor.showNotification(`You crafted a ${craftingRecipe.craftedItemClass.name}.`, 'success');
|
|
92
|
+
|
|
93
|
+
interactor.gamePlayer.eventRouter.emit(BaseCraftingEntityPlayerEvent.CRAFT_ITEM, { crafter: this, craftingRecipeIndex });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public openCraftMenu(interactor: GamePlayerEntity): void {
|
|
97
|
+
interactor.setCurrentCraftingEntity(this);
|
|
98
|
+
interactor.player.ui.sendData({
|
|
99
|
+
type: 'toggleCrafting',
|
|
100
|
+
crafterName: this.name,
|
|
101
|
+
crafterTitle: this.dialogueRoot?.title,
|
|
102
|
+
crafterAvatarUri: this.dialogueRoot?.avatarImageUri,
|
|
103
|
+
craftingRecipes: this.craftingRecipes.map((recipe, index) => ({
|
|
104
|
+
craftedItem: ItemUIDataHelper.getUIData(recipe.craftedItemClass),
|
|
105
|
+
requirements: recipe.requirements.map(requirement => ItemUIDataHelper.getUIData(requirement.itemClass, { quantity: requirement.quantity })),
|
|
106
|
+
position: index,
|
|
107
|
+
})),
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private _awardCraftingSkillExperience(interactor: GamePlayerEntity, craftedItemClass: ItemClass) {
|
|
112
|
+
const craftingSkillExperience = Math.max(10, Math.floor(craftedItemClass.sellPrice / 2));
|
|
113
|
+
interactor.gamePlayer.adjustSkillExperience(SkillId.CRAFTING, craftingSkillExperience);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -8,6 +8,7 @@ import RatkinBonesItem from "../../items/materials/RatkinBonesItem";
|
|
|
8
8
|
import RatkinEyesItem from "../../items/materials/RatkinEyesItem.ts";
|
|
9
9
|
import RatkinTailItem from "../../items/materials/RatkinTailItem";
|
|
10
10
|
import RatkinToothItem from "../../items/materials/RatkinToothItem.ts";
|
|
11
|
+
import RawHideItem from "../../items/materials/RawHideItem.ts";
|
|
11
12
|
|
|
12
13
|
export type RatkinBruteEntityOptions = {
|
|
13
14
|
|
|
@@ -59,6 +60,7 @@ export default class RatkinBruteEntity extends BaseCombatEntity {
|
|
|
59
60
|
{ itemClass: RatkinToothItem, minQuantity: 1, maxQuantity: 3, weight: 4 },
|
|
60
61
|
{ itemClass: RatkinTailItem, minQuantity: 1, maxQuantity: 3, weight: 4 },
|
|
61
62
|
{ itemClass: GoldItem, minQuantity: 6, maxQuantity: 15, weight: 2 },
|
|
63
|
+
{ itemClass: RawHideItem, minQuantity: 1, maxQuantity: 2, weight: 1 },
|
|
62
64
|
{ itemClass: CommonMushroomItem, minQuantity: 1, maxQuantity: 3, weight: 1 },
|
|
63
65
|
{ itemClass: CommonSeedsItem, minQuantity: 1, maxQuantity: 3, weight: 1 },
|
|
64
66
|
],
|
|
@@ -10,6 +10,7 @@ import RatkinBonesItem from "../../items/materials/RatkinBonesItem";
|
|
|
10
10
|
import RatkinEyesItem from "../../items/materials/RatkinEyesItem.ts";
|
|
11
11
|
import RatkinTailItem from "../../items/materials/RatkinTailItem";
|
|
12
12
|
import RatkinToothItem from "../../items/materials/RatkinToothItem.ts";
|
|
13
|
+
import RawHideItem from "../../items/materials/RawHideItem.ts";
|
|
13
14
|
|
|
14
15
|
export type RatkinRangerEntityOptions = {
|
|
15
16
|
|
|
@@ -51,6 +52,7 @@ export default class RatkinRangerEntity extends BaseCombatEntity {
|
|
|
51
52
|
{ itemClass: RatkinToothItem, minQuantity: 1, maxQuantity: 3, weight: 4 },
|
|
52
53
|
{ itemClass: RatkinTailItem, minQuantity: 1, maxQuantity: 3, weight: 4 },
|
|
53
54
|
{ itemClass: GoldItem, minQuantity: 6, maxQuantity: 15, weight: 2 },
|
|
55
|
+
{ itemClass: RawHideItem, minQuantity: 1, maxQuantity: 2, weight: 1 },
|
|
54
56
|
{ itemClass: CommonMushroomItem, minQuantity: 1, maxQuantity: 3, weight: 1 },
|
|
55
57
|
{ itemClass: CommonSeedsItem, minQuantity: 1, maxQuantity: 3, weight: 1 },
|
|
56
58
|
],
|
|
@@ -10,6 +10,7 @@ import RatkinBonesItem from "../../items/materials/RatkinBonesItem";
|
|
|
10
10
|
import RatkinEyesItem from "../../items/materials/RatkinEyesItem.ts";
|
|
11
11
|
import RatkinTailItem from "../../items/materials/RatkinTailItem";
|
|
12
12
|
import RatkinToothItem from "../../items/materials/RatkinToothItem.ts";
|
|
13
|
+
import RawHideItem from "../../items/materials/RawHideItem.ts";
|
|
13
14
|
|
|
14
15
|
export type RatkinSpellcasterEntityOptions = {
|
|
15
16
|
|
|
@@ -41,6 +42,7 @@ export default class RatkinSpellcasterEntity extends BaseCombatEntity {
|
|
|
41
42
|
{ itemClass: RatkinToothItem, minQuantity: 1, maxQuantity: 3, weight: 4 },
|
|
42
43
|
{ itemClass: RatkinTailItem, minQuantity: 1, maxQuantity: 3, weight: 4 },
|
|
43
44
|
{ itemClass: GoldItem, minQuantity: 6, maxQuantity: 15, weight: 2 },
|
|
45
|
+
{ itemClass: RawHideItem, minQuantity: 1, maxQuantity: 2, weight: 1 },
|
|
44
46
|
{ itemClass: CommonMushroomItem, minQuantity: 1, maxQuantity: 3, weight: 1 },
|
|
45
47
|
{ itemClass: CommonSeedsItem, minQuantity: 1, maxQuantity: 3, weight: 1 },
|
|
46
48
|
],
|
|
@@ -8,6 +8,7 @@ import RatkinBonesItem from "../../items/materials/RatkinBonesItem";
|
|
|
8
8
|
import RatkinEyesItem from "../../items/materials/RatkinEyesItem.ts";
|
|
9
9
|
import RatkinTailItem from "../../items/materials/RatkinTailItem";
|
|
10
10
|
import RatkinToothItem from "../../items/materials/RatkinToothItem.ts";
|
|
11
|
+
import RawHideItem from "../../items/materials/RawHideItem.ts";
|
|
11
12
|
|
|
12
13
|
export type RatkinWarriorEntityOptions = {
|
|
13
14
|
|
|
@@ -49,6 +50,7 @@ export default class RatkinWarriorEntity extends BaseCombatEntity {
|
|
|
49
50
|
{ itemClass: RatkinToothItem, minQuantity: 1, maxQuantity: 3, weight: 4 },
|
|
50
51
|
{ itemClass: RatkinTailItem, minQuantity: 1, maxQuantity: 3, weight: 4 },
|
|
51
52
|
{ itemClass: GoldItem, minQuantity: 6, maxQuantity: 15, weight: 2 },
|
|
53
|
+
{ itemClass: RawHideItem, minQuantity: 1, maxQuantity: 2, weight: 1 },
|
|
52
54
|
{ itemClass: CommonMushroomItem, minQuantity: 1, maxQuantity: 3, weight: 1 },
|
|
53
55
|
{ itemClass: CommonSeedsItem, minQuantity: 1, maxQuantity: 3, weight: 1 },
|
|
54
56
|
],
|
|
@@ -8,6 +8,7 @@ import RatkinBonesItem from "../../items/materials/RatkinBonesItem";
|
|
|
8
8
|
import RatkinEyesItem from "../../items/materials/RatkinEyesItem.ts";
|
|
9
9
|
import RatkinTailItem from "../../items/materials/RatkinTailItem";
|
|
10
10
|
import RatkinToothItem from "../../items/materials/RatkinToothItem.ts";
|
|
11
|
+
import RawHideItem from "../../items/materials/RawHideItem.ts";
|
|
11
12
|
|
|
12
13
|
export type TaintedRatkinBruteEntityOptions = {
|
|
13
14
|
|
|
@@ -59,6 +60,7 @@ export default class TaintedRatkinBruteEntity extends BaseCombatEntity {
|
|
|
59
60
|
{ itemClass: RatkinToothItem, minQuantity: 1, maxQuantity: 3, weight: 4 },
|
|
60
61
|
{ itemClass: RatkinTailItem, minQuantity: 1, maxQuantity: 3, weight: 4 },
|
|
61
62
|
{ itemClass: GoldItem, minQuantity: 11, maxQuantity: 20, weight: 2 },
|
|
63
|
+
{ itemClass: RawHideItem, minQuantity: 2, maxQuantity: 3, weight: 1 },
|
|
62
64
|
{ itemClass: CommonMushroomItem, minQuantity: 1, maxQuantity: 3, weight: 1 },
|
|
63
65
|
{ itemClass: CommonSeedsItem, minQuantity: 1, maxQuantity: 3, weight: 1 },
|
|
64
66
|
],
|
|
@@ -10,7 +10,7 @@ import RatkinBonesItem from "../../items/materials/RatkinBonesItem";
|
|
|
10
10
|
import RatkinEyesItem from "../../items/materials/RatkinEyesItem.ts";
|
|
11
11
|
import RatkinTailItem from "../../items/materials/RatkinTailItem";
|
|
12
12
|
import RatkinToothItem from "../../items/materials/RatkinToothItem.ts";
|
|
13
|
-
|
|
13
|
+
import RawHideItem from "../../items/materials/RawHideItem.ts";
|
|
14
14
|
|
|
15
15
|
export type TaintedRatkinRangerEntityOptions = {
|
|
16
16
|
|
|
@@ -52,6 +52,7 @@ export default class TaintedRatkinRangerEntity extends BaseCombatEntity {
|
|
|
52
52
|
{ itemClass: RatkinToothItem, minQuantity: 1, maxQuantity: 3, weight: 4 },
|
|
53
53
|
{ itemClass: RatkinTailItem, minQuantity: 1, maxQuantity: 3, weight: 4 },
|
|
54
54
|
{ itemClass: GoldItem, minQuantity: 9, maxQuantity: 17, weight: 2 },
|
|
55
|
+
{ itemClass: RawHideItem, minQuantity: 2, maxQuantity: 3, weight: 1 },
|
|
55
56
|
{ itemClass: CommonMushroomItem, minQuantity: 1, maxQuantity: 3, weight: 1 },
|
|
56
57
|
{ itemClass: CommonSeedsItem, minQuantity: 1, maxQuantity: 3, weight: 1 },
|
|
57
58
|
],
|
|
@@ -10,6 +10,7 @@ import RatkinBonesItem from "../../items/materials/RatkinBonesItem";
|
|
|
10
10
|
import RatkinEyesItem from "../../items/materials/RatkinEyesItem.ts";
|
|
11
11
|
import RatkinTailItem from "../../items/materials/RatkinTailItem";
|
|
12
12
|
import RatkinToothItem from "../../items/materials/RatkinToothItem.ts";
|
|
13
|
+
import RawHideItem from "../../items/materials/RawHideItem.ts";
|
|
13
14
|
|
|
14
15
|
export type TaintedRatkinSpellcasterEntityOptions = {
|
|
15
16
|
|
|
@@ -41,6 +42,7 @@ export default class TaintedRatkinSpellcasterEntity extends BaseCombatEntity {
|
|
|
41
42
|
{ itemClass: RatkinToothItem, minQuantity: 1, maxQuantity: 3, weight: 4 },
|
|
42
43
|
{ itemClass: RatkinTailItem, minQuantity: 1, maxQuantity: 3, weight: 4 },
|
|
43
44
|
{ itemClass: GoldItem, minQuantity: 9, maxQuantity: 17, weight: 2 },
|
|
45
|
+
{ itemClass: RawHideItem, minQuantity: 2, maxQuantity: 3, weight: 1 },
|
|
44
46
|
{ itemClass: CommonMushroomItem, minQuantity: 1, maxQuantity: 3, weight: 1 },
|
|
45
47
|
{ itemClass: CommonSeedsItem, minQuantity: 1, maxQuantity: 3, weight: 1 },
|
|
46
48
|
],
|
|
@@ -8,6 +8,7 @@ import RatkinBonesItem from "../../items/materials/RatkinBonesItem";
|
|
|
8
8
|
import RatkinEyesItem from "../../items/materials/RatkinEyesItem.ts";
|
|
9
9
|
import RatkinTailItem from "../../items/materials/RatkinTailItem";
|
|
10
10
|
import RatkinToothItem from "../../items/materials/RatkinToothItem.ts";
|
|
11
|
+
import RawHideItem from "../../items/materials/RawHideItem.ts";
|
|
11
12
|
|
|
12
13
|
export type TaintedRatkinWarriorEntityOptions = {
|
|
13
14
|
|
|
@@ -49,6 +50,7 @@ export default class TaintedRatkinWarriorEntity extends BaseCombatEntity {
|
|
|
49
50
|
{ itemClass: RatkinToothItem, minQuantity: 1, maxQuantity: 3, weight: 4 },
|
|
50
51
|
{ itemClass: RatkinTailItem, minQuantity: 1, maxQuantity: 3, weight: 4 },
|
|
51
52
|
{ itemClass: GoldItem, minQuantity: 9, maxQuantity: 17, weight: 2 },
|
|
53
|
+
{ itemClass: RawHideItem, minQuantity: 2, maxQuantity: 3, weight: 1 },
|
|
52
54
|
{ itemClass: CommonMushroomItem, minQuantity: 1, maxQuantity: 3, weight: 1 },
|
|
53
55
|
{ itemClass: CommonSeedsItem, minQuantity: 1, maxQuantity: 3, weight: 1 },
|
|
54
56
|
],
|
|
@@ -5,7 +5,7 @@ import CommonMushroomItem from '../../items/consumables/CommonMushroomItem';
|
|
|
5
5
|
import CommonSeedsItem from '../../items/seeds/CommonSeedsItem';
|
|
6
6
|
import GoldItem from '../../items/general/GoldItem';
|
|
7
7
|
import MinorHealingPotionItem from '../../items/consumables/MinorHealingPotionItem';
|
|
8
|
-
import
|
|
8
|
+
import RawHideItem from '../../items/materials/RawHideItem';
|
|
9
9
|
import StonebellyFungusMushroomItem from '../../items/consumables/StonebellyFungusMushroomItem';
|
|
10
10
|
import UnusualSeedsItem from '../../items/seeds/UnusualSeedsItem';
|
|
11
11
|
|
|
@@ -22,7 +22,7 @@ export default class DecayingPileEntity extends BaseForageableEntity {
|
|
|
22
22
|
{ itemClass: CommonSeedsItem, weight: 35 },
|
|
23
23
|
{ itemClass: GoldItem, weight: 15, minQuantity: 9, maxQuantity: 20 },
|
|
24
24
|
{ itemClass: MinorHealingPotionItem, weight: 25 },
|
|
25
|
-
{ itemClass:
|
|
25
|
+
{ itemClass: RawHideItem, weight: 12 },
|
|
26
26
|
{ itemClass: StonebellyFungusMushroomItem, weight: 5, minQuantity: 1, maxQuantity: 3 },
|
|
27
27
|
{ itemClass: UnusualSeedsItem, weight: 3 },
|
|
28
28
|
],
|
|
@@ -6,7 +6,7 @@ import CommonSeedsItem from '../../items/seeds/CommonSeedsItem';
|
|
|
6
6
|
import EmbercapMushroomItem from '../../items/consumables/EmbercapMushroomItem';
|
|
7
7
|
import GoldItem from '../../items/general/GoldItem';
|
|
8
8
|
import MinorHealingPotionItem from '../../items/consumables/MinorHealingPotionItem';
|
|
9
|
-
import
|
|
9
|
+
import RawHideItem from '../../items/materials/RawHideItem';
|
|
10
10
|
import UnusualSeedsItem from '../../items/seeds/UnusualSeedsItem';
|
|
11
11
|
|
|
12
12
|
export type RottenLogEntityOptions = {
|
|
@@ -22,7 +22,7 @@ export default class RottenLogEntity extends BaseForageableEntity {
|
|
|
22
22
|
{ itemClass: CommonSeedsItem, weight: 25 },
|
|
23
23
|
{ itemClass: MinorHealingPotionItem, weight: 25 },
|
|
24
24
|
{ itemClass: GoldItem, weight: 15, minQuantity: 6, maxQuantity: 17 },
|
|
25
|
-
{ itemClass:
|
|
25
|
+
{ itemClass: RawHideItem, weight: 10 },
|
|
26
26
|
{ itemClass: EmbercapMushroomItem, weight: 5, minQuantity: 1, maxQuantity: 3 },
|
|
27
27
|
{ itemClass: UnusualSeedsItem, weight: 1 },
|
|
28
28
|
],
|
|
@@ -13,7 +13,7 @@ import GoldItem from './general/GoldItem';
|
|
|
13
13
|
|
|
14
14
|
// Materials
|
|
15
15
|
import BlightedRootItem from './materials/BlightedRootItem';
|
|
16
|
-
import
|
|
16
|
+
import RawHideItem from './materials/RawHideItem';
|
|
17
17
|
import RatkinBonesItem from './materials/RatkinBonesItem';
|
|
18
18
|
import RatkinEyesItem from './materials/RatkinEyesItem';
|
|
19
19
|
import RatkinTailItem from './materials/RatkinTailItem';
|
|
@@ -28,6 +28,7 @@ import UnusualSeedsItem from './seeds/UnusualSeedsItem';
|
|
|
28
28
|
import DullSwordItem from './weapons/DullSwordItem';
|
|
29
29
|
import IronDaggerItem from './weapons/IronDaggerItem';
|
|
30
30
|
import IronLongSwordItem from './weapons/IronLongSwordItem';
|
|
31
|
+
import SpikedClubItem from './weapons/SpikedClubItem';
|
|
31
32
|
import TrainingSwordItem from './weapons/TrainingSwordItem';
|
|
32
33
|
|
|
33
34
|
// Wearables
|
|
@@ -36,6 +37,11 @@ import AdventurerGlovesItem from './wearables/AdventurerGlovesItem';
|
|
|
36
37
|
import AdventurerHoodItem from './wearables/AdventurerHoodItem';
|
|
37
38
|
import AdventurerLeggingsItem from './wearables/AdventurerLeggingsItem';
|
|
38
39
|
import AdventurerTunicItem from './wearables/AdventurerTunicItem';
|
|
40
|
+
import LeatherBootsItem from './wearables/LeatherBootsItem';
|
|
41
|
+
import LeatherBracersItem from './wearables/LeatherBracersItem';
|
|
42
|
+
import LeatherHelmetItem from './wearables/LeatherHelmetItem';
|
|
43
|
+
import LeatherLeggingsItem from './wearables/LeatherLeggingsItem';
|
|
44
|
+
import LeatherVestItem from './wearables/LeatherVestItem';
|
|
39
45
|
|
|
40
46
|
export default [
|
|
41
47
|
// Consumables
|
|
@@ -53,7 +59,7 @@ export default [
|
|
|
53
59
|
|
|
54
60
|
// Materials
|
|
55
61
|
BlightedRootItem,
|
|
56
|
-
|
|
62
|
+
RawHideItem,
|
|
57
63
|
RatkinBonesItem,
|
|
58
64
|
RatkinEyesItem,
|
|
59
65
|
RatkinTailItem,
|
|
@@ -68,6 +74,7 @@ export default [
|
|
|
68
74
|
DullSwordItem,
|
|
69
75
|
IronDaggerItem,
|
|
70
76
|
IronLongSwordItem,
|
|
77
|
+
SpikedClubItem,
|
|
71
78
|
TrainingSwordItem,
|
|
72
79
|
|
|
73
80
|
// Wearables
|
|
@@ -76,4 +83,9 @@ export default [
|
|
|
76
83
|
AdventurerHoodItem,
|
|
77
84
|
AdventurerLeggingsItem,
|
|
78
85
|
AdventurerTunicItem,
|
|
86
|
+
LeatherBootsItem,
|
|
87
|
+
LeatherBracersItem,
|
|
88
|
+
LeatherHelmetItem,
|
|
89
|
+
LeatherLeggingsItem,
|
|
90
|
+
LeatherVestItem,
|
|
79
91
|
];
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import BaseItem from '../BaseItem';
|
|
2
|
+
|
|
3
|
+
export default class RawHideItem extends BaseItem {
|
|
4
|
+
static readonly id = 'raw_hide';
|
|
5
|
+
static readonly name = 'Raw Hide';
|
|
6
|
+
static readonly iconImageUri = 'icons/items/raw-hide.png';
|
|
7
|
+
static readonly description = 'Thick hide from a Frontier creature. Tough and weathered.';
|
|
8
|
+
static readonly stackable = true;
|
|
9
|
+
static readonly sellPrice = 15;
|
|
10
|
+
}
|
|
@@ -25,7 +25,7 @@ export default class DullSwordItem extends BaseWeaponItem {
|
|
|
25
25
|
damageDelayMs: 200,
|
|
26
26
|
damageVariance: 0.2,
|
|
27
27
|
knockbackForce: 7,
|
|
28
|
-
reach:
|
|
28
|
+
reach: 1.5,
|
|
29
29
|
};
|
|
30
30
|
static readonly description = 'A dull metal sword. Better than nothing.';
|
|
31
31
|
static readonly heldModelUri = 'models/items/sword-stone.gltf';
|
|
@@ -52,13 +52,14 @@ export default class DullSwordItem extends BaseWeaponItem {
|
|
|
52
52
|
);
|
|
53
53
|
|
|
54
54
|
for (const target of targets) {
|
|
55
|
+
const targetDirection = target.directionFromRotation;
|
|
55
56
|
this.dealDamage(
|
|
56
57
|
target,
|
|
57
58
|
this.calculateDamageWithVariance(attack.damage, attack.damageVariance),
|
|
58
59
|
{
|
|
59
|
-
x: -
|
|
60
|
-
y:
|
|
61
|
-
z: -
|
|
60
|
+
x: -targetDirection.x,
|
|
61
|
+
y: targetDirection.y,
|
|
62
|
+
z: -targetDirection.z,
|
|
62
63
|
},
|
|
63
64
|
attack.knockbackForce
|
|
64
65
|
);
|
|
@@ -13,7 +13,7 @@ export default class IronDaggerItem extends BaseWeaponItem {
|
|
|
13
13
|
damageDelayMs: 50,
|
|
14
14
|
damageVariance: 0.4,
|
|
15
15
|
knockbackForce: 3,
|
|
16
|
-
reach: 1.
|
|
16
|
+
reach: 1.25,
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
static readonly description = `A sharp iron dagger. It doesn't have much reach, but it's good for quick strikes.`;
|
|
@@ -25,7 +25,7 @@ export default class IronLongSwordItem extends BaseWeaponItem {
|
|
|
25
25
|
damageDelayMs: 200,
|
|
26
26
|
damageVariance: 0.2,
|
|
27
27
|
knockbackForce: 7,
|
|
28
|
-
reach:
|
|
28
|
+
reach: 2,
|
|
29
29
|
};
|
|
30
30
|
static readonly description = `A long iron sword. It's heavy and slow, but hits harder than a normal sword.`;
|
|
31
31
|
static readonly heldModelUri = 'models/weapons/iron-long-sword.gltf';
|
|
@@ -52,13 +52,14 @@ export default class IronLongSwordItem extends BaseWeaponItem {
|
|
|
52
52
|
);
|
|
53
53
|
|
|
54
54
|
for (const target of targets) {
|
|
55
|
+
const targetDirection = target.directionFromRotation;
|
|
55
56
|
this.dealDamage(
|
|
56
57
|
target,
|
|
57
58
|
this.calculateDamageWithVariance(attack.damage, attack.damageVariance),
|
|
58
59
|
{
|
|
59
|
-
x: -
|
|
60
|
-
y:
|
|
61
|
-
z: -
|
|
60
|
+
x: -targetDirection.x,
|
|
61
|
+
y: targetDirection.y,
|
|
62
|
+
z: -targetDirection.z,
|
|
62
63
|
},
|
|
63
64
|
attack.knockbackForce
|
|
64
65
|
);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Quaternion } from 'hytopia';
|
|
2
|
+
import BaseWeaponItem, { BaseWeaponItemAttack } from '../BaseWeaponItem';
|
|
3
|
+
|
|
4
|
+
export default class SpikedClubItem extends BaseWeaponItem {
|
|
5
|
+
// Required static properties
|
|
6
|
+
static readonly id = 'spiked_club';
|
|
7
|
+
static readonly name = 'Spiked Club';
|
|
8
|
+
static readonly iconImageUri = 'icons/items/spiked-club.png';
|
|
9
|
+
static readonly attack: BaseWeaponItemAttack = {
|
|
10
|
+
animations: ['sword-attack-upper'],
|
|
11
|
+
cooldownMs: 1500,
|
|
12
|
+
damage: 34,
|
|
13
|
+
damageDelayMs: 200,
|
|
14
|
+
damageVariance: 0.2,
|
|
15
|
+
knockbackForce: 8,
|
|
16
|
+
reach: 1.75,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
static readonly description = `A spiked club. It's bulky and slow to swing but packs a punch.`;
|
|
20
|
+
static readonly heldModelUri = 'models/weapons/spiked-club.gltf';
|
|
21
|
+
static readonly heldModelScale = 0.6;
|
|
22
|
+
static readonly defaultRelativeRotationAsChild = Quaternion.fromEuler(-90, 0, 90);
|
|
23
|
+
static readonly defaultRelativePositionAsChild = { x: 0.3, y: -0.2, z: -0.17 };
|
|
24
|
+
static readonly buyPrice = 750;
|
|
25
|
+
static readonly sellPrice = 75;
|
|
26
|
+
}
|
|
@@ -25,7 +25,7 @@ export default class TrainingSwordItem extends BaseWeaponItem {
|
|
|
25
25
|
damageDelayMs: 200,
|
|
26
26
|
damageVariance: 0.2,
|
|
27
27
|
knockbackForce: 7,
|
|
28
|
-
reach:
|
|
28
|
+
reach: 1.5,
|
|
29
29
|
};
|
|
30
30
|
static readonly description = 'A training sword made from wood. Useless for combat.';
|
|
31
31
|
static readonly heldModelUri = 'models/items/sword-wooden.gltf';
|
|
@@ -52,13 +52,14 @@ export default class TrainingSwordItem extends BaseWeaponItem {
|
|
|
52
52
|
);
|
|
53
53
|
|
|
54
54
|
for (const target of targets) {
|
|
55
|
+
const targetDirection = target.directionFromRotation;
|
|
55
56
|
this.dealDamage(
|
|
56
57
|
target,
|
|
57
58
|
this.calculateDamageWithVariance(attack.damage, attack.damageVariance),
|
|
58
59
|
{
|
|
59
|
-
x: -
|
|
60
|
-
y:
|
|
61
|
-
z: -
|
|
60
|
+
x: -targetDirection.x,
|
|
61
|
+
y: targetDirection.y,
|
|
62
|
+
z: -targetDirection.z,
|
|
62
63
|
},
|
|
63
64
|
attack.knockbackForce
|
|
64
65
|
);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import BaseWearableItem, { WearableSlot } from '../BaseWearableItem';
|
|
2
|
+
|
|
3
|
+
export default class LeatherBootsItem extends BaseWearableItem {
|
|
4
|
+
static readonly id = 'leather_boots';
|
|
5
|
+
static readonly name = 'Leather Boots';
|
|
6
|
+
static readonly iconImageUri = 'icons/items/leather-boots.png';
|
|
7
|
+
static readonly description = `A sturdy pair of boots made from thick leather.`;
|
|
8
|
+
static readonly buyPrice = 350;
|
|
9
|
+
static readonly sellPrice = 35;
|
|
10
|
+
|
|
11
|
+
static readonly damageReduction = 2;
|
|
12
|
+
|
|
13
|
+
static readonly slot: WearableSlot = 'boots';
|
|
14
|
+
}
|