🆕 Brand new Floorplan

This commit is contained in:
duckietm
2026-05-26 16:38:01 +02:00
parent 4f0a8be2b0
commit bf0a73eaf8
24 changed files with 482 additions and 245 deletions
@@ -10,29 +10,105 @@ type Props = {
tile: Tile;
selected: boolean;
isDoor: boolean;
southH?: number;
westH?: number;
};
const HEIGHT_LIFT = TILE_SIZE / 8;
const diamondPoints = (row: number, col: number, h: number): string =>
{
const [ cx, cyBase ] = tileToScreen(row, col);
const cy = cyBase - h * (TILE_SIZE / 8);
const cy = cyBase - h * HEIGHT_LIFT;
const half = TILE_SIZE / 2;
const quarter = TILE_SIZE / 4;
// Diamond corners: top, right, bottom, left
return `${ cx },${ cy - quarter } ${ cx + half },${ cy } ${ cx },${ cy + quarter } ${ cx - half },${ cy }`;
};
const FloorplanTileImpl: FC<Props> = ({ row, col, tile, selected, isDoor }) =>
const darkenHex = (hex: string, factor: number): string =>
{
if(tile.blocked) return null;
const h = hex.replace('#', '');
if(h.length !== 6) return hex;
const r = Math.max(0, Math.floor(parseInt(h.slice(0, 2), 16) * factor));
const g = Math.max(0, Math.floor(parseInt(h.slice(2, 4), 16) * factor));
const b = Math.max(0, Math.floor(parseInt(h.slice(4, 6), 16) * factor));
return `#${ [ r, g, b ].map(v => v.toString(16).padStart(2, '0')).join('') }`;
};
const southWallPoints = (cx: number, cy: number, drop: number): string =>
{
const half = TILE_SIZE / 2;
const quarter = TILE_SIZE / 4;
return `${ cx + half },${ cy } ${ cx + half },${ cy + drop } ${ cx },${ cy + quarter + drop } ${ cx },${ cy + quarter }`;
};
const westWallPoints = (cx: number, cy: number, drop: number): string =>
{
const half = TILE_SIZE / 2;
const quarter = TILE_SIZE / 4;
return `${ cx - half },${ cy } ${ cx },${ cy + quarter } ${ cx },${ cy + quarter + drop } ${ cx - half },${ cy + drop }`;
};
const FloorplanTileImpl: FC<Props> = ({ row, col, tile, selected, isDoor, southH = 0, westH = 0 }) =>
{
if(tile.blocked)
{
if(!selected) return null;
const points = diamondPoints(row, col, tile.h);
return (
<polygon
data-testid="selection-ring"
points={ points }
fill="rgba(250, 204, 21, 0.45)"
stroke="#facc15"
strokeWidth={ 1.5 }
strokeDasharray="3 2"
/>
);
}
const points = diamondPoints(row, col, tile.h);
const fill = tileFill(tile);
const [ cx, cyBase ] = tileToScreen(row, col);
const cy = cyBase - tile.h * HEIGHT_LIFT;
const southDrop = Math.max(0, tile.h - southH) * HEIGHT_LIFT;
const westDrop = Math.max(0, tile.h - westH) * HEIGHT_LIFT;
const southFill = (southDrop > 0) ? darkenHex(fill, 0.70) : null;
const westFill = (westDrop > 0) ? darkenHex(fill, 0.55) : null;
return (
<g>
<polygon points={ points } fill={ fill } stroke="#222" strokeWidth={ 0.5 } />
{ southFill && (
<polygon
data-testid="tile-south-wall"
points={ southWallPoints(cx, cy, southDrop) }
fill={ southFill }
stroke="#222"
strokeWidth={ 0.5 }
/>
) }
{ westFill && (
<polygon
data-testid="tile-west-wall"
points={ westWallPoints(cx, cy, westDrop) }
fill={ westFill }
stroke="#222"
strokeWidth={ 0.5 }
/>
) }
<polygon
data-row={ row }
data-col={ col }
points={ points }
fill={ fill }
stroke="#222"
strokeWidth={ 0.5 }
/>
{ selected && (
<polygon
data-testid="selection-ring"
data-row={ row }
data-col={ col }
points={ points }
fill="none"
stroke="#fff"
@@ -43,6 +119,8 @@ const FloorplanTileImpl: FC<Props> = ({ row, col, tile, selected, isDoor }) =>
{ isDoor && (
<polygon
data-testid="door-marker"
data-row={ row }
data-col={ col }
points={ points }
fill="rgba(255,255,255,0.85)"
stroke="#000"