/** * Galaxy Strike Online - Skill System * Manages skills, progression, and specialization */ class SkillSystem { constructor(gameEngine) { this.game = gameEngine; // Skill categories this.categories = { combat: 'Combat', science: 'Science', crafting: 'Crafting' }; // Skill definitions this.skills = { combat: { weapons_mastery: { name: 'Weapons Mastery', description: 'Increases weapon damage and critical chance', maxLevel: 10, currentLevel: 0, experience: 0, experienceToNext: 100, effects: { attack: 2, criticalChance: 0.01 }, icon: 'fa-sword', unlocked: true }, shield_techniques: { name: 'Shield Techniques', description: 'Improves defense and energy efficiency', maxLevel: 10, currentLevel: 0, experience: 0, experienceToNext: 100, effects: { defense: 2, maxEnergy: 5 }, icon: 'fa-shield-alt', unlocked: true }, piloting: { name: 'Piloting', description: 'Enhances speed and evasion', maxLevel: 10, currentLevel: 0, experience: 0, experienceToNext: 100, effects: { speed: 2, criticalChance: 0.005 }, icon: 'fa-rocket', unlocked: true }, tactical_analysis: { name: 'Tactical Analysis', description: 'Reveals enemy weaknesses and improves accuracy', maxLevel: 10, currentLevel: 0, experience: 0, experienceToNext: 100, effects: { criticalDamage: 0.05, attack: 1 }, icon: 'fa-brain', unlocked: false, requiredLevel: 5 } }, science: { engineering: { name: 'Engineering', description: 'Technical skills for ship components and machinery', maxLevel: 10, currentLevel: 0, experience: 0, experienceToNext: 100, effects: { craftingBonus: 0.08, shipStats: 0.03 }, icon: 'fa-wrench', unlocked: true }, energy_manipulation: { name: 'Energy Manipulation', description: 'Better energy control and regeneration', maxLevel: 10, currentLevel: 0, experience: 0, experienceToNext: 100, effects: { maxEnergy: 10, energyRegeneration: 0.1 }, icon: 'fa-bolt', unlocked: true }, alien_technology: { name: 'Alien Technology', description: 'Understanding and using alien artifacts', maxLevel: 10, currentLevel: 0, experience: 0, experienceToNext: 100, effects: { findRarity: 0.05, itemValue: 0.1 }, icon: 'fa-atom', unlocked: false, requiredLevel: 3 }, quantum_physics: { name: 'Quantum Physics', description: 'Advanced quantum mechanics for better equipment', maxLevel: 10, currentLevel: 0, experience: 0, experienceToNext: 100, effects: { criticalDamage: 0.1, attack: 3 }, icon: 'fa-microscope', unlocked: false, requiredLevel: 8 }, bio_engineering: { name: 'Bio-Engineering', description: 'Biological enhancements and healing', maxLevel: 10, currentLevel: 0, experience: 0, experienceToNext: 100, effects: { maxHealth: 15, healthRegeneration: 0.05 }, icon: 'fa-dna', unlocked: false, requiredLevel: 6 } }, crafting: { crafting: { name: 'General Crafting', description: 'Basic crafting skills for all items', maxLevel: 10, currentLevel: 0, experience: 0, experienceToNext: 100, effects: { craftingBonus: 0.05 }, icon: 'fa-hammer', unlocked: true }, weapon_crafting: { name: 'Weapon Crafting', description: 'Create and upgrade weapons', maxLevel: 10, currentLevel: 0, experience: 0, experienceToNext: 100, effects: { craftingBonus: 0.1, weaponStats: 0.05 }, icon: 'fa-hammer', unlocked: true }, armor_forging: { name: 'Armor Forging', description: 'Forge protective armor and shields', maxLevel: 10, currentLevel: 0, experience: 0, experienceToNext: 100, effects: { craftingBonus: 0.1, armorStats: 0.05 }, icon: 'fa-anvil', unlocked: true }, resource_extraction: { name: 'Resource Extraction', description: 'Better resource gathering and efficiency', maxLevel: 10, currentLevel: 0, experience: 0, experienceToNext: 100, effects: { resourceBonus: 0.15, findResources: 0.1 }, icon: 'fa-gem', unlocked: false, requiredLevel: 4 }, engineering: { name: 'Engineering', description: 'Advanced ship modifications and systems', maxLevel: 10, currentLevel: 0, experience: 0, experienceToNext: 100, effects: { shipUpgrades: 0.2, systemEfficiency: 0.1 }, icon: 'fa-cogs', unlocked: false, requiredLevel: 7 } } }; // Skill experience rates this.experienceRates = { combat: 1.0, science: 0.8, crafting: 0.6 }; // Active buffs from skills this.activeBuffs = {}; } async initialize() { } // Skill management addSkillExperience(category, skillId, amount) { const skill = this.skills[category]?.[skillId]; if (!skill || skill.currentLevel >= skill.maxLevel) { return false; } skill.experience += amount; // Check for level up while (skill.experience >= skill.experienceToNext && skill.currentLevel < skill.maxLevel) { this.levelUpSkill(category, skillId); } this.applySkillEffects(); return true; } levelUpSkill(category, skillId) { const skill = this.skills[category][skillId]; // Handle excess experience const excessExperience = skill.experience - skill.experienceToNext; skill.currentLevel++; skill.experienceToNext = Math.floor(skill.experienceToNext * 1.5); // Set experience to excess (minimum 0) skill.experience = Math.max(0, excessExperience); // Apply skill effects this.applySkillEffects(); this.game.showNotification(`${skill.name} leveled up to ${skill.currentLevel}!`, 'success', 4000); this.game.showNotification('Skill effects applied!', 'info', 3000); } upgradeSkill(category, skillId) { const skill = this.skills[category]?.[skillId]; const player = this.game.systems.player; if (!skill) { this.game.showNotification('Skill not found', 'error', 3000); return false; } if (!skill.unlocked) { this.game.showNotification('Skill is locked', 'error', 3000); return false; } if (skill.currentLevel >= skill.maxLevel) { this.game.showNotification('Skill is at maximum level', 'warning', 3000); return false; } if (player.stats.skillPoints < 1) { this.game.showNotification('Not enough skill points', 'error', 3000); return false; } // Use skill point and level up player.stats.skillPoints--; this.levelUpSkill(category, skillId); // Update UI to refresh skill points display only if in multiplayer mode or game is actively running const shouldUpdateUI = window.smartSaveManager?.isMultiplayer || this.game?.isRunning; if (shouldUpdateUI) { this.updateUI(); } return true; } unlockSkill(category, skillId) { const skill = this.skills[category]?.[skillId]; const player = this.game.systems.player; if (!skill) { this.game.showNotification('Skill not found', 'error', 3000); return false; } if (skill.unlocked) { this.game.showNotification('Skill is already unlocked', 'warning', 3000); return false; } if (skill.requiredLevel && player.stats.level < skill.requiredLevel) { this.game.showNotification(`Requires level ${skill.requiredLevel}`, 'error', 3000); return false; } if (player.stats.skillPoints < 2) { this.game.showNotification('Requires 2 skill points to unlock', 'error', 3000); return false; } // Unlock skill player.stats.skillPoints -= 2; skill.unlocked = true; skill.currentLevel = 1; this.applySkillEffects(); // Update UI to refresh skill points display only if in multiplayer mode or game is actively running const shouldUpdateUI = window.smartSaveManager?.isMultiplayer || this.game?.isRunning; if (shouldUpdateUI) { this.updateUI(); } this.game.showNotification(`${skill.name} unlocked!`, 'success', 4000); return true; } applySkillEffects() { const player = this.game.systems.player; // Reset to base stats first this.resetToBaseStats(); // Apply all skill effects Object.values(this.skills).forEach(skill => { if (skill.level > 0) { const skillData = this.skillData[skill.id]; if (skillData && skillData.effects) { Object.entries(skillData.effects).forEach(([effect, value]) => { const totalEffect = value * skill.level; switch (effect) { case 'attack': player.attributes.attack += totalEffect; break; case 'defense': player.attributes.defense += totalEffect; break; case 'speed': player.attributes.speed += totalEffect; break; case 'maxHealth': player.attributes.maxHealth += totalEffect; break; case 'maxEnergy': player.attributes.maxEnergy += totalEffect; break; case 'criticalChance': player.attributes.criticalChance += totalEffect; break; case 'criticalDamage': player.attributes.criticalDamage += totalEffect; break; case 'energyRegeneration': case 'healthRegeneration': case 'craftingBonus': case 'weaponStats': case 'armorStats': case 'resourceBonus': case 'shipUpgrades': case 'systemEfficiency': case 'findRarity': case 'itemValue': case 'findResources': // Store these for other systems to use if (!this.activeBuffs[effect]) { this.activeBuffs[effect] = 0; } this.activeBuffs[effect] += totalEffect; break; } }); } } }); player.updateUI(); } resetToBaseStats() { const player = this.game.systems.player; // Reset to base values (would need to store base stats separately) // For now, we'll use initial values const baseStats = { attack: 10 + (player.stats.level - 1) * 2, defense: 5 + (player.stats.level - 1) * 1, speed: 10, maxHealth: 100 + (player.stats.level - 1) * 10, maxEnergy: 100 + (player.stats.level - 1) * 5, criticalChance: 0.05, criticalDamage: 1.5 }; Object.assign(player.attributes, baseStats); this.activeBuffs = {}; } // Skill experience from actions awardCombatExperience(amount) { this.addSkillExperience('combat', 'weapons_mastery', amount); this.addSkillExperience('combat', 'tactical_analysis', amount * 0.5); } awardScienceExperience(amount) { this.addSkillExperience('science', 'energy_manipulation', amount); this.addSkillExperience('science', 'alien_technology', amount * 0.3); } awardCraftingExperience(amount) { this.addSkillExperience('crafting', 'weapon_crafting', amount); this.addSkillExperience('crafting', 'armor_forging', amount * 0.5); } // Skill checks getSkillLevel(category, skillId) { return this.skills[category]?.[skillId]?.currentLevel || 0; } hasSkill(category, skillId, minimumLevel = 1) { const skill = this.skills[category]?.[skillId]; return skill && skill.unlocked && skill.currentLevel >= minimumLevel; } getSkillBonus(effect) { return this.activeBuffs[effect] || 0; } // UI updates updateUI() { this.updateSkillsGrid(); this.updateSkillPointsDisplay(); } updateSkillsGrid() { const skillsGridElement = document.getElementById('skillsGrid'); if (!skillsGridElement) return; const activeCategory = document.querySelector('.skill-cat-btn.active')?.dataset.category || 'combat'; const skills = this.skills[activeCategory] || {}; skillsGridElement.innerHTML = ''; Object.entries(skills).forEach(([skillId, skill]) => { const skillElement = document.createElement('div'); skillElement.className = `skill-item ${!skill.unlocked ? 'locked' : ''}`; const progressPercent = skill.currentLevel > 0 ? (skill.experience / skill.experienceToNext) * 100 : 0; // Use texture manager for icon fallback const iconClass = this.game.systems.textureManager ? this.game.systems.textureManager.getIcon(skill.icon) : (skill.icon || 'fa-question'); skillElement.innerHTML = `
${skill.name}
Lv. ${skill.currentLevel}/${skill.maxLevel}
${skill.description}
${skill.currentLevel > 0 && skill.currentLevel < skill.maxLevel ? `
${skill.experience}/${skill.experienceToNext} XP
` : skill.currentLevel >= skill.maxLevel ? `
MAX LEVEL
` : ''}
${!skill.unlocked ? ` ` : skill.currentLevel < skill.maxLevel ? ` ` : ` MAX LEVEL `}
${skill.requiredLevel && !skill.unlocked ? `
Requires Level ${skill.requiredLevel}
` : ''} `; skillsGridElement.appendChild(skillElement); }); } updateSkillPointsDisplay() { const player = this.game.systems.player; // Update skill points display if element exists const skillPointsElements = document.querySelectorAll('.skill-points'); skillPointsElements.forEach(element => { element.textContent = `Skill Points: ${player.stats.skillPoints}`; }); } // Save/Load save() { return { skills: this.skills, activeBuffs: this.activeBuffs }; } load(data) { if (data.skills) { // Deep merge to preserve structure for (const [category, skills] of Object.entries(data.skills)) { if (this.skills[category]) { for (const [skillId, skillData] of Object.entries(skills)) { if (this.skills[category][skillId]) { Object.assign(this.skills[category][skillId], skillData); } } } } } if (data.activeBuffs) { this.activeBuffs = data.activeBuffs; } this.applySkillEffects(); } reset() { this.skillPoints = 0; this.unlockedSkills = []; this.activeBuffs = []; // Skills are already defined in constructor, just reset levels Object.values(this.skills).forEach(category => { Object.values(category).forEach(skill => { skill.currentLevel = 0; skill.experience = 0; }); }); } clear() { this.reset(); } }