Added the first charge-move, razorwind. Future moves incoming. Note that since there are no items or weather, insta-charge is not yet implemented

This commit is contained in:
dalyjame
2019-06-18 16:48:54 -04:00
parent c244d36bd6
commit e008892c13
6 changed files with 147 additions and 47 deletions

View File

@@ -36,6 +36,7 @@ trait MoveTurn extends Effect {
class SwitchOut(val party: Party, val replacement: Monster) extends MoveTurn {
def name = "Swap"
def id = "swap"
def flags = Set()
def prior = +6
def target = Target.Self
@@ -52,11 +53,13 @@ class SwitchOut(val party: Party, val replacement: Monster) extends MoveTurn {
abstract class Move extends MoveTurn {
val name: String
val id: String
val desc: String
val category: MoveType
val pow: Int
val powCallback: (Monster, Move, Monster, SignalConsumer, Random) => Int
val damageCallback: (Monster, Move, Monster, SignalConsumer, Random) => Int
val onTryMove: (Monster, Move, Monster, SignalConsumer, Random) => Boolean
val prior: Int
val accuracy: Int
val pp: Int
@@ -78,53 +81,56 @@ abstract class Move extends MoveTurn {
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 || damageCallback != null) {
val dmg = damageRoll(user, target)
val actualDmg = target.takeDamage(dmg)
if (dmg == actualDmg) {
reader ! Message(s"$target takes $actualDmg damage!")
reader ! DamageMsg(dmg, target, element)
} else {
reader ! Message(s"$target takes $actualDmg (+${dmg - actualDmg} overkill) damage!")
reader ! DamageMsg(dmg, target, element)
if (onTryMove(user, this, target, reader, rng)) {
if (attackRoll(user, target)) {
if (pow > 0 || powCallback != null || damageCallback != null) {
val dmg = damageRoll(user, target)
val actualDmg = target.takeDamage(dmg)
if (dmg == actualDmg) {
reader ! Message(s"$target takes $actualDmg damage!")
reader ! DamageMsg(dmg, target, element)
} else {
reader ! Message(s"$target takes $actualDmg (+${dmg - actualDmg} overkill) damage!")
reader ! DamageMsg(dmg, target, element)
}
if (drain > 0.frac) {
val healing = Math.max(drain * actualDmg, 1)
user.recoverDamage(healing)
reader ! Message(s"$user recovered $healing damage.")
} else if (drain < 0.frac) {
val recoil = Math.max(-drain * actualDmg, 1)
user.takeDamage(recoil)
reader ! Message(s"$user took $recoil damage from recoil!")
reader ! DamageMsg(actualDmg, target, Element("None"))
}
target.base.ability.onAfterDamage(user, this, target, actualDmg)
if (!user.isAlive) {
reader ! Message(s"$user fainted!")
}
if (!target.isAlive) {
reader ! Message(s"$target fainted!")
}
}
if (drain > 0.frac) {
val healing = Math.max(drain * actualDmg, 1)
user.recoverDamage(healing)
reader ! Message(s"$user recovered $healing damage.")
} else if (drain < 0.frac) {
val recoil = Math.max(-drain * actualDmg, 1)
user.takeDamage(recoil)
reader ! Message(s"$user took $recoil damage from recoil!")
reader ! DamageMsg(actualDmg, target, Element("None"))
applyBoosts(target, boosts, user)
applyStatus(target, user, status)
if (effect != null) {
applyEffect(target, user, effect)
}
target.base.ability.onAfterDamage(user, this, target, actualDmg)
if (!user.isAlive) {
reader ! Message(s"$user fainted!")
if (selfEffect != null) {
applyEffect(user, user, selfEffect)
}
if (!target.isAlive) {
reader ! Message(s"$target fainted!")
if (secondary != null && rng.chance(secondary.chance.%%)) {
applyEffect(target, user, secondary)
}
// TODO : Multiparty
} else {
reader ! Message("Missed!")
}
applyBoosts(target, boosts, user)
applyStatus(target, user, status)
if (effect != null) {
applyEffect(target, user, effect)
}
if (selfEffect != null) {
applyEffect(user, user, selfEffect)
}
if (secondary != null && rng.chance(secondary.chance.%%)) {
applyEffect(target, user, secondary)
}
// TODO : Multiparty
} else {
reader ! Message("Missed!")
}
}
def attackRoll(user: Monster, target: Monster)(implicit reader: SignalConsumer, rng: Random) = {
@@ -208,10 +214,12 @@ abstract class Move extends MoveTurn {
case class MoveToken(
val name: String,
val id: String,
val shortDesc: String,
@JsonScalaEnumeration(classOf[MoveTypeType]) val category: MoveType,
val basePower: Option[Int],
val basePowerCallback: String,
val onTryMove: String,
val damage: String,
val priority: Int,
val accuracy: Option[Int],
@@ -233,11 +241,13 @@ case class MoveToken(
val effectToken = SecondaryToken(100, Map(), null, token.volatileStatus, null)
new Move {
val name = token.name
val id = token.id
val desc = token.shortDesc
val category = token.category
val pow = token.basePower.getOrElse(0)
val powCallback = Move.compilePowCallback(token.basePowerCallback)
val damageCallback = Move.compileDamageCallback(token.damage)
val onTryMove = Move.compileOnTryMove(token.onTryMove)
val prior = token.priority
val pp = token.pp
val element = Element(token.`type`)
@@ -265,7 +275,15 @@ object Move {
}
moves(name)
}
private val helpers = """
implicit val dice = rng
implicit val consumer = reader
def msg(text: String): Unit = {
reader ! Message(text)
}
"""
def compilePowCallback(code: String): (Monster, Move, Monster, SignalConsumer, Random) => Int = {
if (code != null) {
val tb = runtimeMirror(getClass.getClassLoader).mkToolBox()
@@ -294,4 +312,29 @@ object Move {
def compileDamageCallback(code: String): (Monster, Move, Monster, SignalConsumer, Random) => Int = {
compilePowCallback(code)
}
def compileOnTryMove(code: String): (Monster, Move, Monster, SignalConsumer, Random) => Boolean = {
if (code == null) {
(_, _, _, _, _) => true
} else {
val tb = runtimeMirror(getClass.getClassLoader).mkToolBox()
val tree = tb.parse(
s"""
|import scala.util.Random
|import fmon._
|import fmon.battle.msg._
|import fmon.stat._
|import fmon.stat.Statistic._
|def callback(user : Monster, move: Move, target : Monster, reader: SignalConsumer, rng: Random): Boolean = {
| $helpers
| $code
|}
|callback _
""".stripMargin)
val f = tb.compile(tree)
val wrapper = f()
wrapper.asInstanceOf[(Monster, Move, Monster, SignalConsumer, Random) => Boolean]
}
}
}