diff --git a/src/data/defs.tsx b/src/data/defs.tsx index 921d0f2..f5f2a82 100644 --- a/src/data/defs.tsx +++ b/src/data/defs.tsx @@ -470,6 +470,16 @@ export function setTileAttributesForTile( } +export function isTileIndexInBrush( + brush: DefTileBrush, + tileIndex: number) + : boolean +{ + const data = brush.tiles[tileIndex.toString()] + return data !== undefined +} + + export function getTileBrushData( brush: DefTileBrush, tileIndex: number) @@ -556,13 +566,11 @@ export function getTileBrushTopmostLeftmostTile( export function getTileBrushDefaultTile( - defs: Defs, brush: DefTileBrush, type: BrushTileType) : number | undefined { let tile = getTileWithCenterTypeInTileBrush( - defs, brush, type) @@ -572,7 +580,6 @@ export function getTileBrushDefaultTile( if (type !== BrushTileType.Full) { tile = getTileWithCenterTypeInTileBrush( - defs, brush, BrushTileType.Full) } @@ -588,7 +595,6 @@ export function getTileBrushDefaultTile( export function getTileTypeInTileBrush( - defs: Defs, brush: DefTileBrush, tileIndex: number) : BrushTileType @@ -602,12 +608,15 @@ export function getTileTypeInTileBrush( export function getTileWithCenterTypeInTileBrush( - defs: Defs, brush: DefTileBrush, centerType: BrushTileType) : number | undefined { - const matches: { score: number, tileIndex: number }[] = [] + const matches: { + score: number, + tileIndex: number, + connections: BrushTileConnections, + }[] = [] for (const [tileIndexKey, data] of Object.entries(brush.tiles)) { @@ -629,6 +638,7 @@ export function getTileWithCenterTypeInTileBrush( matches.push({ score, tileIndex, + connections: data.connections, }) } @@ -636,17 +646,48 @@ export function getTileWithCenterTypeInTileBrush( return undefined matches.sort((a, b) => b.score - a.score) - return matches[0].tileIndex + + const bestScoringMatches = matches.filter(m => + m.score === matches[0].score && + m.connections.every((c, i) => c === matches[0].connections[i])) + + const randomMatch = + bestScoringMatches[Math.floor(Math.random() * bestScoringMatches.length)] + + return randomMatch.tileIndex } export function getMatchingTileInTileBrush( - defs: Defs, brush: DefTileBrush, desiredConnections: BrushTileConnections) : number | undefined { - const matches: { score: number, tileIndex: number }[] = [] + const matches: { + score: number, + tileIndex: number, + connections: BrushTileConnections, + }[] = [] + + const dontCareConnections = [ + true, true, true, + true, true, true, + true, true, true, + ] + + + for (const [tileIndexKey, data] of Object.entries(brush.tiles)) + { + if (data.connections[4] !== desiredConnections[4]) + continue + + for (let c = 0; c < 9; c++) + { + if (data.connections[c] !== BrushTileType.None) + dontCareConnections[c] = false + } + } + for (const [tileIndexKey, data] of Object.entries(brush.tiles)) { @@ -660,7 +701,8 @@ export function getMatchingTileInTileBrush( // Prioritize 4-way connection for (const c of [1, 3, 5, 7]) { - if (data.connections[c] === desiredConnections[c]) + if (data.connections[c] === desiredConnections[c] || + dontCareConnections[c]) { score += 100000 continue @@ -689,7 +731,8 @@ export function getMatchingTileInTileBrush( // Add score for diagonal connections for (const c of [0, 2, 6, 8]) { - if (data.connections[c] === desiredConnections[c]) + if (data.connections[c] === desiredConnections[c] || + dontCareConnections[c]) score += 1000 else if (data.connections[c] === BrushTileType.Full && @@ -706,14 +749,23 @@ export function getMatchingTileInTileBrush( matches.push({ score, tileIndex, + connections: data.connections, }) } + + matches.sort((a, b) => b.score - a.score) if (matches.length == 0) return undefined - matches.sort((a, b) => b.score - a.score) - return matches[0].tileIndex + const bestScoringMatches = matches.filter(m => + m.score === matches[0].score && + m.connections.every((c, i) => c === matches[0].connections[i])) + + const randomMatch = + bestScoringMatches[Math.floor(Math.random() * bestScoringMatches.length)] + + return randomMatch.tileIndex } diff --git a/src/data/map.ts b/src/data/map.ts index 0ed606b..bf346e8 100644 --- a/src/data/map.ts +++ b/src/data/map.ts @@ -477,6 +477,94 @@ export function setTile( } +export function isNewTileOfDifferentBrushType( + layer: LayerTile, + brush: Defs.DefTileBrush, + cell: { x: number, y: number }, + tile: Tile | undefined) + : boolean +{ + const cellIndex = getTileFieldCellIndexForCell(layer.tileField, cell) + if (cellIndex === undefined) + return false + + const origTile = layer.tileField.tiles[cellIndex] + + if (origTile && + tile && + origTile.tilesetDefId === tile.tilesetDefId) + { + const origType = Defs.getTileTypeInTileBrush( + brush, + origTile.tileId) + + const newType = Defs.getTileTypeInTileBrush( + brush, + tile.tileId) + + if (origType === newType) + return false + } + + return true +} + + +export function isNewTileOfDifferentBrushConnections( + layer: LayerTile, + brush: Defs.DefTileBrush, + cell: { x: number, y: number }, + tile: Tile | undefined) + : boolean +{ + const cellIndex = getTileFieldCellIndexForCell(layer.tileField, cell) + if (cellIndex === undefined) + return false + + const origTile = layer.tileField.tiles[cellIndex] + + if (origTile && + tile && + origTile.tilesetDefId === tile.tilesetDefId) + { + const origType = Defs.getTileBrushData( + brush, + origTile.tileId) + + const newType = Defs.getTileBrushData( + brush, + tile.tileId) + + let allSame = true + for (let c = 0; c < 9; c++) + if (origType.connections[c] !== newType.connections[c]) + allSame = false + + return !allSame + } + + return true +} + + +export function setTileIfDifferentBrushConnections( + layer: LayerTile, + brush: Defs.DefTileBrush, + cell: { x: number, y: number }, + tile: Tile | undefined) + : LayerTile +{ + const cellIndex = getTileFieldCellIndexForCell(layer.tileField, cell) + if (cellIndex === undefined) + return layer + + if (!isNewTileOfDifferentBrushType(layer, brush, cell, tile)) + return layer + + return setTile(layer, cell, tile) +} + + export function resizeTileField( tileField: TileField, xOffsetInTiles: number, @@ -511,7 +599,6 @@ export function resizeTileField( export function getBrushTileTypeForMousePosition( - defs: Defs.Defs, brush: Defs.DefTileBrush, layerDef: Defs.DefLayerTile, mousePosInRoom: MathUtils.Point) @@ -541,24 +628,12 @@ export function getBrushTileTypeForMousePosition( export function getBrushTileDecisionAt( - defs: Defs.Defs, brush: Defs.DefTileBrush, tileField: TileField, cell: { x: number, y: number }, secondPass: boolean) - : number | undefined + : number | null | undefined { - const cellIndex = getTileFieldCellIndexForCell( - tileField, - cell) - - if (cellIndex === undefined) - return undefined - - const tile = tileField.tiles[cellIndex] - if (!tile) - return undefined - const connections: Defs.BrushTileConnections = [ Defs.BrushTileType.None, Defs.BrushTileType.None, Defs.BrushTileType.None, Defs.BrushTileType.None, Defs.BrushTileType.None, Defs.BrushTileType.None, @@ -568,6 +643,8 @@ export function getBrushTileDecisionAt( for (let cx = -1; cx <= 1; cx++) for (let cy = -1; cy <= 1; cy++) { + const connection = (cx + 1) + (cy + 1) * 3 + const neighborCell = { x: cell.x + cx, y: cell.y + cy } const neighborCellIndex = getTileFieldCellIndexForCell( tileField, @@ -576,19 +653,16 @@ export function getBrushTileDecisionAt( if (neighborCellIndex === undefined) { if (global.editors.mapEditing.tileBrushEdgeBehavior === "connectAlways") - connections[(cx + 1) + (cy + 1) * 3] = Defs.BrushTileType.Full + connections[connection] = Defs.BrushTileType.Full continue } const neighborTile = tileField.tiles[neighborCellIndex] - if (!neighborTile || neighborTile.tilesetDefId !== tile.tilesetDefId) + if (!neighborTile || neighborTile.tilesetDefId !== brush.tilesetDefId) continue - const connection = (cx + 1) + (cy + 1) * 3 - connections[connection] = Defs.getTileTypeInTileBrush( - defs, brush, neighborTile.tileId) } @@ -612,7 +686,7 @@ export function getBrushTileDecisionAt( continue const neighborTile = tileField.tiles[neighborCellIndex] - if (!neighborTile || neighborTile.tilesetDefId !== tile.tilesetDefId) + if (!neighborTile || neighborTile.tilesetDefId !== brush.tilesetDefId) continue const neighborData = Defs.getTileBrushData( @@ -637,13 +711,20 @@ export function getBrushTileDecisionAt( } } - return Defs.getMatchingTileInTileBrush(defs, brush, connections) ?? - Defs.getTileBrushDefaultTile(defs, brush, connections[4]) + const decidedTileIndex = + Defs.getMatchingTileInTileBrush(brush, connections) + + if (decidedTileIndex !== undefined) + return decidedTileIndex + + if (connections[4] === Defs.BrushTileType.None) + return null + + return Defs.getTileBrushDefaultTile(brush, connections[4]) } export function fixBrushTileAt( - defs: Defs.Defs, brush: Defs.DefTileBrush, layer: LayerTile, cell: { x: number, y: number }, @@ -658,20 +739,15 @@ export function fixBrushTileAt( return layer const neighborTile = layer.tileField.tiles[neighborTileIndex] - if (neighborTile === undefined || + if (neighborTile && neighborTile.tilesetDefId !== brush.tilesetDefId) return layer - const type = Defs.getTileTypeInTileBrush( - defs, - brush, - neighborTile.tileId) - - if (type === Defs.BrushTileType.None) + if (neighborTile && + !Defs.isTileIndexInBrush(brush, neighborTile.tileId)) return layer const modifiedTileIndex = getBrushTileDecisionAt( - defs, brush, layer.tileField, cell, @@ -680,37 +756,50 @@ export function fixBrushTileAt( if (modifiedTileIndex === undefined) return layer + if (modifiedTileIndex === null) + return layer + + const newType = Defs.getTileTypeInTileBrush( + brush, + modifiedTileIndex) + const modifiedTile: Tile = { tilesetDefId: brush.tilesetDefId, tileId: modifiedTileIndex, } - return setTile(layer, cell, modifiedTile) + if (!isNewTileOfDifferentBrushConnections(layer, brush, cell, modifiedTile)) + return layer + + return setTile( + layer, + cell, + modifiedTile) } export function fixBrushTileRegion( - defs: Defs.Defs, brush: Defs.DefTileBrush, layer: LayerTile, aroundCell: { x: number, y: number }) : LayerTile { for (let pass = 0; pass < 2; pass++) - for (let cx = -1; cx <= 1; cx++) - for (let cy = -1; cy <= 1; cy++) { - const neighborCell = { - x: aroundCell.x + cx, - y: aroundCell.y + cy, - } + for (let cy = -1; cy <= 1; cy++) + for (let cx = -1; cx <= 1; cx++) + { + const neighborCell = { + x: aroundCell.x + cx, + y: aroundCell.y + cy, + } - layer = fixBrushTileAt( - defs, - brush, - layer, - neighborCell, - pass !== 0) + layer = fixBrushTileAt( + brush, + layer, + neighborCell, + pass !== 0) + } } return layer diff --git a/src/mapEditor/action_tileDraw.ts b/src/mapEditor/action_tileDraw.ts index 783a2ee..154568c 100644 --- a/src/mapEditor/action_tileDraw.ts +++ b/src/mapEditor/action_tileDraw.ts @@ -68,13 +68,11 @@ export function setupTileDraw(state: MapEditor.State) const fillType = drawnMultiple ? Defs.BrushTileType.Full : Map.getBrushTileTypeForMousePosition( - editor.defs, brush, layerDef, state.mouse.posInRoom) const defaultTileIndex = Defs.getTileWithCenterTypeInTileBrush( - editor.defs, brush, fillType) @@ -85,10 +83,18 @@ export function setupTileDraw(state: MapEditor.State) tilesetDefId: brush.tilesetDefId, tileId: defaultTileIndex, } - - layer = Map.setTile(layer, state.mouse.tile, defaultTile) + + if (lastPlacedTile.x !== state.mouse.tile.x || + lastPlacedTile.y !== state.mouse.tile.y || + Map.isNewTileOfDifferentBrushType(layer, brush, state.mouse.tile, defaultTile)) + { + layer = Map.setTile( + layer, + state.mouse.tile, + defaultTile) + } + layer = Map.fixBrushTileRegion( - editor.defs, brush, layer, state.mouse.tile) @@ -97,9 +103,15 @@ export function setupTileDraw(state: MapEditor.State) { // Fix first placed tile to become // a Full tile. - layer = Map.setTile(layer, lastPlacedTile, defaultTile) + if (Map.isNewTileOfDifferentBrushType(layer, brush, lastPlacedTile, defaultTile)) + { + layer = Map.setTile( + layer, + lastPlacedTile, + defaultTile) + } + layer = Map.fixBrushTileRegion( - editor.defs, brush, layer, lastPlacedTile) diff --git a/src/mapEditor/render.ts b/src/mapEditor/render.ts index 23cd541..5bee17d 100644 --- a/src/mapEditor/render.ts +++ b/src/mapEditor/render.ts @@ -893,13 +893,11 @@ export function renderTileLayerForeground( for (const _ of [0]) { const fillType = Map.getBrushTileTypeForMousePosition( - defs, brush, editingLayerDef, state.mouse.posInRoom) const tileIndex = Defs.getTileBrushDefaultTile( - defs, brush, fillType)