@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.
Files changed (67) hide show
  1. package/frontiers-rpg-game/assets/icons/items/leather-boots.png +0 -0
  2. package/frontiers-rpg-game/assets/icons/items/leather-bracers.png +0 -0
  3. package/frontiers-rpg-game/assets/icons/items/leather-helmet.png +0 -0
  4. package/frontiers-rpg-game/assets/icons/items/leather-leggings.png +0 -0
  5. package/frontiers-rpg-game/assets/icons/items/leather-vest.png +0 -0
  6. package/frontiers-rpg-game/assets/icons/items/spiked-club.png +0 -0
  7. package/frontiers-rpg-game/assets/icons/skills/crafting.png +0 -0
  8. package/frontiers-rpg-game/assets/models/weapons/.optimized/mace/baseColor.png +0 -0
  9. package/frontiers-rpg-game/assets/models/weapons/.optimized/mace/mace-named-nodes.bin +0 -0
  10. package/frontiers-rpg-game/assets/models/weapons/.optimized/mace/mace-named-nodes.gltf +653 -0
  11. package/frontiers-rpg-game/assets/models/weapons/.optimized/mace/mace.bin +0 -0
  12. package/frontiers-rpg-game/assets/models/weapons/.optimized/mace/mace.gltf +135 -0
  13. package/frontiers-rpg-game/assets/models/weapons/.optimized/mace/mace.gltf.md5 +1 -0
  14. package/frontiers-rpg-game/assets/models/weapons/.optimized/spiked-club/baseColor.png +0 -0
  15. package/frontiers-rpg-game/assets/models/weapons/.optimized/spiked-club/spiked-club-named-nodes.bin +0 -0
  16. package/frontiers-rpg-game/assets/models/weapons/.optimized/spiked-club/spiked-club-named-nodes.gltf +840 -0
  17. package/frontiers-rpg-game/assets/models/weapons/.optimized/spiked-club/spiked-club.bin +0 -0
  18. package/frontiers-rpg-game/assets/models/weapons/.optimized/spiked-club/spiked-club.gltf +141 -0
  19. package/frontiers-rpg-game/assets/models/weapons/.optimized/spiked-club/spiked-club.gltf.md5 +1 -0
  20. package/frontiers-rpg-game/assets/models/weapons/mace.gltf +1 -0
  21. package/frontiers-rpg-game/assets/ui/build.js +2 -0
  22. package/frontiers-rpg-game/assets/ui/index.html +1328 -64
  23. package/frontiers-rpg-game/assets/ui/menus/crafting.html +976 -0
  24. package/frontiers-rpg-game/assets/ui/menus/quests.html +70 -2
  25. package/frontiers-rpg-game/assets/ui/shared/item-stats.html +224 -0
  26. package/frontiers-rpg-game/assets/ui/shared/item-tooltips.html +72 -81
  27. package/frontiers-rpg-game/dev/persistence/player-player-1.json +121 -12
  28. package/frontiers-rpg-game/src/GamePlayer.ts +53 -0
  29. package/frontiers-rpg-game/src/GamePlayerEntity.ts +9 -2
  30. package/frontiers-rpg-game/src/config.ts +7 -0
  31. package/frontiers-rpg-game/src/entities/BaseCraftingEntity.ts +115 -0
  32. package/frontiers-rpg-game/src/entities/enemies/RatkinBruteEntity.ts +2 -0
  33. package/frontiers-rpg-game/src/entities/enemies/RatkinRangerEntity.ts +2 -0
  34. package/frontiers-rpg-game/src/entities/enemies/RatkinSpellcasterEntity.ts +2 -0
  35. package/frontiers-rpg-game/src/entities/enemies/RatkinWarriorEntity.ts +2 -0
  36. package/frontiers-rpg-game/src/entities/enemies/TaintedRatkinBruteEntity.ts +2 -0
  37. package/frontiers-rpg-game/src/entities/enemies/TaintedRatkinRangerEntity.ts +2 -1
  38. package/frontiers-rpg-game/src/entities/enemies/TaintedRatkinSpellcasterEntity.ts +2 -0
  39. package/frontiers-rpg-game/src/entities/enemies/TaintedRatkinWarriorEntity.ts +2 -0
  40. package/frontiers-rpg-game/src/entities/forageables/DecayingPileEntity.ts +2 -2
  41. package/frontiers-rpg-game/src/entities/forageables/RottenLogEntity.ts +2 -2
  42. package/frontiers-rpg-game/src/items/ItemClasses.ts +14 -2
  43. package/frontiers-rpg-game/src/items/materials/RawHideItem.ts +10 -0
  44. package/frontiers-rpg-game/src/items/weapons/DullSwordItem.ts +5 -4
  45. package/frontiers-rpg-game/src/items/weapons/IronDaggerItem.ts +1 -1
  46. package/frontiers-rpg-game/src/items/weapons/IronLongSwordItem.ts +5 -4
  47. package/frontiers-rpg-game/src/items/weapons/SpikedClubItem.ts +26 -0
  48. package/frontiers-rpg-game/src/items/weapons/TrainingSwordItem.ts +5 -4
  49. package/frontiers-rpg-game/src/items/wearables/LeatherBootsItem.ts +14 -0
  50. package/frontiers-rpg-game/src/items/wearables/LeatherBracersItem.ts +14 -0
  51. package/frontiers-rpg-game/src/items/wearables/LeatherHelmetItem.ts +14 -0
  52. package/frontiers-rpg-game/src/items/wearables/LeatherLeggingsItem.ts +14 -0
  53. package/frontiers-rpg-game/src/items/wearables/LeatherVestItem.ts +14 -0
  54. package/frontiers-rpg-game/src/quests/BaseQuest.ts +1 -2
  55. package/frontiers-rpg-game/src/quests/QuestClasses.ts +2 -0
  56. package/frontiers-rpg-game/src/quests/side/FungalForagingQuest.ts +1 -23
  57. package/frontiers-rpg-game/src/quests/side/HammersAndCraftingQuest.ts +139 -0
  58. package/frontiers-rpg-game/src/regions/stalkhaven/StalkhavenRegion.ts +2 -0
  59. package/frontiers-rpg-game/src/regions/stalkhaven/npcs/BlacksmithArdenEntity.ts +114 -0
  60. package/frontiers-rpg-game/src/systems/QuestLog.ts +2 -5
  61. package/package.json +1 -1
  62. package/frontiers-rpg-game/dev/persistence/player-player-2.json +0 -31
  63. package/frontiers-rpg-game/dev/persistence/player-player-3.json +0 -25
  64. package/frontiers-rpg-game/dev/persistence/player-player-4.json +0 -31
  65. package/frontiers-rpg-game/src/items/materials/MonsterHideItem.ts +0 -10
  66. /package/frontiers-rpg-game/assets/icons/items/{monster-hide.png → raw-hide.png} +0 -0
  67. /package/frontiers-rpg-game/assets/models/weapons/{club.gltf → spiked-club.gltf} +0 -0
@@ -294,6 +294,40 @@
294
294
  </div>
295
295
  </div>
296
296
  `;
297
+
298
+ // Add tooltips to reward items after rendering
299
+ addRewardTooltips(quest.reward);
300
+ }
301
+
302
+ function addRewardTooltips(reward) {
303
+ // Clear any existing tooltips first
304
+ const existingTooltipItems = document.querySelectorAll('.quests-reward-item-tooltip-enabled');
305
+ existingTooltipItems.forEach(item => removeRewardTooltip(item));
306
+
307
+ // Add tooltips to item rewards
308
+ if (reward.items) {
309
+ reward.items.forEach((itemReward, index) => {
310
+ const rewardItem = document.querySelector(`[data-reward-item-index="${index}"]`);
311
+ if (rewardItem && window.ItemTooltips) {
312
+ createRewardTooltip(rewardItem, itemReward);
313
+ }
314
+ });
315
+ }
316
+ }
317
+
318
+ function createRewardTooltip(item, itemData) {
319
+ const options = {
320
+ tooltipClass: 'quests-reward-item-tooltip',
321
+ contentClass: 'quests-reward-item-tooltip-content',
322
+ showBuyPrice: false,
323
+ showSellPrice: false
324
+ };
325
+
326
+ ItemTooltips.createTooltip(item, itemData, options);
327
+ }
328
+
329
+ function removeRewardTooltip(item) {
330
+ ItemTooltips.removeTooltip(item, 'quests-reward-item-tooltip');
297
331
  }
298
332
 
299
333
  function generateObjectivesHTML(quest) {
@@ -330,11 +364,11 @@
330
364
  });
331
365
 
332
366
  // Handle item rewards
333
- reward.items?.forEach(itemReward => {
367
+ reward.items?.forEach((itemReward, index) => {
334
368
  const quantity = itemReward.quantity > 1 ? `x${itemReward.quantity.toLocaleString()}` : 'x1';
335
369
  const iconSrc = itemReward.iconImageUri ? `{{CDN_ASSETS_URL}}/${itemReward.iconImageUri}` : '{{CDN_ASSETS_URL}}/icons/items/gold.png';
336
370
  rewards.push(`
337
- <div class="quests-reward-item">
371
+ <div class="quests-reward-item quests-reward-item-tooltip-enabled" data-reward-item-index="${index}">
338
372
  <img src="${iconSrc}" alt="Item" class="quests-reward-icon">
339
373
  <span class="quests-reward-text">${sanitizeText(itemReward.name)} (${quantity})</span>
340
374
  </div>
@@ -754,6 +788,40 @@
754
788
  line-height: 1.3;
755
789
  }
756
790
 
791
+ /* Quest reward tooltip positioning - left-aligned for full-width items */
792
+ .quests-reward-item-tooltip {
793
+ position: absolute;
794
+ bottom: 100%;
795
+ left: 0;
796
+ margin-bottom: 8px;
797
+ opacity: 0;
798
+ visibility: hidden;
799
+ transition: all 0.3s ease;
800
+ z-index: 2000;
801
+ pointer-events: none;
802
+ }
803
+
804
+ .quests-reward-item-tooltip-enabled {
805
+ position: relative;
806
+ cursor: pointer;
807
+ }
808
+
809
+ /* Override center positioning for quest reward tooltips */
810
+ .quests-reward-item-tooltip-content {
811
+ transform: translateX(0) !important;
812
+ }
813
+
814
+ /* Position caret over the reward icon */
815
+ .quests-reward-item-tooltip-content::after {
816
+ left: 20px !important;
817
+ transform: translateX(-50%) !important;
818
+ }
819
+
820
+ .quests-reward-item-tooltip-content::before {
821
+ left: 20px !important;
822
+ transform: translateX(-50%) !important;
823
+ }
824
+
757
825
  /* Empty State */
758
826
  .quests-empty-state {
759
827
  flex: 1;
@@ -0,0 +1,224 @@
1
+ <!-- Shared Item Stats System -->
2
+ <script>
3
+ /**
4
+ * Centralized Item Stats System
5
+ * Provides consistent stat formatting across all UI components
6
+ */
7
+ window.ItemStats = (function() {
8
+ 'use strict';
9
+
10
+ // Parse color formatting in text: [HEXCODE]text[/] -> <span style="color: #HEXCODE">text</span>
11
+ // Parse line breaks: [b] -> <br>
12
+ function parseText(text) {
13
+ if (!text) return text;
14
+
15
+ // First, replace [b] with <br> for line breaks
16
+ text = text.replace(/\[b\]/g, '<br>');
17
+
18
+ // Then, handle color formatting [HEXCODE]text[/] pattern
19
+ const colorPattern = /\[([A-Fa-f0-9]{6})\](.*?)\[\/\]/g;
20
+
21
+ return text.replace(colorPattern, (match, hexCode, content) => {
22
+ return `<span style="color: #${hexCode}">${content}</span>`;
23
+ });
24
+ }
25
+
26
+ function generateItemStats(itemData, options = {}) {
27
+ const config = {
28
+ includeDescription: true,
29
+ includePricing: false,
30
+ showBuyPrice: false,
31
+ showSellPrice: false,
32
+ buyPriceLabel: 'Price: ',
33
+ sellPriceLabel: 'Sells For: ',
34
+ notBuyableLabel: 'Not Buyable',
35
+ notSellableLabel: 'Not Sellable',
36
+ statsClass: 'item-stats',
37
+ descriptionClass: 'item-description',
38
+ priceClass: 'item-price',
39
+ ...options
40
+ };
41
+
42
+ const sections = [];
43
+
44
+ // Item stats (weapons and wearables)
45
+ const stats = [];
46
+
47
+ // Weapon damage (no "when equipped" needed since weapons are used directly)
48
+ if (itemData.damage && itemData.damage !== 0) {
49
+ if (itemData.damageVariance && itemData.damageVariance !== 0) {
50
+ const min = Math.floor(itemData.damage * (1 - itemData.damageVariance));
51
+ const max = Math.floor(itemData.damage * (1 + itemData.damageVariance));
52
+ stats.push(`${min}-${max} damage`);
53
+ } else {
54
+ stats.push(`${itemData.damage} damage`);
55
+ }
56
+ }
57
+
58
+ // Wearable stats
59
+ const wearableStats = [];
60
+ if (itemData.damageBonus && itemData.damageBonus !== 0) {
61
+ wearableStats.push(`+${itemData.damageBonus} damage dealt`);
62
+ }
63
+ if (itemData.damageBonusPercent && itemData.damageBonusPercent !== 0) {
64
+ wearableStats.push(`+${itemData.damageBonusPercent}% damage dealt`);
65
+ }
66
+ if (itemData.damageReduction && itemData.damageReduction !== 0) {
67
+ wearableStats.push(`-${itemData.damageReduction} damage taken`);
68
+ }
69
+ if (itemData.damageReductionPercent && itemData.damageReductionPercent !== 0) {
70
+ wearableStats.push(`-${itemData.damageReductionPercent}% damage taken`);
71
+ }
72
+
73
+ // Collect all stat lines first
74
+ const allStatLines = [];
75
+
76
+ // Add wearable stats
77
+ if (wearableStats.length > 0) {
78
+ allStatLines.push(...wearableStats);
79
+ }
80
+
81
+ // Add custom stat texts
82
+ if (itemData.statTexts && itemData.statTexts.length > 0) {
83
+ for (const statText of itemData.statTexts) {
84
+ const parsedStatText = parseText(statText);
85
+ allStatLines.push(parsedStatText);
86
+ }
87
+ }
88
+
89
+ // Add header and stats together if we have stats
90
+ if (allStatLines.length > 0) {
91
+ if (itemData.statsHeader) {
92
+ const headerText = parseText(itemData.statsHeader);
93
+ stats.push(`<div class="stats-header">${headerText}</div>${allStatLines.join('<br>')}`);
94
+ } else {
95
+ stats.push(allStatLines.join('<br>'));
96
+ }
97
+ }
98
+
99
+ if (stats.length > 0) {
100
+ sections.push(`<div class="${config.statsClass}">${stats.join('<br>')}</div>`);
101
+ }
102
+
103
+ // Item description
104
+ if (config.includeDescription && itemData.description) {
105
+ const parsedDescription = parseText(itemData.description);
106
+ sections.push(`<div class="${config.descriptionClass}">${parsedDescription}</div>`);
107
+ }
108
+
109
+ // Price information
110
+ if (config.includePricing) {
111
+ if (config.showBuyPrice && itemData.buyPrice !== undefined) {
112
+ const price = itemData.buyPrice || 0;
113
+ if (price > 0) {
114
+ sections.push(`<div class="${config.priceClass}">${config.buyPriceLabel}${price.toLocaleString()} gold</div>`);
115
+ } else {
116
+ sections.push(`<div class="${config.priceClass}">${config.notBuyableLabel}</div>`);
117
+ }
118
+ }
119
+
120
+ if (config.showSellPrice && itemData.sellPrice !== undefined) {
121
+ const price = itemData.sellPrice || 0;
122
+ if (price > 0) {
123
+ sections.push(`<div class="${config.priceClass}">${config.sellPriceLabel}${price.toLocaleString()} gold</div>`);
124
+ } else {
125
+ sections.push(`<div class="${config.priceClass}">${config.notSellableLabel}</div>`);
126
+ }
127
+ }
128
+ }
129
+
130
+ return sections.join('');
131
+ }
132
+
133
+ function hasItemStats(itemData) {
134
+ return itemData.description ||
135
+ itemData.sellPrice !== undefined ||
136
+ itemData.buyPrice !== undefined ||
137
+ itemData.damageBonus !== undefined ||
138
+ itemData.damageBonusPercent !== undefined ||
139
+ itemData.damageReduction !== undefined ||
140
+ itemData.damageReductionPercent !== undefined ||
141
+ itemData.damage !== undefined ||
142
+ itemData.damageVariance !== undefined ||
143
+ (itemData.statTexts && itemData.statTexts.length > 0) ||
144
+ itemData.statsHeader;
145
+ }
146
+
147
+ // Public API
148
+ return {
149
+ parseText: parseText,
150
+ generateItemStats: generateItemStats,
151
+ hasItemStats: hasItemStats
152
+ };
153
+ })();
154
+ </script>
155
+
156
+ <style>
157
+ /* Shared Item Stats Styles */
158
+ .item-stats {
159
+ margin-top: 6px;
160
+ font-size: 11px;
161
+ line-height: 1.4;
162
+ color: #7dd87d;
163
+ font-weight: 500;
164
+ }
165
+
166
+ .stats-header {
167
+ color: #999999;
168
+ font-weight: 500;
169
+ margin-bottom: 3px;
170
+ font-size: 11px;
171
+ }
172
+
173
+ .item-description {
174
+ color: #cccccc;
175
+ margin-top: 6px;
176
+ font-size: 11px;
177
+ line-height: 1.4;
178
+ }
179
+
180
+ .item-price {
181
+ color: #ffd700;
182
+ margin-top: 6px;
183
+ font-weight: 500;
184
+ font-size: 11px;
185
+ }
186
+
187
+ /* Crafting-specific stat styles */
188
+ .crafting-item-stats {
189
+ margin-top: 4px;
190
+ font-size: 9px;
191
+ line-height: 1.3;
192
+ color: #7dd87d;
193
+ font-weight: 500;
194
+ }
195
+
196
+ .crafting-item-stats .stats-header {
197
+ color: #999999;
198
+ font-weight: 500;
199
+ margin-bottom: 2px;
200
+ font-size: 9px;
201
+ }
202
+
203
+ .crafting-item-description {
204
+ margin-top: 4px;
205
+ font-size: 9px;
206
+ line-height: 1.3;
207
+ color: var(--crafting-text-muted, #cccccc);
208
+ }
209
+
210
+ /* Mobile styles */
211
+ body.mobile .crafting-item-stats {
212
+ font-size: 8px;
213
+ margin-top: 3px;
214
+ }
215
+
216
+ body.mobile .crafting-item-stats .stats-header {
217
+ font-size: 8px;
218
+ }
219
+
220
+ body.mobile .crafting-item-description {
221
+ font-size: 8px;
222
+ margin-top: 3px;
223
+ }
224
+ </style>
@@ -24,6 +24,12 @@ window.ItemTooltips = (function() {
24
24
  }
25
25
 
26
26
  function hasTooltipData(itemData) {
27
+ // Use shared ItemStats system if available, otherwise use basic check
28
+ if (window.ItemStats) {
29
+ return itemData.name || window.ItemStats.hasItemStats(itemData);
30
+ }
31
+
32
+ // Fallback check if ItemStats not available
27
33
  return itemData.name ||
28
34
  itemData.description ||
29
35
  itemData.sellPrice !== undefined ||
@@ -67,71 +73,27 @@ window.ItemTooltips = (function() {
67
73
  sections.push(`<div class="tooltip-name">${itemData.name}</div>`);
68
74
  }
69
75
 
70
- // Item stats (weapons and wearables)
71
- const stats = [];
72
-
73
- // Weapon damage (no "when equipped" needed since weapons are used directly)
74
- if (itemData.damage && itemData.damage !== 0) {
75
- if (itemData.damageVariance && itemData.damageVariance !== 0) {
76
- const min = Math.floor(itemData.damage * (1 - itemData.damageVariance));
77
- const max = Math.floor(itemData.damage * (1 + itemData.damageVariance));
78
- stats.push(`${min}-${max} damage`);
79
- } else {
80
- stats.push(`${itemData.damage} damage`);
81
- }
82
- }
83
-
84
- // Wearable stats
85
- const wearableStats = [];
86
- if (itemData.damageBonus && itemData.damageBonus !== 0) {
87
- wearableStats.push(`+${itemData.damageBonus} damage dealt`);
88
- }
89
- if (itemData.damageBonusPercent && itemData.damageBonusPercent !== 0) {
90
- wearableStats.push(`+${itemData.damageBonusPercent}% damage dealt`);
91
- }
92
- if (itemData.damageReduction && itemData.damageReduction !== 0) {
93
- wearableStats.push(`-${itemData.damageReduction} damage taken`);
94
- }
95
- if (itemData.damageReductionPercent && itemData.damageReductionPercent !== 0) {
96
- wearableStats.push(`-${itemData.damageReductionPercent}% damage taken`);
97
- }
98
-
99
- // Collect all stat lines first
100
- const allStatLines = [];
101
-
102
- // Add wearable stats
103
- if (wearableStats.length > 0) {
104
- allStatLines.push(...wearableStats);
105
- }
106
-
107
- // Add custom stat texts
108
- if (itemData.statTexts && itemData.statTexts.length > 0) {
109
- for (const statText of itemData.statTexts) {
110
- const parsedStatText = parseText(statText);
111
- allStatLines.push(parsedStatText);
76
+ // Use shared ItemStats system for consistent stat generation
77
+ if (window.ItemStats) {
78
+ const itemStatsHTML = window.ItemStats.generateItemStats(itemData, {
79
+ includeDescription: true,
80
+ includePricing: false,
81
+ statsClass: 'tooltip-stats',
82
+ descriptionClass: 'tooltip-description',
83
+ priceClass: 'tooltip-value'
84
+ });
85
+
86
+ if (itemStatsHTML) {
87
+ sections.push(itemStatsHTML);
112
88
  }
113
- }
114
-
115
- // Add header and stats together if we have stats
116
- if (allStatLines.length > 0) {
117
- if (itemData.statsHeader) {
118
- const headerText = parseText(itemData.statsHeader);
119
- stats.push(`<div class="tooltip-stats-header">${headerText}</div>${allStatLines.join('<br>')}`);
120
- } else {
121
- stats.push(allStatLines.join('<br>'));
89
+ } else {
90
+ // Fallback: Item description only if ItemStats not available
91
+ if (itemData.description) {
92
+ const parsedDescription = parseText(itemData.description);
93
+ sections.push(`<div class="tooltip-description">${parsedDescription}</div>`);
122
94
  }
123
95
  }
124
96
 
125
- if (stats.length > 0) {
126
- sections.push(`<div class="tooltip-stats">${stats.join('<br>')}</div>`);
127
- }
128
-
129
- // Item description
130
- if (itemData.description) {
131
- const parsedDescription = parseText(itemData.description);
132
- sections.push(`<div class="tooltip-description">${parsedDescription}</div>`);
133
- }
134
-
135
97
  // Price information
136
98
  if (config.showBuyPrice && itemData.buyPrice !== undefined) {
137
99
  const price = itemData.buyPrice || 0;
@@ -189,22 +151,31 @@ window.ItemTooltips = (function() {
189
151
  .backpack-slot:hover .item-tooltip,
190
152
  .backpack-hotbar-slot:hover .item-tooltip,
191
153
  .backpack-wearable-slot:hover .item-tooltip,
192
- .merchant-slot:hover .item-tooltip,
193
- .merchant-hotbar-slot:hover .item-tooltip,
194
- /* Tooltip visibility on hover - Specific classes */
195
- .backpack-slot:hover .backpack-item-tooltip,
196
- .backpack-hotbar-slot:hover .backpack-item-tooltip,
197
- .backpack-wearable-slot:hover .backpack-item-tooltip,
198
- .merchant-slot:hover .merchant-item-tooltip,
199
- .merchant-hotbar-slot:hover .merchant-item-tooltip {
154
+ .merchant-slot:hover .item-tooltip,
155
+ .merchant-hotbar-slot:hover .item-tooltip,
156
+ .crafting-slot:hover .item-tooltip,
157
+ .crafting-requirement-item:hover .item-tooltip,
158
+ .quests-reward-item:hover .item-tooltip,
159
+ /* Tooltip visibility on hover - Specific classes */
160
+ .backpack-slot:hover .backpack-item-tooltip,
161
+ .backpack-hotbar-slot:hover .backpack-item-tooltip,
162
+ .backpack-wearable-slot:hover .backpack-item-tooltip,
163
+ .merchant-slot:hover .merchant-item-tooltip,
164
+ .merchant-hotbar-slot:hover .merchant-item-tooltip,
165
+ .crafting-slot:hover .crafting-item-tooltip,
166
+ .crafting-requirement-item:hover .crafting-requirement-tooltip,
167
+ .quests-reward-item:hover .quests-reward-item-tooltip {
200
168
  opacity: 1;
201
169
  visibility: visible;
202
170
  transform: translateY(-8px);
203
171
  }
204
172
 
205
- .item-tooltip-content,
206
- .backpack-item-tooltip-content,
207
- .merchant-item-tooltip-content {
173
+ .item-tooltip-content,
174
+ .backpack-item-tooltip-content,
175
+ .merchant-item-tooltip-content,
176
+ .crafting-item-tooltip-content,
177
+ .crafting-requirement-tooltip-content,
178
+ .quests-reward-item-tooltip-content {
208
179
  background: linear-gradient(145deg, #2a2a2a, #1e1e1e);
209
180
  border: 2px solid #444;
210
181
  border-radius: 8px;
@@ -225,9 +196,12 @@ window.ItemTooltips = (function() {
225
196
  }
226
197
 
227
198
  /* Tooltip Caret */
228
- .item-tooltip-content::after,
229
- .backpack-item-tooltip-content::after,
230
- .merchant-item-tooltip-content::after {
199
+ .item-tooltip-content::after,
200
+ .backpack-item-tooltip-content::after,
201
+ .merchant-item-tooltip-content::after,
202
+ .crafting-item-tooltip-content::after,
203
+ .crafting-requirement-tooltip-content::after,
204
+ .quests-reward-item-tooltip-content::after {
231
205
  content: '';
232
206
  position: absolute;
233
207
  top: 100%;
@@ -237,9 +211,12 @@ window.ItemTooltips = (function() {
237
211
  border-top-color: #444;
238
212
  }
239
213
 
240
- .item-tooltip-content::before,
241
- .backpack-item-tooltip-content::before,
242
- .merchant-item-tooltip-content::before {
214
+ .item-tooltip-content::before,
215
+ .backpack-item-tooltip-content::before,
216
+ .merchant-item-tooltip-content::before,
217
+ .crafting-item-tooltip-content::before,
218
+ .crafting-requirement-tooltip-content::before,
219
+ .quests-reward-item-tooltip-content::before {
243
220
  content: '';
244
221
  position: absolute;
245
222
  top: calc(100% - 2px);
@@ -247,8 +224,17 @@ window.ItemTooltips = (function() {
247
224
  transform: translateX(-50%);
248
225
  border: 6px solid transparent;
249
226
  border-top-color: #2a2a2a;
250
- z-index: 1;
251
- }
227
+ z-index: 1;
228
+ }
229
+
230
+ /* Tooltip Content Sections */
231
+ .tooltip-name,
232
+ .backpack-tooltip-name,
233
+ .merchant-tooltip-name {
234
+ font-weight: 600;
235
+ color: #ffffff;
236
+ font-size: 12px;
237
+ }
252
238
 
253
239
  /* Tooltip Content Sections */
254
240
  .tooltip-name,
@@ -295,7 +281,12 @@ window.ItemTooltips = (function() {
295
281
  }
296
282
 
297
283
  /* Mobile - Hide tooltips on mobile devices */
298
- body.mobile .item-tooltip {
284
+ body.mobile .item-tooltip,
285
+ body.mobile .backpack-item-tooltip,
286
+ body.mobile .merchant-item-tooltip,
287
+ body.mobile .crafting-item-tooltip,
288
+ body.mobile .crafting-requirement-tooltip,
289
+ body.mobile .quests-reward-item-tooltip {
299
290
  display: none;
300
291
  }
301
292
 
@@ -1,31 +1,140 @@
1
1
  {
2
- "health": 100,
3
- "currentRegionId": "stalkhaven-port",
4
- "currentRegionSpawnFacingAngle": 180,
5
- "currentRegionSpawnPoint": {
6
- "x": -6,
7
- "y": 8,
8
- "z": -28
9
- },
10
- "skillExperience": [],
2
+ "health": 130,
3
+ "currentRegionId": "stalkhaven",
4
+ "skillExperience": [
5
+ [
6
+ "exploration",
7
+ 375
8
+ ],
9
+ [
10
+ "agility",
11
+ 79
12
+ ],
13
+ [
14
+ "combat",
15
+ 320
16
+ ],
17
+ [
18
+ "foraging",
19
+ 8
20
+ ]
21
+ ],
11
22
  "backpack": {
12
- "items": []
23
+ "items": [
24
+ {
25
+ "position": 0,
26
+ "itemId": "common_mushroom",
27
+ "quantity": 3
28
+ },
29
+ {
30
+ "position": 1,
31
+ "itemId": "ratkin_tooth",
32
+ "quantity": 3
33
+ }
34
+ ]
13
35
  },
14
36
  "hotbar": {
15
37
  "items": [
16
38
  {
17
39
  "position": 0,
40
+ "itemId": "dull_sword"
41
+ },
42
+ {
43
+ "position": 2,
18
44
  "itemId": "toy_sword"
45
+ },
46
+ {
47
+ "position": 3,
48
+ "itemId": "gold",
49
+ "quantity": 147
50
+ },
51
+ {
52
+ "position": 1,
53
+ "itemId": "raw_hide",
54
+ "quantity": 2
55
+ },
56
+ {
57
+ "position": 4,
58
+ "itemId": "ratkin_eyes"
59
+ },
60
+ {
61
+ "position": 5,
62
+ "itemId": "ratkin_tail",
63
+ "quantity": 2
64
+ },
65
+ {
66
+ "position": 6,
67
+ "itemId": "ratkin_bones",
68
+ "quantity": 3
69
+ },
70
+ {
71
+ "position": 7,
72
+ "itemId": "common_seeds",
73
+ "quantity": 4
19
74
  }
20
75
  ]
21
76
  },
22
77
  "questLog": {
23
- "quests": []
78
+ "quests": [
79
+ {
80
+ "questId": "welcome-to-stalkhaven",
81
+ "state": "completed",
82
+ "objectiveProgress": {
83
+ "talk-to-mark": 1
84
+ }
85
+ },
86
+ {
87
+ "questId": "exploring-stalkhaven",
88
+ "state": "completed",
89
+ "objectiveProgress": {
90
+ "talk-to-mycelis": 1,
91
+ "talk-to-finn": 1,
92
+ "talk-to-sporn": 1,
93
+ "talk-to-mark": 1
94
+ }
95
+ },
96
+ {
97
+ "questId": "tested-mettle",
98
+ "state": "completed",
99
+ "objectiveProgress": {
100
+ "kill-5-ratkin": 5,
101
+ "dodge-3-times": 3,
102
+ "talk-to-mark": 1
103
+ }
104
+ },
105
+ {
106
+ "questId": "hammers-and-crafting",
107
+ "state": "active",
108
+ "objectiveProgress": {
109
+ "gather-materials": 2,
110
+ "craft-item": 0,
111
+ "talk-to-arden": 0
112
+ }
113
+ },
114
+ {
115
+ "questId": "stalkhavens-outpost",
116
+ "state": "active",
117
+ "objectiveProgress": {
118
+ "talk-to-chanterelion": 0
119
+ }
120
+ }
121
+ ]
24
122
  },
25
123
  "storage": {
26
124
  "items": []
27
125
  },
28
126
  "wearables": {
29
- "items": []
127
+ "items": [
128
+ {
129
+ "position": 1,
130
+ "itemId": "adventurer_tunic"
131
+ }
132
+ ]
133
+ },
134
+ "currentRegionSpawnFacingAngle": 0,
135
+ "currentRegionSpawnPoint": {
136
+ "x": 1,
137
+ "y": 2,
138
+ "z": 40
30
139
  }
31
140
  }