mucho refactoring

This commit is contained in:
ceikry 2021-11-03 09:17:06 -05:00
parent 86b4bd0582
commit 548622e2c0
11 changed files with 537 additions and 473 deletions

View file

@ -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 = "<html>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) "<font color='red'>No underlay selected!</font>" else "$selectedUnderlayId"}</html>"
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("<h2><b>Tile [${point.x}, ${point.y}] Information</b></h2><br>")
.append("<hr width=\"250px\"><br>")
.append("<table style=\"border:1px solid gray;margin-left:auto;margin-right:auto;>")
.append("<thead>")
.append("<tr style=\"text-align:center\">")
.append("<th>UnderlayID</th>")
.append("<th>Height</th>")
.append("<th>Settings</th>")
.append("</tr>")
.append("</thead>")
.append("<tbody>")
.append("<tr style=\"text-align:center\">")
.append("<td>${def.underlayId}</td>")
.append("<td>${def.height}</td>")
.append("<td>${def.settings}</td>")
.append("</tr>")
.append("</tbody>")
.append("</table>")
.append("<table style=\"border:1px solid gray;margin-left:auto;margin-right:auto;>")
.append("<thead>")
.append("<tr style=\"text-align:center\">")
.append("<th>OverlayID</th>")
.append("<th>Color</th>")
.append("<th>Hide underlay</th>")
.append("</tr>")
.append("</thead>")
.append("<tbody>")
.append("<tr style=\"text-align:center\">")
.append("<td>${def.overlayId}</td>")
.append("<td>${floDef.color}</td>")
.append("<td>${floDef.hideUnderlay}</td>")
.append("</tr>")
.append("</tbody>")
.append("</table>")
.append("<br/>")
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("<table style=\"border:1px solid gray;margin-left:auto;margin-right:auto;>")
.append("<thead>")
.append("<tr style=\"text-align:center\">")
.append("<th>NPC ID</th>")
.append("<th>Name</th>")
.append("</tr>")
.append("</thead>")
.append("<tbody>")
for (npc in npcsHere) {
string.append("<tr style=\"text-align:center\">")
string.append("<td>${npc.id}</td>")
string.append("<td>${npc.definition.name}(${npc.definition.combat})</td>")
string.append("</tr>")
}
string.append("</tbody></table><br/>")
}
if(itemsHere.isNotEmpty()) {
string.append("<table style=\"border:1px solid gray;margin-left:auto;margin-right:auto;>")
.append("<thead>")
.append("<tr style=\"text-align:center\">")
.append("<th>Item ID</th>")
.append("<th>Info</th>")
.append("</tr>")
.append("</thead>")
.append("<tbody>")
for (item in itemsHere) {
string.append("<tr style=\"text-align:center\">")
string.append("<td>${item.id}</td>")
string.append("<td>${item.definition.name}[${item.amount}] \uD83D\uDD64${item.respawnTime}</td>")
string.append("</tr>")
}
string.append("</tbody></table><br/>")
}
if(cell.scenery.id != -1){
string.append("<h3>Scenery Info</h3>")
string.append("${cell.scenery.definition.name} [ID: ${cell.scenery.id}]<br/>")
string.append("Type: ${cell.scenery.type}<br/>")
string.append("Rotation: ${cell.scenery.rotation}<br/>")
string.append("")
}
underlayInfo.text = String.format("<html><body style=\"text-align: center;\">%s</body></html>", 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 = "<html>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) "<font color='red'>No underlay selected!</font>" else "$selectedUnderlayId"}</html>"
}
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())

View file

@ -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))
}
}
}

View file

@ -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)

View file

@ -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)
}
}

View file

@ -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() {

View file

@ -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 = "<html>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) "<font color='red'>No underlay selected!</font>" else "${Rs2MapEditor.selectedUnderlayId}"}</html>"
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("<h2><b>Tile [${point.x}, ${point.y}] Information</b></h2><br>")
.append("<hr width=\"250px\"><br>")
.append("<table style=\"border:1px solid gray;margin-left:auto;margin-right:auto;>")
.append("<thead>")
.append("<tr style=\"text-align:center\">")
.append("<th>UnderlayID</th>")
.append("<th>Height</th>")
.append("<th>Settings</th>")
.append("</tr>")
.append("</thead>")
.append("<tbody>")
.append("<tr style=\"text-align:center\">")
.append("<td>${def.underlayId}</td>")
.append("<td>${def.height}</td>")
.append("<td>${def.settings}</td>")
.append("</tr>")
.append("</tbody>")
.append("</table>")
.append("<table style=\"border:1px solid gray;margin-left:auto;margin-right:auto;>")
.append("<thead>")
.append("<tr style=\"text-align:center\">")
.append("<th>OverlayID</th>")
.append("<th>Color</th>")
.append("<th>Hide underlay</th>")
.append("</tr>")
.append("</thead>")
.append("<tbody>")
.append("<tr style=\"text-align:center\">")
.append("<td>${def.overlayId}</td>")
.append("<td>${floDef.color}</td>")
.append("<td>${floDef.hideUnderlay}</td>")
.append("</tr>")
.append("</tbody>")
.append("</table>")
.append("<br/>")
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("<table style=\"border:1px solid gray;margin-left:auto;margin-right:auto;>")
.append("<thead>")
.append("<tr style=\"text-align:center\">")
.append("<th>NPC ID</th>")
.append("<th>Name</th>")
.append("</tr>")
.append("</thead>")
.append("<tbody>")
for (npc in npcsHere) {
string.append("<tr style=\"text-align:center\">")
string.append("<td>${npc.id}</td>")
string.append("<td>${npc.definition.name}(${npc.definition.combat})</td>")
string.append("</tr>")
}
string.append("</tbody></table><br/>")
}
if(itemsHere.isNotEmpty()) {
string.append("<table style=\"border:1px solid gray;margin-left:auto;margin-right:auto;>")
.append("<thead>")
.append("<tr style=\"text-align:center\">")
.append("<th>Item ID</th>")
.append("<th>Info</th>")
.append("</tr>")
.append("</thead>")
.append("<tbody>")
for (item in itemsHere) {
string.append("<tr style=\"text-align:center\">")
string.append("<td>${item.id}</td>")
string.append("<td>${item.definition.name}[${item.amount}] \uD83D\uDD64${item.respawnTime}</td>")
string.append("</tr>")
}
string.append("</tbody></table><br/>")
}
if(cell.scenery.id != -1){
string.append("<h3>Scenery Info</h3>")
string.append("${cell.scenery.definition.name} [ID: ${cell.scenery.id}]<br/>")
string.append("Type: ${cell.scenery.type}<br/>")
string.append("Rotation: ${cell.scenery.rotation}<br/>")
string.append("")
}
Rs2MapEditor.underlayInfo.text = String.format("<html><body style=\"text-align: center;\">%s</body></html>", 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
}
}

View file

@ -1,3 +1,7 @@
package ui
import EditorState
import Rs2MapEditor
import cacheops.cache.definition.decoder.NPC
import const.Image
import misc.ImgButton

View file

@ -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()
}
}
}
}

View file

@ -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 = "<html>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) "<font color='red'>No underlay selected!</font>" else "${Rs2MapEditor.selectedUnderlayId}"}</html>"
}
else -> {
println("User trying to add new underlay")
}
}
}
}
})
}
}

View file

@ -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)
}
}

View file

@ -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)
}
}