/** * Galaxy Strike Online - Client Item System * Dynamically loads and manages items from the GameServer */ class ItemSystem { constructor(gameEngine) { this.game = gameEngine; // Item storage this.itemCatalog = new Map(); // itemId -> item data this.shopItems = []; // Array of shop items this.lastUpdated = null; // Loading state this.isLoading = false; this.loadPromise = null; // Event listeners this.eventListeners = new Map(); } /** * Initialize the item system and load data from server */ async initialize() { console.log('[ITEM SYSTEM] Initializing client item system'); if (this.loadPromise) { return this.loadPromise; } this.loadPromise = this.loadFromServer(); return this.loadPromise; } /** * Load all items from the GameServer */ async loadFromServer() { if (this.isLoading) { console.log('[ITEM SYSTEM] Already loading items from server'); return this.loadPromise; } this.isLoading = true; try { console.log('[ITEM SYSTEM] Loading items from GameServer - Multiplayer Mode'); console.log('[ITEM SYSTEM] Socket connection status:', !!window.game?.socket); if (!window.game || !window.game.socket) { throw new Error('Not connected to server - multiplayer mode requires server connection'); } // Load shop items from server const shopItems = await this.fetchShopItems(); console.log('[ITEM SYSTEM] Received', shopItems.length, 'items from server'); // Process and store items this.processServerItems(shopItems); this.lastUpdated = Date.now(); console.log(`[ITEM SYSTEM] Successfully loaded ${this.itemCatalog.size} items from server`); console.log('[ITEM SYSTEM] Item categories loaded:', Object.keys(this.itemCatalog).length); // Emit loaded event this.emit('itemsLoaded', { itemCount: this.itemCatalog.size, shopItemCount: this.shopItems.length, timestamp: this.lastUpdated }); return true; } catch (error) { console.error('[ITEM SYSTEM] Failed to load items from server:', error); console.error('[ITEM SYSTEM] Error details:', { message: error.message, stack: error.stack, socketConnected: !!window.game?.socket, socketId: window.game?.socket?.id }); // No fallback - emit error event this.emit('itemsLoadError', error); return false; } finally { this.isLoading = false; } } /** * Fetch shop items from the GameServer */ async fetchShopItems() { console.log('[ITEM SYSTEM] Starting fetchShopItems'); if (!window.game || !window.game.socket) { console.error('[ITEM SYSTEM] No socket connection available'); throw new Error('Not connected to server'); } console.log('[ITEM SYSTEM] Socket ID:', window.game.socket.id); console.log('[ITEM SYSTEM] Socket connected:', window.game.socket.connected); return new Promise((resolve, reject) => { const timeout = setTimeout(() => { console.error('[ITEM SYSTEM] Server request timeout after 10 seconds'); window.game.socket.off('shopItemsReceived', handleResponse); reject(new Error('Server request timeout')); }, 10000); // Request shop items from server console.log('[ITEM SYSTEM] Emitting getShopItems request'); window.game.socket.emit('getShopItems', {}); // Listen for response const handleResponse = (data) => { console.log('[ITEM SYSTEM] Received shopItemsReceived response:', data); clearTimeout(timeout); window.game.socket.off('shopItemsReceived', handleResponse); if (data.success) { console.log('[ITEM SYSTEM] Successfully received', data.items?.length || 0, 'items'); console.log('[ITEM SYSTEM] Response timestamp:', data.timestamp); resolve(data.items || []); } else { console.error('[ITEM SYSTEM] Server returned error:', data.error); reject(new Error(data.error || 'Failed to load shop items')); } }; console.log('[ITEM SYSTEM] Setting up shopItemsReceived listener'); window.game.socket.on('shopItemsReceived', handleResponse); }); } /** * Fetch specific item details from server */ async fetchItemDetails(itemId) { if (!window.game || !window.game.socket) { throw new Error('Not connected to server'); } return new Promise((resolve, reject) => { const timeout = setTimeout(() => { reject(new Error('Server request timeout')); }, 5000); // Request item details from server window.game.socket.emit('getItemDetails', { itemId }); // Listen for response const handleResponse = (data) => { clearTimeout(timeout); window.game.socket.off('itemDetailsReceived', handleResponse); if (data.success) { // Cache the item this.itemCatalog.set(itemId, data.item); resolve(data.item); } else { reject(new Error(data.error || 'Item not found')); } }; window.game.socket.on('itemDetailsReceived', handleResponse); }); } /** * Process items received from server */ processServerItems(items) { console.log('[ITEM SYSTEM] Processing', items.length, 'items from server'); console.log('[ITEM SYSTEM] Sample items:', items.slice(0, 3)); this.itemCatalog.clear(); this.shopItems = []; for (const item of items) { // Store in catalog this.itemCatalog.set(item.id, item); // Add to shop items if available for shop if (item.categories && item.categories.includes('shop')) { this.shopItems.push(item); } console.log('[ITEM SYSTEM] Added item:', { id: item.id, name: item.name, type: item.type, rarity: item.rarity, price: item.price, categories: item.categories }); } console.log('[ITEM SYSTEM] Processing complete - Catalog:', this.itemCatalog.size, 'Shop items:', this.shopItems.length); console.log('[ITEM SYSTEM] Shop items by type:', this.shopItems.reduce((acc, item) => { acc[item.type] = (acc[item.type] || 0) + 1; return acc; }, {})); } /** * Get item by ID */ getItem(itemId) { // Return from cache if available if (this.itemCatalog.has(itemId)) { return this.itemCatalog.get(itemId); } // Try to fetch from server if not cached if (window.game && window.game.socket) { this.fetchItemDetails(itemId).catch(error => { console.warn(`[ITEM SYSTEM] Failed to fetch item ${itemId}:`, error); }); } return null; } /** * Get all shop items */ getShopItems() { return [...this.shopItems]; } /** * Get items by category */ getItemsByCategory(category) { return Array.from(this.itemCatalog.values()).filter(item => item.type === category || (item.categories && item.categories.includes(category)) ); } /** * Get items by type */ getItemsByType(type) { return Array.from(this.itemCatalog.values()).filter(item => item.type === type); } /** * Get items by rarity */ getItemsByRarity(rarity) { return Array.from(this.itemCatalog.values()).filter(item => item.rarity === rarity); } /** * Check if player can use item based on requirements */ canPlayerUseItem(item, playerLevel = null) { if (!item.requirements) return true; // Get player level if not provided if (playerLevel === null && window.game && window.game.systems && window.game.systems.player) { playerLevel = window.game.systems.player.level; } // Check level requirement if (item.requirements.level && playerLevel < item.requirements.level) { return false; } // Add other requirement checks here return true; } /** * Get filtered shop items for current player */ getAvailableShopItems() { return this.shopItems.filter(item => this.canPlayerUseItem(item)); } /** * Format item price for display */ formatPrice(item) { if (!item.price) return 'Free'; const currency = item.currency || 'credits'; const price = this.game.formatNumber(item.price); return `${price} ${currency}`; } /** * Get item rarity color */ getRarityColor(rarity) { const colors = { common: '#888888', uncommon: '#00ff00', rare: '#0088ff', legendary: '#ff8800', epic: '#ff00ff' }; return colors[rarity] || '#ffffff'; } /** * Refresh items from server */ async refresh() { console.log('[ITEM SYSTEM] Refreshing items from server'); return this.loadFromServer(); } /** * Event system */ on(event, callback) { if (!this.eventListeners.has(event)) { this.eventListeners.set(event, []); } this.eventListeners.get(event).push(callback); } off(event, callback) { if (this.eventListeners.has(event)) { const listeners = this.eventListeners.get(event); const index = listeners.indexOf(callback); if (index > -1) { listeners.splice(index, 1); } } } emit(event, data) { if (this.eventListeners.has(event)) { for (const callback of this.eventListeners.get(event)) { try { callback(data); } catch (error) { console.error(`[ITEM SYSTEM] Error in event listener for ${event}:`, error); } } } } /** * Get system statistics */ getStats() { const stats = { totalItems: this.itemCatalog.size, shopItems: this.shopItems.length, lastUpdated: this.lastUpdated, isLoading: this.isLoading, socketConnected: !!(window.game?.socket), socketId: window.game?.socket?.id }; // Add category breakdown stats.categories = {}; for (const item of this.itemCatalog.values()) { stats.categories[item.type] = (stats.categories[item.type] || 0) + 1; } return stats; } } // Export for use in other modules if (typeof module !== 'undefined' && module.exports) { module.exports = ItemSystem; } else { window.ItemSystem = ItemSystem; }