From e87032305ba1639aad983715da50ef9bec6adbc5 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 17 Nov 2025 10:54:37 +0000 Subject: [PATCH] fix: Ensure each connecting room has minimum 1 GU overlap with parent Updated room positioning to verify overlap for EACH connected room after grid alignment, not just the group as a whole. This fixes layouts like: 122 00 Where room 1 was previously positioned with no overlap to room 0. Changes: - positionNorthMultiple/positionSouthMultiple: After centering and aligning group, check first and last room overlap. If insufficient, shift entire group to ensure minimum overlap for each room. - positionEastMultiple/positionWestMultiple: Same approach for vertical stacking along east/west edges. The algorithm now: 1. Centers the group of connecting rooms over parent 2. Aligns starting position to grid 3. Checks if first room has >= 1 GU overlap, adjusts if not 4. Checks if last room has >= 1 GU overlap, adjusts if not 5. Positions all rooms from the adjusted aligned start This guarantees each connecting room overlaps with the parent room by at least one Grid Unit, ensuring proper door placement and room connectivity. --- js/core/rooms.js | 163 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 121 insertions(+), 42 deletions(-) diff --git a/js/core/rooms.js b/js/core/rooms.js index bd4018f..947c5c6 100644 --- a/js/core/rooms.js +++ b/js/core/rooms.js @@ -1061,32 +1061,51 @@ function positionNorthMultiple(currentRoom, connectedRooms, currentPos, dimensio }, 0); // Calculate starting X position to center the group over current room - // This ensures connected rooms are distributed along current room's edge const groupStartX = currentPos.x + (currentDim.widthPx - totalWidth) / 2; // Align the starting position to grid - // All rooms will be placed from this aligned start without individual alignment - // since room widths are multiples of grid units - const alignedGroupStart = alignToGrid(groupStartX, 0); + let alignedStartX = alignToGrid(groupStartX, 0).x; - // Position each room side-by-side starting from aligned position - // No individual alignment needed - rooms naturally align when placed from grid-aligned start - let currentX = alignedGroupStart.x; + // CRITICAL: Ensure each room has at least 1 GU overlap with parent room + // After grid alignment, check if all rooms will have minimum overlap + const minOverlap = GRID_UNIT_WIDTH_PX; + + // Check first room overlap + const firstDim = dimensions[connectedRooms[0]]; + const firstRoomEnd = alignedStartX + firstDim.widthPx; + const firstOverlap = Math.min(firstRoomEnd, currentPos.x + currentDim.widthPx) - Math.max(alignedStartX, currentPos.x); + + if (firstOverlap < minOverlap) { + // First room doesn't have enough overlap, shift group to the right + alignedStartX = currentPos.x - firstDim.widthPx + minOverlap; + alignedStartX = alignToGrid(alignedStartX, 0).x; + } + + // Check last room overlap (after potential adjustment for first room) + const lastRoomStartX = alignedStartX + totalWidth - dimensions[connectedRooms[connectedRooms.length - 1]].widthPx; + const lastRoomEndX = alignedStartX + totalWidth; + const lastOverlap = Math.min(lastRoomEndX, currentPos.x + currentDim.widthPx) - Math.max(lastRoomStartX, currentPos.x); + + if (lastOverlap < minOverlap) { + // Last room doesn't have enough overlap, shift group to the left + const lastDim = dimensions[connectedRooms[connectedRooms.length - 1]]; + alignedStartX = currentPos.x + currentDim.widthPx - totalWidth - lastDim.widthPx + minOverlap; + alignedStartX = alignToGrid(alignedStartX, 0).x; + } + + // Position each room side-by-side starting from adjusted aligned position + let currentX = alignedStartX; connectedRooms.forEach(roomId => { const connectedDim = dimensions[roomId]; // Calculate Y position based on room's stacking height const roomY = currentPos.y - connectedDim.stackingHeightPx; - - // Align Y to grid const alignedY = alignToGrid(0, roomY).y; - // X is already aligned via group start, just use currentX positions[roomId] = { x: currentX, y: alignedY }; - // Move X position for next room (no individual alignment) - // Since room widths are multiples of grid units, this maintains alignment + // Move X position for next room currentX += connectedDim.widthPx; }); @@ -1122,27 +1141,48 @@ function positionSouthMultiple(currentRoom, connectedRooms, currentPos, dimensio }, 0); // Calculate starting X position to center the group over current room - // This ensures connected rooms are distributed along current room's edge const groupStartX = currentPos.x + (currentDim.widthPx - totalWidth) / 2; // Align the starting position to grid - // All rooms will be placed from this aligned start without individual alignment - const alignedGroupStart = alignToGrid(groupStartX, 0); + let alignedStartX = alignToGrid(groupStartX, 0).x; - // Position each room side-by-side starting from aligned position - let currentX = alignedGroupStart.x; + // CRITICAL: Ensure each room has at least 1 GU overlap with parent room + const minOverlap = GRID_UNIT_WIDTH_PX; + + // Check first room overlap + const firstDim = dimensions[connectedRooms[0]]; + const firstRoomEnd = alignedStartX + firstDim.widthPx; + const firstOverlap = Math.min(firstRoomEnd, currentPos.x + currentDim.widthPx) - Math.max(alignedStartX, currentPos.x); + + if (firstOverlap < minOverlap) { + // First room doesn't have enough overlap, shift group to the right + alignedStartX = currentPos.x - firstDim.widthPx + minOverlap; + alignedStartX = alignToGrid(alignedStartX, 0).x; + } + + // Check last room overlap + const lastRoomStartX = alignedStartX + totalWidth - dimensions[connectedRooms[connectedRooms.length - 1]].widthPx; + const lastRoomEndX = alignedStartX + totalWidth; + const lastOverlap = Math.min(lastRoomEndX, currentPos.x + currentDim.widthPx) - Math.max(lastRoomStartX, currentPos.x); + + if (lastOverlap < minOverlap) { + // Last room doesn't have enough overlap, shift group to the left + const lastDim = dimensions[connectedRooms[connectedRooms.length - 1]]; + alignedStartX = currentPos.x + currentDim.widthPx - totalWidth - lastDim.widthPx + minOverlap; + alignedStartX = alignToGrid(alignedStartX, 0).x; + } + + // Position each room side-by-side + let currentX = alignedStartX; const y = currentPos.y + currentDim.stackingHeightPx; - - // Align Y to grid const alignedY = alignToGrid(0, y).y; connectedRooms.forEach(roomId => { const connectedDim = dimensions[roomId]; - // X is already aligned via group start, Y is same for all rooms positions[roomId] = { x: currentX, y: alignedY }; - // Move X position for next room (no individual alignment) + // Move X position for next room currentX += connectedDim.widthPx; }); @@ -1178,29 +1218,48 @@ function positionEastMultiple(currentRoom, connectedRooms, currentPos, dimension }, 0); // Calculate starting Y position to center the group along current room's edge - // This ensures connected rooms are distributed along current room's edge const groupStartY = currentPos.y + (currentDim.stackingHeightPx - totalHeight) / 2; // Align the starting position to grid - // All rooms will be placed from this aligned start without individual alignment - const alignedGroupStart = alignToGrid(0, groupStartY); + let alignedStartY = alignToGrid(0, groupStartY).y; - // Position each room stacked vertically starting from aligned position + // CRITICAL: Ensure each room has at least 1 GU overlap with parent room + const minOverlap = GRID_UNIT_HEIGHT_PX; + + // Check first room overlap + const firstDim = dimensions[connectedRooms[0]]; + const firstRoomEnd = alignedStartY + firstDim.stackingHeightPx; + const firstOverlap = Math.min(firstRoomEnd, currentPos.y + currentDim.stackingHeightPx) - Math.max(alignedStartY, currentPos.y); + + if (firstOverlap < minOverlap) { + // First room doesn't have enough overlap, shift group down + alignedStartY = currentPos.y - firstDim.stackingHeightPx + minOverlap; + alignedStartY = alignToGrid(0, alignedStartY).y; + } + + // Check last room overlap + const lastRoomStartY = alignedStartY + totalHeight - dimensions[connectedRooms[connectedRooms.length - 1]].stackingHeightPx; + const lastRoomEndY = alignedStartY + totalHeight; + const lastOverlap = Math.min(lastRoomEndY, currentPos.y + currentDim.stackingHeightPx) - Math.max(lastRoomStartY, currentPos.y); + + if (lastOverlap < minOverlap) { + // Last room doesn't have enough overlap, shift group up + const lastDim = dimensions[connectedRooms[connectedRooms.length - 1]]; + alignedStartY = currentPos.y + currentDim.stackingHeightPx - totalHeight - lastDim.stackingHeightPx + minOverlap; + alignedStartY = alignToGrid(0, alignedStartY).y; + } + + // Position each room stacked vertically const x = currentPos.x + currentDim.widthPx; - - // Align X to grid const alignedX = alignToGrid(x, 0).x; - - let currentY = alignedGroupStart.y; + let currentY = alignedStartY; connectedRooms.forEach(roomId => { const connectedDim = dimensions[roomId]; - // Y is already aligned via group start, X is same for all rooms positions[roomId] = { x: alignedX, y: currentY }; - // Move Y position for next room (no individual alignment) - // Since room heights are multiples of grid units, this maintains alignment + // Move Y position for next room currentY += connectedDim.stackingHeightPx; }); @@ -1235,30 +1294,50 @@ function positionWestMultiple(currentRoom, connectedRooms, currentPos, dimension }, 0); // Calculate starting Y position to center the group along current room's edge - // This ensures connected rooms are distributed along current room's edge const groupStartY = currentPos.y + (currentDim.stackingHeightPx - totalHeight) / 2; // Align the starting position to grid - // All rooms will be placed from this aligned start without individual alignment - const alignedGroupStart = alignToGrid(0, groupStartY); + let alignedStartY = alignToGrid(0, groupStartY).y; - // Position each room stacked vertically starting from aligned position - let currentY = alignedGroupStart.y; + // CRITICAL: Ensure each room has at least 1 GU overlap with parent room + const minOverlap = GRID_UNIT_HEIGHT_PX; + + // Check first room overlap + const firstDim = dimensions[connectedRooms[0]]; + const firstRoomEnd = alignedStartY + firstDim.stackingHeightPx; + const firstOverlap = Math.min(firstRoomEnd, currentPos.y + currentDim.stackingHeightPx) - Math.max(alignedStartY, currentPos.y); + + if (firstOverlap < minOverlap) { + // First room doesn't have enough overlap, shift group down + alignedStartY = currentPos.y - firstDim.stackingHeightPx + minOverlap; + alignedStartY = alignToGrid(0, alignedStartY).y; + } + + // Check last room overlap + const lastRoomStartY = alignedStartY + totalHeight - dimensions[connectedRooms[connectedRooms.length - 1]].stackingHeightPx; + const lastRoomEndY = alignedStartY + totalHeight; + const lastOverlap = Math.min(lastRoomEndY, currentPos.y + currentDim.stackingHeightPx) - Math.max(lastRoomStartY, currentPos.y); + + if (lastOverlap < minOverlap) { + // Last room doesn't have enough overlap, shift group up + const lastDim = dimensions[connectedRooms[connectedRooms.length - 1]]; + alignedStartY = currentPos.y + currentDim.stackingHeightPx - totalHeight - lastDim.stackingHeightPx + minOverlap; + alignedStartY = alignToGrid(0, alignedStartY).y; + } + + // Position each room stacked vertically + let currentY = alignedStartY; connectedRooms.forEach(roomId => { const connectedDim = dimensions[roomId]; // Position to the left const x = currentPos.x - connectedDim.widthPx; - - // Align X to grid const alignedX = alignToGrid(x, 0).x; - // Y is already aligned via group start positions[roomId] = { x: alignedX, y: currentY }; - // Move Y position for next room (no individual alignment) - // Since room heights are multiples of grid units, this maintains alignment + // Move Y position for next room currentY += connectedDim.stackingHeightPx; });