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 } } }