fakemon/FakeMon/src/fmon/stat/Status.scala

222 lines
6.3 KiB
Scala

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]
}
}
}