749 lines
28 KiB
JavaScript
749 lines
28 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;
|
|
|
|
// Preserve existing economy data if available (prevents wipe during re-initialization)
|
|
const existingEconomy = window.game?.systems?.economy;
|
|
const preservedCredits = existingEconomy?.credits || 0;
|
|
const preservedGems = existingEconomy?.gems || 0;
|
|
|
|
// Player resources
|
|
this.credits = preservedCredits;
|
|
this.gems = preservedGems;
|
|
this.premiumCurrency = 0;
|
|
|
|
// Transaction tracking
|
|
this.transactionHistory = [];
|
|
this.transactions = []; // Add missing transactions array
|
|
|
|
// Owned cosmetics
|
|
this.ownedCosmetics = []; // Add missing owned cosmetics array
|
|
|
|
// Shop categories
|
|
this.shopCategories = {
|
|
ships: 'Ships',
|
|
weapons: 'Weapons',
|
|
modules: 'Modules',
|
|
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.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 = [];
|
|
|
|
console.log('[ECONOMY] Economy system initialized with server-side ItemSystem');
|
|
console.log('[ECONOMY] Preserved values - Credits:', this.credits, 'Gems:', this.gems);
|
|
|
|
// Set up socket listeners for economy sync
|
|
this.setupSocketListeners();
|
|
|
|
// Request fresh economy data after a short delay to ensure sync
|
|
if (window.smartSaveManager?.isMultiplayer) {
|
|
setTimeout(() => {
|
|
this.requestEconomyData();
|
|
}, 1000);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
this.credits = data.credits || 0;
|
|
this.gems = data.gems || 0;
|
|
|
|
// Update UI immediately
|
|
if (this.game.ui) {
|
|
this.game.ui.updatePlayerStats();
|
|
}
|
|
|
|
console.log('[ECONOMY] Economy synced - Credits:', this.credits, 'Gems:', this.gems);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
// UI updates
|
|
updateUI() {
|
|
// 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');
|
|
console.log('[ECONOMY] Multiplayer mode:', window.smartSaveManager?.isMultiplayer);
|
|
console.log('[ECONOMY] ItemSystem available:', !!(this.game.systems.itemSystem));
|
|
console.log('[ECONOMY] ItemSystem catalog:', !!(this.game.systems.itemSystem?.itemCatalog));
|
|
|
|
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, skipping shop update');
|
|
return;
|
|
}
|
|
|
|
// Safe to use ItemSystem now
|
|
const items = Array.from(this.game.systems.itemSystem.shopItems || []);
|
|
console.log('[ECONOMY] Rendering shop with', items.length, 'items from ItemSystem');
|
|
console.log('[ECONOMY] First few items:', items.slice(0, 3));
|
|
this.renderShopItems(items);
|
|
} else {
|
|
// Singleplayer mode - use local shop data
|
|
console.log('[ECONOMY] Singleplayer mode - using local shop data');
|
|
const items = Object.values(this.randomShopItems).flat();
|
|
console.log('[ECONOMY] Rendering shop with', items.length, 'local items');
|
|
this.renderShopItems(items);
|
|
}
|
|
}
|
|
|
|
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);
|
|
console.log('[ECONOMY] All items types:', items.map(item => ({id: item.id, type: item.type, name: item.name})));
|
|
console.log('[ECONOMY] Unique item types:', [...new Set(items.map(item => item.type))]);
|
|
|
|
// Map category names to item types (handle plural/singular mismatches)
|
|
const categoryTypeMap = {
|
|
'ships': 'ship',
|
|
'weapons': 'weapon',
|
|
'armors': 'armor',
|
|
'cosmetics': 'cosmetic',
|
|
'consumables': 'consumable',
|
|
'materials': 'material',
|
|
'keys': 'key'
|
|
};
|
|
|
|
const targetItemType = categoryTypeMap[activeCategory] || activeCategory;
|
|
console.log('[ECONOMY] Mapped category', activeCategory, 'to item type', targetItemType);
|
|
|
|
const categoryItems = items.filter(item => item.type === targetItemType);
|
|
console.log('[ECONOMY] Filtered items for category', activeCategory, '(type:', targetItemType, ') :', categoryItems.length, 'items');
|
|
|
|
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}"
|
|
${!canAfford || isOwned ? 'disabled' : ''}>
|
|
${isOwned ? 'Owned' : 'Purchase'}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}).join('');
|
|
}
|
|
|
|
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;
|
|
}
|