436 lines
13 KiB
JavaScript
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 = [];
|
|
}
|
|
}
|