KStarbound/src/main/kotlin/ru/dbotthepony/kstarbound/world/TileHealth.kt
2024-04-21 22:26:02 +07:00

167 lines
5.3 KiB
Kotlin

package ru.dbotthepony.kstarbound.world
import ru.dbotthepony.kstarbound.io.readVector2d
import ru.dbotthepony.kstarbound.io.readVector2f
import ru.dbotthepony.kommons.io.writeStruct2d
import ru.dbotthepony.kommons.io.writeStruct2f
import ru.dbotthepony.kommons.util.getValue
import ru.dbotthepony.kommons.util.setValue
import ru.dbotthepony.kstarbound.math.vector.Vector2d
import ru.dbotthepony.kstarbound.defs.tile.TileDamage
import ru.dbotthepony.kstarbound.defs.tile.TileDamageParameters
import ru.dbotthepony.kstarbound.defs.tile.TileDamageType
import ru.dbotthepony.kstarbound.math.Interpolator
import ru.dbotthepony.kstarbound.network.syncher.NetworkedGroup
import ru.dbotthepony.kstarbound.network.syncher.networkedBoolean
import ru.dbotthepony.kstarbound.network.syncher.networkedEnum
import ru.dbotthepony.kstarbound.network.syncher.networkedFixedPoint
import java.io.DataInputStream
import java.io.DataOutputStream
sealed class TileHealth() {
var damageSource: Vector2d = Vector2d.ZERO
protected set
abstract var damagePercent: Double
protected set
abstract var damageEffectTimeFactor: Double
protected set
abstract var isHarvested: Boolean
protected set
abstract var damageType: TileDamageType
protected set
var damageEffectPercentage: Double = 0.0
protected set
abstract fun copy(): TileHealth
val isHealthy: Boolean
get() = damagePercent <= 0.0
val isDead: Boolean
get() = damagePercent >= 1.0 && damageType != TileDamageType.PROTECTED
fun write(stream: DataOutputStream, isLegacy: Boolean) {
if (isLegacy) {
stream.writeFloat(damagePercent.toFloat())
stream.writeFloat(damageEffectTimeFactor.toFloat())
stream.writeBoolean(isHarvested)
stream.writeStruct2f(damageSource.toFloatVector())
} else {
stream.writeDouble(damagePercent)
stream.writeDouble(damageEffectTimeFactor)
stream.writeBoolean(isHarvested)
stream.writeStruct2d(damageSource)
}
stream.writeByte(damageType.ordinal)
}
fun read(stream: DataInputStream, isLegacy: Boolean) {
if (isLegacy) {
damagePercent = stream.readFloat().toDouble()
damageEffectTimeFactor = stream.readFloat().toDouble()
isHarvested = stream.readBoolean()
damageSource = stream.readVector2f().toDoubleVector()
} else {
damagePercent = stream.readDouble()
damageEffectTimeFactor = stream.readDouble()
isHarvested = stream.readBoolean()
damageSource = stream.readVector2d()
}
damageType = TileDamageType.entries[stream.readUnsignedByte()]
damageEffectPercentage = damageEffectTimeFactor.coerceIn(0.0, 1.0) * damagePercent
}
fun reset() {
isHarvested = false
damageSource = Vector2d.ZERO
damageType = TileDamageType.PROTECTED
damagePercent = 0.0
damageEffectTimeFactor = 0.0
}
fun damage(config: TileDamageParameters, source: Vector2d, damage: TileDamage) {
val actualDamage = config.damageDone(damage) / config.totalHealth
damagePercent = (damagePercent + actualDamage).coerceAtMost(1.0)
isHarvested = damage.harvestLevel >= config.harvestLevel
damageSource = source
damageType = damage.type
if (actualDamage > 0.0)
damageEffectTimeFactor = config.maximumEffectTime
damageEffectPercentage = damageEffectTimeFactor.coerceIn(0.0, 1.0) * damagePercent
}
val isTicking: Boolean
get() = !isHealthy && !isDead
fun tick(config: TileDamageParameters, delta: Double): Boolean {
if (isDead || isHealthy)
return false
damagePercent -= config.damageRecovery * delta / config.totalHealth
damageEffectTimeFactor -= delta
if (damagePercent <= 0.0) {
damagePercent = 0.0
damageEffectTimeFactor = 0.0
damageType = TileDamageType.PROTECTED
}
damageEffectPercentage = damageEffectTimeFactor.coerceIn(0.0, 1.0) * damagePercent
return damagePercent > 0.0
}
class Tile() : TileHealth() {
constructor(stream: DataInputStream, isLegacy: Boolean) : this() {
read(stream, isLegacy)
}
override var damagePercent: Double = 0.0
override var damageEffectTimeFactor: Double = 0.0
override var isHarvested: Boolean = false
override var damageType: TileDamageType = TileDamageType.PROTECTED
override fun copy(): Tile {
val copy = Tile()
copy.isHarvested = isHarvested
copy.damageSource = damageSource
copy.damageType = damageType
copy.damagePercent = damagePercent
copy.damageEffectTimeFactor = damageEffectTimeFactor
copy.damageEffectPercentage = damageEffectPercentage
return copy
}
}
class TileEntity() : TileHealth() {
constructor(stream: DataInputStream, isLegacy: Boolean) : this() {
read(stream, isLegacy)
}
val networkGroup = NetworkedGroup()
override var damagePercent: Double by networkedFixedPoint(0.001).also { networkGroup.add(it); it.interpolator = Interpolator.Linear }
override var damageEffectTimeFactor: Double by networkedFixedPoint(0.001).also { networkGroup.add(it); it.interpolator = Interpolator.Linear }
override var isHarvested: Boolean by networkedBoolean().also { networkGroup.add(it) }
override var damageType: TileDamageType by networkedEnum(TileDamageType.PROTECTED).also { networkGroup.add(it) }
override fun copy(): TileEntity {
val copy = TileEntity()
copy.isHarvested = isHarvested
copy.damageSource = damageSource
copy.damageType = damageType
copy.damagePercent = damagePercent
copy.damageEffectTimeFactor = damageEffectTimeFactor
copy.damageEffectPercentage = damageEffectPercentage
return copy
}
}
}