597 lines
21 KiB
JavaScript
597 lines
21 KiB
JavaScript
/**
|
|
* 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 = `
|
|
<div class="skill-header">
|
|
<div class="skill-icon">
|
|
<i class="fas ${iconClass}"></i>
|
|
</div>
|
|
<div class="skill-info">
|
|
<div class="skill-name">${skill.name}</div>
|
|
<div class="skill-level">Lv. ${skill.currentLevel}/${skill.maxLevel}</div>
|
|
</div>
|
|
</div>
|
|
<div class="skill-description">${skill.description}</div>
|
|
${skill.currentLevel > 0 && skill.currentLevel < skill.maxLevel ? `
|
|
<div class="skill-progress">
|
|
<div class="progress-bar">
|
|
<div class="progress-fill" style="width: ${progressPercent}%"></div>
|
|
</div>
|
|
<span>${skill.experience}/${skill.experienceToNext} XP</span>
|
|
</div>
|
|
` : skill.currentLevel >= skill.maxLevel ? `
|
|
<div class="skill-max-level">
|
|
<span>MAX LEVEL</span>
|
|
</div>
|
|
` : ''}
|
|
<div class="skill-actions">
|
|
${!skill.unlocked ? `
|
|
<button class="btn btn-warning" onclick="if(window.game && window.game.systems) window.game.systems.skillSystem.unlockSkill('${activeCategory}', '${skillId}')">
|
|
Unlock (2 Points)
|
|
</button>
|
|
` : skill.currentLevel < skill.maxLevel ? `
|
|
<button class="btn btn-primary" onclick="if(window.game && window.game.systems) window.game.systems.skillSystem.upgradeSkill('${activeCategory}', '${skillId}')">
|
|
Upgrade (1 Point)
|
|
</button>
|
|
` : `
|
|
<span class="max-level">MAX LEVEL</span>
|
|
`}
|
|
</div>
|
|
${skill.requiredLevel && !skill.unlocked ? `
|
|
<div class="skill-requirement">Requires Level ${skill.requiredLevel}</div>
|
|
` : ''}
|
|
`;
|
|
|
|
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();
|
|
}
|
|
}
|