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) {
|
function plantFruitTreeTask(cit) {
|
||||||
let px = cit.x + randInt(-50, 50);
|
// Try to find a valid land position nearby
|
||||||
let py = cit.y + randInt(-50, 50);
|
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);
|
moveToward(cit, px, py, 0.4);
|
||||||
if(distance(cit.x, cit.y, px, py) < 10) {
|
if(distance(cit.x, cit.y, px, py) < 10) {
|
||||||
if(cit.carryingFruit >= FRUIT_PLANT_COST) {
|
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
|
* PAN & ZOOM
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
@ -20,6 +24,13 @@ function setupPanZoom() {
|
|||||||
lastMouseX = e.clientX;
|
lastMouseX = e.clientX;
|
||||||
lastMouseY = e.clientY;
|
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) => {
|
canvas.addEventListener('wheel', (e) => {
|
||||||
@ -127,6 +138,12 @@ function setupCanvasClick() {
|
|||||||
let worldX = (cx - (canvas.width/2) - offsetX) / scale;
|
let worldX = (cx - (canvas.width/2) - offsetX) / scale;
|
||||||
let worldY = (cy - (canvas.height/2) - offsetY) / 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) {
|
switch(purchaseMode) {
|
||||||
case "House":
|
case "House":
|
||||||
if(money >= COST_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
|
* INIT WORLD
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
function initWorld() {
|
function initWorld() {
|
||||||
// Normal trees
|
// Normal trees - only on land
|
||||||
for(let i=0; i<15; i++) {
|
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++) {
|
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"
|
// Start with 1 citizen => always a "Builder" - only on land
|
||||||
let c = createCitizen(randomName(), randInt(-200,200), randInt(-200,200), "Builder");
|
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);
|
citizens.push(c);
|
||||||
logAction(`Initial Citizen joined: ${c.name} [Builder]`);
|
logAction(`Initial Citizen joined: ${c.name} [Builder]`);
|
||||||
|
|
||||||
// Spawn some animals
|
// Spawn some animals - only on land
|
||||||
for(let i=0; i<STARTING_RABBITS; i++) {
|
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++) {
|
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);
|
requestAnimationFrame(update);
|
||||||
|
36
render.js
36
render.js
@ -31,6 +31,42 @@ function drawWorld() {
|
|||||||
animals.forEach((ani) => {
|
animals.forEach((ani) => {
|
||||||
if(!ani.dead) drawAnimal(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() {
|
function drawTerrain() {
|
||||||
|
@ -109,8 +109,8 @@ function generateTerrain(width, height, scale) {
|
|||||||
value /= 1.75; // Normalize
|
value /= 1.75; // Normalize
|
||||||
|
|
||||||
// Determine terrain type based on noise value
|
// Determine terrain type based on noise value
|
||||||
// Increase water threshold to create more water areas
|
// Lower water threshold to create more land areas
|
||||||
if (value < 0.0) {
|
if (value < -0.3) { // Changed from 0.0 to -0.3 to reduce water
|
||||||
terrain[x][y] = TERRAIN_WATER;
|
terrain[x][y] = TERRAIN_WATER;
|
||||||
} else {
|
} else {
|
||||||
terrain[x][y] = TERRAIN_GRASS;
|
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
|
* FINDERS
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user