From 20be0861989000e0bcaba1d31cdbdf006ac4a393 Mon Sep 17 00:00:00 2001 From: dtookey Date: Sat, 2 Sep 2023 23:49:11 -0400 Subject: [PATCH] looks like we're go for theory crafting in the morning --- src/main/kotlin/entries/BGSimulation.kt | 23 ++++++++++------ src/main/kotlin/simulation/Attack.kt | 32 ++++++++++++++++++++--- src/main/kotlin/simulation/AttackDice.kt | 2 +- src/main/kotlin/simulation/MeleeAttack.kt | 4 +-- 4 files changed, 47 insertions(+), 14 deletions(-) diff --git a/src/main/kotlin/entries/BGSimulation.kt b/src/main/kotlin/entries/BGSimulation.kt index 1e04089..0d56bbe 100644 --- a/src/main/kotlin/entries/BGSimulation.kt +++ b/src/main/kotlin/entries/BGSimulation.kt @@ -13,17 +13,24 @@ fun doSimulation(){ val itt = 10_000_000 val simulator = Simulator.getInstance(Runtime.getRuntime().availableProcessors()) - val critAttack = SimpleMeleeAttack( - actionRoll = AttackDice("1d20"), - damageRoll = Dice.makeDice("1d8"), - 10 - ) + val attackModifiers = listOf(FlatModifier(4), DiceBonusModifier("1d4")) + + RollType.entries.parallelStream() + .forEach{ + val normalAttack = SimpleMeleeAttack( + actionRoll = AttackDice("1d20", it, attackModifiers), + damageRoll = Dice.makeDice("1d8"), + 19 + ) + val normalAttackModel = AttackSimulatorModel(itt, normalAttack) + val normalResults = simulator.doSimulation(normalAttackModel) + + + AttackResult.printSimulationStatistics(normalResults, "Normal Attack (${it.name})") + } - val normalAttackModel = AttackSimulatorModel(itt, critAttack) - val normalResults = simulator.doSimulation(normalAttackModel) - AttackResult.printSimulationStatistics(normalResults, "Normal Attack") } \ No newline at end of file diff --git a/src/main/kotlin/simulation/Attack.kt b/src/main/kotlin/simulation/Attack.kt index f7e144a..416c167 100644 --- a/src/main/kotlin/simulation/Attack.kt +++ b/src/main/kotlin/simulation/Attack.kt @@ -2,11 +2,33 @@ package simulation import java.util.* +/** + * Attack defines the interface for performing an attack action. + * It handles rolling attack dice, calculating modifiers, checking for hits/crits, and triggering damage calculation. + */ interface Attack { + /** + * We can't call this an 'attack' roll because it could be the case that we're attacking by forcing a DC. So whoever + * is taking the positive action makes this roll. For melee attacks, this is a normal attack. For spell checks this + * would be the save roll. + */ val actionRoll: AttackDice - val passValue: Int + /** + * Similar to [actionRoll], we cannot call this 'defense', because it might be a spell DC. This is the value of the + * responder to the action. In a melee attack, this is AC. For a spell check, this would be the DC. + */ + val responseValue: Int + + /** + * calculateDamage calculates the damage for an attack by: + * - Rolling the relevant action + * - Evaluating action modifiers + * - Checking if action hits by comparing roll + modifiers to response value + * - Calling onCriticalHit, onNormalHit or onMiss based on hit result + * - Returning the AttackResult + */ fun calculateDamage(r: Random): AttackResult { val attackResult = actionRoll.roll(r) @@ -24,9 +46,9 @@ interface Attack { } } - private fun isHit(roll: RollResult, attackBonus: Int): Boolean { + private fun isHit(roll: RollResult, actionBonus: Int): Boolean { //ties go to the roller - return (roll.result + attackBonus) >= passValue + return (roll.result + actionBonus) >= responseValue } fun onNormalHit(r: Random): AttackResult @@ -37,6 +59,10 @@ interface Attack { } +/** + * AttackSimulatorModel simulates attacks by running [sampleSize] simulations using the provided [attack] instance. + * It implements [SimulationModel] to run the simulations and return [AttackResult]. + */ class AttackSimulatorModel(override val sampleSize: Int, private val attack: Attack) : SimulationModel { override fun simulate(r: Random): AttackResult { return attack.calculateDamage(r) diff --git a/src/main/kotlin/simulation/AttackDice.kt b/src/main/kotlin/simulation/AttackDice.kt index 57a0f81..fac1012 100644 --- a/src/main/kotlin/simulation/AttackDice.kt +++ b/src/main/kotlin/simulation/AttackDice.kt @@ -19,7 +19,7 @@ package simulation class AttackDice( override val rollString: String, override val rollType: RollType = RollType.Normal, - override val modifiers: ArrayList> = ArrayList() + override val modifiers: List> = ArrayList() ) : Dice { override val nDice: Int override val dieSize: Int diff --git a/src/main/kotlin/simulation/MeleeAttack.kt b/src/main/kotlin/simulation/MeleeAttack.kt index 9dde32b..737b491 100644 --- a/src/main/kotlin/simulation/MeleeAttack.kt +++ b/src/main/kotlin/simulation/MeleeAttack.kt @@ -7,12 +7,12 @@ import java.util.* * * @param actionRoll The dice roll used to determine if an attack hits. * @param damageRoll The dice roll used to determine damage if attack hits. - * @param passValue The defense value the attack must exceed to hit. + * @param responseValue The defense value the attack must exceed to hit. */ class SimpleMeleeAttack( override val actionRoll: AttackDice, val damageRoll: Dice, - override val passValue: Int + override val responseValue: Int ) : Attack { override fun onNormalHit(r: Random): AttackResult {