Add support for Hp grow bonus and Leaning bonus.

This commit is contained in:
Thomas Andres Gomez 2024-11-30 18:05:55 +01:00
parent 3419afbe59
commit ca20078ffa
18 changed files with 526 additions and 402 deletions

View file

@ -1,8 +1,7 @@
package com.pixelized.desktop.lwa
import com.pixelized.desktop.lwa.business.DamageBonusUseCase
import com.pixelized.desktop.lwa.business.CharacterSheetUseCase
import com.pixelized.desktop.lwa.business.RollUseCase
import com.pixelized.desktop.lwa.business.SkillNormalizerUseCase
import com.pixelized.desktop.lwa.business.SkillStepUseCase
import com.pixelized.desktop.lwa.business.SkillValueComputationUseCase
import com.pixelized.desktop.lwa.parser.arithmetic.ArithmeticParser
@ -71,9 +70,8 @@ val parserDependencies
val useCaseDependencies
get() = module {
factoryOf(::DamageBonusUseCase)
factoryOf(::SkillStepUseCase)
factoryOf(::SkillNormalizerUseCase)
factoryOf(::RollUseCase)
factoryOf(::SkillValueComputationUseCase)
factoryOf(::CharacterSheetUseCase)
}

View file

@ -0,0 +1,56 @@
package com.pixelized.desktop.lwa.business
import kotlin.math.ceil
import kotlin.math.max
class CharacterSheetUseCase {
fun normalize(value: Int): Int {
return value - value % 5 // (truncate(value.toFloat() / 5f) * 5f).toInt()
}
fun defaultMovement(): Int = 10
fun defaultMaxHp(
constitution: Int,
height: Int,
): Int {
return (ceil((constitution + height) / 2f).toInt())
}
fun defaultMaxPower(
power: Int,
): Int {
return power
}
fun defaultDamageBonus(
strength: Int,
height: Int,
): String {
return defaultDamageBonus(sum = strength + height)
}
fun defaultDamageBonus(
sum: Int,
): String {
return when {
sum < 12 -> "-1d6"
sum in 12..17 -> "-1d4"
sum in 18..22 -> "+0"
sum in 23..29 -> "+1d4"
sum in 30..39 -> "+1d6"
else -> "+2d6"
}
}
fun defaultArmor(): Int = 0
fun defaultLearning(intelligence: Int): Int {
return max(0, (intelligence - 10) * 2)
}
fun defaultHpGrow(constitution: Int): Int {
return (constitution / 3)
}
}

View file

@ -1,19 +0,0 @@
package com.pixelized.desktop.lwa.business
class DamageBonusUseCase {
fun bonusDamage(strength: Int, height: Int): String {
return bonusDamage(stat = strength + height)
}
fun bonusDamage(stat: Int): String {
return when {
stat < 12 -> "-1d6"
stat in 12..17 -> "-1d4"
stat in 18..22 -> "+0"
stat in 23..29 -> "+1d4"
stat in 30..39 -> "+1d6"
else -> "+2d6"
}
}
}

View file

@ -7,10 +7,6 @@ import kotlin.math.min
class RollUseCase {
fun rollD100(): Int {
return roll(modifier = null, quantity = 1, faces = 100)
}
fun roll(dice: Instruction.Dice): Int {
return roll(
modifier = dice.modifier,
@ -19,9 +15,13 @@ class RollUseCase {
)
}
fun roll(modifier: Instruction.Dice.Modifier?, quantity: Int, faces: Int): Int {
fun roll(
modifier: Instruction.Dice.Modifier? = null,
quantity: Int = 1,
faces: Int,
): Int {
print("{")
return sum(count = quantity) {
return sum(count = quantity) { left ->
when (modifier) {
Instruction.Dice.Modifier.ADVANTAGE -> {
val roll1 = roll(faces = faces)
@ -54,6 +54,8 @@ class RollUseCase {
null -> {
roll(faces = faces).also { print("$it") }
}
}.also {
if (quantity > 1 && left != 1) print(",")
}
}.also {
print("}:")
@ -61,14 +63,14 @@ class RollUseCase {
}
private fun roll(faces: Int): Int {
return (Math.random() * faces.toDouble() + 1).toInt()
return (Math.random() * faces.toDouble() + 1.0).toInt()
}
private fun sum(count: Int, block: () -> Int): Int {
private fun sum(count: Int, block: (Int) -> Int): Int {
return if (count > 1) {
block() + sum(count - 1, block)
block(count) + sum(count - 1, block)
} else {
block()
block(count)
}
}
}

View file

@ -1,9 +0,0 @@
package com.pixelized.desktop.lwa.business
import kotlin.math.truncate
class SkillNormalizerUseCase {
fun normalize(value: Int): Int {
return (truncate(value.toFloat() / 5f) * 5f).toInt()
}
}

View file

@ -1,16 +1,15 @@
package com.pixelized.desktop.lwa.parser.arithmetic
sealed class Instruction(
val sign: Int,
) {
class Dice(
sign: Int,
sealed class Instruction {
abstract val sign: Int
data class Dice(
override val sign: Int,
val modifier: Modifier?,
val quantity: Int,
val faces: Int,
) : Instruction(
sign = sign,
) {
) : Instruction() {
enum class Modifier {
ADVANTAGE,
DISADVANTAGE,
@ -29,23 +28,20 @@ sealed class Instruction(
}
}
class Flat(
sign: Int,
data class Flat(
override val sign: Int,
val value: Int,
) : Instruction(
sign = sign,
) {
) : Instruction() {
override fun toString(): String {
return "${sign.sign}${value}"
}
}
class Word(
sign: Int,
data class Word(
override val sign: Int,
val type: Type,
) : Instruction(
sign = sign
) {
) : Instruction() {
enum class Type {
BDC, // Damages bonus for melee
BDD, // Damages bonus for range

View file

@ -1,34 +1,13 @@
package com.pixelized.desktop.lwa.repository.characterSheet
import com.pixelized.desktop.lwa.business.DamageBonusUseCase
import com.pixelized.desktop.lwa.parser.arithmetic.ArithmeticParser
import com.pixelized.desktop.lwa.business.CharacterSheetUseCase
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheetJson
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheetJsonV1
import kotlinx.coroutines.runBlocking
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__acrobatics
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__aid
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__athletics
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__bargain
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__combat
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__discretion
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__dodge
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__empathy
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__grab
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__intimidation
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__perception
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__persuasion
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__search
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__sleight_of_hand
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__spiel
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__throw
import org.jetbrains.compose.resources.getString
import kotlin.math.ceil
class CharacterSheetJsonFactory(
private val bonusDamageUseCase: DamageBonusUseCase,
private val skillDescriptionFactory: SkillDescriptionFactory,
private val characterSheetUseCase: CharacterSheetUseCase,
) {
fun convertToJson(
@ -51,6 +30,8 @@ class CharacterSheetJsonFactory(
maxPP = if (sheet.overrideMaxPP) sheet.maxPp else null,
damageBonus = if (sheet.overrideDamageBonus) sheet.damageBonus else null,
armor = if (sheet.overrideArmor) sheet.armor else null,
learning = if (sheet.overrideLearning) sheet.learning else null,
hpGrowf = if (sheet.overrideHpGrow) sheet.hpGrow else null,
skills = sheet.commonSkills.map {
CharacterSheetJsonV1.Skill(
id = it.id,
@ -108,8 +89,8 @@ class CharacterSheetJsonFactory(
private suspend fun convertFromV1(
json: CharacterSheetJsonV1,
): CharacterSheet {
val sheet = CharacterSheet(
): CharacterSheet = characterSheetUseCase.run {
CharacterSheet(
id = json.id,
name = json.name,
strength = json.strength,
@ -120,21 +101,27 @@ class CharacterSheetJsonFactory(
power = json.power,
charisma = json.charisma,
overrideMovement = json.movement != null,
movement = json.movement ?: 10,
movement = json.movement ?: defaultMovement(),
currentHp = json.currentHp,
overrideMaxHp = json.maxHp != null,
maxHp = json.maxHp ?: (ceil((json.constitution + json.height) / 2f).toInt()),
maxHp = json.maxHp ?: defaultMaxHp(
constitution = json.constitution,
height = json.height,
),
currentPp = json.currentPP,
overrideMaxPP = json.maxPP != null,
maxPp = json.maxPP ?: json.power,
maxPp = json.maxPP ?: defaultMaxPower(power = json.power),
overrideDamageBonus = json.damageBonus != null,
damageBonus = json.damageBonus
?: bonusDamageUseCase.bonusDamage(
strength = json.strength,
height = json.height
),
damageBonus = json.damageBonus ?: defaultDamageBonus(
strength = json.strength,
height = json.height,
),
overrideArmor = json.armor != null,
armor = json.armor ?: 0,
armor = json.armor ?: defaultArmor(),
overrideLearning = json.learning != null,
learning = json.learning ?: defaultLearning(intelligence = json.intelligence),
overrideHpGrow = json.hpGrowf != null,
hpGrow = json.hpGrowf ?: defaultHpGrow(constitution = json.constitution),
commonSkills = json.skills.map {
CharacterSheet.Skill(
id = it.id,
@ -179,6 +166,5 @@ class CharacterSheetJsonFactory(
)
},
)
return sheet
}
}

View file

@ -24,6 +24,10 @@ data class CharacterSheet(
val damageBonus: String,
val overrideArmor: Boolean,
val armor: Int,
val overrideLearning: Boolean,
val learning: Int,
val overrideHpGrow: Boolean,
val hpGrow: Int,
// skills
val commonSkills: List<Skill>,
val specialSkills: List<Skill>,
@ -80,5 +84,7 @@ data class CharacterSheet(
const val PP = "PP"
const val DMG = "DMG"
const val ARMOR = "ARMOR"
const val LB = "LEARNING"
const val GHP = "HP_GROW"
}
}

View file

@ -22,6 +22,8 @@ data class CharacterSheetJsonV1(
val maxPP: Int?,
val damageBonus: String?,
val armor: Int?,
val learning: Int?,
val hpGrowf: Int?,
// skills
val skills: List<Skill>,
// occupations

View file

@ -18,6 +18,8 @@ import lwacharactersheet.composeapp.generated.resources.character_sheet__charact
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__armor
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__damage_bonus
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__hit_point
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__hp_grow
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__learning
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__movement
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__power_point
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__charisma
@ -30,6 +32,8 @@ import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__armor
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__bonus_damage
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__hit_point
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__hp_grow
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__learning
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__movement
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__power_point
import org.jetbrains.compose.resources.getString
@ -171,6 +175,26 @@ class CharacterSheetFactory(
),
editable = false,
),
Characteristic(
id = CharacteristicId.LB,
label = getString(Res.string.character_sheet__sub_characteristics__learning),
value = "${sheet.learning}",
tooltips = TooltipUio(
title = getString(Res.string.character_sheet__sub_characteristics__learning),
description = getString(Res.string.tooltip__sub_characteristics__learning),
),
editable = false,
),
Characteristic(
id = CharacteristicId.GHP,
label = getString(Res.string.character_sheet__sub_characteristics__hp_grow),
value = "${sheet.hpGrow}",
tooltips = TooltipUio(
title = getString(Res.string.character_sheet__sub_characteristics__hp_grow),
description = getString(Res.string.tooltip__sub_characteristics__hp_grow),
),
editable = false,
),
),
commonSkills = sheet.commonSkills.map { skill ->
Node(

View file

@ -3,8 +3,7 @@ package com.pixelized.desktop.lwa.screen.characterSheet.edit
import androidx.compose.runtime.State
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.mutableStateOf
import com.pixelized.desktop.lwa.business.DamageBonusUseCase
import com.pixelized.desktop.lwa.business.SkillNormalizerUseCase
import com.pixelized.desktop.lwa.business.CharacterSheetUseCase
import com.pixelized.desktop.lwa.repository.characterSheet.SkillDescriptionFactory
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet
import com.pixelized.desktop.lwa.screen.characterSheet.edit.common.SkillFieldFactory
@ -45,27 +44,26 @@ import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__sk
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__throw
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__sub_characteristics__armor
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__sub_characteristics__damage_bonus
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__sub_characteristics__hit_point
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__sub_characteristics__hp_grow
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__sub_characteristics__learning
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__sub_characteristics__max_hit_point
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__sub_characteristics__max_power_point
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__sub_characteristics__movement
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__sub_characteristics__power_point
import org.jetbrains.compose.resources.getString
import java.util.UUID
import kotlin.math.ceil
import kotlin.math.max
import kotlin.math.min
class CharacterSheetEditFactory(
private val bonusDamageUseCase: DamageBonusUseCase,
private val characterSheetUseCase: CharacterSheetUseCase,
private val skillFieldFactory: SkillFieldFactory,
private val skillDescriptionFactory: SkillDescriptionFactory,
private val normalizer: SkillNormalizerUseCase,
) {
suspend fun updateCharacterSheet(
currentSheet: CharacterSheet?,
editedSheet: CharacterSheetEditPageUio,
): CharacterSheet {
val editedMaxHp = editedSheet.maxHp.unpack()?.toIntOrNull() ?: currentSheet?.maxHp ?: 0
val editedMaxPp = editedSheet.maxPp.unpack()?.toIntOrNull() ?: currentSheet?.maxPp ?: 0
return CharacterSheet(
id = editedSheet.id,
name = editedSheet.name.value.value,
@ -95,19 +93,11 @@ class CharacterSheetEditFactory(
?: currentSheet?.movement
?: 10,
overrideMaxHp = editedSheet.maxHp.value.value.value.isNotBlank(),
maxHp = editedSheet.maxHp.unpack()?.toIntOrNull()
?: currentSheet?.maxHp
?: 0,
currentHp = editedSheet.currentHp.unpack()?.toIntOrNull()
?: currentSheet?.currentHp
?: 0,
maxHp = editedMaxHp,
currentHp = currentSheet?.currentHp?.coerceAtMost(editedMaxHp) ?: editedMaxHp,
overrideMaxPP = editedSheet.maxPp.value.value.value.isNotBlank(),
maxPp = editedSheet.maxPp.unpack()?.toIntOrNull()
?: currentSheet?.maxPp
?: 0,
currentPp = editedSheet.currentPp.unpack()?.toIntOrNull()
?: currentSheet?.currentPp
?: 0,
maxPp = editedMaxPp,
currentPp = currentSheet?.currentPp?.coerceAtMost(editedMaxPp) ?: editedMaxPp,
overrideDamageBonus = editedSheet.damageBonus.value.value.value.isNotBlank(),
damageBonus = editedSheet.damageBonus.unpack()
?: currentSheet?.damageBonus
@ -116,6 +106,10 @@ class CharacterSheetEditFactory(
armor = editedSheet.armor.unpack()?.toIntOrNull()
?: currentSheet?.armor
?: 0,
overrideLearning = editedSheet.learning.value.value.value.isNotBlank(),
learning = editedSheet.learning.unpack()?.toIntOrNull() ?: 0,
overrideHpGrow = editedSheet.hpGrow.value.value.value.isNotBlank(),
hpGrow = editedSheet.hpGrow.unpack()?.toIntOrNull() ?: 0,
commonSkills = editedSheet.commonSkills.map { editedSkill ->
val currentSkill = currentSheet?.commonSkills?.firstOrNull {
it.id == editedSkill.id
@ -236,239 +230,243 @@ class CharacterSheetEditFactory(
val specialSkillsLabel = getString(Res.string.character_sheet_edit__skills__special_title)
val magicSkillsLabel = getString(Res.string.character_sheet_edit__skills__magic_title)
val maxHitPoint = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__sub_characteristics__max_hit_point),
value = skillFieldFactory.createWrapper(
value = if (sheet?.overrideMaxHp == true) "${sheet.maxHp}" else "",
placeholder = derivedStateOf { "${ceil((con() + hei()) / 2f).toInt()}" },
)
)
val maxPowerPoint = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__sub_characteristics__max_power_point),
value = skillFieldFactory.createWrapper(
value = if (sheet?.overrideMaxPP == true) "${sheet.maxPp}" else "",
placeholder = derivedStateOf { "${pow()}" },
)
)
return CharacterSheetEditPageUio(
id = sheet?.id ?: UUID.randomUUID().toString(),
name = skillFieldFactory.createWrapper(
label = mutableStateOf(getString(Res.string.character_sheet_edit__name_label)),
value = sheet?.name ?: ""
),
strength = str,
dexterity = dex,
constitution = con,
height = hei,
intelligence = int,
power = pow,
charisma = cha,
movement = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__sub_characteristics__movement),
value = skillFieldFactory.createWrapper(
value = if (sheet?.overrideMovement == true) "${sheet.movement}" else "",
placeholder = mutableStateOf("10"),
)
),
maxHp = maxHitPoint,
currentHp = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__sub_characteristics__hit_point),
value = skillFieldFactory.createWrapper(
enable = false,
placeholder = derivedStateOf {
val min = min(
sheet?.currentHp ?: Int.MAX_VALUE,
maxHitPoint.unpack()?.toIntOrNull() ?: Int.MAX_VALUE,
)
if (min != Int.MAX_VALUE) "$min" else ""
},
)
),
maxPp = maxPowerPoint,
currentPp = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__sub_characteristics__power_point),
value = skillFieldFactory.createWrapper(
enable = false,
placeholder = derivedStateOf {
val min = min(
sheet?.currentPp ?: Int.MAX_VALUE,
maxPowerPoint.unpack()?.toIntOrNull() ?: Int.MAX_VALUE,
)
if (min != Int.MAX_VALUE) "$min" else ""
},
)
),
damageBonus = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__sub_characteristics__damage_bonus),
value = skillFieldFactory.createWrapper(
value = if (sheet?.overrideDamageBonus == true) sheet.damageBonus else "",
placeholder = derivedStateOf {
bonusDamageUseCase.bonusDamage(
strength = str(),
height = hei()
)
},
)
),
armor = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__sub_characteristics__armor),
value = skillFieldFactory.createWrapper(
value = if (sheet?.overrideArmor == true) "${sheet.armor}" else "",
placeholder = mutableStateOf("0"),
)
),
commonSkills = listOf(
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.COMBAT_ID,
label = getString(Res.string.character_sheet_edit__skills__combat),
base = derivedStateOf { normalizer.normalize(dex() * 2) },
return with(characterSheetUseCase) {
CharacterSheetEditPageUio(
id = sheet?.id ?: UUID.randomUUID().toString(),
name = skillFieldFactory.createWrapper(
label = mutableStateOf(getString(Res.string.character_sheet_edit__name_label)),
value = sheet?.name ?: ""
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.DODGE_ID,
label = getString(Res.string.character_sheet_edit__skills__dodge),
base = derivedStateOf { normalizer.normalize(dex() * 2) },
strength = str,
dexterity = dex,
constitution = con,
height = hei,
intelligence = int,
power = pow,
charisma = cha,
movement = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__sub_characteristics__movement),
value = skillFieldFactory.createWrapper(
value = if (sheet?.overrideMovement == true) "${sheet.movement}" else "",
placeholder = derivedStateOf {
"${characterSheetUseCase.defaultMovement()}"
},
)
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.GRAB_ID,
label = getString(Res.string.character_sheet_edit__skills__grab),
base = derivedStateOf { normalizer.normalize(str() + hei()) },
maxHp = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__sub_characteristics__max_hit_point),
value = skillFieldFactory.createWrapper(
value = if (sheet?.overrideMaxHp == true) "${sheet.maxHp}" else "",
placeholder = derivedStateOf {
"${
characterSheetUseCase.defaultMaxHp(
constitution = con(),
height = hei()
)
}"
},
)
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.THROW_ID,
label = getString(Res.string.character_sheet_edit__skills__throw),
base = derivedStateOf { normalizer.normalize(str() + dex()) },
maxPp = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__sub_characteristics__max_power_point),
value = skillFieldFactory.createWrapper(
value = if (sheet?.overrideMaxPP == true) "${sheet.maxPp}" else "",
placeholder = derivedStateOf {
"${characterSheetUseCase.defaultMaxPower(power = pow())}"
},
)
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.ATHLETICS_ID,
label = getString(Res.string.character_sheet_edit__skills__athletics),
base = derivedStateOf { normalizer.normalize(str() + con() * 2) },
damageBonus = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__sub_characteristics__damage_bonus),
value = skillFieldFactory.createWrapper(
value = if (sheet?.overrideDamageBonus == true) sheet.damageBonus else "",
placeholder = derivedStateOf {
characterSheetUseCase.defaultDamageBonus(
strength = str(),
height = hei()
)
},
)
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.ACROBATICS_ID,
label = getString(Res.string.character_sheet_edit__skills__acrobatics),
base = derivedStateOf { normalizer.normalize(dex() + con() * 2) },
armor = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__sub_characteristics__armor),
value = skillFieldFactory.createWrapper(
value = if (sheet?.overrideArmor == true) "${sheet.armor}" else "",
placeholder = derivedStateOf {
"${characterSheetUseCase.defaultArmor()}"
},
)
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.PERCEPTION_ID,
label = getString(Res.string.character_sheet_edit__skills__perception),
base = derivedStateOf { normalizer.normalize(10 + int() * 2) },
learning = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__sub_characteristics__learning),
value = skillFieldFactory.createWrapper(
value = if (sheet?.overrideLearning == true) "${sheet.learning}" else "",
placeholder = derivedStateOf {
"${characterSheetUseCase.defaultLearning(intelligence = int())}"
},
)
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.SEARCH_ID,
label = getString(Res.string.character_sheet_edit__skills__search),
base = derivedStateOf { normalizer.normalize(10 + int() * 2) },
hpGrow = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__sub_characteristics__hp_grow),
value = skillFieldFactory.createWrapper(
value = if (sheet?.overrideHpGrow == true) "${sheet.hpGrow}" else "",
placeholder = derivedStateOf {
"${characterSheetUseCase.defaultHpGrow(constitution = con())}"
},
)
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.EMPATHY_ID,
label = getString(Res.string.character_sheet_edit__skills__empathy),
base = derivedStateOf { normalizer.normalize(cha() + int()) },
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.PERSUASION_ID,
label = getString(Res.string.character_sheet_edit__skills__persuasion),
base = derivedStateOf { normalizer.normalize(cha() * 3) },
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.INTIMIDATION_ID,
label = getString(Res.string.character_sheet_edit__skills__intimidation),
base = derivedStateOf { normalizer.normalize(cha() + max(pow(), hei()) * 2) },
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.SPIEL_ID,
label = getString(Res.string.character_sheet_edit__skills__spiel),
base = derivedStateOf { normalizer.normalize(cha() * 2 + int()) },
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.BARGAIN_ID,
label = getString(Res.string.character_sheet_edit__skills__bargain),
base = derivedStateOf { normalizer.normalize(cha() * 2) },
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.DISCRETION_ID,
label = getString(Res.string.character_sheet_edit__skills__discretion),
base = derivedStateOf { normalizer.normalize(cha() + dex() * 2 - hei()) },
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.SLEIGHT_OF_HAND_ID,
label = getString(Res.string.character_sheet_edit__skills__sleight_of_hand),
base = derivedStateOf { normalizer.normalize(dex() * 2) },
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.AID_ID,
label = getString(Res.string.character_sheet_edit__skills__aid),
base = derivedStateOf { normalizer.normalize(int() + dex()) },
),
),
specialSkills = sheet?.specialSkills?.map { skill ->
skillFieldFactory.createSkill(
id = skill.id,
label = specialSkillsLabel,
descriptionValue = skill.description ?: "",
labelValue = skill.label,
baseValue = skill.base,
bonusValue = skill.bonus ?: "",
levelValue = skill.level ?: "",
options = run {
val current = sheet.specialSkills.firstOrNull { it.id == skill.id }
listOf(
skillFieldFactory.occupationOption(checked = current?.occupation ?: false),
skillFieldFactory.deleteOption { onDeleteSkill(skill.id) },
)
},
)
} ?: emptyList(),
magicSkills = sheet?.magicSkills?.map { skill ->
skillFieldFactory.createSkill(
id = skill.id,
label = magicSkillsLabel,
descriptionValue = skill.description ?: "",
labelValue = skill.label,
baseValue = skill.base,
bonusValue = skill.bonus ?: "",
levelValue = skill.level ?: "",
options = run {
val current = sheet.magicSkills.firstOrNull { it.id == skill.id }
listOf(
skillFieldFactory.occupationOption(
checked = current?.occupation ?: false
),
skillFieldFactory.deleteOption { onDeleteSkill(skill.id) },
)
},
)
} ?: emptyList(),
actions = sheet?.actions?.map { action ->
ActionFieldUio(
id = action.id,
label = skillFieldFactory.createWrapper(
label = mutableStateOf(getString(Res.string.character_sheet_edit__actions__name_label)),
value = action.label,
commonSkills = listOf(
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.COMBAT_ID,
label = getString(Res.string.character_sheet_edit__skills__combat),
base = derivedStateOf { normalize(dex() * 2) },
),
action = skillFieldFactory.createWrapper(
label = mutableStateOf(getString(Res.string.character_sheet_edit__actions__action_label)),
value = action.roll,
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.DODGE_ID,
label = getString(Res.string.character_sheet_edit__skills__dodge),
base = derivedStateOf { normalize(dex() * 2) },
),
option = skillFieldFactory.deleteOption { onDeleteSkill(action.id) },
)
} ?: emptyList(),
)
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.GRAB_ID,
label = getString(Res.string.character_sheet_edit__skills__grab),
base = derivedStateOf { normalize(str() + hei()) },
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.THROW_ID,
label = getString(Res.string.character_sheet_edit__skills__throw),
base = derivedStateOf { normalize(str() + dex()) },
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.ATHLETICS_ID,
label = getString(Res.string.character_sheet_edit__skills__athletics),
base = derivedStateOf { normalize(str() + con() * 2) },
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.ACROBATICS_ID,
label = getString(Res.string.character_sheet_edit__skills__acrobatics),
base = derivedStateOf { normalize(dex() + con() * 2) },
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.PERCEPTION_ID,
label = getString(Res.string.character_sheet_edit__skills__perception),
base = derivedStateOf { normalize(10 + int() * 2) },
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.SEARCH_ID,
label = getString(Res.string.character_sheet_edit__skills__search),
base = derivedStateOf { normalize(10 + int() * 2) },
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.EMPATHY_ID,
label = getString(Res.string.character_sheet_edit__skills__empathy),
base = derivedStateOf { normalize(cha() + int()) },
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.PERSUASION_ID,
label = getString(Res.string.character_sheet_edit__skills__persuasion),
base = derivedStateOf { normalize(cha() * 3) },
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.INTIMIDATION_ID,
label = getString(Res.string.character_sheet_edit__skills__intimidation),
base = derivedStateOf { normalize(cha() + max(pow(), hei()) * 2) },
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.SPIEL_ID,
label = getString(Res.string.character_sheet_edit__skills__spiel),
base = derivedStateOf { normalize(cha() * 2 + int()) },
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.BARGAIN_ID,
label = getString(Res.string.character_sheet_edit__skills__bargain),
base = derivedStateOf { normalize(cha() * 2) },
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.DISCRETION_ID,
label = getString(Res.string.character_sheet_edit__skills__discretion),
base = derivedStateOf { normalize(cha() + dex() * 2 - hei()) },
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.SLEIGHT_OF_HAND_ID,
label = getString(Res.string.character_sheet_edit__skills__sleight_of_hand),
base = derivedStateOf { normalize(dex() * 2) },
),
createBaseSkill(
sheet = sheet,
id = CharacterSheet.CommonSkillId.AID_ID,
label = getString(Res.string.character_sheet_edit__skills__aid),
base = derivedStateOf { normalize(int() + dex()) },
),
),
specialSkills = sheet?.specialSkills?.map { skill ->
skillFieldFactory.createSkill(
id = skill.id,
label = specialSkillsLabel,
descriptionValue = skill.description ?: "",
labelValue = skill.label,
baseValue = skill.base,
bonusValue = skill.bonus ?: "",
levelValue = skill.level ?: "",
options = run {
val current = sheet.specialSkills.firstOrNull { it.id == skill.id }
listOf(
skillFieldFactory.occupationOption(current?.occupation ?: false),
skillFieldFactory.deleteOption { onDeleteSkill(skill.id) },
)
},
)
} ?: emptyList(),
magicSkills = sheet?.magicSkills?.map { skill ->
skillFieldFactory.createSkill(
id = skill.id,
label = magicSkillsLabel,
descriptionValue = skill.description ?: "",
labelValue = skill.label,
baseValue = skill.base,
bonusValue = skill.bonus ?: "",
levelValue = skill.level ?: "",
options = run {
val current = sheet.magicSkills.firstOrNull { it.id == skill.id }
listOf(
skillFieldFactory.occupationOption(
checked = current?.occupation ?: false
),
skillFieldFactory.deleteOption { onDeleteSkill(skill.id) },
)
},
)
} ?: emptyList(),
actions = sheet?.actions?.map { action ->
ActionFieldUio(
id = action.id,
label = skillFieldFactory.createWrapper(
label = mutableStateOf(getString(Res.string.character_sheet_edit__actions__name_label)),
value = action.label,
),
action = skillFieldFactory.createWrapper(
label = mutableStateOf(getString(Res.string.character_sheet_edit__actions__action_label)),
value = action.roll,
),
option = skillFieldFactory.deleteOption { onDeleteSkill(action.id) },
)
} ?: emptyList(),
)
}
}
private suspend fun createBaseSkill(

View file

@ -70,10 +70,10 @@ data class CharacterSheetEditPageUio(
val movement: SimpleFieldUio,
val maxHp: SimpleFieldUio,
val maxPp: SimpleFieldUio,
val currentHp: SimpleFieldUio,
val currentPp: SimpleFieldUio,
val damageBonus: SimpleFieldUio,
val armor: SimpleFieldUio,
val learning: SimpleFieldUio,
val hpGrow: SimpleFieldUio,
val commonSkills: List<BaseSkillFieldUio>,
val specialSkills: List<SkillFieldUio>,
val magicSkills: List<SkillFieldUio>,
@ -94,11 +94,11 @@ data class CharacterSheetEditPageUio(
get() = listOf(
movement,
maxHp,
currentHp,
maxPp,
currentPp,
damageBonus,
armor,
learning,
hpGrow,
)
}