// Track mouse position for placement indicator let lastMouseWorldX = null; let lastMouseWorldY = null; /********************************************************************** * PAN & ZOOM **********************************************************************/ function setupPanZoom() { canvas.addEventListener('mousedown', (e) => { // Only start dragging if not in terrain drawing mode if(!purchaseMode || !purchaseMode.startsWith('Draw')) { isDragging = true; lastMouseX = e.clientX; lastMouseY = e.clientY; } }); canvas.addEventListener('mouseup', () => { isDragging = false; }); canvas.addEventListener('mouseleave', () => { isDragging = false; }); canvas.addEventListener('mousemove', (e) => { if(isDragging) { let dx = e.clientX - lastMouseX; let dy = e.clientY - lastMouseY; offsetX += dx; offsetY += dy; lastMouseX = e.clientX; lastMouseY = e.clientY; } // Update world coordinates for placement indicator const rect = canvas.getBoundingClientRect(); let cx = e.clientX - rect.left; let cy = e.clientY - rect.top; lastMouseWorldX = (cx - (canvas.width/2) - offsetX) / scale; lastMouseWorldY = (cy - (canvas.height/2) - offsetY) / scale; }); canvas.addEventListener('wheel', (e) => { e.preventDefault(); let zoomSpeed = 0.001; let delta = e.deltaY * zoomSpeed; let oldScale = scale; scale -= delta; if(scale < 0.1) scale = 0.1; if(scale > 5) scale = 5; let mouseX = e.clientX - (canvas.width/2 + offsetX); let mouseY = e.clientY - (canvas.height/2 + offsetY); offsetX -= mouseX * (scale - oldScale); offsetY -= mouseY * (scale - oldScale); }, {passive: false}); } /********************************************************************** * BUY MENU LOGIC **********************************************************************/ function setupBuyButtons() { document.getElementById('buyHouseBtn').addEventListener('click', () => { purchaseMode = "House"; logAction("Click on map to place a House site."); }); document.getElementById('buyRoadBtn').addEventListener('click', () => { purchaseMode = "Road"; logAction("Click on map to place a Road site."); }); document.getElementById('buyBuilderBtn').addEventListener('click', () => { purchaseMode = "Builder"; logAction("Click on map to place a new Builder citizen."); }); document.getElementById('buyFarmerBtn').addEventListener('click', () => { purchaseMode = "Farmer"; logAction("Click on map to place a new Farmer citizen."); }); document.getElementById('buyMerchantBtn').addEventListener('click', () => { purchaseMode = "Merchant"; logAction("Click on map to place a new Merchant citizen."); }); document.getElementById('buyDoctorBtn').addEventListener('click', () => { purchaseMode = "Doctor"; logAction("Click on map to place a new Doctor citizen."); }); document.getElementById('buyTeacherBtn').addEventListener('click', () => { purchaseMode = "Teacher"; logAction("Click on map to place a new Teacher citizen."); }); document.getElementById('buySoldierBtn').addEventListener('click', () => { purchaseMode = "Soldier"; logAction("Click on map to place a new Soldier citizen."); }); document.getElementById('buyPlannerBtn').addEventListener('click', () => { purchaseMode = "Planner"; logAction("Click on map to place a new Planner citizen."); }); document.getElementById('buyMarketBtn').addEventListener('click', () => { purchaseMode = "Market"; logAction("Click on map to place a Market site."); }); document.getElementById('buyHospitalBtn').addEventListener('click', () => { purchaseMode = "Hospital"; logAction("Click on map to place a Hospital site."); }); document.getElementById('buySchoolBtn').addEventListener('click', () => { purchaseMode = "School"; logAction("Click on map to place a School site."); }); document.getElementById('buySpawnerBtn').addEventListener('click', () => { purchaseMode = "Spawner"; logAction("Click on map to place a Spawner building."); }); document.getElementById('buyTreeBtn').addEventListener('click', () => { purchaseMode = "Tree"; logAction("Click on map to place a new Tree."); }); // Terrain drawing buttons document.getElementById('drawWaterBtn').addEventListener('click', () => { purchaseMode = "DrawWater"; logAction("Click and drag on map to draw Water ($20)."); }); document.getElementById('drawGrassBtn').addEventListener('click', () => { purchaseMode = "DrawGrass"; logAction("Click and drag on map to draw Grass ($10)."); }); document.getElementById('drawSandBtn').addEventListener('click', () => { purchaseMode = "DrawSand"; logAction("Click and drag on map to draw Sand ($15)."); }); document.getElementById('drawDirtBtn').addEventListener('click', () => { purchaseMode = "DrawDirt"; logAction("Click and drag on map to draw Dirt ($5)."); }); document.getElementById('drawStoneBtn').addEventListener('click', () => { purchaseMode = "DrawStone"; logAction("Click and drag on map to draw Stone ($25)."); }); document.getElementById('toggleLogsBtn').addEventListener('click', (e) => { if(logContainer.style.display === "none") { logContainer.style.display = "block"; e.target.textContent = "Hide Logs"; } else { logContainer.style.display = "none"; e.target.textContent = "Show Logs"; } }); } // Variables for terrain drawing let isDrawingTerrain = false; let lastDrawX = null; let lastDrawY = null; let terrainDrawCost = 0; let terrainDrawType = null; let terrainDrawCount = 0; function setupCanvasClick() { // Mouse down for terrain drawing canvas.addEventListener('mousedown', (e) => { if(!purchaseMode || !purchaseMode.startsWith('Draw')) return; const rect = canvas.getBoundingClientRect(); let cx = e.clientX - rect.left; let cy = e.clientY - rect.top; let worldX = (cx - (canvas.width/2) - offsetX) / scale; let worldY = (cy - (canvas.height/2) - offsetY) / scale; isDrawingTerrain = true; lastDrawX = worldX; lastDrawY = worldY; terrainDrawCount = 0; // Set terrain type and cost based on mode switch(purchaseMode) { case "DrawWater": terrainDrawType = TERRAIN_WATER; terrainDrawCost = COST_WATER; break; case "DrawGrass": terrainDrawType = TERRAIN_GRASS; terrainDrawCost = COST_GRASS; break; case "DrawSand": terrainDrawType = TERRAIN_SAND; terrainDrawCost = COST_SAND; break; case "DrawDirt": terrainDrawType = TERRAIN_DIRT; terrainDrawCost = COST_DIRT; break; case "DrawStone": terrainDrawType = TERRAIN_STONE; terrainDrawCost = COST_STONE; break; } }); // Mouse move for terrain drawing canvas.addEventListener('mousemove', (e) => { if(isDrawingTerrain && terrainDrawType !== null) { const rect = canvas.getBoundingClientRect(); let cx = e.clientX - rect.left; let cy = e.clientY - rect.top; let worldX = (cx - (canvas.width/2) - offsetX) / scale; let worldY = (cy - (canvas.height/2) - offsetY) / scale; // Only draw if moved enough distance if(Math.abs(worldX - lastDrawX) > 5 || Math.abs(worldY - lastDrawY) > 5) { // Check if we can afford it if(money >= terrainDrawCost) { // Draw a 3x3 area of terrain for(let dx = -1; dx <= 1; dx++) { for(let dy = -1; dy <= 1; dy++) { setTerrainType(worldX + dx * 10, worldY + dy * 10, terrainDrawType); } } addMoney(-terrainDrawCost, `Draw ${getTerrainName(terrainDrawType)}`); terrainDrawCount++; lastDrawX = worldX; lastDrawY = worldY; } else { // Stop drawing if out of money isDrawingTerrain = false; logAction("Not enough money to continue drawing terrain!"); } } } }); // Mouse up to stop terrain drawing canvas.addEventListener('mouseup', () => { if(isDrawingTerrain) { isDrawingTerrain = false; if(terrainDrawCount > 0) { logAction(`Drew ${terrainDrawCount} patches of ${getTerrainName(terrainDrawType)}.`); } terrainDrawType = null; } }); // Mouse leave to stop terrain drawing canvas.addEventListener('mouseleave', () => { isDrawingTerrain = false; terrainDrawType = null; }); canvas.addEventListener('click', (e) => { if(!purchaseMode || purchaseMode.startsWith('Draw')) return; const rect = canvas.getBoundingClientRect(); let cx = e.clientX - rect.left; let cy = e.clientY - rect.top; let worldX = (cx - (canvas.width/2) - offsetX) / scale; let worldY = (cy - (canvas.height/2) - offsetY) / scale; // Check if the placement is valid (not in water) if (!isValidPlacement(worldX, worldY)) { logAction("Cannot build on water! Choose a land location."); return; } switch(purchaseMode) { case "House": if(money >= COST_HOUSE) { addMoney(-COST_HOUSE, "Buy House"); let site = createHouseSite(worldX, worldY); buildings.push(site); logAction(`Purchased House site @(${Math.floor(worldX)},${Math.floor(worldY)})`); } else { logAction("Not enough money to buy House!"); } break; case "Road": if(money >= COST_ROAD) { addMoney(-COST_ROAD, "Buy Road"); // For simplicity, we create a short horizontal road let site = createRoadSite(worldX-50, worldY, worldX+50, worldY); buildings.push(site); logAction(`Purchased Road site @(${Math.floor(worldX)},${Math.floor(worldY)})`); } else { logAction("Not enough money to buy Road!"); } break; case "Market": if(money >= COST_MARKET) { addMoney(-COST_MARKET, "Buy Market"); let site = createMarketSite(worldX, worldY); buildings.push(site); logAction(`Purchased Market site @(${Math.floor(worldX)},${Math.floor(worldY)})`); } else { logAction("Not enough money to buy Market!"); } break; case "Hospital": if(money >= COST_HOSPITAL) { addMoney(-COST_HOSPITAL, "Buy Hospital"); let site = createHospitalSite(worldX, worldY); buildings.push(site); logAction(`Purchased Hospital site @(${Math.floor(worldX)},${Math.floor(worldY)})`); } else { logAction("Not enough money to buy Hospital!"); } break; case "School": if(money >= COST_SCHOOL) { addMoney(-COST_SCHOOL, "Buy School"); let site = createSchoolSite(worldX, worldY); buildings.push(site); logAction(`Purchased School site @(${Math.floor(worldX)},${Math.floor(worldY)})`); } else { logAction("Not enough money to buy School!"); } break; case "Builder": if(money >= COST_BUILDER) { addMoney(-COST_BUILDER, "Buy Builder"); let c = createCitizen(randomName(), worldX, worldY, "Builder"); citizens.push(c); logAction(`Purchased new Builder @(${Math.floor(worldX)},${Math.floor(worldY)})`); } else { logAction("Not enough money to buy Builder!"); } break; case "Farmer": if(money >= COST_FARMER) { addMoney(-COST_FARMER, "Buy Farmer"); let c = createCitizen(randomName(), worldX, worldY, "Farmer"); citizens.push(c); logAction(`Purchased new Farmer @(${Math.floor(worldX)},${Math.floor(worldY)})`); } else { logAction("Not enough money to buy Farmer!"); } break; case "Merchant": if(money >= COST_MERCHANT) { addMoney(-COST_MERCHANT, "Buy Merchant"); let c = createCitizen(randomName(), worldX, worldY, "Merchant"); citizens.push(c); logAction(`Purchased new Merchant @(${Math.floor(worldX)},${Math.floor(worldY)})`); } else { logAction("Not enough money to buy Merchant!"); } break; case "Doctor": if(money >= COST_DOCTOR) { addMoney(-COST_DOCTOR, "Buy Doctor"); let c = createCitizen(randomName(), worldX, worldY, "Doctor"); citizens.push(c); logAction(`Purchased new Doctor @(${Math.floor(worldX)},${Math.floor(worldY)})`); } else { logAction("Not enough money to buy Doctor!"); } break; case "Teacher": if(money >= COST_TEACHER) { addMoney(-COST_TEACHER, "Buy Teacher"); let c = createCitizen(randomName(), worldX, worldY, "Teacher"); citizens.push(c); logAction(`Purchased new Teacher @(${Math.floor(worldX)},${Math.floor(worldY)})`); } else { logAction("Not enough money to buy Teacher!"); } break; case "Soldier": if(money >= COST_SOLDIER) { addMoney(-COST_SOLDIER, "Buy Soldier"); let c = createCitizen(randomName(), worldX, worldY, "Soldier"); citizens.push(c); logAction(`Purchased new Soldier @(${Math.floor(worldX)},${Math.floor(worldY)})`); } else { logAction("Not enough money to buy Soldier!"); } break; case "Planner": if(money >= COST_PLANNER) { addMoney(-COST_PLANNER, "Buy Planner"); let c = createCitizen(randomName(), worldX, worldY, "Planner"); citizens.push(c); logAction(`Purchased new Planner @(${Math.floor(worldX)},${Math.floor(worldY)})`); } else { logAction("Not enough money to buy Planner!"); } break; case "Spawner": if(money >= COST_SPAWNER) { addMoney(-COST_SPAWNER, "Buy Spawner"); let spawnBuild = { buildingType: "Spawner", x: worldX, y: worldY, completed: true, lastSpawnTime: frameCount }; buildings.push(spawnBuild); logAction(`Purchased Spawner @(${Math.floor(worldX)},${Math.floor(worldY)})`); } else { logAction("Not enough money to buy Spawner!"); } break; case "Tree": if(money >= COST_TREE) { addMoney(-COST_TREE, "Buy Tree"); let t = createResource("Tree", worldX, worldY, 100); resources.push(t); logAction(`Purchased a new Tree @(${Math.floor(worldX)},${Math.floor(worldY)})`); } else { logAction("Not enough money to buy Tree!"); } break; } purchaseMode = null; }); }