DEADSOFTWARE

MainComponent in kotlin
[cavedroid.git] / core / src / ru / deadsoftware / cavedroid / game / model / item / InventoryItem.kt
index 49cc59d6a5366f484df8a51a6ecd400d538a2a14..f420120b2844e7bd2d77ae4d01513837bac80c74 100644 (file)
@@ -4,30 +4,73 @@ import com.badlogic.gdx.graphics.Color
 import com.badlogic.gdx.graphics.g2d.SpriteBatch
 import com.badlogic.gdx.graphics.glutils.ShapeRenderer
 import ru.deadsoftware.cavedroid.game.GameItemsHolder
+import ru.deadsoftware.cavedroid.game.model.dto.SaveDataDto
 import ru.deadsoftware.cavedroid.misc.Assets
+import ru.deadsoftware.cavedroid.misc.Saveable
+import ru.deadsoftware.cavedroid.misc.utils.drawSprite
 import ru.deadsoftware.cavedroid.misc.utils.drawString
 import ru.deadsoftware.cavedroid.misc.utils.px
-import java.io.Serializable
+import kotlin.contracts.ExperimentalContracts
+import kotlin.contracts.contract
 
 class InventoryItem @JvmOverloads constructor(
     val itemKey: String,
-    var amount: Int = 1,
-) : Serializable {
+    _amount: Int = 1,
+) :  Saveable {
 
-    @Transient
-    lateinit var item: Item
-        private set
+    var amount = _amount
+        set(value) {
+            field = if (value < 0) {
+                0
+            } else {
+                value
+            }
+        }
+
+    private var _item: Item? = null
+
+    var item: Item
+        get() {
+            requireNotNull(_item) { "_item is null" }
+            return _item.takeIf { amount > 0 } ?: throw IllegalArgumentException("Accessing item with zero amount")
+        }
+        private set (value) {
+            _item = value
+        }
 
     @JvmOverloads
-    constructor(_item: Item, amount: Int = 1) : this(_item.params.key, amount) {
-        item = _item
+    constructor(item: Item, amount: Int = 1) : this(item.params.key, amount) {
+        _item = item
     }
 
     fun init(gameItemsHolder: GameItemsHolder) {
-        if (this::item.isInitialized) {
+        if (_item != null) {
             return
         }
-        item = gameItemsHolder.getItem(itemKey)
+        _item = gameItemsHolder.getItem(itemKey)
+    }
+
+    @JvmOverloads
+    fun add(count: Int = 1) {
+        if (count > 0 && Int.MAX_VALUE - count < amount) {
+            throw IllegalArgumentException("$amount + $count exceeds Int.MAX_VALUE")
+        }
+
+        amount += count
+    }
+
+    @JvmOverloads
+    fun subtract(count: Int = 1) {
+        if (count < 0) {
+            throw IllegalArgumentException("Can't subtract negative amount")
+        }
+
+        add(-count)
+    }
+
+    @JvmOverloads
+    fun canBeAdded(count: Int = 1): Boolean {
+        return amount + count <= item.params.maxStack
     }
 
     private fun drawAmountText(spriteBatch: SpriteBatch, text: String,  x: Float, y: Float) {
@@ -35,13 +78,31 @@ class InventoryItem @JvmOverloads constructor(
         spriteBatch.drawString(text, x, y, Color.WHITE)
     }
 
+    fun drawSelected(spriteBatch: SpriteBatch, x: Float, y: Float) {
+        if (item.isNone()) {
+            return
+        }
+
+        val sprite = item.sprite
+        val amountString = amount.toString()
+        spriteBatch.drawSprite(sprite, x - 10f, y - 10f, rotation = 0f, width = 20f, height = 20f)
+        drawAmountText(
+            spriteBatch = spriteBatch,
+            text = amountString,
+            x = x + 10f - Assets.getStringWidth(amountString) + 1f,
+            y = y + 10f - Assets.getStringHeight(amountString) + 1f
+        )
+    }
+
     fun draw(spriteBatch: SpriteBatch, shapeRenderer: ShapeRenderer, x: Float, y: Float) {
         if (item.isNone()) {
             return
         }
 
         val sprite = item.sprite
-        spriteBatch.draw(sprite, x, y)
+        val placeableMarginTop = (item as? Item.Placeable)?.block?.params?.spriteMargins?.top ?: 0
+        val placeableMarginLeft = (item as? Item.Placeable)?.block?.params?.spriteMargins?.left ?: 0
+        spriteBatch.drawSprite(sprite, x + placeableMarginLeft, y + placeableMarginTop)
 
         if (amount < 2) {
             return
@@ -70,4 +131,35 @@ class InventoryItem @JvmOverloads constructor(
         }
     }
 
+    override fun getSaveData(): SaveDataDto.InventoryItemSaveData {
+        return SaveDataDto.InventoryItemSaveData(
+            version = SAVE_DATA_VERSION,
+            itemKey = itemKey,
+            amount = amount,
+        )
+    }
+
+    companion object {
+        private const val SAVE_DATA_VERSION = 1
+
+        @OptIn(ExperimentalContracts::class)
+        fun InventoryItem?.isNoneOrNull(): Boolean {
+            contract { returns(false) implies(this@isNoneOrNull != null) }
+            return this?.item == null || this.item.isNone()
+        }
+
+
+        fun fromSaveData(
+            saveData: SaveDataDto.InventoryItemSaveData,
+            gameItemsHolder: GameItemsHolder? = null
+        ): InventoryItem {
+            saveData.verifyVersion(SAVE_DATA_VERSION)
+
+            val inventoryItem = InventoryItem(saveData.itemKey, saveData.amount)
+            gameItemsHolder?.let(inventoryItem::init)
+
+            return inventoryItem
+        }
+    }
+
 }