You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
182 lines
6.3 KiB
182 lines
6.3 KiB
package model
|
|
|
|
import korlibs.math.*
|
|
import korlibs.time.*
|
|
import kotlin.math.*
|
|
|
|
data class Battler(
|
|
var name: String,
|
|
var composure: Double,
|
|
var health: Double,
|
|
var maxHealth: Double,
|
|
var energy: Double,
|
|
var stamina: Double,
|
|
var maxStamina: Double,
|
|
|
|
var shaken: Boolean = false,
|
|
var shakenTimes: Int = 0,
|
|
var composurePausedUntil: TimeSpan = TimeSpan.ZERO,
|
|
var energyPausedUntil: TimeSpan = TimeSpan.ZERO,
|
|
var currentUpdate: TimeSpan = TimeSpan.ZERO,
|
|
private var lastUpdate: TimeSpan = TimeSpan.ZERO,
|
|
private var lastShaken: Boolean = shaken,
|
|
private var lastComposure: Double = composure,
|
|
private var lastEnergy: Double = energy,
|
|
private var lastStamina: Double = stamina,
|
|
) {
|
|
constructor(name: String, health: Double, stamina: Double) :
|
|
this(name = name, composure = health, health = health, maxHealth = health,
|
|
energy = stamina, stamina = stamina, maxStamina = stamina)
|
|
|
|
private val composureChargeTime: TimeSpan get() = TimeSpan(45_000.0 * 1.2.pow(shakenTimes - 1))
|
|
private val composureChargeDelay: TimeSpan get() = TimeSpan(2_000.0 * 1.2.pow(shakenTimes - 1))
|
|
private val composureRecoveryTime: TimeSpan get() = TimeSpan(7_000.0 * 1.2.pow(shakenTimes - 1))
|
|
private val composureRecoveryDelay: TimeSpan get() = TimeSpan(3_000.0 * 1.2.pow(shakenTimes - 1))
|
|
|
|
private val composureChargeCoefficient: Double get() = health / composureChargeTime.milliseconds.squared()
|
|
|
|
private val energyChargeTime: TimeSpan get() = TimeSpan(30_000.0)
|
|
private val energyChargeDelay: TimeSpan get() = TimeSpan(1_000.0)
|
|
private val staminaChargeTime: TimeSpan get() = TimeSpan(300_000.0)
|
|
|
|
private fun advanceComposureTo(t: TimeSpan) {
|
|
var dtComposure = if (lastUpdate < composurePausedUntil) {
|
|
if (t > composurePausedUntil) {
|
|
t - composurePausedUntil
|
|
} else {
|
|
TimeSpan.ZERO
|
|
}
|
|
} else {
|
|
t - lastUpdate
|
|
}
|
|
if (lastShaken && dtComposure.isPositive() && health > 0) {
|
|
val halfHealth = health/2.0
|
|
val dtRecover = composureRecoveryTime * (halfHealth - lastComposure.coerceAtLeast(0.0)) / halfHealth
|
|
if (dtComposure > dtRecover) {
|
|
composure = halfHealth
|
|
shaken = false
|
|
dtComposure -= dtRecover
|
|
} else {
|
|
composure = (
|
|
lastComposure.coerceAtLeast(0.0) + dtComposure.milliseconds * halfHealth / composureRecoveryTime.milliseconds)
|
|
shaken = lastShaken
|
|
dtComposure = TimeSpan.ZERO
|
|
}
|
|
} else {
|
|
composure = lastComposure
|
|
shaken = lastShaken
|
|
}
|
|
if (dtComposure.isPositive()) {
|
|
if (health > 0) {
|
|
val lastChargeTime = TimeSpan(
|
|
sqrt(4 * composureChargeCoefficient * composure) / (2 * composureChargeCoefficient)
|
|
)
|
|
composure = if (dtComposure + lastChargeTime >= composureChargeTime) {
|
|
health
|
|
} else {
|
|
(composureChargeCoefficient * (lastChargeTime + dtComposure).milliseconds.squared())
|
|
}
|
|
} else {
|
|
composure = health
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun advanceEnergyAndStaminaTo(t: TimeSpan) {
|
|
var dtEnergy = if (lastUpdate < energyPausedUntil) {
|
|
if (t > energyPausedUntil) {
|
|
t - energyPausedUntil
|
|
} else {
|
|
TimeSpan.ZERO
|
|
}
|
|
} else {
|
|
t - lastUpdate
|
|
}
|
|
if (dtEnergy.isPositive()) {
|
|
if (lastEnergy < lastStamina) {
|
|
if (lastStamina > 0) {
|
|
val dtToFull = energyChargeTime * (lastStamina - lastEnergy) / lastStamina
|
|
if (dtEnergy >= dtToFull) {
|
|
energy = lastStamina
|
|
dtEnergy -= dtToFull
|
|
} else {
|
|
energy = lastEnergy + (lastStamina * dtEnergy.milliseconds) / energyChargeTime.milliseconds
|
|
dtEnergy = TimeSpan.ZERO
|
|
}
|
|
} else {
|
|
energy = lastStamina
|
|
}
|
|
}
|
|
if (dtEnergy.isPositive() && lastStamina < maxStamina) {
|
|
stamina = min(
|
|
maxStamina,
|
|
lastStamina + (maxStamina * dtEnergy.milliseconds) / staminaChargeTime.milliseconds)
|
|
energy = stamina
|
|
}
|
|
}
|
|
}
|
|
|
|
fun advanceTo(t: TimeSpan) {
|
|
currentUpdate = t
|
|
if (composure < health) {
|
|
advanceComposureTo(t)
|
|
}
|
|
if (energy < stamina || stamina < maxStamina) {
|
|
advanceEnergyAndStaminaTo(t)
|
|
}
|
|
}
|
|
|
|
fun becomeShaken() {
|
|
composure = health.coerceAtMost(0.0)
|
|
if (shaken) {
|
|
return
|
|
}
|
|
composurePausedUntil = (currentUpdate + composureRecoveryDelay).coerceAtLeast(composurePausedUntil)
|
|
shaken = true
|
|
shakenTimes += 1
|
|
}
|
|
|
|
fun inflictComposureDamage(damage: Double) {
|
|
if (shaken) {
|
|
return
|
|
}
|
|
composurePausedUntil = (currentUpdate + composureChargeDelay).coerceAtLeast(composurePausedUntil)
|
|
composure -= damage
|
|
if (composure <= 0) {
|
|
becomeShaken()
|
|
}
|
|
}
|
|
|
|
fun inflictHealthDamage(damage: Double) {
|
|
composurePausedUntil = (currentUpdate + composureRecoveryDelay).coerceAtLeast(composurePausedUntil)
|
|
health -= damage
|
|
composure -= damage
|
|
if (composure <= 0) {
|
|
becomeShaken()
|
|
}
|
|
}
|
|
|
|
fun spendEnergy(cost: Double) {
|
|
energyPausedUntil = (currentUpdate + energyChargeDelay).coerceAtLeast(energyPausedUntil)
|
|
energy = (energy - cost).coerceAtLeast(0.0)
|
|
}
|
|
|
|
fun spendStamina(cost: Double) {
|
|
energyPausedUntil = (currentUpdate + energyChargeDelay).coerceAtLeast(energyPausedUntil)
|
|
stamina = (stamina - cost).coerceAtLeast(0.0)
|
|
energy = (energy - cost).coerceAtLeast(0.0)
|
|
}
|
|
|
|
fun updateAt(t: TimeSpan, block: Battler.() -> Unit) {
|
|
advanceTo(t)
|
|
|
|
block(this)
|
|
|
|
lastUpdate = currentUpdate
|
|
lastShaken = shaken
|
|
lastComposure = composure
|
|
lastEnergy = energy
|
|
lastStamina = stamina
|
|
}
|
|
}
|
|
|
|
|