feat: Prevent placing entities on water and improve land generation
This commit is contained in:
parent
cde5301c2b
commit
3fa8a695b3
17
ai.js
17
ai.js
@ -648,8 +648,21 @@ function deliverFruitTask(cit) {
|
||||
}
|
||||
|
||||
function plantFruitTreeTask(cit) {
|
||||
let px = cit.x + randInt(-50, 50);
|
||||
let py = cit.y + randInt(-50, 50);
|
||||
// Try to find a valid land position nearby
|
||||
let px, py;
|
||||
let attempts = 0;
|
||||
do {
|
||||
px = cit.x + randInt(-50, 50);
|
||||
py = cit.y + randInt(-50, 50);
|
||||
attempts++;
|
||||
// Give up after too many attempts and find a new task
|
||||
if (attempts > 20) {
|
||||
cit.task = null;
|
||||
cit.target = null;
|
||||
return;
|
||||
}
|
||||
} while (!isValidPlacement(px, py));
|
||||
|
||||
moveToward(cit, px, py, 0.4);
|
||||
if(distance(cit.x, cit.y, px, py) < 10) {
|
||||
if(cit.carryingFruit >= FRUIT_PLANT_COST) {
|
||||
|
17
events.js
17
events.js
@ -1,3 +1,7 @@
|
||||
// Track mouse position for placement indicator
|
||||
let lastMouseWorldX = null;
|
||||
let lastMouseWorldY = null;
|
||||
|
||||
/**********************************************************************
|
||||
* PAN & ZOOM
|
||||
**********************************************************************/
|
||||
@ -20,6 +24,13 @@ function setupPanZoom() {
|
||||
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) => {
|
||||
@ -127,6 +138,12 @@ function setupCanvasClick() {
|
||||
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) {
|
||||
|
44
game.js
44
game.js
@ -97,27 +97,53 @@ const WOLF_SPEED = 0.7; // Faster than rabbits
|
||||
* INIT WORLD
|
||||
**********************************************************************/
|
||||
function initWorld() {
|
||||
// Normal trees
|
||||
// Normal trees - only on land
|
||||
for(let i=0; i<15; i++) {
|
||||
resources.push(createResource("Tree", randInt(-1000,1000), randInt(-1000,1000), 100));
|
||||
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
|
||||
|
||||
// Fruit trees - only on land
|
||||
for(let i=0; i<10; i++) {
|
||||
resources.push(createResource("FruitTree", randInt(-1000,1000), randInt(-1000,1000), FRUIT_TREE_START_AMOUNT));
|
||||
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"
|
||||
let c = createCitizen(randomName(), randInt(-200,200), randInt(-200,200), "Builder");
|
||||
// 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
|
||||
// Spawn some animals - only on land
|
||||
for(let i=0; i<STARTING_RABBITS; i++) {
|
||||
animals.push(createAnimal("Rabbit", randInt(-1000,1000), randInt(-1000,1000)));
|
||||
let x, y;
|
||||
do {
|
||||
x = randInt(-1000,1000);
|
||||
y = randInt(-1000,1000);
|
||||
} while (!isValidPlacement(x, y));
|
||||
animals.push(createAnimal("Rabbit", x, y));
|
||||
}
|
||||
|
||||
for(let i=0; i<STARTING_WOLVES; i++) {
|
||||
animals.push(createAnimal("Wolf", randInt(-1000,1000), randInt(-1000,1000)));
|
||||
let x, y;
|
||||
do {
|
||||
x = randInt(-1000,1000);
|
||||
y = randInt(-1000,1000);
|
||||
} while (!isValidPlacement(x, y));
|
||||
animals.push(createAnimal("Wolf", x, y));
|
||||
}
|
||||
|
||||
requestAnimationFrame(update);
|
||||
|
36
render.js
36
render.js
@ -31,6 +31,42 @@ function drawWorld() {
|
||||
animals.forEach((ani) => {
|
||||
if(!ani.dead) drawAnimal(ani);
|
||||
});
|
||||
|
||||
// Draw placement indicator when in purchase mode
|
||||
if (purchaseMode) {
|
||||
drawPlacementIndicator();
|
||||
}
|
||||
}
|
||||
|
||||
// Draw a placement indicator at mouse position
|
||||
function drawPlacementIndicator() {
|
||||
if (!lastMouseWorldX || !lastMouseWorldY) return;
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(canvas.width/2 + offsetX, canvas.height/2 + offsetY);
|
||||
ctx.scale(scale, scale);
|
||||
|
||||
const isValid = isValidPlacement(lastMouseWorldX, lastMouseWorldY);
|
||||
|
||||
// Draw indicator circle
|
||||
ctx.beginPath();
|
||||
ctx.arc(lastMouseWorldX, lastMouseWorldY, 15, 0, Math.PI*2);
|
||||
ctx.strokeStyle = isValid ? "rgba(0, 255, 0, 0.7)" : "rgba(255, 0, 0, 0.7)";
|
||||
ctx.lineWidth = 2/scale;
|
||||
ctx.stroke();
|
||||
|
||||
// Draw X if invalid
|
||||
if (!isValid) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(lastMouseWorldX - 10, lastMouseWorldY - 10);
|
||||
ctx.lineTo(lastMouseWorldX + 10, lastMouseWorldY + 10);
|
||||
ctx.moveTo(lastMouseWorldX + 10, lastMouseWorldY - 10);
|
||||
ctx.lineTo(lastMouseWorldX - 10, lastMouseWorldY + 10);
|
||||
ctx.strokeStyle = "rgba(255, 0, 0, 0.7)";
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
function drawTerrain() {
|
||||
|
@ -109,8 +109,8 @@ function generateTerrain(width, height, scale) {
|
||||
value /= 1.75; // Normalize
|
||||
|
||||
// Determine terrain type based on noise value
|
||||
// Increase water threshold to create more water areas
|
||||
if (value < 0.0) {
|
||||
// Lower water threshold to create more land areas
|
||||
if (value < -0.3) { // Changed from 0.0 to -0.3 to reduce water
|
||||
terrain[x][y] = TERRAIN_WATER;
|
||||
} else {
|
||||
terrain[x][y] = TERRAIN_GRASS;
|
||||
|
8
utils.js
8
utils.js
@ -90,6 +90,14 @@ function knockback(ent, tx, ty, dist) {
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* PLACEMENT VALIDATION
|
||||
**********************************************************************/
|
||||
// Check if a position is valid for placement (not in water)
|
||||
function isValidPlacement(x, y) {
|
||||
return !isWater(x, y);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* FINDERS
|
||||
**********************************************************************/
|
||||
|
Loading…
x
Reference in New Issue
Block a user