diff --git a/src/map-construct/layer.ts b/src/map-construct/layer.ts new file mode 100644 index 0000000..9ce8e6e --- /dev/null +++ b/src/map-construct/layer.ts @@ -0,0 +1,110 @@ +import { MapThemeConfig } from "../map-construct/theme" +import { Coll } from "../util/map" +import { Array2d } from "../util/util" + +export interface MapConstructionLayers { + background: number[][][] + shadow: number[][] + light: number[][] + coll: number[][][] + nav: number[][][] +} + +export function emptyLayer( + size: Vec2, + fill: number, + rest: Pick +): sc.MapModel.MapLayer { + return { + visible: 1, + repeat: false, + distance: 1, + yDistance: 0, + tilesize: 16, + moveSpeed: { x: 0, y: 0 }, + lighter: false, + id: -10, + + data: Array2d.empty(size, fill), + width: size.x, + height: size.y, + ...rest, + } +} + +export function getEmptyLayers( + size: Vec2, + levelCount: number, + theme: MapThemeConfig +): { layers: MapConstructionLayers; levels: sc.MapModel.Map['levels']; layer: sc.MapModel.MapLayer[] } { + const layer: sc.MapModel.MapLayer[] = [] + const levels: sc.MapModel.Map['levels'] = [] + + let background: number[][][] = [], + shadow: number[][] = [], + coll: number[][][] = [], + nav: number[][][] = [] + + for (let level = 0; level < levelCount; level++) { + levels.push({ height: level * 16 * 2 }) + + const backgroundLayer = emptyLayer(size, level == 0 ? theme.blackTile : 0, { + type: 'Background', + name: 'NEW_BACKGROUND', + tilesetName: theme.tileset, + level, + }) + + background.push(backgroundLayer.data) + layer.push(backgroundLayer) + + if (level == 0 && theme.addShadows) { + const shadowLayer = emptyLayer(size, 0, { + name: 'NEW_SHADOW', + type: 'Background', + tilesetName: theme.shadowTileset, + level, + }) + shadow = shadowLayer.data + layer.push(shadowLayer) + } + const collisionLayer = emptyLayer(size, Coll.Wall, { + name: 'NEW_COLLISION', + type: 'Collision', + tilesetName: 'media/map/collisiontiles-16x16.png', + level, + }) + coll.push(collisionLayer.data) + layer.push(collisionLayer) + + const navigationLayer = emptyLayer(size, 0, { + name: 'NEW_NAVIGATION', + type: 'Navigation', + tilesetName: 'media/map/pathmap-tiles.png', + level, + }) + nav.push(navigationLayer.data) + layer.push(navigationLayer) + } + + const lightLayer = emptyLayer(size, 0, { + name: 'NEW_LIGHT', + type: 'Light', + tilesetName: 'media/map/lightmap-tiles.png', + level: 'last', + }) + const light: number[][] = lightLayer.data + layer.push(lightLayer) + + return { + layers: { + background, + shadow, + light, + coll, + nav, + }, + levels, + layer, + } +} diff --git a/src/map-construct/map-construct.ts b/src/map-construct/map-construct.ts index bd4aeeb..cacc43a 100644 --- a/src/map-construct/map-construct.ts +++ b/src/map-construct/map-construct.ts @@ -1,14 +1,16 @@ -import { copyMapArrange, MapArrange, RoomArrange } from '../map-arrange/map-arrange' +import { copyMapArrange, MapArrange, offsetMapArrange } from '../map-arrange/map-arrange' import { MapPicker } from '../map-arrange/map-picker/configurable' import { Id } from '../build-queue/build-queue' import { assert } from '../util/util' import { Item } from '../util/items' -import { Rect } from '../util/geometry' +import { Dir, Rect } from '../util/geometry' +import { MapConstructionLayers } from './layer' +import { getEmptyLayers } from './layer' +import { MapTheme } from './theme' export interface MapConstruct extends MapArrange { constructed: sc.MapModel.Map - rectsAbsolute: RoomArrange[] - bounds: Rect + rectsAbsolute: Rect[] title: string } @@ -49,3 +51,45 @@ export function constructMapsFromMapsArrange(maps: MapArrange[], areaInfo: AreaI return mapsConstruct } + +export interface MapInConstruction extends sc.MapModel.Map { + layers: MapConstructionLayers +} + +export function baseMapConstruct( + map: MapArrange, + mapName: string, + areaId: string, + theme: MapTheme +): { mic: MapInConstruction; rectsAbsolute: Rect[] } { + const rectsAbsolute = map.rects.map(Rect.copy) + + const boundsEntity = Rect.boundsOfArr(map.rects) + + Rect.extend(boundsEntity, 7 * 16, { [Dir.NORTH]: true }) + Rect.extend(boundsEntity, 1 * 16, [false, true, true, true]) + const offset = Vec2.mulC(boundsEntity, -1) + + offsetMapArrange(map, offset) + + const bounds = Rect.div(Rect.copy(boundsEntity), 16) + + const mapSize: Vec2 = Rect.toTwoVecSize(bounds)[1] + + const mic: MapInConstruction = { + name: mapName, + mapWidth: mapSize.x, + mapHeight: mapSize.y, + masterLevel: 0, + attributes: theme.getMapAttributes(areaId), + screen: { x: 0, y: 0 }, + entities: [], + + ...getEmptyLayers(mapSize, 3, theme.config), + } + return { mic, rectsAbsolute } +} + +export function getTprName(isEntrance: boolean, index: number): string { + return `${isEntrance ? 'entrance' : 'rest'}_${index}` +} diff --git a/src/map-construct/room.ts b/src/map-construct/room.ts new file mode 100644 index 0000000..5546f28 --- /dev/null +++ b/src/map-construct/room.ts @@ -0,0 +1,236 @@ +import { RoomArrange } from '../map-arrange/map-arrange' +import { Rect, Dir } from '../util/geometry' +import { Coll } from '../util/map' +import { Array2d, assert } from '../util/util' +import { MapInConstruction } from './map-construct' +import { MapThemeConfig } from './theme' + +export function placeRoom(room: RoomArrange, map: MapInConstruction, tc: MapThemeConfig, addNavMap: boolean) { + const rect = Rect.div(Rect.copy(room), 16) + const { x: rx, y: ry } = rect + const { x: rx2, y: ry2 } = Rect.x2y2(rect) + const background = map.layers.background[0] + const shadow = map.layers.shadow + const light = map.layers.light + const colls = map.layers.coll + const navs = map.layers.nav + + // draw floor + for (let y = ry; y < ry2; y++) { + for (let x = rx; x < rx2; x++) { + background[y][x] = tc.floorTile + if (tc.addShadows) { + shadow![y][x] = 0 + } + for (const coll of colls) { + coll[y][x] = 0 + } + light[y][x] = 0 + if (addNavMap) { + for (const nav of navs) { + nav[y][x] = 1 + } + } + } + } + + if (room.walls[Dir.NORTH]) { + for (let x = rx; x < rx2; x++) { + placeWall(map, tc, { x, y: ry }, Dir.NORTH) + } + } else if (tc.addShadows) { + Array2d.pasteInto(shadow, tc.edgeShadowBottomLeft!, rx, ry - 2) + Array2d.pasteInto(shadow, tc.edgeShadowBottomRight!, rx2 - 2, ry - 2) + for (let x = rx + 2; x < rx2 - 2; x++) { + for (let y = ry - 2; y < ry; y++) { + shadow![y][x] = 0 + } + } + } + + if (room.walls[Dir.EAST]) { + for (let y = ry; y < ry2; y++) { + placeWall(map, tc, { x: rx2, y }, Dir.EAST) + } + } else if (tc.addShadows) { + Array2d.pasteInto(shadow!, tc.edgeShadowTopLeft!, rx2, ry) + Array2d.pasteInto(shadow!, tc.edgeShadowBottomLeft!, rx2, ry2 - 2) + for (let y = ry + 2; y < ry2 - 2; y++) { + for (let x = rx2; x < rx2 + 2; x++) { + shadow![y][x] = 0 + } + } + } + + if (room.walls[Dir.SOUTH]) { + for (let x = rx; x < rx2; x++) { + placeWall(map, tc, { x, y: ry2 }, Dir.SOUTH) + } + } else if (tc.addShadows) { + Array2d.pasteInto(shadow!, tc.edgeShadowTopLeft!, rx, ry2) + Array2d.pasteInto(shadow!, tc.edgeShadowTopRight!, rx2 - 2, ry2) + for (let x = rx + 2; x < rx2 - 2; x++) { + for (let y = ry2; y < ry2 + 2; y++) { + shadow![y][x] = 0 + } + } + } + + if (room.walls[Dir.WEST]) { + for (let y = ry; y < ry2; y++) { + placeWall(map, tc, { x: rx, y }, Dir.WEST) + } + } else if (tc.addShadows) { + Array2d.pasteInto(shadow!, tc.edgeShadowTopRight!, rx - 2, ry) + Array2d.pasteInto(shadow!, tc.edgeShadowBottomRight!, rx - 2, ry2 - 2) + for (let y = ry + 2; y < ry2 - 2; y++) { + for (let x = rx - 2; x < rx; x++) { + shadow![y][x] = 0 + } + } + } + + if (tc.addShadows) { + // fix shadow corners + if (room.walls[Dir.NORTH] && room.walls[Dir.WEST]) { + Array2d.pasteInto(shadow!, tc.cornerShadowTopLeft!, rx, ry) + } + if (room.walls[Dir.NORTH] && room.walls[Dir.EAST]) { + Array2d.pasteInto(shadow!, tc.cornerShadowTopRight!, rx2 - 2, ry) + } + if (room.walls[Dir.SOUTH] && room.walls[Dir.WEST]) { + Array2d.pasteInto(shadow!, tc.cornerShadowBottomLeft!, rx, ry2 - 2) + } + if (room.walls[Dir.SOUTH] && room.walls[Dir.EAST]) { + Array2d.pasteInto(shadow!, tc.cornerShadowBottomRight!, rx2 - 2, ry2 - 2) + } + } + + if (tc.addLight) { + assert(tc.lightStep) + assert(tc.lightTile) + const distFromWall = 5 + const lx1 = rx + distFromWall - 1 + const ly1 = ry + distFromWall - 1 + const lx2 = rx2 - distFromWall + const ly2 = ry2 - distFromWall + + const mx = Math.floor(lx1 + (lx2 - lx1) / 2) + const my = Math.floor(ly1 + (ly2 - ly1) / 2) + light[my][mx] = tc.lightTile + + for (let x = lx1; x <= mx; x += tc.lightStep) { + for (let y = ly1; y <= my; y += tc.lightStep) { + light[y][x] = tc.lightTile + } + for (let y = ly2; y >= my; y -= tc.lightStep) { + light[y][x] = tc.lightTile + } + light[my][x] = tc.lightTile + } + for (let x = lx2; x >= mx; x -= tc.lightStep) { + for (let y = ly1; y <= my; y += tc.lightStep) { + light[y][x] = tc.lightTile + } + for (let y = ly2; y >= my; y -= tc.lightStep) { + light[y][x] = tc.lightTile + } + light[my][x] = tc.lightTile + } + + for (let y = ly1; y <= ly2; y += tc.lightStep) { + light[y][mx] = tc.lightTile + } + for (let y = ly2; y >= my; y -= tc.lightStep) { + light[y][mx] = tc.lightTile + } + } +} + +export function placeWall(map: MapInConstruction, tc: MapThemeConfig, pos: Vec2, dir: Dir): void { + const background = map.layers.background[0] + const shadow = map.layers.shadow + const colls = map.layers.coll + + switch (dir) { + case Dir.NORTH: { + for (let i = 0; i < tc.wallUp.length; i++) { + const y = pos.y - i + 1 + if (tc.wallUp[i]) { + background[y][pos.x] = tc.wallUp[i] + } + if (tc.addShadows && tc.wallUpShadow![i]) { + shadow![y][pos.x] = tc.wallUpShadow![i] + } + } + for (let i = map.masterLevel; i < colls.length; i++) { + const ri = i - map.masterLevel + const coll: number[][] = colls[i] + for (let y = pos.y - 3; y <= pos.y; y++) { + coll[y - ri * 2][pos.x] = Coll.None + } + let y: number = pos.y - ri * 2 - 1 + coll[y][pos.x] = Coll.Wall + } + break + } + case Dir.EAST: { + for (let i = 0; i < tc.wallRight.length; i++) { + const x = pos.x - tc.wallRight.length + i + 1 + if (tc.wallRight[i]) { + if (!background[pos.y][x]) { + background[pos.y][x] = tc.wallRight[i] + } + + for (const coll of colls) { + coll[pos.y][x] = Coll.Wall + coll[pos.y][x + 1] = Coll.Wall + } + } + if (tc.addShadows && tc.wallRightShadow![i]) { + shadow![pos.y][x] = tc.wallRightShadow![i] + } + } + break + } + case Dir.SOUTH: { + for (let i = 0; i < tc.wallDown.length; i++) { + const y = pos.y - tc.wallDown.length + i + 1 + if (tc.wallDown[i]) { + background[y][pos.x] = tc.wallDown[i] + } + if (tc.addShadows && tc.wallDownShadow![i]) { + shadow![y][pos.x] = tc.wallDownShadow![i] + } + } + for (let i = map.masterLevel; i < colls.length; i++) { + const ri = i - map.masterLevel + const coll: number[][] = colls[i] + for (let y = pos.y; y >= pos.y - 3; y--) { + coll[y - ri * 2][pos.x] = Coll.None + } + const y: number = pos.y - ri * 2 + coll[y][pos.x] = Coll.Wall + } + break + } + case Dir.WEST: { + for (let i = 0; i < tc.wallLeft.length; i++) { + const x = pos.x + i - 1 + if (tc.wallLeft[i]) { + if (!background[pos.y][x]) { + background[pos.y][x] = tc.wallLeft[i] + } + for (const coll of colls) { + coll[pos.y][x] = Coll.Wall + coll[pos.y][x - 1] = Coll.Wall + } + } + if (tc.addShadows && tc.wallLeftShadow![i]) { + shadow![pos.y][x] = tc.wallLeftShadow![i] + } + } + break + } + } +} diff --git a/src/map-construct/theme.ts b/src/map-construct/theme.ts index e592c02..f98d974 100644 --- a/src/map-construct/theme.ts +++ b/src/map-construct/theme.ts @@ -53,7 +53,7 @@ export class MapTheme { } } - static themes: Record = { + static themes = { 'rhombus-dng': new MapTheme({ bgm: 'puzzle', mapSounds: '', @@ -130,12 +130,12 @@ export class MapTheme { wallDown: [0, 0, 147], wallLeft: [135, 0, 0], }), - } + } as const satisfies Record static default: MapTheme = MapTheme.themes['rhombus-dng'] static fromArea(areaName: string): MapTheme { if (areaName in MapTheme.themes) { - return MapTheme.themes[areaName] + return MapTheme.themes[areaName as keyof typeof MapTheme.themes] } else { return MapTheme.default } diff --git a/src/maps/simple.ts b/src/maps/simple.ts index f8f9c9d..be23023 100644 --- a/src/maps/simple.ts +++ b/src/maps/simple.ts @@ -6,15 +6,14 @@ import { MapArrange, RoomArrange, doesMapArrangeFit, - offsetMapArrange, TprArrange3d, } from '../map-arrange/map-arrange' import { MapPicker, registerMapPickerNodeConfig } from '../map-arrange/map-picker/configurable' import { Dir, DirU, Rect } from '../util/geometry' -import { Array2d, assert, shuffleArray } from '../util/util' -import { registerMapConstructor } from '../map-construct/map-construct' -import { MapTheme, MapThemeConfig } from '../map-construct/theme' -import { Coll } from '../util/map' +import { shuffleArray } from '../util/util' +import { baseMapConstruct, getTprName, registerMapConstructor } from '../map-construct/map-construct' +import { placeRoom } from '../map-construct/room' +import { MapTheme } from '../map-construct/theme' declare global { export namespace MapPickerNodeConfigs { @@ -126,40 +125,17 @@ export function simpleMapArrange({ } registerMapConstructor('Simple', (map, areaInfo, pathResolver, _mapsArranged, _mapsConstructed) => { - const boundsEntity = Rect.boundsOfArr(map.rects) - const extend = 8 * 16 - const rectsAbsolute = map.rects.map(a => ({ ...a })) - - Rect.extend(boundsEntity, extend) - const offset = Vec2.mulC(boundsEntity, -1) - - offsetMapArrange(map, offset) - - const bounds = Rect.div(Rect.copy(boundsEntity), 16) - const theme = MapTheme.default - const mapSize: Vec2 = Rect.toTwoVecSize(bounds)[1] - - const mic: MapInConstruction = { - name: pathResolver(map.id), - mapWidth: mapSize.x, - mapHeight: mapSize.y, - masterLevel: 0, - attributes: theme.getMapAttributes(areaInfo.id), - screen: { x: 0, y: 0 }, - entities: [], - - ...getEmptyLayers(mapSize, 3, theme.config), - } + const { mic, rectsAbsolute } = baseMapConstruct(map, pathResolver(map.id), areaInfo.id, theme) function pushTprEntity(tpr: TprArrange3d, isEntrance: boolean, index: number) { const name = getTprName(isEntrance, index) const dir = DirU.flip(tpr.dir as Dir) if (tpr.destId == -1) { + const middle = Vec2.subC(Rect.middle(map.rects[0]), 16, 16) return mic.entities.push({ type: 'Marker', - x: tpr.x, - y: tpr.y, + ...middle, level: 0, settings: { name, dir: DirU.toString(dir) }, }) @@ -197,352 +173,7 @@ registerMapConstructor('Simple', (map, areaInfo, pathResolver, _mapsArranged, _m return { ...map, constructed, - bounds, rectsAbsolute, title: `map ${constructed.name}`, } }) - -function getTprName(isEntrance: boolean, index: number): string { - return `${isEntrance ? 'entrance' : 'rest'}_${index}` -} - -interface MapConstructionLayers { - background: number[][][] - shadow: number[][] - light: number[][] - coll: number[][][] - nav: number[][][] -} -interface MapInConstruction extends sc.MapModel.Map { - layers: MapConstructionLayers -} - -function emptyLayer( - size: Vec2, - fill: number, - rest: Pick -): sc.MapModel.MapLayer { - return { - visible: 1, - repeat: false, - distance: 1, - yDistance: 0, - tilesize: 16, - moveSpeed: { x: 0, y: 0 }, - lighter: false, - id: -10, - - data: Array2d.empty(size, fill), - width: size.x, - height: size.y, - ...rest, - } -} - -function getEmptyLayers( - size: Vec2, - levelCount: number, - theme: MapThemeConfig -): { layers: MapConstructionLayers; levels: sc.MapModel.Map['levels']; layer: sc.MapModel.MapLayer[] } { - const layer: sc.MapModel.MapLayer[] = [] - const levels: sc.MapModel.Map['levels'] = [] - - let background: number[][][] = [], - shadow: number[][] = [], - coll: number[][][] = [], - nav: number[][][] = [] - - for (let level = 0; level < levelCount; level++) { - levels.push({ height: level * 16 * 2 }) - - const backgroundLayer = emptyLayer(size, level == 0 ? theme.blackTile : 0, { - type: 'Background', - name: 'NEW_BACKGROUND', - tilesetName: theme.tileset, - level, - }) - - background.push(backgroundLayer.data) - layer.push(backgroundLayer) - - if (level == 0 && theme.addShadows) { - const shadowLayer = emptyLayer(size, 0, { - name: 'NEW_SHADOW', - type: 'Background', - tilesetName: theme.shadowTileset, - level, - }) - shadow = shadowLayer.data - layer.push(shadowLayer) - } - const collisionLayer = emptyLayer(size, Coll.Wall, { - name: 'NEW_COLLISION', - type: 'Collision', - tilesetName: 'media/map/collisiontiles-16x16.png', - level, - }) - coll.push(collisionLayer.data) - layer.push(collisionLayer) - - const navigationLayer = emptyLayer(size, 0, { - name: 'NEW_NAVIGATION', - type: 'Navigation', - tilesetName: 'media/map/pathmap-tiles.png', - level, - }) - nav.push(navigationLayer.data) - layer.push(navigationLayer) - } - - const lightLayer = emptyLayer(size, 0, { - name: 'NEW_LIGHT', - type: 'Light', - tilesetName: 'media/map/lightmap-tiles.png', - level: 'last', - }) - const light: number[][] = lightLayer.data - layer.push(lightLayer) - - return { - layers: { - background, - shadow, - light, - coll, - nav, - }, - levels, - layer, - } -} - -function placeRoom(room: RoomArrange, map: MapInConstruction, tc: MapThemeConfig, addNavMap: boolean) { - const rect = Rect.div(Rect.copy(room), 16) - const { x: rx, y: ry } = rect - const { x: rx2, y: ry2 } = Rect.x2y2(rect) - const background = map.layers.background[0] - const shadow = map.layers.shadow - const light = map.layers.light - const colls = map.layers.coll - const navs = map.layers.nav - - // draw floor - for (let y = ry; y < ry2; y++) { - for (let x = rx; x < rx2; x++) { - background[y][x] = tc.floorTile - if (tc.addShadows) { - shadow![y][x] = 0 - } - for (const coll of colls) { - coll[y][x] = 0 - } - light[y][x] = 0 - if (addNavMap) { - for (const nav of navs) { - nav[y][x] = 1 - } - } - } - } - - if (room.walls[Dir.NORTH]) { - for (let x = rx; x < rx2; x++) { - placeWall(map, tc, { x, y: ry }, Dir.NORTH) - } - } else if (tc.addShadows) { - Array2d.pasteInto(shadow, tc.edgeShadowBottomLeft!, rx, ry - 2) - Array2d.pasteInto(shadow, tc.edgeShadowBottomRight!, rx2 - 2, ry - 2) - for (let x = rx + 2; x < rx2 - 2; x++) { - for (let y = ry - 2; y < ry; y++) { - shadow![y][x] = 0 - } - } - } - - if (room.walls[Dir.EAST]) { - for (let y = ry; y < ry2; y++) { - placeWall(map, tc, { x: rx2, y }, Dir.EAST) - } - } else if (tc.addShadows) { - Array2d.pasteInto(shadow!, tc.edgeShadowTopLeft!, rx2, ry) - Array2d.pasteInto(shadow!, tc.edgeShadowBottomLeft!, rx2, ry2 - 2) - for (let y = ry + 2; y < ry2 - 2; y++) { - for (let x = rx2; x < rx2 + 2; x++) { - shadow![y][x] = 0 - } - } - } - - if (room.walls[Dir.SOUTH]) { - for (let x = rx; x < rx2; x++) { - placeWall(map, tc, { x, y: ry2 }, Dir.SOUTH) - } - } else if (tc.addShadows) { - Array2d.pasteInto(shadow!, tc.edgeShadowTopLeft!, rx, ry2) - Array2d.pasteInto(shadow!, tc.edgeShadowTopRight!, rx2 - 2, ry2) - for (let x = rx + 2; x < rx2 - 2; x++) { - for (let y = ry2; y < ry2 + 2; y++) { - shadow![y][x] = 0 - } - } - } - - if (room.walls[Dir.WEST]) { - for (let y = ry; y < ry2; y++) { - placeWall(map, tc, { x: rx, y }, Dir.WEST) - } - } else if (tc.addShadows) { - Array2d.pasteInto(shadow!, tc.edgeShadowTopRight!, rx - 2, ry) - Array2d.pasteInto(shadow!, tc.edgeShadowBottomRight!, rx - 2, ry2 - 2) - for (let y = ry + 2; y < ry2 - 2; y++) { - for (let x = rx - 2; x < rx; x++) { - shadow![y][x] = 0 - } - } - } - - if (tc.addShadows) { - // fix shadow corners - if (room.walls[Dir.NORTH] && room.walls[Dir.WEST]) { - Array2d.pasteInto(shadow!, tc.cornerShadowTopLeft!, rx, ry) - } - if (room.walls[Dir.NORTH] && room.walls[Dir.EAST]) { - Array2d.pasteInto(shadow!, tc.cornerShadowTopRight!, rx2 - 2, ry) - } - if (room.walls[Dir.SOUTH] && room.walls[Dir.WEST]) { - Array2d.pasteInto(shadow!, tc.cornerShadowBottomLeft!, rx, ry2 - 2) - } - if (room.walls[Dir.SOUTH] && room.walls[Dir.EAST]) { - Array2d.pasteInto(shadow!, tc.cornerShadowBottomRight!, rx2 - 2, ry2 - 2) - } - } - - if (tc.addLight) { - assert(tc.lightStep) - assert(tc.lightTile) - const distFromWall = 5 - const lx1 = rx + distFromWall - 1 - const ly1 = ry + distFromWall - 1 - const lx2 = rx2 - distFromWall - const ly2 = ry2 - distFromWall - - const mx = Math.floor(lx1 + (lx2 - lx1) / 2) - const my = Math.floor(ly1 + (ly2 - ly1) / 2) - light[my][mx] = tc.lightTile - - for (let x = lx1; x <= mx; x += tc.lightStep) { - for (let y = ly1; y <= my; y += tc.lightStep) { - light[y][x] = tc.lightTile - } - for (let y = ly2; y >= my; y -= tc.lightStep) { - light[y][x] = tc.lightTile - } - light[my][x] = tc.lightTile - } - for (let x = lx2; x >= mx; x -= tc.lightStep) { - for (let y = ly1; y <= my; y += tc.lightStep) { - light[y][x] = tc.lightTile - } - for (let y = ly2; y >= my; y -= tc.lightStep) { - light[y][x] = tc.lightTile - } - light[my][x] = tc.lightTile - } - - for (let y = ly1; y <= ly2; y += tc.lightStep) { - light[y][mx] = tc.lightTile - } - for (let y = ly2; y >= my; y -= tc.lightStep) { - light[y][mx] = tc.lightTile - } - } -} - -function placeWall(map: MapInConstruction, tc: MapThemeConfig, pos: Vec2, dir: Dir): void { - const background = map.layers.background[0] - const shadow = map.layers.shadow - const colls = map.layers.coll - - switch (dir) { - case Dir.NORTH: { - for (let i = 0; i < tc.wallUp.length; i++) { - const y = pos.y - i + 1 - if (tc.wallUp[i]) { - background[y][pos.x] = tc.wallUp[i] - } - if (tc.addShadows && tc.wallUpShadow![i]) { - shadow![y][pos.x] = tc.wallUpShadow![i] - } - } - for (let i = map.masterLevel; i < colls.length; i++) { - const ri = i - map.masterLevel - const coll: number[][] = colls[i] - for (let y = pos.y - 3; y <= pos.y; y++) { - coll[y - ri * 2][pos.x] = Coll.None - } - let y: number = pos.y - ri * 2 - 1 - coll[y][pos.x] = Coll.Wall - } - break - } - case Dir.EAST: { - for (let i = 0; i < tc.wallRight.length; i++) { - const x = pos.x - tc.wallRight.length + i + 1 - if (tc.wallRight[i]) { - if (!background[pos.y][x]) { - background[pos.y][x] = tc.wallRight[i] - } - - for (const coll of colls) { - coll[pos.y][x] = Coll.Wall - coll[pos.y][x + 1] = Coll.Wall - } - } - if (tc.addShadows && tc.wallRightShadow![i]) { - shadow![pos.y][x] = tc.wallRightShadow![i] - } - } - break - } - case Dir.SOUTH: { - for (let i = 0; i < tc.wallDown.length; i++) { - const y = pos.y - tc.wallDown.length + i + 1 - if (tc.wallDown[i]) { - background[y][pos.x] = tc.wallDown[i] - } - if (tc.addShadows && tc.wallDownShadow![i]) { - shadow![y][pos.x] = tc.wallDownShadow![i] - } - } - for (let i = map.masterLevel; i < colls.length; i++) { - const ri = i - map.masterLevel - const coll: number[][] = colls[i] - for (let y = pos.y; y >= pos.y - 3; y--) { - coll[y - ri * 2][pos.x] = Coll.None - } - const y: number = pos.y - ri * 2 - coll[y][pos.x] = Coll.Wall - } - break - } - case Dir.WEST: { - for (let i = 0; i < tc.wallLeft.length; i++) { - const x = pos.x + i - 1 - if (tc.wallLeft[i]) { - if (!background[pos.y][x]) { - background[pos.y][x] = tc.wallLeft[i] - } - for (const coll of colls) { - coll[pos.y][x] = Coll.Wall - coll[pos.y][x - 1] = Coll.Wall - } - } - if (tc.addShadows && tc.wallLeftShadow![i]) { - shadow![pos.y][x] = tc.wallLeftShadow![i] - } - } - break - } - } -} diff --git a/src/util/geometry.ts b/src/util/geometry.ts index 7da86d5..37b9043 100644 --- a/src/util/geometry.ts +++ b/src/util/geometry.ts @@ -161,11 +161,24 @@ export namespace Rect { } } /** Extends the `rect` by `num` on all sides */ - export function extend(rect: Rect, num: number): Rect { - rect.x -= num - rect.y -= num - rect.width += num * 2 - rect.height += num * 2 + export function extend(rect: Rect, num: number, dirs?: PartialRecord): Rect { + if (!dirs) { + rect.x -= num + rect.y -= num + rect.width += num * 2 + rect.height += num * 2 + return rect + } + if (dirs[Dir.WEST]) { + rect.x -= num + rect.width += num + } + if (dirs[Dir.NORTH]) { + rect.y -= num + rect.height += num + } + if (dirs[Dir.SOUTH]) rect.height += num + if (dirs[Dir.EAST]) rect.width += num return rect } export function corner(