445 lines
15 KiB
JavaScript
445 lines
15 KiB
JavaScript
// 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;
|
|
});
|
|
}
|