DEADSOFTWARE

71909880fde87171235d4e665c39ca1f4837fad2
[cavedroid.git] / core / src / ru / deadsoftware / cavedroid / game / model / item / InventoryItem.kt
1 package ru.deadsoftware.cavedroid.game.model.item
3 import com.badlogic.gdx.graphics.Color
4 import com.badlogic.gdx.graphics.g2d.SpriteBatch
5 import com.badlogic.gdx.graphics.glutils.ShapeRenderer
6 import ru.deadsoftware.cavedroid.game.GameItemsHolder
7 import ru.deadsoftware.cavedroid.game.model.dto.SaveDataDto
8 import ru.deadsoftware.cavedroid.misc.Assets
9 import ru.deadsoftware.cavedroid.misc.Saveable
10 import ru.deadsoftware.cavedroid.misc.utils.drawSprite
11 import ru.deadsoftware.cavedroid.misc.utils.drawString
12 import ru.deadsoftware.cavedroid.misc.utils.px
13 import java.io.Serializable
14 import kotlin.contracts.ExperimentalContracts
15 import kotlin.contracts.contract
17 class InventoryItem @JvmOverloads constructor(
18 val itemKey: String,
19 _amount: Int = 1,
20 ) : Serializable, Saveable {
22 var amount = _amount
23 set(value) {
24 field = if (value < 0) {
25 0
26 } else {
27 value
28 }
29 }
31 @Transient
32 private var _item: Item? = null
34 var item: Item
35 get() {
36 requireNotNull(_item) { "_item is null" }
37 return _item.takeIf { amount > 0 } ?: throw IllegalArgumentException("Accessing item with zero amount")
38 }
39 private set (value) {
40 _item = value
41 }
43 @JvmOverloads
44 constructor(item: Item, amount: Int = 1) : this(item.params.key, amount) {
45 _item = item
46 }
48 fun init(gameItemsHolder: GameItemsHolder) {
49 if (_item != null) {
50 return
51 }
52 _item = gameItemsHolder.getItem(itemKey)
53 }
55 @JvmOverloads
56 fun add(count: Int = 1) {
57 if (count > 0 && Int.MAX_VALUE - count < amount) {
58 throw IllegalArgumentException("$amount + $count exceeds Int.MAX_VALUE")
59 }
61 amount += count
62 }
64 @JvmOverloads
65 fun subtract(count: Int = 1) {
66 if (count < 0) {
67 throw IllegalArgumentException("Can't subtract negative amount")
68 }
70 add(-count)
71 }
73 @JvmOverloads
74 fun canBeAdded(count: Int = 1): Boolean {
75 return amount + count <= item.params.maxStack
76 }
78 private fun drawAmountText(spriteBatch: SpriteBatch, text: String, x: Float, y: Float) {
79 spriteBatch.drawString(text, x + 1, y + 1, Color.BLACK)
80 spriteBatch.drawString(text, x, y, Color.WHITE)
81 }
83 fun drawSelected(spriteBatch: SpriteBatch, x: Float, y: Float) {
84 if (item.isNone()) {
85 return
86 }
88 val sprite = item.sprite
89 val amountString = amount.toString()
90 spriteBatch.drawSprite(sprite, x - 10f, y - 10f, rotation = 0f, width = 20f, height = 20f)
91 drawAmountText(
92 spriteBatch = spriteBatch,
93 text = amountString,
94 x = x + 10f - Assets.getStringWidth(amountString) + 1f,
95 y = y + 10f - Assets.getStringHeight(amountString) + 1f
96 )
97 }
99 fun draw(spriteBatch: SpriteBatch, shapeRenderer: ShapeRenderer, x: Float, y: Float) {
100 if (item.isNone()) {
101 return
104 val sprite = item.sprite
105 val placeableMarginTop = (item as? Item.Placeable)?.block?.params?.spriteMargins?.top ?: 0
106 val placeableMarginLeft = (item as? Item.Placeable)?.block?.params?.spriteMargins?.left ?: 0
107 spriteBatch.drawSprite(sprite, x + placeableMarginLeft, y + placeableMarginTop)
109 if (amount < 2) {
110 return
113 if (item.isTool()) {
114 spriteBatch.end()
115 shapeRenderer.begin(ShapeRenderer.ShapeType.Filled)
116 shapeRenderer.color = Color.GREEN
117 shapeRenderer.rect(
118 /* x = */ x,
119 /* y = */ y + 1.px - 2,
120 /* width = */ 1.px * (amount.toFloat() / item.params.maxStack.toFloat()),
121 /* height = */ 2f
123 shapeRenderer.end()
124 spriteBatch.begin()
125 } else {
126 val amountString = amount.toString()
127 drawAmountText(
128 spriteBatch = spriteBatch,
129 text = amountString,
130 x = x + 1.px - Assets.getStringWidth(amountString),
131 y = y + 1.px - Assets.getStringHeight(amountString)
136 override fun getSaveData(): SaveDataDto.InventoryItemSaveData {
137 return SaveDataDto.InventoryItemSaveData(
138 version = SAVE_DATA_VERSION,
139 itemKey = itemKey,
140 amount = amount,
144 companion object {
145 private const val SAVE_DATA_VERSION = 1
147 @OptIn(ExperimentalContracts::class)
148 fun InventoryItem?.isNoneOrNull(): Boolean {
149 contract { returns(false) implies(this@isNoneOrNull != null) }
150 return this?.item == null || this.item.isNone()
154 fun fromSaveData(
155 saveData: SaveDataDto.InventoryItemSaveData,
156 gameItemsHolder: GameItemsHolder? = null
157 ): InventoryItem {
158 saveData.verifyVersion(SAVE_DATA_VERSION)
160 val inventoryItem = InventoryItem(saveData.itemKey, saveData.amount)
161 gameItemsHolder?.let(inventoryItem::init)
163 return inventoryItem