package mon.stat import scala.reflect.runtime.universe._ import scala.tools.reflect.ToolBox import com.fasterxml.jackson.module.scala.JsonScalaEnumeration import scala.io.Source import mon.util.{TypeReference, YamlHelper} object MoveType extends Enumeration { val Physical, Special, Status = Value } class MoveTypeType extends TypeReference[MoveType.type] object Target extends Enumeration { val Normal, Self, AllAdjacentFoes = Value } class TargetType extends TypeReference[Target.type] abstract class Move { val name : String val desc : String val mvType : MoveType val pow : Int val powCallback : (Monster, Monster) => Int val prior : Int val accuracy : Int val pp : Int val element : Element val flags : Set[String] val target : Target val boosts : Map[Stat, Int] val crit : Int val selfEffect : Secondary val secondary: Secondary // boosts // onHit // onTryHit // zPower, zMoveEffect, zMoveBoost override def toString = { name } } case class MoveToken( val name : String, val shortDesc : String, @JsonScalaEnumeration(classOf[MoveTypeType]) val category : MoveType, val basePower : Option[Int], val basePowerCallback : String, val priority : Int, val accuracy : Option[Int], val pp : Int, val `type` : String, val flags : Map[String, Int], val self : SecondaryToken, val secondary : SecondaryToken, @JsonScalaEnumeration(classOf[TargetType]) val target : Target = Target.Normal, val boosts : Map[String, Int] = Map(), val crit : Int = 0) { def instantiate() = { val token = this new Move { val name = token.name val desc = token.shortDesc val mvType = category val pow = token.basePower.getOrElse(0) val powCallback = Move.compilePowCallback(token.basePowerCallback) val prior = token.priority val pp = token.pp val element = Element(token.`type`) val accuracy = token.accuracy.getOrElse(100) val flags = token.flags.keySet val target = token.target val boosts = if (token.boosts != null) token.boosts.map{case (s, i) => (Statistic(s), i)} else Map() val crit = token.crit val selfEffect = if (token.self != null) token.self.instantiate() else null val secondary = if (token.secondary != null) token.secondary.instantiate() else null } } } object Move { val tokens = YamlHelper.extractSeq[MoveToken](Source.fromInputStream(Move.getClass.getResourceAsStream("data/moves.yaml"))) val moves = tokens.map(_.instantiate()) val byName = moves.map(m => (m.name, m)).toMap def apply(s : String) = byName(s) def compilePowCallback(code: String): (Monster, Monster) => Int = { if (code != null) { val tb = runtimeMirror(getClass.getClassLoader).mkToolBox() val tree = tb.parse( s""" |import mon.stat.Monster |import mon.stat.Statistic._ |def callback(user : Monster, target : Monster): Int = { | $code |} |callback _ """.stripMargin) val f = tb.compile(tree) val wrapper = f() wrapper.asInstanceOf[(Monster, Monster) => Int] } else { null } } }