/** * Galaxy Strike Online - Inventory System * Manages player items, equipment, and storage */ class Inventory { constructor(gameEngine) { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.startStep('Inventory.constructor', { gameEngineProvided: !!gameEngine }); this.game = gameEngine; // Inventory configuration this.maxSlots = 30; this.baseMaxSlots = 30; // Base slots without starbase bonuses this.maxStack = 999; // Starbase inventory bonuses this.starbaseBonusSlots = 0; this.totalMaxSlots = this.baseMaxSlots + this.starbaseBonusSlots; // Inventory data - ensure items is always an array this.items = []; this.equipment = { weapon: null, armor: null, engine: null, shield: null, accessory: null }; // Item categories this.categories = { weapon: 'Weapons', armor: 'Armor', engine: 'Engines', shield: 'Shields', accessory: 'Accessories', consumable: 'Consumables', material: 'Materials', cosmetic: 'Cosmetics' }; // Item rarities this.rarities = { common: { name: 'Common', color: '#888888', multiplier: 1 }, uncommon: { name: 'Uncommon', color: '#00ff00', multiplier: 1.2 }, rare: { name: 'Rare', color: '#0088ff', multiplier: 1.5 }, epic: { name: 'Epic', color: '#8833ff', multiplier: 2 }, legendary: { name: 'Legendary', color: '#ff8800', multiplier: 3 } }; if (debugLogger) debugLogger.endStep('Inventory.constructor', { maxSlots: this.maxSlots, baseMaxSlots: this.baseMaxSlots, maxStack: this.maxStack, starbaseBonusSlots: this.starbaseBonusSlots, totalMaxSlots: this.totalMaxSlots, initialItemCount: this.items.length, equipmentSlots: Object.keys(this.equipment).length, categoriesCount: Object.keys(this.categories).length, raritiesCount: Object.keys(this.rarities).length }); } async initialize() { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.startStep('Inventory.initialize', { currentItemCount: this.items.length }); // Initialize with starting items if (this.items.length === 0) { if (debugLogger) debugLogger.logStep('Adding starting items to empty inventory'); this.addStartingItems(); } else { if (debugLogger) debugLogger.logStep('Inventory already has items, skipping starting items'); } if (debugLogger) debugLogger.endStep('Inventory.initialize', { finalItemCount: this.items.length, startingItemsAdded: this.items.length > 0 }); } addStartingItems() { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.startStep('Inventory.addStartingItems', { currentItemCount: this.items.length, maxSlots: this.maxSlots }); // In multiplayer mode, starting items should come from server if (window.smartSaveManager?.isMultiplayer) { console.log('[INVENTORY] Multiplayer mode - starting items will be provided by server'); if (debugLogger) debugLogger.logStep('Skipping starting items in multiplayer mode'); if (debugLogger) debugLogger.endStep('Inventory.addStartingItems', { finalItemCount: this.items.length, itemsAdded: 0 }); return; } // Singleplayer mode - no hardcoded starting items available console.log('[INVENTORY] Singleplayer mode - no hardcoded starting items available'); if (debugLogger) debugLogger.logStep('No starting items available in singleplayer mode'); if (debugLogger) debugLogger.endStep('Inventory.addStartingItems', { finalItemCount: this.items.length, itemsAdded: 0 }); } // Item management addItem(itemData, quantity = 1) { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.startStep('Inventory.addItem', { itemData: itemData, quantity: quantity, currentItemCount: this.items.length, maxSlots: this.maxSlots, maxStack: this.maxStack }); if (!itemData || !itemData.id) { console.error('Invalid item data:', itemData); if (debugLogger) debugLogger.errorEvent('Inventory.addItem', new Error('Invalid item data'), { itemData: itemData, quantity: quantity }); return false; } const item = { ...itemData, quantity }; // Auto-stack: Check if exact same item already exists (same type, rarity, and stats) const existingItem = this.items.find(i => i.id === item.id && i.type === item.type && i.rarity === item.rarity && JSON.stringify(i.stats) === JSON.stringify(item.stats) ); if (existingItem) { if (debugLogger) debugLogger.logStep('Found existing item for stacking', { existingItemId: existingItem.id, existingItemName: existingItem.name, currentQuantity: existingItem.quantity, addingQuantity: quantity, maxStack: this.maxStack }); // Stack items up to max stack const totalQuantity = existingItem.quantity + quantity; if (totalQuantity <= this.maxStack) { existingItem.quantity = totalQuantity; this.game.showNotification(`${item.name} +${quantity} (Stacked)`, 'success', 2000); if (debugLogger) debugLogger.logStep('Item stacked successfully', { itemId: existingItem.id, oldQuantity: existingItem.quantity - quantity, newQuantity: existingItem.quantity, added: quantity }); } else { // Add to existing stack and create new item if needed const remainingQuantity = totalQuantity - this.maxStack; existingItem.quantity = this.maxStack; if (debugLogger) debugLogger.logStep('Stack overflow, creating new item', { itemId: existingItem.id, maxStackReached: this.maxStack, remainingQuantity: remainingQuantity, currentSlots: this.items.length, maxSlots: this.totalMaxSlots }); // Try to add remaining quantity as new item if (this.items.length < this.totalMaxSlots) { const newItem = { ...itemData, quantity: remainingQuantity }; this.items.push(newItem); this.game.showNotification(`${item.name} +${quantity} (Stack: ${this.maxStack}, New: ${remainingQuantity})`, 'success', 2000); if (debugLogger) debugLogger.logStep('New item created for overflow', { newItemId: newItem.id, newItemQuantity: remainingQuantity, totalSlotsUsed: this.items.length }); } else { this.game.showNotification(`${item.name} +${quantity} (Stack full: ${this.maxStack})`, 'warning', 3000); if (debugLogger) debugLogger.logStep('Inventory full, overflow lost', { lostQuantity: remainingQuantity, maxSlots: this.totalMaxSlots }); } } } else { // Find empty slot if (this.items.length >= this.totalMaxSlots) { this.game.showNotification('Inventory is full!', 'error', 3000); if (debugLogger) debugLogger.endStep('Inventory.addItem', { success: false, reason: 'Inventory full', itemId: item.id, itemName: item.name, quantity: quantity, currentSlots: this.items.length, maxSlots: this.totalMaxSlots }); return false; } this.items.push(item); this.game.showNotification(`Acquired ${item.name}`, 'success', 2000); if (debugLogger) debugLogger.logStep('New item added to inventory', { itemId: item.id, itemName: item.name, itemType: item.type, itemRarity: item.rarity, quantity: quantity, slotUsed: this.items.length - 1 }); } this.autoStackItems(); // Reorganize inventory if (debugLogger) debugLogger.endStep('Inventory.addItem', { success: true, itemId: item.id, itemName: item.name, quantity: quantity, finalItemCount: this.items.length, slotsUsed: this.items.length, maxSlots: this.maxSlots }); return true; } // Auto-stack and organize inventory autoStackItems() { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.startStep('Inventory.autoStackItems', { currentItemCount: this.items.length, maxSlots: this.maxSlots, maxStack: this.maxStack }); const stackedItems = {}; const originalItemCount = this.items.length; // Group items by exact ID, type, rarity, and stats this.items.forEach(item => { const stackKey = `${item.id}_${item.type}_${item.rarity}_${JSON.stringify(item.stats || {})}`; if (!stackedItems[stackKey]) { stackedItems[stackKey] = { ...item, quantity: 0 }; } stackedItems[stackKey].quantity += item.quantity; }); if (debugLogger) debugLogger.logStep('Items grouped for stacking', { originalItemCount: originalItemCount, stackGroupsCreated: Object.keys(stackedItems).length, stackGroups: Object.entries(stackedItems).map(([key, item]) => ({ stackKey: key, itemId: item.id, itemName: item.name, totalQuantity: item.quantity })) }); // Convert back to array and limit by max stack const newItems = []; const stackedValues = Object.values(stackedItems); for (const item of stackedValues) { if (newItems.length >= this.totalMaxSlots) break; while (item.quantity > 0 && newItems.length < this.totalMaxSlots) { const stackQuantity = Math.min(item.quantity, this.maxStack); newItems.push({ ...item, quantity: stackQuantity }); item.quantity -= stackQuantity; } } this.items = newItems; if (debugLogger) debugLogger.endStep('Inventory.autoStackItems', { originalItemCount: originalItemCount, newItemCount: this.items.length, stackGroupsProcessed: stackedValues.length, slotsUsed: this.items.length, maxSlots: this.maxSlots }); } removeItem(itemId, quantity = 1) { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.startStep('Inventory.removeItem', { itemId: itemId, quantity: quantity, currentItemCount: this.items.length }); const itemIndex = this.items.findIndex(item => item.id === itemId); if (itemIndex === -1) { if (debugLogger) debugLogger.endStep('Inventory.removeItem', { success: false, reason: 'Item not found', itemId: itemId, quantity: quantity }); return false; } const item = this.items[itemIndex]; const oldQuantity = item.quantity; if (item.quantity > quantity) { item.quantity -= quantity; if (debugLogger) debugLogger.logStep('Item quantity reduced', { itemId: itemId, itemName: item.name, oldQuantity: oldQuantity, newQuantity: item.quantity, removed: quantity }); } else { this.items.splice(itemIndex, 1); if (debugLogger) debugLogger.logStep('Item completely removed', { itemId: itemId, itemName: item.name, oldQuantity: oldQuantity, removed: oldQuantity, itemIndex: itemIndex }); } if (debugLogger) debugLogger.endStep('Inventory.removeItem', { success: true, itemId: itemId, itemName: item.name, quantityRemoved: quantity, finalItemCount: this.items.length, itemStillExists: this.items.find(i => i.id === itemId) !== undefined }); return true; } hasItem(itemId, quantity = 1) { const item = this.items.find(item => item.id === itemId); return item && item.quantity >= quantity; } getItemCount(itemId) { const item = this.items.find(item => item.id === itemId); return item ? item.quantity : 0; } // Equipment management equipItem(itemId) { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.startStep('Inventory.equipItem', { itemId: itemId, currentItemCount: this.items.length, currentEquipment: this.equipment }); console.log('Attempting to equip item:', itemId); const item = this.items.find(item => item.id === itemId); console.log('Found item:', item); if (!item) { console.log('Item not found in inventory'); this.game.showNotification('Item not found', 'error', 3000); if (debugLogger) debugLogger.endStep('Inventory.equipItem', { success: false, reason: 'Item not found', itemId: itemId }); return false; } if (!item.equipable) { console.log('Item is not equipable:', item); this.game.showNotification('This item cannot be equipped', 'error', 3000); if (debugLogger) debugLogger.endStep('Inventory.equipItem', { success: false, reason: 'Item not equipable', itemId: itemId, itemName: item.name, itemType: item.type }); return false; } const slot = item.type; console.log('Equipping to slot:', slot); const currentItem = this.equipment[slot]; if (debugLogger) debugLogger.logStep('Equipment slot validation', { itemId: itemId, itemName: item.name, itemType: item.type, targetSlot: slot, currentItemInSlot: currentItem ? currentItem.name : null, itemStats: item.stats }); // Unequip current item if exists if (currentItem) { console.log('Unequipping current item:', currentItem); if (debugLogger) debugLogger.logStep('Unequipping current item', { currentItemName: currentItem.name, currentItemStats: currentItem.stats, returningToInventory: true }); this.addItem(currentItem, 1); } // Equip new item this.equipment[slot] = item; this.removeItem(itemId, 1); // Apply item stats to player this.applyEquipmentStats(); // Update UI this.updateUI(); console.log('Successfully equipped:', item.name); this.game.showNotification(`Equipped ${item.name}`, 'success', 3000); if (debugLogger) debugLogger.endStep('Inventory.equipItem', { success: true, itemId: itemId, itemName: item.name, slot: slot, previousItem: currentItem ? currentItem.name : null, newEquipmentState: this.equipment, finalItemCount: this.items.length }); return true; } unequipItem(slot) { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.startStep('Inventory.unequipItem', { slot: slot, currentEquipment: this.equipment, currentItemCount: this.items.length, maxSlots: this.maxSlots }); console.log('Attempting to unequip slot:', slot); const item = this.equipment[slot]; if (!item) { console.log('No item in slot:', slot); if (debugLogger) debugLogger.endStep('Inventory.unequipItem', { success: false, reason: 'No item in slot', slot: slot }); return false; } // Check inventory space if (this.items.length >= this.totalMaxSlots) { console.log('Inventory is full, cannot unequip'); this.game.showNotification('Inventory is full!', 'error', 3000); if (debugLogger) debugLogger.endStep('Inventory.unequipItem', { success: false, reason: 'Inventory full', slot: slot, itemName: item.name, currentItemCount: this.items.length, maxSlots: this.maxSlots }); return false; } if (debugLogger) debugLogger.logStep('Unequipping item', { slot: slot, itemName: item.name, itemStats: item.stats, returningToInventory: true, inventorySpaceAvailable: this.items.length < this.maxSlots }); // Unequip item this.equipment[slot] = null; this.addItem(item, 1); // Remove item stats from player this.applyEquipmentStats(); // Update UI this.updateUI(); console.log('Successfully unequipped:', item.name); this.game.showNotification(`Unequipped ${item.name}`, 'info', 3000); if (debugLogger) debugLogger.endStep('Inventory.unequipItem', { success: true, slot: slot, itemName: item.name, newEquipmentState: this.equipment, finalItemCount: this.items.length }); return true; } applyEquipmentStats() { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.startStep('Inventory.applyEquipmentStats', { currentEquipment: this.equipment, equippedItemsCount: Object.values(this.equipment).filter(item => item !== null).length }); // Reset player stats to base const player = this.game.systems.player; const oldPlayerAttributes = { ...player.attributes }; if (debugLogger) debugLogger.logStep('Applying equipment bonuses', { oldPlayerAttributes: oldPlayerAttributes, equipmentToApply: Object.entries(this.equipment).filter(([slot, item]) => item !== null) }); // Apply equipment bonuses for (const [slot, item] of Object.entries(this.equipment)) { if (item && item.stats) { for (const [stat, value] of Object.entries(item.stats)) { if (player.attributes[stat] !== undefined) { const oldValue = player.attributes[stat]; player.attributes[stat] += value; if (debugLogger) debugLogger.logStep('Stat bonus applied', { slot: slot, itemName: item.name, stat: stat, value: value, oldValue: oldValue, newValue: player.attributes[stat] }); } } } } player.updateUI(); if (debugLogger) debugLogger.endStep('Inventory.applyEquipmentStats', { oldPlayerAttributes: oldPlayerAttributes, newPlayerAttributes: player.attributes, statChanges: Object.entries(player.attributes).map(([stat, newValue]) => ({ stat: stat, oldValue: oldPlayerAttributes[stat], newValue: newValue, change: newValue - oldPlayerAttributes[stat] })).filter(change => change.change !== 0) }); } // Consumable usage useItem(itemId) { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.startStep('Inventory.useItem', { itemId: itemId, currentItemCount: this.items.length }); const item = this.items.find(item => item.id === itemId); if (!item || !item.consumable) { this.game.showNotification('This item cannot be used', 'error', 3000); if (debugLogger) debugLogger.endStep('Inventory.useItem', { success: false, reason: !item ? 'Item not found' : 'Item not consumable', itemId: itemId }); return false; } if (debugLogger) debugLogger.logStep('Using consumable item', { itemId: itemId, itemName: item.name, itemEffect: item.effect, oldQuantity: item.quantity }); const player = this.game.systems.player; const oldPlayerHealth = player.attributes.health; const oldPlayerEnergy = player.attributes.energy; // Apply item effects if (item.effect) { if (item.effect.heal) { player.heal(item.effect.heal); this.game.showNotification(`Restored ${item.effect.heal} health`, 'success', 2000); if (debugLogger) debugLogger.logStep('Healing effect applied', { healAmount: item.effect.heal, oldHealth: oldPlayerHealth, newHealth: player.attributes.health }); } if (item.effect.energy) { player.restoreEnergy(item.effect.energy); this.game.showNotification(`Restored ${item.effect.energy} energy`, 'success', 2000); if (debugLogger) debugLogger.logStep('Energy effect applied', { energyAmount: item.effect.energy, oldEnergy: oldPlayerEnergy, newEnergy: player.attributes.energy }); } if (item.effect.buff) { // Apply temporary buffs (would need buff system) this.game.showNotification(`Buff applied: ${item.effect.buff}`, 'success', 2000); if (debugLogger) debugLogger.logStep('Buff effect applied', { buffType: item.effect.buff }); } } // Remove consumed item this.removeItem(itemId, 1); if (debugLogger) debugLogger.endStep('Inventory.useItem', { success: true, itemId: itemId, itemName: item.name, effectsApplied: item.effect, finalItemCount: this.items.length }); return true; } // Item generation generateItem(type, rarity = 'common', level = 1) { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.startStep('Inventory.generateItem', { type: type, rarity: rarity, level: level }); const itemTemplates = { weapon: { common: [ { name: 'Basic Blaster', stats: { attack: 5 } }, { name: 'Laser Rifle', stats: { attack: 6 } } ], uncommon: [ { name: 'Plasma Cannon', stats: { attack: 8, criticalChance: 0.02 } }, { name: 'Ion Blaster', stats: { attack: 7, speed: 2 } } ], rare: [ { name: 'Quantum Rifle', stats: { attack: 12, criticalChance: 0.05 } }, { name: 'Fusion Cannon', stats: { attack: 15, criticalDamage: 0.2 } } ] }, armor: { common: [ { name: 'Basic Plating', stats: { defense: 3, maxHealth: 10 } }, { name: 'Light Armor', stats: { defense: 4, speed: -1 } } ], uncommon: [ { name: 'Reinforced Plating', stats: { defense: 6, maxHealth: 20 } }, { name: 'Energy Shield', stats: { defense: 5, maxEnergy: 10 } } ], rare: [ { name: 'Titanium Armor', stats: { defense: 10, maxHealth: 40 } }, { name: 'Phase Shield', stats: { defense: 8, criticalChance: -0.05 } } ] } }; const templates = itemTemplates[type]?.[rarity] || itemTemplates.weapon.common; const template = templates[Math.floor(Math.random() * templates.length)]; const rarityData = this.rarities[rarity]; const levelMultiplier = 1 + (level - 1) * 0.1; const generatedItem = { id: `${type}_${rarity}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, name: template.name, type: type, rarity: rarity, quantity: 1, stats: Object.fromEntries( Object.entries(template.stats).map(([stat, value]) => [ stat, Math.floor(value * rarityData.multiplier * levelMultiplier) ]) ), description: `Level ${level} ${rarityData.name} ${type}`, equipable: true, value: Math.floor(50 * rarityData.multiplier * levelMultiplier) }; if (debugLogger) debugLogger.endStep('Inventory.generateItem', { type: type, rarity: rarity, level: level, templateUsed: template.name, rarityMultiplier: rarityData.multiplier, levelMultiplier: levelMultiplier, generatedItem: generatedItem, finalStats: generatedItem.stats, itemValue: generatedItem.value }); return generatedItem; } // UI updates clear() { const debugLogger = window.debugLogger; const oldState = { itemCount: this.items.length, maxSlots: this.maxSlots, cargo: this.cargo ? this.cargo.length : 0, maxCargo: this.maxCargo }; if (debugLogger) debugLogger.startStep('Inventory.clear', { oldState: oldState }); this.items = []; this.maxSlots = 30; this.cargo = []; this.maxCargo = 100; this.updateUI(); if (debugLogger) debugLogger.endStep('Inventory.clear', { oldState: oldState, newState: { itemCount: this.items.length, maxSlots: this.maxSlots, cargo: this.cargo.length, maxCargo: this.maxCargo } }); } reset() { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.startStep('Inventory.reset'); this.clear(); if (debugLogger) debugLogger.endStep('Inventory.reset', { cleared: true }); } updateUI() { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.startStep('Inventory.updateUI', { itemCount: this.items.length, equipmentCount: Object.values(this.equipment).filter(item => item !== null).length }); this.updateInventoryGrid(); this.updateEquipmentDisplay(); if (debugLogger) debugLogger.endStep('Inventory.updateUI', { inventoryGridUpdated: true, equipmentDisplayUpdated: true }); } updateInventoryGrid() { const grid = document.getElementById('inventoryGrid'); if (!grid) return; grid.innerHTML = ''; // Create inventory slots using total max slots (base + starbase bonuses) for (let i = 0; i < this.totalMaxSlots; i++) { const slot = document.createElement('div'); slot.className = 'inventory-slot'; // Add special styling for starbase bonus slots if (i >= this.baseMaxSlots) { slot.classList.add('starbase-bonus-slot'); } const item = this.items[i]; if (item) { const iconHtml = this.getItemIconHtml(item.type, '24px'); const quantityBadge = item.quantity > 1 ? `
${item.quantity}
` : ''; slot.innerHTML = `
${iconHtml}
${item.name}
${this.rarities[item.rarity].name}
${quantityBadge}
`; // Add click handlers const itemCard = slot.querySelector('.item-card'); itemCard.addEventListener('click', () => this.showItemDetails(item)); if (item.equipable) { itemCard.addEventListener('contextmenu', (e) => { e.preventDefault(); this.equipItem(item.id); }); } if (item.consumable) { itemCard.addEventListener('dblclick', () => this.useItem(item.id)); } } else { slot.innerHTML = '
'; } grid.appendChild(slot); } } updateEquipmentDisplay() { // Update equipment slots in UI for (const [slot, item] of Object.entries(this.equipment)) { const slotElement = document.getElementById(`equip-${slot}`); if (slotElement) { if (item) { const iconHtml = this.getItemIconHtml(item.type, '24px'); slotElement.innerHTML = `
${iconHtml}
${item.name}
`; // Add click handler to unequip slotElement.onclick = () => this.unequipItem(slot); } else { slotElement.innerHTML = `
Empty
`; slotElement.onclick = null; } } } } showItemDetails(item) { const detailsElement = document.getElementById('itemDetails'); if (!detailsElement) return; const rarityData = this.rarities[item.rarity]; const statsHtml = item.stats ? Object.entries(item.stats) .map(([stat, value]) => `
${stat}: +${value}
`) .join('') : ''; detailsElement.innerHTML = `

${item.name}

${item.description}

Type: ${this.categories[item.type]}
Rarity: ${rarityData.name}
${item.quantity > 1 ? `
Quantity: ${item.quantity}
` : ''} ${statsHtml ? `
${statsHtml}
` : ''}
${item.equipable ? `` : ''} ${item.consumable ? `` : ''}
`; } getItemIcon(type) { const icons = { weapon: 'fa-sword', armor: 'fa-shield-alt', engine: 'fa-rocket', shield: 'fa-shield-virus', accessory: 'fa-ring', consumable: 'fa-flask', material: 'fa-cube', cosmetic: 'fa-star' }; const iconClass = icons[type] || 'fa-cube'; // Use texture manager for icon fallback if available if (this.game.systems.textureManager) { return this.game.systems.textureManager.getIcon(iconClass); } return iconClass; } getItemIconHtml(type, size = '32px') { // Use texture manager for icon HTML if available if (this.game.systems.textureManager && typeof this.game.systems.textureManager.getItemIconElement === 'function') { return this.game.systems.textureManager.getItemIconElement(this.getItemIcon(type), size); } // Fallback to FontAwesome const iconClass = this.getItemIcon(type); return ``; } // Starbase inventory integration methods updateStarbaseBonusSlots(bonusSlots) { this.starbaseBonusSlots = bonusSlots; this.totalMaxSlots = this.baseMaxSlots + this.starbaseBonusSlots; } getInventoryInfo() { return { currentSlots: this.items.length, baseMaxSlots: this.baseMaxSlots, starbaseBonusSlots: this.starbaseBonusSlots, totalMaxSlots: this.totalMaxSlots, availableSlots: this.totalMaxSlots - this.items.length }; } // Save/Load save() { const debugLogger = window.debugLogger; // if (debugLogger) debugLogger.startStep('Inventory.save', { // itemCount: this.items.length, // equipmentCount: Object.values(this.equipment).filter(item => item !== null).length, // baseMaxSlots: this.baseMaxSlots, // starbaseBonusSlots: this.starbaseBonusSlots // }); const saveData = { items: this.items, equipment: this.equipment, baseMaxSlots: this.baseMaxSlots, starbaseBonusSlots: this.starbaseBonusSlots }; // if (debugLogger) debugLogger.endStep('Inventory.save', { // saveDataSize: JSON.stringify(saveData).length, // itemsSaved: this.items.length, // equipmentSaved: Object.keys(this.equipment).length, // saveData: saveData // }); return saveData; } load(data) { const debugLogger = window.debugLogger; const oldState = { itemCount: this.items.length, equipmentCount: Object.values(this.equipment).filter(item => item !== null).length, baseMaxSlots: this.baseMaxSlots, starbaseBonusSlots: this.starbaseBonusSlots }; if (debugLogger) debugLogger.startStep('Inventory.load', { oldState: oldState, loadData: data }); try { if (data.items) { // Ensure items is always an array this.items = Array.isArray(data.items) ? data.items : []; if (debugLogger) debugLogger.logStep('Loading items', { itemsLoaded: this.items.length, itemsArray: Array.isArray(data.items), autoStacking: true }); this.autoStackItems(); } if (data.equipment) { this.equipment = data.equipment; if (debugLogger) debugLogger.logStep('Loading equipment', { equipmentLoaded: Object.keys(data.equipment).length, equipmentState: data.equipment }); } // Load starbase bonus slots if (data.baseMaxSlots !== undefined) { this.baseMaxSlots = data.baseMaxSlots; if (debugLogger) debugLogger.logStep('Loading base max slots', { oldBaseMaxSlots: oldState.baseMaxSlots, newBaseMaxSlots: this.baseMaxSlots }); } if (data.starbaseBonusSlots !== undefined) { this.starbaseBonusSlots = data.starbaseBonusSlots; if (debugLogger) debugLogger.logStep('Loading starbase bonus slots', { oldStarbaseBonusSlots: oldState.starbaseBonusSlots, newStarbaseBonusSlots: this.starbaseBonusSlots }); } // Recalculate total max slots this.totalMaxSlots = this.baseMaxSlots + this.starbaseBonusSlots; if (debugLogger) debugLogger.logStep('Recalculating total max slots', { baseMaxSlots: this.baseMaxSlots, starbaseBonusSlots: this.starbaseBonusSlots, totalMaxSlots: this.totalMaxSlots }); // Update UI to show loaded equipment this.updateUI(); if (debugLogger) debugLogger.endStep('Inventory.load', { success: true, oldState: oldState, newState: { itemCount: this.items.length, equipmentCount: Object.values(this.equipment).filter(item => item !== null).length, baseMaxSlots: this.baseMaxSlots, starbaseBonusSlots: this.starbaseBonusSlots, totalMaxSlots: this.totalMaxSlots } }); } catch (error) { if (debugLogger) debugLogger.errorEvent('Inventory.load', error, { oldState: oldState, loadData: data, error: error.message }); throw error; } } }