2189 lines
82 KiB
JavaScript
2189 lines
82 KiB
JavaScript
/**
|
|
* Galaxy Strike Online - Base System
|
|
* Manages player base building and customization
|
|
*/
|
|
|
|
class BaseSystem {
|
|
constructor(gameEngine) {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('BaseSystem.constructor', {
|
|
gameEngineProvided: !!gameEngine
|
|
});
|
|
|
|
this.game = gameEngine;
|
|
|
|
// Base configuration
|
|
this.base = {
|
|
name: 'Command Center Alpha',
|
|
level: 1,
|
|
experience: 0,
|
|
experienceToNext: 500,
|
|
rooms: [],
|
|
decorations: [],
|
|
power: 100,
|
|
maxPower: 100,
|
|
storage: 1000,
|
|
maxStorage: 1000
|
|
};
|
|
|
|
if (debugLogger) debugLogger.logStep('Base configuration initialized', {
|
|
baseName: this.base.name,
|
|
baseLevel: this.base.level,
|
|
initialPower: this.base.power,
|
|
maxPower: this.base.maxPower,
|
|
initialStorage: this.base.storage,
|
|
maxStorage: this.base.maxStorage
|
|
});
|
|
|
|
// Room types
|
|
this.roomTypes = {
|
|
command_center: {
|
|
name: 'Command Center',
|
|
description: 'Central control room for your operations',
|
|
size: 'large',
|
|
powerCost: 20,
|
|
storageBonus: 0,
|
|
buildCost: 0,
|
|
requiredLevel: 1,
|
|
maxLevel: 1,
|
|
icon: 'fa-satellite-dish'
|
|
},
|
|
barracks: {
|
|
name: 'Barracks',
|
|
description: 'Housing for crew and allies',
|
|
size: 'medium',
|
|
powerCost: 10,
|
|
storageBonus: 100,
|
|
buildCost: 500,
|
|
requiredLevel: 2,
|
|
maxLevel: 5,
|
|
icon: 'fa-home'
|
|
},
|
|
laboratory: {
|
|
name: 'Laboratory',
|
|
description: 'Research facility for new technologies',
|
|
size: 'medium',
|
|
powerCost: 15,
|
|
storageBonus: 50,
|
|
buildCost: 1000,
|
|
requiredLevel: 3,
|
|
maxLevel: 5,
|
|
icon: 'fa-flask'
|
|
},
|
|
workshop: {
|
|
name: 'Workshop',
|
|
description: 'Crafting and equipment modification station',
|
|
size: 'medium',
|
|
powerCost: 12,
|
|
storageBonus: 80,
|
|
buildCost: 800,
|
|
requiredLevel: 2,
|
|
maxLevel: 5,
|
|
icon: 'fa-hammer'
|
|
},
|
|
storage_bay: {
|
|
name: 'Storage Bay',
|
|
description: 'Additional storage for resources and items',
|
|
size: 'large',
|
|
powerCost: 5,
|
|
storageBonus: 500,
|
|
buildCost: 300,
|
|
requiredLevel: 1,
|
|
maxLevel: 10,
|
|
icon: 'fa-warehouse'
|
|
},
|
|
power_generator: {
|
|
name: 'Power Generator',
|
|
description: 'Generates power for base operations',
|
|
size: 'small',
|
|
powerCost: -25,
|
|
storageBonus: 0,
|
|
buildCost: 600,
|
|
requiredLevel: 2,
|
|
maxLevel: 5,
|
|
icon: 'fa-bolt'
|
|
},
|
|
defense_turret: {
|
|
name: 'Defense Turret',
|
|
description: 'Automated defense system',
|
|
size: 'small',
|
|
powerCost: 8,
|
|
storageBonus: 0,
|
|
buildCost: 400,
|
|
requiredLevel: 3,
|
|
maxLevel: 8,
|
|
icon: 'fa-crosshairs'
|
|
},
|
|
communication_array: {
|
|
name: 'Communication Array',
|
|
description: 'Long-range communication and scanning',
|
|
size: 'medium',
|
|
powerCost: 10,
|
|
storageBonus: 20,
|
|
buildCost: 700,
|
|
requiredLevel: 4,
|
|
maxLevel: 3,
|
|
icon: 'fa-broadcast-tower'
|
|
},
|
|
medical_bay: {
|
|
name: 'Medical Bay',
|
|
description: 'Health restoration and crew recovery',
|
|
size: 'medium',
|
|
powerCost: 12,
|
|
storageBonus: 30,
|
|
buildCost: 900,
|
|
requiredLevel: 3,
|
|
maxLevel: 4,
|
|
icon: 'fa-medkit'
|
|
},
|
|
recreation_room: {
|
|
name: 'Recreation Room',
|
|
description: 'Crew morale and relaxation facilities',
|
|
size: 'small',
|
|
powerCost: 6,
|
|
storageBonus: 10,
|
|
buildCost: 350,
|
|
requiredLevel: 2,
|
|
maxLevel: 3,
|
|
icon: 'fa-gamepad'
|
|
}
|
|
};
|
|
|
|
// Base upgrades
|
|
this.upgrades = {
|
|
power_efficiency: {
|
|
name: 'Power Efficiency',
|
|
description: 'Reduces power consumption of all rooms',
|
|
cost: 1000,
|
|
effect: { powerReduction: 0.1 },
|
|
maxLevel: 5,
|
|
currentLevel: 0
|
|
},
|
|
storage_expansion: {
|
|
name: 'Storage Expansion',
|
|
description: 'Increases inventory slots for item storage',
|
|
cost: 5000,
|
|
maxLevel: 10,
|
|
currentLevel: 0,
|
|
icon: 'fa-boxes',
|
|
slotBonus: 5 // +5 slots per level
|
|
},
|
|
automation_systems: {
|
|
name: 'Automation Systems',
|
|
description: 'Automated resource collection and processing',
|
|
cost: 1500,
|
|
effect: {
|
|
productionBonus: 0.2 // +20% production
|
|
},
|
|
maxLevel: 5,
|
|
currentLevel: 0
|
|
},
|
|
advanced_defenses: {
|
|
name: 'Advanced Defenses',
|
|
description: 'Improved base defense systems',
|
|
cost: 2000,
|
|
effect: { defenseBonus: 10 },
|
|
maxLevel: 3,
|
|
currentLevel: 0
|
|
}
|
|
};
|
|
|
|
// Base grid layout (10x10)
|
|
this.gridSize = 10;
|
|
this.grid = [];
|
|
|
|
if (debugLogger) debugLogger.logStep('Grid configuration initialized', {
|
|
gridSize: this.gridSize,
|
|
gridInitialized: false
|
|
});
|
|
|
|
// Initialize grid
|
|
this.initializeGrid();
|
|
|
|
if (debugLogger) debugLogger.endStep('BaseSystem.constructor', {
|
|
roomTypesCount: Object.keys(this.roomTypes).length,
|
|
upgradesCount: Object.keys(this.upgrades).length,
|
|
gridSize: this.gridSize,
|
|
gridInitialized: !!this.grid,
|
|
baseConfiguration: this.base
|
|
});
|
|
}
|
|
|
|
initializeBaseData() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('BaseSystem.initializeBaseData', {
|
|
oldBaseName: this.base.name,
|
|
oldBaseLevel: this.base.level
|
|
});
|
|
|
|
// Initialize base with default values
|
|
this.base = {
|
|
name: 'Command Center Alpha',
|
|
level: 1,
|
|
experience: 0,
|
|
experienceToNext: 500,
|
|
rooms: [],
|
|
decorations: [],
|
|
power: 100,
|
|
maxPower: 100,
|
|
storage: 1000,
|
|
maxStorage: 1000
|
|
};
|
|
|
|
// Initialize resources
|
|
this.resources = {
|
|
energy: 100,
|
|
materials: 50,
|
|
research: 0
|
|
};
|
|
|
|
if (debugLogger) debugLogger.endStep('BaseSystem.initializeBaseData', {
|
|
newBaseName: this.base.name,
|
|
newBaseLevel: this.base.level,
|
|
roomsCount: this.base.rooms.length,
|
|
decorationsCount: this.base.decorations.length,
|
|
resourcesInitialized: this.resources
|
|
});
|
|
}
|
|
|
|
initialize() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('BaseSystem.initialize', {
|
|
currentBaseLevel: this.base.level,
|
|
roomsCount: this.base.rooms.length
|
|
});
|
|
|
|
// Initialize base data
|
|
if (debugLogger) debugLogger.logStep('Initializing base data');
|
|
this.initializeBaseData();
|
|
|
|
// Initialize inventory bonus slots on game start
|
|
if (debugLogger) debugLogger.logStep('Updating inventory bonus slots');
|
|
this.updateInventoryBonusSlots();
|
|
|
|
if (debugLogger) debugLogger.endStep('BaseSystem.initialize', {
|
|
baseDataInitialized: true,
|
|
inventoryBonusSlotsUpdated: true
|
|
});
|
|
}
|
|
|
|
async initialize() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('BaseSystem.asyncInitialize', {
|
|
currentBaseLevel: this.base.level,
|
|
roomsCount: this.base.rooms.length
|
|
});
|
|
|
|
// Start with command center
|
|
if (debugLogger) debugLogger.logStep('Adding command center room');
|
|
this.addRoom('command_center', 5, 5);
|
|
|
|
// Set up base navigation
|
|
if (debugLogger) debugLogger.logStep('Setting up base navigation');
|
|
this.setupBaseNavigation();
|
|
|
|
// Initialize ship gallery
|
|
if (debugLogger) debugLogger.logStep('Initializing ship gallery');
|
|
this.initializeShipGallery();
|
|
|
|
// Initialize starbase system
|
|
if (debugLogger) debugLogger.logStep('Initializing starbase system');
|
|
this.initializeStarbaseSystem();
|
|
|
|
if (debugLogger) debugLogger.endStep('BaseSystem.asyncInitialize', {
|
|
commandCenterAdded: true,
|
|
navigationSetup: true,
|
|
shipGalleryInitialized: true,
|
|
starbaseSystemInitialized: true
|
|
});
|
|
}
|
|
|
|
initializeGrid() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('BaseSystem.initializeGrid', {
|
|
gridSize: this.gridSize
|
|
});
|
|
|
|
this.grid = [];
|
|
for (let y = 0; y < this.gridSize; y++) {
|
|
this.grid[y] = [];
|
|
for (let x = 0; x < this.gridSize; x++) {
|
|
this.grid[y][x] = null;
|
|
}
|
|
}
|
|
|
|
if (debugLogger) debugLogger.endStep('BaseSystem.initializeGrid', {
|
|
gridSize: this.gridSize,
|
|
gridCreated: true,
|
|
totalCells: this.gridSize * this.gridSize
|
|
});
|
|
}
|
|
|
|
// Room management
|
|
getRoomAt(x, y) {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.log('BaseSystem.getRoomAt called', {
|
|
x: x,
|
|
y: y,
|
|
gridSize: this.gridSize
|
|
});
|
|
|
|
// Check if coordinates are within grid bounds
|
|
if (x < 0 || x >= this.gridSize || y < 0 || y >= this.gridSize) {
|
|
if (debugLogger) debugLogger.log('Coordinates out of bounds', {
|
|
x: x,
|
|
y: y,
|
|
gridSize: this.gridSize
|
|
});
|
|
return null;
|
|
}
|
|
|
|
// Ensure grid exists
|
|
if (!this.grid || !this.grid[y]) {
|
|
console.log('[BASE SYSTEM] Grid not properly initialized in getRoomAt');
|
|
if (debugLogger) debugLogger.log('Grid not properly initialized', {
|
|
gridExists: !!this.grid,
|
|
gridRowExists: !!(this.grid && this.grid[y]),
|
|
y: y
|
|
});
|
|
return null;
|
|
}
|
|
|
|
// Get room ID from grid
|
|
const roomId = this.grid[y][x];
|
|
if (!roomId) {
|
|
if (debugLogger) debugLogger.log('No room at coordinates', {
|
|
x: x,
|
|
y: y,
|
|
roomId: roomId
|
|
});
|
|
return null;
|
|
}
|
|
|
|
// Find room by ID
|
|
const room = this.base.rooms.find(r => r.id === roomId) || null;
|
|
|
|
if (debugLogger) debugLogger.log('Room found at coordinates', {
|
|
x: x,
|
|
y: y,
|
|
roomId: roomId,
|
|
roomFound: !!room,
|
|
roomName: room ? room.name : null,
|
|
roomType: room ? room.type : null
|
|
});
|
|
|
|
return room;
|
|
}
|
|
|
|
canBuildRoom(roomType, x, y) {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('BaseSystem.canBuildRoom', {
|
|
roomType: roomType,
|
|
x: x,
|
|
y: y,
|
|
currentBaseLevel: this.base.level,
|
|
currentCredits: this.game.systems.economy.credits,
|
|
currentRooms: this.base.rooms.length
|
|
});
|
|
|
|
const roomTemplate = this.roomTypes[roomType];
|
|
if (!roomTemplate) {
|
|
if (debugLogger) debugLogger.endStep('BaseSystem.canBuildRoom', {
|
|
success: false,
|
|
reason: 'Room template not found',
|
|
roomType: roomType
|
|
});
|
|
return false;
|
|
}
|
|
|
|
if (debugLogger) debugLogger.logStep('Room template found', {
|
|
roomName: roomTemplate.name,
|
|
requiredLevel: roomTemplate.requiredLevel,
|
|
buildCost: roomTemplate.buildCost,
|
|
powerCost: roomTemplate.powerCost,
|
|
maxLevel: roomTemplate.maxLevel
|
|
});
|
|
|
|
// Check player level
|
|
if (this.game.systems.player.stats.level < roomTemplate.requiredLevel) {
|
|
if (debugLogger) debugLogger.endStep('BaseSystem.canBuildRoom', {
|
|
success: false,
|
|
reason: 'Player level too low',
|
|
playerLevel: this.game.systems.player.stats.level,
|
|
requiredLevel: roomTemplate.requiredLevel
|
|
});
|
|
return false;
|
|
}
|
|
|
|
// Check resources
|
|
if (this.game.systems.economy.credits < roomTemplate.buildCost) {
|
|
if (debugLogger) debugLogger.endStep('BaseSystem.canBuildRoom', {
|
|
success: false,
|
|
reason: 'Insufficient credits',
|
|
currentCredits: this.game.systems.economy.credits,
|
|
requiredCredits: roomTemplate.buildCost
|
|
});
|
|
return false;
|
|
}
|
|
|
|
// Check if room already exists at max level
|
|
const existingRoom = this.base.rooms.find(r => r.type === roomType);
|
|
if (existingRoom && existingRoom.level >= roomTemplate.maxLevel) {
|
|
if (debugLogger) debugLogger.endStep('BaseSystem.canBuildRoom', {
|
|
success: false,
|
|
reason: 'Room already at max level',
|
|
roomType: roomType,
|
|
currentLevel: existingRoom.level,
|
|
maxLevel: roomTemplate.maxLevel
|
|
});
|
|
return false;
|
|
}
|
|
|
|
// Check grid placement
|
|
const roomSize = this.getRoomSize(roomTemplate.size);
|
|
if (!this.canPlaceRoom(x, y, roomSize.width, roomSize.height)) {
|
|
if (debugLogger) debugLogger.endStep('BaseSystem.canBuildRoom', {
|
|
success: false,
|
|
reason: 'Cannot place room at location',
|
|
x: x,
|
|
y: y,
|
|
roomSize: roomSize
|
|
});
|
|
return false;
|
|
}
|
|
|
|
// Check power availability
|
|
const powerRequirement = roomTemplate.powerCost;
|
|
if (this.base.power + powerRequirement > this.base.maxPower) {
|
|
if (debugLogger) debugLogger.endStep('BaseSystem.canBuildRoom', {
|
|
success: false,
|
|
reason: 'Insufficient power',
|
|
currentPower: this.base.power,
|
|
powerRequirement: powerRequirement,
|
|
maxPower: this.base.maxPower,
|
|
totalPowerNeeded: this.base.power + powerRequirement
|
|
});
|
|
return false;
|
|
}
|
|
|
|
if (debugLogger) debugLogger.endStep('BaseSystem.canBuildRoom', {
|
|
success: true,
|
|
roomType: roomType,
|
|
roomName: roomTemplate.name,
|
|
x: x,
|
|
y: y,
|
|
isUpgrade: !!existingRoom,
|
|
currentLevel: existingRoom ? existingRoom.level : 0
|
|
});
|
|
|
|
return true;
|
|
}
|
|
|
|
getRoomSize(size) {
|
|
const sizes = {
|
|
small: { width: 1, height: 1 },
|
|
medium: { width: 2, height: 2 },
|
|
large: { width: 3, height: 3 }
|
|
};
|
|
return sizes[size] || sizes.medium;
|
|
}
|
|
|
|
canPlaceRoom(x, y, width, height) {
|
|
// Check bounds
|
|
if (x < 0 || y < 0 || x + width > this.gridSize || y + height > this.gridSize) {
|
|
return false;
|
|
}
|
|
|
|
// Check for collisions
|
|
for (let dy = 0; dy < height; dy++) {
|
|
for (let dx = 0; dx < width; dx++) {
|
|
if (this.grid[y + dy][x + dx] !== null) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
addRoom(roomType, x, y) {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('BaseSystem.addRoom', {
|
|
roomType: roomType,
|
|
x: x,
|
|
y: y,
|
|
currentRoomsCount: this.base.rooms.length,
|
|
currentCredits: this.game.systems.economy.credits
|
|
});
|
|
|
|
if (!this.canBuildRoom(roomType, x, y)) {
|
|
if (debugLogger) debugLogger.endStep('BaseSystem.addRoom', {
|
|
success: false,
|
|
reason: 'Cannot build room - failed validation',
|
|
roomType: roomType,
|
|
x: x,
|
|
y: y
|
|
});
|
|
return false;
|
|
}
|
|
|
|
const roomTemplate = this.roomTypes[roomType];
|
|
const roomSize = this.getRoomSize(roomTemplate.size);
|
|
|
|
if (debugLogger) debugLogger.logStep('Room validation passed', {
|
|
roomName: roomTemplate.name,
|
|
roomSize: roomSize,
|
|
buildCost: roomTemplate.buildCost
|
|
});
|
|
|
|
// Check if upgrading existing room
|
|
const existingRoom = this.base.rooms.find(r => r.type === roomType);
|
|
const isUpgrade = !!existingRoom;
|
|
|
|
if (isUpgrade) {
|
|
if (debugLogger) debugLogger.logStep('Upgrading existing room', {
|
|
roomId: existingRoom.id,
|
|
currentLevel: existingRoom.level,
|
|
newLevel: existingRoom.level + 1
|
|
});
|
|
|
|
// Upgrade existing room
|
|
existingRoom.level++;
|
|
existingRoom.powerCost = roomTemplate.powerCost * existingRoom.level;
|
|
existingRoom.storageBonus = roomTemplate.storageBonus * existingRoom.level;
|
|
} else {
|
|
if (debugLogger) debugLogger.logStep('Creating new room', {
|
|
roomType: roomType,
|
|
roomName: roomTemplate.name,
|
|
x: x,
|
|
y: y,
|
|
roomSize: roomSize
|
|
});
|
|
|
|
// Create new room
|
|
const room = {
|
|
id: Date.now().toString(),
|
|
type: roomType,
|
|
name: roomTemplate.name,
|
|
level: 1,
|
|
x: x,
|
|
y: y,
|
|
width: roomSize.width,
|
|
height: roomSize.height,
|
|
powerCost: roomTemplate.powerCost,
|
|
storageBonus: roomTemplate.storageBonus,
|
|
icon: roomTemplate.icon,
|
|
description: roomTemplate.description
|
|
};
|
|
|
|
this.base.rooms.push(room);
|
|
|
|
// Place on grid
|
|
for (let dy = 0; dy < roomSize.height; dy++) {
|
|
for (let dx = 0; dx < roomSize.width; dx++) {
|
|
this.grid[y + dy][x + dx] = room.id;
|
|
}
|
|
}
|
|
|
|
if (debugLogger) debugLogger.logStep('New room placed on grid', {
|
|
roomId: room.id,
|
|
gridPositions: roomSize.width * roomSize.height
|
|
});
|
|
}
|
|
|
|
// Update base stats
|
|
if (debugLogger) debugLogger.logStep('Updating base stats');
|
|
this.updateBaseStats();
|
|
|
|
// Deduct cost
|
|
const oldCredits = this.game.systems.economy.credits;
|
|
this.game.systems.economy.removeCredits(roomTemplate.buildCost);
|
|
|
|
if (debugLogger) debugLogger.logStep('Build cost deducted', {
|
|
buildCost: roomTemplate.buildCost,
|
|
oldCredits: oldCredits,
|
|
newCredits: this.game.systems.economy.credits
|
|
});
|
|
|
|
this.game.showNotification(`${roomTemplate.name} ${isUpgrade ? 'upgraded' : 'built'}!`, 'success', 3000);
|
|
|
|
if (debugLogger) debugLogger.endStep('BaseSystem.addRoom', {
|
|
success: true,
|
|
roomType: roomType,
|
|
roomName: roomTemplate.name,
|
|
isUpgrade: isUpgrade,
|
|
roomId: isUpgrade ? existingRoom.id : this.base.rooms[this.base.rooms.length - 1].id,
|
|
newLevel: isUpgrade ? existingRoom.level : 1,
|
|
finalRoomsCount: this.base.rooms.length,
|
|
buildCost: roomTemplate.buildCost,
|
|
finalCredits: this.game.systems.economy.credits
|
|
});
|
|
|
|
return true;
|
|
}
|
|
|
|
removeRoom(roomId) {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('BaseSystem.removeRoom', {
|
|
roomId: roomId,
|
|
currentRoomsCount: this.base.rooms.length
|
|
});
|
|
|
|
const roomIndex = this.base.rooms.findIndex(r => r.id === roomId);
|
|
if (roomIndex === -1) {
|
|
if (debugLogger) debugLogger.endStep('BaseSystem.removeRoom', {
|
|
success: false,
|
|
reason: 'Room not found',
|
|
roomId: roomId
|
|
});
|
|
return false;
|
|
}
|
|
|
|
const room = this.base.rooms[roomIndex];
|
|
|
|
if (debugLogger) debugLogger.logStep('Room found for removal', {
|
|
roomId: room.id,
|
|
roomName: room.name,
|
|
roomType: room.type,
|
|
roomLevel: room.level,
|
|
roomPosition: { x: room.x, y: room.y }
|
|
});
|
|
|
|
// Don't allow removing command center
|
|
if (room.type === 'command_center') {
|
|
this.game.showNotification('Cannot remove Command Center', 'error', 3000);
|
|
|
|
if (debugLogger) debugLogger.endStep('BaseSystem.removeRoom', {
|
|
success: false,
|
|
reason: 'Cannot remove command center',
|
|
roomId: roomId,
|
|
roomType: room.type
|
|
});
|
|
return false;
|
|
}
|
|
|
|
// Remove from grid
|
|
let gridCellsCleared = 0;
|
|
for (let dy = 0; dy < room.height; dy++) {
|
|
for (let dx = 0; dx < room.width; dx++) {
|
|
this.grid[room.y + dy][room.x + dx] = null;
|
|
gridCellsCleared++;
|
|
}
|
|
}
|
|
|
|
if (debugLogger) debugLogger.logStep('Room removed from grid', {
|
|
gridCellsCleared: gridCellsCleared,
|
|
roomSize: { width: room.width, height: room.height }
|
|
});
|
|
|
|
// Remove from rooms array
|
|
this.base.rooms.splice(roomIndex, 1);
|
|
|
|
if (debugLogger) debugLogger.logStep('Room removed from rooms array', {
|
|
removedIndex: roomIndex,
|
|
remainingRoomsCount: this.base.rooms.length
|
|
});
|
|
|
|
// Update base stats
|
|
if (debugLogger) debugLogger.logStep('Updating base stats after removal');
|
|
this.updateBaseStats();
|
|
|
|
// Refund some resources
|
|
const refundAmount = Math.floor(this.roomTypes[room.type].buildCost * 0.5);
|
|
const oldCredits = this.game.systems.economy.credits;
|
|
this.game.systems.economy.addCredits(refundAmount, 'room_refund');
|
|
|
|
if (debugLogger) debugLogger.logStep('Refund processed', {
|
|
refundAmount: refundAmount,
|
|
oldCredits: oldCredits,
|
|
newCredits: this.game.systems.economy.credits,
|
|
originalBuildCost: this.roomTypes[room.type].buildCost,
|
|
refundPercentage: 0.5
|
|
});
|
|
|
|
this.game.showNotification(`${room.name} removed. Refunded ${refundAmount} credits`, 'info', 3000);
|
|
|
|
if (debugLogger) debugLogger.endStep('BaseSystem.removeRoom', {
|
|
success: true,
|
|
roomId: roomId,
|
|
roomName: room.name,
|
|
roomType: room.type,
|
|
refundAmount: refundAmount,
|
|
finalRoomsCount: this.base.rooms.length,
|
|
finalCredits: this.game.systems.economy.credits
|
|
});
|
|
|
|
return true;
|
|
}
|
|
|
|
calculateBaseStats() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('BaseSystem.calculateBaseStats', {
|
|
currentRoomsCount: this.base.rooms.length,
|
|
currentPower: this.base.power,
|
|
currentMaxPower: this.base.maxPower,
|
|
currentStorage: this.base.storage,
|
|
currentMaxStorage: this.base.maxStorage
|
|
});
|
|
|
|
let totalPowerCost = 0;
|
|
let totalStorageBonus = 0;
|
|
|
|
// Calculate power cost and storage bonus from rooms
|
|
this.base.rooms.forEach(room => {
|
|
const roomType = this.roomTypes[room.type];
|
|
const roomPowerCost = roomType.powerCost * room.level;
|
|
const roomStorageBonus = roomType.storageBonus * room.level;
|
|
|
|
totalPowerCost += roomPowerCost;
|
|
totalStorageBonus += roomStorageBonus;
|
|
|
|
if (debugLogger) debugLogger.logStep('Room contribution calculated', {
|
|
roomId: room.id,
|
|
roomType: room.type,
|
|
roomName: room.name,
|
|
roomLevel: room.level,
|
|
powerCost: roomPowerCost,
|
|
storageBonus: roomStorageBonus
|
|
});
|
|
});
|
|
|
|
// Add upgrade bonuses
|
|
const storageExpansion = (this.upgrades.storage_expansion?.currentLevel || 0) * (this.upgrades.storage_expansion?.slotBonus || 5);
|
|
totalStorageBonus += storageExpansion;
|
|
|
|
if (debugLogger) debugLogger.logStep('Upgrade bonuses calculated', {
|
|
storageExpansionLevel: this.upgrades.storage_expansion?.currentLevel || 0,
|
|
storageExpansionBonus: storageExpansion,
|
|
totalStorageBonusWithUpgrades: totalStorageBonus
|
|
});
|
|
|
|
const oldPower = this.base.power;
|
|
const oldMaxPower = this.base.maxPower;
|
|
const oldStorage = this.base.storage;
|
|
const oldMaxStorage = this.base.maxStorage;
|
|
|
|
this.base.power = Math.max(0, totalPowerCost);
|
|
this.base.maxPower = 100 + ((this.upgrades.power_efficiency?.currentLevel || 0) * 20);
|
|
|
|
// Update inventory base slots with storage upgrades
|
|
if (this.game.systems.inventory) {
|
|
const newBaseSlots = 30 + totalStorageBonus; // 30 base + storage bonuses
|
|
const oldBaseSlots = this.game.systems.inventory.baseMaxSlots;
|
|
|
|
this.game.systems.inventory.baseMaxSlots = newBaseSlots;
|
|
this.game.systems.inventory.updateStarbaseBonusSlots(this.game.systems.inventory.starbaseBonusSlots);
|
|
|
|
if (debugLogger) debugLogger.logStep('Inventory slots updated', {
|
|
oldBaseSlots: oldBaseSlots,
|
|
newBaseSlots: newBaseSlots,
|
|
starbaseBonusSlots: this.game.systems.inventory.starbaseBonusSlots,
|
|
finalMaxSlots: this.game.systems.inventory.maxSlots
|
|
});
|
|
}
|
|
|
|
// Keep legacy storage for backward compatibility
|
|
this.base.storage = 1000 + (totalStorageBonus * 100);
|
|
this.base.maxStorage = this.base.storage;
|
|
|
|
if (debugLogger) debugLogger.endStep('BaseSystem.calculateBaseStats', {
|
|
powerChanges: {
|
|
oldPower: oldPower,
|
|
newPower: this.base.power,
|
|
oldMaxPower: oldMaxPower,
|
|
newMaxPower: this.base.maxPower
|
|
},
|
|
storageChanges: {
|
|
oldStorage: oldStorage,
|
|
newStorage: this.base.storage,
|
|
oldMaxStorage: oldMaxStorage,
|
|
newMaxStorage: this.base.maxStorage
|
|
},
|
|
totals: {
|
|
totalPowerCost: totalPowerCost,
|
|
totalStorageBonus: totalStorageBonus,
|
|
storageExpansionBonus: storageExpansion
|
|
},
|
|
roomsProcessed: this.base.rooms.length
|
|
});
|
|
}
|
|
|
|
// Base upgrades
|
|
upgradeBase(upgradeId) {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('BaseSystem.upgradeBase', {
|
|
upgradeId: upgradeId,
|
|
currentCredits: this.game.systems.economy.credits,
|
|
currentUpgradeLevel: this.upgrades[upgradeId] ? this.upgrades[upgradeId].currentLevel : null
|
|
});
|
|
|
|
const upgrade = this.upgrades[upgradeId];
|
|
if (!upgrade) {
|
|
if (debugLogger) debugLogger.endStep('BaseSystem.upgradeBase', {
|
|
success: false,
|
|
reason: 'Upgrade not found',
|
|
upgradeId: upgradeId
|
|
});
|
|
return false;
|
|
}
|
|
|
|
if (debugLogger) debugLogger.logStep('Upgrade found', {
|
|
upgradeName: upgrade.name,
|
|
currentLevel: upgrade.currentLevel,
|
|
maxLevel: upgrade.maxLevel,
|
|
baseCost: upgrade.cost
|
|
});
|
|
|
|
if (upgrade.currentLevel >= upgrade.maxLevel) {
|
|
this.game.showNotification('Upgrade at maximum level', 'warning', 3000);
|
|
|
|
if (debugLogger) debugLogger.endStep('BaseSystem.upgradeBase', {
|
|
success: false,
|
|
reason: 'Upgrade at maximum level',
|
|
upgradeId: upgradeId,
|
|
currentLevel: upgrade.currentLevel,
|
|
maxLevel: upgrade.maxLevel
|
|
});
|
|
return false;
|
|
}
|
|
|
|
const cost = upgrade.cost * (upgrade.currentLevel + 1);
|
|
if (this.game.systems.economy.credits < cost) {
|
|
this.game.showNotification('Not enough credits', 'error', 3000);
|
|
|
|
if (debugLogger) debugLogger.endStep('BaseSystem.upgradeBase', {
|
|
success: false,
|
|
reason: 'Insufficient credits',
|
|
upgradeId: upgradeId,
|
|
requiredCredits: cost,
|
|
currentCredits: this.game.systems.economy.credits
|
|
});
|
|
return false;
|
|
}
|
|
|
|
if (debugLogger) debugLogger.logStep('Upgrade validation passed', {
|
|
upgradeId: upgradeId,
|
|
currentLevel: upgrade.currentLevel,
|
|
newLevel: upgrade.currentLevel + 1,
|
|
cost: cost
|
|
});
|
|
|
|
// Apply upgrade
|
|
const oldCredits = this.game.systems.economy.credits;
|
|
this.game.systems.economy.removeCredits(cost);
|
|
upgrade.currentLevel++;
|
|
|
|
if (debugLogger) debugLogger.logStep('Upgrade applied', {
|
|
oldCredits: oldCredits,
|
|
newCredits: this.game.systems.economy.credits,
|
|
costDeducted: cost,
|
|
newUpgradeLevel: upgrade.currentLevel
|
|
});
|
|
|
|
// Apply effects
|
|
let statsUpdated = false;
|
|
if (upgrade.effect.powerReduction) {
|
|
if (debugLogger) debugLogger.logStep('Applying power reduction effect');
|
|
this.updateBaseStats();
|
|
statsUpdated = true;
|
|
}
|
|
|
|
if (upgrade.effect.storageBonus) {
|
|
if (debugLogger) debugLogger.logStep('Applying storage bonus effect');
|
|
this.updateBaseStats();
|
|
statsUpdated = true;
|
|
}
|
|
|
|
if (upgrade.effect.productionBonus) {
|
|
if (debugLogger) debugLogger.logStep('Applying production bonus effect', {
|
|
productionBonus: upgrade.effect.productionBonus
|
|
});
|
|
statsUpdated = true;
|
|
}
|
|
|
|
if (upgrade.effect.defenseBonus) {
|
|
if (debugLogger) debugLogger.logStep('Applying defense bonus effect', {
|
|
defenseBonus: upgrade.effect.defenseBonus
|
|
});
|
|
statsUpdated = true;
|
|
}
|
|
|
|
if (!statsUpdated) {
|
|
// For upgrades like storage_expansion that don't have effects in the effect object
|
|
if (debugLogger) debugLogger.logStep('Updating base stats for upgrade');
|
|
this.updateBaseStats();
|
|
}
|
|
|
|
this.game.showNotification(`${upgrade.name} upgraded to level ${upgrade.currentLevel}!`, 'success', 3000);
|
|
|
|
if (debugLogger) debugLogger.endStep('BaseSystem.upgradeBase', {
|
|
success: true,
|
|
upgradeId: upgradeId,
|
|
upgradeName: upgrade.name,
|
|
oldLevel: upgrade.currentLevel - 1,
|
|
newLevel: upgrade.currentLevel,
|
|
cost: cost,
|
|
finalCredits: this.game.systems.economy.credits,
|
|
effectsApplied: statsUpdated
|
|
});
|
|
|
|
return true;
|
|
}
|
|
|
|
// Base production
|
|
update(deltaTime) {
|
|
if (this.game.state.paused) {
|
|
return;
|
|
}
|
|
|
|
// Auto production from automation systems
|
|
const autoProductionRate = (this.upgrades.automation_systems?.currentLevel || 0) * 0.05;
|
|
if (autoProductionRate > 0) {
|
|
// Use real computer time delta
|
|
const production = (deltaTime / 1000) * autoProductionRate * 10; // 10 credits per second per level
|
|
|
|
this.game.systems.economy.addCredits(Math.floor(production), 'base_production');
|
|
}
|
|
|
|
// Power generation from power generators
|
|
const powerGenerators = this.base.rooms.filter(r => r.type === 'power_generator');
|
|
if (powerGenerators.length > 0) {
|
|
const powerGeneration = powerGenerators.reduce((total, gen) => total + Math.abs(gen.powerCost), 0);
|
|
|
|
// Power generation would affect other systems
|
|
}
|
|
|
|
// Research production
|
|
if ((this.upgrades.research_lab?.currentLevel || 0) > 0) {
|
|
const researchRate = (this.upgrades.research_lab?.currentLevel || 0) * 0.1;
|
|
// Research points generation would go here
|
|
}
|
|
|
|
// Resource processing
|
|
if ((this.upgrades.resource_processor?.currentLevel || 0) > 0) {
|
|
const processingRate = (this.upgrades.resource_processor?.currentLevel || 0) * 0.05;
|
|
// Resource processing would go here
|
|
}
|
|
}
|
|
|
|
// UI updates
|
|
updateUI() {
|
|
this.setupBaseNavigation();
|
|
this.updateBaseDisplay();
|
|
this.updateUpgradesList();
|
|
this.updateShipGallery();
|
|
this.updateStarbaseList();
|
|
}
|
|
|
|
// Base Navigation
|
|
setupBaseNavigation() {
|
|
const navButtons = document.querySelectorAll('.base-nav-btn');
|
|
navButtons.forEach(button => {
|
|
button.addEventListener('click', () => {
|
|
const view = button.dataset.view;
|
|
this.switchBaseView(view);
|
|
});
|
|
});
|
|
}
|
|
|
|
switchBaseView(view) {
|
|
// Hide all views
|
|
document.querySelectorAll('.base-view-content').forEach(content => {
|
|
content.classList.add('hidden');
|
|
});
|
|
|
|
// Remove active class from all buttons
|
|
document.querySelectorAll('.base-nav-btn').forEach(btn => {
|
|
btn.classList.remove('active');
|
|
});
|
|
|
|
// Show selected view
|
|
const selectedView = document.getElementById(`base-${view}`);
|
|
if (selectedView) {
|
|
selectedView.classList.remove('hidden');
|
|
}
|
|
|
|
// Add active class to clicked button
|
|
const activeBtn = document.querySelector(`[data-view="${view}"]`);
|
|
if (activeBtn) {
|
|
activeBtn.classList.add('active');
|
|
}
|
|
|
|
// Initialize view-specific content
|
|
if (view === 'visualization') {
|
|
this.initializeBaseVisualization();
|
|
} else if (view === 'ships') {
|
|
this.updateShipGallery();
|
|
} else if (view === 'starbases') {
|
|
this.updateStarbaseList();
|
|
this.updateStarbasePurchaseList();
|
|
}
|
|
}
|
|
|
|
// Base Visualization
|
|
initializeBaseVisualization() {
|
|
const canvas = document.getElementById('baseCanvas');
|
|
if (!canvas) return;
|
|
|
|
const ctx = canvas.getContext('2d');
|
|
|
|
// Clear canvas
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
|
|
// Draw base grid
|
|
this.drawBaseVisualization(ctx, canvas);
|
|
|
|
// Update info overlay
|
|
this.updateBaseInfoOverlay();
|
|
}
|
|
|
|
drawBaseVisualization(ctx, canvas) {
|
|
const cellSize = 40;
|
|
const offsetX = (canvas.width - this.gridSize * cellSize) / 2;
|
|
const offsetY = (canvas.height - this.gridSize * cellSize) / 2;
|
|
|
|
// Draw grid
|
|
ctx.strokeStyle = '#333';
|
|
ctx.lineWidth = 1;
|
|
|
|
for (let y = 0; y <= this.gridSize; y++) {
|
|
ctx.beginPath();
|
|
ctx.moveTo(offsetX, offsetY + y * cellSize);
|
|
ctx.lineTo(offsetX + this.gridSize * cellSize, offsetY + y * cellSize);
|
|
ctx.stroke();
|
|
}
|
|
|
|
for (let x = 0; x <= this.gridSize; x++) {
|
|
ctx.beginPath();
|
|
ctx.moveTo(offsetX + x * cellSize, offsetY);
|
|
ctx.lineTo(offsetX + x * cellSize, offsetY + this.gridSize * cellSize);
|
|
ctx.stroke();
|
|
}
|
|
|
|
// Draw rooms
|
|
for (let y = 0; y < this.gridSize; y++) {
|
|
for (let x = 0; x < this.gridSize; x++) {
|
|
const roomId = this.grid[y][x];
|
|
if (roomId) {
|
|
const room = this.base.rooms.find(r => r.id === roomId);
|
|
if (room) {
|
|
this.drawRoom(ctx, room, x, y, cellSize, offsetX, offsetY);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
drawRoom(ctx, room, gridX, gridY, cellSize, offsetX, offsetY) {
|
|
const x = offsetX + gridX * cellSize;
|
|
const y = offsetY + gridY * cellSize;
|
|
|
|
// Room colors by type
|
|
const roomColors = {
|
|
command_center: '#4CAF50',
|
|
power_generator: '#FFC107',
|
|
defense_turret: '#F44336',
|
|
storage: '#2196F3',
|
|
research_lab: '#9C27B0',
|
|
factory: '#FF9800',
|
|
medical_bay: '#00BCD4',
|
|
hangar: '#795548'
|
|
};
|
|
|
|
const color = roomColors[room.type] || '#666';
|
|
|
|
// Draw room
|
|
ctx.fillStyle = color;
|
|
ctx.fillRect(x + 2, y + 2, cellSize - 4, cellSize - 4);
|
|
|
|
// Draw room border
|
|
ctx.strokeStyle = '#fff';
|
|
ctx.lineWidth = 2;
|
|
ctx.strokeRect(x + 2, y + 2, cellSize - 4, cellSize - 4);
|
|
|
|
// Draw room icon/initial
|
|
ctx.fillStyle = '#fff';
|
|
ctx.font = 'bold 16px Arial';
|
|
ctx.textAlign = 'center';
|
|
ctx.textBaseline = 'middle';
|
|
ctx.fillText(room.name.charAt(0), x + cellSize/2, y + cellSize/2);
|
|
}
|
|
|
|
updateBaseInfoOverlay() {
|
|
const infoDisplay = document.getElementById('baseInfoDisplay');
|
|
if (!infoDisplay) return;
|
|
|
|
const totalRooms = this.base.rooms.length;
|
|
const powerUsage = this.base.power;
|
|
const maxPower = this.base.maxPower;
|
|
const storage = this.base.storage;
|
|
const maxStorage = this.base.maxStorage;
|
|
|
|
infoDisplay.innerHTML = `
|
|
<div class="base-info-item">
|
|
<strong>Base Name:</strong> ${this.base.name}
|
|
</div>
|
|
<div class="base-info-item">
|
|
<strong>Level:</strong> ${this.base.level}
|
|
</div>
|
|
<div class="base-info-item">
|
|
<strong>Total Rooms:</strong> ${totalRooms}
|
|
</div>
|
|
<div class="base-info-item">
|
|
<strong>Power Usage:</strong> ${powerUsage}/${maxPower}
|
|
</div>
|
|
<div class="base-info-item">
|
|
<strong>Storage:</strong> ${storage}/${maxStorage}
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
// Ship Gallery
|
|
initializeShipGallery() {
|
|
// Initialize purchased ships array
|
|
if (!this.purchasedShips) {
|
|
this.purchasedShips = [];
|
|
|
|
// Add current ship to gallery with proper timestamp ID
|
|
const player = this.game.systems.player;
|
|
if (player.ship) {
|
|
this.purchasedShips.push({
|
|
id: Date.now().toString(), // Use timestamp instead of hardcoded 'current_ship'
|
|
name: player.ship.name || 'Default Ship',
|
|
class: player.ship.class || 'fighter',
|
|
level: player.ship.level || 1,
|
|
stats: { ...player.attributes },
|
|
isCurrent: true
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
updateShipGallery() {
|
|
const shipGrid = document.getElementById('shipGrid');
|
|
if (!shipGrid) {
|
|
return;
|
|
}
|
|
|
|
if (!this.purchasedShips) {
|
|
this.initializeShipGallery();
|
|
}
|
|
|
|
if (!this.purchasedShips || this.purchasedShips.length === 0) {
|
|
shipGrid.innerHTML = '<p>No ships purchased yet. Visit the shop to buy ships!</p>';
|
|
return;
|
|
}
|
|
|
|
shipGrid.innerHTML = '';
|
|
|
|
this.purchasedShips.forEach(ship => {
|
|
const shipElement = document.createElement('div');
|
|
shipElement.className = `ship-card ${ship.isCurrent ? 'current-ship' : ''}`;
|
|
|
|
shipElement.innerHTML = `
|
|
<div class="ship-header">
|
|
<h4>${ship.name}</h4>
|
|
${ship.isCurrent ? '<span class="current-badge">Current</span>' : ''}
|
|
</div>
|
|
<div class="ship-info">
|
|
<div class="ship-class">Class: ${ship.class}</div>
|
|
<div class="ship-level">Level: ${ship.level}</div>
|
|
</div>
|
|
<div class="ship-stats">
|
|
<div class="stat">Attack: ${ship.stats.attack || 0}</div>
|
|
<div class="stat">Speed: ${ship.stats.speed || 0}</div>
|
|
<div class="stat">Defense: ${ship.stats.defense || 0}</div>
|
|
</div>
|
|
${!ship.isCurrent ? `
|
|
<button class="btn btn-primary equip-ship-btn" onclick="window.game.systems.baseSystem.equipShip('${ship.id}')">Equip Ship</button>
|
|
` : ''}
|
|
`;
|
|
|
|
shipGrid.appendChild(shipElement);
|
|
});
|
|
}
|
|
|
|
equipShip(shipId) {
|
|
const ship = this.purchasedShips.find(s => s.id === shipId);
|
|
if (!ship) {
|
|
this.game.showNotification('Ship not found!', 'error', 3000);
|
|
return;
|
|
}
|
|
|
|
if (ship.isCurrent) {
|
|
this.game.showNotification('This ship is already equipped!', 'info', 3000);
|
|
return;
|
|
}
|
|
|
|
const player = this.game.systems.player;
|
|
|
|
player.ship.name = ship.name;
|
|
player.ship.class = ship.class;
|
|
player.ship.level = ship.level;
|
|
player.ship.texture = ship.texture; // Copy texture for image display
|
|
|
|
// Apply ship-specific stats (not just attributes)
|
|
if (ship.stats.health || ship.stats.hull) {
|
|
const healthValue = ship.stats.health || ship.stats.hull || 100;
|
|
player.ship.maxHealth = healthValue;
|
|
player.ship.health = healthValue;
|
|
}
|
|
if (ship.stats.attack) {
|
|
player.ship.attack = ship.stats.attack;
|
|
}
|
|
if (ship.stats.defense) {
|
|
player.ship.defense = ship.stats.defense;
|
|
}
|
|
if (ship.stats.speed) {
|
|
player.ship.speed = ship.stats.speed;
|
|
}
|
|
if (ship.stats.criticalChance) {
|
|
player.ship.criticalChance = ship.stats.criticalChance;
|
|
}
|
|
if (ship.stats.criticalDamage) {
|
|
player.ship.criticalDamage = ship.stats.criticalDamage;
|
|
}
|
|
|
|
// Also update player attributes for compatibility
|
|
player.attributes.attack = ship.stats.attack || player.attributes.attack;
|
|
player.attributes.speed = ship.stats.speed || player.attributes.speed;
|
|
player.attributes.defense = ship.stats.defense || player.attributes.defense;
|
|
if (ship.stats.health || ship.stats.hull) {
|
|
const healthValue = ship.stats.health || ship.stats.hull || 100;
|
|
player.attributes.maxHealth = healthValue;
|
|
player.attributes.health = healthValue;
|
|
}
|
|
|
|
// Update isCurrent flags
|
|
this.purchasedShips.forEach(s => s.isCurrent = false);
|
|
ship.isCurrent = true;
|
|
|
|
// Force immediate gallery update after flag changes
|
|
const shipGrid = document.getElementById('shipGrid');
|
|
if (shipGrid) {
|
|
shipGrid.innerHTML = '';
|
|
this.updateShipGallery();
|
|
}
|
|
|
|
// Also update ShipSystem's currentShip to keep systems synchronized
|
|
if (this.game.systems.ship) {
|
|
// Find or create a ship object in ShipSystem format
|
|
const shipSystemShip = {
|
|
id: ship.id,
|
|
name: ship.name,
|
|
image: ship.texture || `assets/textures/ships/${ship.class.toLowerCase()}.png`,
|
|
class: ship.class,
|
|
level: ship.level,
|
|
stats: ship.stats,
|
|
status: 'active',
|
|
rarity: 'Common'
|
|
};
|
|
|
|
// Update ShipSystem's current ship
|
|
this.game.systems.ship.currentShip = shipSystemShip;
|
|
|
|
// Update the ships array in ShipSystem if needed
|
|
const existingShipIndex = this.game.systems.ship.ships.findIndex(s => s.id === ship.id);
|
|
if (existingShipIndex >= 0) {
|
|
this.game.systems.ship.ships[existingShipIndex].status = 'active';
|
|
this.game.systems.ship.ships[existingShipIndex] = shipSystemShip;
|
|
} else {
|
|
// Add to ships array if not present
|
|
this.game.systems.ship.ships.push(shipSystemShip);
|
|
}
|
|
|
|
// Mark all other ships as inactive
|
|
this.game.systems.ship.ships.forEach(s => {
|
|
if (s.id !== ship.id) s.status = 'inactive';
|
|
});
|
|
}
|
|
|
|
// Only update player UI if in multiplayer mode or game is actively running
|
|
if (this.game.shouldUpdateGUI()) {
|
|
player.updateUI();
|
|
}
|
|
|
|
this.updateShipGallery();
|
|
|
|
// Also update ShipSystem display
|
|
if (this.game.systems.ship && this.game.systems.ship.updateCurrentShipDisplay) {
|
|
this.game.systems.ship.updateCurrentShipDisplay();
|
|
} else {
|
|
this.updateCurrentShipDisplayDirect();
|
|
}
|
|
|
|
// Force save the game to persist the ship change
|
|
this.game.save().then(() => {
|
|
// Force complete gallery refresh after save completes
|
|
const shipGrid = document.getElementById('shipGrid');
|
|
if (shipGrid) {
|
|
shipGrid.innerHTML = ''; // Clear completely
|
|
this.updateShipGallery(); // Rebuild from scratch
|
|
}
|
|
|
|
// Force ShipSystem to sync with new current ship
|
|
if (this.game.systems.ship && this.game.systems.ship.syncWithPlayerShip) {
|
|
this.game.systems.ship.syncWithPlayerShip();
|
|
}
|
|
});
|
|
|
|
this.game.showNotification(`Equipped ${ship.name}!`, 'success', 3000);
|
|
}
|
|
|
|
updateCurrentShipDisplayDirect() {
|
|
const player = this.game.systems.player;
|
|
if (!player || !player.ship) {
|
|
return;
|
|
}
|
|
|
|
const elements = {
|
|
currentShipImage: document.getElementById('currentShipImage'),
|
|
currentShipName: document.getElementById('currentShipName'),
|
|
currentShipClass: document.getElementById('currentShipClass'),
|
|
currentShipLevel: document.getElementById('currentShipLevel'),
|
|
currentShipHealth: document.getElementById('currentShipHealth'),
|
|
currentShipAttack: document.getElementById('currentShipAttack'),
|
|
currentShipDefense: document.getElementById('currentShipDefense'),
|
|
currentShipSpeed: document.getElementById('currentShipSpeed')
|
|
};
|
|
|
|
const ship = player.ship;
|
|
|
|
if (elements.currentShipImage) {
|
|
const imagePath = ship.texture || `assets/textures/ships/${ship.class.toLowerCase()}.png`;
|
|
console.log(`[DEBUG] Ship image path: ${imagePath}, texture: ${ship.texture}, class: ${ship.class}`);
|
|
elements.currentShipImage.src = imagePath;
|
|
|
|
// Add error handling for image loading
|
|
elements.currentShipImage.onerror = function() {
|
|
console.error(`[DEBUG] Failed to load image: ${imagePath}`);
|
|
// Fallback to default ship image
|
|
this.src = 'assets/textures/ships/starter_cruiser.png';
|
|
};
|
|
}
|
|
|
|
if (elements.currentShipName) elements.currentShipName.textContent = ship.name || 'Unknown Ship';
|
|
if (elements.currentShipClass) elements.currentShipClass.textContent = ship.class || 'Unknown';
|
|
if (elements.currentShipLevel) elements.currentShipLevel.textContent = ship.level || 1;
|
|
if (elements.currentShipHealth) elements.currentShipHealth.textContent = `${ship.health}/${ship.maxHealth}`;
|
|
if (elements.currentShipAttack) elements.currentShipAttack.textContent = ship.attack || 0;
|
|
if (elements.currentShipDefense) elements.currentShipDefense.textContent = ship.defense || ship.defence || 0;
|
|
if (elements.currentShipSpeed) elements.currentShipSpeed.textContent = ship.speed || 0;
|
|
}
|
|
|
|
addShipToGallery(shipData) {
|
|
this.purchasedShips.push({
|
|
id: Date.now().toString(),
|
|
name: shipData.name,
|
|
class: shipData.type,
|
|
level: 1,
|
|
stats: { ...shipData.stats },
|
|
texture: shipData.texture, // Include texture for image display
|
|
isCurrent: false
|
|
});
|
|
|
|
this.updateShipGallery();
|
|
}
|
|
|
|
// Starbase System
|
|
initializeStarbaseSystem() {
|
|
// Initialize starbase collection
|
|
if (!this.starbases) {
|
|
this.starbases = [
|
|
{
|
|
id: 'main_base',
|
|
name: 'Command Center Alpha',
|
|
type: 'command',
|
|
level: 1,
|
|
location: 'Sector Alpha-1',
|
|
isMain: true
|
|
}
|
|
];
|
|
}
|
|
|
|
// Define available starbase types
|
|
this.starbaseTypes = {
|
|
mining: {
|
|
name: 'Mining Outpost',
|
|
description: 'Automated mining facility for resource extraction',
|
|
price: 25000,
|
|
currency: 'credits',
|
|
icon: 'fa-hammer',
|
|
benefits: ['+500 credits/hour', '+50 gems/day', '+5 inventory slots'],
|
|
requiredLevel: 5,
|
|
inventoryBonus: 5
|
|
},
|
|
research: {
|
|
name: 'Research Station',
|
|
description: 'Advanced research facility for technology development',
|
|
price: 50000,
|
|
currency: 'credits',
|
|
icon: 'fa-flask',
|
|
benefits: ['+100 experience/hour', '+10% skill progression', '+10 inventory slots'],
|
|
requiredLevel: 10,
|
|
inventoryBonus: 10
|
|
},
|
|
defense: {
|
|
name: 'Defense Platform',
|
|
description: 'Military installation for sector protection',
|
|
price: 40000,
|
|
currency: 'credits',
|
|
icon: 'fa-shield-alt',
|
|
benefits: ['+15% combat effectiveness', '+100 defense rating'],
|
|
requiredLevel: 8,
|
|
inventoryBonus: 8
|
|
},
|
|
trading: {
|
|
name: 'Trading Hub',
|
|
description: 'Commercial center for trade and commerce',
|
|
price: 75000,
|
|
currency: 'credits',
|
|
icon: 'fa-store',
|
|
benefits: ['+20% shop discounts', '+200 gems/day'],
|
|
requiredLevel: 12,
|
|
inventoryBonus: 15
|
|
}
|
|
};
|
|
}
|
|
|
|
updateStarbaseList() {
|
|
const starbaseList = document.getElementById('starbaseList');
|
|
if (!starbaseList) return;
|
|
|
|
starbaseList.innerHTML = '';
|
|
|
|
// Initialize starbases if not exists
|
|
if (!this.starbases) {
|
|
this.initializeStarbaseSystem();
|
|
}
|
|
|
|
if (!this.starbases || this.starbases.length === 0) {
|
|
starbaseList.innerHTML = '<p>No starbases owned yet.</p>';
|
|
return;
|
|
}
|
|
|
|
this.starbases.forEach(starbase => {
|
|
const starbaseElement = document.createElement('div');
|
|
starbaseElement.className = `starbase-card ${starbase.isMain ? 'main-starbase' : ''}`;
|
|
|
|
starbaseElement.innerHTML = `
|
|
<div class="starbase-header">
|
|
<h4>${starbase.name}</h4>
|
|
${starbase.isMain ? '<span class="main-badge">Main Base</span>' : ''}
|
|
</div>
|
|
<div class="starbase-info">
|
|
<div class="starbase-type">Type: ${starbase.type}</div>
|
|
<div class="starbase-level">Level: ${starbase.level}</div>
|
|
<div class="starbase-location">Location: ${starbase.location}</div>
|
|
</div>
|
|
<div class="starbase-actions">
|
|
<button class="btn btn-secondary" onclick="if(window.game && window.game.systems) window.game.systems.baseSystem.viewStarbaseDetails('${starbase.id}')">
|
|
View Details
|
|
</button>
|
|
${!starbase.isMain ? `
|
|
<button class="btn btn-danger" onclick="if(window.game && window.game.systems) window.game.systems.baseSystem.decommissionStarbase('${starbase.id}')">
|
|
Decommission
|
|
</button>
|
|
` : ''}
|
|
</div>
|
|
`;
|
|
|
|
starbaseList.appendChild(starbaseElement);
|
|
});
|
|
}
|
|
|
|
updateStarbasePurchaseList() {
|
|
const purchaseList = document.getElementById('starbasePurchaseItems');
|
|
if (!purchaseList) return;
|
|
|
|
purchaseList.innerHTML = '';
|
|
|
|
const player = this.game.systems.player;
|
|
|
|
Object.entries(this.starbaseTypes).forEach(([type, starbase]) => {
|
|
const starbaseElement = document.createElement('div');
|
|
starbaseElement.className = 'starbase-purchase-card';
|
|
|
|
const canAfford = this.game.systems.economy.credits >= starbase.price;
|
|
const meetsLevel = player.stats.level >= starbase.requiredLevel;
|
|
const canPurchase = canAfford && meetsLevel;
|
|
|
|
starbaseElement.innerHTML = `
|
|
<div class="starbase-purchase-header">
|
|
<h4>${starbase.name}</h4>
|
|
<div class="starbase-icon">
|
|
<i class="fas ${starbase.icon}"></i>
|
|
</div>
|
|
</div>
|
|
<div class="starbase-purchase-description">
|
|
${starbase.description}
|
|
</div>
|
|
<div class="starbase-purchase-benefits">
|
|
<h5>Benefits:</h5>
|
|
<ul>
|
|
${starbase.benefits.map(benefit => `<li>${benefit}</li>`).join('')}
|
|
</ul>
|
|
</div>
|
|
<div class="starbase-purchase-requirements">
|
|
<div class="requirement">
|
|
<strong>Cost:</strong> ${starbase.price} ${starbase.currency}
|
|
</div>
|
|
<div class="requirement">
|
|
<strong>Required Level:</strong> ${starbase.requiredLevel}
|
|
</div>
|
|
</div>
|
|
<div class="starbase-purchase-actions">
|
|
<button class="btn btn-primary ${!canPurchase ? 'disabled' : ''}"
|
|
onclick="if(window.game && window.game.systems) window.game.systems.baseSystem.purchaseStarbase('${type}')"
|
|
${!canPurchase ? 'disabled' : ''}>
|
|
${!meetsLevel ? 'Level Required' : !canAfford ? 'Insufficient Funds' : 'Purchase Starbase'}
|
|
</button>
|
|
</div>
|
|
`;
|
|
|
|
purchaseList.appendChild(starbaseElement);
|
|
});
|
|
}
|
|
|
|
purchaseStarbase(type) {
|
|
const starbaseTemplate = this.starbaseTypes[type];
|
|
if (!starbaseTemplate) {
|
|
this.game.showNotification('Invalid starbase type!', 'error', 3000);
|
|
return;
|
|
}
|
|
|
|
const player = this.game.systems.player;
|
|
const economy = this.game.systems.economy;
|
|
|
|
// Check requirements
|
|
if (player.stats.level < starbaseTemplate.requiredLevel) {
|
|
this.game.showNotification(`Level ${starbaseTemplate.requiredLevel} required!`, 'error', 3000);
|
|
return;
|
|
}
|
|
|
|
if (economy.credits < starbaseTemplate.price) {
|
|
this.game.showNotification('Insufficient credits!', 'error', 3000);
|
|
return;
|
|
}
|
|
|
|
// Process payment
|
|
economy.credits -= starbaseTemplate.price;
|
|
|
|
// Create new starbase
|
|
const newStarbase = {
|
|
id: Date.now().toString(),
|
|
name: `${starbaseTemplate.name} ${this.starbases.length}`,
|
|
type: type,
|
|
level: 1,
|
|
location: `Sector ${String.fromCharCode(65 + this.starbases.length)}-${this.starbases.length}`,
|
|
isMain: false,
|
|
benefits: starbaseTemplate.benefits
|
|
};
|
|
|
|
this.starbases.push(newStarbase);
|
|
|
|
// Apply benefits
|
|
this.applyStarbaseBenefits(newStarbase);
|
|
|
|
// Only update UI if in multiplayer mode or game is actively running
|
|
if (this.game.shouldUpdateGUI()) {
|
|
economy.updateUI();
|
|
this.updateStarbaseList();
|
|
this.updateStarbasePurchaseList();
|
|
}
|
|
|
|
this.game.showNotification(`Purchased ${starbaseTemplate.name}!`, 'success', 4000);
|
|
}
|
|
|
|
applyStarbaseBenefits(starbase) {
|
|
// Apply passive benefits based on starbase type
|
|
switch (starbase.type) {
|
|
case 'mining':
|
|
// Start passive credit generation
|
|
this.startMiningProduction(starbase);
|
|
// Apply inventory bonus
|
|
this.updateInventoryBonusSlots();
|
|
break;
|
|
case 'research':
|
|
// Apply experience bonus
|
|
this.game.systems.player.experienceMultiplier = (this.game.systems.player.experienceMultiplier || 1) + 0.1;
|
|
// Apply inventory bonus
|
|
this.updateInventoryBonusSlots();
|
|
break;
|
|
case 'defense':
|
|
// Apply defense bonus
|
|
this.game.systems.player.attributes.defense = Math.floor(this.game.systems.player.attributes.defense * 1.2);
|
|
// Apply inventory bonus
|
|
this.updateInventoryBonusSlots();
|
|
break;
|
|
case 'trading':
|
|
// Apply shop discount
|
|
this.game.systems.economy.discountMultiplier = 0.85;
|
|
// Apply inventory bonus
|
|
this.updateInventoryBonusSlots();
|
|
break;
|
|
}
|
|
}
|
|
|
|
updateInventoryBonusSlots() {
|
|
// Calculate total inventory bonus from all owned starbases
|
|
let totalBonusSlots = 0;
|
|
|
|
if (this.starbases && this.starbases.length > 0) {
|
|
this.starbases.forEach(starbase => {
|
|
const starbaseType = this.starbaseTypes[starbase.type];
|
|
if (starbaseType && starbaseType.inventoryBonus) {
|
|
totalBonusSlots += starbaseType.inventoryBonus;
|
|
}
|
|
});
|
|
}
|
|
|
|
// Update inventory system with new bonus slots
|
|
if (this.game.systems.inventory) {
|
|
this.game.systems.inventory.updateStarbaseBonusSlots(totalBonusSlots);
|
|
}
|
|
}
|
|
|
|
startMiningProduction(starbase) {
|
|
// Only start mining if in multiplayer mode or game is actively running
|
|
const shouldStartMining = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
|
|
|
|
if (shouldStartMining && !this.miningInterval) {
|
|
// Set up passive credit generation
|
|
this.miningInterval = setInterval(() => {
|
|
this.game.systems.economy.addCredits(500, 'mining_outpost');
|
|
}, 3600000); // 1 hour
|
|
|
|
console.log('[BASE SYSTEM] Mining production started');
|
|
} else if (!shouldStartMining) {
|
|
console.log('[BASE SYSTEM] Skipping mining production - not in multiplayer mode');
|
|
}
|
|
}
|
|
|
|
viewStarbaseDetails(starbaseId) {
|
|
const starbase = this.starbases.find(s => s.id === starbaseId);
|
|
if (!starbase) return;
|
|
|
|
const details = `
|
|
<h3>${starbase.name}</h3>
|
|
<p><strong>Type:</strong> ${starbase.type}</p>
|
|
<p><strong>Level:</strong> ${starbase.level}</p>
|
|
<p><strong>Location:</strong> ${starbase.location}</p>
|
|
${starbase.benefits ? `
|
|
<h4>Active Benefits:</h4>
|
|
<ul>
|
|
${starbase.benefits.map(benefit => `<li>${benefit}</li>`).join('')}
|
|
</ul>
|
|
` : ''}
|
|
`;
|
|
|
|
if (this.game && this.game.systems && this.game.systems.ui) {
|
|
this.game.systems.ui.showModal('Starbase Details', details);
|
|
}
|
|
}
|
|
|
|
decommissionStarbase(starbaseId) {
|
|
if (!confirm('Are you sure you want to decommission this starbase? You will receive 50% of its value back.')) {
|
|
return;
|
|
}
|
|
|
|
const starbaseIndex = this.starbases.findIndex(s => s.id === starbaseId);
|
|
if (starbaseIndex === -1) return;
|
|
|
|
const starbase = this.starbases[starbaseIndex];
|
|
const refundAmount = Math.floor(this.starbaseTypes[starbase.type].price * 0.5);
|
|
|
|
// Remove starbase
|
|
this.starbases.splice(starbaseIndex, 1);
|
|
|
|
// Give refund
|
|
this.game.systems.economy.addCredits(refundAmount, 'starbase_refund');
|
|
|
|
// Update inventory bonus slots after removal
|
|
this.updateInventoryBonusSlots();
|
|
|
|
// Update UI
|
|
this.updateStarbaseList();
|
|
this.updateStarbasePurchaseList();
|
|
|
|
this.game.showNotification(`Decommissioned ${starbase.name}. Refunded ${refundAmount} credits.`, 'info', 4000);
|
|
}
|
|
|
|
updateBaseDisplay() {
|
|
const baseRoomsElement = document.getElementById('baseRooms');
|
|
if (!baseRoomsElement) return;
|
|
|
|
// Ensure grid is initialized
|
|
if (!this.grid || this.grid.length === 0) {
|
|
console.log('[BASE SYSTEM] Grid not initialized, initializing now');
|
|
this.initializeGrid();
|
|
}
|
|
|
|
baseRoomsElement.innerHTML = '';
|
|
|
|
// Create grid container
|
|
const gridContainer = document.createElement('div');
|
|
gridContainer.className = 'base-grid';
|
|
|
|
// Create grid cells
|
|
for (let y = 0; y < this.gridSize; y++) {
|
|
for (let x = 0; x < this.gridSize; x++) {
|
|
const cell = document.createElement('div');
|
|
cell.className = 'base-cell';
|
|
cell.dataset.x = x;
|
|
cell.dataset.y = y;
|
|
|
|
const room = this.getRoomAt(x, y);
|
|
if (room) {
|
|
// Check if this is the main cell of the room
|
|
if (room.x === x && room.y === y) {
|
|
cell.className += ` room ${room.type}`;
|
|
cell.innerHTML = `
|
|
<div class="room-icon">
|
|
<i class="fas ${this.roomTypes[room.type].icon}"></i>
|
|
</div>
|
|
<div class="room-level">L${room.level}</div>
|
|
`;
|
|
cell.title = `${room.name} (Level ${room.level})`;
|
|
} else {
|
|
// Other cells of the same room are just filled
|
|
cell.innerHTML = '';
|
|
}
|
|
cell.title = `${room.name} (Level ${room.level})`;
|
|
} else {
|
|
cell.className += ' empty';
|
|
cell.addEventListener('click', () => this.showRoomBuildMenu(x, y));
|
|
}
|
|
|
|
gridContainer.appendChild(cell);
|
|
}
|
|
}
|
|
|
|
baseRoomsElement.appendChild(gridContainer);
|
|
|
|
// Add base info with connected inventory storage
|
|
const baseInfo = document.createElement('div');
|
|
baseInfo.className = 'base-info';
|
|
|
|
// Get inventory information
|
|
const inventoryInfo = this.game.systems.inventory ? this.game.systems.inventory.getInventoryInfo() : null;
|
|
|
|
baseInfo.innerHTML = `
|
|
<h3>${this.base.name}</h3>
|
|
<div class="base-stats">
|
|
<div>Level: ${this.base.level}</div>
|
|
<div>Power: ${this.base.power}/${this.base.maxPower}</div>
|
|
<div>Storage: ${inventoryInfo ? `${inventoryInfo.currentSlots}/${inventoryInfo.totalMaxSlots}` : `${this.base.storage}/${this.base.maxStorage}`} slots</div>
|
|
${inventoryInfo ? `<div class="storage-breakdown">
|
|
<small>Base: ${inventoryInfo.baseMaxSlots} | Starbase Bonus: +${inventoryInfo.starbaseBonusSlots}</small>
|
|
</div>` : ''}
|
|
</div>
|
|
`;
|
|
|
|
baseRoomsElement.appendChild(baseInfo);
|
|
}
|
|
|
|
updateUpgradesList() {
|
|
const upgradesElement = document.getElementById('baseUpgrades');
|
|
if (!upgradesElement) return;
|
|
|
|
upgradesElement.innerHTML = '';
|
|
|
|
Object.entries(this.upgrades).forEach(([upgradeId, upgrade]) => {
|
|
const upgradeElement = document.createElement('div');
|
|
upgradeElement.className = 'upgrade-item';
|
|
|
|
const cost = upgrade.cost * (upgrade.currentLevel + 1);
|
|
const canAfford = this.game.systems.economy.credits >= cost;
|
|
const isMaxLevel = upgrade.currentLevel >= upgrade.maxLevel;
|
|
|
|
upgradeElement.innerHTML = `
|
|
<div class="upgrade-name">${upgrade.name}</div>
|
|
<div class="upgrade-description">${upgrade.description}</div>
|
|
<div class="upgrade-level">Level: ${upgrade.currentLevel}/${upgrade.maxLevel}</div>
|
|
<div class="upgrade-cost">Cost: ${cost} credits</div>
|
|
<button class="btn btn-primary ${!canAfford || isMaxLevel ? 'disabled' : ''}"
|
|
onclick="if(window.game && window.game.systems) window.game.systems.baseSystem.upgradeBase('${upgradeId}')"
|
|
${!canAfford || isMaxLevel ? 'disabled' : ''}>
|
|
${isMaxLevel ? 'MAX' : 'Upgrade'}
|
|
</button>
|
|
`;
|
|
|
|
upgradesElement.appendChild(upgradeElement);
|
|
});
|
|
}
|
|
|
|
showRoomBuildMenu(x, y) {
|
|
const availableRooms = Object.entries(this.roomTypes)
|
|
.filter(([roomType, template]) =>
|
|
template.requiredLevel <= this.game.systems.player.stats.level
|
|
)
|
|
.filter(([roomType, template]) => this.canBuildRoom(roomType, x, y));
|
|
|
|
if (availableRooms.length === 0) {
|
|
this.game.showNotification('No rooms available for this location', 'warning', 3000);
|
|
return;
|
|
}
|
|
|
|
let menuContent = '<h3>Build Room</h3><div class="room-options">';
|
|
|
|
availableRooms.forEach(([roomType, template]) => {
|
|
const roomSize = this.getRoomSize(template.size);
|
|
menuContent += `
|
|
<div class="room-option" onclick="if(window.game && window.game.systems) window.game.systems.baseSystem.addRoom('${roomType}', ${x}, ${y})">
|
|
<div class="room-option-header">
|
|
<i class="fas ${template.icon}"></i>
|
|
<span>${template.name}</span>
|
|
</div>
|
|
<div class="room-option-info">
|
|
<div>Size: ${roomSize.width}x${roomSize.height}</div>
|
|
<div>Power: ${template.powerCost > 0 ? '+' : ''}${template.powerCost}</div>
|
|
<div>Cost: ${template.buildCost} credits</div>
|
|
</div>
|
|
<div class="room-option-description">${template.description}</div>
|
|
</div>
|
|
`;
|
|
});
|
|
|
|
menuContent += '</div>';
|
|
}
|
|
|
|
updateUpgradesList() {
|
|
const upgradesElement = document.getElementById('baseUpgrades');
|
|
if (!upgradesElement) return;
|
|
|
|
upgradesElement.innerHTML = '';
|
|
|
|
Object.entries(this.upgrades).forEach(([upgradeId, upgrade]) => {
|
|
const upgradeElement = document.createElement('div');
|
|
upgradeElement.className = 'upgrade-item';
|
|
|
|
const cost = upgrade.cost * (upgrade.currentLevel + 1);
|
|
const canAfford = this.game.systems.economy.credits >= cost;
|
|
const isMaxLevel = upgrade.currentLevel >= upgrade.maxLevel;
|
|
|
|
upgradeElement.innerHTML = `
|
|
<div class="upgrade-name">${upgrade.name}</div>
|
|
<div class="upgrade-description">${upgrade.description}</div>
|
|
<div class="upgrade-level">Level: ${upgrade.currentLevel}/${upgrade.maxLevel}</div>
|
|
<div class="upgrade-cost">Cost: ${cost} credits</div>
|
|
<button class="btn btn-primary ${!canAfford || isMaxLevel ? 'disabled' : ''}"
|
|
onclick="if(window.game && window.game.systems) window.game.systems.baseSystem.upgradeBase('${upgradeId}')"
|
|
${!canAfford || isMaxLevel ? 'disabled' : ''}>
|
|
${isMaxLevel ? 'MAX' : 'Upgrade'}
|
|
</button>
|
|
`;
|
|
|
|
upgradesElement.appendChild(upgradeElement);
|
|
});
|
|
}
|
|
|
|
showRoomBuildMenu(x, y) {
|
|
const availableRooms = Object.entries(this.roomTypes)
|
|
.filter(([roomType, template]) =>
|
|
template.requiredLevel <= this.game.systems.player.stats.level
|
|
)
|
|
.filter(([roomType, template]) => this.canBuildRoom(roomType, x, y));
|
|
|
|
if (availableRooms.length === 0) {
|
|
this.game.showNotification('No rooms available for this location', 'warning', 3000);
|
|
return;
|
|
}
|
|
|
|
let menuContent = '<h3>Build Room</h3><div class="room-options">';
|
|
|
|
availableRooms.forEach(([roomType, template]) => {
|
|
const roomSize = this.getRoomSize(template.size);
|
|
menuContent += `
|
|
<div class="room-option" onclick="if(window.game && window.game.systems) window.game.systems.baseSystem.addRoom('${roomType}', ${x}, ${y})">
|
|
<div class="room-option-header">
|
|
<i class="fas ${template.icon}"></i>
|
|
<span>${template.name}</span>
|
|
</div>
|
|
<div class="room-option-info">
|
|
<div>Size: ${roomSize.width}x${roomSize.height}</div>
|
|
<div>Power: ${template.powerCost > 0 ? '+' : ''}${template.powerCost}</div>
|
|
<div>Cost: ${template.buildCost} credits</div>
|
|
</div>
|
|
<div class="room-option-description">${template.description}</div>
|
|
</div>
|
|
`;
|
|
});
|
|
|
|
menuContent += '</div>';
|
|
|
|
if (this.game && this.game.systems && this.game.systems.ui) {
|
|
this.game.systems.ui.showModal('Build Room', menuContent);
|
|
}
|
|
}
|
|
|
|
// Save/Load
|
|
save() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
// if (debugLogger) debugLogger.startStep('BaseSystem.save', {
|
|
// baseName: this.base.name,
|
|
// baseLevel: this.base.level,
|
|
// roomsCount: this.base.rooms.length,
|
|
// gridCellsCount: this.grid.flat().filter(cell => cell !== null).length,
|
|
// upgradesCount: Object.keys(this.upgrades).length
|
|
// });
|
|
|
|
const saveData = {
|
|
base: this.base,
|
|
grid: this.grid,
|
|
upgrades: this.upgrades,
|
|
purchasedShips: this.purchasedShips || []
|
|
};
|
|
|
|
// if (debugLogger) debugLogger.endStep('BaseSystem.save', {
|
|
// saveDataSize: JSON.stringify(saveData).length,
|
|
// baseSaved: {
|
|
// name: saveData.base.name,
|
|
// level: saveData.base.level,
|
|
// roomsCount: saveData.base.rooms.length
|
|
// },
|
|
// gridSaved: {
|
|
// gridSize: this.gridSize,
|
|
// occupiedCells: this.grid.flat().filter(cell => cell !== null).length
|
|
// },
|
|
// upgradesSaved: Object.keys(saveData.upgrades).map(id => ({
|
|
// id: id,
|
|
// currentLevel: saveData.upgrades[id].currentLevel
|
|
// })),
|
|
// saveData: saveData
|
|
// });
|
|
|
|
return saveData;
|
|
}
|
|
|
|
load(data) {
|
|
const debugLogger = window.debugLogger;
|
|
const oldState = {
|
|
baseName: this.base.name,
|
|
baseLevel: this.base.level,
|
|
roomsCount: this.base.rooms.length,
|
|
upgradesState: Object.keys(this.upgrades).map(id => ({
|
|
id: id,
|
|
currentLevel: this.upgrades[id].currentLevel
|
|
}))
|
|
};
|
|
|
|
if (debugLogger) debugLogger.startStep('BaseSystem.load', {
|
|
oldState: oldState,
|
|
loadData: data
|
|
});
|
|
|
|
try {
|
|
if (data.base) {
|
|
const oldBase = { ...this.base };
|
|
this.base = { ...this.base, ...data.base };
|
|
|
|
if (debugLogger) debugLogger.logStep('Base data loaded', {
|
|
oldBase: {
|
|
name: oldBase.name,
|
|
level: oldBase.level,
|
|
roomsCount: oldBase.rooms.length
|
|
},
|
|
newBase: {
|
|
name: this.base.name,
|
|
level: this.base.level,
|
|
roomsCount: this.base.rooms.length
|
|
}
|
|
});
|
|
}
|
|
|
|
if (data.grid) {
|
|
const oldGrid = this.grid;
|
|
this.grid = data.grid;
|
|
|
|
if (debugLogger) debugLogger.logStep('Grid data loaded', {
|
|
oldGridCells: oldGrid.flat().filter(cell => cell !== null).length,
|
|
newGridCells: this.grid.flat().filter(cell => cell !== null).length,
|
|
gridSize: this.gridSize
|
|
});
|
|
}
|
|
|
|
if (data.upgrades) {
|
|
const oldUpgrades = Object.keys(this.upgrades).map(id => ({
|
|
id: id,
|
|
currentLevel: this.upgrades[id].currentLevel
|
|
}));
|
|
|
|
Object.entries(data.upgrades).forEach(([upgradeId, upgrade]) => {
|
|
if (this.upgrades[upgradeId]) {
|
|
Object.assign(this.upgrades[upgradeId], upgrade);
|
|
|
|
if (debugLogger) debugLogger.logStep('Upgrade loaded', {
|
|
upgradeId: upgradeId,
|
|
oldLevel: oldUpgrades.find(u => u.id === upgradeId)?.currentLevel || 0,
|
|
newLevel: this.upgrades[upgradeId].currentLevel
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Load purchased ships
|
|
if (data.purchasedShips) {
|
|
this.purchasedShips = data.purchasedShips;
|
|
if (debugLogger) debugLogger.logStep('Purchased ships loaded', {
|
|
shipsCount: this.purchasedShips.length,
|
|
shipNames: this.purchasedShips.map(s => s.name)
|
|
});
|
|
|
|
// Find the current ship from gallery and sync with player
|
|
const currentGalleryShip = this.purchasedShips.find(s => s.isCurrent);
|
|
if (currentGalleryShip) {
|
|
const player = this.game.systems.player;
|
|
if (player && player.ship) {
|
|
console.log('[DEBUG] Syncing player ship with gallery current ship:', currentGalleryShip);
|
|
|
|
// Update player's ship with gallery current ship data
|
|
player.ship.name = currentGalleryShip.name;
|
|
player.ship.class = currentGalleryShip.class;
|
|
player.ship.level = currentGalleryShip.level;
|
|
player.ship.texture = currentGalleryShip.texture;
|
|
|
|
// Update player attributes with ship stats
|
|
if (currentGalleryShip.stats) {
|
|
Object.assign(player.attributes, currentGalleryShip.stats);
|
|
|
|
// Update player.ship properties for consistency
|
|
player.ship.health = currentGalleryShip.stats.health || currentGalleryShip.stats.hull || 100;
|
|
player.ship.maxHealth = currentGalleryShip.stats.maxHealth || currentGalleryShip.stats.hull || 100;
|
|
player.ship.attack = currentGalleryShip.stats.attack || 10;
|
|
player.ship.defence = currentGalleryShip.stats.defense || currentGalleryShip.stats.defence || 5;
|
|
player.ship.speed = currentGalleryShip.stats.speed || 10;
|
|
}
|
|
|
|
console.log('[DEBUG] Player ship updated:', player.ship);
|
|
console.log('[DEBUG] Player attributes updated:', player.attributes);
|
|
|
|
// Only update UI displays if in multiplayer mode or game is actively running
|
|
if (this.game.shouldUpdateGUI()) {
|
|
player.updateUI();
|
|
if (this.game.systems.ship && this.game.systems.ship.updateCurrentShipDisplay) {
|
|
this.game.systems.ship.updateCurrentShipDisplay();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update base stats after loading
|
|
if (debugLogger) debugLogger.logStep('Updating base stats after load');
|
|
this.updateBaseStats();
|
|
|
|
// Update ship gallery after loading ships
|
|
if (data.purchasedShips) {
|
|
this.updateShipGallery();
|
|
}
|
|
|
|
if (debugLogger) debugLogger.endStep('BaseSystem.load', {
|
|
success: true,
|
|
oldState: oldState,
|
|
newState: {
|
|
baseName: this.base.name,
|
|
baseLevel: this.base.level,
|
|
roomsCount: this.base.rooms.length,
|
|
upgradesState: Object.keys(this.upgrades).map(id => ({
|
|
id: id,
|
|
currentLevel: this.upgrades[id].currentLevel
|
|
}))
|
|
},
|
|
baseStatsUpdated: true
|
|
});
|
|
} catch (error) {
|
|
if (debugLogger) debugLogger.errorEvent('BaseSystem.load', error, {
|
|
oldState: oldState,
|
|
loadData: data,
|
|
error: error.message
|
|
});
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
reset() {
|
|
this.baseLevel = 1;
|
|
this.rooms = {};
|
|
// Reset upgrades to initial state
|
|
this.upgrades = {
|
|
power_efficiency: {
|
|
name: 'Power Efficiency',
|
|
description: 'Reduces power consumption of all rooms',
|
|
cost: 1000,
|
|
effect: { powerReduction: 0.1 },
|
|
maxLevel: 5,
|
|
currentLevel: 0
|
|
},
|
|
storage_expansion: {
|
|
name: 'Storage Expansion',
|
|
description: 'Increases inventory slots for item storage',
|
|
cost: 5000,
|
|
maxLevel: 10,
|
|
currentLevel: 0,
|
|
icon: 'fa-boxes',
|
|
slotBonus: 5
|
|
},
|
|
automation_systems: {
|
|
name: 'Automation Systems',
|
|
description: 'Automated resource generation and processing',
|
|
cost: 2500,
|
|
maxLevel: 10,
|
|
currentLevel: 0,
|
|
icon: 'fa-robot'
|
|
}
|
|
};
|
|
this.resources = {
|
|
energy: 100,
|
|
materials: 50,
|
|
research: 0
|
|
};
|
|
this.initializeBaseData();
|
|
}
|
|
|
|
updateBaseStats() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('BaseSystem.updateBaseStats');
|
|
|
|
// Calculate total power and storage from rooms
|
|
let totalPower = 0;
|
|
let totalStorage = 0;
|
|
|
|
this.base.rooms.forEach(room => {
|
|
const roomTemplate = this.roomTypes[room.type];
|
|
if (roomTemplate) {
|
|
totalPower += roomTemplate.powerGeneration || 0;
|
|
totalStorage += roomTemplate.storageBonus || 0;
|
|
}
|
|
});
|
|
|
|
// Update base stats
|
|
this.base.power = Math.max(0, totalPower);
|
|
this.base.maxStorage = 1000 + totalStorage;
|
|
|
|
// Update UI if available
|
|
if (this.game.systems.ui && this.game.systems.ui.updateBaseSystem) {
|
|
this.game.systems.ui.updateBaseSystem();
|
|
}
|
|
|
|
// if (debugLogger) debugLogger.endStep('BaseSystem.updateBaseStats', {
|
|
// totalPower: this.base.power,
|
|
// maxStorage: this.base.maxStorage,
|
|
// roomsCount: this.base.rooms.length
|
|
// });
|
|
}
|
|
}
|