This repository has been archived on 2026-05-04. You can view files and clone it, but cannot push or open issues or pull requests.
Galaxy-Strike-Online/Client/js/core/Economy.js
2026-01-30 10:58:30 -04:00

919 lines
35 KiB
JavaScript

/**
* Galaxy Strike Online - Economy System
* Manages player currency, transactions, and shop functionality
* Now uses server-side ItemSystem for all item data
*/
class Economy {
constructor(gameEngine) {
this.game = gameEngine;
// Currency - don't override in multiplayer mode, will be set by server data
if (window.smartSaveManager?.isMultiplayer) {
this.credits = 0; // Will be updated by server
this.gems = 0; // Will be updated by server
this.premiumCurrency = 0; // Will be updated by server
} else {
this.credits = 10000; // Starting credits for singleplayer
this.gems = 50; // Starting premium currency
this.premiumCurrency = 0; // Additional premium currency
}
// Transaction history
this.transactions = [];
// Shop categories
this.shopCategories = {
ships: 'Ships',
weapons: 'Weapons',
armors: 'Armors',
cosmetics: 'Cosmetics',
consumables: 'Consumables',
materials: 'Materials'
};
// Random shop system - now uses server ItemSystem
this.randomShopItems = {}; // Current random items per category
this.shopRefreshInterval = null; // Timer for 2-hour refresh
this.shopHeartbeatInterval = null; // Timer for live countdown updates
this.lastShopRefresh = null; // Timestamp of last refresh
this.currentShopData = null; // Current shop data from server
this.SHOP_REFRESH_INTERVAL = 2 * 60 * 60 * 1000; // 2 hours in milliseconds
this.MAX_ITEMS_PER_CATEGORY = 8;
this.categoryPurchaseLimits = {}; // Track purchases per category per refresh
// Shop items - now loaded from server ItemSystem
this.shopItems = null; // Will be populated by ItemSystem in multiplayer
// Owned cosmetics
this.ownedCosmetics = [];
// Owned ships
this.ownedShips = [];
console.log('[ECONOMY] Economy system initialized');
// Initialize global purchase function
Economy.initGlobalPurchaseFunction();
}
// Create global purchase function for shop buttons
static initGlobalPurchaseFunction() {
window.purchaseShopItem = function(itemId) {
console.log('[GLOBAL] Purchase shop item called:', itemId);
if (window.game && window.game.systems && window.game.systems.economy) {
window.game.systems.economy.purchaseItem(itemId, 1);
} else {
console.error('[GLOBAL] Economy system not available for purchase');
}
};
// Add test function for idle system
window.testIdleRewards = function() {
console.log('[GLOBAL] Testing idle rewards...');
if (window.game && window.game.socket) {
window.game.socket.emit('testIdleRewards', {});
// Listen for response
window.game.socket.once('testIdleRewards', (data) => {
console.log('[GLOBAL] Test idle rewards response:', data);
});
} else {
console.error('[GLOBAL] No socket available for idle test');
}
};
// Add socket event monitor
window.monitorSocketEvents = function() {
if (window.game && window.game.socket) {
console.log('[GLOBAL] Monitoring socket events...');
// Monitor all incoming events
const originalOn = window.game.socket.on;
window.game.socket.on = function(event, callback) {
const wrappedCallback = function(data) {
if (event === 'onlineIdleRewards' || event === 'economy_data') {
console.log('[SOCKET MONITOR] Received event:', event, data);
}
return callback(data);
};
return originalOn.call(this, event, wrappedCallback);
};
console.log('[GLOBAL] Socket event monitoring enabled');
} else {
console.error('[GLOBAL] No socket available for monitoring');
}
};
// Add function to give player energy for testing dungeons
window.addEnergy = function(amount = 50) {
if (window.game && window.game.systems && window.game.systems.player) {
const player = window.game.systems.player;
const oldEnergy = player.attributes.energy || 0;
player.attributes.energy = Math.min(oldEnergy + amount, player.attributes.maxEnergy || 100);
console.log('[GLOBAL] Added energy:', oldEnergy, '->', player.attributes.energy);
// Update UI
if (player.updateUI) {
player.updateUI();
}
// Update dungeon UI if available
if (window.game.systems.dungeonSystem && window.game.systems.dungeonSystem.updateUI) {
window.game.systems.dungeonSystem.updateUI();
}
return player.attributes.energy;
} else {
console.error('[GLOBAL] Player system not available');
return 0;
}
};
console.log('[GLOBAL] Global functions initialized - purchaseShopItem() and testIdleRewards() available');
}
/**
* Set up socket listeners for economy data synchronization
*/
setupSocketListeners() {
if (!this.game.socket) {
console.warn('[ECONOMY] No socket available for economy sync');
return;
}
// Listen for economy data updates from server
this.game.socket.on('economy_data', (data) => {
console.log('[ECONOMY] Received economy data from server:', data);
console.log('[ECONOMY] Current credits before update:', this.credits);
console.log('[ECONOMY] Current gems before update:', this.gems);
this.credits = data.credits || 0;
this.gems = data.gems || 0;
console.log('[ECONOMY] Updated credits:', this.credits);
console.log('[ECONOMY] Updated gems:', this.gems);
// Update UI immediately
if (this.game.ui) {
this.game.ui.updatePlayerStats();
}
console.log('[ECONOMY] Economy synced - Credits:', this.credits, 'Gems:', this.gems);
});
// Note: onlineIdleRewards is handled by GameInitializer to avoid duplicate event handling
// Listen for play time updates from server
this.game.socket.on('playTimeUpdated', (data) => {
console.log('[ECONOMY] Received play time update from server:', data);
// Update player stats if available
if (this.game.systems.player && this.game.systems.player.stats) {
this.game.systems.player.stats.playTime = data.playTime;
}
});
}
/**
* Request economy data from server
*/
requestEconomyData() {
if (this.game.socket) {
console.log('[ECONOMY] Requesting economy data from server');
this.game.socket.emit('get_economy_data');
} else {
console.warn('[ECONOMY] Cannot request economy data - no socket available');
}
}
async initialize() {
console.log('[ECONOMY] Initializing economy system');
// In multiplayer mode, wait for ItemSystem to be ready (handled by event listener)
this.game.on('itemSystemReady', () => {
console.log('[ECONOMY] ItemSystem is ready, updating shop UI');
this.updateShopUI();
});
if (window.smartSaveManager?.isMultiplayer) {
console.log('[ECONOMY] Multiplayer mode - waiting for ItemSystem to be ready');
// ItemSystem initialization removed - wait for event instead
} else {
console.log('[ECONOMY] Singleplayer mode - using local shop data');
// Initialize random shop for singleplayer
this.initializeRandomShop();
}
console.log('[ECONOMY] Economy system initialized');
}
// Shop functionality - now uses ItemSystem in multiplayer
purchaseItem(itemId, quantity = 1) {
const debugLogger = window.debugLogger;
// In multiplayer mode, send request to server
if (window.smartSaveManager?.isMultiplayer) {
if (debugLogger) debugLogger.logStep('Sending purchase request to server', {
itemId: itemId,
quantity: quantity
});
// Send purchase request to server
if (window.game && window.game.socket) {
window.game.socket.emit('purchaseItem', {
itemId: itemId,
quantity: quantity
});
// Show loading message
this.game.showNotification('Processing purchase...', 'info', 2000);
} else {
this.game.showNotification('Not connected to server', 'error', 3000);
}
return;
}
// Singleplayer mode - use local logic
const item = this.findShopItem(itemId);
if (!item) {
if (debugLogger) debugLogger.logStep('Item purchase failed - item not found', {
itemId: itemId,
quantity: quantity
});
this.game.showNotification('Item not found in shop', 'error', 3000);
return false;
}
const totalCost = item.price * quantity;
const currency = item.currency;
const oldCredits = this.credits;
const oldGems = this.gems;
if (debugLogger) debugLogger.logStep('Item purchase attempted', {
itemId: itemId,
itemName: item.name,
itemType: item.type,
quantity: quantity,
unitPrice: item.price,
totalCost: totalCost,
currency: currency,
currentCredits: oldCredits,
currentGems: oldGems
});
// Check if player can afford
if (currency === 'credits' && this.credits < totalCost) {
if (debugLogger) debugLogger.logStep('Item purchase failed - insufficient credits', {
totalCost: totalCost,
currentCredits: oldCredits,
deficit: totalCost - oldCredits
});
this.game.showNotification('Not enough credits!', 'error', 3000);
return false;
}
if (currency === 'gems' && this.gems < totalCost) {
if (debugLogger) debugLogger.logStep('Item purchase failed - insufficient gems', {
totalCost: totalCost,
currentGems: oldGems,
deficit: totalCost - oldGems
});
this.game.showNotification('Not enough gems!', 'error', 3000);
return false;
}
// Check if already owns this cosmetic
if (item.type === 'cosmetic' && this.ownedCosmetics.includes(item.id)) {
this.game.showNotification('You already own this cosmetic!', 'error', 3000);
return false;
}
// Process payment and give item based on type
if (currency === 'credits') {
this.credits -= totalCost;
} else if (currency === 'gems') {
this.gems -= totalCost;
}
switch (item.type) {
case 'ship':
this.purchaseShip(item, quantity);
break;
case 'cosmetic':
this.purchaseCosmetic(item, quantity);
break;
case 'consumable':
this.purchaseConsumable(item, quantity);
break;
case 'material':
this.purchaseMaterial(item, quantity);
break;
default:
console.warn(`[ECONOMY] Unknown item type: ${item.type}`);
return false;
}
// Show success message
this.game.showNotification(`Purchased ${item.name}!`, 'success', 3000);
if (debugLogger) debugLogger.logStep('Item purchase completed successfully', {
itemId: itemId,
itemName: item.name,
itemType: item.type,
quantity: quantity,
totalCost: totalCost,
currency: currency,
oldCredits: oldCredits,
newCredits: this.credits,
oldGems: oldGems,
newGems: this.gems
});
// Update UI without calling updateShopUI to avoid circular updates
return true;
}
findShopItem(itemId) {
const debugLogger = window.debugLogger;
console.log('[ECONOMY] Looking for shop item:', itemId);
console.log('[ECONOMY] Multiplayer mode:', window.smartSaveManager?.isMultiplayer);
console.log('[ECONOMY] ItemSystem available:', !!(this.game.systems.itemSystem));
// In multiplayer mode, use ItemSystem (required)
if (window.smartSaveManager?.isMultiplayer) {
// Check if ItemSystem is ready before using it
if (!this.game.systems.itemSystem || !this.game.systems.itemSystem.itemCatalog) {
console.log('[ECONOMY] ItemSystem not ready yet, cannot find shop item');
if (debugLogger) debugLogger.logStep('Shop item lookup failed - ItemSystem not ready', {
itemId: itemId,
multiplayer: true
});
return null;
}
// Search in ItemSystem catalog
const item = this.game.systems.itemSystem.itemCatalog.get(itemId);
if (item) {
console.log('[ECONOMY] Found item in ItemSystem:', item.name);
return item;
} else {
console.log('[ECONOMY] Item not found in ItemSystem:', itemId);
return null;
}
} else {
// Singleplayer mode - search in local random shop
for (const categoryItems of Object.values(this.randomShopItems)) {
const item = categoryItems.find(item => item.id === itemId);
if (item) return item;
}
return null;
}
}
// Purchase methods
purchaseShip(ship) {
const debugLogger = window.debugLogger;
const player = this.game.systems.player;
const oldShipName = player.ship.name;
const oldShipClass = player.ship.class;
const oldAttributes = { ...player.attributes };
// Update player ship
player.ship = {
name: ship.name,
class: ship.id,
texture: ship.texture,
stats: ship.stats || {}
};
// Update player attributes
if (ship.stats) {
player.attributes = { ...player.attributes, ...ship.stats };
}
// Add to owned ships
if (!player.ownedShips) {
player.ownedShips = [];
}
if (!player.ownedShips.includes(ship.id)) {
player.ownedShips.push(ship.id);
}
// Add ship to BaseSystem ship gallery (singleplayer)
if (this.game.systems.baseSystem) {
const shipData = {
id: ship.id,
name: ship.name,
class: ship.name.replace(/\s+/g, '_').toLowerCase(), // Generate class from name
level: 1,
stats: ship.stats || {},
texture: ship.texture || `assets/textures/ships/${ship.id}.png`,
isCurrent: false,
rarity: ship.rarity || 'common'
};
// Initialize ship gallery if needed
if (!this.game.systems.baseSystem.purchasedShips) {
this.game.systems.baseSystem.initializeShipGallery();
}
// Add ship to gallery
this.game.systems.baseSystem.purchasedShips.push(shipData);
// Update the ship gallery UI
this.game.systems.baseSystem.updateShipGallery();
console.log('[ECONOMY] Ship added to BaseSystem gallery (singleplayer):', shipData.name);
}
if (debugLogger) debugLogger.logStep('Ship purchase completed', {
shipId: ship.id,
shipName: ship.name,
oldShipName: oldShipName,
oldShipClass: oldShipClass,
newShipName: ship.name,
newShipClass: ship.id,
oldAttributes: oldAttributes,
newAttributes: player.attributes
});
}
purchaseCosmetic(cosmetic) {
const debugLogger = window.debugLogger;
const oldOwnedCount = this.ownedCosmetics.length;
// Add to owned cosmetics
this.ownedCosmetics.push(cosmetic.id);
this.game.showNotification(`Cosmetic unlocked: ${cosmetic.name}`, 'success', 3000);
if (debugLogger) debugLogger.logStep('Cosmetic purchase completed', {
cosmeticId: cosmetic.id,
cosmeticName: cosmetic.name,
oldOwnedCount: oldOwnedCount,
newOwnedCount: this.ownedCosmetics.length,
totalOwnedCosmetics: this.ownedCosmetics.length
});
}
purchaseConsumable(consumable, quantity) {
const debugLogger = window.debugLogger;
const inventory = this.game.systems.inventory;
// Create item object for inventory
const item = {
id: consumable.id,
name: consumable.name,
type: consumable.type,
rarity: consumable.rarity,
quantity: quantity,
description: consumable.description,
texture: consumable.texture,
stats: consumable.stats || {},
acquired: new Date().toISOString()
};
try {
const oldInventorySize = inventory.items.length;
inventory.addItem(item);
if (debugLogger) debugLogger.logStep('Consumable purchase completed', {
itemId: consumable.id,
itemName: consumable.name,
quantity: quantity,
oldInventorySize: oldInventorySize,
newInventorySize: inventory.items.length
});
} catch (error) {
console.error('[ECONOMY] Error adding consumable to inventory:', error);
this.game.showNotification('Failed to add item to inventory', 'error', 3000);
}
}
purchaseMaterial(material, quantity) {
const debugLogger = window.debugLogger;
const inventory = this.game.systems.inventory;
// Create item object for inventory
const item = {
id: material.id,
name: material.name,
type: material.type,
rarity: material.rarity,
quantity: quantity,
description: material.description,
texture: material.texture,
stackable: material.stackable || true,
acquired: new Date().toISOString()
};
try {
const oldInventorySize = inventory.items.length;
inventory.addItem(item);
if (debugLogger) debugLogger.logStep('Material purchase completed', {
itemId: material.id,
itemName: material.name,
quantity: quantity,
oldInventorySize: oldInventorySize,
newInventorySize: inventory.items.length
});
} catch (error) {
console.error('[ECONOMY] Error adding material to inventory:', error);
this.game.showNotification('Failed to add item to inventory', 'error', 3000);
}
}
// Currency management
addCredits(amount, source = 'unknown') {
const oldCredits = this.credits;
this.credits += amount;
// Add transaction
this.addTransaction({
type: 'credit',
amount: amount,
source: source,
balance: this.credits,
timestamp: new Date().toISOString()
});
console.log(`[ECONOMY] Added ${amount} credits from ${source}. New balance: ${this.credits}`);
this.updateUI();
return this.credits - oldCredits;
}
addGems(amount, source = 'unknown') {
const oldGems = this.gems;
this.gems += amount;
// Add transaction
this.addTransaction({
type: 'gem',
amount: amount,
source: source,
balance: this.gems,
timestamp: new Date().toISOString()
});
console.log(`[ECONOMY] Added ${amount} gems from ${source}. New balance: ${this.gems}`);
this.updateUI();
return this.gems - oldGems;
}
canAfford(cost, currency = 'credits') {
if (currency === 'credits') {
return this.credits >= cost;
} else if (currency === 'gems') {
return this.gems >= cost;
} else if (currency === 'premium') {
return this.premiumCurrency >= cost;
}
return false;
}
// Transaction management
addTransaction(transaction) {
this.transactions.push(transaction);
this.transactionHistory.push(transaction);
// Keep only last 100 transactions in memory
if (this.transactions.length > 100) {
this.transactions = this.transactions.slice(-100);
}
}
// Manual sync with server data - call this to force update
syncWithServerData(serverPlayerData) {
console.log('[ECONOMY] Manual sync with server data:', {
serverCredits: serverPlayerData?.stats?.credits,
serverGems: serverPlayerData?.stats?.gems,
currentCredits: this.credits,
currentGems: this.gems
});
if (serverPlayerData?.stats?.credits !== undefined) {
this.credits = serverPlayerData.stats.credits;
console.log('[ECONOMY] Updated credits from server:', this.credits);
}
if (serverPlayerData?.stats?.gems !== undefined) {
this.gems = serverPlayerData.stats.gems;
console.log('[ECONOMY] Updated gems from server:', this.gems);
}
// Update UI after sync
this.updateUI();
}
// UI updates
updateUI() {
// Debug logging to track current values
console.log('[ECONOMY] updateUI called - Current values:', {
credits: this.credits,
gems: this.gems,
gameSystemsAvailable: !!(this.game && this.game.systems),
uiSystemAvailable: !!(this.game && this.game.systems && this.game.systems.ui)
});
// Update resource display
if (this.game.systems.ui) {
this.game.systems.ui.updateResourceDisplay();
}
// Update shop UI if open
this.updateShopUI();
}
updateShopUI() {
const debugLogger = window.debugLogger;
console.log('[ECONOMY] updateShopUI called');
if (this.game.multiplayerMode && this.game.itemSystem && this.game.itemSystem.catalog) {
console.log('[ECONOMY] Multiplayer mode:', true);
console.log('[ECONOMY] ItemSystem available:', !!this.game.itemSystem);
console.log('[ECONOMY] ItemSystem catalog:', !!this.game.itemSystem.catalog);
const shopItems = this.game.itemSystem.catalog;
console.log('[ECONOMY] Got categorized shop items:', Object.keys(shopItems));
// Get current active category
const activeCategory = this.game.itemSystem.activeCategory || 'ships';
console.log('[ECONOMY] Active shop category:', activeCategory);
// Filter items for active category
const categoryItems = shopItems[activeCategory] || [];
console.log('[ECONOMY] Using new shop structure - found', categoryItems.length, 'categories');
console.log('[ECONOMY] Filtered items for category', activeCategory, ':', categoryItems.length, 'items');
console.log('[ECONOMY] Item types in category:', categoryItems.map(item => item.type));
this.renderShopItems(categoryItems);
} else {
// Singleplayer mode - use local shop data
const items = Object.values(this.randomShopItems).flat();
// Convert to categorized structure for consistency
const categorizedItems = this.randomShopItems || {};
this.renderShopItems(categorizedItems);
}
}
renderShopItems(items) {
const shopItemsElement = document.getElementById('shopItems');
if (!shopItemsElement) return;
const activeCategory = document.querySelector('.shop-cat-btn.active')?.dataset.category || 'ships';
console.log('[ECONOMY] Active shop category:', activeCategory);
// Handle new shop data structure (items by category) or old structure (flat array)
let categoryItems = [];
if (items && typeof items === 'object' && !Array.isArray(items)) {
// New structure: { ships: [...], weapons: [...], ... }
categoryItems = items[activeCategory] || [];
console.log('[ECONOMY] Using new shop structure - found', Object.keys(items).length, 'categories');
} else if (Array.isArray(items)) {
// Old structure: flat array of items
const targetItemType = activeCategory.slice(0, -1); // Remove 's' from 'ships', 'weapons', etc.
categoryItems = items.filter(item => item.type === targetItemType);
console.log('[ECONOMY] Using old shop structure - filtered', items.length, 'total items');
} else {
console.warn('[ECONOMY] Invalid shop items structure:', typeof items);
shopItemsElement.innerHTML = '<p>No items available</p>';
return;
}
console.log('[ECONOMY] Filtered items for category', activeCategory, ':', categoryItems.length, 'items');
console.log('[ECONOMY] Item types in category:', categoryItems.map(item => item.type));
if (categoryItems.length === 0) {
shopItemsElement.innerHTML = '<p>No items available in this category</p>';
return;
}
shopItemsElement.innerHTML = categoryItems.map(item => {
const canAfford = this.canAfford(item.price, item.currency);
const isOwned = item.type === 'cosmetic' && this.ownedCosmetics.includes(item.id);
// Generate image URL - server will serve images
const imageUrl = this.getItemImageUrl(item);
const placeholderUrl = 'https://dev.gameserver.galaxystrike.online/images/ui/placeholder.png';
return `
<div class="shop-item ${canAfford ? '' : 'cant-afford'} ${isOwned ? 'owned' : ''}" data-item-id="${item.id}">
<div class="shop-item-content">
<div class="shop-item-image">
<img src="${imageUrl}" alt="${item.name}"
onerror="this.src='${placeholderUrl}'"
loading="lazy">
</div>
<div class="shop-item-info">
<div class="shop-item-header">
<h3 class="shop-item-name">${item.name}</h3>
<span class="shop-item-rarity ${item.rarity}">${item.rarity}</span>
</div>
<div class="shop-item-body">
<p class="shop-item-description">${item.description}</p>
<div class="shop-item-price">
${this.formatPrice(item)}
</div>
</div>
<div class="shop-item-footer">
<button class="shop-item-purchase-btn"
data-item-id="${item.id}"
onclick="purchaseShopItem('${item.id}')"
${!canAfford || isOwned ? 'disabled' : ''}>
${isOwned ? 'Owned' : 'Purchase'}
</button>
</div>
</div>
</div>
</div>
`;
}).join('');
// Add event listeners to purchase buttons
shopItemsElement.querySelectorAll('.shop-item-purchase-btn').forEach(button => {
button.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
const itemId = button.getAttribute('data-item-id');
if (itemId && !button.disabled) {
console.log('[ECONOMY] Purchase button clicked for item:', itemId);
this.purchaseItem(itemId, 1);
}
});
});
}
formatPrice(item) {
if (!item.price) return 'Free';
const currency = item.currency || 'credits';
const price = this.game.formatNumber(item.price);
return `${price} ${currency}`;
}
/**
* Get image URL for an item from server
*/
getItemImageUrl(item) {
if (!item) return 'https://dev.gameserver.galaxystrike.online/images/ui/placeholder.png';
// For multiplayer, ALWAYS get from server
if (window.smartSaveManager?.isMultiplayer && this.game.socket) {
const serverUrl = this.getServerUrl();
// Map item types to proper server paths
switch (item.type) {
case 'ship':
return `${serverUrl}/images/ships/${item.id}.png`;
case 'weapon':
return `${serverUrl}/images/weapons/${item.id}.png`;
case 'armor':
return `${serverUrl}/images/armors/${item.id}.png`;
case 'material':
return `${serverUrl}/images/items/materials/${item.id}.png`;
case 'consumable':
return `${serverUrl}/images/items/consumables/${item.id}.png`;
case 'cosmetic':
return `${serverUrl}/images/items/cosmetics/${item.id}.png`;
default:
return `${serverUrl}/images/ui/placeholder.png`;
}
}
// For singleplayer, use local texture path (if available)
if (item.texture) {
return item.texture;
}
// Fallback to server placeholder
return 'https://dev.gameserver.galaxystrike.online/images/ui/placeholder.png';
}
/**
* Get server URL for image requests
*/
getServerUrl() {
// Get server URL from socket connection
if (this.game.socket && this.game.socket.io && this.game.socket.io.uri) {
return this.game.socket.io.uri.replace('/socket.io', '');
}
// Fallback to environment variable or production server
return process.env.SERVER_URL || 'https://dev.gameserver.galaxystrike.online';
}
// Save/Load functionality
save() {
return {
credits: this.credits,
gems: this.gems,
premiumCurrency: this.premiumCurrency,
transactions: this.transactions,
ownedCosmetics: this.ownedCosmetics,
shopData: {
randomShopItems: this.randomShopItems,
categoryPurchaseLimits: this.categoryPurchaseLimits,
lastShopRefresh: this.lastShopRefresh
}
};
}
load(data) {
if (data.credits !== undefined) this.credits = data.credits;
if (data.gems !== undefined) this.gems = data.gems;
if (data.premiumCurrency !== undefined) this.premiumCurrency = data.premiumCurrency;
if (data.transactions) this.transactions = data.transactions;
if (data.ownedCosmetics) this.ownedCosmetics = data.ownedCosmetics;
// Load shop data
if (data.shopData) {
this.randomShopItems = data.shopData.randomShopItems || {};
this.categoryPurchaseLimits = data.shopData.categoryPurchaseLimits || {};
this.lastShopRefresh = data.shopData.lastShopRefresh || null;
}
this.updateUI();
}
// Reset functionality
reset() {
const oldState = {
credits: this.credits,
gems: this.gems,
premiumCurrency: this.premiumCurrency,
transactionCount: this.transactions.length,
ownedCosmeticsCount: this.ownedCosmetics.length
};
this.credits = 1000;
this.gems = 10;
this.premiumCurrency = 0;
this.transactions = [];
this.ownedCosmetics = [];
// Reset daily rewards
localStorage.removeItem('lastDailyReward');
this.updateUI();
return oldState;
}
clear() {
const oldState = {
credits: this.credits,
gems: this.gems,
premiumCurrency: this.premiumCurrency,
transactionCount: this.transactions.length,
ownedCosmeticsCount: this.ownedCosmetics.length
};
this.credits = 0;
this.gems = 0;
this.premiumCurrency = 0;
this.transactions = [];
this.ownedCosmetics = [];
this.updateUI();
return oldState;
}
// Initialize random shop for singleplayer (minimal implementation)
initializeRandomShop() {
console.log('[ECONOMY] Random shop not available in singleplayer mode');
this.randomShopItems = {};
}
// Get system statistics
getStats() {
return {
credits: this.credits,
gems: this.gems,
premiumCurrency: this.premiumCurrency,
transactionCount: this.transactions.length,
ownedCosmeticsCount: this.ownedCosmetics.length,
shopItemsCount: this.game.systems.itemSystem && this.game.systems.itemSystem.itemCatalog ?
this.game.systems.itemSystem.getStats().totalItems : 0
};
}
}
// Export for use in other modules
if (typeof module !== 'undefined' && module.exports) {
module.exports = Economy;
} else {
window.Economy = Economy;
}