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("| UnderlayID | ")
- .append("Height | ")
- .append("Settings | ")
- .append("
")
- .append("")
- .append("")
- .append("")
- .append("| ${def.underlayId} | ")
- .append("${def.height} | ")
- .append("${def.settings} | ")
- .append("
")
- .append("")
- .append("
")
- .append("")
- .append("")
- .append("")
- .append("| OverlayID | ")
- .append("Color | ")
- .append("Hide underlay | ")
- .append("
")
- .append("")
- .append("")
- .append("")
- .append("| ${def.overlayId} | ")
- .append("${floDef.color} | ")
- .append("${floDef.hideUnderlay} | ")
- .append("
")
- .append("")
- .append("
")
- .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("| NPC ID | ")
- .append("Name | ")
- .append("
")
- .append("")
- .append("")
- for (npc in npcsHere) {
- string.append("")
- string.append("| ${npc.id} | ")
- string.append("${npc.definition.name}(${npc.definition.combat}) | ")
- string.append("
")
- }
- string.append("
")
- }
-
- if(itemsHere.isNotEmpty()) {
- string.append("")
- .append("")
- .append("")
- .append("| Item ID | ")
- .append("Info | ")
- .append("
")
- .append("")
- .append("")
- for (item in itemsHere) {
- string.append("")
- string.append("| ${item.id} | ")
- string.append("${item.definition.name}[${item.amount}] \uD83D\uDD64${item.respawnTime} | ")
- string.append("
")
- }
- string.append("
")
- }
-
- 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("| UnderlayID | ")
+ .append("Height | ")
+ .append("Settings | ")
+ .append("
")
+ .append("")
+ .append("")
+ .append("")
+ .append("| ${def.underlayId} | ")
+ .append("${def.height} | ")
+ .append("${def.settings} | ")
+ .append("
")
+ .append("")
+ .append("
")
+ .append("")
+ .append("")
+ .append("")
+ .append("| OverlayID | ")
+ .append("Color | ")
+ .append("Hide underlay | ")
+ .append("
")
+ .append("")
+ .append("")
+ .append("")
+ .append("| ${def.overlayId} | ")
+ .append("${floDef.color} | ")
+ .append("${floDef.hideUnderlay} | ")
+ .append("
")
+ .append("")
+ .append("
")
+ .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("| NPC ID | ")
+ .append("Name | ")
+ .append("
")
+ .append("")
+ .append("")
+ for (npc in npcsHere) {
+ string.append("")
+ string.append("| ${npc.id} | ")
+ string.append("${npc.definition.name}(${npc.definition.combat}) | ")
+ string.append("
")
+ }
+ string.append("
")
+ }
+
+ if(itemsHere.isNotEmpty()) {
+ string.append("")
+ .append("")
+ .append("")
+ .append("| Item ID | ")
+ .append("Info | ")
+ .append("
")
+ .append("")
+ .append("")
+ for (item in itemsHere) {
+ string.append("")
+ string.append("| ${item.id} | ")
+ string.append("${item.definition.name}[${item.amount}] \uD83D\uDD64${item.respawnTime} | ")
+ string.append("
")
+ }
+ string.append("
")
+ }
+
+ 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