SYSTEMS 4-6/9 COMPLETE: ZombieScoutSkills (skill tree, active/passive abilities), NomadRaiderAI (state machine, pathfinding, loot stealing), FarmRaidSystem (wave spawning, difficulty scaling, rewards). Progress: 6/9 systems (67%).
This commit is contained in:
420
src/systems/ZombieScoutSkills.js
Normal file
420
src/systems/ZombieScoutSkills.js
Normal file
@@ -0,0 +1,420 @@
|
||||
/**
|
||||
* ZOMBIE SCOUT SKILLS SYSTEM
|
||||
* Skill tree with active/passive abilities
|
||||
* Integrates with ZombieScoutLevelingSystem
|
||||
*/
|
||||
|
||||
export class ZombieScoutSkills {
|
||||
constructor(scene) {
|
||||
this.scene = scene;
|
||||
|
||||
// Skill trees
|
||||
this.skills = new Map();
|
||||
this.unlockedSkills = new Set();
|
||||
this.activeSkills = new Map(); // Currently equipped active skills
|
||||
|
||||
// Skill categories
|
||||
this.categories = ['digging', 'combat', 'utility'];
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.initializeSkillTree();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize all available skills
|
||||
*/
|
||||
initializeSkillTree() {
|
||||
// DIGGING SKILLS
|
||||
this.registerSkill({
|
||||
id: 'speed_dig',
|
||||
name: 'Speed Dig',
|
||||
category: 'digging',
|
||||
type: 'active',
|
||||
unlockLevel: 10,
|
||||
cooldown: 30000, // 30 seconds
|
||||
duration: 10000, // 10 seconds
|
||||
description: 'Dig 50% faster for 10 seconds',
|
||||
effect: () => this.activateSpeedDig()
|
||||
});
|
||||
|
||||
this.registerSkill({
|
||||
id: 'deep_scan',
|
||||
name: 'Deep Scan',
|
||||
category: 'digging',
|
||||
type: 'passive',
|
||||
unlockLevel: 5,
|
||||
description: 'Reveal buried items within 5 tiles',
|
||||
effect: () => this.enableDeepScan()
|
||||
});
|
||||
|
||||
this.registerSkill({
|
||||
id: 'treasure_sense',
|
||||
name: 'Treasure Sense',
|
||||
category: 'digging',
|
||||
type: 'active',
|
||||
unlockLevel: 15,
|
||||
cooldown: 60000, // 60 seconds
|
||||
description: 'Reveal all buried treasure on screen',
|
||||
effect: () => this.activateTreasureSense()
|
||||
});
|
||||
|
||||
// COMBAT SKILLS
|
||||
this.registerSkill({
|
||||
id: 'basic_attack',
|
||||
name: 'Claw Swipe',
|
||||
category: 'combat',
|
||||
type: 'active',
|
||||
unlockLevel: 5,
|
||||
cooldown: 2000, // 2 seconds
|
||||
damage: 10,
|
||||
description: 'Basic melee attack dealing 10 damage',
|
||||
effect: () => this.performBasicAttack()
|
||||
});
|
||||
|
||||
this.registerSkill({
|
||||
id: 'leap_attack',
|
||||
name: 'Leap Attack',
|
||||
category: 'combat',
|
||||
type: 'active',
|
||||
unlockLevel: 12,
|
||||
cooldown: 8000, // 8 seconds
|
||||
damage: 25,
|
||||
description: 'Leap at enemy dealing 25 damage',
|
||||
effect: () => this.performLeapAttack()
|
||||
});
|
||||
|
||||
this.registerSkill({
|
||||
id: 'tank_stance',
|
||||
name: 'Undead Resilience',
|
||||
category: 'combat',
|
||||
type: 'passive',
|
||||
unlockLevel: 8,
|
||||
description: '+20% damage resistance',
|
||||
effect: () => this.enableTankStance()
|
||||
});
|
||||
|
||||
// UTILITY SKILLS
|
||||
this.registerSkill({
|
||||
id: 'scout_speed',
|
||||
name: 'Scout Sprint',
|
||||
category: 'utility',
|
||||
type: 'active',
|
||||
unlockLevel: 7,
|
||||
cooldown: 20000, // 20 seconds
|
||||
duration: 5000, // 5 seconds
|
||||
description: 'Move 100% faster for 5 seconds',
|
||||
effect: () => this.activateScoutSpeed()
|
||||
});
|
||||
|
||||
this.registerSkill({
|
||||
id: 'pack_mule',
|
||||
name: 'Pack Mule',
|
||||
category: 'utility',
|
||||
type: 'passive',
|
||||
unlockLevel: 6,
|
||||
description: '+10 inventory slots',
|
||||
effect: () => this.enablePackMule()
|
||||
});
|
||||
|
||||
this.registerSkill({
|
||||
id: 'night_vision',
|
||||
name: 'Night Vision',
|
||||
category: 'utility',
|
||||
type: 'passive',
|
||||
unlockLevel: 10,
|
||||
description: 'See in darkness without penalty',
|
||||
effect: () => this.enableNightVision()
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a skill in the system
|
||||
*/
|
||||
registerSkill(skillData) {
|
||||
this.skills.set(skillData.id, {
|
||||
...skillData,
|
||||
unlocked: false,
|
||||
active: false,
|
||||
lastUsed: 0
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock skill (called when level requirement met)
|
||||
*/
|
||||
unlockSkill(skillId) {
|
||||
const skill = this.skills.get(skillId);
|
||||
if (!skill) return false;
|
||||
|
||||
const scoutLevel = this.scene.zombieScoutLeveling?.currentLevel || 1;
|
||||
|
||||
// Check level requirement
|
||||
if (scoutLevel < skill.unlockLevel) {
|
||||
console.warn(`Scout level ${scoutLevel} too low for ${skill.name} (requires ${skill.unlockLevel})`);
|
||||
return false;
|
||||
}
|
||||
|
||||
skill.unlocked = true;
|
||||
this.unlockedSkills.add(skillId);
|
||||
|
||||
// Auto-activate passive skills
|
||||
if (skill.type === 'passive') {
|
||||
skill.effect();
|
||||
}
|
||||
|
||||
// Notification
|
||||
this.scene.uiSystem?.showNotification(
|
||||
`Skill Unlocked: ${skill.name}!`,
|
||||
'skill_unlock',
|
||||
{ description: skill.description }
|
||||
);
|
||||
|
||||
console.log(`✨ Unlocked skill: ${skill.name}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use active skill
|
||||
*/
|
||||
useSkill(skillId) {
|
||||
const skill = this.skills.get(skillId);
|
||||
if (!skill || !skill.unlocked || skill.type !== 'active') return false;
|
||||
|
||||
// Check cooldown
|
||||
const now = Date.now();
|
||||
const timeSinceLastUse = now - skill.lastUsed;
|
||||
|
||||
if (timeSinceLastUse < skill.cooldown) {
|
||||
const remainingCooldown = Math.ceil((skill.cooldown - timeSinceLastUse) / 1000);
|
||||
console.log(`Skill on cooldown: ${remainingCooldown}s remaining`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Activate skill
|
||||
skill.lastUsed = now;
|
||||
skill.effect();
|
||||
|
||||
// UI feedback
|
||||
this.scene.uiSystem?.showSkillActivation(skill.name, skill.cooldown);
|
||||
|
||||
console.log(`🔥 Activated: ${skill.name}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* SKILL EFFECTS
|
||||
*/
|
||||
|
||||
activateSpeedDig() {
|
||||
const scout = this.scene.zombieScout;
|
||||
if (!scout) return;
|
||||
|
||||
scout.digSpeed *= 1.5; // 50% faster
|
||||
|
||||
// VFX
|
||||
this.scene.vfxSystem?.playEffect('speed_buff', scout.x, scout.y);
|
||||
|
||||
// Restore after duration
|
||||
this.scene.time.delayedCall(10000, () => {
|
||||
scout.digSpeed /= 1.5;
|
||||
console.log('Speed Dig expired');
|
||||
});
|
||||
}
|
||||
|
||||
enableDeepScan() {
|
||||
// Enable passive treasure detection
|
||||
this.scene.gameState.buffs.treasure_detection_range = 5;
|
||||
console.log('Deep Scan enabled: 5 tile range');
|
||||
}
|
||||
|
||||
activateTreasureSense() {
|
||||
// Reveal all buried items on screen
|
||||
this.scene.treasureSystem?.revealAllTreasures();
|
||||
|
||||
// VFX: Screen pulse
|
||||
this.scene.cameras.main.flash(500, 255, 215, 0, true);
|
||||
|
||||
console.log('Treasure Sense activated: All treasures revealed');
|
||||
}
|
||||
|
||||
performBasicAttack() {
|
||||
const scout = this.scene.zombieScout;
|
||||
if (!scout) return;
|
||||
|
||||
// Find nearest enemy
|
||||
const enemy = this.findNearestEnemy(scout, 50);
|
||||
if (!enemy) {
|
||||
console.log('No enemy in range');
|
||||
return;
|
||||
}
|
||||
|
||||
// Deal damage
|
||||
enemy.takeDamage(10);
|
||||
|
||||
// VFX
|
||||
this.scene.vfxSystem?.playEffect('claw_swipe', enemy.x, enemy.y);
|
||||
this.scene.soundSystem?.play('zombie_attack');
|
||||
|
||||
console.log('Basic attack: 10 damage');
|
||||
}
|
||||
|
||||
performLeapAttack() {
|
||||
const scout = this.scene.zombieScout;
|
||||
if (!scout) return;
|
||||
|
||||
// Find nearest enemy
|
||||
const enemy = this.findNearestEnemy(scout, 150);
|
||||
if (!enemy) return;
|
||||
|
||||
// Leap animation
|
||||
this.scene.tweens.add({
|
||||
targets: scout,
|
||||
x: enemy.x,
|
||||
y: enemy.y - 20,
|
||||
duration: 300,
|
||||
ease: 'Quad.easeOut',
|
||||
onComplete: () => {
|
||||
// Deal damage on landing
|
||||
enemy.takeDamage(25);
|
||||
this.scene.vfxSystem?.playEffect('impact', enemy.x, enemy.y);
|
||||
this.scene.cameras.main.shake(200, 0.008);
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Leap attack: 25 damage');
|
||||
}
|
||||
|
||||
enableTankStance() {
|
||||
const scout = this.scene.zombieScout;
|
||||
if (scout) {
|
||||
scout.damageResistance = (scout.damageResistance || 0) + 0.2; // +20%
|
||||
console.log('Undead Resilience enabled: +20% damage resistance');
|
||||
}
|
||||
}
|
||||
|
||||
activateScoutSpeed() {
|
||||
const scout = this.scene.zombieScout;
|
||||
if (!scout) return;
|
||||
|
||||
scout.moveSpeed *= 2; // 100% faster
|
||||
|
||||
// VFX: Speed trails
|
||||
this.scene.vfxSystem?.playEffect('speed_trail', scout.x, scout.y, { duration: 5000 });
|
||||
|
||||
// Restore after duration
|
||||
this.scene.time.delayedCall(5000, () => {
|
||||
scout.moveSpeed /= 2;
|
||||
console.log('Scout Sprint expired');
|
||||
});
|
||||
}
|
||||
|
||||
enablePackMule() {
|
||||
this.scene.inventorySystem?.addInventorySlots(10);
|
||||
console.log('Pack Mule enabled: +10 inventory slots');
|
||||
}
|
||||
|
||||
enableNightVision() {
|
||||
this.scene.gameState.buffs.night_vision = true;
|
||||
console.log('Night Vision enabled: Full visibility at night');
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: Find nearest enemy
|
||||
*/
|
||||
findNearestEnemy(from, maxDistance) {
|
||||
let nearest = null;
|
||||
let minDist = maxDistance;
|
||||
|
||||
// Search for enemies in scene
|
||||
const enemies = this.scene.enemies || [];
|
||||
|
||||
enemies.forEach(enemy => {
|
||||
const dist = Phaser.Math.Distance.Between(from.x, from.y, enemy.x, enemy.y);
|
||||
if (dist < minDist) {
|
||||
minDist = dist;
|
||||
nearest = enemy;
|
||||
}
|
||||
});
|
||||
|
||||
return nearest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get unlocked skills by category
|
||||
*/
|
||||
getSkillsByCategory(category) {
|
||||
return Array.from(this.skills.values())
|
||||
.filter(s => s.category === category && s.unlocked);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all unlocked skills
|
||||
*/
|
||||
getUnlockedSkills() {
|
||||
return Array.from(this.skills.values()).filter(s => s.unlocked);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check skill availability
|
||||
*/
|
||||
isSkillAvailable(skillId) {
|
||||
const skill = this.skills.get(skillId);
|
||||
if (!skill || !skill.unlocked) return false;
|
||||
|
||||
if (skill.type === 'passive') return true;
|
||||
|
||||
const now = Date.now();
|
||||
return (now - skill.lastUsed) >= skill.cooldown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get skill cooldown remaining
|
||||
*/
|
||||
getCooldownRemaining(skillId) {
|
||||
const skill = this.skills.get(skillId);
|
||||
if (!skill) return 0;
|
||||
|
||||
const now = Date.now();
|
||||
const elapsed = now - skill.lastUsed;
|
||||
const remaining = Math.max(0, skill.cooldown - elapsed);
|
||||
|
||||
return Math.ceil(remaining / 1000); // Return in seconds
|
||||
}
|
||||
|
||||
/**
|
||||
* Save/Load
|
||||
*/
|
||||
getSaveData() {
|
||||
return {
|
||||
unlockedSkills: Array.from(this.unlockedSkills),
|
||||
skillCooldowns: Array.from(this.skills.entries()).map(([id, skill]) => ({
|
||||
id,
|
||||
lastUsed: skill.lastUsed
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
loadSaveData(data) {
|
||||
this.unlockedSkills = new Set(data.unlockedSkills || []);
|
||||
|
||||
// Restore cooldowns
|
||||
data.skillCooldowns?.forEach(({ id, lastUsed }) => {
|
||||
const skill = this.skills.get(id);
|
||||
if (skill) {
|
||||
skill.lastUsed = lastUsed;
|
||||
skill.unlocked = this.unlockedSkills.has(id);
|
||||
}
|
||||
});
|
||||
|
||||
// Re-apply passive skills
|
||||
this.unlockedSkills.forEach(skillId => {
|
||||
const skill = this.skills.get(skillId);
|
||||
if (skill && skill.type === 'passive') {
|
||||
skill.effect();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user