@file:Suppress("unused", "MemberVisibilityCanBePrivate") package net.axay.kspigot.gui import net.axay.kspigot.languageextensions.kotlinextensions.MinMaxPair // INVENTORY data class InventoryDimensions(val width: Int, val height: Int) { val slotAmount = width * height val invSlots by lazy { ArrayList().apply { (1..height).forEach { row -> (1..width).forEach { slotInRow -> this += InventorySlot(row, slotInRow) } } } } val invSlotsWithRealSlots by lazy { HashMap().apply { invSlots.forEach { curSlot -> curSlot.realSlotIn(this@InventoryDimensions)?.let { this[curSlot] = it } } } } val realSlots by lazy { invSlotsWithRealSlots.values } } // SLOTS data class InventorySlot(val row: Int, val slotInRow: Int) : Comparable { companion object { fun fromRealSlot(realSlot: Int, dimensions: InventoryDimensions) = dimensions.invSlotsWithRealSlots.toList().find { it.second == realSlot }?.first } override fun compareTo(other: InventorySlot) = when { row > other.row -> 1 row < other.row -> -1 else -> when { slotInRow > other.slotInRow -> 1 slotInRow < other.slotInRow -> -1 else -> 0 } } fun realSlotIn(inventoryDimensions: InventoryDimensions): Int? { if (!isInDimension(inventoryDimensions)) return null val realRow = inventoryDimensions.height - (row - 1) val rowsUnder = if (realRow - 1 >= 0) realRow - 1 else 0 return ((rowsUnder * inventoryDimensions.width) + slotInRow) - 1 } fun isInDimension(inventoryDimensions: InventoryDimensions) = (1..inventoryDimensions.width).contains(slotInRow) && (1..inventoryDimensions.height).contains(row) fun add(offsetHorizontally: Int, offsetVertically: Int) = InventorySlot( row + offsetVertically, slotInRow + offsetHorizontally ) } interface InventorySlotCompound { fun withInvType(invType: GUIType): Collection fun realSlotsWithInvType(invType: GUIType) = withInvType(invType).mapNotNull { it.realSlotIn(invType.dimensions) } } open class SingleInventorySlot internal constructor( val inventorySlot: InventorySlot ) : InventorySlotCompound { constructor(row: Int, slotInRow: Int) : this(InventorySlot(row, slotInRow)) private val slotAsList = listOf(inventorySlot) override fun withInvType(invType: GUIType) = slotAsList } internal enum class InventorySlotRangeType { LINEAR, RECTANGLE, } class InventorySlotRange internal constructor( startSlot: SingleInventorySlot, endSlot: SingleInventorySlot, private val type: InventorySlotRangeType ) : InventorySlotCompound, ClosedRange { override val start: InventorySlot override val endInclusive: InventorySlot init { val minMaxPair = MinMaxPair(startSlot.inventorySlot, endSlot.inventorySlot) start = minMaxPair.min endInclusive = minMaxPair.max } override fun withInvType(invType: GUIType) = LinkedHashSet().apply { when (type) { InventorySlotRangeType.RECTANGLE -> { // all possible combinations between the two slots // -> form a rectangle for (row in start.row..endInclusive.row) for (slotInRow in start.slotInRow..endInclusive.slotInRow) this += InventorySlot(row, slotInRow) } InventorySlotRangeType.LINEAR -> { if (endInclusive.row > start.row) { // from start --->| to end of row for (slotInRow in start.slotInRow..invType.dimensions.width) this += InventorySlot(start.row, slotInRow) // all rows in between if (endInclusive.row > start.row + 1) for (row in start.row + 1 until endInclusive.row) for (slotInRow in 1..invType.dimensions.width) this += InventorySlot(row, slotInRow) // from start of row |----> to endInclusive for (slotInRow in 1..endInclusive.slotInRow) this += InventorySlot(endInclusive.row, slotInRow) } else if (endInclusive.row == start.row) { // from start ---> to endInclusive in the same row for (slotInRow in start.slotInRow..endInclusive.slotInRow) this += InventorySlot(start.row, slotInRow) } } } } } /** * This range contains all slots having an index between * the indeces of the two given slots. */ infix fun SingleInventorySlot.linTo(slot: SingleInventorySlot) = InventorySlotRange(this, slot, InventorySlotRangeType.LINEAR) /** * This range contains all slots inside of a thought rectangle * with the two given slots as two opposite corners of the rectangle. */ infix fun SingleInventorySlot.rectTo(slot: SingleInventorySlot) = InventorySlotRange(this, slot, InventorySlotRangeType.RECTANGLE) class InventoryRowSlots internal constructor( val row: Int ) : InventorySlotCompound { override fun withInvType(invType: GUIType) = HashSet().apply { for (slotInRow in 1..invType.dimensions.width) this += InventorySlot(row, slotInRow) } } class InventoryColumnSlots internal constructor( val column: Int ) : InventorySlotCompound { override fun withInvType(invType: GUIType) = HashSet().apply { for (row in 1..invType.dimensions.height) this += InventorySlot(row, column) } } class InventoryBorderSlots internal constructor( val padding: Int ) : InventorySlotCompound { override fun withInvType(invType: GUIType) = HashSet().apply { val dimensions = invType.dimensions for (currentPadding in 0 until padding) { for (slotInRow in 1 + currentPadding..dimensions.width - currentPadding) { this += InventorySlot(1, slotInRow) this += InventorySlot(dimensions.height, slotInRow) } for (row in 2 + currentPadding until dimensions.height - currentPadding) { this += InventorySlot(row, 1) this += InventorySlot(row, dimensions.width) } } } } class InventoryCornerSlots internal constructor( val ifBottomLeft: Boolean = false, val ifBottomRight: Boolean = false, val ifTopLeft: Boolean = false, val ifTopRight: Boolean = false ) : InventorySlotCompound { override fun withInvType(invType: GUIType) = HashSet().apply { val dimensions = invType.dimensions if (ifBottomLeft) this += InventorySlot(1, 1) if (ifBottomRight) this += InventorySlot(1, dimensions.width) if (ifTopLeft) this += InventorySlot(dimensions.height, 1) if (ifTopRight) this += InventorySlot(dimensions.height, dimensions.width) } } class InventoryAllSlots : InventorySlotCompound { override fun withInvType(invType: GUIType) = invType.dimensions.invSlots } // SLOT TYPE SAFETY // COLUMNS interface ForColumnOne : ForInventoryWidthThree, ForInventoryWidthFive, ForInventoryWidthNine interface ForColumnTwo : ForInventoryWidthThree, ForInventoryWidthFive, ForInventoryWidthNine interface ForColumnThree : ForInventoryWidthThree, ForInventoryWidthFive, ForInventoryWidthNine interface ForColumnFour : ForInventoryWidthFive, ForInventoryWidthNine interface ForColumnFive : ForInventoryWidthFive, ForInventoryWidthNine interface ForColumnSix : ForInventoryWidthNine interface ForColumnSeven : ForInventoryWidthNine interface ForColumnEight : ForInventoryWidthNine interface ForColumnNine : ForInventoryWidthNine // ROWS interface ForRowOne : ForInventoryOneByNine, ForInventoryTwoByNine, ForInventoryThreeByNine, ForInventoryFourByNine, ForInventoryFiveByNine, ForInventorySixByNine interface ForRowTwo : ForInventoryTwoByNine, ForInventoryThreeByNine, ForInventoryFourByNine, ForInventoryFiveByNine, ForInventorySixByNine interface ForRowThree : ForInventoryThreeByNine, ForInventoryFourByNine, ForInventoryFiveByNine, ForInventorySixByNine interface ForRowFour : ForInventoryFourByNine, ForInventoryFiveByNine, ForInventorySixByNine interface ForRowFive : ForInventoryFiveByNine, ForInventorySixByNine interface ForRowSix : ForInventorySixByNine // EDGE CASES: // ROW ONE interface ForRowOneSlotOneToThree : ForRowOne, ForInventoryOneByFive, ForInventoryThreeByThree interface ForRowOneSlotFourToFive : ForRowOne, ForInventoryOneByFive // ROW TWO interface ForRowTwoSlotOneToThree : ForRowTwo, ForInventoryThreeByThree // ROW THREE interface ForRowThreeSlotOneToThree : ForRowThree, ForInventoryThreeByThree // COMPLETE ROWS (including the edge cases) interface ForCompleteRowOne : ForRowOne, ForRowOneSlotOneToThree, ForRowOneSlotFourToFive interface ForCompleteRowTwo : ForRowTwo, ForRowTwoSlotOneToThree interface ForCompleteRowThree : ForRowThree, ForRowThreeSlotOneToThree object Slots { // ROW ONE val RowOneSlotOne = SingleInventorySlot(1, 1) val RowOneSlotTwo = SingleInventorySlot(1, 2) val RowOneSlotThree = SingleInventorySlot(1, 3) val RowOneSlotFour = SingleInventorySlot(1, 4) val RowOneSlotFive = SingleInventorySlot(1, 5) val RowOneSlotSix = SingleInventorySlot(1, 6) val RowOneSlotSeven = SingleInventorySlot(1, 7) val RowOneSlotEight = SingleInventorySlot(1, 8) val RowOneSlotNine = SingleInventorySlot(1, 9) // ROW TWO val RowTwoSlotOne = SingleInventorySlot(2, 1) val RowTwoSlotTwo = SingleInventorySlot(2, 2) val RowTwoSlotThree = SingleInventorySlot(2, 3) val RowTwoSlotFour = SingleInventorySlot(2, 4) val RowTwoSlotFive = SingleInventorySlot(2, 5) val RowTwoSlotSix = SingleInventorySlot(2, 6) val RowTwoSlotSeven = SingleInventorySlot(2, 7) val RowTwoSlotEight = SingleInventorySlot(2, 8) val RowTwoSlotNine = SingleInventorySlot(2, 9) // ROW THREE val RowThreeSlotOne = SingleInventorySlot(3, 1) val RowThreeSlotTwo = SingleInventorySlot(3, 2) val RowThreeSlotThree = SingleInventorySlot(3, 3) val RowThreeSlotFour = SingleInventorySlot(3, 4) val RowThreeSlotFive = SingleInventorySlot(3, 5) val RowThreeSlotSix = SingleInventorySlot(3, 6) val RowThreeSlotSeven = SingleInventorySlot(3, 7) val RowThreeSlotEight = SingleInventorySlot(3, 8) val RowThreeSlotNine = SingleInventorySlot(3, 9) // ROW FOUR val RowFourSlotOne = SingleInventorySlot(4, 1) val RowFourSlotTwo = SingleInventorySlot(4, 2) val RowFourSlotThree = SingleInventorySlot(4, 3) val RowFourSlotFour = SingleInventorySlot(4, 4) val RowFourSlotFive = SingleInventorySlot(4, 5) val RowFourSlotSix = SingleInventorySlot(4, 6) val RowFourSlotSeven = SingleInventorySlot(4, 7) val RowFourSlotEight = SingleInventorySlot(4, 8) val RowFourSlotNine = SingleInventorySlot(4, 9) // ROW FIVE val RowFiveSlotOne = SingleInventorySlot(5, 1) val RowFiveSlotTwo = SingleInventorySlot(5, 2) val RowFiveSlotThree = SingleInventorySlot(5, 3) val RowFiveSlotFour = SingleInventorySlot(5, 4) val RowFiveSlotFive = SingleInventorySlot(5, 5) val RowFiveSlotSix = SingleInventorySlot(5, 6) val RowFiveSlotSeven = SingleInventorySlot(5, 7) val RowFiveSlotEight = SingleInventorySlot(5, 8) val RowFiveSlotNine = SingleInventorySlot(5, 9) // ROW SIX val RowSixSlotOne = SingleInventorySlot(6, 1) val RowSixSlotTwo = SingleInventorySlot(6, 2) val RowSixSlotThree = SingleInventorySlot(6, 3) val RowSixSlotFour = SingleInventorySlot(6, 4) val RowSixSlotFive = SingleInventorySlot(6, 5) val RowSixSlotSix = SingleInventorySlot(6, 6) val RowSixSlotSeven = SingleInventorySlot(6, 7) val RowSixSlotEight = SingleInventorySlot(6, 8) val RowSixSlotNine = SingleInventorySlot(6, 9) // ROW val RowOne = InventoryRowSlots(1) val RowTwo = InventoryRowSlots(2) val RowThree = InventoryRowSlots(3) val RowFour = InventoryRowSlots(4) val RowFive = InventoryRowSlots(5) val RowSix = InventoryRowSlots(6) // COLUMN val ColumnOne = InventoryColumnSlots(1) val ColumnTwo = InventoryColumnSlots(2) val ColumnThree = InventoryColumnSlots(3) val ColumnFour = InventoryColumnSlots(4) val ColumnFive = InventoryColumnSlots(5) val ColumnSix = InventoryColumnSlots(6) val ColumnSeven = InventoryColumnSlots(7) val ColumnEight = InventoryColumnSlots(8) val ColumnNine = InventoryColumnSlots(9) // BORDER val BorderPaddingOne = InventoryBorderSlots(1) val BorderPaddingTwo = InventoryBorderSlots(2) val BorderPaddingThree = InventoryBorderSlots(3) val Border = BorderPaddingOne // CORNER val Corners = InventoryCornerSlots() val CornersLeft = InventoryCornerSlots(ifBottomLeft = true, ifTopLeft = true) val CornersRight = InventoryCornerSlots(ifBottomRight = true, ifTopRight = true) val CornersBottom = InventoryCornerSlots(ifBottomLeft = true, ifBottomRight = true) val CornersTop = InventoryCornerSlots(ifTopLeft = true, ifTopRight = true) val CornerBottomLeft = InventoryCornerSlots(ifBottomLeft = true) val CornerBottomRight = InventoryCornerSlots(ifBottomRight = true) val CornerTopLeft = InventoryCornerSlots(ifTopLeft = true) val CornerTopRight = InventoryCornerSlots(ifTopRight = true) // ALL val All = InventoryAllSlots() }