forked from nova/jmonkey-test
139 lines
4.2 KiB
Scala
139 lines
4.2 KiB
Scala
package wow.doge.mygame.game.entities
|
|
|
|
import akka.actor.typed.ActorRef
|
|
import akka.actor.typed.Behavior
|
|
import akka.actor.typed.scaladsl.ActorContext
|
|
import akka.actor.typed.scaladsl.Behaviors
|
|
import cats.Show
|
|
import cats.kernel.Eq
|
|
import io.estatico.newtype.macros.newtype
|
|
|
|
final case class CharacterStats(
|
|
hp: CharacterStats.Health,
|
|
stamina: CharacterStats.Stamina
|
|
)
|
|
object CharacterStats {
|
|
@newtype final case class HealHealth(toInt: Int)
|
|
@newtype final case class DamageHealth(toInt: Int)
|
|
@newtype final case class Health(toInt: Int)
|
|
object Health {
|
|
implicit class HealthOps(private val h: Health) extends AnyVal {
|
|
def :+(v: HealHealth): Health = Health(h.toInt + v.toInt)
|
|
def -(v: DamageHealth): Health = Health(h.toInt - v.toInt)
|
|
}
|
|
}
|
|
@newtype final case class HealStamina(toInt: Int)
|
|
@newtype final case class DamageStamina(toInt: Int)
|
|
@newtype final case class Stamina(toInt: Int)
|
|
object Stamina {
|
|
implicit class StaminaOps(private val h: Stamina) extends AnyVal {
|
|
def :+(v: HealStamina): Stamina = Stamina(h.toInt + v.toInt)
|
|
def -(v: DamageStamina): Stamina = Stamina(h.toInt - v.toInt)
|
|
}
|
|
}
|
|
|
|
implicit val show = Show.fromToString[CharacterStats]
|
|
implicit val eq = Eq.fromUniversalEquals[CharacterStats]
|
|
|
|
}
|
|
|
|
object StatsActor {
|
|
import CharacterStats._
|
|
|
|
sealed trait Status
|
|
object Status {
|
|
case object Alive extends Status
|
|
case object Dead extends Status
|
|
}
|
|
|
|
sealed trait Command
|
|
final case class TakeDamageResult(
|
|
value: CharacterStats.DamageHealth,
|
|
replyTo: ActorRef[(Status, CharacterStats)]
|
|
) extends Command
|
|
final case class ConsumeStaminaResult(
|
|
value: CharacterStats.DamageStamina,
|
|
replyTo: ActorRef[(Status, CharacterStats)]
|
|
) extends Command
|
|
final case class HealHealthResult(
|
|
value: HealHealth,
|
|
replyTo: ActorRef[CharacterStats]
|
|
) extends Command
|
|
|
|
final case class HealStaminaResult(
|
|
value: HealStamina,
|
|
replyTo: ActorRef[CharacterStats]
|
|
) extends Command
|
|
final case class CurrentStats(replyTo: ActorRef[CharacterStats])
|
|
extends Command
|
|
|
|
class Props(
|
|
startingHealth: CharacterStats.Health,
|
|
startingStamina: CharacterStats.Stamina
|
|
) {
|
|
def behavior =
|
|
Behaviors.setup[Command] { ctx =>
|
|
new StatsActor(ctx, this)
|
|
.receive(
|
|
State(CharacterStats(startingHealth, startingStamina))
|
|
)
|
|
}
|
|
}
|
|
|
|
final case class State(stats: CharacterStats)
|
|
}
|
|
class StatsActor(
|
|
ctx: ActorContext[StatsActor.Command],
|
|
props: StatsActor.Props
|
|
) {
|
|
import StatsActor._
|
|
import CharacterStats._
|
|
import com.softwaremill.quicklens._
|
|
def receive(state: State): Behavior[Command] =
|
|
Behaviors.receiveMessage[Command] {
|
|
// Todo add min max values
|
|
// case TakeDamage(value) =>
|
|
// val nextState =
|
|
// if (state.stats.hp - value <= 0)
|
|
// state.modify(_.stats.hp).setTo(0)
|
|
// else
|
|
// state.modify(_.stats.hp).using(_ - value)
|
|
// receive(nextState)
|
|
case TakeDamageResult(value, replyTo) =>
|
|
val nextState = if ((state.stats.hp - value).toInt <= 0) {
|
|
val s = state.modify(_.stats.hp).setTo(Health(0))
|
|
replyTo ! Status.Dead -> s.stats
|
|
s
|
|
} else {
|
|
val s = state.modify(_.stats.hp).using(_ - value)
|
|
replyTo ! Status.Alive -> s.stats
|
|
s
|
|
}
|
|
receive(nextState)
|
|
case ConsumeStaminaResult(value, replyTo) =>
|
|
val nextState = if ((state.stats.stamina - value).toInt <= 0) {
|
|
val s = state.modify(_.stats.stamina).setTo(Stamina(0))
|
|
replyTo ! Status.Alive -> s.stats
|
|
s
|
|
} else {
|
|
val s = state.modify(_.stats.stamina).using(_ - value)
|
|
replyTo ! Status.Alive -> s.stats
|
|
s
|
|
}
|
|
receive(nextState)
|
|
case HealHealthResult(value, replyTo) =>
|
|
val nextState = receive(state.modify(_.stats.hp).using(_ :+ value))
|
|
replyTo ! state.stats
|
|
nextState
|
|
|
|
case HealStaminaResult(value, replyTo) =>
|
|
val nextState = receive(state.modify(_.stats.stamina).using(_ :+ value))
|
|
replyTo ! state.stats
|
|
nextState
|
|
|
|
case CurrentStats(replyTo) =>
|
|
replyTo ! state.stats
|
|
Behaviors.same
|
|
}
|
|
}
|