Refactor the roll mechanism to allow broader instructions set.
This commit is contained in:
parent
d2ae180cf7
commit
8d93d46cce
10 changed files with 207 additions and 146 deletions
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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 "-"
|
||||||
}
|
}
|
||||||
|
|
@ -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,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
) {
|
) {
|
||||||
Loading…
Add table
Add a link
Reference in a new issue