Files
novafarma/src/systems/ElectionSystem.js

436 lines
13 KiB
JavaScript

/**
* ELECTION & SOCIAL ORDER SYSTEM
* Mrtva Dolina - City Evolution Through Democracy
*
* Features:
* - Chaos phase (no leader, messy city)
* - Election trigger (after 5+ NPCs arrive)
* - Vote gathering & influence system
* - Mayor inauguration with visual/audio changes
* - Unlocks city improvements (walls, patrols)
*/
export class ElectionSystem {
constructor(scene) {
this.scene = scene;
// Election state
this.electionPhase = 'none'; // none, chaos, campaign, complete
this.mayorElected = false;
this.currentMayor = null;
// Candidates
this.candidates = [
{
id: 'mayor_default',
name: 'Župan',
votes: 0,
platform: 'Obzidje in varnost',
supportingNPCs: []
},
{
id: 'ivan_kovac',
name: 'Ivan Kovač',
votes: 0,
platform: 'Proizvodni razvoj',
supportingNPCs: []
},
{
id: 'tehnik',
name: 'Tehnik',
votes: 0,
platform: 'Tehnološki napredek',
supportingNPCs: []
}
];
// City visual state
this.cityState = {
cleanliness: 0, // 0-100
security: 0, // 0-100
morale: 0 // 0-100
};
// Trash/debris objects for visual chaos
this.debrisObjects = [];
// Population tracking
this.npcCount = 0;
this.electionThreshold = 5; // Trigger election at 5 NPCs
this.init();
}
init() {
// Listen for NPC arrival events
this.scene.events.on('npc:arrived', this.onNPCArrival, this);
this.scene.events.on('quest:completed', this.onQuestCompleted, this);
console.log('✅ ElectionSystem initialized');
}
/**
* NPC ARRIVAL - Track population
*/
onNPCArrival(npcData) {
this.npcCount++;
console.log(`👤 NPC arrived: ${npcData.name}. Total: ${this.npcCount}`);
// Check if chaos phase should start
if (this.npcCount >= 3 && this.electionPhase === 'none') {
this.startChaosPhase();
}
// Check if election should trigger
if (this.npcCount >= this.electionThreshold && this.electionPhase === 'chaos') {
this.triggerElection();
}
}
/**
* CHAOS PHASE - City is disorganized
*/
startChaosPhase() {
this.electionPhase = 'chaos';
console.log('💥 CHAOS PHASE STARTED - City needs leadership!');
// Spawn trash/debris around town
this.spawnDebris(15); // 15 trash piles
// Lower city stats
this.cityState.cleanliness = 20;
this.cityState.security = 10;
this.cityState.morale = 30;
// NPCs start discussing need for leader
this.startChaosDialogues();
// Show notification
this.scene.events.emit('show-notification', {
title: 'Stanje Kaosa',
message: 'Ljudje potrebujejo vodjo! Uredite red v mestu.',
icon: '⚠️',
duration: 5000
});
// Update status board
this.updateStatusBoard();
}
spawnDebris(count) {
const debrisTypes = ['trash_pile', 'broken_crate', 'rubble', 'scattered_papers'];
for (let i = 0; i < count; i++) {
const x = Phaser.Math.Between(100, this.scene.cameras.main.width - 100);
const y = Phaser.Math.Between(100, this.scene.cameras.main.height - 100);
const type = Phaser.Utils.Array.GetRandom(debrisTypes);
const debris = this.scene.add.sprite(x, y, type);
debris.setDepth(1);
this.debrisObjects.push(debris);
}
}
startChaosDialogues() {
// NPCs randomly discuss the chaos
const dialogues = [
{ npc: 'sivilja', text: 'Ta kaos je neznosn! Rabimo vodjo!' },
{ npc: 'pek', text: 'Kdo bo prinesel red v to mesto?' },
{ npc: 'ivan_kovac', text: 'Brez organizacije ne moremo preživeti.' }
];
// Emit dialogue events periodically
this.chaosDialogueTimer = setInterval(() => {
const dialogue = Phaser.Utils.Array.GetRandom(dialogues);
this.scene.events.emit('npc:dialogue', dialogue);
}, 30000); // Every 30 seconds
}
/**
* TRIGGER ELECTION
*/
triggerElection() {
this.electionPhase = 'campaign';
console.log('🗳️ ELECTION TRIGGERED - Campaign begins!');
// Stop chaos dialogues
if (this.chaosDialogueTimer) {
clearInterval(this.chaosDialogueTimer);
}
// Create election quest
this.createElectionQuest();
// Show notification
this.scene.events.emit('show-notification', {
title: 'Volitve za Župana',
message: 'Mesto potrebuje vodjo! Pomagaj pri zbiranju glasov.',
icon: '🗳️',
duration: 5000
});
// NPCs start campaign dialogues
this.startCampaignDialogues();
}
createElectionQuest() {
if (!this.scene.questSystem) return;
const electionQuest = {
id: 'election_campaign',
title: 'Zbiranje Glasov za Župana',
type: 'social',
priority: 5,
description: 'Pomagaj izbrati župana za Mrtvo Dolino.',
objectives: [
{
id: 'talk_to_npcs',
text: 'Pogovor s 5 NPC-ji o volitvah',
type: 'interaction',
required: 5,
current: 0
},
{
id: 'support_candidate',
text: 'Podpri kandidata z opravljanjem questov',
type: 'flag',
complete: false
}
],
rewards: {
xp: 1000,
unlocks: ['mayor_office', 'city_improvements']
},
dialogue: {
start: ['Ljudi potrebujejo vodjo. Kdo bo župan?'],
complete: ['Volitve so končane! Novi župan je izvoljen!']
},
npc: 'mayor'
};
this.scene.questSystem.registerQuest(electionQuest);
this.scene.questSystem.startQuest('election_campaign');
}
startCampaignDialogues() {
// Each candidate promotes their platform
const campaignLines = {
mayor_default: 'Glasujte zame! Zgradil bom obzidje in patruljo!',
ivan_kovac: 'Potrebujemo proizvodnjo! Podprite me!',
tehnik: 'Tehnologija je prihodnost! Volite tehnološki napredek!'
};
// NPCs express support for different candidates
this.campaignDialogueTimer = setInterval(() => {
const candidate = Phaser.Utils.Array.GetRandom(this.candidates);
this.scene.events.emit('npc:dialogue', {
npc: candidate.id,
text: campaignLines[candidate.id]
});
}, 45000); // Every 45 seconds
}
/**
* VOTING - Player influences votes through quests
*/
onQuestCompleted(questId) {
if (this.electionPhase !== 'campaign') return;
// Check which candidate benefits from this quest
const questCandidateMap = {
'obzidje': 'mayor_default',
'pekov_recept': 'mayor_default',
'tehnikova_naprava': 'tehnik',
'siviljina_prosnja': 'ivan_kovac'
};
const candidateId = questCandidateMap[questId];
if (candidateId) {
this.addVote(candidateId, 1);
// Show feedback
this.scene.events.emit('show-floating-text', {
x: this.scene.player.x,
y: this.scene.player.y - 50,
text: `+1 glas za ${candidateId}`,
color: '#FFD700'
});
}
}
addVote(candidateId, votes = 1) {
const candidate = this.candidates.find(c => c.id === candidateId);
if (candidate) {
candidate.votes += votes;
console.log(`🗳️ ${candidate.name} dobil ${votes} glas(ov). Skupaj: ${candidate.votes}`);
}
}
/**
* COMPLETE ELECTION - Inaugurate mayor
*/
completeElection() {
if (this.mayorElected) return;
// Count votes and determine winner
const winner = this.candidates.reduce((prev, current) =>
(prev.votes > current.votes) ? prev : current
);
this.currentMayor = winner;
this.mayorElected = true;
this.electionPhase = 'complete';
console.log(`🏛️ ${winner.name} je izvoljen za župana!`);
// Inauguration sequence
this.inauguration(winner);
}
inauguration(mayor) {
// Visual changes
this.cleanUpCity();
// Mayor moves to town hall
if (this.scene.npcs && this.scene.npcs[mayor.id]) {
const mayorNPC = this.scene.npcs[mayor.id];
this.scene.tweens.add({
targets: mayorNPC,
x: this.scene.townHallX || 400,
y: this.scene.townHallY || 300,
duration: 3000,
ease: 'Sine.easeInOut'
});
}
// Change music to ordered/military theme
if (this.scene.sound && this.scene.sound.get('background_music')) {
this.scene.sound.get('background_music').stop();
}
this.scene.sound.play('mayor_anthem', { loop: true, volume: 0.5 });
// Unlock new features
this.unlockMayorFeatures();
// Show inauguration cutscene
this.scene.events.emit('show-notification', {
title: `Župan ${mayor.name}`,
message: `${mayor.name} je uradno inauguriran! Mesto je zdaj pod vodstvom.`,
icon: '🏛️',
duration: 7000
});
// Update city stats
this.cityState.cleanliness = 80;
this.cityState.security = 70;
this.cityState.morale = 90;
this.updateStatusBoard();
// Complete election quest
if (this.scene.questSystem) {
this.scene.questSystem.completeQuest('election_campaign');
}
}
cleanUpCity() {
// Remove all debris with animation
this.debrisObjects.forEach((debris, index) => {
this.scene.tweens.add({
targets: debris,
alpha: 0,
scaleX: 0,
scaleY: 0,
duration: 1000,
delay: index * 100,
onComplete: () => debris.destroy()
});
});
this.debrisObjects = [];
// Add clean visual elements (flags, guards, etc.)
this.addCityImprovements();
}
addCityImprovements() {
// Add flags
const flagPositions = [
{ x: 200, y: 150 },
{ x: 400, y: 150 },
{ x: 600, y: 150 }
];
flagPositions.forEach(pos => {
const flag = this.scene.add.sprite(pos.x, pos.y, 'city_flag');
flag.setDepth(10);
// Waving animation
this.scene.tweens.add({
targets: flag,
scaleX: 1.1,
duration: 1000,
yoyo: true,
repeat: -1,
ease: 'Sine.easeInOut'
});
});
// Add guards (if available)
// ... patrol implementation
}
unlockMayorFeatures() {
// Unlock wall building
if (this.scene.buildingSystem) {
this.scene.buildingSystem.unlock('wall_wooden');
this.scene.buildingSystem.unlock('wall_stone');
}
// Unlock patrol system
if (this.scene.defenseSystem) {
this.scene.defenseSystem.unlockPatrols();
}
// Unlock mayor's office
this.scene.events.emit('building:unlocked', 'mayor_office');
console.log('🔓 Mayor features unlocked: walls, patrols, office');
}
updateStatusBoard() {
// Update city status display
this.scene.events.emit('city:stats_updated', {
cleanliness: this.cityState.cleanliness,
security: this.cityState.security,
morale: this.cityState.morale,
population: this.npcCount,
mayor: this.currentMayor ? this.currentMayor.name : 'None'
});
}
/**
* Get election results for UI display
*/
getElectionResults() {
return {
phase: this.electionPhase,
candidates: this.candidates,
winner: this.currentMayor,
cityState: this.cityState
};
}
destroy() {
if (this.chaosDialogueTimer) clearInterval(this.chaosDialogueTimer);
if (this.campaignDialogueTimer) clearInterval(this.campaignDialogueTimer);
this.debrisObjects.forEach(obj => obj.destroy());
this.debrisObjects = [];
}
}