465 lines
13 KiB
JavaScript
465 lines
13 KiB
JavaScript
/**
|
|
* ZOMBIE MINER AUTOMATION SYSTEM
|
|
* Part of: Mining System Expansion
|
|
* Created: January 4, 2026
|
|
*
|
|
* Features:
|
|
* - Hire zombie miners for passive resource generation
|
|
* - Assign miners to specific mine depths
|
|
* - Efficiency & loyalty mechanics
|
|
* - Automated ore collection
|
|
* - Zombie equipment upgrades
|
|
*/
|
|
|
|
class ZombieMinerAutomationSystem {
|
|
constructor(game) {
|
|
this.game = game;
|
|
this.player = game.player;
|
|
|
|
// Zombie miners
|
|
this.zombieMiners = [];
|
|
this.maxZombieMiners = 10;
|
|
this.zombieMinerCost = 5000;
|
|
|
|
// Automation settings
|
|
this.automationActive = false;
|
|
this.totalYieldPerHour = 0;
|
|
this.lastCollectionTime = null;
|
|
|
|
// Equipment for zombies
|
|
this.zombieEquipment = {
|
|
pickaxe_tier: 1, // 1-5
|
|
helmet_lamp: false, // Better visibility
|
|
oxygen_tank: false, // Deeper mining
|
|
cart: false // Auto-transport
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Hire a zombie miner
|
|
*/
|
|
hireZombieMiner() {
|
|
if (this.zombieMiners.length >= this.maxZombieMiners) {
|
|
return {
|
|
success: false,
|
|
message: `Maximum ${this.maxZombieMiners} zombie miners allowed!`
|
|
};
|
|
}
|
|
|
|
if (this.player.money < this.zombieMinerCost) {
|
|
return {
|
|
success: false,
|
|
message: `Need ${this.zombieMinerCost}g to hire zombie miner!`
|
|
};
|
|
}
|
|
|
|
// Hire zombie
|
|
this.player.money -= this.zombieMinerCost;
|
|
|
|
const miner = {
|
|
id: `zombie_miner_${this.zombieMiners.length + 1}`,
|
|
name: this.generateZombieName(),
|
|
assignedMine: null,
|
|
assignedDepth: 0,
|
|
efficiency: 1.0, // 0.5 - 2.0
|
|
loyalty: 50, // 0-100
|
|
yieldPerHour: 5, // Base yield
|
|
level: 1,
|
|
experience: 0
|
|
};
|
|
|
|
this.zombieMiners.push(miner);
|
|
|
|
// Recalculate automation
|
|
this.updateAutomationYield();
|
|
|
|
this.game.showMessage(
|
|
`Hired ${miner.name}! (${this.zombieMiners.length}/${this.maxZombieMiners})`
|
|
);
|
|
|
|
return { success: true, miner: miner };
|
|
}
|
|
|
|
/**
|
|
* Generate random zombie miner name
|
|
*/
|
|
generateZombieName() {
|
|
const prefixes = ['Grumpy', 'Rusty', 'Dusty', 'Grumbly', 'Moaning', 'Shuffling'];
|
|
const suffixes = ['Zed', 'Mort', 'Bones', 'Guts', 'Picks', 'Drills'];
|
|
|
|
const prefix = Phaser.Utils.Array.GetRandom(prefixes);
|
|
const suffix = Phaser.Utils.Array.GetRandom(suffixes);
|
|
|
|
return `${prefix} ${suffix}`;
|
|
}
|
|
|
|
/**
|
|
* Assign zombie miner to specific mine & depth
|
|
*/
|
|
assignZombieMiner(minerId, mineId, depth) {
|
|
const miner = this.zombieMiners.find(m => m.id === minerId);
|
|
|
|
if (!miner) {
|
|
return { success: false, message: 'Zombie miner not found!' };
|
|
}
|
|
|
|
// Check if mine exists
|
|
const mine = this.game.miningSystem.getMineInfo(mineId);
|
|
if (!mine) {
|
|
return { success: false, message: 'Mine not found!' };
|
|
}
|
|
|
|
// Check if depth is unlocked
|
|
const maxDepth = this.game.miningSystem.maxDepthReached || 0;
|
|
if (depth > maxDepth) {
|
|
return {
|
|
success: false,
|
|
message: `Must explore depth ${depth} first!`
|
|
};
|
|
}
|
|
|
|
// Assign miner
|
|
miner.assignedMine = mineId;
|
|
miner.assignedDepth = depth;
|
|
|
|
// Update automation
|
|
this.updateAutomationYield();
|
|
|
|
this.game.showMessage(
|
|
`${miner.name} assigned to ${mine.name} - Depth ${depth}`
|
|
);
|
|
|
|
return { success: true };
|
|
}
|
|
|
|
/**
|
|
* Unassign zombie miner (return to surface)
|
|
*/
|
|
unassignZombieMiner(minerId) {
|
|
const miner = this.zombieMiners.find(m => m.id === minerId);
|
|
|
|
if (!miner) {
|
|
return { success: false };
|
|
}
|
|
|
|
miner.assignedMine = null;
|
|
miner.assignedDepth = 0;
|
|
|
|
// Update automation
|
|
this.updateAutomationYield();
|
|
|
|
this.game.showMessage(
|
|
`${miner.name} returned to surface.`
|
|
);
|
|
|
|
return { success: true };
|
|
}
|
|
|
|
/**
|
|
* Update total automation yield
|
|
*/
|
|
updateAutomationYield() {
|
|
let totalYield = 0;
|
|
|
|
this.zombieMiners.forEach(miner => {
|
|
if (miner.assignedMine && miner.assignedDepth > 0) {
|
|
// Base yield
|
|
let hourlyYield = miner.yieldPerHour;
|
|
|
|
// Depth bonus (+10% per 10 levels)
|
|
const depthBonus = (miner.assignedDepth / 10) * 0.1;
|
|
hourlyYield *= (1 + depthBonus);
|
|
|
|
// Efficiency factor
|
|
hourlyYield *= miner.efficiency;
|
|
|
|
// Loyalty factor (50% loyalty = 0.5x yield, 100% = 1.5x yield)
|
|
const loyaltyFactor = 0.5 + (miner.loyalty / 100);
|
|
hourlyYield *= loyaltyFactor;
|
|
|
|
// Equipment bonuses
|
|
if (this.zombieEquipment.pickaxe_tier > 1) {
|
|
hourlyYield *= (1 + (this.zombieEquipment.pickaxe_tier - 1) * 0.25);
|
|
}
|
|
if (this.zombieEquipment.cart) {
|
|
hourlyYield *= 1.5; // 50% faster collection
|
|
}
|
|
|
|
totalYield += hourlyYield;
|
|
}
|
|
});
|
|
|
|
this.totalYieldPerHour = Math.floor(totalYield);
|
|
this.automationActive = (totalYield > 0);
|
|
}
|
|
|
|
/**
|
|
* Collect automated mining resources
|
|
*/
|
|
collectAutomatedYield() {
|
|
if (!this.automationActive) {
|
|
return {
|
|
success: false,
|
|
message: 'No zombie miners assigned!'
|
|
};
|
|
}
|
|
|
|
// Calculate time since last collection
|
|
const hoursSinceLastCollection = this.getHoursSinceLastCollection();
|
|
|
|
if (hoursSinceLastCollection < 0.1) {
|
|
return {
|
|
success: false,
|
|
message: 'Collected too recently! Wait a bit.'
|
|
};
|
|
}
|
|
|
|
const resources = {};
|
|
|
|
// Collect from each zombie
|
|
this.zombieMiners.forEach(miner => {
|
|
if (miner.assignedMine && miner.assignedDepth > 0) {
|
|
// Get mine info
|
|
const mine = this.game.miningSystem.getMineInfo(miner.assignedMine);
|
|
|
|
// Determine ore type based on depth
|
|
const oreType = this.getOreTypeForDepth(mine, miner.assignedDepth);
|
|
|
|
// Calculate yield
|
|
const hourlyYield = miner.yieldPerHour * miner.efficiency *
|
|
(0.5 + miner.loyalty / 100);
|
|
|
|
const amount = Math.floor(hourlyYield * hoursSinceLastCollection);
|
|
|
|
if (amount > 0) {
|
|
resources[oreType] = (resources[oreType] || 0) + amount;
|
|
|
|
// Grant XP to miner
|
|
miner.experience += amount;
|
|
this.checkMinerLevelUp(miner);
|
|
}
|
|
}
|
|
});
|
|
|
|
// Add resources to inventory
|
|
let totalCollected = 0;
|
|
for (const [ore, amount] of Object.entries(resources)) {
|
|
this.player.inventory.addItem(ore, amount);
|
|
totalCollected += amount;
|
|
}
|
|
|
|
// Update last collection time
|
|
this.lastCollectionTime = this.game.time.currentTime;
|
|
|
|
// Show collection message
|
|
const resourceList = Object.entries(resources)
|
|
.map(([ore, amount]) => `${amount}x ${ore}`)
|
|
.join(', ');
|
|
|
|
this.game.showMessage(
|
|
`Collected: ${resourceList} (${hoursSinceLastCollection.toFixed(1)}h)`
|
|
);
|
|
|
|
return {
|
|
success: true,
|
|
resources: resources,
|
|
totalAmount: totalCollected,
|
|
hours: hoursSinceLastCollection
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get ore type based on mine and depth
|
|
*/
|
|
getOreTypeForDepth(mine, depth) {
|
|
// Logic from mine zones
|
|
if (depth <= 25) return 'copper_ore';
|
|
if (depth <= 50) return 'iron_ore';
|
|
if (depth <= 75) return 'gold_ore';
|
|
return 'diamond_ore';
|
|
}
|
|
|
|
/**
|
|
* Check if miner levels up
|
|
*/
|
|
checkMinerLevelUp(miner) {
|
|
const xpRequired = miner.level * 100;
|
|
|
|
if (miner.experience >= xpRequired) {
|
|
miner.level++;
|
|
miner.experience = 0;
|
|
|
|
// Bonuses per level
|
|
miner.yieldPerHour += 1;
|
|
miner.efficiency += 0.05;
|
|
|
|
this.game.showMessage(
|
|
`${miner.name} leveled up! (Lv.${miner.level})`
|
|
);
|
|
|
|
this.updateAutomationYield();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Feed zombie miner (restore loyalty)
|
|
*/
|
|
feedZombieMiner(minerId, foodType) {
|
|
const miner = this.zombieMiners.find(m => m.id === minerId);
|
|
|
|
if (!miner) {
|
|
return { success: false };
|
|
}
|
|
|
|
// Check if player has food
|
|
if (!this.player.inventory.hasItem(foodType)) {
|
|
return {
|
|
success: false,
|
|
message: 'You don\'t have this food!'
|
|
};
|
|
}
|
|
|
|
// Remove food
|
|
this.player.inventory.removeItem(foodType, 1);
|
|
|
|
// Loyalty bonus based on food quality
|
|
const loyaltyGain = this.getFoodLoyaltyValue(foodType);
|
|
miner.loyalty = Math.min(100, miner.loyalty + loyaltyGain);
|
|
|
|
this.game.showMessage(
|
|
`${miner.name} ate ${foodType}. Loyalty +${loyaltyGain} (${miner.loyalty}/100)`
|
|
);
|
|
|
|
// Update automation
|
|
this.updateAutomationYield();
|
|
|
|
return { success: true, loyaltyGain: loyaltyGain };
|
|
}
|
|
|
|
/**
|
|
* Get food loyalty value
|
|
*/
|
|
getFoodLoyaltyValue(foodType) {
|
|
const foodValues = {
|
|
'brain': 20, // Best food
|
|
'meat': 15,
|
|
'bread': 10,
|
|
'vegetables': 5
|
|
};
|
|
|
|
return foodValues[foodType] || 5;
|
|
}
|
|
|
|
/**
|
|
* Upgrade zombie equipment
|
|
*/
|
|
upgradeEquipment(equipmentType) {
|
|
const costs = {
|
|
pickaxe_tier: 3000,
|
|
helmet_lamp: 2000,
|
|
oxygen_tank: 2500,
|
|
cart: 4000
|
|
};
|
|
|
|
const cost = costs[equipmentType];
|
|
|
|
if (!cost) {
|
|
return { success: false, message: 'Invalid equipment!' };
|
|
}
|
|
|
|
// Check if already owned (except pickaxe tiers)
|
|
if (equipmentType !== 'pickaxe_tier') {
|
|
if (this.zombieEquipment[equipmentType]) {
|
|
return {
|
|
success: false,
|
|
message: 'Already owned!'
|
|
};
|
|
}
|
|
} else {
|
|
// Check pickaxe tier limit
|
|
if (this.zombieEquipment.pickaxe_tier >= 5) {
|
|
return {
|
|
success: false,
|
|
message: 'Pickaxe already max tier!'
|
|
};
|
|
}
|
|
}
|
|
|
|
// Check money
|
|
if (this.player.money < cost) {
|
|
return {
|
|
success: false,
|
|
message: `Need ${cost}g!`
|
|
};
|
|
}
|
|
|
|
// Purchase
|
|
this.player.money -= cost;
|
|
|
|
if (equipmentType === 'pickaxe_tier') {
|
|
this.zombieEquipment.pickaxe_tier++;
|
|
} else {
|
|
this.zombieEquipment[equipmentType] = true;
|
|
}
|
|
|
|
// Update automation
|
|
this.updateAutomationYield();
|
|
|
|
this.game.showMessage(
|
|
`Upgraded zombie equipment: ${equipmentType}! ${cost}g`
|
|
);
|
|
|
|
return { success: true };
|
|
}
|
|
|
|
/**
|
|
* Get hours since last collection
|
|
*/
|
|
getHoursSinceLastCollection() {
|
|
if (!this.lastCollectionTime) {
|
|
this.lastCollectionTime = this.game.time.currentTime;
|
|
return 0;
|
|
}
|
|
|
|
const secondsElapsed = this.game.time.currentTime - this.lastCollectionTime;
|
|
return secondsElapsed / 3600;
|
|
}
|
|
|
|
/**
|
|
* Get automation UI data
|
|
*/
|
|
getAutomationUIData() {
|
|
return {
|
|
zombieMiners: this.zombieMiners,
|
|
maxZombieMiners: this.maxZombieMiners,
|
|
totalYieldPerHour: this.totalYieldPerHour,
|
|
automationActive: this.automationActive,
|
|
equipment: this.zombieEquipment,
|
|
canHireMore: this.zombieMiners.length < this.maxZombieMiners,
|
|
hireCost: this.zombieMinerCost,
|
|
hoursSinceCollection: this.getHoursSinceLastCollection()
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Update (passive decay of loyalty)
|
|
*/
|
|
update(deltaTime) {
|
|
// Loyalty slowly decays if zombies are working
|
|
this.zombieMiners.forEach(miner => {
|
|
if (miner.assignedMine && miner.assignedDepth > 0) {
|
|
// Lose 1 loyalty per hour worked
|
|
const loyaltyLoss = (deltaTime / 3600);
|
|
miner.loyalty = Math.max(0, miner.loyalty - loyaltyLoss);
|
|
}
|
|
});
|
|
|
|
// Recalculate if needed
|
|
if (this.automationActive) {
|
|
this.updateAutomationYield();
|
|
}
|
|
}
|
|
}
|
|
|
|
|