Refactor the roll mechanism to allow broader instructions set.

This commit is contained in:
Thomas Andres Gomez 2024-11-27 14:09:26 +01:00
parent d2ae180cf7
commit 8d93d46cce
10 changed files with 207 additions and 146 deletions

View file

@ -1,19 +1,7 @@
package com.pixelized.desktop.lwa.business package com.pixelized.desktop.lwa.business
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet
object RollUseCase { object RollUseCase {
private val diceParser = Regex(
"""(?<sign>[+-])?\s*(?<modifier>[ade])?(?<quantity>\d+)[dD](?<face>\d+)"""
)
private val flatParser = Regex(
"""(?<sign>[+-])?\s*[^a-zA-Z](?<value>\d+)\b"""
)
private val paramParser = Regex(
"""(?<sign>[+-])?\s*(?<param>BDGT)\b"""
)
fun rollD100(): Int { fun rollD100(): Int {
return roll(quantity = 1, faces = 100) return roll(quantity = 1, faces = 100)
} }
@ -22,39 +10,6 @@ object RollUseCase {
return sum(count = quantity) { (Math.random() * faces.toDouble() + 1).toInt() } return sum(count = quantity) { (Math.random() * faces.toDouble() + 1).toInt() }
} }
fun roll(characterSheet: CharacterSheet, roll: String): Int {
println(roll)
return diceParser.findAll(roll).sumOf { match ->
val (sign, modifier, quantity, faces) = match.destructured
((if (sign == "-") -1 else 1) * roll(
quantity = quantity.toInt(),
faces = faces.toInt()
)).also {
println("roll ${sign}${quantity}d${faces} -> $it")
}
} + flatParser.findAll(roll).sumOf { match ->
val (sign, value) = match.destructured
((if (sign == "-") -1 else 1) * value.toInt()).also {
println("flat: ${sign}${value} -> $it")
}
} + paramParser.findAll(roll).sumOf { match ->
val (sign, param) = match.destructured
(if (sign == "-") -1 else 1) * when (param) {
"BDGT" -> diceParser.findAll(characterSheet.damageBonus).sumOf {
val (sign, modifier, quantity, faces) = it.destructured
((if (sign == "-") -1 else 1) * roll(
quantity = quantity.toInt(),
faces = faces.toInt()
)).also {
println("param: ${sign}${param} -> $it")
}
}
else -> 0
}
}
}
private fun sum(count: Int, block: () -> Int): Int { private fun sum(count: Int, block: () -> Int): Int {
return if (count > 1) { return if (count > 1) {
block() + sum(count - 1, block) block() + sum(count - 1, block)

View file

@ -1,39 +1,110 @@
package com.pixelized.desktop.lwa.business package com.pixelized.desktop.lwa.business
import com.pixelized.desktop.lwa.parser.arithmetic.ArithmeticParser
import com.pixelized.desktop.lwa.parser.arithmetic.Instruction import com.pixelized.desktop.lwa.parser.arithmetic.Instruction
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet
import kotlin.math.max import kotlin.math.max
class SkillValueComputationUseCase { class SkillValueComputationUseCase(
private val arithmeticParser: ArithmeticParser,
) {
fun computeSkillValue( fun computeSkillValue(
sheet: CharacterSheet, sheet: CharacterSheet,
skill: CharacterSheet.Skill, skill: CharacterSheet.Skill,
diminished: Int, diminished: Int,
): Int { ): Int {
val baseSum = skill.base.sumOf { val baseSum = arithmeticParser.parse(skill.base).sumOf { instruction ->
when (val instruction = it.instruction) { when (instruction) {
is Instruction.Dice -> 0 is Instruction.Dice -> 0
is Instruction.Flat -> instruction.value
Instruction.Word.BDC -> 0 is Instruction.Flat -> {
Instruction.Word.BDD -> 0 instruction.value
Instruction.Word.STR -> sheet.strength }
Instruction.Word.DEX -> sheet.dexterity
Instruction.Word.CON -> sheet.constitution is Instruction.Word -> {
Instruction.Word.HEI -> sheet.height when (instruction.type) {
Instruction.Word.INT -> sheet.intelligence Instruction.Word.Type.BDC -> 0
Instruction.Word.POW -> sheet.power Instruction.Word.Type.BDD -> 0
Instruction.Word.CHA -> sheet.charisma Instruction.Word.Type.STR -> sheet.strength
} * it.sign Instruction.Word.Type.DEX -> sheet.dexterity
Instruction.Word.Type.CON -> sheet.constitution
Instruction.Word.Type.HEI -> sheet.height
Instruction.Word.Type.INT -> sheet.intelligence
Instruction.Word.Type.POW -> sheet.power
Instruction.Word.Type.CHA -> sheet.charisma
}
}
} * instruction.sign
} }
val base = if (skill.occupation) { val base = if (skill.occupation) {
max(MIN_OCCUPATION_VALUE, baseSum) max(MIN_OCCUPATION_VALUE, baseSum)
} else { } else {
baseSum baseSum
} }
return max(base + skill.bonus + skill.level - diminished, 0) return max(base + skill.bonus + skill.level - diminished, 0)
} }
fun computeRoll(
sheet: CharacterSheet,
roll: String,
): Int { // TODO Roll detail instead of an simple Int.
print("Roll ->")
return arithmeticParser.parse(roll).sumOf { instruction ->
val value = when (instruction) {
is Instruction.Dice -> RollUseCase.roll(
quantity = instruction.quantity,
faces = instruction.faces
)
is Instruction.Flat -> instruction.value
is Instruction.Word -> {
when (instruction.type) {
Instruction.Word.Type.BDC -> {
val damageBonusInstructions = arithmeticParser
.parse(sheet.damageBonus)
.firstOrNull()
if (damageBonusInstructions is Instruction.Dice) {
RollUseCase.roll(
quantity = damageBonusInstructions.quantity,
faces = damageBonusInstructions.faces
)
} else {
0
}
}
Instruction.Word.Type.BDD -> {
val damageBonusInstructions = arithmeticParser
.parse(sheet.damageBonus)
.firstOrNull()
if (damageBonusInstructions is Instruction.Dice) {
RollUseCase.roll(
quantity = damageBonusInstructions.quantity,
faces = damageBonusInstructions.faces
) / 2
} else {
0
}
}
Instruction.Word.Type.STR -> sheet.strength
Instruction.Word.Type.DEX -> sheet.dexterity
Instruction.Word.Type.CON -> sheet.constitution
Instruction.Word.Type.HEI -> sheet.height
Instruction.Word.Type.INT -> sheet.intelligence
Instruction.Word.Type.POW -> sheet.power
Instruction.Word.Type.CHA -> sheet.charisma
}
}
} * instruction.sign
value.also { print(" ($instruction):$it") }
}.also { println() }
}
companion object { companion object {
private const val MIN_OCCUPATION_VALUE = 40 private const val MIN_OCCUPATION_VALUE = 40
} }

View file

@ -21,13 +21,13 @@ class ArithmeticParser {
) )
@Throws(Instruction.UnknownInstruction::class) @Throws(Instruction.UnknownInstruction::class)
fun parse(value: String): List<Arithmetic> { fun parse(value: String): List<Instruction> {
return operatorParser.findAll(value).mapNotNull { return operatorParser.findAll(value).mapNotNull {
val (operator, instruction) = it.destructured val (operator, instruction) = it.destructured
if (instruction.isNotBlank()) { if (instruction.isNotBlank()) {
Arithmetic( parseInstruction(
sign = parseOperator(operator), sign = parseOperator(operator),
instruction = parseInstruction(instruction), instruction = instruction,
) )
} else { } else {
null null
@ -36,10 +36,14 @@ class ArithmeticParser {
} }
@Throws(Instruction.UnknownInstruction::class) @Throws(Instruction.UnknownInstruction::class)
fun parseInstruction(instruction: String): Instruction { fun parseInstruction(
sign: Int,
instruction: String
): Instruction {
diceParser.find(instruction)?.let { diceParser.find(instruction)?.let {
val (modifier, quantity, faces) = it.destructured val (modifier, quantity, faces) = it.destructured
Instruction.Dice( Instruction.Dice(
sign = sign,
modifier = parseModifier(value = modifier), modifier = parseModifier(value = modifier),
quantity = quantity.toInt(), quantity = quantity.toInt(),
faces = faces.toInt(), faces = faces.toInt(),
@ -47,11 +51,17 @@ class ArithmeticParser {
}?.let { return it } }?.let { return it }
wordParser.find(instruction)?.let { wordParser.find(instruction)?.let {
parseWord(value = it.value) parseWord(
sign = sign,
value = it.value
)
}?.let { return it } }?.let { return it }
flatParser.find(instruction)?.let { flatParser.find(instruction)?.let {
Instruction.Flat(value = it.value.toInt()) Instruction.Flat(
sign = sign,
value = it.value.toInt(),
)
}?.let { return it } }?.let { return it }
throw Instruction.UnknownInstruction(payload = instruction) throw Instruction.UnknownInstruction(payload = instruction)
@ -74,31 +84,39 @@ class ArithmeticParser {
} }
} }
private fun parseWord(value: String): Word? { private fun parseWord(
sign: Int,
value: String,
): Word? {
return try { return try {
Word.valueOf(value) Word(
sign = sign,
type = Word.Type.valueOf(value),
)
} catch (_: Exception) { } catch (_: Exception) {
return null return null
} }
} }
fun convertInstructionToString( fun convertInstructionToString(
instructions: List<Arithmetic>, instructions: List<Instruction>,
): String { ): String {
return instructions.map { return instructions.map {
val sign = if (it.sign > 0) "+" else "-" val sign = if (it.sign > 0) "+" else "-"
val value = when (val instruction = it.instruction) { val value = when (it) {
is Instruction.Dice -> "${instruction.modifier ?: ""}${instruction.quantity}d${instruction.faces}" is Instruction.Dice -> "${it.modifier ?: ""}${it.quantity}d${it.faces}"
is Instruction.Flat -> "${instruction.value}" is Instruction.Flat -> "${it.value}"
Word.BDC -> Word.BDC.name is Word -> when (it.type) {
Word.BDD -> Word.BDD.name Word.Type.BDC -> Word.Type.BDC.name
Word.STR -> Word.STR.name Word.Type.BDD -> Word.Type.BDD.name
Word.DEX -> Word.DEX.name Word.Type.STR -> Word.Type.STR.name
Word.CON -> Word.CON.name Word.Type.DEX -> Word.Type.DEX.name
Word.HEI -> Word.HEI.name Word.Type.CON -> Word.Type.CON.name
Word.INT -> Word.INT.name Word.Type.HEI -> Word.Type.HEI.name
Word.POW -> Word.POW.name Word.Type.INT -> Word.Type.INT.name
Word.CHA -> Word.CHA.name Word.Type.POW -> Word.Type.POW.name
Word.Type.CHA -> Word.Type.CHA.name
}
} }
"$sign$value" "$sign$value"
}.joinToString(separator = " ") { }.joinToString(separator = " ") {
@ -107,6 +125,6 @@ class ArithmeticParser {
} }
companion object { companion object {
val words: List<String> = Word.entries.map { it.name } val words: List<String> = Word.Type.entries.map { it.name }
} }
} }

View file

@ -1,40 +1,64 @@
package com.pixelized.desktop.lwa.parser.arithmetic package com.pixelized.desktop.lwa.parser.arithmetic
class Arithmetic( sealed class Instruction(
val sign: Int, val sign: Int,
val instruction: Instruction, ) {
) class Dice(
sign: Int,
sealed interface Instruction {
data class Dice(
val modifier: Modifier?, val modifier: Modifier?,
val quantity: Int, val quantity: Int,
val faces: Int, val faces: Int,
) : Instruction { ) : Instruction(
sign = sign,
) {
enum class Modifier { enum class Modifier {
ADVANTAGE, ADVANTAGE,
DISADVANTAGE, DISADVANTAGE,
EMPHASIS, EMPHASIS,
} }
override fun toString(): String {
return "${sign.sign}${quantity}d${faces}"
}
} }
data class Flat( class Flat(
sign: Int,
val value: Int, val value: Int,
) : Instruction ) : Instruction(
sign = sign,
) {
override fun toString(): String {
return "${sign.sign}${value}"
}
}
enum class Word : Instruction { class Word(
BDC, // Damages bonus for melee sign: Int,
BDD, // Damages bonus for range val type: Type,
STR, // Strength ) : Instruction(
DEX, // Dexterity sign = sign
CON, // Constitution ) {
HEI, // Height enum class Type {
INT, // Intelligence BDC, // Damages bonus for melee
POW, // Power BDD, // Damages bonus for range
CHA, // Charisma STR, // Strength
DEX, // Dexterity
CON, // Constitution
HEI, // Height
INT, // Intelligence
POW, // Power
CHA, // Charisma
}
override fun toString(): String {
return "${sign.sign}${type}"
}
} }
class UnknownInstruction(payload: String) : RuntimeException( class UnknownInstruction(payload: String) : RuntimeException(
"Unknown instruction exception. Unable to parse the following payload:\"$payload\" into an instruction" "Unknown instruction exception. Unable to parse the following payload:\"$payload\" into an instruction"
) )
val Int.sign: String get() = if (this > 0) "+" else "-"
} }

View file

@ -36,7 +36,7 @@ class CharacterSheetJsonFactory(
CharacterSheetJsonV1.Skill( CharacterSheetJsonV1.Skill(
id = it.id, id = it.id,
label = it.label, label = it.label,
base = arithmeticParser.convertInstructionToString(it.base), base = it.base,
bonus = it.bonus, bonus = it.bonus,
level = it.level, level = it.level,
occupation = it.occupation, occupation = it.occupation,
@ -47,7 +47,7 @@ class CharacterSheetJsonFactory(
CharacterSheetJsonV1.Skill( CharacterSheetJsonV1.Skill(
id = it.id, id = it.id,
label = it.label, label = it.label,
base = arithmeticParser.convertInstructionToString(it.base), base = it.base,
bonus = it.bonus, bonus = it.bonus,
level = it.level, level = it.level,
occupation = it.occupation, occupation = it.occupation,
@ -58,7 +58,7 @@ class CharacterSheetJsonFactory(
CharacterSheetJsonV1.Skill( CharacterSheetJsonV1.Skill(
id = it.id, id = it.id,
label = it.label, label = it.label,
base = arithmeticParser.convertInstructionToString(it.base), base = it.base,
bonus = it.bonus, bonus = it.bonus,
level = it.level, level = it.level,
occupation = it.occupation, occupation = it.occupation,
@ -69,7 +69,7 @@ class CharacterSheetJsonFactory(
CharacterSheetJsonV1.Roll( CharacterSheetJsonV1.Roll(
id = it.id, id = it.id,
label = it.label, label = it.label,
roll = arithmeticParser.convertInstructionToString(it.roll), roll = it.roll,
) )
}, },
) )
@ -117,7 +117,7 @@ class CharacterSheetJsonFactory(
CharacterSheet.Skill( CharacterSheet.Skill(
id = it.id, id = it.id,
label = it.label, label = it.label,
base = arithmeticParser.parse(it.base), base = it.base,
bonus = it.bonus, bonus = it.bonus,
level = it.level, level = it.level,
occupation = it.occupation, occupation = it.occupation,
@ -128,7 +128,7 @@ class CharacterSheetJsonFactory(
CharacterSheet.Skill( CharacterSheet.Skill(
id = it.id, id = it.id,
label = it.label, label = it.label,
base = arithmeticParser.parse(it.base), base = it.base,
bonus = it.bonus, bonus = it.bonus,
level = it.level, level = it.level,
occupation = it.occupation, occupation = it.occupation,
@ -139,7 +139,7 @@ class CharacterSheetJsonFactory(
CharacterSheet.Skill( CharacterSheet.Skill(
id = it.id, id = it.id,
label = it.label, label = it.label,
base = arithmeticParser.parse(it.base), base = it.base,
bonus = it.bonus, bonus = it.bonus,
level = it.level, level = it.level,
occupation = it.occupation, occupation = it.occupation,
@ -150,7 +150,7 @@ class CharacterSheetJsonFactory(
CharacterSheet.Roll( CharacterSheet.Roll(
id = it.id, id = it.id,
label = it.label, label = it.label,
roll = arithmeticParser.parse(it.roll), roll = it.roll,
) )
}, },
) )

View file

@ -1,7 +1,5 @@
package com.pixelized.desktop.lwa.repository.characterSheet.model package com.pixelized.desktop.lwa.repository.characterSheet.model
import com.pixelized.desktop.lwa.parser.arithmetic.Arithmetic
data class CharacterSheet( data class CharacterSheet(
val id: String, val id: String,
val name: String, val name: String,
@ -36,7 +34,7 @@ data class CharacterSheet(
data class Skill( data class Skill(
val id: String, val id: String,
val label: String, val label: String,
val base: List<Arithmetic>, val base: String,
val bonus: Int, val bonus: Int,
val level: Int, val level: Int,
val occupation: Boolean, val occupation: Boolean,
@ -46,7 +44,7 @@ data class CharacterSheet(
data class Roll( data class Roll(
val id: String, val id: String,
val label: String, val label: String,
val roll: List<Arithmetic>, val roll: String,
) )
object CommonSkillId { object CommonSkillId {

View file

@ -2,6 +2,7 @@ package com.pixelized.desktop.lwa.screen.characterSheet.detail
import com.pixelized.desktop.lwa.business.SkillValueComputationUseCase import com.pixelized.desktop.lwa.business.SkillValueComputationUseCase
import com.pixelized.desktop.lwa.composable.tooltip.TooltipUio import com.pixelized.desktop.lwa.composable.tooltip.TooltipUio
import com.pixelized.desktop.lwa.parser.arithmetic.ArithmeticParser
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet.CommonSkillId import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet.CommonSkillId
import com.pixelized.desktop.lwa.screen.characterSheet.detail.CharacterSheetPageUio.Characteristic import com.pixelized.desktop.lwa.screen.characterSheet.detail.CharacterSheetPageUio.Characteristic
@ -51,6 +52,7 @@ import org.jetbrains.compose.resources.getString
class CharacterSheetFactory( class CharacterSheetFactory(
private val skillUseCase: SkillValueComputationUseCase, private val skillUseCase: SkillValueComputationUseCase,
private val arithmeticParser: ArithmeticParser,
) { ) {
companion object { companion object {
@ -251,7 +253,7 @@ class CharacterSheetFactory(
if (it.roll.isNotEmpty()) { if (it.roll.isNotEmpty()) {
CharacterSheetPageUio.Roll( CharacterSheetPageUio.Roll(
label = it.label, label = it.label,
value = "TODO",//it.roll, value = it.roll,
) )
} else { } else {
null null

View file

@ -4,9 +4,7 @@ import androidx.compose.runtime.State
import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.derivedStateOf
import com.pixelized.desktop.lwa.business.DamageBonusUseCase import com.pixelized.desktop.lwa.business.DamageBonusUseCase
import com.pixelized.desktop.lwa.business.SkillNormalizerUseCase.normalize import com.pixelized.desktop.lwa.business.SkillNormalizerUseCase.normalize
import com.pixelized.desktop.lwa.parser.arithmetic.Arithmetic
import com.pixelized.desktop.lwa.parser.arithmetic.ArithmeticParser import com.pixelized.desktop.lwa.parser.arithmetic.ArithmeticParser
import com.pixelized.desktop.lwa.parser.arithmetic.Instruction
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet
import com.pixelized.desktop.lwa.screen.characterSheet.common.SkillFieldFactory import com.pixelized.desktop.lwa.screen.characterSheet.common.SkillFieldFactory
import com.pixelized.desktop.lwa.screen.characterSheet.common.occupation import com.pixelized.desktop.lwa.screen.characterSheet.common.occupation
@ -94,12 +92,7 @@ class CharacterSheetEditFactory(
CharacterSheet.Skill( CharacterSheet.Skill(
id = editedSkill.id, id = editedSkill.id,
label = editedSkill.label, label = editedSkill.label,
base = listOf( base = "${editedSkill.base}",
Arithmetic(
sign = 1,
instruction = Instruction.Flat(editedSkill.base.value)
)
),
bonus = editedSkill.bonus.value.value.toIntOrNull() ?: 0, bonus = editedSkill.bonus.value.value.toIntOrNull() ?: 0,
level = editedSkill.level.value.value.toIntOrNull() ?: 0, level = editedSkill.level.value.value.toIntOrNull() ?: 0,
occupation = editedSkill.option.checked.value, occupation = editedSkill.option.checked.value,
@ -113,7 +106,7 @@ class CharacterSheetEditFactory(
CharacterSheet.Skill( CharacterSheet.Skill(
id = editedSkill.id, id = editedSkill.id,
label = editedSkill.label.value.value, label = editedSkill.label.value.value,
base = parser.parse(editedSkill.base.value.value), base = editedSkill.base.value.value,
bonus = editedSkill.bonus.value.value.toIntOrNull() ?: 0, bonus = editedSkill.bonus.value.value.toIntOrNull() ?: 0,
level = editedSkill.level.value.value.toIntOrNull() ?: 0, level = editedSkill.level.value.value.toIntOrNull() ?: 0,
occupation = editedSkill.options.occupation, occupation = editedSkill.options.occupation,
@ -127,7 +120,7 @@ class CharacterSheetEditFactory(
CharacterSheet.Skill( CharacterSheet.Skill(
id = editedSkill.id, id = editedSkill.id,
label = editedSkill.label.value.value, label = editedSkill.label.value.value,
base = parser.parse(editedSkill.base.value.value), base = editedSkill.base.value.value,
bonus = editedSkill.bonus.value.value.toIntOrNull() ?: 0, bonus = editedSkill.bonus.value.value.toIntOrNull() ?: 0,
level = editedSkill.level.value.value.toIntOrNull() ?: 0, level = editedSkill.level.value.value.toIntOrNull() ?: 0,
occupation = editedSkill.options.occupation, occupation = editedSkill.options.occupation,
@ -138,7 +131,7 @@ class CharacterSheetEditFactory(
CharacterSheet.Roll( CharacterSheet.Roll(
id = "", // TODO id = "", // TODO
label = it.label.value, label = it.label.value,
roll = parser.parse(value = it.unpack()), roll = it.unpack(),
) )
}, },
) )
@ -345,7 +338,7 @@ class CharacterSheetEditFactory(
id = skill.id, id = skill.id,
label = specialSkillsLabel, label = specialSkillsLabel,
labelValue = skill.label, labelValue = skill.label,
baseValue = parser.convertInstructionToString(instructions = skill.base), baseValue = skill.base,
bonusValue = skill.bonus.takeIf { it > 0 }?.toString() ?: "", bonusValue = skill.bonus.takeIf { it > 0 }?.toString() ?: "",
levelValue = skill.level.takeIf { it > 0 }?.toString() ?: "", levelValue = skill.level.takeIf { it > 0 }?.toString() ?: "",
options = run { options = run {
@ -362,7 +355,7 @@ class CharacterSheetEditFactory(
id = skill.id, id = skill.id,
label = magicSkillsLabel, label = magicSkillsLabel,
labelValue = skill.label, labelValue = skill.label,
baseValue = parser.convertInstructionToString(instructions = skill.base), baseValue = skill.base,
bonusValue = skill.bonus.takeIf { it > 0 }?.toString() ?: "", bonusValue = skill.bonus.takeIf { it > 0 }?.toString() ?: "",
levelValue = skill.level.takeIf { it > 0 }?.toString() ?: "", levelValue = skill.level.takeIf { it > 0 }?.toString() ?: "",
options = run { options = run {

View file

@ -3,14 +3,13 @@ package com.pixelized.desktop.lwa.screen.roll
import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.Spring import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween
import androidx.compose.runtime.State import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import com.pixelized.desktop.lwa.business.RollUseCase
import com.pixelized.desktop.lwa.business.SkillStepUseCase import com.pixelized.desktop.lwa.business.SkillStepUseCase
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet import com.pixelized.desktop.lwa.business.SkillValueComputationUseCase
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet
import com.pixelized.desktop.lwa.repository.roll.RollHistoryRepository import com.pixelized.desktop.lwa.repository.roll.RollHistoryRepository
import com.pixelized.desktop.lwa.screen.characterSheet.detail.CharacterSheetPageUio import com.pixelized.desktop.lwa.screen.characterSheet.detail.CharacterSheetPageUio
import com.pixelized.desktop.lwa.screen.roll.DifficultyUio.Difficulty import com.pixelized.desktop.lwa.screen.roll.DifficultyUio.Difficulty
@ -34,6 +33,7 @@ import org.jetbrains.compose.resources.getString
class RollViewModel( class RollViewModel(
private val characterSheetRepository: CharacterSheetRepository, private val characterSheetRepository: CharacterSheetRepository,
private val rollHistoryRepository: RollHistoryRepository, private val rollHistoryRepository: RollHistoryRepository,
private val skillComputation: SkillValueComputationUseCase,
) : ViewModel() { ) : ViewModel() {
private lateinit var sheet: CharacterSheet private lateinit var sheet: CharacterSheet
@ -168,11 +168,12 @@ class RollViewModel(
} }
) )
} }
val roll = if (rollAction == "1d100") {
RollUseCase.rollD100() val roll = skillComputation.computeRoll(
} else { sheet = sheet,
RollUseCase.roll(characterSheet = sheet, roll = rollAction) roll = rollAction,
} )
val success = rollStep?.let { val success = rollStep?.let {
when (roll) { when (roll) {
in it.criticalSuccess -> getString(resource = Res.string.roll_page__critical_success) in it.criticalSuccess -> getString(resource = Res.string.roll_page__critical_success)

View file

@ -1,12 +1,11 @@
package com.pixelized.desktop.lwa.parser package com.pixelized.desktop.lwa.parser
import com.pixelized.desktop.lwa.parser.arithmetic.Arithmetic
import com.pixelized.desktop.lwa.parser.arithmetic.ArithmeticParser
import com.pixelized.desktop.lwa.parser.arithmetic.Instruction import com.pixelized.desktop.lwa.parser.arithmetic.Instruction
import com.pixelized.desktop.lwa.parser.arithmetic.ArithmeticParser
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertFails import kotlin.test.assertFails
class ArithmeticParserTest { class InstructionParserTest {
@Test @Test
fun testDiceInstructionParse() { fun testDiceInstructionParse() {
@ -14,16 +13,16 @@ class ArithmeticParserTest {
fun test( fun test(
instruction: String, instruction: String,
expectedModifier: Instruction.Dice.Modifier?, expectedModifier: Instruction.Dice.Modifier.Dice.Modifier?,
expectedQuantity: Int, expectedQuantity: Int,
expectedFaces: Int, expectedFaces: Int,
) { ) {
val dice = parser.parseInstruction(instruction = instruction) val dice = parser.parseInstruction(instruction = instruction)
assert(dice is Instruction.Dice) { assert(dice is Instruction.Dice.Dice) {
"Instruction should be ArithmeticInstruction.Dice but was: ${dice::class.java.simpleName}" "Instruction should be ArithmeticInstruction.Dice but was: ${dice::class.java.simpleName}"
} }
(dice as? Instruction.Dice)?.let { (dice as? Instruction.Dice.Dice)?.let {
assert(dice.modifier == expectedModifier) { assert(dice.modifier == expectedModifier) {
"$instruction modifier should be:\"$expectedModifier\", but was: ${dice.modifier}" "$instruction modifier should be:\"$expectedModifier\", but was: ${dice.modifier}"
} }
@ -69,10 +68,10 @@ class ArithmeticParserTest {
ArithmeticParser.words.map { instruction -> ArithmeticParser.words.map { instruction ->
val word = parser.parseInstruction(instruction = instruction) val word = parser.parseInstruction(instruction = instruction)
assert(word is Instruction.Word) { assert(word is Instruction.Word.Word) {
"Instruction should be ArithmeticInstruction.Word but was: ${word::class.java.simpleName}" "Instruction should be ArithmeticInstruction.Word but was: ${word::class.java.simpleName}"
} }
(word as? Instruction.Word)?.let { (word as? Instruction.Word.Word)?.let {
assert(it.name == instruction) { assert(it.name == instruction) {
"Instruction should be $instruction, but was ${it.name}" "Instruction should be $instruction, but was ${it.name}"
} }
@ -87,10 +86,10 @@ class ArithmeticParserTest {
"100".let { instruction -> "100".let { instruction ->
val flat = parser.parseInstruction(instruction = instruction) val flat = parser.parseInstruction(instruction = instruction)
assert(flat is Instruction.Flat) { assert(flat is Instruction.Flat.Flat) {
"Instruction should be ArithmeticInstruction.Flat but was: ${flat::class.java.simpleName}" "Instruction should be ArithmeticInstruction.Flat but was: ${flat::class.java.simpleName}"
} }
(flat as? Instruction.Flat)?.let { (flat as? Instruction.Flat.Flat)?.let {
assert("${it.value}" == instruction) { assert("${it.value}" == instruction) {
"Instruction should be $instruction, but was ${it.value}" "Instruction should be $instruction, but was ${it.value}"
} }
@ -113,7 +112,7 @@ class ArithmeticParserTest {
val parser = ArithmeticParser() val parser = ArithmeticParser()
fun test( fun test(
arithmetics: Arithmetic, arithmetics: Instruction,
expectedSign: Int, expectedSign: Int,
expectedInstruction: Instruction, expectedInstruction: Instruction,
) { ) {