diff --git a/src/data/editors.ts b/src/data/editors.ts index 38693e9..c673d89 100644 --- a/src/data/editors.ts +++ b/src/data/editors.ts @@ -46,7 +46,13 @@ export interface Global export const LAYERDEF_ID_MAP = "world" -export type Tool = "move" | "draw" | "fill" | "erase" | "select" +export type Tool = + "move" | + "draw" | + "fill" | + "replace" | + "erase" | + "select" export type Editor = diff --git a/src/data/map.ts b/src/data/map.ts index bf346e8..48dde3d 100644 --- a/src/data/map.ts +++ b/src/data/map.ts @@ -441,6 +441,19 @@ export function *enumerateTileFieldCellsCentered(tileField: TileField): Generato } +export function getTile( + layer: LayerTile, + cell: { x: number, y: number }) + : Tile | undefined +{ + const cellIndex = getTileFieldCellIndexForCell(layer.tileField, cell) + if (cellIndex === undefined) + return undefined + + return layer.tileField.tiles[cellIndex] +} + + export function setTile( layer: LayerTile, cell: { x: number, y: number }, diff --git a/src/events.ts b/src/events.ts index e566140..006d5c9 100644 --- a/src/events.ts +++ b/src/events.ts @@ -82,6 +82,11 @@ export function useKeyboardShortcuts() global.editors.mapEditing.tool = "fill" global.editors.refreshToken.commit() break + + case "r": + global.editors.mapEditing.tool = "replace" + global.editors.refreshToken.commit() + break case "e": global.editors.mapEditing.tool = "erase" diff --git a/src/mapEditor/action_tileReplace.ts b/src/mapEditor/action_tileReplace.ts new file mode 100644 index 0000000..818607a --- /dev/null +++ b/src/mapEditor/action_tileReplace.ts @@ -0,0 +1,84 @@ +import * as MapEditor from "./index" +import * as ID from "../data/id" +import * as Defs from "../data/defs" +import * as Map from "../data/map" +import * as Editors from "../data/editors" +import { global } from "../global" + + +export function setupTileReplace(state: MapEditor.State) +{ + const editor = (global.editors.editors[state.editorIndex] as Editors.EditorMap) + const tileStamp = global.editors.mapEditing.tileStamp + const brush = Defs.getTileBrushDef(editor.defs, global.editors.mapEditing.tileBrushDefId) + + + let lastPlacedTile = { x: -100000, y: -100000 } + let drawnMultiple = false + + state.rectSelection = null + + state.onMouseMove = () => + { + editor.map = Map.ensureRoomLayer( + editor.defs, + editor.map, + state.roomId, + global.editors.mapEditing.layerDefId) + + let layer = Map.getRoomLayer( + editor.map, + state.roomId, + global.editors.mapEditing.layerDefId) + + if (!layer || layer.type !== "tile") + return + + const layerDef = Defs.getLayerDef(editor.defs, layer.layerDefId) + if (!layerDef || layerDef.type !== "tile") + return + + + if (!brush) + { + if (state.toolMoveWithoutSnap && + Math.abs(state.mouse.tile.x - lastPlacedTile.x) < tileStamp.width && + Math.abs(state.mouse.tile.y - lastPlacedTile.y) < tileStamp.height) + return + + for (const cell of Map.enumerateTileFieldCellsCentered(tileStamp)) + { + const mouseCell = { + x: state.mouse.tile.x + cell.x, + y: state.mouse.tile.y + cell.y, + } + + const originalTile = Map.getTile(layer, mouseCell) + + for (const replaceCell of Map.enumerateTileFieldCells(layer.tileField)) + { + const replaceTile = Map.getTile(layer, replaceCell) + + const isSameTile = + (originalTile === undefined && + replaceTile === undefined) || + (originalTile?.tilesetDefId === replaceTile?.tilesetDefId && + originalTile?.tileId === replaceTile?.tileId) + + if (isSameTile) + layer = Map.setTile(layer, replaceCell, cell.tile) + } + + layer = Map.setTile(layer, mouseCell, cell.tile) + } + } + + lastPlacedTile = state.mouse.tile + + editor.map = Map.setRoomLayer( + editor.map, + state.roomId, + global.editors.mapEditing.layerDefId, + layer) + } +} \ No newline at end of file diff --git a/src/mapEditor/index.ts b/src/mapEditor/index.ts index 3db2303..c5843ae 100644 --- a/src/mapEditor/index.ts +++ b/src/mapEditor/index.ts @@ -7,6 +7,7 @@ export * from "./action_roomDraw" export * from "./action_roomSelect" export * from "./action_tileDraw" export * from "./action_tileFill" +export * from "./action_tileReplace" export * from "./action_tileErase" export * from "./action_tileSelect" export * from "./action_objectMove" diff --git a/src/mapEditor/render.ts b/src/mapEditor/render.ts index 5bee17d..fd4edc1 100644 --- a/src/mapEditor/render.ts +++ b/src/mapEditor/render.ts @@ -881,7 +881,8 @@ export function renderTileLayerForeground( editingLayerDef.gridCellHeight) if ((global.editors.mapEditing.tool === "draw" || - global.editors.mapEditing.tool === "fill") && + global.editors.mapEditing.tool === "fill" || + global.editors.mapEditing.tool === "replace") && !state.onMouseMove) { state.ctx.save() diff --git a/src/mapEditor/state.ts b/src/mapEditor/state.ts index 182cfb0..325f582 100644 --- a/src/mapEditor/state.ts +++ b/src/mapEditor/state.ts @@ -612,6 +612,9 @@ export function onMouseDown(state: State, ev: MouseEvent) else if (global.editors.mapEditing.tool === "fill") MapEditor.setupTileFill(state) + else if (global.editors.mapEditing.tool === "replace") + MapEditor.setupTileReplace(state) + else if (global.editors.mapEditing.tool === "erase") MapEditor.setupTileErase(state) diff --git a/src/panels/EditorMap.tsx b/src/panels/EditorMap.tsx index 5614002..3aad936 100644 --- a/src/panels/EditorMap.tsx +++ b/src/panels/EditorMap.tsx @@ -229,6 +229,12 @@ export function EditorMap(props: { onClick={ () => chooseTool("fill") } /> + chooseTool("replace") } + /> +