Renamed the root package to fmon and added paralysis, burn, and sleep status effects
This commit is contained in:
parent
d13d5b3bf6
commit
40553d36b9
@ -1,4 +1,4 @@
|
|||||||
package mon
|
package fmon
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
|
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.reflect.runtime.universe._
|
||||||
import scala.tools.reflect.ToolBox
|
import scala.tools.reflect.ToolBox
|
||||||
|
|
||||||
import mon.battle.BattleEngine
|
import fmon.battle.BattleEngine
|
||||||
import mon.stat._
|
import fmon.stat._
|
||||||
|
|
||||||
case class Prop(url : Seq[String])
|
case class Prop(url : Seq[String])
|
||||||
|
|
||||||
@ -19,8 +19,8 @@ object Game {
|
|||||||
implicit val rng = new scala.util.Random()
|
implicit val rng = new scala.util.Random()
|
||||||
val form1 = Form("Diabolo")
|
val form1 = Form("Diabolo")
|
||||||
val form2 = Form("Chanilla")
|
val form2 = Form("Chanilla")
|
||||||
val movepool1 = IndexedSeq(Move("Close Combat"))
|
val movepool1 = IndexedSeq(Move("Ice Beam"))
|
||||||
val movepool2 = IndexedSeq(Move("Absorb"))
|
val movepool2 = IndexedSeq(Move("Scald"))
|
||||||
val p1 = TrainerID("Jaeda", Gender.Female, 0)
|
val p1 = TrainerID("Jaeda", Gender.Female, 0)
|
||||||
val p2 = TrainerID("Wild Monster", Gender.Male, 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())
|
val party1 = new Party(p1, new MonsterPtr(new Monster(new StorageMon("Allied Mon", 500, Gene.randomGene(null, form1), form1, Statistic.emptyEvs, movepool1))), IndexedSeq())
|
@ -1,7 +1,7 @@
|
|||||||
package mon.battle
|
package fmon.battle
|
||||||
|
|
||||||
import mon.stat._
|
import fmon.stat._
|
||||||
import mon.stat.Statistic.Speed
|
import fmon.stat.Statistic.Speed
|
||||||
|
|
||||||
case class Action(user : MonsterPtr, move : MoveTurn, target : MonsterPtr) extends Comparable[Action] {
|
case class Action(user : MonsterPtr, move : MoveTurn, target : MonsterPtr) extends Comparable[Action] {
|
||||||
override def compareTo(other : Action) = {
|
override def compareTo(other : Action) = {
|
@ -1,10 +1,10 @@
|
|||||||
package mon.battle
|
package fmon.battle
|
||||||
|
|
||||||
import scala.util.Random
|
import scala.util.Random
|
||||||
|
|
||||||
import mon.stat._
|
import fmon.stat._
|
||||||
import mon.stat.Statistic._
|
import fmon.stat.Statistic._
|
||||||
import mon.util.Fraction
|
import fmon.util.Fraction
|
||||||
|
|
||||||
class BattleEngine(val player: Party, val enemy: Party)(implicit val rng: Random) {
|
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() = {
|
def playTurn() = {
|
||||||
val playerAction = player.pollAction(enemy)
|
val playerAction = player.pollAction(enemy)
|
||||||
val enemyAction = enemy.pollAction(player)
|
val enemyAction = enemy.pollAction(player)
|
||||||
println(enemyAction)
|
|
||||||
|
|
||||||
val actions = Seq(playerAction, enemyAction)
|
val actions = Seq(playerAction, enemyAction)
|
||||||
val queue = rng.shuffle(actions).sorted // Shuffle to randomize in the event of a tie
|
val queue = rng.shuffle(actions).sorted // Shuffle to randomize in the event of a tie
|
||||||
queue.foreach(useMove)
|
queue.foreach(useMove)
|
||||||
val eotQueue = Seq(player.lead, enemy.lead).sortBy(_(Speed))
|
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.lead.isAlive) {
|
||||||
if (player.canFight) {
|
if (player.canFight) {
|
||||||
@ -52,7 +51,9 @@ class BattleEngine(val player: Party, val enemy: Party)(implicit val rng: Random
|
|||||||
val move = action.move
|
val move = action.move
|
||||||
val target = action.target
|
val target = action.target
|
||||||
if (user.isAlive) {
|
if (user.isAlive) {
|
||||||
move.useMove(user, target)
|
if (user.status.forall(_.onBeforeMove(user, move, target, rng))) {
|
||||||
|
move.useMove(user, target)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,9 +1,9 @@
|
|||||||
package mon
|
package fmon
|
||||||
|
|
||||||
import scala.languageFeature.implicitConversions
|
import scala.language.implicitConversions
|
||||||
import scala.util.Random
|
import scala.util.Random
|
||||||
|
|
||||||
import mon.util._
|
import fmon.util._
|
||||||
|
|
||||||
|
|
||||||
package object battle {
|
package object battle {
|
@ -1,8 +1,8 @@
|
|||||||
package mon.stat
|
package fmon.stat
|
||||||
|
|
||||||
import scala.io.Source
|
import scala.io.Source
|
||||||
|
|
||||||
import mon.util.YamlHelper
|
import fmon.util.YamlHelper
|
||||||
|
|
||||||
case class Element(val name : String, val effect : Map[String, Double]) {
|
case class Element(val name : String, val effect : Map[String, Double]) {
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package mon.stat
|
package fmon.stat
|
||||||
|
|
||||||
import scala.io.Source
|
import scala.io.Source
|
||||||
|
|
||||||
@ -6,7 +6,7 @@ import com.fasterxml.jackson.module.scala.JsonScalaEnumeration
|
|||||||
|
|
||||||
import Statistic._
|
import Statistic._
|
||||||
|
|
||||||
import mon.util.YamlHelper
|
import fmon.util.YamlHelper
|
||||||
|
|
||||||
abstract class Form {
|
abstract class Form {
|
||||||
val name : String
|
val name : String
|
@ -1,4 +1,4 @@
|
|||||||
package mon.stat
|
package fmon.stat
|
||||||
|
|
||||||
object Gender extends Enumeration {
|
object Gender extends Enumeration {
|
||||||
val Male, Female, Fluid, Neuter = Value
|
val Male, Female, Fluid, Neuter = Value
|
@ -1,4 +1,4 @@
|
|||||||
package mon.stat
|
package fmon.stat
|
||||||
|
|
||||||
import scala.util.Random
|
import scala.util.Random
|
||||||
|
|
@ -1,8 +1,8 @@
|
|||||||
package mon.stat
|
package fmon.stat
|
||||||
|
|
||||||
import scala.util._
|
import scala.util._
|
||||||
|
|
||||||
import mon.util.Fraction
|
import fmon.util._
|
||||||
|
|
||||||
import Monster._
|
import Monster._
|
||||||
import Statistic._
|
import Statistic._
|
||||||
@ -20,7 +20,7 @@ class Monster(val base : StorageMon) {
|
|||||||
def apply(s : Stat) = {
|
def apply(s : Stat) = {
|
||||||
val mod = boosts.getOrElse(s, 0)
|
val mod = boosts.getOrElse(s, 0)
|
||||||
val mult = if (mod > 0) Fraction(2 + mod, 2) else Fraction(2, 2 - mod)
|
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
|
def elements = base.form.elements
|
||||||
@ -36,6 +36,11 @@ class Monster(val base : StorageMon) {
|
|||||||
hp = Math.min(stats(Hp), hp + healing)
|
hp = Math.min(stats(Hp), hp + healing)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def cureStatus() {
|
||||||
|
status.map(_.onEnd(this))
|
||||||
|
status = None
|
||||||
|
}
|
||||||
|
|
||||||
def applyBoost(s : Stat, boost : Int) {
|
def applyBoost(s : Stat, boost : Int) {
|
||||||
val modified = boosts.getOrElse(s, 0) + boost
|
val modified = boosts.getOrElse(s, 0) + boost
|
||||||
boosts = boosts.updated(s, Math.min(MaxBoost, Math.max(-MaxBoost, modified)))
|
boosts = boosts.updated(s, Math.min(MaxBoost, Math.max(-MaxBoost, modified)))
|
@ -1,4 +1,4 @@
|
|||||||
package mon.stat
|
package fmon.stat
|
||||||
|
|
||||||
class MonsterPtr(var mon : Monster) {
|
class MonsterPtr(var mon : Monster) {
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package mon.stat
|
package fmon.stat
|
||||||
|
|
||||||
import scala.reflect.runtime.universe._
|
import scala.reflect.runtime.universe._
|
||||||
import scala.tools.reflect.ToolBox
|
import scala.tools.reflect.ToolBox
|
||||||
@ -9,7 +9,7 @@ import scala.io.Source
|
|||||||
import scala.util.Random
|
import scala.util.Random
|
||||||
|
|
||||||
import Statistic._
|
import Statistic._
|
||||||
import mon.util._
|
import fmon.util._
|
||||||
|
|
||||||
object MoveType extends Enumeration {
|
object MoveType extends Enumeration {
|
||||||
val Physical, Special, Status = Value
|
val Physical, Special, Status = Value
|
||||||
@ -23,6 +23,7 @@ class TargetType extends TypeReference[Target.type]
|
|||||||
|
|
||||||
trait MoveTurn {
|
trait MoveTurn {
|
||||||
def name: String
|
def name: String
|
||||||
|
def flags: Set[String]
|
||||||
def prior: Int
|
def prior: Int
|
||||||
def target: Target
|
def target: Target
|
||||||
def useMove(user: Monster, target: Monster)(implicit rng: Random): Unit
|
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 {
|
class SwitchOut(val party: Party, val replacement: Monster) extends MoveTurn {
|
||||||
def name = "Swap"
|
def name = "Swap"
|
||||||
|
def flags = Set()
|
||||||
def prior = +6
|
def prior = +6
|
||||||
def target = Target.Self
|
def target = Target.Self
|
||||||
|
|
||||||
@ -134,14 +136,14 @@ abstract class Move extends MoveTurn {
|
|||||||
println("It's not very effective.")
|
println("It's not very effective.")
|
||||||
}
|
}
|
||||||
val maxDmg = (baseDmg * multiplier).toInt
|
val maxDmg = (baseDmg * multiplier).toInt
|
||||||
val minDmg = (17 \ 20) * maxDmg
|
val minDmg = (17 \\ 20) * maxDmg
|
||||||
rng.nextInt(minDmg, maxDmg)
|
rng.nextInt(minDmg, maxDmg)
|
||||||
}
|
}
|
||||||
|
|
||||||
def critMultiplier(user: Monster, target: Monster)(implicit rng: Random) = {
|
def critMultiplier(user: Monster, target: Monster)(implicit rng: Random) = {
|
||||||
// Percentage chance is different from Pokemon
|
// Percentage chance is different from Pokemon
|
||||||
val stage = crit
|
val stage = crit
|
||||||
val chance = (1 << stage) \ 16 // Doubles per stage
|
val chance = (1 << stage) \\ 16 // Doubles per stage
|
||||||
if (rng.chance(chance)) {
|
if (rng.chance(chance)) {
|
||||||
println("A critical hit!")
|
println("A critical hit!")
|
||||||
1.5
|
1.5
|
||||||
@ -156,11 +158,13 @@ abstract class Move extends MoveTurn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def applyStatus(target: Monster, status: Status) {
|
def applyStatus(target: Monster, status: Status) {
|
||||||
if (target.isAlive) {
|
if (target.isAlive && status != null) {
|
||||||
if (status != null && target.status == None) {
|
if (target.status == None) {
|
||||||
// apply status
|
// apply status
|
||||||
target.status = Some(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 boosts = if (token.boosts != null) token.boosts.map { case (s, i) => (Statistic(s), i) } else Map()
|
||||||
val crit = token.critRatio
|
val crit = token.critRatio
|
||||||
val status = if (token.status != null) Status(token.status) else null
|
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 selfEffect = if (token.self != null) token.self.instantiate() else null
|
||||||
val secondary = if (token.secondary != null) token.secondary.instantiate() else null
|
val secondary = if (token.secondary != null) token.secondary.instantiate() else null
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package mon.stat
|
package fmon.stat
|
||||||
|
|
||||||
import scala.util.Random
|
import scala.util.Random
|
||||||
|
|
@ -1,9 +1,9 @@
|
|||||||
package mon.stat
|
package fmon.stat
|
||||||
|
|
||||||
import scala.util.Random
|
import scala.util.Random
|
||||||
|
|
||||||
import mon.battle.Action
|
import fmon.battle.Action
|
||||||
import mon.stat.Target._
|
import fmon.stat.Target._
|
||||||
|
|
||||||
class Party(val trainer: TrainerID, val lead: MonsterPtr, var sideboard: IndexedSeq[Monster]) {
|
class Party(val trainer: TrainerID, val lead: MonsterPtr, var sideboard: IndexedSeq[Monster]) {
|
||||||
def pollAction(them: Party)(implicit rng: Random): Action = {
|
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 = {
|
def shouldSwitch(them: Party)(implicit rng: Random): Boolean = {
|
||||||
true
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
def canFight: Boolean = {
|
def canFight: Boolean = {
|
@ -1,4 +1,4 @@
|
|||||||
package mon.stat
|
package fmon.stat
|
||||||
|
|
||||||
abstract class Secondary {
|
abstract class Secondary {
|
||||||
val chance : Int
|
val chance : Int
|
@ -1,4 +1,4 @@
|
|||||||
package mon.stat
|
package fmon.stat
|
||||||
|
|
||||||
class Species {
|
class Species {
|
||||||
// name
|
// name
|
@ -1,4 +1,4 @@
|
|||||||
package mon.stat
|
package fmon.stat
|
||||||
|
|
||||||
object Statistic extends Enumeration {
|
object Statistic extends Enumeration {
|
||||||
val Hp = Value("Hp")
|
val Hp = Value("Hp")
|
142
FakeMon/src/fmon/stat/Status.scala
Normal file
142
FakeMon/src/fmon/stat/Status.scala
Normal 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]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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]) {
|
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)
|
def level = form.xpCurve(xp)
|
@ -1,4 +1,4 @@
|
|||||||
package mon.stat
|
package fmon.stat
|
||||||
|
|
||||||
case class TrainerID(name : String, gender : Gender, id : Long) {
|
case class TrainerID(name : String, gender : Gender, id : Long) {
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
package mon.stat
|
package fmon.stat
|
||||||
|
|
||||||
import mon.util.TypeReference
|
import fmon.util.TypeReference
|
||||||
|
|
||||||
object XpCurve extends Enumeration {
|
object XpCurve extends Enumeration {
|
||||||
case class Val protected(val curve: Int => Int) extends super.Val {
|
case class Val protected(val curve: Int => Int) extends super.Val {
|
@ -8,7 +8,7 @@
|
|||||||
pdef: 70
|
pdef: 70
|
||||||
matk: 70
|
matk: 70
|
||||||
mdef: 70
|
mdef: 70
|
||||||
spd: 60
|
spd: 75
|
||||||
xpCurve: MediumSlow
|
xpCurve: MediumSlow
|
||||||
|
|
||||||
- name: Diabolo
|
- name: Diabolo
|
@ -164,6 +164,28 @@
|
|||||||
type: "Ice"
|
type: "Ice"
|
||||||
zMovePower: 120
|
zMovePower: 120
|
||||||
contestType: "Beautiful"
|
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"
|
- name: "Poison Gas"
|
||||||
num: 139
|
num: 139
|
||||||
@ -207,6 +229,30 @@
|
|||||||
type: "Poison"
|
type: "Poison"
|
||||||
zMovePower: 100
|
zMovePower: 100
|
||||||
contestType: "Clever"
|
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"
|
- name: "Snarl"
|
||||||
num: 555
|
num: 555
|
||||||
@ -251,6 +297,30 @@
|
|||||||
zMovePower: 100
|
zMovePower: 100
|
||||||
contestType: Tough
|
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"
|
- name: "Volt Tackle"
|
||||||
num: 344
|
num: 344
|
||||||
accuracy: 100
|
accuracy: 100
|
||||||
@ -265,9 +335,32 @@
|
|||||||
flags: {contact: 1, protect: 1, mirror: 1}
|
flags: {contact: 1, protect: 1, mirror: 1}
|
||||||
recoil: {num: 33, denom: 100}
|
recoil: {num: 33, denom: 100}
|
||||||
secondary:
|
secondary:
|
||||||
chance: 10
|
chance: 100
|
||||||
xstatus: 'par'
|
status: 'par'
|
||||||
target: "Normal"
|
target: "Normal"
|
||||||
type: "Electric"
|
type: "Electric"
|
||||||
zMovePower: 190
|
zMovePower: 190
|
||||||
contestType: "Cool"
|
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
|
@ -2,38 +2,57 @@
|
|||||||
id: 'brn'
|
id: 'brn'
|
||||||
num: 0
|
num: 0
|
||||||
effectType: 'Status'
|
effectType: 'Status'
|
||||||
onStart: |
|
onModifyStat: |
|
||||||
if (sourceEffect && sourceEffect.id === 'flameorb') {
|
if (stat == PAtk) {
|
||||||
this.add('-status', target, 'brn', '[from] item: Flame Orb');
|
1 \\ 2
|
||||||
} else if (sourceEffect && sourceEffect.effectType === 'Ability') {
|
|
||||||
this.add('-status', target, 'brn', '[from] ability: ' + sourceEffect.name, '[of] ' + source);
|
|
||||||
} else {
|
} 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
|
onResidualOrder: 9
|
||||||
onResidual: |
|
onResidual: |
|
||||||
this.damage(pokemon.maxhp / 16);
|
mon.takeDamage(mon(Hp) / 16);
|
||||||
|
println(s"${mon} was hurt by its burn!")
|
||||||
|
|
||||||
- name: 'par'
|
- name: 'par'
|
||||||
id: 'par'
|
id: 'par'
|
||||||
num: 0
|
num: 0
|
||||||
effectType: 'Status'
|
effectType: 'Status'
|
||||||
onStart: |
|
onStart: |
|
||||||
|
println(s"${mon} was paralyzed!")
|
||||||
|
/*
|
||||||
if (sourceEffect && sourceEffect.effectType === 'Ability') {
|
if (sourceEffect && sourceEffect.effectType === 'Ability') {
|
||||||
this.add('-status', target, 'par', '[from] ability: ' + sourceEffect.name, '[of] ' + source);
|
this.add('-status', target, 'par', '[from] ability: ' + sourceEffect.name, '[of] ' + source);
|
||||||
} else {
|
} else {
|
||||||
this.add('-status', target, 'par');
|
this.add('-status', target, 'par');
|
||||||
}
|
}
|
||||||
onModifySpe: |
|
*/
|
||||||
if (!pokemon.hasAbility('quickfeet')) {
|
onEnd: |
|
||||||
return this.chainModify(0.5);
|
println(s"${mon} is no longer paralyzed!")
|
||||||
|
onModifyStat: |
|
||||||
|
if (stat == Speed /* && !mon.hasAbility('quickfeet') */) {
|
||||||
|
1 \\ 2
|
||||||
|
} else {
|
||||||
|
1.frac
|
||||||
}
|
}
|
||||||
onBeforeMovePriority: 1
|
onBeforeMovePriority: 1
|
||||||
onBeforeMove: |
|
onBeforeMove: |
|
||||||
if (this.randomChance(1, 4)) {
|
if (rng.chance(1, 4)) {
|
||||||
this.add('cant', pokemon, 'par');
|
println(s"${mon} is fully paralyzed!")
|
||||||
return false;
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
- name: 'slp'
|
- name: 'slp'
|
||||||
@ -51,52 +70,62 @@
|
|||||||
// 1-3 turns
|
// 1-3 turns
|
||||||
this.effectData.startTime = this.random(2, 5);
|
this.effectData.startTime = this.random(2, 5);
|
||||||
this.effectData.time = this.effectData.startTime;
|
this.effectData.time = this.effectData.startTime;
|
||||||
|
onEnd: |
|
||||||
|
println(s"${mon} woke up!")
|
||||||
onBeforeMovePriority: 10
|
onBeforeMovePriority: 10
|
||||||
onBeforeMove: |
|
onBeforeMove: |
|
||||||
|
/*
|
||||||
if (pokemon.hasAbility('earlybird')) {
|
if (pokemon.hasAbility('earlybird')) {
|
||||||
pokemon.statusData.time--;
|
pokemon.statusData.time--;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
pokemon.statusData.time--;
|
pokemon.statusData.time--;
|
||||||
if (pokemon.statusData.time <= 0) {
|
if (pokemon.statusData.time <= 0) {
|
||||||
pokemon.cureStatus();
|
pokemon.cureStatus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
this.add('cant', pokemon, 'slp');
|
this.add('cant', pokemon, 'slp');
|
||||||
if (move.sleepUsable) {
|
if (move.sleepUsable) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
- name: 'frz'
|
- name: 'frz'
|
||||||
id: 'frz'
|
effectType: Status
|
||||||
|
id: frz
|
||||||
num: 0
|
num: 0
|
||||||
effectType: 'Status'
|
onBeforeMove: |-
|
||||||
onStart: |
|
if (move.flags("defrost") || rng.chance(1, 5)) {
|
||||||
if (sourceEffect && sourceEffect.effectType === 'Ability') {
|
mon.cureStatus()
|
||||||
this.add('-status', target, 'frz', '[from] ability: ' + sourceEffect.name, '[of] ' + source);
|
true
|
||||||
} else {
|
} else {
|
||||||
this.add('-status', target, 'frz');
|
println(s"${mon} is completely frozen!")
|
||||||
}
|
false
|
||||||
if (target.template.species === 'Shaymin-Sky' && target.baseTemplate.baseSpecies === 'Shaymin') {
|
|
||||||
target.formeChange('Shaymin', this.effect, true);
|
|
||||||
}
|
}
|
||||||
onBeforeMovePriority: 10
|
onBeforeMovePriority: 10
|
||||||
onBeforeMove: |
|
onHit: |-
|
||||||
if (move.flags['defrost']) return;
|
if (move.flags("thaws") || move.element === 'Fire' && move.category !== MoveType.Status) {
|
||||||
if (this.randomChance(1, 5)) {
|
target.cureStatus()
|
||||||
pokemon.cureStatus();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
this.add('cant', pokemon, 'frz');
|
onStart: |-
|
||||||
return false;
|
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: |
|
onModifyMove: |
|
||||||
if (move.flags['defrost']) {
|
if (move.flags("defrost")) {
|
||||||
this.add('-curestatus', pokemon, 'frz', '[from] move: ' + move);
|
mon.cureStatus()
|
||||||
pokemon.setStatus('');
|
|
||||||
}
|
|
||||||
onHit: |
|
|
||||||
if (move.thawsTarget || move.type === 'Fire' && move.category !== 'Status') {
|
|
||||||
target.cureStatus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- name: 'psn'
|
- name: 'psn'
|
||||||
@ -112,6 +141,8 @@
|
|||||||
this.add('-status', target, 'psn');
|
this.add('-status', target, 'psn');
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
oneEnd: |
|
||||||
|
println(s"${mon} was cured of its poison.")
|
||||||
onResidualOrder: 9
|
onResidualOrder: 9
|
||||||
onResidual: |
|
onResidual: |
|
||||||
mon.takeDamage(mon(Hp) / 8);
|
mon.takeDamage(mon(Hp) / 8);
|
@ -1,11 +1,13 @@
|
|||||||
package mon
|
package fmon
|
||||||
|
|
||||||
|
import scala.language.implicitConversions
|
||||||
|
|
||||||
import org.json4s.DefaultFormats
|
import org.json4s.DefaultFormats
|
||||||
import org.json4s.ext.EnumNameSerializer
|
import org.json4s.ext.EnumNameSerializer
|
||||||
|
|
||||||
import scala.util.Random
|
import scala.util.Random
|
||||||
|
|
||||||
import mon.util.Dice
|
import fmon.util.Dice
|
||||||
|
|
||||||
package object stat {
|
package object stat {
|
||||||
type Stat = Statistic.Value
|
type Stat = Statistic.Value
|
@ -1,4 +1,4 @@
|
|||||||
package mon.util
|
package fmon.util
|
||||||
|
|
||||||
import scala.util.Random
|
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 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
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package mon.util
|
package fmon.util
|
||||||
|
|
||||||
case class Fraction(val num : Int, val denom : Int) extends Ordered[Fraction] {
|
case class Fraction(val num : Int, val denom : Int) extends Ordered[Fraction] {
|
||||||
def *(f : Fraction) = Fraction(num * f.num, denom * f.denom)
|
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 {
|
class IntFraction(val x : Int) extends AnyVal {
|
||||||
def %% = Fraction(x, 100)
|
def %% = Fraction(x, 100)
|
||||||
def \ (denom : Int) = Fraction(x, denom)
|
def \\ (denom : Int) = Fraction(x, denom)
|
||||||
def frac = Fraction(x, 1)
|
def frac = Fraction(x, 1)
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package mon.util
|
package fmon.util
|
||||||
|
|
||||||
import org.json4s._
|
import org.json4s._
|
||||||
import org.json4s.jackson.JsonMethods._
|
import org.json4s.jackson.JsonMethods._
|
||||||
@ -12,7 +12,7 @@ object JsonHelper {
|
|||||||
|
|
||||||
// Maybe Look at Jackson-YAML & Jackson-Scala
|
// 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 = {
|
def extract[T](text : String)(implicit mf : Manifest[T]) : T = {
|
||||||
val json = parse(text)
|
val json = parse(text)
|
@ -1,4 +1,4 @@
|
|||||||
package mon.util
|
package fmon.util
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature
|
import com.fasterxml.jackson.databind.DeserializationFeature
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
@ -10,7 +10,7 @@ import java.io.InputStream
|
|||||||
|
|
||||||
import scala.io.Source
|
import scala.io.Source
|
||||||
|
|
||||||
import mon.util._
|
import fmon.util._
|
||||||
|
|
||||||
object YamlHelper {
|
object YamlHelper {
|
||||||
val mapper = new ObjectMapper(new YAMLFactory()) with ScalaObjectMapper
|
val mapper = new ObjectMapper(new YAMLFactory()) with ScalaObjectMapper
|
@ -1,4 +1,4 @@
|
|||||||
package mon
|
package fmon
|
||||||
|
|
||||||
import java.io._
|
import java.io._
|
||||||
|
|
@ -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])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user