package fmon.stat import scala.collection.mutable.{Map => MutMap} import scala.reflect.runtime.universe._ import scala.tools.reflect.ToolBox import scala.util.Random import scala.io.Source import fmon.util._ import EffectType.Volatile object EffectType extends Enumeration { val NonVolatile, Volatile, AbilityEffect, MoveEffect, ItemEffect, Field, Weather = Value def parse(s : String, default : EffectType) = s match { case "ability" => AbilityEffect case "item" => ItemEffect case "move" => MoveEffect case "status" => NonVolatile case "volatile" => Volatile case "weather" => Weather case _ => default } } trait Effect { def name: String def effectType: EffectType def isItem = effectType == EffectType.ItemEffect def isMove = effectType == EffectType.MoveEffect def isAbility = effectType == EffectType.AbilityEffect } case class EffectSource(mon: Monster, effect: Effect) { def isItem = effect.isItem def isMove = effect.isMove def isAbility = effect.isAbility def triggerMsg = s"[${mon}'s ${effect}]" } class Status(template: StatusTemplate) extends Effect { def name = template.name // val id def effectType = template.effectType def onStart(mon: Monster, source: EffectSource)(implicit rng: Random) = template.onStart(this, mon, source, rng) def onEnd(mon: Monster) = template.onEnd(this, mon) def onModifyStat(mon: Monster, stat: Stat) = template.onModifyStat(this, mon, stat) // val onBeforeMovePriority : Int def onBeforeMove(mon: Monster, move: MoveTurn, target: Monster)(implicit rng: Random) = template.onBeforeMove(this, mon, move, target, rng) // val onModifyMove // val onHit def onResidualOrder = template.onResidualOrder def onResidual(mon: Monster) = template.onResidual(this, mon) // val onSwitchIn val intData: MutMap[String, Int] = MutMap[String, Int]() val stringData = MutMap[String, String]() override def toString = name } abstract class StatusTemplate { val name: String // val id val effectType: EffectType val onStart: (Status, Monster, EffectSource, Random) => Unit val onEnd: (Status, Monster) => Unit val onModifyStat: (Status, Monster, Stat) => Fraction // val onBeforeMovePriority : Int val onBeforeMove: (Status, Monster, MoveTurn, Monster, Random) => Boolean // val onModifyMove // val onHit val onResidualOrder: Int val onResidual: (Status, Monster) => Unit // val onSwitchIn def build = new Status(this) override def toString = name } case class StatusToken( val name: String, val effectType: String, val onStart: String, val onEnd: String, val onBeforeMove: String, val onModifyStat: String, val onResidualOrder: Int, val onResidual: String) { def instantiate() = { val self = this new StatusTemplate { val name = self.name val effectType = EffectType.parse(self.effectType, Volatile) val onStart = Status.compileOnStart(self.onStart) val onEnd = Status.compileOnEnd(self.onEnd) val onBeforeMove = Status.compileOnBeforeMove(self.onBeforeMove) val onModifyStat = Status.compileOnModifyStat(self.onModifyStat) val onResidualOrder = self.onResidualOrder val onResidual = Status.compileOnResidual(self.onResidual) } } } object Status { private var statuses = Map[String, StatusTemplate]() val tokens = YamlHelper.extractMap[StatusToken](Source.fromInputStream(Status.getClass.getResourceAsStream("data/statuses.yaml"))) def apply(name: String): StatusTemplate = { if (!statuses.contains(name)) { statuses = statuses.updated(name, tokens(name).instantiate()) } statuses(name) } private val tb = runtimeMirror(getClass.getClassLoader).mkToolBox() private val header = """ import scala.util.Random import fmon.stat._ import fmon.stat.MoveType._ import fmon.stat.Statistic._ import fmon.util._ """ def compileOnStart(code: String): (Status, Monster, EffectSource, Random ) => Unit = { if (code == null) { (_, _, _, _) => () } else { val tree = tb.parse( s""" |$header |def onStart(self:Status, mon: Monster, source: EffectSource, rng: Random) = { | $code |} |onStart _ """.stripMargin) val f = tb.compile(tree) val wrapper = f() wrapper.asInstanceOf[(Status, Monster, EffectSource, Random) => Unit] } } def compileOnEnd(code: String): (Status, Monster) => Unit = { if (code == null) { (_, _) => () } else { val tree = tb.parse( s""" |$header |def onStart(self:Status, mon: Monster) = { | $code |} onStart _ """.stripMargin) val f = tb.compile(tree) val wrapper = f() wrapper.asInstanceOf[(Status, Monster) => Unit] } } def compileOnBeforeMove(code: String): (Status, Monster, MoveTurn, Monster, Random) => Boolean = { if (code == null) { (_, _, _, _, _) => true } else { val tree = tb.parse( s""" $header def onBeforeMove(self: Status, mon: Monster, move: MoveTurn, target: Monster, rng: Random): Boolean = { $code } onBeforeMove _ """) val f = tb.compile(tree) val wrapper = f() wrapper.asInstanceOf[(Status, Monster, MoveTurn, Monster, Random) => Boolean] } } def compileOnModifyStat(code: String): (Status, Monster, Stat) => Fraction = { if (code == null) { (_, _, _) => 1.frac } else { val tree = tb.parse( s""" $header def onModifyStat(self: Status, mon: Monster, stat: Stat): Fraction = { $code } onModifyStat _ """) val f = tb.compile(tree) val wrapper = f() wrapper.asInstanceOf[(Status, Monster, Stat) => Fraction] } } def compileOnResidual(code: String): (Status, Monster) => Unit = { if (code == null) { (_, _) => () } else { val tree = tb.parse( s""" |$header |def onResidual(self: Status, mon: Monster) = { | $code |} |onResidual _ """.stripMargin) val f = tb.compile(tree) val wrapper = f() wrapper.asInstanceOf[(Status, Monster) => Unit] } } }