Connected the battle engine to the UI. Beginning to make messages appear in the UI

This commit is contained in:
James Daly
2019-06-13 22:22:57 -04:00
parent 2805bbf1c7
commit 0b52e91a3d
11 changed files with 109 additions and 61 deletions

View File

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

View File

@@ -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)

View File

@@ -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))
}

View File

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

View File

@@ -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