Added fixed-damage moves

This commit is contained in:
dalyjame 2019-06-15 14:07:28 -04:00
parent 38dbb7fa92
commit b6fc98f44e
4 changed files with 259 additions and 38 deletions

View File

@ -14,23 +14,6 @@ case class Prop(url : Seq[String])
object Game { object Game {
def main(args : Array[String]): Unit = { def main(args : Array[String]): Unit = {
/*
implicit val rng = new scala.util.Random()
val form1 = Form("Diabolo")
val form2 = Form("Chanilla")
val movepool1 = IndexedSeq(Move("eruption"))
val movepool2 = IndexedSeq(Move("flail"))
val p1 = TrainerID("Jaeda", Gender.Female, 0)
val p2 = TrainerID("Wild Monster", Gender.Male, 0)
val party1 = new Party(p1, new MonsterPtr(Monster.generate("Allied Mon", p1, 500, form1, movepool1)), IndexedSeq())
val party2 = new Party(p2, new MonsterPtr(Monster.generate("Wild Mon", p2, 500, form2, movepool2)), IndexedSeq(
Monster.generate("Sideboard Mon", p2, 500, form2, movepool2)
))
println(form1.xpCurve)
val engine = new BattleEngine(party1, party2)
engine.play()
println(party1.lead.elements)
* */
Application.launch(classOf[Game], args: _*) Application.launch(classOf[Game], args: _*)
} }
} }
@ -46,7 +29,7 @@ class Game extends Application {
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("eruption"), Move("willowisp"), Move("thunderbolt"), Move("thunderwave")) val movepool1 = IndexedSeq(Move("eruption"), Move("willowisp"), Move("thunderbolt"), Move("thunderwave"), Move("facade"))
val movepool2 = IndexedSeq(Move("flail")) val movepool2 = IndexedSeq(Move("flail"))
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)

View File

@ -53,7 +53,8 @@ abstract class Move extends MoveTurn {
val desc: String val desc: String
val category: MoveType val category: MoveType
val pow: Int val pow: Int
val powCallback: (Monster, Move, Monster) => Int val powCallback: (Monster, Move, Monster, SignalConsumer, Random) => Int
val damageCallback: (Monster, Move, Monster, SignalConsumer, Random) => Int
val prior: Int val prior: Int
val accuracy: Int val accuracy: Int
val pp: Int val pp: Int
@ -76,7 +77,7 @@ abstract class Move extends MoveTurn {
override def useMove(user: Monster, target: Monster)(implicit reader: SignalConsumer, rng: Random) = { override def useMove(user: Monster, target: Monster)(implicit reader: SignalConsumer, rng: Random) = {
reader ! Message(s"$user used $name.") reader ! Message(s"$user used $name.")
if (attackRoll(user, target)) { if (attackRoll(user, target)) {
if (pow > 0 || powCallback != null) { if (pow > 0 || powCallback != null || damageCallback != null) {
val dmg = damageRoll(user, target) val dmg = damageRoll(user, target)
val actualDmg = target.takeDamage(dmg) val actualDmg = target.takeDamage(dmg)
if (dmg == actualDmg) { if (dmg == actualDmg) {
@ -133,10 +134,12 @@ abstract class Move extends MoveTurn {
} }
def damageRoll(user: Monster, target: Monster)(implicit reader: SignalConsumer, rng: Random) = { def damageRoll(user: Monster, target: Monster)(implicit reader: SignalConsumer, rng: Random) = {
if (damageCallback != null) {
damageCallback(user, this, target, reader, rng)
} else {
val atkStat = if (category == MoveType.Physical) PAtk else MAtk val atkStat = if (category == MoveType.Physical) PAtk else MAtk
val defStat = if (category == MoveType.Physical) PDef else MDef val defStat = if (category == MoveType.Physical) PDef else MDef
// TODO : Fixed damage val actualPow = if (powCallback != null) powCallback(user, this, target, reader, rng) else pow
val actualPow = if (powCallback != null) powCallback(user, this, target) else pow
val baseDmg = (2 * user.level / 5 + 2) * actualPow * user(atkStat) / (target(defStat) * 50) + 2 val baseDmg = (2 * user.level / 5 + 2) * actualPow * user(atkStat) / (target(defStat) * 50) + 2
val effectiveness = target.effectiveness(element) val effectiveness = target.effectiveness(element)
val multiplier = effectiveness * critMultiplier(user, target) val multiplier = effectiveness * critMultiplier(user, target)
@ -149,6 +152,7 @@ abstract class Move extends MoveTurn {
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 reader: SignalConsumer, rng: Random) = { def critMultiplier(user: Monster, target: Monster)(implicit reader: SignalConsumer, rng: Random) = {
// Percentage chance is different from Pokemon // Percentage chance is different from Pokemon
@ -195,6 +199,7 @@ case class MoveToken(
@JsonScalaEnumeration(classOf[MoveTypeType]) val category: MoveType, @JsonScalaEnumeration(classOf[MoveTypeType]) val category: MoveType,
val basePower: Option[Int], val basePower: Option[Int],
val basePowerCallback: String, val basePowerCallback: String,
val damage: String,
val priority: Int, val priority: Int,
val accuracy: Option[Int], val accuracy: Option[Int],
val pp: Int, val pp: Int,
@ -219,6 +224,7 @@ case class MoveToken(
val category = token.category val category = token.category
val pow = token.basePower.getOrElse(0) val pow = token.basePower.getOrElse(0)
val powCallback = Move.compilePowCallback(token.basePowerCallback) val powCallback = Move.compilePowCallback(token.basePowerCallback)
val damageCallback = Move.compileDamageCallback(token.damage)
val prior = token.priority val prior = token.priority
val pp = token.pp val pp = token.pp
val element = Element(token.`type`) val element = Element(token.`type`)
@ -247,14 +253,16 @@ object Move {
moves(name) moves(name)
} }
def compilePowCallback(code: String): (Monster, Move, Monster) => Int = { def compilePowCallback(code: String): (Monster, Move, Monster, SignalConsumer, Random) => Int = {
if (code != null) { if (code != null) {
val tb = runtimeMirror(getClass.getClassLoader).mkToolBox() val tb = runtimeMirror(getClass.getClassLoader).mkToolBox()
val tree = tb.parse( val tree = tb.parse(
s""" s"""
|import scala.util.Random
|import fmon.battle.msg._
|import fmon.stat._ |import fmon.stat._
|import fmon.stat.Statistic._ |import fmon.stat.Statistic._
|def callback(user : Monster, move: Move, target : Monster): Int = { |def callback(user : Monster, move: Move, target : Monster, reader: SignalConsumer, rng: Random): Int = {
| $code | $code
|} |}
|callback _ |callback _
@ -262,10 +270,14 @@ object Move {
val f = tb.compile(tree) val f = tb.compile(tree)
val wrapper = f() val wrapper = f()
wrapper.asInstanceOf[(Monster, Move, Monster) => Int] wrapper.asInstanceOf[(Monster, Move, Monster, SignalConsumer, Random) => Int]
} else { } else {
null null
} }
} }
def compileDamageCallback(code: String): (Monster, Move, Monster, SignalConsumer, Random) => Int = {
compilePowCallback(code)
}
} }

View File

@ -1621,6 +1621,25 @@ dragonpulse:
target: Any target: Any
type: Dragon type: Dragon
zMovePower: 160 zMovePower: 160
dragonrage:
accuracy: 100
basePower: 0
category: Special
contestType: Cool
damage: 40
flags:
mirror: 1
protect: 1
id: dragonrage
name: Dragon Rage
num: 82
pp: 10
priority: 0
secondary: null
shortDesc: Deals 40 HP of damage to the target.
target: Normal
type: Dragon
zMovePower: 100
dragonrush: dragonrush:
accuracy: 75 accuracy: 75
basePower: 100 basePower: 100
@ -2021,6 +2040,34 @@ extremespeed:
target: Normal target: Normal
type: Normal type: Normal
zMovePower: 160 zMovePower: 160
facade:
accuracy: 100
basePower: 70
category: Physical
contestType: Cute
desc: Power doubles if the user is burned, paralyzed, or poisoned. The physical
damage halving effect from the user's burn is ignored.
flags:
contact: 1
mirror: 1
protect: 1
id: facade
isViable: true
name: Facade
num: 263
onBasePower: |-
if (user.status != null && user.status != Status("slp")) {
move.pow * 2
} else {
move.pow
}
pp: 20
priority: 0
secondary: null
shortDesc: Power doubles if user is burn/poison/paralyzed.
target: Normal
type: Normal
zMovePower: 140
fairywind: fairywind:
accuracy: 100 accuracy: 100
basePower: 40 basePower: 40
@ -4081,6 +4128,28 @@ nastyplot:
target: Self target: Self
type: Dark type: Dark
zMoveEffect: clearnegativeboost zMoveEffect: clearnegativeboost
naturesmadness:
accuracy: 90
basePower: 0
category: Special
contestType: Tough
damage: Math.max(target.hp / 2, 1);
desc: Deals damage to the target equal to half of its current HP, rounded down,
but not less than 1 HP.
flags:
mirror: 1
protect: 1
id: naturesmadness
isViable: true
name: Nature's Madness
num: 717
pp: 10
priority: 0
secondary: null
shortDesc: Does damage equal to 1/2 target's current HP.
target: Normal
type: Fairy
zMovePower: 100
needlearm: needlearm:
accuracy: 100 accuracy: 100
basePower: 60 basePower: 60
@ -4125,6 +4194,27 @@ nightdaze:
target: Normal target: Normal
type: Dark type: Dark
zMovePower: 160 zMovePower: 160
nightshade:
accuracy: 100
basePower: 0
category: Special
contestType: Clever
damage: user.level
desc: Deals damage to the target equal to the user's level.
flags:
mirror: 1
protect: 1
id: nightshade
isViable: true
name: Night Shade
num: 101
pp: 15
priority: 0
secondary: null
shortDesc: Does damage equal to the user's level.
target: Normal
type: Ghost
zMovePower: 100
nightslash: nightslash:
accuracy: 100 accuracy: 100
basePower: 70 basePower: 70
@ -4799,7 +4889,27 @@ psychocut:
target: Normal target: Normal
type: Psychic type: Psychic
zMovePower: 140 zMovePower: 140
psywave:
accuracy: 100
basePower: 0
category: Special
contestType: Clever
damage: rng.nextInt(50, 151) * user.level / 100
desc: Deals damage to the target equal to (user's level) * (X + 50) / 100, where
X is a random number from 0 to 100, rounded down, but not less than 1 HP.
flags:
mirror: 1
protect: 1
id: psywave
name: Psywave
num: 149
pp: 15
priority: 0
secondary: null
shortDesc: Random damage equal to 0.5x-1.5x user's level.
target: Normal
type: Psychic
zMovePower: 100
quickattack: quickattack:
accuracy: 100 accuracy: 100
basePower: 40 basePower: 40
@ -5244,6 +5354,29 @@ seedflare:
target: Normal target: Normal
type: Grass type: Grass
zMovePower: 190 zMovePower: 190
seismictoss:
accuracy: 100
basePower: 0
category: Physical
contestType: Tough
damage: user.level
desc: Deals damage to the target equal to the user's level.
flags:
contact: 1
mirror: 1
nonsky: 1
protect: 1
id: seismictoss
isViable: true
name: Seismic Toss
num: 69
pp: 20
priority: 0
secondary: null
shortDesc: Does damage equal to the user's level.
target: Normal
type: Fighting
zMovePower: 100
shadowball: shadowball:
accuracy: 100 accuracy: 100
basePower: 80 basePower: 80
@ -5803,6 +5936,26 @@ snarl:
target: AllAdjacentFoes target: AllAdjacentFoes
type: Dark type: Dark
zMovePower: 100 zMovePower: 100
sonicboom:
accuracy: 90
basePower: 0
category: Special
contestType: Cool
damage: 20
desc: Deals 20 HP of damage to the target.
flags:
mirror: 1
protect: 1
id: sonicboom
name: Sonic Boom
num: 49
pp: 20
priority: 0
secondary: null
shortDesc: Always does 20 HP of damage.
target: Normal
type: Normal
zMovePower: 100
spacialrend: spacialrend:
accuracy: 95 accuracy: 95
basePower: 100 basePower: 100
@ -6140,6 +6293,30 @@ submission:
target: Normal target: Normal
type: Fighting type: Fighting
zMovePower: 160 zMovePower: 160
superfang:
accuracy: 90
basePower: 0
category: Physical
contestType: Tough
damage: Math.max(target.hp / 2, 1);
desc: Deals damage to the target equal to half of its current HP, rounded down,
but not less than 1 HP.
flags:
contact: 1
mirror: 1
protect: 1
id: superfang
isViable: true
name: Super Fang
num: 162
pp: 10
priority: 0
secondary: null
shortDesc: Does damage equal to 1/2 target's current HP.
target: Normal
type: Normal
zMovePower: 100
superpower: superpower:
accuracy: 100 accuracy: 100
basePower: 120 basePower: 120
@ -6763,6 +6940,34 @@ vitalthrow:
target: Normal target: Normal
type: Fighting type: Fighting
zMovePower: 140 zMovePower: 140
volttackle:
accuracy: 100
basePower: 120
category: Physical
contestType: Cool
desc: Has a 10% chance to paralyze the target. If the target lost HP, the user takes
recoil damage equal to 33% the HP lost by the target, rounded half up, but not
less than 1 HP.
flags:
contact: 1
mirror: 1
protect: 1
id: volttackle
isViable: true
name: Volt Tackle
num: 344
pp: 15
priority: 0
recoil:
denom: 100
num: 33
secondary:
chance: 10
status: par
shortDesc: Has 33% recoil. 10% chance to paralyze target.
target: Normal
type: Electric
zMovePower: 190
waterfall: waterfall:
accuracy: 100 accuracy: 100
basePower: 80 basePower: 80
@ -6985,6 +7190,26 @@ workup:
type: Normal type: Normal
zMoveBoost: zMoveBoost:
PAtk: 1 PAtk: 1
xscissor:
accuracy: 100
basePower: 80
category: Physical
contestType: Cool
flags:
contact: 1
mirror: 1
protect: 1
id: xscissor
isViable: true
name: X-Scissor
num: 404
pp: 15
priority: 0
secondary: null
shortDesc: No additional effect.
target: Normal
type: Bug
zMovePower: 160
zapcannon: zapcannon:
accuracy: 50 accuracy: 50
basePower: 120 basePower: 120

View File

@ -18,4 +18,5 @@ package object stat {
implicit def rngDice(rng : Random) = new Dice(rng) implicit def rngDice(rng : Random) = new Dice(rng)
implicit def ptrToMonster(ptr : MonsterPtr) : Monster = ptr.mon implicit def ptrToMonster(ptr : MonsterPtr) : Monster = ptr.mon
implicit def templateToStatus(status: StatusTemplate): Status = status.build implicit def templateToStatus(status: StatusTemplate): Status = status.build
} }