diff --git a/src/main/kotlin/Rs2MapEditor.kt b/src/main/kotlin/Rs2MapEditor.kt index abd8639..42fdc66 100644 --- a/src/main/kotlin/Rs2MapEditor.kt +++ b/src/main/kotlin/Rs2MapEditor.kt @@ -1,22 +1,17 @@ -import cacheops.cache.definition.data.MapTile import cacheops.cache.definition.data.OverlayDefinition import cacheops.cache.definition.data.UnderlayDefinition import cacheops.cache.definition.decoder.* -import cacheops.cache.definition.encoder.NPCSpawnEncoder import com.displee.cache.CacheLibrary import com.formdev.flatlaf.FlatDarculaLaf import const.Image.RED_DOT import const.Image.YELLOW_DOT import const.cachePath import misc.CustomEventQueue -import misc.ItemSpawnPanel import tools.ItemSearchTool import tools.NPCSearchTool +import ui.* import java.awt.* -import java.awt.event.KeyEvent -import java.awt.event.MouseAdapter -import java.awt.event.MouseEvent import javax.swing.* import javax.swing.border.* import kotlin.system.exitProcess @@ -144,13 +139,24 @@ object Rs2MapEditor { val mapCell = MapCell() var overlayID = (MapTileParser.definition.getTile(column, flippedY, plane).overlayId - 1) - if (overlayID < 0) { - overlayID = 0 - } var underlayID = (MapTileParser.definition.getTile(column, flippedY, plane).underlayId - 1) + + + componentPointMap[point] = mapCell + add(mapCell, gbc) + + if(overlayID < 0 && underlayID < 0){ + mapCell.defaultBackground = Color(0,0,0,0) + mapCell.background = mapCell.defaultBackground + continue + } if (underlayID < 0) { underlayID = 0 } + if (overlayID < 0) { + overlayID = 0 + } + val fluDef = underlayMap[underlayID] val floDef = overlayMap[overlayID] @@ -179,327 +185,14 @@ object Rs2MapEditor { mapCell.layout = BorderLayout() mapCell.add(JLabel(RED_DOT)) } - componentPointMap[point] = mapCell - add(mapCell, gbc) } } SwingUtilities.invokeLater { - this.revalidate() + this.repaint() } } } - class MapCell : JPanel() { - var defaultBackground: Color = background - var scenery: Scenery = Scenery(-1,-1,-1,-1,-1,-1) - override fun getPreferredSize(): Dimension { - return Dimension(cellX, cellY) - } - init { - - //add(underlayLabel) - addMouseListener(object : MouseAdapter() { - override fun mouseEntered(e: MouseEvent) { - selectedPointX = e.component.bounds.location.x / cellX - selectedPointY = e.component.bounds.location.y / cellY - statusLabel.foreground = Color.YELLOW - statusLabel.text = "Region: $region | " + - "Local Coordinates: [$selectedPointX, $selectedPointY] | " + - "Global Coordinates: [${MapTileParser.coordinateX(selectedPointX)}, ${MapTileParser.coordinateX(selectedPointY)}] | " + - "Viewing Underlay: ${MapTileParser.definition.getTile(selectedPointX, selectedPointY, 0).underlayId} | " + - "Selected Underlay: ${if (selectedUnderlayId == null) "No underlay selected!" else "$selectedUnderlayId"}" - defaultBackground = background - if(state == EditorState.SET_UNDERLAY || state == EditorState.NONE) { - background = Color.BLUE - } else if (state == EditorState.ADD_NPC){ - background = Color.YELLOW - } else if (state == EditorState.ADD_GROUNDITEM){ - background = Color.RED - } - } - - override fun mouseExited(e: MouseEvent) { - background = defaultBackground - } - - override fun mouseClicked(e: MouseEvent) { - if (SwingUtilities.isLeftMouseButton(e)) { - if (selectedUnderlayId != null && state == EditorState.SET_UNDERLAY) { - val originalTile = MapTileParser.definition.getTile(selectedPointX, selectedPointY, 0) - val underlayID = selectedUnderlayId - val point = Point(selectedPointX, selectedPointY) - val oldValue = colorPointMap[point] - colorPointMap[point] = underlayID!! - println("UPDATED UNDERLAY VALUES @ [${point.x}, ${point.y}] [$oldValue >> ${colorPointMap[point]}]") - defaultBackground = underlayMap[selectedUnderlayId]?.getRGB()!! - background = underlayMap[selectedUnderlayId]?.getRGB() - - // Update map tile cacheops.definitions with new tile information - MapTileParser.definition.setTile(point.x, point.y, 0, MapTile(originalTile.height, originalTile.attrOpcode, originalTile.overlayId, originalTile.overlayPath, originalTile.overlayRotation, originalTile.settings, underlayID)) - } - else if (npcIdInput.text.isNotEmpty() && state == EditorState.ADD_NPC){ - val id = npcIdInput.text.toIntOrNull() - if(id == null){ - state = EditorState.NONE - return - } - - val npc = NPC(id, selectedPointX, selectedPointY, plane) - npcs.add(npc) - componentPointMap.filter { it.key.x == selectedPointX && it.key.y == selectedPointY }.forEach {(_, cell) -> - var hasLabel = false - cell.components.forEach { if(it is JLabel && it.icon == YELLOW_DOT) hasLabel = true } - cell.layout = FlowLayout() - if(!hasLabel) cell.add(JLabel(YELLOW_DOT)) - cell.repaint() - } - npcPanel.redrawRows() - npcsUpdated = true - } - else if (itemIdInput.text.isNotEmpty() && state == EditorState.ADD_GROUNDITEM){ - val id = itemIdInput.text.toIntOrNull() - val amount = itemAmountInput.text.toIntOrNull() ?: 1 - val respawnTime = itemRespawnInput.text.toIntOrNull() ?: 1 - if(id == null){ - state = EditorState.NONE - return - } - - val item = Item(id, selectedPointX, selectedPointY, plane, respawnTime, amount) - items.add(item) - componentPointMap.filter { it.key.x == selectedPointX && it.key.y == selectedPointY }.forEach {(_, cell) -> - var hasLabel = false - cell.components.forEach { if(it is JLabel && it.icon == RED_DOT) hasLabel = true } - cell.layout = FlowLayout() - if(!hasLabel) cell.add(JLabel(RED_DOT)) - cell.repaint() - } - itemPanel.redrawRows() - itemsUpdated = true - } - } else if (SwingUtilities.isRightMouseButton(e)) { - val point = Point(selectedPointX, selectedPointY) - val def = MapTileParser.definition.getTile(point.x, point.y, 0) - val floDef = overlayMap[def.overlayId]!! - val cell = componentPointMap[point]!! - val string = StringBuilder() - .append("

Tile [${point.x}, ${point.y}] Information


") - .append("

") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("
UnderlayIDHeightSettings
${def.underlayId}${def.height}${def.settings}
") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("
OverlayIDColorHide underlay
${def.overlayId}${floDef.color}${floDef.hideUnderlay}
") - .append("
") - val itemsHere = items.filter { it.x == selectedPointX && it.y == selectedPointY && it.plane == plane }.toList() - val npcsHere = npcs.filter { it.x == selectedPointX && it.y == selectedPointY && it.plane == plane }.toList() - - if(npcsHere.isNotEmpty()) { - string.append("") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("") - for (npc in npcsHere) { - string.append("") - string.append("") - string.append("") - string.append("") - } - string.append("
NPC IDName
${npc.id}${npc.definition.name}(${npc.definition.combat})

") - } - - if(itemsHere.isNotEmpty()) { - string.append("") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("") - .append("") - for (item in itemsHere) { - string.append("") - string.append("") - string.append("") - string.append("") - } - string.append("
Item IDInfo
${item.id}${item.definition.name}[${item.amount}] \uD83D\uDD64${item.respawnTime}

") - } - - if(cell.scenery.id != -1){ - string.append("

Scenery Info

") - string.append("${cell.scenery.definition.name} [ID: ${cell.scenery.id}]
") - string.append("Type: ${cell.scenery.type}
") - string.append("Rotation: ${cell.scenery.rotation}
") - string.append("") - } - - underlayInfo.text = String.format("%s", string.toString()) - infoPane.selectedIndex = 0 - } - } - }) - } - - fun flagScenery(scenery: Scenery){ - this.scenery = scenery - } - - override fun paintComponent(g: Graphics) { - super.paintComponent(g) - var pointX1 = 0 - var pointY1 = 0 - var pointX2 = 0 - var pointY2 = 0 - val color = g.color - val rotationOdd = scenery.rotation % 2 != 0 - when(scenery.type){ - 10 -> g.drawOval(5,5,this.width - 10, this.height - 10) - 4 ->{ - val offSetX = if(!rotationOdd) (scenery.rotation * 0.375 * width).toInt() else (0.35 * width).toInt() - val offSetY = if(!rotationOdd) (0.65 * height).toInt() else (scenery.rotation * 0.375 * height).toInt() - g.drawString("=", offSetX, offSetY) - } - 11 -> { - g.color = Color(255,255,255,75) - g.drawString("⛝",(0.25 * width).toInt(),(0.75 * height).toInt()) - g.color = color - } - 22 -> { - g.color = Color(255,255,255,55) - g.drawString("⛆",(0.15 * width).toInt(),(0.65 * height).toInt()) - g.color = color - } - 0,5 -> { - if(scenery.id == 85) return - when(scenery.rotation){ - 0 -> {pointX1 = 2; pointY1 = this.height; pointX2 = 2; pointY2 = 0} - 1 -> {pointX1 = 0; pointY1 = 2; pointX2 = this.width; pointY2 = 2} - 2 -> {pointX1 = this.width - 2; pointY1 = 0; pointX2 = this.width - 2; pointY2 = this.height} - 3 -> {pointX1 = 0; pointY1 = this.height - 2; pointX2 = this.width; pointY2 = this.height - 2} - } - if(scenery.definition.interactive == 1){ - g.color = Color.RED - } - g.drawLine(pointX1, pointY1, pointX2, pointY2) - g.color = color - } - - 2 -> { - val nPoints = 4 - var xArray: IntArray = intArrayOf(0,0,0,0) - var yArray: IntArray = intArrayOf(0,0,0,0) - when(scenery.rotation){ - 0 -> {xArray = intArrayOf(2,2,2,this.width); yArray = intArrayOf(2,this.height,2,2)} - 1 -> {xArray = intArrayOf(0, this.width, this.width - 2, this.width - 2); yArray = intArrayOf(2, 2, 2, this.height)} - 2 -> {xArray = intArrayOf(0, this.width, this.width, this.width); yArray = intArrayOf(this.height - 2, this.height - 2, 0, this.height - 2)} - 3 -> {xArray = intArrayOf(0, 0, 0, this.width); intArrayOf(0, this.height - 2, this.height - 2, this.height - 2)} - } - if(scenery.definition.interactive == 1){ - g.color = Color.RED - } - g.drawPolyline(xArray, yArray, nPoints) - g.color = color - } - - 9,7,6,8 -> { - if(scenery.id == 85 || scenery.id == 83) return - when(scenery.rotation){ - 0,2 -> {pointX1 = 0; pointY1 = height; pointX2 = width; pointY2 = 0} - 1,3 -> {pointX1 = 0; pointY1 = 0; pointX2 = width; pointY2 = height} - } - - val overlayNorth = getOverlayId(scenery.x + 1, scenery.y) - val overlaySouth = getOverlayId(scenery.x - 1, scenery.y) - val northWest = getOverlayId(scenery.x - 1, scenery.y + 1) - val north = getOverlayId(scenery.x, scenery.y + 1) - val northEast = getOverlayId(scenery.x + 1, scenery.y + 1) - val east = getOverlayId(scenery.x + 1, scenery.y) - val southWest = getOverlayId(scenery.x - 1, scenery.y - 1) - val south = getOverlayId(scenery.x, scenery.y - 1) - val southEast = getOverlayId(scenery.x + 1, scenery.y - 1) - val west = getOverlayId(scenery.x - 1, scenery.y) - - var backFillVertice = Pair(0,0) - when(scenery.rotation){ - 0, 2 -> { - val sumA = getOverlaySum(north, northWest, west) - val sumB = getOverlaySum(south, southEast, east) - backFillVertice = if(sumA > sumB) Pair(width,height) - else if (sumA == sumB) Pair(-1,-1) - else Pair(0,0) - } - 1,3 -> { - val sumA = getOverlaySum(north, northEast, east) - val sumB = getOverlaySum(south, southWest, west) - backFillVertice = if(sumA > sumB) Pair(0,height) - else if (sumA == sumB) Pair(-1,-1) - else Pair(width,0) - } - } - - val fluDef = getUnderlayColor(scenery.x, scenery.y) - g.color = fluDef - if(overlaySouth != overlayNorth && backFillVertice.first != -1) - g.fillPolygon(intArrayOf(pointX1, pointX2, backFillVertice.first), intArrayOf(pointY1, pointY2, backFillVertice.second), 3) - g.color = color - g.drawLine(pointX1, pointY1, pointX2, pointY2) - } - } - } - - fun getOverlaySum(vararg overlays: Int): Int{ - var sum = 0 - for(overlay in overlays){ - sum += overlay.coerceAtMost(1) - } - return sum - } - - fun getUnderlayColor(x: Int, y: Int): Color { - var underlayID = (MapTileParser.definition.getTile(x, y, plane).underlayId - 1) - if (underlayID < 0) { - underlayID = 0 - } - return underlayMap[underlayID]?.getRGB() ?: Color.BLACK - } - - fun getOverlayId(x: Int, y: Int): Int { - return MapTileParser.definition.getTile(x, y, plane).overlayId - } - } - class ScrollPane : JPanel() { init { // Scroll bar @@ -522,34 +215,6 @@ object Rs2MapEditor { } } - class InfoPane : JTabbedPane() { - init { - val informationComponent: JComponent = TileInformationPanel() - val underlayComponent: JComponent = FLUGridPanel() - val panel3: JComponent = makeTextPanel("Howdy Ho! I'm an overlay panel, or soon will be that is!") - - preferredSize = Dimension(230, 4000) - border = CompoundBorder(LineBorder(Color.DARK_GRAY), EmptyBorder(0, 0, 0, 0)) - - addTab("Information", informationComponent) - setMnemonicAt(0, KeyEvent.VK_1) - add("Underlays", underlayComponent) - setMnemonicAt(1, KeyEvent.VK_2) - addTab("Overlays", panel3) - setMnemonicAt(2, KeyEvent.VK_3) - add("NPC Spawn", npcPanel) - add("Item Spawn", itemPanel) - } - } - - class SettingsPane : JPanel(FlowLayout(FlowLayout.RIGHT)) { - init { - layout = FlowLayout(FlowLayout.LEFT) - add(CommitButton()) - add(RevertButton()) - } - } - fun makeTextPanel(text: String?): JComponent { val panel = JPanel(false) val filler = JLabel(text) @@ -559,111 +224,6 @@ object Rs2MapEditor { return panel } - class TileInformationPanel : JPanel() { - init { - underlayInfo.foreground = Color.white - underlayInfo.verticalAlignment = SwingConstants.TOP - underlayInfo.horizontalAlignment = SwingConstants.CENTER - layout = BorderLayout() - add(underlayInfo) - } - } - - class FLUGridPanel : JPanel() { - init { - underlayMap.forEach { - val underlay = UnderlaySquarePanel(it.value.getRGB(),30, it.key) - add(underlay) - } - val addAnUnderlay = UnderlaySquarePanel(Color.darkGray,30, "+") - add(addAnUnderlay) - } - } - - class UnderlaySquarePanel(color: Color, size: Int, val id: Any) : JPanel() { - init { - when (id) { - is Int -> { - background = color - } - else -> { - background = color - border = BorderFactory.createDashedBorder(Color.GREEN) - } - } - val text = JLabel("$id") - text.foreground = Color((color.rgb).inv()).brighter() - - minimumSize = Dimension(size, size) - maximumSize = Dimension(size, size) - preferredSize = Dimension(size, size) - add(text) - - addMouseListener(object : MouseAdapter() { - val border: Border = MatteBorder(1, 1, 1, 1, Color.GRAY) - val highlight: Border = MatteBorder(1, 1, 1, 1, Color.YELLOW) - val selectionBorder = MatteBorder(1,1,1,1, Color.WHITE) - - override fun mouseEntered(e: MouseEvent?) { - this@UnderlaySquarePanel.border = selectionBorder - colorPointMap.filter { it.value == id }.forEach{ componentPointMap[it.key]!!.border = highlight} - } - - override fun mouseExited(e: MouseEvent?) { - this@UnderlaySquarePanel.border = null - colorPointMap.filter { it.value == id }.forEach{ componentPointMap[it.key]!!.border = border} - } - - override fun mouseClicked(e: MouseEvent) { - if (SwingUtilities.isLeftMouseButton(e)) { - when (id) { - is Int -> { - if(selectedUnderlayId == id){ - state = EditorState.NONE - } else { - state = EditorState.SET_UNDERLAY - selectedUnderlayId = id - } - statusLabel.text = "Region: $region | " + - "Local Coordinates: [$selectedPointX, $selectedPointY, $plane] | " + - "Global Coordinates: [${MapTileParser.coordinateX(selectedPointX)}, ${MapTileParser.coordinateX(selectedPointY)}, $plane] | " + - "Viewing Underlay: ${MapTileParser.definition.getTile(selectedPointX, selectedPointY, 0).underlayId - 1} | " + - "Selected Underlay: ${if (selectedUnderlayId == null) "No underlay selected!" else "$selectedUnderlayId"}" - } - else -> { - println("User trying to add new underlay") - } - } - } - } - }) - } - } - - class CommitButton : JButton() { - init { - val label = JLabel("Commit") - add(label) - addActionListener { - println("User attempting to commit") - // TODO: DISABLED FOR NOW - //MapTileWriter.replaceValues() - NPCSpawnEncoder.write(npcs) - println("Wrote data to the cache!") - } - } - } - - class RevertButton : JButton() { - init { - val label = JLabel("Revert") - add(label) - addActionListener { - println("User attempting to revert") - } - } - } - class MenuBar : JMenuBar() { init { add(FileMenuOption()) @@ -679,19 +239,6 @@ object Rs2MapEditor { } } - class PlaneButton(val plane: Int) : JButton(plane.toString()){ - init { - addActionListener { - if(Rs2MapEditor.plane != this.plane){ - Rs2MapEditor.plane = this.plane - npcPanel.redrawRows() - itemPanel.redrawRows() - mapPanel.repaintMap() - } - } - } - } - class ToolsMenuOption : JMenu("Tools") { init { add(NPCSearchItem()) diff --git a/src/main/kotlin/cacheops/cache/definition/decoder/MapTileDecoder.kt b/src/main/kotlin/cacheops/cache/definition/decoder/MapTileDecoder.kt index 83b91b6..cf34221 100644 --- a/src/main/kotlin/cacheops/cache/definition/decoder/MapTileDecoder.kt +++ b/src/main/kotlin/cacheops/cache/definition/decoder/MapTileDecoder.kt @@ -8,6 +8,7 @@ import java.nio.ByteBuffer class MapTileDecoder { fun readLoop(definition: MapDefinition, buffer: ByteBuffer): ByteArray { + for (plane in 0 until 4) { for (localX in 0 until 64) { for (localY in 0 until 64) { @@ -37,7 +38,7 @@ class MapTileDecoder { } } if (height != 0 || attrOpcode != 0 || overlayPath != 0 || overlayRotation != 0 || overlayId != 0 || settings != 0 || underlayId != 0) { - definition.setTile(localX, localY, plane, MapTile(height, attrOpcode, overlayId, overlayPath, overlayRotation, settings, underlayId)) + definition.setTile(localX, localY, plane, MapTile(height, attrOpcode, if(overlayId == 42) 0 else overlayId, overlayPath, overlayRotation, settings, underlayId)) } } } diff --git a/src/main/kotlin/cacheops/cache/definition/decoder/MapTileParser.kt b/src/main/kotlin/cacheops/cache/definition/decoder/MapTileParser.kt index 13e0583..512a38c 100644 --- a/src/main/kotlin/cacheops/cache/definition/decoder/MapTileParser.kt +++ b/src/main/kotlin/cacheops/cache/definition/decoder/MapTileParser.kt @@ -31,6 +31,8 @@ object MapTileParser { } fun init() { + definition.objects.clear() + definition.tiles.clear() val region = Rs2MapEditor.region val baseX = ((region shr 8) shl 6) val baseY = ((region and 0xFF) shl 6) diff --git a/src/main/kotlin/ui/InfoPane.kt b/src/main/kotlin/ui/InfoPane.kt new file mode 100644 index 0000000..bb50bd8 --- /dev/null +++ b/src/main/kotlin/ui/InfoPane.kt @@ -0,0 +1,30 @@ +package ui + +import java.awt.Color +import java.awt.Dimension +import java.awt.event.KeyEvent +import javax.swing.JComponent +import javax.swing.JTabbedPane +import javax.swing.border.CompoundBorder +import javax.swing.border.EmptyBorder +import javax.swing.border.LineBorder + +class InfoPane : JTabbedPane() { + init { + val informationComponent: JComponent = TileInformationPanel() + val underlayComponent: JComponent = UnderlaySelectionPanel() + val panel3: JComponent = Rs2MapEditor.makeTextPanel("Howdy Ho! I'm an overlay panel, or soon will be that is!") + + preferredSize = Dimension(230, 4000) + border = CompoundBorder(LineBorder(Color.DARK_GRAY), EmptyBorder(0, 0, 0, 0)) + + addTab("Information", informationComponent) + setMnemonicAt(0, KeyEvent.VK_1) + add("Underlays", underlayComponent) + setMnemonicAt(1, KeyEvent.VK_2) + addTab("Overlays", panel3) + setMnemonicAt(2, KeyEvent.VK_3) + add("NPC Spawn", Rs2MapEditor.npcPanel) + add("Item Spawn", Rs2MapEditor.itemPanel) + } +} \ No newline at end of file diff --git a/src/main/kotlin/misc/ItemSpawnPanel.kt b/src/main/kotlin/ui/ItemSpawnPanel.kt similarity index 98% rename from src/main/kotlin/misc/ItemSpawnPanel.kt rename to src/main/kotlin/ui/ItemSpawnPanel.kt index 03628b8..2f8755a 100644 --- a/src/main/kotlin/misc/ItemSpawnPanel.kt +++ b/src/main/kotlin/ui/ItemSpawnPanel.kt @@ -1,7 +1,8 @@ -package misc +package ui import cacheops.cache.definition.decoder.Item import const.Image +import misc.ImgButton import java.awt.BorderLayout import java.awt.Color import java.awt.Dimension @@ -11,8 +12,6 @@ import java.awt.event.MouseEvent import javax.swing.BoxLayout import javax.swing.JLabel import javax.swing.JPanel -import javax.swing.JSeparator -import javax.swing.border.Border import javax.swing.border.MatteBorder class ItemSpawnPanel : JPanel() { diff --git a/src/main/kotlin/ui/MapCell.kt b/src/main/kotlin/ui/MapCell.kt new file mode 100644 index 0000000..962f911 --- /dev/null +++ b/src/main/kotlin/ui/MapCell.kt @@ -0,0 +1,354 @@ +package ui + +import EditorState +import Rs2MapEditor +import cacheops.cache.definition.data.MapTile +import cacheops.cache.definition.decoder.Item +import cacheops.cache.definition.decoder.MapTileParser +import cacheops.cache.definition.decoder.NPC +import cacheops.cache.definition.decoder.Scenery +import const.Image +import java.awt.* +import java.awt.event.MouseAdapter +import java.awt.event.MouseEvent +import javax.swing.JLabel +import javax.swing.JPanel +import javax.swing.SwingUtilities + +class MapCell : JPanel() { + var defaultBackground: Color = background + var scenery: Scenery = Scenery(-1, -1, -1, -1, -1, -1) + override fun getPreferredSize(): Dimension { + return Dimension(Rs2MapEditor.cellX, Rs2MapEditor.cellY) + } + init { + + //add(underlayLabel) + addMouseListener(object : MouseAdapter() { + override fun mouseEntered(e: MouseEvent) { + Rs2MapEditor.selectedPointX = e.component.bounds.location.x / Rs2MapEditor.cellX + Rs2MapEditor.selectedPointY = e.component.bounds.location.y / Rs2MapEditor.cellY + Rs2MapEditor.statusLabel.foreground = Color.YELLOW + Rs2MapEditor.statusLabel.text = "Region: ${Rs2MapEditor.region} | " + + "Local Coordinates: [${Rs2MapEditor.selectedPointX}, ${Rs2MapEditor.selectedPointY}] | " + + "Global Coordinates: [${MapTileParser.coordinateX(Rs2MapEditor.selectedPointX)}, ${ + MapTileParser.coordinateX( + Rs2MapEditor.selectedPointY + ) + }] | " + + "Viewing Underlay: ${ + MapTileParser.definition.getTile( + Rs2MapEditor.selectedPointX, + Rs2MapEditor.selectedPointY, 0).underlayId} | " + + "Selected Underlay: ${if (Rs2MapEditor.selectedUnderlayId == null) "No underlay selected!" else "${Rs2MapEditor.selectedUnderlayId}"}" + defaultBackground = background + if(Rs2MapEditor.state == EditorState.SET_UNDERLAY || Rs2MapEditor.state == EditorState.NONE) { + background = Color.BLUE + } else if (Rs2MapEditor.state == EditorState.ADD_NPC){ + background = Color.YELLOW + } else if (Rs2MapEditor.state == EditorState.ADD_GROUNDITEM){ + background = Color.RED + } + } + + override fun mouseExited(e: MouseEvent) { + background = defaultBackground + } + + override fun mouseClicked(e: MouseEvent) { + if (SwingUtilities.isLeftMouseButton(e)) { + if (Rs2MapEditor.selectedUnderlayId != null && Rs2MapEditor.state == EditorState.SET_UNDERLAY) { + val originalTile = MapTileParser.definition.getTile( + Rs2MapEditor.selectedPointX, + Rs2MapEditor.selectedPointY, 0) + val underlayID = Rs2MapEditor.selectedUnderlayId + val point = Point(Rs2MapEditor.selectedPointX, Rs2MapEditor.selectedPointY) + val oldValue = Rs2MapEditor.colorPointMap[point] + Rs2MapEditor.colorPointMap[point] = underlayID!! + println("UPDATED UNDERLAY VALUES @ [${point.x}, ${point.y}] [$oldValue >> ${Rs2MapEditor.colorPointMap[point]}]") + defaultBackground = Rs2MapEditor.underlayMap[Rs2MapEditor.selectedUnderlayId]?.getRGB()!! + background = Rs2MapEditor.underlayMap[Rs2MapEditor.selectedUnderlayId]?.getRGB() + + // Update map tile cacheops.definitions with new tile information + MapTileParser.definition.setTile(point.x, point.y, Rs2MapEditor.plane, + MapTile( + originalTile.height, + originalTile.attrOpcode, + originalTile.overlayId, + originalTile.overlayPath, + originalTile.overlayRotation, + originalTile.settings, + underlayID + ) + ) + } + else if (Rs2MapEditor.npcIdInput.text.isNotEmpty() && Rs2MapEditor.state == EditorState.ADD_NPC){ + val id = Rs2MapEditor.npcIdInput.text.toIntOrNull() + if(id == null){ + Rs2MapEditor.state = EditorState.NONE + return + } + + val npc = NPC(id, Rs2MapEditor.selectedPointX, Rs2MapEditor.selectedPointY, Rs2MapEditor.plane) + Rs2MapEditor.npcs.add(npc) + Rs2MapEditor.componentPointMap.filter { it.key.x == Rs2MapEditor.selectedPointX && it.key.y == Rs2MapEditor.selectedPointY }.forEach { (_, cell) -> + var hasLabel = false + cell.components.forEach { if(it is JLabel && it.icon == Image.YELLOW_DOT) hasLabel = true } + cell.layout = FlowLayout() + if(!hasLabel) cell.add(JLabel(Image.YELLOW_DOT)) + cell.repaint() + } + Rs2MapEditor.npcPanel.redrawRows() + Rs2MapEditor.npcsUpdated = true + } + else if (Rs2MapEditor.itemIdInput.text.isNotEmpty() && Rs2MapEditor.state == EditorState.ADD_GROUNDITEM){ + val id = Rs2MapEditor.itemIdInput.text.toIntOrNull() + val amount = Rs2MapEditor.itemAmountInput.text.toIntOrNull() ?: 1 + val respawnTime = Rs2MapEditor.itemRespawnInput.text.toIntOrNull() ?: 1 + if(id == null){ + Rs2MapEditor.state = EditorState.NONE + return + } + + val item = Item( + id, + Rs2MapEditor.selectedPointX, + Rs2MapEditor.selectedPointY, + Rs2MapEditor.plane, + respawnTime, + amount + ) + Rs2MapEditor.items.add(item) + Rs2MapEditor.componentPointMap.filter { it.key.x == Rs2MapEditor.selectedPointX && it.key.y == Rs2MapEditor.selectedPointY }.forEach { (_, cell) -> + var hasLabel = false + cell.components.forEach { if(it is JLabel && it.icon == Image.RED_DOT) hasLabel = true } + cell.layout = FlowLayout() + if(!hasLabel) cell.add(JLabel(Image.RED_DOT)) + cell.repaint() + } + Rs2MapEditor.itemPanel.redrawRows() + Rs2MapEditor.itemsUpdated = true + } + } else if (SwingUtilities.isRightMouseButton(e)) { + val point = Point(Rs2MapEditor.selectedPointX, Rs2MapEditor.selectedPointY) + val def = MapTileParser.definition.getTile(point.x, point.y, Rs2MapEditor.plane) + val floDef = Rs2MapEditor.overlayMap[def.overlayId]!! + val cell = Rs2MapEditor.componentPointMap[point]!! + val string = StringBuilder() + .append("

Tile [${point.x}, ${point.y}] Information


") + .append("

") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("
UnderlayIDHeightSettings
${def.underlayId}${def.height}${def.settings}
") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("
OverlayIDColorHide underlay
${def.overlayId}${floDef.color}${floDef.hideUnderlay}
") + .append("
") + val itemsHere = Rs2MapEditor.items.filter { it.x == Rs2MapEditor.selectedPointX && it.y == Rs2MapEditor.selectedPointY && it.plane == Rs2MapEditor.plane }.toList() + val npcsHere = Rs2MapEditor.npcs.filter { it.x == Rs2MapEditor.selectedPointX && it.y == Rs2MapEditor.selectedPointY && it.plane == Rs2MapEditor.plane }.toList() + + if(npcsHere.isNotEmpty()) { + string.append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + for (npc in npcsHere) { + string.append("") + string.append("") + string.append("") + string.append("") + } + string.append("
NPC IDName
${npc.id}${npc.definition.name}(${npc.definition.combat})

") + } + + if(itemsHere.isNotEmpty()) { + string.append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("") + for (item in itemsHere) { + string.append("") + string.append("") + string.append("") + string.append("") + } + string.append("
Item IDInfo
${item.id}${item.definition.name}[${item.amount}] \uD83D\uDD64${item.respawnTime}

") + } + + if(cell.scenery.id != -1){ + string.append("

Scenery Info

") + string.append("${cell.scenery.definition.name} [ID: ${cell.scenery.id}]
") + string.append("Type: ${cell.scenery.type}
") + string.append("Rotation: ${cell.scenery.rotation}
") + string.append("") + } + + Rs2MapEditor.underlayInfo.text = String.format("%s", string.toString()) + Rs2MapEditor.infoPane.selectedIndex = 0 + } + } + }) + } + + fun flagScenery(scenery: Scenery){ + this.scenery = scenery + } + + override fun paintComponent(g: Graphics) { + if(this.defaultBackground == Color(0,0,0,0)) return + super.paintComponent(g) + var pointX1 = 0 + var pointY1 = 0 + var pointX2 = 0 + var pointY2 = 0 + val color = g.color + val rotationOdd = scenery.rotation % 2 != 0 + when(scenery.type){ + 10 -> g.drawOval(5,5,this.width - 10, this.height - 10) + 4 ->{ + val offSetX = if(!rotationOdd) (scenery.rotation * 0.375 * width).toInt() else (0.35 * width).toInt() + val offSetY = if(!rotationOdd) (0.65 * height).toInt() else (scenery.rotation * 0.375 * height).toInt() + g.drawString("=", offSetX, offSetY) + } + 11 -> { + g.color = Color(255, 255, 255, 75) + g.drawString("⛝",(0.25 * width).toInt(),(0.75 * height).toInt()) + g.color = color + } + 22 -> { + g.color = Color(255, 255, 255, 55) + g.drawString("⛆",(0.15 * width).toInt(),(0.65 * height).toInt()) + g.color = color + } + 0,5 -> { + if(scenery.id == 85) return + when(scenery.rotation){ + 0 -> {pointX1 = 2; pointY1 = this.height; pointX2 = 2; pointY2 = 0} + 1 -> {pointX1 = 0; pointY1 = 2; pointX2 = this.width; pointY2 = 2} + 2 -> {pointX1 = this.width - 2; pointY1 = 0; pointX2 = this.width - 2; pointY2 = this.height} + 3 -> {pointX1 = 0; pointY1 = this.height - 2; pointX2 = this.width; pointY2 = this.height - 2} + } + if(scenery.definition.interactive == 1){ + g.color = Color.RED + } + g.drawLine(pointX1, pointY1, pointX2, pointY2) + g.color = color + } + + 2 -> { + val nPoints = 4 + var xArray: IntArray = intArrayOf(0,0,0,0) + var yArray: IntArray = intArrayOf(0,0,0,0) + when(scenery.rotation){ + 0 -> {xArray = intArrayOf(2,2,2,this.width); yArray = intArrayOf(2,this.height,2,2)} + 1 -> {xArray = intArrayOf(0, this.width, this.width - 2, this.width - 2); yArray = intArrayOf(2, 2, 2, this.height)} + 2 -> {xArray = intArrayOf(0, this.width, this.width, this.width); yArray = intArrayOf(this.height - 2, this.height - 2, 0, this.height - 2)} + 3 -> {xArray = intArrayOf(0, 0, 0, this.width); intArrayOf(0, this.height - 2, this.height - 2, this.height - 2)} + } + if(scenery.definition.interactive == 1){ + g.color = Color.RED + } + g.drawPolyline(xArray, yArray, nPoints) + g.color = color + } + + 9,7,6,8 -> { + if(scenery.id == 85 || scenery.id == 83) return + when(scenery.rotation){ + 0,2 -> {pointX1 = 0; pointY1 = height; pointX2 = width; pointY2 = 0} + 1,3 -> {pointX1 = 0; pointY1 = 0; pointX2 = width; pointY2 = height} + } + + val overlayNorth = getOverlayId(scenery.x + 1, scenery.y) + val overlaySouth = getOverlayId(scenery.x - 1, scenery.y) + val northWest = getOverlayId(scenery.x - 1, scenery.y + 1) + val north = getOverlayId(scenery.x, scenery.y + 1) + val northEast = getOverlayId(scenery.x + 1, scenery.y + 1) + val east = getOverlayId(scenery.x + 1, scenery.y) + val southWest = getOverlayId(scenery.x - 1, scenery.y - 1) + val south = getOverlayId(scenery.x, scenery.y - 1) + val southEast = getOverlayId(scenery.x + 1, scenery.y - 1) + val west = getOverlayId(scenery.x - 1, scenery.y) + + var backFillVertice = Pair(0,0) + when(scenery.rotation){ + 0, 2 -> { + val sumA = getOverlaySum(north, northWest, west) + val sumB = getOverlaySum(south, southEast, east) + backFillVertice = if(sumA > sumB) Pair(width,height) + else if (sumA == sumB) Pair(-1,-1) + else Pair(0,0) + } + 1,3 -> { + val sumA = getOverlaySum(north, northEast, east) + val sumB = getOverlaySum(south, southWest, west) + backFillVertice = if(sumA > sumB) Pair(0,height) + else if (sumA == sumB) Pair(-1,-1) + else Pair(width,0) + } + } + + val fluDef = getUnderlayColor(scenery.x, scenery.y) + g.color = fluDef + if(overlaySouth != overlayNorth && backFillVertice.first != -1) + g.fillPolygon(intArrayOf(pointX1, pointX2, backFillVertice.first), intArrayOf(pointY1, pointY2, backFillVertice.second), 3) + g.color = color + g.drawLine(pointX1, pointY1, pointX2, pointY2) + } + } + } + + fun getOverlaySum(vararg overlays: Int): Int{ + var sum = 0 + for(overlay in overlays){ + sum += overlay.coerceAtMost(1) + } + return sum + } + + fun getUnderlayColor(x: Int, y: Int): Color { + var underlayID = (MapTileParser.definition.getTile(x, y, Rs2MapEditor.plane).underlayId - 1) + if (underlayID < 0) { + underlayID = 0 + } + return Rs2MapEditor.underlayMap[underlayID]?.getRGB() ?: Color.BLACK + } + + fun getOverlayId(x: Int, y: Int): Int { + return MapTileParser.definition.getTile(x, y, Rs2MapEditor.plane).overlayId + } +} \ No newline at end of file diff --git a/src/main/kotlin/NPCSpawnPanel.kt b/src/main/kotlin/ui/NPCSpawnPanel.kt similarity index 98% rename from src/main/kotlin/NPCSpawnPanel.kt rename to src/main/kotlin/ui/NPCSpawnPanel.kt index 6203ec9..4edb8bd 100644 --- a/src/main/kotlin/NPCSpawnPanel.kt +++ b/src/main/kotlin/ui/NPCSpawnPanel.kt @@ -1,3 +1,7 @@ +package ui + +import EditorState +import Rs2MapEditor import cacheops.cache.definition.decoder.NPC import const.Image import misc.ImgButton diff --git a/src/main/kotlin/ui/PlaneButton.kt b/src/main/kotlin/ui/PlaneButton.kt new file mode 100644 index 0000000..0a9f6b3 --- /dev/null +++ b/src/main/kotlin/ui/PlaneButton.kt @@ -0,0 +1,16 @@ +package ui + +import javax.swing.JButton + +class PlaneButton(val plane: Int) : JButton(plane.toString()){ + init { + addActionListener { + if(Rs2MapEditor.plane != this.plane){ + Rs2MapEditor.plane = this.plane + Rs2MapEditor.npcPanel.redrawRows() + Rs2MapEditor.itemPanel.redrawRows() + Rs2MapEditor.mapPanel.repaintMap() + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/ui/SelectableUnderlayCell.kt b/src/main/kotlin/ui/SelectableUnderlayCell.kt new file mode 100644 index 0000000..eac551b --- /dev/null +++ b/src/main/kotlin/ui/SelectableUnderlayCell.kt @@ -0,0 +1,80 @@ +package ui + +import cacheops.cache.definition.decoder.MapTileParser +import java.awt.Color +import java.awt.Dimension +import java.awt.event.MouseAdapter +import java.awt.event.MouseEvent +import javax.swing.BorderFactory +import javax.swing.JLabel +import javax.swing.JPanel +import javax.swing.SwingUtilities +import javax.swing.border.Border +import javax.swing.border.MatteBorder + +class SelectableUnderlayCell(color: Color, size: Int, val id: Any) : JPanel() { + init { + when (id) { + is Int -> { + background = color + } + else -> { + background = color + border = BorderFactory.createDashedBorder(Color.GREEN) + } + } + val text = JLabel("$id") + text.foreground = Color((color.rgb).inv()).brighter() + + minimumSize = Dimension(size, size) + maximumSize = Dimension(size, size) + preferredSize = Dimension(size, size) + add(text) + + addMouseListener(object : MouseAdapter() { + val border: Border = MatteBorder(1, 1, 1, 1, Color.GRAY) + val highlight: Border = MatteBorder(1, 1, 1, 1, Color.YELLOW) + val selectionBorder = MatteBorder(1, 1, 1, 1, Color.WHITE) + + override fun mouseEntered(e: MouseEvent?) { + this@SelectableUnderlayCell.border = selectionBorder + Rs2MapEditor.colorPointMap.filter { it.value == id }.forEach{ Rs2MapEditor.componentPointMap[it.key]!!.border = highlight} + } + + override fun mouseExited(e: MouseEvent?) { + this@SelectableUnderlayCell.border = null + Rs2MapEditor.colorPointMap.filter { it.value == id }.forEach{ Rs2MapEditor.componentPointMap[it.key]!!.border = border} + } + + override fun mouseClicked(e: MouseEvent) { + if (SwingUtilities.isLeftMouseButton(e)) { + when (id) { + is Int -> { + if(Rs2MapEditor.selectedUnderlayId == id){ + Rs2MapEditor.state = EditorState.NONE + } else { + Rs2MapEditor.state = EditorState.SET_UNDERLAY + Rs2MapEditor.selectedUnderlayId = id + } + Rs2MapEditor.statusLabel.text = "Region: ${Rs2MapEditor.region} | " + + "Local Coordinates: [${Rs2MapEditor.selectedPointX}, ${Rs2MapEditor.selectedPointY}, ${Rs2MapEditor.plane}] | " + + "Global Coordinates: [${MapTileParser.coordinateX(Rs2MapEditor.selectedPointX)}, ${ + MapTileParser.coordinateX( + Rs2MapEditor.selectedPointY + ) + }, ${Rs2MapEditor.plane}] | " + + "Viewing Underlay: ${ + MapTileParser.definition.getTile( + Rs2MapEditor.selectedPointX, + Rs2MapEditor.selectedPointY, 0).underlayId - 1} | " + + "Selected Underlay: ${if (Rs2MapEditor.selectedUnderlayId == null) "No underlay selected!" else "${Rs2MapEditor.selectedUnderlayId}"}" + } + else -> { + println("User trying to add new underlay") + } + } + } + } + }) + } +} \ No newline at end of file diff --git a/src/main/kotlin/ui/TileInformationPanel.kt b/src/main/kotlin/ui/TileInformationPanel.kt new file mode 100644 index 0000000..a16c970 --- /dev/null +++ b/src/main/kotlin/ui/TileInformationPanel.kt @@ -0,0 +1,16 @@ +package ui + +import java.awt.BorderLayout +import java.awt.Color +import javax.swing.JPanel +import javax.swing.SwingConstants + +class TileInformationPanel : JPanel() { + init { + Rs2MapEditor.underlayInfo.foreground = Color.white + Rs2MapEditor.underlayInfo.verticalAlignment = SwingConstants.TOP + Rs2MapEditor.underlayInfo.horizontalAlignment = SwingConstants.CENTER + layout = BorderLayout() + add(Rs2MapEditor.underlayInfo) + } +} \ No newline at end of file diff --git a/src/main/kotlin/ui/UnderlaySelectionPanel.kt b/src/main/kotlin/ui/UnderlaySelectionPanel.kt new file mode 100644 index 0000000..4f1b859 --- /dev/null +++ b/src/main/kotlin/ui/UnderlaySelectionPanel.kt @@ -0,0 +1,15 @@ +package ui + +import java.awt.Color +import javax.swing.JPanel + +class UnderlaySelectionPanel : JPanel() { + init { + Rs2MapEditor.underlayMap.forEach { + val underlay = SelectableUnderlayCell(it.value.getRGB(), 30, it.key) + add(underlay) + } + val addAnUnderlay = SelectableUnderlayCell(Color.darkGray, 30, "+") + add(addAnUnderlay) + } +} \ No newline at end of file