DEADSOFTWARE

f420120b2844e7bd2d77ae4d01513837bac80c74
[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 kotlin.contracts.ExperimentalContracts
14 import kotlin.contracts.contract
16 class InventoryItem @JvmOverloads constructor(
17 val itemKey: String,
18 _amount: Int = 1,
19 ) : Saveable {
21 var amount = _amount
22 set(value) {
23 field = if (value < 0) {
24 0
25 } else {
26 value
27 }
28 }
30 private var _item: Item? = null
32 var item: Item
33 get() {
34 requireNotNull(_item) { "_item is null" }
35 return _item.takeIf { amount > 0 } ?: throw IllegalArgumentException("Accessing item with zero amount")
36 }
37 private set (value) {
38 _item = value
39 }
41 @JvmOverloads
42 constructor(item: Item, amount: Int = 1) : this(item.params.key, amount) {
43 _item = item
44 }
46 fun init(gameItemsHolder: GameItemsHolder) {
47 if (_item != null) {
48 return
49 }
50 _item = gameItemsHolder.getItem(itemKey)
51 }
53 @JvmOverloads
54 fun add(count: Int = 1) {
55 if (count > 0 && Int.MAX_VALUE - count < amount) {
56 throw IllegalArgumentException("$amount + $count exceeds Int.MAX_VALUE")
57 }
59 amount += count
60 }
62 @JvmOverloads
63 fun subtract(count: Int = 1) {
64 if (count < 0) {
65 throw IllegalArgumentException("Can't subtract negative amount")
66 }
68 add(-count)
69 }
71 @JvmOverloads
72 fun canBeAdded(count: Int = 1): Boolean {
73 return amount + count <= item.params.maxStack
74 }
76 private fun drawAmountText(spriteBatch: SpriteBatch, text: String, x: Float, y: Float) {
77 spriteBatch.drawString(text, x + 1, y + 1, Color.BLACK)
78 spriteBatch.drawString(text, x, y, Color.WHITE)
79 }
81 fun drawSelected(spriteBatch: SpriteBatch, x: Float, y: Float) {
82 if (item.isNone()) {
83 return
84 }
86 val sprite = item.sprite
87 val amountString = amount.toString()
88 spriteBatch.drawSprite(sprite, x - 10f, y - 10f, rotation = 0f, width = 20f, height = 20f)
89 drawAmountText(
90 spriteBatch = spriteBatch,
91 text = amountString,
92 x = x + 10f - Assets.getStringWidth(amountString) + 1f,
93 y = y + 10f - Assets.getStringHeight(amountString) + 1f
94 )
95 }
97 fun draw(spriteBatch: SpriteBatch, shapeRenderer: ShapeRenderer, x: Float, y: Float) {
98 if (item.isNone()) {
99 return
102 val sprite = item.sprite
103 val placeableMarginTop = (item as? Item.Placeable)?.block?.params?.spriteMargins?.top ?: 0
104 val placeableMarginLeft = (item as? Item.Placeable)?.block?.params?.spriteMargins?.left ?: 0
105 spriteBatch.drawSprite(sprite, x + placeableMarginLeft, y + placeableMarginTop)
107 if (amount < 2) {
108 return
111 if (item.isTool()) {
112 spriteBatch.end()
113 shapeRenderer.begin(ShapeRenderer.ShapeType.Filled)
114 shapeRenderer.color = Color.GREEN
115 shapeRenderer.rect(
116 /* x = */ x,
117 /* y = */ y + 1.px - 2,
118 /* width = */ 1.px * (amount.toFloat() / item.params.maxStack.toFloat()),
119 /* height = */ 2f
121 shapeRenderer.end()
122 spriteBatch.begin()
123 } else {
124 val amountString = amount.toString()
125 drawAmountText(
126 spriteBatch = spriteBatch,
127 text = amountString,
128 x = x + 1.px - Assets.getStringWidth(amountString),
129 y = y + 1.px - Assets.getStringHeight(amountString)
134 override fun getSaveData(): SaveDataDto.InventoryItemSaveData {
135 return SaveDataDto.InventoryItemSaveData(
136 version = SAVE_DATA_VERSION,
137 itemKey = itemKey,
138 amount = amount,
142 companion object {
143 private const val SAVE_DATA_VERSION = 1
145 @OptIn(ExperimentalContracts::class)
146 fun InventoryItem?.isNoneOrNull(): Boolean {
147 contract { returns(false) implies(this@isNoneOrNull != null) }
148 return this?.item == null || this.item.isNone()
152 fun fromSaveData(
153 saveData: SaveDataDto.InventoryItemSaveData,
154 gameItemsHolder: GameItemsHolder? = null
155 ): InventoryItem {
156 saveData.verifyVersion(SAVE_DATA_VERSION)
158 val inventoryItem = InventoryItem(saveData.itemKey, saveData.amount)
159 gameItemsHolder?.let(inventoryItem::init)
161 return inventoryItem