looks like we're go for theory crafting in the morning
This commit is contained in:
parent
ac5aec6cb4
commit
20be086198
@ -13,17 +13,24 @@ fun doSimulation(){
|
||||
val itt = 10_000_000
|
||||
val simulator = Simulator.getInstance<AttackResult>(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")
|
||||
}
|
||||
@ -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<AttackResult> {
|
||||
override fun simulate(r: Random): AttackResult {
|
||||
return attack.calculateDamage(r)
|
||||
|
||||
@ -19,7 +19,7 @@ package simulation
|
||||
class AttackDice(
|
||||
override val rollString: String,
|
||||
override val rollType: RollType = RollType.Normal,
|
||||
override val modifiers: ArrayList<Modifier<Int>> = ArrayList()
|
||||
override val modifiers: List<Modifier<Int>> = ArrayList()
|
||||
) : Dice {
|
||||
override val nDice: Int
|
||||
override val dieSize: Int
|
||||
|
||||
@ -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 {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user