Files
novafarma/EMERGENCY_SYSTEMS_RECOVERY/TownGrowthSystem.js
2026-01-16 02:43:46 +01:00

461 lines
15 KiB
JavaScript

/**
* TOWN GROWTH SYSTEM - Population & Expansion
* Part of: Game Systems Expansion
* Created: January 4, 2026
*
* Features:
* - Dynamic town population (4 → 20 NPCs)
* - Town sign with live stats
* - Small villages (5-10 scattered across map)
* - Population unlock requirements
* - Town Services unlock based on population
*/
class TownGrowthSystem {
constructor(game) {
this.game = game;
this.player = game.player;
// Town stats
this.townName = 'Dolina Smrti';
this.population = 4; // Starting NPCs: Kai, Ana, Gronk, Baker
this.maxPopulation = 20;
this.populationSlots = [
{ index: 1, unlocked: true, npc: 'kai' },
{ index: 2, unlocked: true, npc: 'ana' },
{ index: 3, unlocked: true, npc: 'gronk' },
{ index: 4, unlocked: true, npc: 'baker' },
{ index: 5, unlocked: false, npc: null, requirement: { farmLevel: 2 } },
{ index: 6, unlocked: false, npc: null, requirement: { money: 10000 } },
{ index: 7, unlocked: false, npc: null, requirement: { quest: 'expand_town_1' } },
{ index: 8, unlocked: false, npc: null, requirement: { population: 6 } },
{ index: 9, unlocked: false, npc: null, requirement: { building: 'bakery' } },
{ index: 10, unlocked: false, npc: null, requirement: { building: 'barbershop' } },
{ index: 11, unlocked: false, npc: null, requirement: { hearts: 5, npcId: 'any' } },
{ index: 12, unlocked: false, npc: null, requirement: { quest: 'expand_town_2' } },
{ index: 13, unlocked: false, npc: null, requirement: { zombieWorkers: 5 } },
{ index: 14, unlocked: false, npc: null, requirement: { building: 'mine' } },
{ index: 15, unlocked: false, npc: null, requirement: { money: 50000 } },
{ index: 16, unlocked: false, npc: null, requirement: { quest: 'expand_town_3' } },
{ index: 17, unlocked: false, npc: null, requirement: { marriage: true } },
{ index: 18, unlocked: false, npc: null, requirement: { population: 15 } },
{ index: 19, unlocked: false, npc: null, requirement: { allBuildings: true } },
{ index: 20, unlocked: false, npc: null, requirement: { quest: 'town_master' } }
];
// Town sign
this.townSign = {
location: { x: 400, y: 300 },
visible: true,
displayMode: 'population' // 'population', 'status', 'full'
};
// Small villages
this.villages = this.initializeVillages();
// Town services (unlock based on population)
this.services = {
market: { unlocked: false, requiredPopulation: 6 },
hospital: { unlocked: false, requiredPopulation: 8 },
school: { unlocked: false, requiredPopulation: 10 },
bank: { unlocked: false, requiredPopulation: 12 },
museum: { unlocked: false, requiredPopulation: 15 },
theater: { unlocked: false, requiredPopulation: 18 }
};
}
/**
* Initialize small villages
*/
initializeVillages() {
return [
{
id: 'village_north',
name: 'Severna Vas',
position: { x: 3000, y: 500 },
population: 7,
discovered: false,
npcs: [
{ id: 'fisherman', name: 'Old Fisher', hobby: 'fishing' },
{ id: 'hunter', name: 'Hunter Dane', hobby: 'hunting' },
{ id: 'hermit', name: 'Wise Hermit', hobby: 'meditation' }
],
specialItems: ['ancient_fishing_rod', 'hunter_bow', 'meditation_mat']
},
{
id: 'village_east',
name: 'Vzhodna Stran',
position: { x: 5000, y: 2000 },
population: 5,
discovered: false,
npcs: [
{ id: 'blacksmith', name: 'Master Smith', hobby: 'forging' },
{ id: 'alchemist', name: 'Mysterious Alchemist', hobby: 'alchemy' }
],
specialItems: ['master_anvil', 'legendary_hammer', 'philosopher_stone']
},
{
id: 'village_south',
name: 'Južno Naselje',
position: { x: 2500, y: 4500 },
population: 6,
discovered: false,
npcs: [
{ id: 'trader', name: 'Traveling Trader', hobby: 'collecting' },
{ id: 'musician', name: 'Bard Luka', hobby: 'music' }
],
specialItems: ['exotic_seeds', 'rare_instruments', 'ancient_map']
},
{
id: 'village_west',
name: 'Zahodna Dolina',
position: { x: 500, y: 3000 },
population: 8,
discovered: false,
npcs: [
{ id: 'chef', name: 'Chef Antonio', hobby: 'cooking' },
{ id: 'librarian', name: 'Keeper of Books', hobby: 'reading' },
{ id: 'artist', name: 'Painter Ana', hobby: 'painting' }
],
specialItems: ['master_cookbook', 'ancient_tome', 'rare_pigments']
},
{
id: 'village_mysterious',
name: '??? Mystery Village',
position: { x: 4000, y: 4000 },
population: 10,
discovered: false,
hidden: true, // Only visible after completing special quest
npcs: [
{ id: 'time_keeper', name: 'Keeper of Time', hobby: 'timekeeping' },
{ id: 'oracle', name: 'Oracle of Dolina', hobby: 'prophecy' }
],
specialItems: ['time_crystal', 'prophecy_scroll', 'reality_gem']
}
];
}
/**
* Check and unlock new population slot
*/
checkPopulationUnlocks() {
let newUnlocks = 0;
this.populationSlots.forEach(slot => {
if (!slot.unlocked && slot.requirement) {
if (this.meetsRequirement(slot.requirement)) {
slot.unlocked = true;
newUnlocks++;
this.game.showMessage(
`New population slot unlocked! (${this.population}/${this.maxPopulation})`
);
}
}
});
if (newUnlocks > 0) {
this.updateTownServices();
}
return newUnlocks;
}
/**
* Check if requirement is met
*/
meetsRequirement(requirement) {
// Farm level
if (requirement.farmLevel) {
if (this.player.farmLevel < requirement.farmLevel) {
return false;
}
}
// Money
if (requirement.money) {
if (this.player.money < requirement.money) {
return false;
}
}
// Quest
if (requirement.quest) {
if (!this.player.hasCompletedQuest(requirement.quest)) {
return false;
}
}
// Building
if (requirement.building) {
if (!this.player.hasBuilding(requirement.building)) {
return false;
}
}
// Current population
if (requirement.population) {
if (this.population < requirement.population) {
return false;
}
}
// Zombie workers
if (requirement.zombieWorkers) {
const zombieCount = this.game.zombieWorkers?.getWorkerCount() || 0;
if (zombieCount < requirement.zombieWorkers) {
return false;
}
}
// Marriage
if (requirement.marriage) {
if (!this.player.isMarried) {
return false;
}
}
// Hearts with any NPC
if (requirement.hearts && requirement.npcId === 'any') {
const hasHighRelationship = this.game.npcs.getAllNPCs()
.some(npc => npc.relationshipHearts >= requirement.hearts);
if (!hasHighRelationship) {
return false;
}
}
// All buildings
if (requirement.allBuildings) {
const requiredBuildings = ['bakery', 'barbershop', 'lawyer', 'mine', 'hospital'];
if (!requiredBuildings.every(b => this.player.hasBuilding(b))) {
return false;
}
}
return true;
}
/**
* Invite new NPC to town
*/
inviteNPC(npcId) {
// Find available slot
const availableSlot = this.populationSlots.find(
slot => slot.unlocked && slot.npc === null
);
if (!availableSlot) {
return {
success: false,
message: 'No available population slots!'
};
}
// Check if NPC exists
const npcData = this.game.npcs.getNPCData(npcId);
if (!npcData) {
return { success: false, message: 'NPC not found!' };
}
// Assign NPC to slot
availableSlot.npc = npcId;
// Spawn NPC in town
this.game.npcs.spawn(npcId, {
homeLocation: 'town',
moveInDate: this.game.time.currentDate
});
// Increase population
this.population++;
// Update town sign
this.updateTownSign();
// Check for service unlocks
this.updateTownServices();
this.game.showMessage(
`${npcData.name} moved to town! Population: ${this.population}/${this.maxPopulation}`
);
return { success: true, npc: npcData };
}
/**
* Update town services based on population
*/
updateTownServices() {
let newServices = [];
Object.entries(this.services).forEach(([serviceId, service]) => {
if (!service.unlocked && this.population >= service.requiredPopulation) {
service.unlocked = true;
newServices.push(serviceId);
this.game.showMessage(
`🏛️ New service unlocked: ${serviceId}! (Pop: ${this.population})`
);
// Trigger service built event
this.game.emit('serviceUnlocked', {
serviceId: serviceId,
population: this.population
});
}
});
return newServices;
}
/**
* Update town sign display
*/
updateTownSign() {
const signData = {
townName: this.townName,
population: this.population,
maxPopulation: this.maxPopulation,
status: this.getTownStatus(),
services: Object.keys(this.services).filter(s => this.services[s].unlocked).length
};
// Emit event to update sign sprite
this.game.emit('townSignUpdate', signData);
}
/**
* Get town status description
*/
getTownStatus() {
if (this.population >= 18) {
return 'Thriving City';
}
if (this.population >= 15) {
return 'Prosperous Town';
}
if (this.population >= 10) {
return 'Growing Town';
}
if (this.population >= 6) {
return 'Small Town';
}
return 'Village';
}
/**
* Discover village
*/
discoverVillage(villageId) {
const village = this.villages.find(v => v.id === villageId);
if (!village) {
return { success: false };
}
if (village.discovered) {
return {
success: false,
message: 'Village already discovered!'
};
}
// Check if hidden village requires quest
if (village.hidden && !this.player.hasCompletedQuest('find_mystery_village')) {
return {
success: false,
message: 'This village remains hidden...'
};
}
// Discover village
village.discovered = true;
// Spawn village NPCs
village.npcs.forEach(npcData => {
this.game.npcs.spawn(npcData.id, {
homeLocation: villageId,
position: village.position,
hobby: npcData.hobby
});
});
// Mark special items as available
village.specialItems.forEach(itemId => {
this.game.items.markAsDiscovered(itemId, villageId);
});
this.game.showMessage(
`Discovered ${village.name}! Population: ${village.population} NPCs`
);
// Achievement
const discoveredCount = this.villages.filter(v => v.discovered).length;
if (discoveredCount === this.villages.length) {
this.game.achievements.unlock('village_explorer');
}
return { success: true, village: village };
}
/**
* Get travel distance to village
*/
getTravelDistance(villageId) {
const village = this.villages.find(v => v.id === villageId);
if (!village) return null;
const playerPos = this.player.getPosition();
const dx = village.position.x - playerPos.x;
const dy = village.position.y - playerPos.y;
return Math.sqrt(dx * dx + dy * dy);
}
/**
* Get village trade options
*/
getVillageTradeOptions(villageId) {
const village = this.villages.find(v => v.id === villageId);
if (!village || !village.discovered) return null;
return {
villageName: village.name,
npcs: village.npcs,
specialItems: village.specialItems,
population: village.population
};
}
/**
* Get town growth UI data
*/
getTownGrowthUIData() {
return {
townName: this.townName,
population: this.population,
maxPopulation: this.maxPopulation,
status: this.getTownStatus(),
populationSlots: this.populationSlots,
availableSlots: this.populationSlots.filter(s => s.unlocked && !s.npc).length,
services: this.services,
villages: this.villages.filter(v => !v.hidden || v.discovered),
discoveredVillages: this.villages.filter(v => v.discovered).length,
totalVillages: this.villages.filter(v => !v.hidden).length
};
}
/**
* Update (check for new unlocks)
*/
update() {
// Check for new population slot unlocks
this.checkPopulationUnlocks();
// Update town sign
this.updateTownSign();
}
}