Renamed the root package to fmon and added paralysis, burn, and sleep status effects

This commit is contained in:
James Daly 2019-06-02 17:40:40 -04:00
parent d13d5b3bf6
commit 40553d36b9
31 changed files with 378 additions and 195 deletions

View File

@ -1,4 +1,4 @@
package mon
package fmon
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
@ -7,8 +7,8 @@ import com.fasterxml.jackson.module.scala.DefaultScalaModule
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
import mon.battle.BattleEngine
import mon.stat._
import fmon.battle.BattleEngine
import fmon.stat._
case class Prop(url : Seq[String])
@ -19,8 +19,8 @@ object Game {
implicit val rng = new scala.util.Random()
val form1 = Form("Diabolo")
val form2 = Form("Chanilla")
val movepool1 = IndexedSeq(Move("Close Combat"))
val movepool2 = IndexedSeq(Move("Absorb"))
val movepool1 = IndexedSeq(Move("Ice Beam"))
val movepool2 = IndexedSeq(Move("Scald"))
val p1 = TrainerID("Jaeda", Gender.Female, 0)
val p2 = TrainerID("Wild Monster", Gender.Male, 0)
val party1 = new Party(p1, new MonsterPtr(new Monster(new StorageMon("Allied Mon", 500, Gene.randomGene(null, form1), form1, Statistic.emptyEvs, movepool1))), IndexedSeq())

View File

@ -1,7 +1,7 @@
package mon.battle
package fmon.battle
import mon.stat._
import mon.stat.Statistic.Speed
import fmon.stat._
import fmon.stat.Statistic.Speed
case class Action(user : MonsterPtr, move : MoveTurn, target : MonsterPtr) extends Comparable[Action] {
override def compareTo(other : Action) = {

View File

@ -1,10 +1,10 @@
package mon.battle
package fmon.battle
import scala.util.Random
import mon.stat._
import mon.stat.Statistic._
import mon.util.Fraction
import fmon.stat._
import fmon.stat.Statistic._
import fmon.util.Fraction
class BattleEngine(val player: Party, val enemy: Party)(implicit val rng: Random) {
@ -18,13 +18,12 @@ class BattleEngine(val player: Party, val enemy: Party)(implicit val rng: Random
def playTurn() = {
val playerAction = player.pollAction(enemy)
val enemyAction = enemy.pollAction(player)
println(enemyAction)
val actions = Seq(playerAction, enemyAction)
val queue = rng.shuffle(actions).sorted // Shuffle to randomize in the event of a tie
queue.foreach(useMove)
val eotQueue = Seq(player.lead, enemy.lead).sortBy(_(Speed))
eotQueue.foreach(mon => mon.status.map(_.onResidual.map(_(mon))))
eotQueue.foreach(mon => mon.status.map(_.onResidual(mon)))
if (!player.lead.isAlive) {
if (player.canFight) {
@ -52,7 +51,9 @@ class BattleEngine(val player: Party, val enemy: Party)(implicit val rng: Random
val move = action.move
val target = action.target
if (user.isAlive) {
move.useMove(user, target)
if (user.status.forall(_.onBeforeMove(user, move, target, rng))) {
move.useMove(user, target)
}
}
}
}

View File

@ -1,9 +1,9 @@
package mon
package fmon
import scala.languageFeature.implicitConversions
import scala.language.implicitConversions
import scala.util.Random
import mon.util._
import fmon.util._
package object battle {

View File

@ -1,8 +1,8 @@
package mon.stat
package fmon.stat
import scala.io.Source
import mon.util.YamlHelper
import fmon.util.YamlHelper
case class Element(val name : String, val effect : Map[String, Double]) {

View File

@ -1,4 +1,4 @@
package mon.stat
package fmon.stat
import scala.io.Source
@ -6,7 +6,7 @@ import com.fasterxml.jackson.module.scala.JsonScalaEnumeration
import Statistic._
import mon.util.YamlHelper
import fmon.util.YamlHelper
abstract class Form {
val name : String

View File

@ -1,4 +1,4 @@
package mon.stat
package fmon.stat
object Gender extends Enumeration {
val Male, Female, Fluid, Neuter = Value

View File

@ -1,4 +1,4 @@
package mon.stat
package fmon.stat
import scala.util.Random

View File

@ -1,8 +1,8 @@
package mon.stat
package fmon.stat
import scala.util._
import mon.util.Fraction
import fmon.util._
import Monster._
import Statistic._
@ -20,7 +20,7 @@ class Monster(val base : StorageMon) {
def apply(s : Stat) = {
val mod = boosts.getOrElse(s, 0)
val mult = if (mod > 0) Fraction(2 + mod, 2) else Fraction(2, 2 - mod)
mult * stats(s)
status.foldLeft(1.frac)((m, sts) => m * sts.onModifyStat(this, s)) * mult * stats(s)
}
def elements = base.form.elements
@ -36,6 +36,11 @@ class Monster(val base : StorageMon) {
hp = Math.min(stats(Hp), hp + healing)
}
def cureStatus() {
status.map(_.onEnd(this))
status = None
}
def applyBoost(s : Stat, boost : Int) {
val modified = boosts.getOrElse(s, 0) + boost
boosts = boosts.updated(s, Math.min(MaxBoost, Math.max(-MaxBoost, modified)))

View File

@ -1,4 +1,4 @@
package mon.stat
package fmon.stat
class MonsterPtr(var mon : Monster) {

View File

@ -1,4 +1,4 @@
package mon.stat
package fmon.stat
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
@ -9,7 +9,7 @@ import scala.io.Source
import scala.util.Random
import Statistic._
import mon.util._
import fmon.util._
object MoveType extends Enumeration {
val Physical, Special, Status = Value
@ -23,6 +23,7 @@ class TargetType extends TypeReference[Target.type]
trait MoveTurn {
def name: String
def flags: Set[String]
def prior: Int
def target: Target
def useMove(user: Monster, target: Monster)(implicit rng: Random): Unit
@ -30,6 +31,7 @@ trait MoveTurn {
class SwitchOut(val party: Party, val replacement: Monster) extends MoveTurn {
def name = "Swap"
def flags = Set()
def prior = +6
def target = Target.Self
@ -134,14 +136,14 @@ abstract class Move extends MoveTurn {
println("It's not very effective.")
}
val maxDmg = (baseDmg * multiplier).toInt
val minDmg = (17 \ 20) * maxDmg
val minDmg = (17 \\ 20) * maxDmg
rng.nextInt(minDmg, maxDmg)
}
def critMultiplier(user: Monster, target: Monster)(implicit rng: Random) = {
// Percentage chance is different from Pokemon
val stage = crit
val chance = (1 << stage) \ 16 // Doubles per stage
val chance = (1 << stage) \\ 16 // Doubles per stage
if (rng.chance(chance)) {
println("A critical hit!")
1.5
@ -156,11 +158,13 @@ abstract class Move extends MoveTurn {
}
def applyStatus(target: Monster, status: Status) {
if (target.isAlive) {
if (status != null && target.status == None) {
if (target.isAlive && status != null) {
if (target.status == None) {
// apply status
target.status = Some(status)
status.onStart.map(_(target))
status.onStart(target)
} else {
println("But it failed!")
}
}
}
@ -222,7 +226,7 @@ case class MoveToken(
val boosts = if (token.boosts != null) token.boosts.map { case (s, i) => (Statistic(s), i) } else Map()
val crit = token.critRatio
val status = if (token.status != null) Status(token.status) else null
val drain = if (token.drain != null) token.drain else if (token.recoil != null) -token.recoil else 0 \ 1
val drain = if (token.drain != null) token.drain else if (token.recoil != null) -token.recoil else 0.frac
val selfEffect = if (token.self != null) token.self.instantiate() else null
val secondary = if (token.secondary != null) token.secondary.instantiate() else null
}

View File

@ -1,4 +1,4 @@
package mon.stat
package fmon.stat
import scala.util.Random

View File

@ -1,9 +1,9 @@
package mon.stat
package fmon.stat
import scala.util.Random
import mon.battle.Action
import mon.stat.Target._
import fmon.battle.Action
import fmon.stat.Target._
class Party(val trainer: TrainerID, val lead: MonsterPtr, var sideboard: IndexedSeq[Monster]) {
def pollAction(them: Party)(implicit rng: Random): Action = {
@ -38,7 +38,7 @@ class Party(val trainer: TrainerID, val lead: MonsterPtr, var sideboard: Indexed
}
def shouldSwitch(them: Party)(implicit rng: Random): Boolean = {
true
false
}
def canFight: Boolean = {

View File

@ -1,4 +1,4 @@
package mon.stat
package fmon.stat
abstract class Secondary {
val chance : Int

View File

@ -1,4 +1,4 @@
package mon.stat
package fmon.stat
class Species {
// name

View File

@ -1,4 +1,4 @@
package mon.stat
package fmon.stat
object Statistic extends Enumeration {
val Hp = Value("Hp")

View File

@ -0,0 +1,142 @@
package fmon.stat
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
import scala.util.Random
import scala.io.Source
import fmon.util._
abstract class Status {
val name: String
// val id
// val effectType
val onStart: Monster => Unit
val onEnd: Monster => Unit
val onModifyStat: (Monster, Stat) => Fraction
// val onBeforeMovePriority : Int
val onBeforeMove: (Monster, MoveTurn, Monster, Random) => Boolean
// val onModifyMove
// val onHit
val onResidualOrder: Int
val onResidual: Monster => Unit
// val onSwitchIn
override def toString = name
}
case class StatusToken(
val name: 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 Status {
val name = self.name
val onStart = Status.compileOnStart(self.onStart)
val onEnd = Status.compileOnStart(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, Status]()
val tokens = YamlHelper.extractSeq[StatusToken](Source.fromInputStream(Move.getClass.getResourceAsStream("data/statuses.yaml"))).map(t => (t.name, t)).toMap
def apply(name: String) = {
if (!statuses.contains(name)) {
statuses = statuses.updated(name, tokens(name).instantiate())
}
statuses(name)
}
private val tb = runtimeMirror(getClass.getClassLoader).mkToolBox()
def compileOnStart(code: String): (Monster /*, source, source effect */ ) => Unit = {
if (code == null) {
_ => ()
} else {
val tree = tb.parse(
s"""
|import fmon.stat._
|import fmon.stat.Statistic._
|def onStart(mon : Monster) = {
| $code
|}
|onStart _
""".stripMargin)
val f = tb.compile(tree)
val wrapper = f()
wrapper.asInstanceOf[Monster => Unit]
}
}
def compileOnBeforeMove(code: String): (Monster, MoveTurn, Monster, Random) => Boolean = {
if (code == null) {
(_, _, _, _) => true
} else {
val tree = tb.parse(
s"""
import scala.util.Random
import fmon.stat._
import fmon.stat.Statistic._
def onBeforeMove(mon: Monster, move: MoveTurn, target: Monster, rng: Random): Boolean = {
$code
}
onBeforeMove _
""")
val f = tb.compile(tree)
val wrapper = f()
wrapper.asInstanceOf[(Monster, MoveTurn, Monster, Random) => Boolean]
}
}
def compileOnModifyStat(code: String): (Monster, Stat) => Fraction = {
if (code == null) {
(_, _) => 1.frac
} else {
val tree = tb.parse(
s"""
import fmon.stat._
import fmon.stat.Statistic._
import fmon.util._
def onModifyStat(mon: Monster, stat: Stat): Fraction = {
$code
}
onModifyStat _
""")
val f = tb.compile(tree)
val wrapper = f()
wrapper.asInstanceOf[(Monster, Stat) => Fraction]
}
}
def compileOnResidual(code: String): Monster => Unit = {
if (code == null) {
_ => ()
} else {
val tree = tb.parse(
s"""
|import fmon.stat._
|import fmon.stat.Statistic._
|def onResidual(mon : Monster) = {
| $code
|}
|onResidual _
""".stripMargin)
val f = tb.compile(tree)
val wrapper = f()
wrapper.asInstanceOf[Monster => Unit]
}
}
}

View File

@ -1,4 +1,4 @@
package mon.stat
package fmon.stat
class StorageMon(val nickname : String, val xp: Int, val gene : Gene, val form : Form, val evs : Map[Stat, Int], val moves : IndexedSeq[Move]) {
def level = form.xpCurve(xp)

View File

@ -1,4 +1,4 @@
package mon.stat
package fmon.stat
case class TrainerID(name : String, gender : Gender, id : Long) {

View File

@ -1,6 +1,6 @@
package mon.stat
package fmon.stat
import mon.util.TypeReference
import fmon.util.TypeReference
object XpCurve extends Enumeration {
case class Val protected(val curve: Int => Int) extends super.Val {

View File

@ -8,7 +8,7 @@
pdef: 70
matk: 70
mdef: 70
spd: 60
spd: 75
xpCurve: MediumSlow
- name: Diabolo

View File

@ -164,6 +164,28 @@
type: "Ice"
zMovePower: 120
contestType: "Beautiful"
- name: Ice Beam
accuracy: 100
basePower: 90
category: Special
contestType: Beautiful
desc: Has a 10% chance to freeze the target.
flags:
mirror: 1
protect: 1
id: icebeam
isViable: true
num: 58
pp: 10
priority: 0
secondary:
chance: 10
status: frz
shortDesc: 10% chance to freeze the target.
target: Normal
type: Ice
zMovePower: 175
- name: "Poison Gas"
num: 139
@ -207,6 +229,30 @@
type: "Poison"
zMovePower: 100
contestType: "Clever"
- name: Scald
accuracy: 100
basePower: 80
category: Special
contestType: Tough
desc: Has a 30% chance to burn the target. The target thaws out if it is frozen.
flags:
defrost: 1
mirror: 1
protect: 1
thaws: 1
id: scald
isViable: true
num: 503
pp: 15
priority: 0
secondary:
chance: 30
status: brn
shortDesc: 30% chance to burn the target. Thaws target.
target: Normal
type: Water
zMovePower: 160
- name: "Snarl"
num: 555
@ -251,6 +297,30 @@
zMovePower: 100
contestType: Tough
- name: Thunder Wave
accuracy: 90
basePower: 0
category: Status
contestType: Cool
desc: Paralyzes the target. This move does not ignore type immunity.
flags:
mirror: 1
protect: 1
reflectable: 1
id: thunderwave
ignoreImmunity: false
isViable: true
num: 86
pp: 20
priority: 0
secondary: null
shortDesc: Paralyzes the target.
status: par
target: Normal
type: Electric
zMoveBoost:
MDef: 1
- name: "Volt Tackle"
num: 344
accuracy: 100
@ -265,9 +335,32 @@
flags: {contact: 1, protect: 1, mirror: 1}
recoil: {num: 33, denom: 100}
secondary:
chance: 10
xstatus: 'par'
chance: 100
status: 'par'
target: "Normal"
type: "Electric"
zMovePower: 190
contestType: "Cool"
- name: Will-O-Wisp
accuracy: 85
basePower: 0
category: Status
contestType: Beautiful
desc: Burns the target.
flags:
mirror: 1
protect: 1
reflectable: 1
id: willowisp
isViable: true
num: 261
pp: 15
priority: 0
secondary: null
shortDesc: Burns the target.
status: brn
target: Normal
type: Fire
zMoveBoost:
PAtk: 1

View File

@ -2,38 +2,57 @@
id: 'brn'
num: 0
effectType: 'Status'
onStart: |
if (sourceEffect && sourceEffect.id === 'flameorb') {
this.add('-status', target, 'brn', '[from] item: Flame Orb');
} else if (sourceEffect && sourceEffect.effectType === 'Ability') {
this.add('-status', target, 'brn', '[from] ability: ' + sourceEffect.name, '[of] ' + source);
onModifyStat: |
if (stat == PAtk) {
1 \\ 2
} else {
this.add('-status', target, 'brn');
1.frac
}
// Damage reduction is handled directly in the sim/battle.js damage function
onStart: |
println(s"${mon} was burned!")
/*
if (sourceEffect && sourceEffect.id === 'flameorb') {
target.status = Status('brn', '[from] 'item': Flame Orb');
} else if (sourceEffect && sourceEffect.effectType === 'Ability') {
target.status = Status('brn', '[from] 'ability': ' + sourceEffect.name, '[of] ' + source);
} else {
target.status = Status('brn');
}*/
onEnd: |
println(s"${mon} was healed of its burn.")
onResidualOrder: 9
onResidual: |
this.damage(pokemon.maxhp / 16);
mon.takeDamage(mon(Hp) / 16);
println(s"${mon} was hurt by its burn!")
- name: 'par'
id: 'par'
num: 0
effectType: 'Status'
onStart: |
println(s"${mon} was paralyzed!")
/*
if (sourceEffect && sourceEffect.effectType === 'Ability') {
this.add('-status', target, 'par', '[from] ability: ' + sourceEffect.name, '[of] ' + source);
} else {
this.add('-status', target, 'par');
}
onModifySpe: |
if (!pokemon.hasAbility('quickfeet')) {
return this.chainModify(0.5);
*/
onEnd: |
println(s"${mon} is no longer paralyzed!")
onModifyStat: |
if (stat == Speed /* && !mon.hasAbility('quickfeet') */) {
1 \\ 2
} else {
1.frac
}
onBeforeMovePriority: 1
onBeforeMove: |
if (this.randomChance(1, 4)) {
this.add('cant', pokemon, 'par');
return false;
if (rng.chance(1, 4)) {
println(s"${mon} is fully paralyzed!")
false
} else {
true
}
- name: 'slp'
@ -51,52 +70,62 @@
// 1-3 turns
this.effectData.startTime = this.random(2, 5);
this.effectData.time = this.effectData.startTime;
onEnd: |
println(s"${mon} woke up!")
onBeforeMovePriority: 10
onBeforeMove: |
/*
if (pokemon.hasAbility('earlybird')) {
pokemon.statusData.time--;
}
*/
pokemon.statusData.time--;
if (pokemon.statusData.time <= 0) {
pokemon.cureStatus();
return;
}
/*
this.add('cant', pokemon, 'slp');
if (move.sleepUsable) {
return;
}
*/
return false;
- name: 'frz'
id: 'frz'
effectType: Status
id: frz
num: 0
effectType: 'Status'
onStart: |
if (sourceEffect && sourceEffect.effectType === 'Ability') {
this.add('-status', target, 'frz', '[from] ability: ' + sourceEffect.name, '[of] ' + source);
onBeforeMove: |-
if (move.flags("defrost") || rng.chance(1, 5)) {
mon.cureStatus()
true
} else {
this.add('-status', target, 'frz');
}
if (target.template.species === 'Shaymin-Sky' && target.baseTemplate.baseSpecies === 'Shaymin') {
target.formeChange('Shaymin', this.effect, true);
println(s"${mon} is completely frozen!")
false
}
onBeforeMovePriority: 10
onBeforeMove: |
if (move.flags['defrost']) return;
if (this.randomChance(1, 5)) {
pokemon.cureStatus();
return;
onHit: |-
if (move.flags("thaws") || move.element === 'Fire' && move.category !== MoveType.Status) {
target.cureStatus()
}
this.add('cant', pokemon, 'frz');
return false;
onStart: |-
println(s"${mon} was frozen solid!")
/*
if (sourceEffect && sourceEffect.effectType === 'Ability') {
target.status = Status('frz', '[from] 'ability': ' + sourceEffect.name, '[of] ' + source);
} else {
target.status = Status('frz');
}
if (target.template.species === 'Shaymin-Sky' && target.baseTemplate.baseSpecies === 'Shaymin') {
target.formeChange('Shaymin', this.effect, true);
}
*/
onEnd: |-
println(s"${mon} thawed out.")
onModifyMove: |
if (move.flags['defrost']) {
this.add('-curestatus', pokemon, 'frz', '[from] move: ' + move);
pokemon.setStatus('');
}
onHit: |
if (move.thawsTarget || move.type === 'Fire' && move.category !== 'Status') {
target.cureStatus();
if (move.flags("defrost")) {
mon.cureStatus()
}
- name: 'psn'
@ -112,6 +141,8 @@
this.add('-status', target, 'psn');
}
*/
oneEnd: |
println(s"${mon} was cured of its poison.")
onResidualOrder: 9
onResidual: |
mon.takeDamage(mon(Hp) / 8);

View File

@ -1,11 +1,13 @@
package mon
package fmon
import scala.language.implicitConversions
import org.json4s.DefaultFormats
import org.json4s.ext.EnumNameSerializer
import scala.util.Random
import mon.util.Dice
import fmon.util.Dice
package object stat {
type Stat = Statistic.Value

View File

@ -1,4 +1,4 @@
package mon.util
package fmon.util
import scala.util.Random
@ -7,5 +7,6 @@ class Dice(val rng : Random) extends AnyVal {
def pick[T](seq : IndexedSeq[T]) : T = seq(rng.nextInt(seq.size))
def chance(frac : Fraction) = rng.nextInt(frac.denom) < frac.num
def chance(frac : Fraction) :Boolean = chance(frac.num, frac.denom)
def chance(num : Int, denom : Int) : Boolean = rng.nextInt(denom) < num
}

View File

@ -1,4 +1,4 @@
package mon.util
package fmon.util
case class Fraction(val num : Int, val denom : Int) extends Ordered[Fraction] {
def *(f : Fraction) = Fraction(num * f.num, denom * f.denom)
@ -13,6 +13,6 @@ case class Fraction(val num : Int, val denom : Int) extends Ordered[Fraction] {
class IntFraction(val x : Int) extends AnyVal {
def %% = Fraction(x, 100)
def \ (denom : Int) = Fraction(x, denom)
def \\ (denom : Int) = Fraction(x, denom)
def frac = Fraction(x, 1)
}

View File

@ -1,4 +1,4 @@
package mon.util
package fmon.util
import org.json4s._
import org.json4s.jackson.JsonMethods._
@ -12,7 +12,7 @@ object JsonHelper {
// Maybe Look at Jackson-YAML & Jackson-Scala
implicit val formats = mon.stat.formats
implicit val formats = fmon.stat.formats
def extract[T](text : String)(implicit mf : Manifest[T]) : T = {
val json = parse(text)

View File

@ -1,4 +1,4 @@
package mon.util
package fmon.util
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
@ -10,7 +10,7 @@ import java.io.InputStream
import scala.io.Source
import mon.util._
import fmon.util._
object YamlHelper {
val mapper = new ObjectMapper(new YAMLFactory()) with ScalaObjectMapper

View File

@ -1,4 +1,4 @@
package mon
package fmon
import java.io._

View File

@ -1,96 +0,0 @@
package mon.stat
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
import scala.io.Source
import mon.util.YamlHelper
abstract class Status {
val name : String
// val id
// val effectType
val onStart : Option[Monster => Unit]
// val onModifyStat
// val onBeforeMovePriority : Int
// val onBeforeMove
// val onModifyMove
// val onHit
val onResidualOrder : Int
val onResidual : Option[Monster => Unit]
// val onSwitchIn
override def toString = name
}
case class StatusToken(
val name : String,
val onStart : String,
val onResidualOrder : Int,
val onResidual : String
) {
def instantiate() = {
val self = this
new Status{
val name = self.name
val onStart = Status.compileOnStart(self.onStart)
val onResidualOrder = self.onResidualOrder
val onResidual = Status.compileOnResidual(self.onResidual)
}
}
}
object Status {
private var statuses = Map[String, Status]()
val tokens = YamlHelper.extractSeq[StatusToken](Source.fromInputStream(Move.getClass.getResourceAsStream("data/statuses.yaml"))).map(t => (t.name, t)).toMap
def apply(name : String) = {
if (!statuses.contains(name)) {
statuses = statuses.updated(name, tokens(name).instantiate())
}
statuses(name)
}
private val tb = runtimeMirror(getClass.getClassLoader).mkToolBox()
def compileOnStart(code : String) : Option[(Monster /*, source, source effect */) => Unit] = {
if (code == null) {
None
} else {
val tree = tb.parse(
s"""
|import mon.stat.Monster
|import mon.stat.Statistic._
|def onStart(mon : Monster) = {
| $code
|}
|onStart _
""".stripMargin)
val f = tb.compile(tree)
val wrapper = f()
Some(wrapper.asInstanceOf[Monster => Unit])
}
}
def compileOnResidual(code : String) : Option[Monster => Unit] = {
if (code == null) {
None
} else {
val tree = tb.parse(
s"""
|import mon.stat.Monster
|import mon.stat.Statistic._
|def onResidual(mon : Monster) = {
| $code
|}
|onResidual _
""".stripMargin)
val f = tb.compile(tree)
val wrapper = f()
Some(wrapper.asInstanceOf[Monster => Unit])
}
}
}