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.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())
|
@ -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) = {
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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 {
|
@ -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]) {
|
||||
|
@ -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
|
@ -1,4 +1,4 @@
|
||||
package mon.stat
|
||||
package fmon.stat
|
||||
|
||||
object Gender extends Enumeration {
|
||||
val Male, Female, Fluid, Neuter = Value
|
@ -1,4 +1,4 @@
|
||||
package mon.stat
|
||||
package fmon.stat
|
||||
|
||||
import scala.util.Random
|
||||
|
@ -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)))
|
@ -1,4 +1,4 @@
|
||||
package mon.stat
|
||||
package fmon.stat
|
||||
|
||||
class MonsterPtr(var mon : Monster) {
|
||||
|
@ -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
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package mon.stat
|
||||
package fmon.stat
|
||||
|
||||
import scala.util.Random
|
||||
|
@ -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 = {
|
@ -1,4 +1,4 @@
|
||||
package mon.stat
|
||||
package fmon.stat
|
||||
|
||||
abstract class Secondary {
|
||||
val chance : Int
|
@ -1,4 +1,4 @@
|
||||
package mon.stat
|
||||
package fmon.stat
|
||||
|
||||
class Species {
|
||||
// name
|
@ -1,4 +1,4 @@
|
||||
package mon.stat
|
||||
package fmon.stat
|
||||
|
||||
object Statistic extends Enumeration {
|
||||
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]) {
|
||||
def level = form.xpCurve(xp)
|
@ -1,4 +1,4 @@
|
||||
package mon.stat
|
||||
package fmon.stat
|
||||
|
||||
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 {
|
||||
case class Val protected(val curve: Int => Int) extends super.Val {
|
@ -8,7 +8,7 @@
|
||||
pdef: 70
|
||||
matk: 70
|
||||
mdef: 70
|
||||
spd: 60
|
||||
spd: 75
|
||||
xpCurve: MediumSlow
|
||||
|
||||
- name: Diabolo
|
@ -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
|
@ -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);
|
@ -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
|
@ -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
|
||||
}
|
@ -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)
|
||||
}
|
@ -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)
|
@ -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
|
@ -1,4 +1,4 @@
|
||||
package mon
|
||||
package fmon
|
||||
|
||||
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