@hytopia.com/examples 1.0.12 → 1.0.14

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 (68) 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 +120 -11
  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/BaseWeaponItem.ts +2 -2
  43. package/frontiers-rpg-game/src/items/ItemClasses.ts +14 -2
  44. package/frontiers-rpg-game/src/items/materials/RawHideItem.ts +10 -0
  45. package/frontiers-rpg-game/src/items/weapons/DullSwordItem.ts +5 -4
  46. package/frontiers-rpg-game/src/items/weapons/IronDaggerItem.ts +1 -1
  47. package/frontiers-rpg-game/src/items/weapons/IronLongSwordItem.ts +5 -4
  48. package/frontiers-rpg-game/src/items/weapons/SpikedClubItem.ts +26 -0
  49. package/frontiers-rpg-game/src/items/weapons/TrainingSwordItem.ts +5 -4
  50. package/frontiers-rpg-game/src/items/wearables/LeatherBootsItem.ts +14 -0
  51. package/frontiers-rpg-game/src/items/wearables/LeatherBracersItem.ts +14 -0
  52. package/frontiers-rpg-game/src/items/wearables/LeatherHelmetItem.ts +14 -0
  53. package/frontiers-rpg-game/src/items/wearables/LeatherLeggingsItem.ts +14 -0
  54. package/frontiers-rpg-game/src/items/wearables/LeatherVestItem.ts +14 -0
  55. package/frontiers-rpg-game/src/quests/BaseQuest.ts +1 -2
  56. package/frontiers-rpg-game/src/quests/QuestClasses.ts +2 -0
  57. package/frontiers-rpg-game/src/quests/side/FungalForagingQuest.ts +1 -23
  58. package/frontiers-rpg-game/src/quests/side/HammersAndCraftingQuest.ts +139 -0
  59. package/frontiers-rpg-game/src/regions/stalkhaven/StalkhavenRegion.ts +35 -22
  60. package/frontiers-rpg-game/src/regions/stalkhaven/npcs/BlacksmithArdenEntity.ts +114 -0
  61. package/frontiers-rpg-game/src/systems/QuestLog.ts +2 -5
  62. package/package.json +1 -1
  63. package/frontiers-rpg-game/dev/persistence/player-player-2.json +0 -31
  64. package/frontiers-rpg-game/dev/persistence/player-player-3.json +0 -25
  65. package/frontiers-rpg-game/dev/persistence/player-player-4.json +0 -31
  66. package/frontiers-rpg-game/src/items/materials/MonsterHideItem.ts +0 -10
  67. /package/frontiers-rpg-game/assets/icons/items/{monster-hide.png → raw-hide.png} +0 -0
  68. /package/frontiers-rpg-game/assets/models/weapons/{club.gltf → spiked-club.gltf} +0 -0
@@ -0,0 +1,976 @@
1
+ <!-- Crafting UI -->
2
+ <div class="crafting-overlay">
3
+ <div class="crafting-container">
4
+ <div class="crafting-header">
5
+ <div class="crafting-info">
6
+ <img src="" alt="Crafter" class="crafting-avatar">
7
+ <div class="crafting-details">
8
+ <div class="crafting-name"></div>
9
+ <div class="crafting-title"></div>
10
+ </div>
11
+ </div>
12
+ <button class="crafting-close">×</button>
13
+ </div>
14
+
15
+ <div class="crafting-content">
16
+ <!-- Left Panel - Craftable Items Grid -->
17
+ <div class="crafting-grid-container">
18
+ <div class="crafting-grid" id="crafting-grid">
19
+ <!-- Grid slots will be generated by JavaScript -->
20
+ </div>
21
+ </div>
22
+
23
+ <!-- Right Panel - Crafting Details & Requirements -->
24
+ <div class="crafting-right-panel">
25
+ <div class="crafting-panel-content">
26
+ <div class="crafting-placeholder">
27
+ Select an item to view its requirements and craft it.
28
+ </div>
29
+ </div>
30
+ </div>
31
+ </div>
32
+ </div>
33
+ </div>
34
+
35
+ <script>
36
+ // Configuration
37
+ const CRAFTING_CONFIG = {
38
+ slots: 12,
39
+ rowWidth: 4,
40
+ minRows: 3
41
+ };
42
+
43
+ // State management
44
+ const craftingState = {
45
+ craftingRecipes: [],
46
+ selectedRecipe: null
47
+ };
48
+
49
+ // Setup hytopia data handlers
50
+ hytopia.onData(data => {
51
+ if (data.type === 'toggleCrafting') {
52
+ toggleCrafting(data);
53
+ }
54
+ });
55
+
56
+ // Initialize crafting system
57
+ function initializeCrafting() {
58
+ createCraftingSlots();
59
+
60
+ // Add close button handler
61
+ const closeButton = document.querySelector('.crafting-close');
62
+ if (closeButton) {
63
+ closeButton.addEventListener('click', () => toggleCrafting(null));
64
+ }
65
+ }
66
+
67
+ function createCraftingSlots() {
68
+ const grid = document.getElementById('crafting-grid');
69
+ grid.innerHTML = '';
70
+
71
+ for (let i = 0; i < CRAFTING_CONFIG.slots; i++) {
72
+ const slot = document.createElement('div');
73
+ slot.className = 'crafting-slot';
74
+ slot.dataset.slotIndex = i;
75
+ slot.innerHTML = '<div class="crafting-slot-content"></div>';
76
+ grid.appendChild(slot);
77
+ }
78
+ }
79
+
80
+ // Use shared tooltip system
81
+ function createTooltip(slot, itemData) {
82
+ const options = {
83
+ tooltipClass: 'crafting-item-tooltip',
84
+ contentClass: 'crafting-item-tooltip-content',
85
+ showBuyPrice: false,
86
+ showSellPrice: false,
87
+ showCraftable: true
88
+ };
89
+
90
+ ItemTooltips.createTooltip(slot, itemData, options);
91
+ }
92
+
93
+ function removeTooltip(slot) {
94
+ ItemTooltips.removeTooltip(slot, 'crafting-item-tooltip');
95
+ }
96
+
97
+ // Create tooltip for requirement items
98
+ function createRequirementTooltip(item, requirementData) {
99
+ const options = {
100
+ tooltipClass: 'crafting-requirement-tooltip',
101
+ contentClass: 'crafting-requirement-tooltip-content',
102
+ showBuyPrice: false,
103
+ showSellPrice: false
104
+ };
105
+
106
+ ItemTooltips.createTooltip(item, requirementData, options);
107
+ }
108
+
109
+ function removeRequirementTooltip(item) {
110
+ ItemTooltips.removeTooltip(item, 'crafting-requirement-tooltip');
111
+ }
112
+
113
+ function createItemContent(content, itemData) {
114
+ // Create item icon
115
+ const icon = document.createElement('img');
116
+ icon.src = `{{CDN_ASSETS_URL}}/${itemData.iconImageUri}`;
117
+ icon.alt = 'Item';
118
+ icon.className = 'crafting-item-icon';
119
+ content.appendChild(icon);
120
+
121
+ // Add quantity if greater than 1
122
+ if (itemData.quantity && itemData.quantity > 1) {
123
+ const quantity = document.createElement('div');
124
+ quantity.className = 'crafting-slot-quantity';
125
+ quantity.textContent = itemData.quantity.toLocaleString();
126
+ content.appendChild(quantity);
127
+ }
128
+ }
129
+
130
+ // Slot update functions
131
+ function updateCraftingSlot(position, recipeData) {
132
+ if (position < 0 || position >= CRAFTING_CONFIG.slots) return;
133
+
134
+ const slots = document.querySelectorAll('.crafting-slot');
135
+ const slot = slots[position];
136
+ if (!slot) return;
137
+
138
+ const content = slot.querySelector('.crafting-slot-content');
139
+ if (!content) return;
140
+
141
+ // Clear existing content and tooltip
142
+ content.innerHTML = '';
143
+ removeTooltip(slot);
144
+
145
+ // Remove previous click handler
146
+ slot.onclick = null;
147
+ slot.classList.remove('crafting-slot-selected');
148
+
149
+ if (!recipeData || recipeData.removed) {
150
+ // Empty slot
151
+ return;
152
+ }
153
+
154
+ const craftedItem = recipeData.craftedItem;
155
+ createItemContent(content, craftedItem);
156
+ createTooltip(slot, craftedItem);
157
+
158
+ // Add click handler for recipe selection
159
+ slot.onclick = () => selectCraftingRecipe(recipeData, position);
160
+ }
161
+
162
+ // Helper functions for crafting management
163
+ function updateCrafterInfo(crafterName, crafterTitle, crafterAvatarUri) {
164
+ const avatar = document.querySelector('.crafting-avatar');
165
+ const name = document.querySelector('.crafting-name');
166
+ const title = document.querySelector('.crafting-title');
167
+
168
+ if (avatar && crafterAvatarUri) {
169
+ avatar.src = `{{CDN_ASSETS_URL}}/${crafterAvatarUri}`;
170
+ }
171
+ if (name) {
172
+ name.textContent = crafterName || 'Crafter';
173
+ }
174
+ if (title) {
175
+ title.textContent = crafterTitle || '';
176
+ }
177
+ }
178
+
179
+ function setCraftingVisibility(visible) {
180
+ const overlay = document.querySelector('.crafting-overlay');
181
+ if (overlay) {
182
+ overlay.style.display = visible ? 'flex' : 'none';
183
+ }
184
+ }
185
+
186
+ function updateCraftingGrid(rows) {
187
+ CRAFTING_CONFIG.slots = rows * CRAFTING_CONFIG.rowWidth;
188
+ createCraftingSlots();
189
+
190
+ const craftingGrid = document.getElementById('crafting-grid');
191
+ if (craftingGrid) {
192
+ craftingGrid.style.gridTemplateRows = `repeat(${rows}, 1fr)`;
193
+ }
194
+ }
195
+
196
+ function populateSlots(items, maxSlots, updateFunction) {
197
+ for (let i = 0; i < maxSlots; i++) {
198
+ const item = items[i];
199
+ updateFunction(i, item || { removed: true });
200
+ }
201
+ }
202
+
203
+ function calculateRequiredRows(craftingRecipes) {
204
+ if (!craftingRecipes || craftingRecipes.length === 0) return CRAFTING_CONFIG.minRows;
205
+
206
+ const positions = craftingRecipes
207
+ .map(recipe => recipe.position)
208
+ .filter(pos => typeof pos === 'number');
209
+
210
+ if (positions.length === 0) return CRAFTING_CONFIG.minRows;
211
+
212
+ const maxPosition = Math.max(11, Math.max(...positions)); // At least 12 slots (0-11)
213
+ return Math.ceil((maxPosition + 1) / CRAFTING_CONFIG.rowWidth);
214
+ }
215
+
216
+ function populateCraftingRecipes(craftingRecipes) {
217
+ if (!craftingRecipes || craftingRecipes.length === 0) return;
218
+
219
+ craftingRecipes.forEach(recipe => {
220
+ if (typeof recipe.position === 'number' &&
221
+ recipe.position >= 0 &&
222
+ recipe.position < CRAFTING_CONFIG.slots) {
223
+ updateCraftingSlot(recipe.position, recipe);
224
+ }
225
+ });
226
+ }
227
+
228
+ function updateRightPanelContent() {
229
+ const placeholder = document.querySelector('.crafting-panel-content');
230
+ if (!placeholder) return;
231
+
232
+ if (craftingState.selectedRecipe) {
233
+ renderCraftingDetails();
234
+ } else {
235
+ placeholder.innerHTML = `
236
+ <div class="crafting-placeholder">
237
+ Select a craftable item to view its requirements and craft it.
238
+ </div>
239
+ `;
240
+ }
241
+ }
242
+
243
+ function selectCraftingRecipe(recipeData, position) {
244
+ // Clear previous selection highlighting
245
+ document.querySelectorAll('.crafting-slot-selected').forEach(slot => {
246
+ slot.classList.remove('crafting-slot-selected');
247
+ });
248
+
249
+ craftingState.selectedRecipe = {
250
+ ...recipeData,
251
+ position
252
+ };
253
+
254
+ // Highlight the selected slot
255
+ const slots = document.querySelectorAll('.crafting-slot');
256
+ const selectedSlot = slots[position];
257
+ if (selectedSlot) {
258
+ selectedSlot.classList.add('crafting-slot-selected');
259
+ }
260
+
261
+ updateRightPanelContent();
262
+ }
263
+
264
+ function clearSelection() {
265
+ // Clear previous selection highlighting
266
+ document.querySelectorAll('.crafting-slot-selected').forEach(slot => {
267
+ slot.classList.remove('crafting-slot-selected');
268
+ });
269
+
270
+ craftingState.selectedRecipe = null;
271
+ updateRightPanelContent();
272
+ }
273
+
274
+ function renderCraftingDetails() {
275
+ const placeholder = document.querySelector('.crafting-panel-content');
276
+ if (!placeholder || !craftingState.selectedRecipe) return;
277
+
278
+ // Clear any existing requirement tooltips
279
+ const existingRequirements = placeholder.querySelectorAll('.crafting-requirement-item');
280
+ existingRequirements.forEach(item => removeRequirementTooltip(item));
281
+
282
+ const recipe = craftingState.selectedRecipe;
283
+ const craftedItem = recipe.craftedItem;
284
+ const requirements = recipe.requirements || [];
285
+
286
+ // Generate item stats using the shared system
287
+ const itemStatsHTML = window.ItemStats ?
288
+ window.ItemStats.generateItemStats(craftedItem, {
289
+ includeDescription: true,
290
+ includePricing: false,
291
+ statsClass: 'crafting-item-stats',
292
+ descriptionClass: 'crafting-item-description'
293
+ }) : '';
294
+
295
+ placeholder.innerHTML = `
296
+ <div class="crafting-item-details">
297
+ <div class="crafting-item-header">
298
+ <img src="{{CDN_ASSETS_URL}}/${craftedItem.iconImageUri}" alt="${craftedItem.name}" class="crafting-item-icon">
299
+ <div class="crafting-item-info">
300
+ <div class="crafting-item-name">${craftedItem.name}</div>
301
+ ${itemStatsHTML}
302
+ </div>
303
+ </div>
304
+
305
+ <div class="crafting-requirements">
306
+ <div class="crafting-requirements-title">Requirements:</div>
307
+ <div class="crafting-requirements-list">
308
+ ${requirements.length > 0 ?
309
+ requirements.map((req, index) => `
310
+ <div class="crafting-requirement-item" data-requirement-index="${index}">
311
+ <img src="{{CDN_ASSETS_URL}}/${req.iconImageUri}" alt="${req.name}" class="crafting-requirement-icon">
312
+ <div class="crafting-requirement-info">
313
+ <div class="crafting-requirement-name">${req.name}</div>
314
+ <div class="crafting-requirement-quantity">x${req.quantity || 1}</div>
315
+ </div>
316
+ </div>
317
+ `).join('') :
318
+ '<div class="crafting-no-requirements">No materials required</div>'
319
+ }
320
+ </div>
321
+ </div>
322
+
323
+ <div class="crafting-item-actions">
324
+ <button class="crafting-action-btn crafting-confirm-action">Craft</button>
325
+ </div>
326
+ </div>
327
+ `;
328
+
329
+ // Add event listener
330
+ const confirmBtn = placeholder.querySelector('.crafting-confirm-action');
331
+
332
+ if (confirmBtn) {
333
+ confirmBtn.addEventListener('click', confirmCrafting);
334
+ }
335
+
336
+ // Add tooltips to requirement items
337
+ const requirementItems = placeholder.querySelectorAll('.crafting-requirement-item');
338
+ requirementItems.forEach((item, index) => {
339
+ if (requirements[index]) {
340
+ createRequirementTooltip(item, requirements[index]);
341
+ }
342
+ });
343
+ }
344
+
345
+ function confirmCrafting() {
346
+ if (!craftingState.selectedRecipe) return;
347
+
348
+ const actionData = {
349
+ type: 'craftItem',
350
+ recipeIndex: craftingState.selectedRecipe.position,
351
+ quantity: 1
352
+ };
353
+
354
+ hytopia.sendData(actionData);
355
+ clearSelection();
356
+ }
357
+
358
+ function toggleCrafting(data) {
359
+ if (!data) {
360
+ setCraftingVisibility(false);
361
+ clearSelection();
362
+ hytopia.lockPointer(true);
363
+ return;
364
+ }
365
+
366
+ const { craftingRecipes, crafterName, crafterTitle, crafterAvatarUri } = data;
367
+ craftingState.craftingRecipes = craftingRecipes || [];
368
+ clearSelection(); // Clear selection when opening
369
+
370
+ // Update crafter info
371
+ updateCrafterInfo(crafterName, crafterTitle, crafterAvatarUri);
372
+
373
+ setCraftingVisibility(true);
374
+
375
+ const requiredRows = calculateRequiredRows(craftingRecipes);
376
+ updateCraftingGrid(requiredRows);
377
+ populateCraftingRecipes(craftingRecipes);
378
+
379
+ hytopia.lockPointer(false, true);
380
+ }
381
+
382
+ // Initialize on load
383
+ initializeCrafting();
384
+ </script>
385
+
386
+ <style>
387
+ :root {
388
+ --crafting-slot-size: 56px;
389
+ --crafting-icon-size: 32px;
390
+ --crafting-gap: 6px;
391
+ --crafting-padding: 12px;
392
+ --crafting-font: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
393
+
394
+ /* Color palette - matching merchant */
395
+ --crafting-bg-primary: linear-gradient(145deg, #2a2a2a, #1e1e1e);
396
+ --crafting-bg-secondary: linear-gradient(135deg, #3a3a3a, #2d2d2d);
397
+ --crafting-border: #444;
398
+ --crafting-border-light: #555;
399
+ --crafting-text: #ffffff;
400
+ --crafting-text-muted: #cccccc;
401
+ --crafting-text-dim: #888;
402
+ --crafting-overlay: rgba(0, 0, 0, 0.3);
403
+ --crafting-shadow: 0 8px 32px rgba(0, 0, 0, 0.9);
404
+ --crafting-shadow-inset: inset 0 2px 8px rgba(0, 0, 0, 0.5);
405
+ --crafting-accent: #4CAF50;
406
+ --crafting-accent-hover: #66BB6A;
407
+ }
408
+
409
+ .crafting-overlay {
410
+ position: fixed;
411
+ inset: 0;
412
+ background: rgba(0, 0, 0, 0.8);
413
+ display: none;
414
+ flex-direction: column;
415
+ align-items: center;
416
+ justify-content: center;
417
+ z-index: 1000;
418
+ font-family: var(--crafting-font);
419
+ user-select: none;
420
+ }
421
+
422
+ /* Container styles */
423
+ .crafting-container {
424
+ background: var(--crafting-bg-primary);
425
+ border: 2px solid var(--crafting-border);
426
+ border-radius: 12px;
427
+ box-shadow: var(--crafting-shadow), inset 0 1px 0 rgba(255, 255, 255, 0.1);
428
+ width: 680px;
429
+ }
430
+
431
+ /* Header styles */
432
+ .crafting-header {
433
+ display: flex;
434
+ justify-content: space-between;
435
+ align-items: center;
436
+ padding: 16px 20px;
437
+ background: var(--crafting-bg-secondary);
438
+ border-bottom: 1px solid var(--crafting-border);
439
+ }
440
+
441
+ .crafting-info {
442
+ display: flex;
443
+ align-items: center;
444
+ gap: 12px;
445
+ flex: 1;
446
+ min-width: 0;
447
+ }
448
+
449
+ .crafting-avatar {
450
+ width: 48px;
451
+ height: 48px;
452
+ border: 2px solid var(--crafting-border);
453
+ border-radius: 6px;
454
+ object-fit: cover;
455
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.6);
456
+ flex-shrink: 0;
457
+ }
458
+
459
+ .crafting-details {
460
+ display: flex;
461
+ flex-direction: column;
462
+ min-width: 0;
463
+ flex: 1;
464
+ }
465
+
466
+ .crafting-name {
467
+ font-size: 16px;
468
+ font-weight: 600;
469
+ color: var(--crafting-text);
470
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.9);
471
+ line-height: 1;
472
+ white-space: nowrap;
473
+ overflow: hidden;
474
+ text-overflow: ellipsis;
475
+ }
476
+
477
+ .crafting-title {
478
+ font-size: 14px;
479
+ font-weight: 500;
480
+ color: var(--crafting-text-muted);
481
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.9);
482
+ margin-top: 2px;
483
+ white-space: nowrap;
484
+ overflow: hidden;
485
+ text-overflow: ellipsis;
486
+ letter-spacing: 0.3px;
487
+ }
488
+
489
+ .crafting-close {
490
+ background: rgba(255, 0, 0, 0.2);
491
+ border: 1px solid rgba(255, 0, 0, 0.3);
492
+ border-radius: 6px;
493
+ color: #ff6b6b;
494
+ width: 24px;
495
+ height: 24px;
496
+ display: flex;
497
+ align-items: center;
498
+ justify-content: center;
499
+ font-size: 16px;
500
+ font-weight: bold;
501
+ cursor: pointer;
502
+ transition: all 0.2s ease;
503
+ }
504
+
505
+ .crafting-close:hover {
506
+ background: rgba(255, 0, 0, 0.3);
507
+ transform: scale(1.05);
508
+ }
509
+
510
+ /* Layout - 50/50 split */
511
+ .crafting-content {
512
+ padding: 20px;
513
+ display: flex;
514
+ gap: 20px;
515
+ align-items: flex-start;
516
+ }
517
+
518
+ .crafting-grid-container {
519
+ flex: 1;
520
+ }
521
+
522
+ .crafting-right-panel {
523
+ flex: 1;
524
+ background: var(--crafting-overlay);
525
+ border: 1px solid var(--crafting-border);
526
+ border-radius: 8px;
527
+ padding: var(--crafting-padding);
528
+ min-height: 192px;
529
+ display: flex;
530
+ align-items: center;
531
+ justify-content: center;
532
+ }
533
+
534
+ .crafting-panel-content {
535
+ width: 100%;
536
+ }
537
+
538
+ .crafting-placeholder {
539
+ color: #666;
540
+ font-size: 14px;
541
+ text-align: center;
542
+ line-height: 1.5;
543
+ }
544
+
545
+ /* Grid styles */
546
+ .crafting-grid {
547
+ display: grid;
548
+ grid-template: repeat(3, 1fr) / repeat(4, 1fr);
549
+ gap: var(--crafting-gap);
550
+ background: var(--crafting-overlay);
551
+ padding: var(--crafting-padding);
552
+ border: 1px solid var(--crafting-border);
553
+ border-radius: 8px;
554
+ box-shadow: var(--crafting-shadow-inset);
555
+ }
556
+
557
+ /* Slot styles */
558
+ .crafting-slot {
559
+ background: rgba(0, 0, 0, 0.6);
560
+ border: 2px solid #333;
561
+ border-radius: 6px;
562
+ display: flex;
563
+ align-items: center;
564
+ justify-content: center;
565
+ position: relative;
566
+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.7);
567
+ transition: all 0.2s ease;
568
+ cursor: pointer;
569
+ width: var(--crafting-slot-size);
570
+ height: var(--crafting-slot-size);
571
+ }
572
+
573
+ .crafting-slot:hover {
574
+ border-color: var(--crafting-border-light);
575
+ background: rgba(0, 0, 0, 0.8);
576
+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.7), 0 2px 8px rgba(0, 0, 0, 0.5);
577
+ transform: translateY(-1px);
578
+ }
579
+
580
+ .crafting-slot-selected {
581
+ border-color: #4CAF50 !important;
582
+ background: rgba(76, 175, 80, 0.1) !important;
583
+ box-shadow: 0 0 0 2px rgba(76, 175, 80, 0.3) !important;
584
+ }
585
+
586
+ .crafting-slot-content {
587
+ width: 100%;
588
+ height: 100%;
589
+ display: flex;
590
+ align-items: center;
591
+ justify-content: center;
592
+ }
593
+
594
+ .crafting-item-icon {
595
+ width: 48px;
596
+ height: 48px;
597
+ object-fit: contain;
598
+ image-rendering: pixelated;
599
+ filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.8));
600
+ }
601
+
602
+ /* Quantity badges */
603
+ .crafting-slot-quantity {
604
+ position: absolute;
605
+ bottom: 2px;
606
+ right: 2px;
607
+ background: rgba(0, 0, 0, 0.8);
608
+ color: var(--crafting-text);
609
+ font-weight: 700;
610
+ padding: 1px 3px;
611
+ border-radius: 3px;
612
+ line-height: 1;
613
+ text-shadow: 0 1px 1px rgba(0, 0, 0, 0.9);
614
+ border: 1px solid rgba(255, 255, 255, 0.2);
615
+ min-width: 10px;
616
+ text-align: center;
617
+ font-size: 9px;
618
+ }
619
+
620
+ /* Item Details Panel */
621
+ .crafting-item-details {
622
+ width: 100%;
623
+ display: flex;
624
+ flex-direction: column;
625
+ gap: 10px;
626
+ }
627
+
628
+ .crafting-item-header {
629
+ display: flex;
630
+ flex-direction: row;
631
+ align-items: flex-start;
632
+ gap: 8px;
633
+ padding: 8px;
634
+ background: rgba(0, 0, 0, 0.2);
635
+ border: 1px solid var(--crafting-border);
636
+ border-radius: 6px;
637
+ margin-bottom: 8px;
638
+ }
639
+
640
+ .crafting-item-header .crafting-item-icon {
641
+ width: 32px;
642
+ height: 32px;
643
+ border-radius: 4px;
644
+ background: rgba(0, 0, 0, 0.4);
645
+ padding: 2px;
646
+ flex-shrink: 0;
647
+ }
648
+
649
+ .crafting-item-info {
650
+ display: flex;
651
+ flex-direction: column;
652
+ align-items: flex-start;
653
+ gap: 2px;
654
+ flex: 1;
655
+ min-width: 0;
656
+ }
657
+
658
+ .crafting-item-name {
659
+ font-size: 12px;
660
+ font-weight: 500;
661
+ color: var(--crafting-text);
662
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.9);
663
+ text-align: left;
664
+ width: 100%;
665
+ line-height: 1.2;
666
+ word-wrap: break-word;
667
+ word-break: break-word;
668
+ hyphens: auto;
669
+ }
670
+
671
+ /* Requirements section */
672
+ .crafting-requirements {
673
+ display: flex;
674
+ flex-direction: column;
675
+ gap: 8px;
676
+ }
677
+
678
+ .crafting-requirements-title {
679
+ font-size: 12px;
680
+ font-weight: 600;
681
+ color: var(--crafting-text);
682
+ margin-bottom: 4px;
683
+ }
684
+
685
+ .crafting-requirements-list {
686
+ display: grid;
687
+ grid-template-columns: repeat(3, 1fr);
688
+ gap: 6px;
689
+ }
690
+
691
+ .crafting-requirement-item {
692
+ display: flex;
693
+ flex-direction: row;
694
+ align-items: center;
695
+ gap: 6px;
696
+ padding: 4px 6px;
697
+ background: rgba(0, 0, 0, 0.3);
698
+ border: 1px solid var(--crafting-border);
699
+ border-radius: 6px;
700
+ min-height: 32px;
701
+ position: relative;
702
+ cursor: pointer;
703
+ transition: all 0.2s ease;
704
+ }
705
+
706
+ .crafting-requirement-item:hover {
707
+ background: rgba(0, 0, 0, 0.5);
708
+ border-color: var(--crafting-border-light);
709
+ transform: translateY(-1px);
710
+ }
711
+
712
+ .crafting-requirement-icon {
713
+ width: 20px;
714
+ height: 20px;
715
+ object-fit: contain;
716
+ image-rendering: pixelated;
717
+ border-radius: 3px;
718
+ background: rgba(0, 0, 0, 0.4);
719
+ padding: 1px;
720
+ flex-shrink: 0;
721
+ }
722
+
723
+ .crafting-requirement-info {
724
+ display: flex;
725
+ flex-direction: column;
726
+ align-items: flex-start;
727
+ gap: 1px;
728
+ min-width: 0;
729
+ flex: 1;
730
+ }
731
+
732
+ .crafting-requirement-name {
733
+ font-size: 10px;
734
+ color: var(--crafting-text);
735
+ font-weight: 500;
736
+ line-height: 1.2;
737
+ text-align: left;
738
+ width: 100%;
739
+ overflow: hidden;
740
+ text-overflow: ellipsis;
741
+ white-space: nowrap;
742
+ }
743
+
744
+ .crafting-requirement-quantity {
745
+ font-size: 9px;
746
+ color: var(--crafting-text-muted);
747
+ font-weight: 600;
748
+ padding: 1px 3px;
749
+ border-radius: 2px;
750
+ line-height: 1;
751
+ }
752
+
753
+ .crafting-no-requirements {
754
+ color: var(--crafting-text-dim);
755
+ font-size: 12px;
756
+ text-align: center;
757
+ padding: 16px;
758
+ font-style: italic;
759
+ grid-column: 1 / -1;
760
+ background: rgba(0, 0, 0, 0.2);
761
+ border: 1px dashed var(--crafting-border);
762
+ border-radius: 6px;
763
+ }
764
+
765
+ /* Actions section */
766
+ .crafting-item-actions {
767
+ display: flex;
768
+ align-items: center;
769
+ justify-content: center;
770
+ padding-top: 8px;
771
+ }
772
+
773
+ .crafting-action-btn {
774
+ padding: 8px 16px;
775
+ border: 1px solid #4CAF50;
776
+ border-radius: 4px;
777
+ background: rgba(76, 175, 80, 0.2);
778
+ color: #4CAF50;
779
+ font-size: 12px;
780
+ font-weight: 600;
781
+ cursor: pointer;
782
+ transition: all 0.2s ease;
783
+ text-transform: uppercase;
784
+ letter-spacing: 0.3px;
785
+ }
786
+
787
+ .crafting-action-btn:hover {
788
+ background: rgba(76, 175, 80, 0.3);
789
+ color: #66BB6A;
790
+ }
791
+
792
+ /* Disabled button styles */
793
+ .crafting-action-btn:disabled {
794
+ opacity: 0.5;
795
+ cursor: not-allowed;
796
+ pointer-events: none;
797
+ }
798
+
799
+ /* Item rarity colors */
800
+ .crafting-slot.crafting-common { border-color: #9CA3AF; }
801
+ .crafting-slot.crafting-uncommon { border-color: #22C55E; }
802
+ .crafting-slot.crafting-rare { border-color: #3B82F6; }
803
+ .crafting-slot.crafting-epic { border-color: #A855F7; }
804
+ .crafting-slot.crafting-legendary { border-color: #F59E0B; }
805
+
806
+ /* Crafting-specific tooltip positioning (content handled by shared system) */
807
+ .crafting-item-tooltip {
808
+ position: absolute;
809
+ bottom: 100%;
810
+ left: 50%;
811
+ margin-bottom: 8px;
812
+ opacity: 0;
813
+ visibility: hidden;
814
+ transition: all 0.3s ease;
815
+ z-index: 2000;
816
+ pointer-events: none;
817
+ }
818
+
819
+ .crafting-requirement-tooltip {
820
+ position: absolute;
821
+ bottom: 100%;
822
+ left: 50%;
823
+ margin-bottom: 8px;
824
+ opacity: 0;
825
+ visibility: hidden;
826
+ transition: all 0.3s ease;
827
+ z-index: 2000;
828
+ pointer-events: none;
829
+ }
830
+
831
+
832
+
833
+ /* Mobile responsive */
834
+ @media (max-width: 768px) {
835
+ body.mobile {
836
+ --crafting-slot-size: 40px;
837
+ --crafting-icon-size: 20px;
838
+ --crafting-gap: 3px;
839
+ --crafting-padding: 6px;
840
+ }
841
+
842
+ body.mobile .crafting-container {
843
+ width: auto;
844
+ max-width: 500px;
845
+ min-width: 320px;
846
+ }
847
+
848
+ body.mobile .crafting-content {
849
+ padding: 6px;
850
+ flex-direction: column;
851
+ gap: 8px;
852
+ }
853
+
854
+ body.mobile .crafting-grid {
855
+ justify-items: center;
856
+ width: fit-content;
857
+ margin: 0 auto;
858
+ }
859
+
860
+ body.mobile .crafting-right-panel {
861
+ width: auto;
862
+ flex: 1;
863
+ min-height: 80px;
864
+ padding: var(--crafting-padding);
865
+ }
866
+
867
+ body.mobile .crafting-panel-content {
868
+ padding: 8px;
869
+ font-size: 12px;
870
+ }
871
+
872
+ body.mobile .crafting-placeholder {
873
+ font-size: 12px;
874
+ padding: 16px;
875
+ }
876
+
877
+
878
+
879
+ body.mobile .crafting-header {
880
+ padding: 4px 8px;
881
+ }
882
+
883
+ body.mobile .crafting-info {
884
+ gap: 8px;
885
+ }
886
+
887
+ body.mobile .crafting-avatar {
888
+ width: 32px;
889
+ height: 32px;
890
+ }
891
+
892
+ body.mobile .crafting-name {
893
+ font-size: 12px;
894
+ }
895
+
896
+ body.mobile .crafting-title {
897
+ font-size: 10px;
898
+ }
899
+
900
+ body.mobile .crafting-item-details {
901
+ gap: 6px;
902
+ }
903
+
904
+ body.mobile .crafting-item-header {
905
+ gap: 6px;
906
+ padding: 6px;
907
+ margin-bottom: 6px;
908
+ }
909
+
910
+ body.mobile .crafting-item-header .crafting-item-icon {
911
+ width: 24px;
912
+ height: 24px;
913
+ }
914
+
915
+ body.mobile .crafting-item-name {
916
+ font-size: 10px;
917
+ }
918
+
919
+ body.mobile .crafting-requirements-title {
920
+ font-size: 10px;
921
+ }
922
+
923
+ body.mobile .crafting-requirements-list {
924
+ grid-template-columns: repeat(2, 1fr);
925
+ gap: 3px;
926
+ }
927
+
928
+ body.mobile .crafting-requirement-item {
929
+ padding: 3px 4px;
930
+ min-height: 28px;
931
+ gap: 4px;
932
+ }
933
+
934
+ body.mobile .crafting-requirement-icon {
935
+ width: 16px;
936
+ height: 16px;
937
+ }
938
+
939
+ body.mobile .crafting-requirement-name {
940
+ font-size: 9px;
941
+ }
942
+
943
+ body.mobile .crafting-requirement-quantity {
944
+ font-size: 8px;
945
+ padding: 1px 2px;
946
+ }
947
+
948
+ body.mobile .crafting-no-requirements {
949
+ font-size: 10px;
950
+ padding: 12px;
951
+ }
952
+
953
+ body.mobile .crafting-item-actions {
954
+ padding-top: 6px;
955
+ }
956
+
957
+ body.mobile .crafting-action-btn {
958
+ padding: 6px 12px;
959
+ font-size: 10px;
960
+ }
961
+
962
+ body.mobile .crafting-item-stats {
963
+ font-size: 8px;
964
+ margin-top: 3px;
965
+ }
966
+
967
+ body.mobile .crafting-item-stats .stats-header {
968
+ font-size: 8px;
969
+ }
970
+
971
+ body.mobile .crafting-item-description {
972
+ font-size: 8px;
973
+ margin-top: 3px;
974
+ }
975
+ }
976
+ </style>