Connected the battle engine to the UI. Beginning to make messages appear in the UI
This commit is contained in:
@@ -5,6 +5,7 @@ import scala.tools.reflect.ToolBox
|
||||
import scala.io.Source
|
||||
import scala.util.Random
|
||||
|
||||
import fmon.battle.msg.SignalConsumer
|
||||
import fmon.util._
|
||||
|
||||
abstract class Ability extends Effect {
|
||||
@@ -13,9 +14,10 @@ abstract class Ability extends Effect {
|
||||
|
||||
def effectType = EffectType.AbilityEffect
|
||||
|
||||
def onAfterDamage(source: Monster, move: MoveTurn, mon: Monster, dmg: Int)(implicit rng: Random) = onAfterDamageImp(this, source, move, mon, dmg, rng)
|
||||
def onAfterDamage(source: Monster, move: MoveTurn, mon: Monster, dmg: Int)(implicit reader: SignalConsumer, rng: Random) =
|
||||
onAfterDamageImp(this, source, move, mon, dmg, reader, rng)
|
||||
|
||||
protected val onAfterDamageImp: (Ability, Monster, MoveTurn, Monster, Int, Random) => Unit
|
||||
protected val onAfterDamageImp: (Ability, Monster, MoveTurn, Monster, Int, SignalConsumer, Random) => Unit
|
||||
|
||||
override def toString = name
|
||||
}
|
||||
@@ -50,6 +52,7 @@ object Ability {
|
||||
|
||||
private val header = """
|
||||
|import scala.util.Random
|
||||
|import fmon.battle.msg._
|
||||
|import fmon.stat._
|
||||
|import fmon.stat.MoveType._
|
||||
|import fmon.stat.Statistic._
|
||||
@@ -57,20 +60,21 @@ object Ability {
|
||||
"""
|
||||
private val helper = """
|
||||
implicit val gen = rng
|
||||
implicit val signalConsumer = reader
|
||||
def trigger {
|
||||
print(s"[${mon}'s ${self}]")
|
||||
reader ! Message(s"[${mon}'s ${self}]")
|
||||
}
|
||||
def effect = EffectSource(mon, self)
|
||||
"""
|
||||
|
||||
def compileOnAfterDamage(code: String): (Ability, Monster, MoveTurn, Monster, Int, Random) => Unit = {
|
||||
def compileOnAfterDamage(code: String): (Ability, Monster, MoveTurn, Monster, Int, SignalConsumer, Random) => Unit = {
|
||||
if (code == null) {
|
||||
(_, _, _, _, _, _) => ()
|
||||
(_, _, _, _, _, _, _) => ()
|
||||
} else {
|
||||
val tree = tb.parse(
|
||||
s"""
|
||||
|$header
|
||||
|def onAfterDamage(self: Ability, source: Monster, move: MoveTurn, mon: Monster, damage: Int, rng: Random): Unit = {
|
||||
|def onAfterDamage(self: Ability, source: Monster, move: MoveTurn, mon: Monster, damage: Int, reader: SignalConsumer, rng: Random): Unit = {
|
||||
| $helper
|
||||
| $code
|
||||
|}
|
||||
@@ -79,7 +83,7 @@ object Ability {
|
||||
val f = tb.compile(tree)
|
||||
val wrapper = f()
|
||||
implicit val c = code
|
||||
wrapper.asInstanceOf[(Ability, Monster, MoveTurn, Monster, Int, Random) => Unit]
|
||||
wrapper.asInstanceOf[(Ability, Monster, MoveTurn, Monster, Int, SignalConsumer, Random) => Unit]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package fmon.stat
|
||||
|
||||
import scala.util._
|
||||
|
||||
import fmon.battle.msg._
|
||||
import fmon.util._
|
||||
|
||||
import Monster._
|
||||
@@ -45,7 +46,7 @@ class Monster(val base : StorageMon) {
|
||||
status = None
|
||||
}
|
||||
|
||||
def addStatus(s : Status, source: EffectSource)(implicit rng: Random) = {
|
||||
def addStatus(s : Status, source: EffectSource)(implicit reader: SignalConsumer, rng: Random) = {
|
||||
if (s.effectType == EffectType.Volatile && !volatile.exists(_.name == s.name)) {
|
||||
volatile +:= s
|
||||
s.onStart(this, source)
|
||||
|
||||
@@ -9,6 +9,7 @@ import scala.io.Source
|
||||
import scala.util.Random
|
||||
|
||||
import Statistic._
|
||||
import fmon.battle.msg.{Message, SignalConsumer}
|
||||
import fmon.util._
|
||||
|
||||
object MoveType extends Enumeration {
|
||||
@@ -28,7 +29,7 @@ trait MoveTurn extends Effect {
|
||||
def prior: Int
|
||||
def target: Target
|
||||
def category: MoveType
|
||||
def useMove(user: Monster, target: Monster)(implicit rng: Random): Unit
|
||||
def useMove(user: Monster, target: Monster)(implicit reader: SignalConsumer, rng: Random): Unit
|
||||
}
|
||||
|
||||
class SwitchOut(val party: Party, val replacement: Monster) extends MoveTurn {
|
||||
@@ -38,10 +39,10 @@ class SwitchOut(val party: Party, val replacement: Monster) extends MoveTurn {
|
||||
def target = Target.Self
|
||||
def category = MoveType.Other
|
||||
|
||||
def useMove(user: Monster, target: Monster)(implicit rng: Random): Unit = {
|
||||
println(s"${party.trainer} withdrew $user!")
|
||||
def useMove(user: Monster, target: Monster)(implicit reader: SignalConsumer, rng: Random): Unit = {
|
||||
reader ! Message(s"${party.trainer} withdrew $user!")
|
||||
party.switchIn(replacement)
|
||||
println(s"${party.trainer} sent out $replacement")
|
||||
reader ! Message(s"${party.trainer} sent out $replacement")
|
||||
}
|
||||
|
||||
override def toString: String = s"Swap -> $replacement"
|
||||
@@ -72,34 +73,34 @@ abstract class Move extends MoveTurn {
|
||||
|
||||
// zPower, zMoveEffect, zMoveBoost
|
||||
|
||||
override def useMove(user: Monster, target: Monster)(implicit rng: Random) = {
|
||||
println(s"$user used $name.")
|
||||
override def useMove(user: Monster, target: Monster)(implicit reader: SignalConsumer, rng: Random) = {
|
||||
reader ! Message(s"$user used $name.")
|
||||
if (attackRoll(user, target)) {
|
||||
if (pow > 0 || powCallback != null) {
|
||||
val dmg = damageRoll(user, target)
|
||||
val actualDmg = target.takeDamage(dmg)
|
||||
if (dmg == actualDmg) {
|
||||
println(s"$target takes $actualDmg damage!")
|
||||
reader ! Message(s"$target takes $actualDmg damage!")
|
||||
} else {
|
||||
println(s"$target takes $actualDmg (+${dmg - actualDmg} overkill) damage!")
|
||||
reader ! Message(s"$target takes $actualDmg (+${dmg - actualDmg} overkill) damage!")
|
||||
}
|
||||
if (drain > 0.frac) {
|
||||
val healing = Math.max(drain * actualDmg, 1)
|
||||
user.recoverDamage(healing)
|
||||
println(s"$user recovered $healing damage.")
|
||||
reader ! Message(s"$user recovered $healing damage.")
|
||||
} else if (drain < 0.frac) {
|
||||
val recoil = Math.max(-drain * actualDmg, 1)
|
||||
user.takeDamage(recoil)
|
||||
println(s"$user took $recoil damage from recoil!")
|
||||
reader ! Message(s"$user took $recoil damage from recoil!")
|
||||
}
|
||||
|
||||
target.base.ability.onAfterDamage(user, this, target, actualDmg)
|
||||
|
||||
if (!user.isAlive) {
|
||||
println(s"$user fainted!")
|
||||
reader ! Message(s"$user fainted!")
|
||||
}
|
||||
if (!target.isAlive) {
|
||||
println(s"$target fainted!")
|
||||
reader ! Message(s"$target fainted!")
|
||||
}
|
||||
}
|
||||
applyBoosts(target, boosts, user)
|
||||
@@ -116,11 +117,11 @@ abstract class Move extends MoveTurn {
|
||||
|
||||
// TODO : Multiparty
|
||||
} else {
|
||||
println("Missed!")
|
||||
reader ! Message("Missed!")
|
||||
}
|
||||
}
|
||||
|
||||
def attackRoll(user: Monster, target: Monster)(implicit rng: Random) = {
|
||||
def attackRoll(user: Monster, target: Monster)(implicit reader: SignalConsumer, rng: Random) = {
|
||||
if (accuracy == 0) {
|
||||
true
|
||||
} else {
|
||||
@@ -131,7 +132,7 @@ abstract class Move extends MoveTurn {
|
||||
}
|
||||
}
|
||||
|
||||
def damageRoll(user: Monster, target: Monster)(implicit rng: Random) = {
|
||||
def damageRoll(user: Monster, target: Monster)(implicit reader: SignalConsumer, rng: Random) = {
|
||||
val atkStat = if (category == MoveType.Physical) PAtk else MAtk
|
||||
val defStat = if (category == MoveType.Physical) PDef else MDef
|
||||
// TODO : Fixed damage
|
||||
@@ -140,34 +141,34 @@ abstract class Move extends MoveTurn {
|
||||
val effectiveness = target.effectiveness(element)
|
||||
val multiplier = effectiveness * critMultiplier(user, target)
|
||||
if (effectiveness > 1.0) {
|
||||
println("It's super effective!")
|
||||
reader ! Message("It's super effective!")
|
||||
} else if (effectiveness < 1.0) {
|
||||
println("It's not very effective.")
|
||||
reader ! Message("It's not very effective.")
|
||||
}
|
||||
val maxDmg = (baseDmg * multiplier).toInt
|
||||
val minDmg = (17 \\ 20) * maxDmg
|
||||
rng.nextInt(minDmg, maxDmg)
|
||||
}
|
||||
|
||||
def critMultiplier(user: Monster, target: Monster)(implicit rng: Random) = {
|
||||
def critMultiplier(user: Monster, target: Monster)(implicit reader: SignalConsumer, rng: Random) = {
|
||||
// Percentage chance is different from Pokemon
|
||||
val stage = crit
|
||||
val chance = (1 << stage) \\ 16 // Doubles per stage
|
||||
if (rng.chance(chance)) {
|
||||
println("A critical hit!")
|
||||
reader ! Message("A critical hit!")
|
||||
1.5
|
||||
} else {
|
||||
1.0
|
||||
}
|
||||
}
|
||||
|
||||
def applyEffect(target: Monster, source: Monster, effect: Secondary)(implicit rng: Random) {
|
||||
def applyEffect(target: Monster, source: Monster, effect: Secondary)(implicit reader: SignalConsumer, rng: Random) {
|
||||
applyBoosts(target, effect.boosts, source)
|
||||
applyStatus(target, source, effect.status)
|
||||
applyStatus(target, source, effect.volatile)
|
||||
}
|
||||
|
||||
def applyStatus(target: Monster, user: Monster, status: StatusTemplate)(implicit rng: Random) {
|
||||
def applyStatus(target: Monster, user: Monster, status: StatusTemplate)(implicit reader: SignalConsumer, rng: Random) {
|
||||
if (target.isAlive && status != null) {
|
||||
target.addStatus(status.build, EffectSource(user, this))
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import scala.util.Random
|
||||
|
||||
import scala.io.Source
|
||||
|
||||
import fmon.battle.msg._
|
||||
import fmon.util._
|
||||
import EffectType.Volatile
|
||||
|
||||
@@ -47,11 +48,11 @@ 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 onStart(mon: Monster, source: EffectSource)(implicit reader: SignalConsumer, rng: Random) = template.onStart(this, mon, source, reader, 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)
|
||||
def onBeforeMove(mon: Monster, move: MoveTurn, target: Monster)(implicit reader: SignalConsumer, rng: Random) = template.onBeforeMove(this, mon, move, target, reader, rng)
|
||||
// val onModifyMove
|
||||
// val onHit
|
||||
def onResidualOrder = template.onResidualOrder
|
||||
@@ -68,11 +69,11 @@ abstract class StatusTemplate {
|
||||
val name: String
|
||||
// val id
|
||||
val effectType: EffectType
|
||||
val onStart: (Status, Monster, EffectSource, Random) => Unit
|
||||
val onStart: (Status, Monster, EffectSource, SignalConsumer, 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 onBeforeMove: (Status, Monster, MoveTurn, Monster, SignalConsumer, Random) => Boolean
|
||||
// val onModifyMove
|
||||
// val onHit
|
||||
val onResidualOrder: Int
|
||||
@@ -122,27 +123,34 @@ object Status {
|
||||
private val tb = runtimeMirror(getClass.getClassLoader).mkToolBox()
|
||||
private val header = """
|
||||
import scala.util.Random
|
||||
import fmon.battle.msg._
|
||||
import fmon.stat._
|
||||
import fmon.stat.MoveType._
|
||||
import fmon.stat.Statistic._
|
||||
import fmon.util._
|
||||
"""
|
||||
private val helpers = """
|
||||
def msg(text: String): Unit = {
|
||||
reader ! Message(text)
|
||||
}
|
||||
"""
|
||||
|
||||
def compileOnStart(code: String): (Status, Monster, EffectSource, Random ) => Unit = {
|
||||
def compileOnStart(code: String): (Status, Monster, EffectSource, SignalConsumer, Random ) => Unit = {
|
||||
if (code == null) {
|
||||
(_, _, _, _) => ()
|
||||
(_, _, _, _, _) => ()
|
||||
} else {
|
||||
val tree = tb.parse(
|
||||
s"""
|
||||
|$header
|
||||
|def onStart(self:Status, mon: Monster, source: EffectSource, rng: Random) = {
|
||||
|def onStart(self:Status, mon: Monster, source: EffectSource, reader: SignalConsumer, rng: Random) = {
|
||||
| $helpers
|
||||
| $code
|
||||
|}
|
||||
|onStart _
|
||||
""".stripMargin)
|
||||
val f = tb.compile(tree)
|
||||
val wrapper = f()
|
||||
wrapper.asInstanceOf[(Status, Monster, EffectSource, Random) => Unit]
|
||||
wrapper.asInstanceOf[(Status, Monster, EffectSource, SignalConsumer, Random) => Unit]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,14 +172,15 @@ object Status {
|
||||
}
|
||||
}
|
||||
|
||||
def compileOnBeforeMove(code: String): (Status, Monster, MoveTurn, Monster, Random) => Boolean = {
|
||||
def compileOnBeforeMove(code: String): (Status, Monster, MoveTurn, Monster, SignalConsumer, Random) => Boolean = {
|
||||
if (code == null) {
|
||||
(_, _, _, _, _) => true
|
||||
(_, _, _, _, _, _) => true
|
||||
} else {
|
||||
val tree = tb.parse(
|
||||
s"""
|
||||
$header
|
||||
def onBeforeMove(self: Status, mon: Monster, move: MoveTurn, target: Monster, rng: Random): Boolean = {
|
||||
def onBeforeMove(self: Status, mon: Monster, move: MoveTurn, target: Monster, reader: SignalConsumer, rng: Random): Boolean = {
|
||||
$helpers
|
||||
$code
|
||||
}
|
||||
onBeforeMove _
|
||||
@@ -179,7 +188,7 @@ object Status {
|
||||
|
||||
val f = tb.compile(tree)
|
||||
val wrapper = f()
|
||||
wrapper.asInstanceOf[(Status, Monster, MoveTurn, Monster, Random) => Boolean]
|
||||
wrapper.asInstanceOf[(Status, Monster, MoveTurn, Monster, SignalConsumer, Random) => Boolean]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ brn:
|
||||
if (!source.isMove) {
|
||||
print(s"[${source.mon}'s ${source.effect}]")
|
||||
}
|
||||
println(s"${mon} was burned!")
|
||||
msg(s"${mon} was burned!")
|
||||
/*
|
||||
if (sourceEffect && sourceEffect.id === 'flameorb') {
|
||||
target.status = Status('brn', '[from] 'item': Flame Orb');
|
||||
@@ -45,7 +45,7 @@ confusion:
|
||||
val maxDmg = (2 * mon.level / 5 + 2) * 40 * mon(PAtk) / (mon(PDef) * 50) + 2
|
||||
val minDmg = (17 \\ 20) * maxDmg
|
||||
val dmg = rng.nextInt(minDmg, maxDmg)
|
||||
println(s"${mon} hurt itself in its confusion.")
|
||||
msg(s"${mon} hurt itself in its confusion.")
|
||||
mon.takeDamage(dmg)
|
||||
false
|
||||
} else {
|
||||
@@ -65,7 +65,7 @@ confusion:
|
||||
onBeforeMovePriority: 3
|
||||
onEnd: println(s"${mon} snapped out of its confusion.")
|
||||
onStart: |-
|
||||
println(s"${mon} was confused!")
|
||||
msg(s"${mon} was confused!")
|
||||
/*
|
||||
if (sourceEffect && sourceEffect.id === 'lockedmove') {
|
||||
this.add('-start', target, 'confusion', '[fatigue]');
|
||||
@@ -102,7 +102,7 @@ par:
|
||||
onBeforeMovePriority: 1
|
||||
onBeforeMove: |
|
||||
if (rng.chance(1, 4)) {
|
||||
println(s"${mon} is fully paralyzed!")
|
||||
msg(s"${mon} is fully paralyzed!")
|
||||
false
|
||||
} else {
|
||||
true
|
||||
|
||||
Reference in New Issue
Block a user