/********************************************************************** * GAME CORE **********************************************************************/ // AI functions are defined in ai.js and loaded via script tag let frameCount = 0; let money = 5000; // Start with 5000 let purchaseMode = null; // Shared city storage (wood, etc.) const cityStorage = { wood: 0, food: 0, medicine: 0, knowledge: 0 }; // Arrays let resources = []; // Trees, FruitTrees let buildings = []; // House, Road, Market, Hospital, School let citizens = []; let animals = []; /********************************************************************** * COSTS & EARNINGS **********************************************************************/ const COST_HOUSE = 300; const COST_ROAD = 150; const COST_BUILDER = 100; const COST_FARMER = 100; const COST_MERCHANT = 150; const COST_DOCTOR = 200; const COST_TEACHER = 180; const COST_MARKET = 400; const COST_HOSPITAL = 500; const COST_SCHOOL = 450; const COST_SPAWNER = 500; const COST_TREE = 50; const COST_SOLDIER = 250; // Earn money const REWARD_DELIVER_WOOD = 5; const REWARD_BUILD_COMPLETE = 20; const REWARD_MARKET_INCOME = 15; const REWARD_EDUCATION = 10; /********************************************************************** * STATS & CONSTANTS **********************************************************************/ // Hunger & energy const HUNGER_MAX = 100; const ENERGY_MAX = 100; const HEALTH_MAX = 100; const EDUCATION_MAX = 100; const HUNGER_INCREMENT = 0.005; const ENERGY_DECREMENT_WORK = 0.02; const ENERGY_INCREMENT_REST = 0.05; const HUNGER_THRESHOLD = 50; const ENERGY_THRESHOLD = 30; const HEALTH_THRESHOLD = 40; // Trees const FRUIT_TREE_START_AMOUNT = 20; const FRUIT_GATHER_RATE = 1; const FRUIT_PLANT_COST = 1; // House & Road const HOUSE_WOOD_REQUIRED = 50; const HOUSE_BUILD_RATE = 0.2; const HOUSE_MAX_FRUIT = 30; const ROAD_WOOD_REQUIRED = 10; const ROAD_BUILD_RATE = 0.3; // Market, Hospital, School const MARKET_WOOD_REQUIRED = 60; const MARKET_BUILD_RATE = 0.15; const HOSPITAL_WOOD_REQUIRED = 70; const HOSPITAL_BUILD_RATE = 0.1; const SCHOOL_WOOD_REQUIRED = 65; const SCHOOL_BUILD_RATE = 0.12; // Professions const PROFESSIONS = ["Farmer", "Builder", "Merchant", "Doctor", "Teacher", "Soldier"]; // Animals const STARTING_RABBITS = 10; const STARTING_WOLVES = 3; const RABBIT_HUNGER_INCREMENT = 0.003; const RABBIT_REPRO_COOLDOWN = 3000; const RABBIT_REPRO_CHANCE = 0.0005; const WOLF_SPEED = 0.7; // Faster than rabbits /********************************************************************** * INIT WORLD **********************************************************************/ function initWorld() { // Normal trees - only on land for(let i=0; i<15; i++) { let x, y; do { x = randInt(-1000,1000); y = randInt(-1000,1000); } while (!isValidPlacement(x, y)); resources.push(createResource("Tree", x, y, 100)); } // Fruit trees - only on land for(let i=0; i<10; i++) { let x, y; do { x = randInt(-1000,1000); y = randInt(-1000,1000); } while (!isValidPlacement(x, y)); resources.push(createResource("FruitTree", x, y, FRUIT_TREE_START_AMOUNT)); } // Start with 1 citizen => always a "Builder" - only on land let cx, cy; do { cx = randInt(-200,200); cy = randInt(-200,200); } while (!isValidPlacement(cx, cy)); let c = createCitizen(randomName(), cx, cy, "Builder"); citizens.push(c); logAction(`Initial Citizen joined: ${c.name} [Builder]`); // Spawn some animals - only on land for(let i=0; i { if(typeof updateCitizen === 'function') { updateCitizen(cit); } else { console.error("updateCitizen function is not defined!"); } }); // Animals animals.forEach((ani) => { if(!ani.dead) updateAnimal(ani); }); animals = animals.filter(a => !a.dead); // Automatic new citizen every 3000 frames if(frameCount % 3000 === 0) { let baby = createCitizen(randomName(), randInt(-200,200), randInt(-200,200)); citizens.push(baby); logAction(`A new citizen is born: ${baby.name} [${baby.profession}]`); } // Buildings buildings.forEach((b) => { if(!b.completed && b.deliveredWood >= b.requiredWood) { let buildRate; switch(b.buildingType) { case "Road": buildRate = ROAD_BUILD_RATE; break; case "House": buildRate = HOUSE_BUILD_RATE; break; case "Market": buildRate = MARKET_BUILD_RATE; break; case "Hospital": buildRate = HOSPITAL_BUILD_RATE; break; case "School": buildRate = SCHOOL_BUILD_RATE; break; default: buildRate = HOUSE_BUILD_RATE; } b.buildProgress += buildRate; if(b.buildProgress >= 100) { b.completed = true; addMoney(REWARD_BUILD_COMPLETE, `Complete ${b.buildingType}`); if(b.buildingType === "House") { logAction(`A new House completed @(${Math.floor(b.x)},${Math.floor(b.y)})!`); maybeBuildRoad(b); } else if(b.buildingType === "Road") { logAction(`A Road has been completed!`); } else if(b.buildingType === "Market") { logAction(`A Market has been completed! Will generate income.`); } else if(b.buildingType === "Hospital") { logAction(`A Hospital has been completed! Citizens can heal here.`); } else if(b.buildingType === "School") { logAction(`A School has been completed! Citizens can learn here.`); } } } // Special building functions if(b.completed) { if(b.buildingType === "Market" && frameCount % 500 === 0) { addMoney(REWARD_MARKET_INCOME, "Market income"); } if(b.buildingType === "School" && frameCount % 800 === 0) { addMoney(REWARD_EDUCATION, "Education benefits"); } } }); drawWorld(); updateHUD(); requestAnimationFrame(update); } function updateHUD() { // Update money and citizen count moneyDisplay.textContent = `Money: $${money}`; citizenCountDisplay.textContent = `Citizens: ${citizens.length}`; // Update resource counts woodDisplay.textContent = `Wood: ${cityStorage.wood}`; foodDisplay.textContent = `Food: ${cityStorage.food}`; medicineDisplay.textContent = `Medicine: ${cityStorage.medicine}`; knowledgeDisplay.textContent = `Knowledge: ${cityStorage.knowledge}`; // Update building counts const houseCount = buildings.filter(b => b.buildingType === "House" && b.completed).length; const marketCount = buildings.filter(b => b.buildingType === "Market" && b.completed).length; const hospitalCount = buildings.filter(b => b.buildingType === "Hospital" && b.completed).length; const schoolCount = buildings.filter(b => b.buildingType === "School" && b.completed).length; buildingCountsDisplay.textContent = `Buildings: 🏠${houseCount} 🏪${marketCount} 🏥${hospitalCount} 🏫${schoolCount}`; // Update profession counts const builderCount = citizens.filter(c => c.profession === "Builder").length; const farmerCount = citizens.filter(c => c.profession === "Farmer").length; const merchantCount = citizens.filter(c => c.profession === "Merchant").length; const doctorCount = citizens.filter(c => c.profession === "Doctor").length; const teacherCount = citizens.filter(c => c.profession === "Teacher").length; const soldierCount = citizens.filter(c => c.profession === "Soldier").length; professionCountsDisplay.textContent = `Citizens: 👷${builderCount} 🌾${farmerCount} 💰${merchantCount} 💉${doctorCount} 📚${teacherCount} ⚔️${soldierCount}`; }