DEADSOFTWARE

Add furnace, more craft and items
[cavedroid.git] / core / src / ru / deadsoftware / cavedroid / game / model / block / Block.kt
1 package ru.deadsoftware.cavedroid.game.model.block
3 import com.badlogic.gdx.graphics.g2d.Sprite
4 import com.badlogic.gdx.graphics.g2d.SpriteBatch
5 import com.badlogic.gdx.math.Rectangle
6 import com.badlogic.gdx.utils.TimeUtils
7 import ru.deadsoftware.cavedroid.game.model.item.Item
8 import ru.deadsoftware.cavedroid.misc.utils.colorFromHexString
9 import kotlin.contracts.ExperimentalContracts
10 import kotlin.contracts.contract
12 @OptIn(ExperimentalContracts::class)
13 sealed class Block {
15 abstract val params: CommonBlockParams
17 val width: Float get() = 16f - params.collisionMargins.left - params.collisionMargins.right
18 val height: Float get() = 16f - params.collisionMargins.top - params.collisionMargins.bottom
20 val spriteWidth: Float get() = 16f - params.spriteMargins.left - params.spriteMargins.right
21 val spriteHeight: Float get() = 16f - params.spriteMargins.top - params.spriteMargins.bottom
23 protected var animation: Array<Sprite>? = null
25 private var _sprite: Sprite? = null
26 get() {
27 return animation?.get(currentAnimationFrame) ?: field
28 }
30 open val sprite: Sprite
31 get() = requireNotNull(_sprite) { "null sprite for block '${params.key}'" }
33 private val currentAnimationFrame: Int
34 get() {
35 return params.animationInfo?.let { animInfo ->
36 ((TimeUtils.millis() / ANIMATION_FRAME_DURATION_MS) % animInfo.framesCount).toInt()
37 } ?: 0
38 }
40 override fun hashCode(): Int {
41 return params.key.hashCode()
42 }
44 override fun equals(other: Any?): Boolean {
45 return params.key == (other as Item).params.key
46 }
48 fun initialize() {
49 initAnimation()
50 initSprite()
51 }
53 private fun initAnimation() {
54 animation = params.animationInfo?.let { animInfo ->
55 requireNotNull(params.texture) { "Cannot derive animation frames from null sprite" }
56 Array(animInfo.framesCount) { y ->
57 val width = 16 - params.spriteMargins.left - params.spriteMargins.right
58 val height = 16 - params.spriteMargins.top - params.spriteMargins.bottom
59 Sprite(params.texture, params.spriteMargins.left, 16 * y + params.spriteMargins.top, width, height)
60 .apply {
61 flip(false, true)
62 params.tint?.let { tint -> color = colorFromHexString(tint) }
63 }
64 }
65 }
66 }
68 private fun initSprite() {
69 _sprite = animation?.get(0) ?: params.texture?.let { tex ->
70 val width = 16 - params.spriteMargins.left - params.spriteMargins.right
71 val height = 16 - params.spriteMargins.top - params.spriteMargins.bottom
72 Sprite(tex, params.spriteMargins.left, params.spriteMargins.top, width, height)
73 .apply {
74 flip(false, true)
75 params.tint?.let { tint -> color = colorFromHexString(tint) }
76 }
77 }
78 }
80 fun requireSprite() = requireNotNull(sprite)
82 fun draw(spriter: SpriteBatch, x: Float, y: Float) {
83 sprite.apply {
84 setBounds(
85 /* x = */ x + params.spriteMargins.left,
86 /* y = */ y + params.spriteMargins.top,
87 /* width = */ spriteWidth,
88 /* height = */ spriteHeight
89 )
90 draw(spriter)
91 }
92 }
94 fun isFluid(): Boolean {
95 contract { returns(true) implies (this@Block is Fluid) }
96 return this is Fluid
97 }
99 fun isWater(): Boolean {
100 contract { returns(true) implies (this@Block is Water) }
101 return this is Water
104 fun isLava(): Boolean {
105 contract { returns(true) implies (this@Block is Lava) }
106 return this is Lava
109 fun isSlab(): Boolean {
110 contract { returns(true) implies (this@Block is Slab) }
111 return this is Slab
114 fun isFurnace(): Boolean {
115 contract { returns(true) implies (this@Block is Furnace) }
116 return this is Furnace
119 fun isNone(): Boolean {
120 contract { returns(true) implies (this@Block is None) }
121 return this is None
124 fun getRectangle(x: Int, y: Int): Rectangle {
125 return Rectangle(
126 /* x = */ x * 16f + params.collisionMargins.left,
127 /* y = */ y * 16f + params.collisionMargins.top,
128 /* width = */ width,
129 /* height = */ height
133 data class None(
134 override val params: CommonBlockParams
135 ) : Block()
137 data class Normal(
138 override val params: CommonBlockParams,
139 ) : Block()
141 data class Furnace(
142 override val params: CommonBlockParams,
143 ): Block() {
145 override val sprite: Sprite
146 get() = getSprite(false)
148 private fun getSprite(isActive: Boolean): Sprite {
149 return animation?.let { animation ->
150 if (isActive) {
151 animation[1]
152 } else {
153 animation[0]
155 } ?: sprite
158 fun draw(spriter: SpriteBatch, x: Float, y: Float, isActive: Boolean) {
159 getSprite(isActive).apply {
160 setBounds(
161 /* x = */ x + params.spriteMargins.left,
162 /* y = */ y + params.spriteMargins.top,
163 /* width = */ spriteWidth,
164 /* height = */ spriteHeight
166 draw(spriter)
172 data class Slab(
173 override val params: CommonBlockParams,
174 val fullBlockKey: String,
175 val otherPartBlockKey: String,
176 ): Block()
178 sealed class Fluid: Block() {
179 abstract val state: Int
182 data class Water(
183 override val params: CommonBlockParams,
184 override val state: Int,
185 ) : Fluid()
187 data class Lava(
188 override val params: CommonBlockParams,
189 override val state: Int,
190 ) : Fluid()
192 /* Legacy accessors below */
194 // collision margins
195 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) val left: Int get() = params.collisionMargins.left
196 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) val right: Int get() = params.collisionMargins.left
197 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) val top: Int get() = params.collisionMargins.left
198 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) val bottom: Int get() = params.collisionMargins.left
200 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) val hp: Int get() = params.hitPoints
201 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) val collision: Boolean get() = params.hasCollision
202 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) val animated: Boolean get() = params.animationInfo != null
203 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) val frames: Int get() = params.animationInfo?.framesCount ?: 0
204 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) val drop: String get() = params.dropInfo?.itemKey ?: "none"
205 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) fun hasDrop() = params.dropInfo != null
206 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) fun toJump() = params.hasCollision && params.collisionMargins.top < 8
207 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) fun hasCollision() = params.hasCollision
208 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) fun isBackground() = params.isBackground
209 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) fun isTransparent() = params.isTransparent
210 @Deprecated(LEGACY_ACCESSOR_DEPRECATION) fun getTexture() = sprite
212 companion object {
213 private const val LEGACY_ACCESSOR_DEPRECATION = "legacy accessors will be removed"
214 private const val ANIMATION_FRAME_DURATION_MS = 100L