Allow negative value into the character sheet bonuses.

This commit is contained in:
Thomas Andres Gomez 2024-11-27 15:39:22 +01:00
parent 8d93d46cce
commit d93ffd9499
8 changed files with 154 additions and 45 deletions

View file

@ -63,6 +63,8 @@
<string name="character_sheet_edit__skills__aid">Premiers soins</string>
<string name="character_sheet_edit__occupation__title">Occupations</string>
<string name="character_sheet_edit__occupation__add_action">Ajouter une occupation</string>
<string name="character_sheet_edit__actions__name_label">Nom</string>
<string name="character_sheet_edit__actions__action_label">Bonus</string>
<string name="character_sheet_edit__magic__title">Compétences magiques</string>
<string name="character_sheet_edit__magic__add_action">Ajouter une compétence magique</string>
<string name="character_sheet_edit__delete__label">Supprimer</string>

View file

@ -43,7 +43,7 @@ class SkillValueComputationUseCase(
baseSum
}
return max(base + skill.bonus + skill.level - diminished, 0)
return max(base + (skill.bonus ?: 0) + (skill.level ?: 0) - diminished, 0)
}
fun computeRoll(
@ -83,8 +83,8 @@ class SkillValueComputationUseCase(
if (damageBonusInstructions is Instruction.Dice) {
RollUseCase.roll(
quantity = damageBonusInstructions.quantity,
faces = damageBonusInstructions.faces
) / 2
faces = damageBonusInstructions.faces / 2,
)
} else {
0
}

View file

@ -35,8 +35,8 @@ data class CharacterSheet(
val id: String,
val label: String,
val base: String,
val bonus: Int,
val level: Int,
val bonus: Int?,
val level: Int?,
val occupation: Boolean,
val used: Boolean,
)

View file

@ -36,8 +36,8 @@ data class CharacterSheetJsonV1(
val id: String,
val label: String,
val base: String,
val bonus: Int,
val level: Int,
val bonus: Int?,
val level: Int?,
val occupation: Boolean,
val used: Boolean,
)

View file

@ -4,13 +4,15 @@ import androidx.compose.runtime.State
import androidx.compose.runtime.derivedStateOf
import com.pixelized.desktop.lwa.business.DamageBonusUseCase
import com.pixelized.desktop.lwa.business.SkillNormalizerUseCase.normalize
import com.pixelized.desktop.lwa.parser.arithmetic.ArithmeticParser
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.occupation
import com.pixelized.desktop.lwa.screen.characterSheet.edit.composable.ActionFieldUio
import com.pixelized.desktop.lwa.screen.characterSheet.edit.composable.BaseSkillFieldUio
import com.pixelized.desktop.lwa.screen.characterSheet.edit.composable.FieldUio
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__action_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__name_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__cha
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__con
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__dex
@ -53,7 +55,6 @@ import kotlin.math.min
class CharacterSheetEditFactory(
private val bonusDamageUseCase: DamageBonusUseCase,
private val skillFactory: SkillFieldFactory,
private val parser: ArithmeticParser,
) {
fun updateCharacterSheet(
currentSheet: CharacterSheet?,
@ -92,9 +93,9 @@ class CharacterSheetEditFactory(
CharacterSheet.Skill(
id = editedSkill.id,
label = editedSkill.label,
base = "${editedSkill.base}",
bonus = editedSkill.bonus.value.value.toIntOrNull() ?: 0,
level = editedSkill.level.value.value.toIntOrNull() ?: 0,
base = "${editedSkill.base.value}",
bonus = editedSkill.bonus.value.value.toIntOrNull(),
level = editedSkill.level.value.value.toIntOrNull(),
occupation = editedSkill.option.checked.value,
used = currentSkill?.used ?: false,
)
@ -107,8 +108,8 @@ class CharacterSheetEditFactory(
id = editedSkill.id,
label = editedSkill.label.value.value,
base = editedSkill.base.value.value,
bonus = editedSkill.bonus.value.value.toIntOrNull() ?: 0,
level = editedSkill.level.value.value.toIntOrNull() ?: 0,
bonus = editedSkill.bonus.value.value.toIntOrNull(),
level = editedSkill.level.value.value.toIntOrNull(),
occupation = editedSkill.options.occupation,
used = currentSkill?.used ?: false,
)
@ -121,17 +122,17 @@ class CharacterSheetEditFactory(
id = editedSkill.id,
label = editedSkill.label.value.value,
base = editedSkill.base.value.value,
bonus = editedSkill.bonus.value.value.toIntOrNull() ?: 0,
level = editedSkill.level.value.value.toIntOrNull() ?: 0,
bonus = editedSkill.bonus.value.value.toIntOrNull(),
level = editedSkill.level.value.value.toIntOrNull(),
occupation = editedSkill.options.occupation,
used = currentSkill?.used ?: false,
)
},
actions = editedSheet.actions.map {
CharacterSheet.Roll(
id = "", // TODO
label = it.label.value,
roll = it.unpack(),
id = it.id,
label = it.label.value.value,
roll = it.action.value.value,
)
},
)
@ -139,7 +140,7 @@ class CharacterSheetEditFactory(
suspend fun convertToUio(
sheet: CharacterSheet?,
onDeleteSkill: (skillId: String) -> Unit,
onDeleteSkill: (id: String) -> Unit,
): CharacterSheetEditPageUio {
val str = FieldUio.create(
initialLabel = getString(Res.string.character_sheet_edit__characteristics__str),
@ -149,27 +150,27 @@ class CharacterSheetEditFactory(
val dex = FieldUio.create(
initialLabel = getString(Res.string.character_sheet_edit__characteristics__dex),
initialValue = sheet?.dexterity?.toString() ?: "",
valuePlaceHolder = { "11" }
valuePlaceHolder = { "10" }
)
val con = FieldUio.create(
initialLabel = getString(Res.string.character_sheet_edit__characteristics__con),
initialValue = sheet?.constitution?.toString() ?: "",
valuePlaceHolder = { "15" }
valuePlaceHolder = { "10" }
)
val hei = FieldUio.create(
initialLabel = getString(Res.string.character_sheet_edit__characteristics__hei),
initialValue = sheet?.height?.toString() ?: "",
valuePlaceHolder = { "13" }
valuePlaceHolder = { "10" }
)
val int = FieldUio.create(
initialLabel = getString(Res.string.character_sheet_edit__characteristics__int),
initialValue = sheet?.intelligence?.toString() ?: "",
valuePlaceHolder = { "9" }
valuePlaceHolder = { "10" }
)
val pow = FieldUio.create(
initialLabel = getString(Res.string.character_sheet_edit__characteristics__pow),
initialValue = sheet?.power?.toString() ?: "",
valuePlaceHolder = { "15" }
valuePlaceHolder = { "10" }
)
val cha = FieldUio.create(
initialLabel = getString(Res.string.character_sheet_edit__characteristics__cha),
@ -339,8 +340,8 @@ class CharacterSheetEditFactory(
label = specialSkillsLabel,
labelValue = skill.label,
baseValue = skill.base,
bonusValue = skill.bonus.takeIf { it > 0 }?.toString() ?: "",
levelValue = skill.level.takeIf { it > 0 }?.toString() ?: "",
bonusValue = skill.bonus?.toString() ?: "",
levelValue = skill.level?.toString() ?: "",
options = run {
val current = sheet.specialSkills.firstOrNull { it.id == skill.id }
listOf(
@ -356,8 +357,8 @@ class CharacterSheetEditFactory(
label = magicSkillsLabel,
labelValue = skill.label,
baseValue = skill.base,
bonusValue = skill.bonus.takeIf { it > 0 }?.toString() ?: "",
levelValue = skill.level.takeIf { it > 0 }?.toString() ?: "",
bonusValue = skill.bonus?.toString() ?: "",
levelValue = skill.level?.toString() ?: "",
options = run {
val current = sheet.magicSkills.firstOrNull { it.id == skill.id }
listOf(
@ -367,7 +368,20 @@ class CharacterSheetEditFactory(
},
)
} ?: emptyList(),
actions = emptyList(),
actions = sheet?.actions?.map { action ->
ActionFieldUio(
id = action.id,
label = skillFactory.createWrapper(
label = getString(Res.string.character_sheet_edit__actions__name_label),
value = action.label,
),
action = skillFactory.createWrapper(
label = getString(Res.string.character_sheet_edit__actions__action_label),
value = action.roll,
),
option = skillFactory.deleteOption { onDeleteSkill(action.id) },
)
} ?: emptyList(),
)
}
@ -385,17 +399,16 @@ class CharacterSheetEditFactory(
base = base,
bonus = skillFactory.createWrapper(
label = getString(Res.string.character_sheet_edit__skills__bonus_label),
value = skill?.bonus?.takeIf { it > 0 }?.toString() ?: "",
value = skill?.bonus?.toString() ?: "",
),
level = skillFactory.createWrapper(
label = getString(Res.string.character_sheet_edit__skills__level_label),
value = skill?.level?.takeIf { it > 0 }?.toString() ?: "",
value = skill?.level?.toString() ?: "",
),
option = skillFactory.occupationOption(skill?.occupation ?: false),
)
}
private inline fun <reified T> FieldUio.unpack(): T {
val tmp = value.value.ifBlank { valuePlaceHolder.value }
return when (T::class) {

View file

@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Icon
@ -32,6 +33,8 @@ import com.pixelized.desktop.lwa.LocalWindowController
import com.pixelized.desktop.lwa.composable.decoratedBox.DecoratedBox
import com.pixelized.desktop.lwa.navigation.screen.LocalScreenController
import com.pixelized.desktop.lwa.navigation.window.LocalWindow
import com.pixelized.desktop.lwa.screen.characterSheet.edit.composable.ActionField
import com.pixelized.desktop.lwa.screen.characterSheet.edit.composable.ActionFieldUio
import com.pixelized.desktop.lwa.screen.characterSheet.edit.composable.BaseSkillFieldUio
import com.pixelized.desktop.lwa.screen.characterSheet.edit.composable.BaseSkillForm
import com.pixelized.desktop.lwa.screen.characterSheet.edit.composable.FieldUio
@ -74,7 +77,7 @@ data class CharacterSheetEditPageUio(
val commonSkills: List<BaseSkillFieldUio>,
val specialSkills: List<SkillFieldUio>,
val magicSkills: List<SkillFieldUio>,
val actions: List<FieldUio>,
val actions: List<ActionFieldUio>,
) {
val characteristics
get() = listOf(
@ -340,12 +343,15 @@ fun CharacterSheetEdit(
}
}
form.actions.forEach {
Form(
modifier = Modifier.fillMaxWidth(),
valueWidth = 120.dp,
field = it,
)
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
form.actions.forEach {
ActionField(
modifier = Modifier.fillMaxWidth().padding(end = (4 + 2).dp),
action = it
)
}
}
Row(

View file

@ -7,9 +7,11 @@ import androidx.lifecycle.ViewModel
import com.pixelized.desktop.lwa.navigation.screen.destination.CharacterSheetEditDestination
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
import com.pixelized.desktop.lwa.screen.characterSheet.common.SkillFieldFactory
import com.pixelized.desktop.lwa.screen.characterSheet.edit.composable.FieldUio
import com.pixelized.desktop.lwa.screen.characterSheet.edit.composable.ActionFieldUio
import kotlinx.coroutines.runBlocking
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__action_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__name_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__magic_title
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__special_title
import org.jetbrains.compose.resources.getString
@ -73,10 +75,16 @@ class CharacterSheetEditViewModel(
}
suspend fun onNewAction() {
val field = FieldUio.create(
initialLabel = "",
isLabelEditable = true,
valuePlaceHolder = { "" },
val id = UUID.randomUUID().toString()
val field = ActionFieldUio(
id = id,
label = skillFactory.createWrapper(
label = getString(Res.string.character_sheet_edit__actions__name_label),
),
action = skillFactory.createWrapper(
label = getString(Res.string.character_sheet_edit__actions__action_label),
),
option = skillFactory.deleteOption { deleteSkill(id) },
)
val actions = _characterSheet.value.actions.toMutableList().also {
it.add(field)
@ -94,6 +102,9 @@ class CharacterSheetEditViewModel(
magicSkills = _characterSheet.value.magicSkills.toMutableList().also { skills ->
skills.removeIf { it.id == skillId }
},
actions = _characterSheet.value.actions.toMutableList().also { actions ->
actions.removeIf { it.id == skillId }
}
)
}

View file

@ -0,0 +1,77 @@
package com.pixelized.desktop.lwa.screen.characterSheet.edit.composable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.width
import androidx.compose.material.DropdownMenu
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.pixelized.desktop.lwa.screen.characterSheet.edit.composable.option.ActionOption
import com.pixelized.desktop.lwa.screen.characterSheet.edit.composable.option.DropDownActionMenuItem
import com.pixelized.desktop.lwa.screen.characterSheet.edit.composable.textfield.TextFieldWrapper
import com.pixelized.desktop.lwa.screen.characterSheet.edit.composable.textfield.TextFieldWrapperUio
@Stable
data class ActionFieldUio(
val id: String,
val label: TextFieldWrapperUio,
val action: TextFieldWrapperUio,
val option: ActionOption.DeleteOptionUio,
)
@Composable
fun ActionField(
modifier: Modifier = Modifier,
action: ActionFieldUio,
) {
val showMenu = remember { mutableStateOf(false) }
Row(
modifier = modifier,
horizontalArrangement = Arrangement.spacedBy(space = 4.dp, alignment = Alignment.End),
verticalAlignment = Alignment.CenterVertically,
) {
TextFieldWrapper(
modifier = Modifier.weight(weight = 1f),
wrapper = action.label,
)
TextFieldWrapper(
modifier = Modifier.width(width = (192+4).dp),
wrapper = action.action,
)
Box {
IconButton(
onClick = { showMenu.value = showMenu.value.not() },
) {
Icon(
imageVector = Icons.Default.MoreVert,
tint = MaterialTheme.colors.primary,
contentDescription = null,
)
}
DropdownMenu(
expanded = showMenu.value,
onDismissRequest = { showMenu.value = false }
) {
DropDownActionMenuItem(
wrapper = action.option,
onClick = {
showMenu.value = false
action.option.onOption()
}
)
}
}
}
}