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 io.estatico.newtype.macros.newtype import wow.doge.mygame.game.entities.CharacterStats.HealHealth case class CharacterStats(hp: CharacterStats.Health, stamina: Int) object CharacterStats { @newtype case class HealHealth(toInt: Int) @newtype case class DamageHealth(toInt: Int) @newtype case class Health(toInt: Int) object Health { implicit class HealthOps(private val h: Health) extends AnyVal { // def +(v: Int): Health = Health(h.toInt + v) // def -(v: Int): Health = Health(h.toInt - v) // def *(v: Int): Health = Health(h.toInt * v) // def /(v: Int): Health = Health(h.toInt / v) def :+(v: HealHealth): Health = Health(h.toInt + v.toInt) def -(v: DamageHealth): Health = Health(h.toInt - v.toInt) } } @newtype case class HealStamina(toInt: Int) @newtype case class DamageStamina(toInt: Int) @newtype case class Stamina(toInt: Int) object Stamina { implicit class StaminaOps(private val h: Stamina) extends AnyVal { // def +(v: Int): Stamina = Stamina(h.toInt + v) // def -(v: Int): Stamina = Stamina(h.toInt - v) // def *(v: Int): Stamina = Stamina(h.toInt * v) // def /(v: Int): Stamina = Stamina(h.toInt / v) def :+(v: HealStamina): Stamina = Stamina(h.toInt + v.toInt) def -(v: DamageStamina): Stamina = Stamina(h.toInt - v.toInt) } } // object Stamina { // implicit class StaminaOps(private val h: Stamina) extends AnyVal { // def +(v: Health): Stamina = Stamina(h.toInt + v.toInt) // def -(v: Health): Stamina = Stamina(h.toInt - v.toInt) // def *(v: Health): Stamina = Stamina(h.toInt * v.toInt) // def /(v: Health): Stamina = Stamina(h.toInt / v.toInt) // } // } // object Damage { // implicit class DamageOps(private val h: Damage) extends AnyVal { // def +(v: Health): Damage = Damage(h.toInt + v.toInt) // def -(v: Health): Damage = Damage(h.toInt - v.toInt) // def *(v: Health): Damage = Damage(h.toInt * v.toInt) // def /(v: Health): Damage = Damage(h.toInt / v.toInt) // } // } } object StatsActor { sealed trait Command // case class TakeDamage(value: Int) extends Command case class TakeDamageResult( value: CharacterStats.DamageHealth, replyTo: ActorRef[(Boolean, CharacterStats)] ) extends Command case class HealResult(value: HealHealth) extends Command 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.toInt)) ) } } 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) { replyTo ! true -> state.stats state.modify(_.stats.hp).setTo(Health(0)) } else { replyTo ! false -> state.stats state.modify(_.stats.hp).using(_ - value) } receive(nextState) case HealResult(value) => receive(state.modify(_.stats.hp).using(_ :+ value)) case CurrentStats(replyTo) => replyTo ! state.stats Behaviors.same } }