started modeling 5th ed fight mechanics
This commit is contained in:
parent
e96a231d3c
commit
526caf9690
21
src/main/kotlin/simulation/Attack.kt
Normal file
21
src/main/kotlin/simulation/Attack.kt
Normal file
@ -0,0 +1,21 @@
|
||||
package simulation
|
||||
|
||||
import java.util.*
|
||||
|
||||
interface Attack {
|
||||
fun attackerSuccessful(r: Random): Boolean
|
||||
|
||||
fun resultingDamage(r: Random, attackSuccessful: Boolean): Int
|
||||
|
||||
fun getResultingDamage(r: Random): Int{
|
||||
val success = attackerSuccessful(r)
|
||||
return resultingDamage(r, success)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class AttackSimulatorModel(override val sampleSize: Int, private val attack: Attack) : SimulationModel<Int>{
|
||||
override fun simulate(r: Random): Int {
|
||||
return attack.getResultingDamage(r)
|
||||
}
|
||||
}
|
||||
86
src/main/kotlin/simulation/Dice.kt
Normal file
86
src/main/kotlin/simulation/Dice.kt
Normal file
@ -0,0 +1,86 @@
|
||||
package simulation
|
||||
|
||||
import java.util.*
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* Enumeration of different dice roll types.
|
||||
*
|
||||
* @property Advantage Rolls the dice twice and takes the higher result.
|
||||
* @property Normal Rolls the dice normally once.
|
||||
* @property Disadvantage Rolls the dice twice and takes the lower result.
|
||||
*/
|
||||
enum class RollType{
|
||||
/**
|
||||
* Rolls the dice twice and returns the higher of the two results.
|
||||
*/
|
||||
Advantage,
|
||||
/**
|
||||
* Rolls the dice once normally.
|
||||
*/
|
||||
Normal,
|
||||
/**
|
||||
* Rolls the dice twice and returns the lower of the two results.
|
||||
*/
|
||||
Disadvantage
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents dice that can be rolled with different roll types and modifiers.
|
||||
*
|
||||
* @param rollString The dice roll notation, e.g. "2d6"
|
||||
* @param rollType The roll type to use, which determines how the dice are rolled
|
||||
* @param modifiers Optional modifier functions that add a bonus to the roll result
|
||||
*/
|
||||
class Dice(rollString: String, private val rollType: RollType = RollType.Normal, private vararg val modifiers: Modifier<Int>) {
|
||||
private val nDice: Int
|
||||
private val dieSize: Int
|
||||
|
||||
init {
|
||||
val parts = rollString.lowercase().split("d")
|
||||
nDice = parts[0].toInt()
|
||||
dieSize = parts[1].toInt()
|
||||
}
|
||||
|
||||
/**
|
||||
* Rolls the dice and returns the result.
|
||||
*
|
||||
* The roll result is determined based on the [rollType].
|
||||
*
|
||||
* The result is also modified by any [modifiers] that have been added to this [Dice].
|
||||
*
|
||||
* @param r The [Random] instance to use for the dice rolls
|
||||
* @return The result of the dice roll with modifiers applied
|
||||
* @see RollType
|
||||
*/
|
||||
fun roll(r: Random): Int {
|
||||
val result = when(rollType){
|
||||
RollType.Advantage->{
|
||||
val range1 = (dieSize * nDice) - nDice
|
||||
val range2 = (dieSize * nDice) - nDice
|
||||
max(range1, range2) + nDice
|
||||
}
|
||||
RollType.Disadvantage->{
|
||||
val range1 = (dieSize * nDice) - nDice
|
||||
val range2 = (dieSize * nDice) - nDice
|
||||
min(range1, range2) + nDice
|
||||
}
|
||||
else->{
|
||||
val range = (dieSize * nDice) - nDice
|
||||
r.nextInt(range) + nDice
|
||||
}
|
||||
}
|
||||
return result + evaluateModifiers(r)
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates all the modifiers passed to this Dice instance and returns their sum.
|
||||
*
|
||||
* @param r The Random instance to pass to each modifier's getBonus() method
|
||||
* @return The summed bonus values from all modifiers
|
||||
*/
|
||||
fun evaluateModifiers(r: Random): Int{
|
||||
return modifiers.sumOf{ it.getBonus(r) }
|
||||
}
|
||||
}
|
||||
@ -1,99 +0,0 @@
|
||||
package simulation
|
||||
|
||||
import java.util.*
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
interface Attack {
|
||||
fun attackerSuccessful(r: Random): Boolean
|
||||
|
||||
fun resultingDamage(r: Random, attackSuccessful: Boolean): Int
|
||||
|
||||
fun getResultingDamage(r: Random): Int{
|
||||
val success = attackerSuccessful(r)
|
||||
return resultingDamage(r, success)
|
||||
}
|
||||
}
|
||||
|
||||
interface Bonus {
|
||||
fun getBonus(r: Random): Int
|
||||
}
|
||||
|
||||
class AttackSimulatorModel(override val sampleSize: Int, private val attack: Attack) : SimulationModel<Int>{
|
||||
override fun simulate(r: Random): Int {
|
||||
return attack.getResultingDamage(r)
|
||||
}
|
||||
}
|
||||
|
||||
enum class RollType{
|
||||
Advantage,
|
||||
Normal,
|
||||
Disadvantage
|
||||
}
|
||||
|
||||
class Dice(rollString: String, val rollType: RollType = RollType.Normal) {
|
||||
private val nDice: Int
|
||||
private val dieSize: Int
|
||||
|
||||
init {
|
||||
val parts = rollString.lowercase().split("d")
|
||||
nDice = parts[0].toInt()
|
||||
dieSize = parts[1].toInt()
|
||||
}
|
||||
|
||||
fun roll(r: Random): Int {
|
||||
return when(rollType){
|
||||
RollType.Advantage->{
|
||||
val range1 = (dieSize * nDice) - nDice
|
||||
val range2 = (dieSize * nDice) - nDice
|
||||
return max(range1, range2) + nDice
|
||||
}
|
||||
RollType.Disadvantage->{
|
||||
val range1 = (dieSize * nDice) - nDice
|
||||
val range2 = (dieSize * nDice) - nDice
|
||||
return min(range1, range2) + nDice
|
||||
}
|
||||
else->{
|
||||
val range = (dieSize * nDice) - nDice
|
||||
r.nextInt(range) + nDice
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class DiceBonus(private val dice: Dice) : Bonus {
|
||||
override fun getBonus(r: Random): Int {
|
||||
return dice.roll(r)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class FlatBonus(private val bonus: Int) : Bonus {
|
||||
override fun getBonus(r: Random): Int {
|
||||
return bonus
|
||||
}
|
||||
}
|
||||
|
||||
class SimpleMeleeAttack(
|
||||
val attack: Dice,
|
||||
val attackBonus: ArrayList<Bonus>,
|
||||
val damageRoll: Dice,
|
||||
val damageBonus: ArrayList<Bonus>,
|
||||
val defense: Int
|
||||
) : Attack {
|
||||
override fun attackerSuccessful(r: Random): Boolean {
|
||||
val attackTotal = attack.roll(r) + attackBonus.sumOf { it.getBonus(r) }
|
||||
|
||||
return attackTotal >= defense
|
||||
}
|
||||
|
||||
override fun resultingDamage(r: Random, attackSuccessful: Boolean): Int {
|
||||
return if(attackSuccessful){
|
||||
damageRoll.roll(r) + damageBonus.sumOf { it.getBonus(r) }
|
||||
}else{
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
31
src/main/kotlin/simulation/MeleeAttack.kt
Normal file
31
src/main/kotlin/simulation/MeleeAttack.kt
Normal file
@ -0,0 +1,31 @@
|
||||
package simulation
|
||||
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Represents a simple melee attack in a simulation.
|
||||
*
|
||||
* @param attackRoll The dice roll used to determine if an attack hits.
|
||||
* @param damageRoll The dice roll used to determine damage if attack hits.
|
||||
* @param defense The defense value the attack must exceed to hit.
|
||||
*/
|
||||
class SimpleMeleeAttack(
|
||||
val attackRoll: Dice,
|
||||
val damageRoll: Dice,
|
||||
val defense: Int
|
||||
) : Attack {
|
||||
override fun attackerSuccessful(r: Random): Boolean {
|
||||
val attackTotal = attackRoll.roll(r)
|
||||
|
||||
return attackTotal >= defense
|
||||
}
|
||||
|
||||
override fun resultingDamage(r: Random, attackSuccessful: Boolean): Int {
|
||||
return if(attackSuccessful){
|
||||
damageRoll.roll(r)
|
||||
}else{
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
63
src/main/kotlin/simulation/Modifier.kt
Normal file
63
src/main/kotlin/simulation/Modifier.kt
Normal file
@ -0,0 +1,63 @@
|
||||
package simulation
|
||||
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Interface for objects that can modify a value with a bonus.
|
||||
*
|
||||
* Implementations will generate a bonus value based on their internal logic.
|
||||
*
|
||||
* A [Random] object is provided if the bonus is variable.
|
||||
*/
|
||||
interface Modifier<T> {
|
||||
|
||||
/**
|
||||
* Generates a bonus integer, potentially using the provided Random instance if needs be.
|
||||
*
|
||||
* @param r Random instance to use for random number generation
|
||||
* @return a generated bonus integer
|
||||
*/
|
||||
fun getBonus(r: Random): T
|
||||
}
|
||||
|
||||
/**
|
||||
* A [Modifier] that generates a random bonus integer based on a provided [Dice].
|
||||
*
|
||||
* On each call to [getBonus], it will roll the given [Dice] using the passed [Random]
|
||||
* instance and return the result as a positive bonus amount.
|
||||
*
|
||||
* @param dice The [Dice] instance to use for generating bonus values.
|
||||
*/
|
||||
class DiceBonus(private val dice: Dice) : Modifier<Int> {
|
||||
override fun getBonus(r: Random): Int {
|
||||
return dice.roll(r)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A [Modifier] that applies a random penalty based on a [Dice].
|
||||
*
|
||||
* On each call to [getBonus], it will roll the provided [Dice] object and return the
|
||||
* result as a negative number.
|
||||
*
|
||||
* @param dice The [Dice] to use for generating penalty values.
|
||||
*/
|
||||
class DicePenalty(private val dice: Dice): Modifier<Int>{
|
||||
override fun getBonus(r: Random): Int {
|
||||
return -dice.roll(r)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A [Modifier] that applies a fixed bonus amount.
|
||||
*
|
||||
* The bonus value is set on construction and does not vary.
|
||||
*
|
||||
* @param bonus The fixed bonus amount to apply.
|
||||
*/
|
||||
class FlatModifier(private val bonus: Int) : Modifier<Int> {
|
||||
override fun getBonus(r: Random): Int {
|
||||
return bonus
|
||||
}
|
||||
}
|
||||
@ -21,18 +21,14 @@ class SimulatorTest {
|
||||
val simulator = Simulator.getInstance<Int>(Runtime.getRuntime().availableProcessors())
|
||||
|
||||
val attack = SimpleMeleeAttack(
|
||||
Dice("1d20"),
|
||||
arrayListOf(FlatBonus(5)),
|
||||
Dice("2d6"),
|
||||
arrayListOf(FlatBonus(5)),
|
||||
Dice("1d20", RollType.Normal, FlatModifier(5)),
|
||||
Dice("2d6", RollType.Normal, FlatModifier(5)),
|
||||
15
|
||||
)
|
||||
|
||||
val attackWithAdvantageAndBless = SimpleMeleeAttack(
|
||||
Dice("1d20", RollType.Advantage),
|
||||
arrayListOf(FlatBonus(5), DiceBonus(Dice("1d4"))),
|
||||
Dice("2d6"),
|
||||
arrayListOf(FlatBonus(5)),
|
||||
Dice("1d20", RollType.Advantage,FlatModifier(5), DiceBonus(Dice("1d4"))),
|
||||
Dice("2d6", RollType.Normal, FlatModifier(5)),
|
||||
15
|
||||
)
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user