Files
novafarma/DEBUG_TOTAL_RECOVERY/ZombieEconomySystem.js
2026-01-16 02:43:46 +01:00

570 lines
17 KiB
JavaScript

/**
* ZOMBIE ECONOMY & CITY SANITATION SYSTEM
* Mrtva Dolina - Worker Zombies, Smetarji, Redka Darila
*
* Features:
* - Worker Zombies (heavy labor, construction)
* - Sanitation System (Smetar cleans city)
* - Rare Gift System (unique rewards from zombie work)
* - Zombie Maintenance (Brain feeding)
* - Contract System (loan zombies to NPCs)
* - Happiness impact on city growth
*/
export class ZombieEconomySystem {
constructor(scene) {
this.scene = scene;
// Worker zombie types
this.zombieTypes = {
scout: {
name: 'Zombi Skavt',
strength: 30,
speed: 60,
brainConsumption: 0.5, // per hour
tasks: ['scouting', 'light_work']
},
worker: {
name: 'Delovni Zombi',
strength: 80,
speed: 40,
brainConsumption: 1.5, // per hour
tasks: ['construction', 'hauling', 'sanitation']
},
sanitation: {
name: 'Smetar Zombi',
strength: 50,
speed: 50,
brainConsumption: 1.0, // per hour
tasks: ['cleaning', 'graffiti_removal']
}
};
// Active zombies
this.activeZombies = [];
// Contracts (zombies loaned to NPCs)
this.activeContracts = [];
// Rare gifts catalogue
this.rareGifts = [
{ id: 'family_heirloom', name: 'Starinski družinski artefakt', rarity: 'legendary', value: 1000 },
{ id: 'ancient_dye', name: 'Starodavno barvilo', rarity: 'epic', value: 500 },
{ id: 'rare_seed_pack', name: 'Paket redkih semen', rarity: 'rare', value: 300 },
{ id: 'kai_memory_photo', name: 'Kaijeva skrita fotografija', rarity: 'legendary', value: 2000 },
{ id: 'mystical_paint', name: 'Mistično barvilo', rarity: 'epic', value: 600 }
];
// City cleanliness tracking
this.cityTrash = [];
this.cityGraffiti = [];
this.cleanlinessScore = 50; // 0-100
// Happiness impact
this.citizenHappiness = 50; // 0-100
this.init();
}
init() {
// Listen for trash generation
this.scene.events.on('npc:activity', this.onNPCActivity, this);
this.scene.events.on('vandal:graffiti', this.onGraffitiCreated, this);
// Start passive systems
this.startBrainConsumption();
this.startCleaningSweep();
console.log('✅ ZombieEconomySystem initialized');
}
/**
* RECRUIT ZOMBIE
*/
recruitZombie(type, name = null) {
const zombieData = this.zombieTypes[type];
if (!zombieData) {
console.error(`Unknown zombie type: ${type}`);
return null;
}
const zombie = {
id: `zombie_${Date.now()}`,
type: type,
name: name || zombieData.name,
strength: zombieData.strength,
speed: zombieData.speed,
brainLevel: 100, // 0-100, energy/hunger
brainConsumption: zombieData.brainConsumption,
tasks: zombieData.tasks,
currentTask: null,
isContracted: false,
grumbleTimer: null,
x: this.scene.player.x,
y: this.scene.player.y,
sprite: null
};
// Create sprite
zombie.sprite = this.scene.add.sprite(zombie.x, zombie.y, `zombie_${type}`);
zombie.sprite.setDepth(5);
this.activeZombies.push(zombie);
console.log(`🧟 Recruited: ${zombie.name}`);
return zombie;
}
/**
* FEED ZOMBIE (with brains)
*/
feedZombie(zombieId, brainsAmount = 50) {
const zombie = this.activeZombies.find(z => z.id === zombieId);
if (!zombie) return false;
zombie.brainLevel = Math.min(100, zombie.brainLevel + brainsAmount);
// Happy zombie sound
this.scene.sound.play('zombie_satisfied', { volume: 0.5 });
// Show feedback
this.scene.events.emit('show-floating-text', {
x: zombie.sprite.x,
y: zombie.sprite.y - 30,
text: '*munch* ...dobr!',
color: '#90EE90'
});
// Stop grumbling
if (zombie.grumbleTimer) {
clearInterval(zombie.grumbleTimer);
zombie.grumbleTimer = null;
}
return true;
}
/**
* BRAIN CONSUMPTION - Passive hunger system
*/
startBrainConsumption() {
setInterval(() => {
this.activeZombies.forEach(zombie => {
// Reduce brain level based on consumption rate
zombie.brainLevel = Math.max(0, zombie.brainLevel - (zombie.brainConsumption / 60)); // per minute
// Check hunger
if (zombie.brainLevel < 30) {
this.zombieHungry(zombie);
}
// Critical hunger - zombie becomes slow
if (zombie.brainLevel < 10) {
zombie.speed *= 0.5; // 50% slower
if (zombie.sprite) {
zombie.sprite.setTint(0x666666); // Darken sprite
}
}
});
}, 60000); // Every minute
}
zombieHungry(zombie) {
if (zombie.grumbleTimer) return; // Already grumbling
// Start periodic grumbling
zombie.grumbleTimer = setInterval(() => {
const hungerLines = [
'Braaaaains...',
'Možgaaaaani...',
'Hrrrngh... lačen...',
'*godrnja o hrani*'
];
const line = Phaser.Utils.Array.GetRandom(hungerLines);
// Show speech bubble
this.scene.events.emit('show-speech-bubble', {
x: zombie.sprite.x,
y: zombie.sprite.y - 50,
text: line,
duration: 3000
});
// Play hungry sound
if (this.scene.sound) {
this.scene.sound.play('zombie_groan', { volume: 0.4 });
}
}, 15000); // Every 15 seconds
}
/**
* CONTRACT SYSTEM - Loan zombies to NPCs
*/
createContract(zombieId, npc, task, duration, payment) {
const zombie = this.activeZombies.find(z => z.id === zombieId);
if (!zombie || zombie.isContracted) {
console.warn('Zombie not available for contract');
return false;
}
const contract = {
id: `contract_${Date.now()}`,
zombieId: zombieId,
npc: npc, // 'ivan_kovac', 'tehnik', etc.
task: task, // 'wall_construction', 'steel_hauling', etc.
duration: duration, // in game hours
payment: payment, // gold or rare gift
startTime: this.scene.gameTime || Date.now(),
completed: false
};
zombie.isContracted = true;
zombie.currentTask = task;
this.activeContracts.push(contract);
// Move zombie to work site
this.moveZombieToWorkSite(zombie, npc);
console.log(`📄 Contract created: ${zombie.name}${npc} (${task})`);
// Start work visuals
this.startWorkAnimation(zombie, task);
return contract;
}
moveZombieToWorkSite(zombie, npc) {
const workSites = {
ivan_kovac: { x: 300, y: 200 }, // Blacksmith
tehnik: { x: 500, y: 250 }, // Tech Workshop
mayor: { x: 400, y: 300 } // Town Hall
};
const site = workSites[npc] || { x: 400, y: 300 };
if (zombie.sprite) {
this.scene.tweens.add({
targets: zombie.sprite,
x: site.x,
y: site.y,
duration: 2000,
ease: 'Sine.easeInOut'
});
}
}
startWorkAnimation(zombie, task) {
// Different animations for different tasks
const animations = {
wall_construction: 'zombie_hammering',
steel_hauling: 'zombie_carrying',
sanitation: 'zombie_sweeping',
graffiti_removal: 'zombie_scrubbing'
};
const anim = animations[task] || 'zombie_working';
if (zombie.sprite && zombie.sprite.anims) {
zombie.sprite.play(anim, true);
}
}
/**
* COMPLETE CONTRACT - Award payment
*/
completeContract(contractId) {
const contract = this.activeContracts.find(c => c.id === contractId);
if (!contract || contract.completed) return;
const zombie = this.activeZombies.find(z => z.id === contract.zombieId);
contract.completed = true;
zombie.isContracted = false;
zombie.currentTask = null;
// Award payment
if (contract.payment.type === 'gold') {
this.scene.inventorySystem.addGold(contract.payment.amount);
this.scene.events.emit('show-notification', {
title: 'Pogodba Končana',
message: `${zombie.name} je končal delo! +${contract.payment.amount} zlata.`,
icon: '💰',
duration: 3000
});
} else if (contract.payment.type === 'rare_gift') {
this.awardRareGift(contract.payment.giftId);
}
// Return zombie to player
if (zombie.sprite) {
this.scene.tweens.add({
targets: zombie.sprite,
x: this.scene.player.x + 50,
y: this.scene.player.y,
duration: 2000,
ease: 'Sine.easeOut'
});
}
console.log(`✅ Contract completed: ${contract.task}`);
}
/**
* RARE GIFT SYSTEM
*/
awardRareGift(giftId = null) {
// Random gift if not specified
if (!giftId) {
const gift = Phaser.Utils.Array.GetRandom(this.rareGifts);
giftId = gift.id;
}
const gift = this.rareGifts.find(g => g.id === giftId);
if (!gift) return;
// Add to inventory
if (this.scene.inventorySystem) {
this.scene.inventorySystem.addItem(gift.id, 1);
}
// Show special notification
this.scene.events.emit('show-notification', {
title: '🎁 REDKO DARILO!',
message: `Prejel si: ${gift.name} (${gift.rarity})`,
icon: '✨',
duration: 7000,
color: this.getRarityColor(gift.rarity)
});
// Play special sound
if (this.scene.sound) {
this.scene.sound.play('rare_gift_fanfare', { volume: 0.7 });
}
console.log(`🎁 Awarded rare gift: ${gift.name}`);
}
getRarityColor(rarity) {
const colors = {
legendary: '#FFD700', // Gold
epic: '#9B59B6', // Purple
rare: '#3498DB' // Blue
};
return colors[rarity] || '#FFFFFF';
}
/**
* SANITATION SYSTEM - Trash & Graffiti
*/
onNPCActivity(npcData) {
// NPCs randomly drop trash
if (Math.random() < 0.1) { // 10% chance
this.spawnTrash(npcData.x, npcData.y);
}
}
spawnTrash(x, y) {
const trashTypes = ['trash_bag', 'litter', 'broken_bottle', 'paper_waste'];
const type = Phaser.Utils.Array.GetRandom(trashTypes);
const trash = this.scene.add.sprite(x, y, type);
trash.setDepth(1);
this.cityTrash.push({
id: `trash_${Date.now()}_${Math.random()}`,
x: x,
y: y,
type: type,
sprite: trash
});
// Lower cleanliness
this.cleanlinessScore = Math.max(0, this.cleanlinessScore - 2);
this.updateCityStats();
}
onGraffitiCreated(graffitiData) {
const graffiti = this.scene.add.sprite(graffitiData.x, graffitiData.y, 'graffiti_tag');
graffiti.setDepth(2);
this.cityGraffiti.push({
id: `graffiti_${Date.now()}`,
x: graffitiData.x,
y: graffitiData.y,
sprite: graffiti
});
// Lower cleanliness
this.cleanlinessScore = Math.max(0, this.cleanlinessScore - 5);
this.updateCityStats();
}
/**
* CLEANING SWEEP - Zombies clean autonomously
*/
startCleaningSweep() {
setInterval(() => {
// Find sanitation zombies
const cleaners = this.activeZombies.filter(z =>
z.tasks.includes('cleaning') &&
!z.isContracted &&
z.brainLevel > 20
);
cleaners.forEach(cleaner => {
// Clean nearest trash
const nearestTrash = this.findNearestTrash(cleaner.sprite.x, cleaner.sprite.y);
if (nearestTrash) {
this.cleanTrash(cleaner, nearestTrash);
}
// Clean nearest graffiti
const nearestGraffiti = this.findNearestGraffiti(cleaner.sprite.x, cleaner.sprite.y);
if (nearestGraffiti) {
this.cleanGraffiti(cleaner, nearestGraffiti);
}
});
}, 10000); // Every 10 seconds
}
findNearestTrash(x, y) {
let nearest = null;
let minDist = Infinity;
this.cityTrash.forEach(trash => {
const dist = Phaser.Math.Distance.Between(x, y, trash.x, trash.y);
if (dist < minDist) {
minDist = dist;
nearest = trash;
}
});
return minDist < 200 ? nearest : null; // Within 200px
}
findNearestGraffiti(x, y) {
let nearest = null;
let minDist = Infinity;
this.cityGraffiti.forEach(graffiti => {
const dist = Phaser.Math.Distance.Between(x, y, graffiti.x, graffiti.y);
if (dist < minDist) {
minDist = dist;
nearest = graffiti;
}
});
return minDist < 200 ? nearest : null;
}
cleanTrash(zombie, trash) {
// Move to trash
this.scene.tweens.add({
targets: zombie.sprite,
x: trash.x,
y: trash.y,
duration: 1000,
onComplete: () => {
// Play cleaning animation
if (zombie.sprite.anims) {
zombie.sprite.play('zombie_sweeping', true);
}
// Remove trash after delay
setTimeout(() => {
trash.sprite.destroy();
this.cityTrash = this.cityTrash.filter(t => t.id !== trash.id);
// Increase cleanliness
this.cleanlinessScore = Math.min(100, this.cleanlinessScore + 3);
this.updateCityStats();
console.log(`🧹 ${zombie.name} cleaned trash`);
}, 2000);
}
});
}
cleanGraffiti(zombie, graffiti) {
// Move to graffiti
this.scene.tweens.add({
targets: zombie.sprite,
x: graffiti.x,
y: graffiti.y,
duration: 1000,
onComplete: () => {
// Play scrubbing animation
if (zombie.sprite.anims) {
zombie.sprite.play('zombie_scrubbing', true);
}
// Remove graffiti with fade
this.scene.tweens.add({
targets: graffiti.sprite,
alpha: 0,
duration: 3000,
onComplete: () => {
graffiti.sprite.destroy();
this.cityGraffiti = this.cityGraffiti.filter(g => g.id !== graffiti.id);
// Increase cleanliness
this.cleanlinessScore = Math.min(100, this.cleanlinessScore + 5);
this.updateCityStats();
console.log(`🧽 ${zombie.name} removed graffiti`);
}
});
}
});
}
/**
* CITY STATS UPDATE
*/
updateCityStats() {
// Calculate happiness based on cleanliness
this.citizenHappiness = Math.min(100, this.cleanlinessScore * 1.2);
// Emit stats update
this.scene.events.emit('city:stats_updated', {
cleanliness: this.cleanlinessScore,
happiness: this.citizenHappiness,
trashCount: this.cityTrash.length,
graffitiCount: this.cityGraffiti.length
});
// Happiness affects NPC arrival rate
if (this.citizenHappiness > 70) {
// Faster settler arrivals
this.scene.events.emit('city:boost_immigration');
}
}
/**
* Get zombie status for UI
*/
getZombieStatus() {
return this.activeZombies.map(z => ({
id: z.id,
name: z.name,
type: z.type,
brainLevel: z.brainLevel,
currentTask: z.currentTask,
isContracted: z.isContracted
}));
}
destroy() {
this.activeZombies.forEach(zombie => {
if (zombie.sprite) zombie.sprite.destroy();
if (zombie.grumbleTimer) clearInterval(zombie.grumbleTimer);
});
this.cityTrash.forEach(trash => trash.sprite.destroy());
this.cityGraffiti.forEach(graffiti => graffiti.sprite.destroy());
}
}