diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/admin/character/edit/GMCharacterEditFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/admin/character/edit/GMCharacterEditFactory.kt index cc8fd92..8f9b10a 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/admin/character/edit/GMCharacterEditFactory.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/admin/character/edit/GMCharacterEditFactory.kt @@ -5,8 +5,13 @@ import com.pixelized.desktop.lwa.ui.composable.checkbox.LwaCheckBoxUio import com.pixelized.desktop.lwa.ui.composable.textfield.createLwaTextField import com.pixelized.desktop.lwa.ui.composable.textfield.createLwaTextFieldFlow import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.item.GMActionFieldUio +import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.item.GMCharacteristicFieldUio import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.item.GMSkillFieldUio import com.pixelized.desktop.lwa.ui.screen.admin.common.tag.GMTagFactory +import com.pixelized.desktop.lwa.utils.extention.constitution +import com.pixelized.desktop.lwa.utils.extention.dexterity +import com.pixelized.desktop.lwa.utils.extention.height +import com.pixelized.desktop.lwa.utils.extention.strength import com.pixelized.desktop.lwa.utils.extention.unpack import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CommonSkillId.ACROBATICS_ID @@ -109,6 +114,13 @@ import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__sk import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__throw_base import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__throw_description import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__throw_label +import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__charisma +import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__constitution +import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__dexterity +import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__height +import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__intelligence +import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__power +import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__strength import org.jetbrains.compose.resources.getString import java.util.UUID @@ -132,20 +144,17 @@ class GMCharacterEditFactory( level = form.level.unpack() ?: error("Missing character level"), shouldLevelUp = form.levelUp.checked.value, - strength = form.characteristics.strength.unpack() - ?: error("Missing character strength"), - dexterity = form.characteristics.dexterity.unpack() - ?: error("Missing character dexterity"), - constitution = form.characteristics.constitution.unpack() - ?: error("Missing character constitution"), - height = form.characteristics.height.unpack() - ?: error("Missing character height"), - intelligence = form.characteristics.intelligence.unpack() - ?: error("Missing character intelligence"), - power = form.characteristics.power.unpack() - ?: error("Missing character power"), - charisma = form.characteristics.charisma.unpack() - ?: error("Missing character charisma"), + characteristics = form.characteristics.map { characteristic -> + val characteristicId: String = characteristic.id.unpack() + ?: error("Missing characteristic id") + CharacterSheet.Characteristic( + id = characteristicId, + label = characteristic.label.unpack() ?: "", + description = characteristic.description.unpack() ?: "", + base = characteristic.base.unpack() ?: 0, + level = characteristic.level.unpack() ?: 0, + ) + }, alterations = sheet?.alterations ?: emptyList(), damage = sheet?.damage ?: 0, fatigue = sheet?.fatigue ?: 0, @@ -185,7 +194,6 @@ class GMCharacterEditFactory( magicSkills = form.magicSkills.map { editedSkill -> val skillId: String = editedSkill.id.unpack() ?: error("Missing skill id") - CharacterSheet.Skill( id = skillId, label = editedSkill.label.unpack() @@ -333,10 +341,18 @@ class GMCharacterEditFactory( actions = sheet?.actions?.map { createAction(action = it) } ?: emptyList()) } + private suspend fun createCharacteristic( + scope: CoroutineScope, + skill: CharacterSheet.Skill, + characteristics: List, + ): List { + + } + private suspend fun createCommonSkill( scope: CoroutineScope, skill: CharacterSheet.Skill, - characteristics: GMCharacterEditPageUio.CharacteristicsUio, + characteristics: List, ): GMSkillFieldUio { val baseLabel = getString(Res.string.character_sheet_edit__skills__base_label) val idFlow = createLwaTextFieldFlow( @@ -585,6 +601,23 @@ class GMCharacterEditFactory( } } + private suspend fun commonCharacteristicDescription( + skillId: String, + ): String? { + return when (skillId) { + CharacterSheet.CharacteristicId.STR -> Res.string.tooltip__characteristics__strength + CharacterSheet.CharacteristicId.CON -> Res.string.tooltip__characteristics__constitution + CharacterSheet.CharacteristicId.HEI -> Res.string.tooltip__characteristics__height + CharacterSheet.CharacteristicId.INT -> Res.string.tooltip__characteristics__intelligence + CharacterSheet.CharacteristicId.POW -> Res.string.tooltip__characteristics__power + CharacterSheet.CharacteristicId.DEX -> Res.string.tooltip__characteristics__dexterity + CharacterSheet.CharacteristicId.CHA -> Res.string.tooltip__characteristics__charisma + else -> null + }?.let { + getString(it) + } + } + private suspend fun commonSkillDescription( skillId: String, ): String? { @@ -639,10 +672,11 @@ class GMCharacterEditFactory( private fun commonSkillBaseFlow( scope: CoroutineScope, - characteristics: GMCharacterEditPageUio.CharacteristicsUio, + characteristics: List, skillId: String, ): MutableStateFlow { val flow = combine( + characteristics.map { it. } characteristics.strength.valueFlow.map { it.toIntOrNull() ?: 0 }, characteristics.dexterity.valueFlow.map { it.toIntOrNull() ?: 0 }, characteristics.constitution.valueFlow.map { it.toIntOrNull() ?: 0 }, diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/admin/character/edit/GMCharacterEditPage.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/admin/character/edit/GMCharacterEditPage.kt index 464d01b..57395f9 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/admin/character/edit/GMCharacterEditPage.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/admin/character/edit/GMCharacterEditPage.kt @@ -67,6 +67,8 @@ import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.dialog.GMCharact import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.dialog.GMCharacterSheetCopyDialogViewModel import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.item.GMActionField import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.item.GMActionFieldUio +import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.item.GMCharacteristicField +import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.item.GMCharacteristicFieldUio import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.item.GMSkillField import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.item.GMSkillFieldUio import com.pixelized.desktop.lwa.ui.screen.admin.common.tag.GMTagButton @@ -96,27 +98,13 @@ data class GMCharacterEditPageUio( val externalLink: LwaTextFieldUio, val level: LwaTextFieldUio, val levelUp: LwaCheckBoxUio, - val characteristics: CharacteristicsUio, + val characteristics: List, val tags: MutableStateFlow>, val commonSkills: List, val specialSkills: List, val magicSkills: List, val actions: List, -) { - @Stable - data class CharacteristicsUio( - val strength: LwaTextFieldUio, - val dexterity: LwaTextFieldUio, - val constitution: LwaTextFieldUio, - val height: LwaTextFieldUio, - val intelligence: LwaTextFieldUio, - val power: LwaTextFieldUio, - val charisma: LwaTextFieldUio, - ) { - val values = - listOf(strength, dexterity, constitution, height, intelligence, power, charisma) - } -} +) @Stable object GMCharacterEditPageDefault { @@ -166,6 +154,13 @@ fun GMCharacterEditPage( onTag = { tag -> viewModel.addTag(tag = tag) }, + onCharacteristicAdd = { + + }, + onCharacteristicDelete = { index -> + focus.clearFocus(force = true) + scope.launch { viewModel.deleteCharacteristic(index = index) } + }, onSpecialSkillAdd = { focus.clearFocus(force = true) scope.launch { viewModel.addSpecialSkill() } @@ -244,6 +239,8 @@ fun GMCharacterEditContent( onSaveAs: () -> Unit, onSave: () -> Unit, onTag: (GMTagUio) -> Unit, + onCharacteristicAdd: () -> Unit, + onCharacteristicDelete: (Int) -> Unit, onSpecialSkillAdd: () -> Unit, onSpecialSkillDelete: (Int) -> Unit, onMagicSkillAdd: () -> Unit, @@ -482,17 +479,17 @@ fun GMCharacterEditContent( text = "Characteristics", ) } - items( - items = form.characteristics.values, - key = { "characteristics-${it.labelFlow}" }, - ) { characteristic -> - LwaTextField( + itemsIndexed( + items = form.characteristics, + key = { _, item -> item.key }, + ) { index, characteristic -> + GMCharacteristicField( modifier = Modifier .animateItem() .fillMaxWidth() .padding(paddingValues = horizontalPadding), - field = characteristic, - singleLine = true, + characteristic = characteristic, + onDelete = { onCharacteristicDelete(index) }, ) } item(key = "CommonSkillsTitle") { diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/admin/character/edit/GMCharacterEditViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/admin/character/edit/GMCharacterEditViewModel.kt index c332b4d..961e0ff 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/admin/character/edit/GMCharacterEditViewModel.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/admin/character/edit/GMCharacterEditViewModel.kt @@ -103,6 +103,18 @@ class GMCharacterEditViewModel( } } + suspend fun deleteCharacteristic( + index: Int + ) { + _form.update { form -> + form?.copy( + characteristics = form.characteristics.toMutableList().also { + it.removeAt(index) + }, + ) + } + } + suspend fun deleteSpecialSkill( index: Int, ) { diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/admin/character/edit/item/GMCharacteristicFieldUio.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/admin/character/edit/item/GMCharacteristicFieldUio.kt new file mode 100644 index 0000000..2b9b003 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/admin/character/edit/item/GMCharacteristicFieldUio.kt @@ -0,0 +1,144 @@ +package com.pixelized.desktop.lwa.ui.screen.admin.character.edit.item + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material.DropdownMenu +import androidx.compose.material.DropdownMenuItem +import androidx.compose.material.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Delete +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.platform.LocalFocusManager +import androidx.compose.ui.unit.DpOffset +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp +import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextField +import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio +import com.pixelized.desktop.lwa.utils.extention.moveFocusOnTab + +@Stable +data class GMCharacteristicFieldUio( + val key: String, + val id: LwaTextFieldUio, + val label: LwaTextFieldUio, + val description: LwaTextFieldUio, + val base: LwaTextFieldUio, + val level: LwaTextFieldUio, +) + +@Stable +object GMCharacteristicFieldDefault { + @Stable + val spacing: DpSize = DpSize(4.dp, 4.dp) +} + +@Composable +fun GMCharacteristicField( + modifier: Modifier = Modifier, + spacing: DpSize = GMCharacteristicFieldDefault.spacing, + characteristic: GMCharacteristicFieldUio, + onDelete: ((GMCharacteristicFieldUio) -> Unit)?, +) { + val focus = LocalFocusManager.current + val showMenu = remember { mutableStateOf(false) } + val onDismissRequest = remember { + { + focus.clearFocus(force = true) + showMenu.value = false + } + } + + Row( + modifier = modifier, + horizontalArrangement = Arrangement.spacedBy(space = spacing.width), + ) { + Column( + modifier = Modifier.weight(weight = 1f), + verticalArrangement = Arrangement.spacedBy(space = spacing.height), + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(space = spacing.width), + ) { + LwaTextField( + modifier = Modifier.weight(weight = 1f), + field = skill.id, + ) + LwaTextField( + modifier = Modifier.weight(weight = 1f), + field = skill.label, + ) + } + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(space = spacing.width), + ) { + LwaTextField( + modifier = Modifier.weight(weight = 1f), + field = skill.base, + ) + LwaTextField( + modifier = Modifier.weight(weight = 1f), + field = skill.level, + ) + } + skill.description?.let { description -> + LwaTextField( + modifier = Modifier + .fillMaxWidth() + .moveFocusOnTab(focusManager = LocalFocusManager.current), + field = description, + singleLine = false, + ) + } + } + Box { + IconButton( + onClick = { showMenu.value = showMenu.value.not() }, + ) { + Icon( + imageVector = Icons.Default.MoreVert, + tint = MaterialTheme.colors.primary, + contentDescription = null, + ) + } + DropdownMenu( + expanded = showMenu.value, + offset = DpOffset(x = (-48).dp - spacing.width, y = (-48).dp), + onDismissRequest = onDismissRequest, + ) { + DropdownMenuItem( + modifier = modifier, + enabled = onDelete != null, + onClick = { + onDismissRequest() + onDelete?.invoke(skill) + }, + ) { + Icon( + imageVector = Icons.Default.Delete, + tint = MaterialTheme.colors.primary, + contentDescription = null, + ) + Text( + modifier = Modifier.padding(start = 8.dp), + text = "Supprimer", + ) + } + } + } + } +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/AlteredCharacterSheet.kt b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/AlteredCharacterSheet.kt index 85d5a32..efb3c38 100644 --- a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/AlteredCharacterSheet.kt +++ b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/AlteredCharacterSheet.kt @@ -3,7 +3,6 @@ package com.pixelized.shared.lwa.model import com.pixelized.shared.lwa.model.alteration.FieldAlteration import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.ARMOR -import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.CHA import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.CON import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.DEX import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.DMG @@ -69,37 +68,24 @@ class AlteredCharacterSheet( val level: Int get() = sheet.level + fieldAlterations[LVL].sum() - val strength: Int - get() = sheet.strength + fieldAlterations[STR].sum() - - val dexterity: Int - get() = sheet.dexterity + fieldAlterations[DEX].sum() - - val constitution: Int - get() = sheet.constitution + fieldAlterations[CON].sum() - - val height: Int - get() = sheet.height + fieldAlterations[HEI].sum() - - val intelligence: Int - get() = sheet.intelligence + fieldAlterations[INT].sum() - - val power: Int - get() = sheet.power + fieldAlterations[POW].sum() - - val charisma: Int - get() = sheet.charisma + fieldAlterations[CHA].sum() + /** + * see CharacterSheet.CharacteristicId + */ + fun characteristic(id: String): Int = + sheet.characteristics.firstOrNull { it.id == id }?.let { characteristic -> + characteristic.base + characteristic.level + fieldAlterations[id].sum() + } ?: 0 val maxHp: Int get() = sheetUseCase.maxHp( - constitution = constitution, - height = height, + constitution = characteristic(id = CON), + height = characteristic(id = HEI), level = level, ) + fieldAlterations[HP].sum() val maxPp: Int get() = sheetUseCase.maxPp( - power = power, + power = characteristic(id = POW), ) + fieldAlterations[PP].sum() val damage: Int @@ -125,19 +111,21 @@ class AlteredCharacterSheet( val reflex: Int get() = sheetUseCase.reflex( - strength = strength, - dexterity = dexterity, - intelligence = intelligence, + strength = characteristic(id = STR), + dexterity = characteristic(id = DEX), + intelligence = characteristic(id = INT), ) + fieldAlterations[REFLEX].sum() val initiative: Int - get() = sheetUseCase.initiative(dexterity = dexterity) + fieldAlterations[INITIATIVE].sum() + get() = sheetUseCase.initiative( + dexterity = characteristic(id = DEX) + ) + fieldAlterations[INITIATIVE].sum() val damageBonus: String get() { val initial = sheetUseCase.meleeBonusDamage( - strength = strength, - height = height, + strength = characteristic(id = STR), + height = characteristic(id = HEI), ) return fieldAlterations[DMG] ?.joinToString(separator = "+") { it.expression.toString() } @@ -147,12 +135,12 @@ class AlteredCharacterSheet( val learning: Int get() = sheetUseCase.learning( - intelligence = intelligence + intelligence = characteristic(id = INT), ) + fieldAlterations[LB].sum() val hpGrow: Int get() = sheetUseCase.hpGrow( - constitution = constitution, + constitution = characteristic(id = CON), ) + fieldAlterations[GHP].sum() // Helper method diff --git a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/CharacterSheet.kt b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/CharacterSheet.kt index 3d5fe99..dcf8ea8 100644 --- a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/CharacterSheet.kt +++ b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/CharacterSheet.kt @@ -10,13 +10,7 @@ data class CharacterSheet( val level: Int, val shouldLevelUp: Boolean, // characteristics - val strength: Int, - val dexterity: Int, - val constitution: Int, - val height: Int, - val intelligence: Int, - val power: Int, - val charisma: Int, + val characteristics: List, // alterations val damage: Int, // damage taken on the hp pool val fatigue: Int, // damage taken on the pp pool @@ -35,6 +29,14 @@ data class CharacterSheet( ?: specialSkills.firstOrNull { it.id == id } ?: magicSkills.firstOrNull { it.id == id } + data class Characteristic( + val id: String, + val label: String, + val description: String?, + val base: Int, + val level: Int, + ) + data class Skill( val id: String, val label: String, diff --git a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/CharacterSheetJsonV2.kt b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/CharacterSheetJsonV2.kt new file mode 100644 index 0000000..93aa4ce --- /dev/null +++ b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/CharacterSheetJsonV2.kt @@ -0,0 +1,63 @@ +package com.pixelized.shared.lwa.model.characterSheet + +import kotlinx.serialization.Serializable + +@Serializable +data class CharacterSheetJsonV2( + override val id: String, + override val name: String, + val job: String?, + val portrait: String?, + val thumbnail: String?, + val externalLink: String?, + val level: Int, + val shouldLevelUp: Boolean?, + // characteristics + val characteristics: List, + // alterations + val damage: Int?, + val fatigue: Int?, + val diminished: Int?, + val alterations: List?, + // skills + val skills: List, + val occupations: List, + val magics: List, + // actions + val rolls: List, + // tags + val tag: List?, +) : CharacterSheetJson { + + @Serializable + data class Characteristic( + val id: String, + val label: String, + val description: String?, + val base: Int, + val level: Int, + ) + + @Serializable + data class Skill( + val id: String, + val label: String, + val description: String?, + val base: String, + val bonus: String?, + val level: Int, + val occupation: Boolean, + val used: Boolean, + ) + + @Serializable + data class Roll( + val id: String, + val label: String, + val description: String?, + val canBeCritical: Boolean, + val roll: String, + val special: String?, + val critical: String?, + ) +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/factory/CharacterSheetJsonFactory.kt b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/factory/CharacterSheetJsonFactory.kt index 400e53a..b33f28b 100644 --- a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/factory/CharacterSheetJsonFactory.kt +++ b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/factory/CharacterSheetJsonFactory.kt @@ -3,18 +3,21 @@ package com.pixelized.shared.lwa.model.characterSheet.factory import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJson import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJsonV1 +import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJsonV2 import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetPreview import com.pixelized.shared.lwa.protocol.rest.CharacterPreviewJson class CharacterSheetJsonFactory( private val v1: CharacterSheetJsonV1Factory, + private val v2: CharacterSheetJsonV2Factory, ) { fun convertFromJson( json: CharacterSheetJson, ): CharacterSheet { return when (json) { is CharacterSheetJsonV1 -> v1.convertFromJson(json = json) + is CharacterSheetJsonV2 -> v2.convertFromJson(json = json) } } @@ -23,7 +26,7 @@ class CharacterSheetJsonFactory( fun convertToJson( sheet: CharacterSheet, ): CharacterSheetJson { - val json = CharacterSheetJsonV1( + val json = CharacterSheetJsonV2( id = sheet.id, name = sheet.name, job = sheet.job, @@ -32,19 +35,21 @@ class CharacterSheetJsonFactory( externalLink = sheet.externalLink, level = sheet.level, shouldLevelUp = sheet.shouldLevelUp, - strength = sheet.strength, - dexterity = sheet.dexterity, - constitution = sheet.constitution, - height = sheet.height, - intelligence = sheet.intelligence, - power = sheet.power, - charisma = sheet.charisma, + characteristics = sheet.characteristics.map { + CharacterSheetJsonV2.Characteristic( + id = it.id, + label = it.label, + description = it.description, + base = it.base, + level = it.level, + ) + }, damage = sheet.damage, fatigue = sheet.fatigue, diminished = sheet.diminished, alterations = sheet.alterations, skills = sheet.commonSkills.map { - CharacterSheetJsonV1.Skill( + CharacterSheetJsonV2.Skill( id = it.id, label = it.label, description = it.description, @@ -56,7 +61,7 @@ class CharacterSheetJsonFactory( ) }, occupations = sheet.specialSkills.map { - CharacterSheetJsonV1.Skill( + CharacterSheetJsonV2.Skill( id = it.id, label = it.label, description = it.description, @@ -68,7 +73,7 @@ class CharacterSheetJsonFactory( ) }, magics = sheet.magicSkills.map { - CharacterSheetJsonV1.Skill( + CharacterSheetJsonV2.Skill( id = it.id, label = it.label, description = it.description, @@ -80,7 +85,7 @@ class CharacterSheetJsonFactory( ) }, rolls = sheet.actions.map { - CharacterSheetJsonV1.Roll( + CharacterSheetJsonV2.Roll( id = it.id, label = it.label, description = it.description, diff --git a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/factory/CharacterSheetJsonV1Factory.kt b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/factory/CharacterSheetJsonV1Factory.kt index deeac86..19cfaa4 100644 --- a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/factory/CharacterSheetJsonV1Factory.kt +++ b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/factory/CharacterSheetJsonV1Factory.kt @@ -19,13 +19,57 @@ class CharacterSheetJsonV1Factory( externalLink = json.externalLink, level = json.level, shouldLevelUp = json.shouldLevelUp ?: false, - strength = json.strength, - dexterity = json.dexterity, - constitution = json.constitution, - height = json.height, - intelligence = json.intelligence, - power = json.power, - charisma = json.charisma, + characteristics = listOf( + CharacterSheet.Characteristic( + id = CharacterSheet.CharacteristicId.STR, + label = "Force", + description = "La Force représente essentiellement la puissance musculaire du personnage. Elle ne décrit pas nécessairement la masse musculaire brute, mais l’efficacité avec laquelle le personnage exerce ses muscles pour accomplir des actions physiques pénibles.\n\n- Bonus aux dégats\n- Réflexe\n- Athlétisme\n- Lancer\n- Saisie", + base = json.strength, + level = 0, + ), + CharacterSheet.Characteristic( + id = CharacterSheet.CharacteristicId.DEX, + label = "Dextérité", + description = "La Constitution est une mesure de la ténacité et de la résilience du personnage. Elle sert à résister aux maladies. Mais son aspect le plus important réside dans la détermination du nombre de dommages qu’un personnage peut supporter avant de succomber.\n\n- Point de vie maximum\n- Athlétisme\n- Acrobatie", + base = json.dexterity, + level = 0, + ), + CharacterSheet.Characteristic( + id = CharacterSheet.CharacteristicId.CON, + label = "Constitution", + description = "La Taille est une mesure de la masse du personnage. Elle ne représente pas forcément la taille en centimètres, mais une idée générale de sa masse physique. Un personnage à la TAI élevée peut être très grand et mince, ou petit et massif, ou de taille moyenne en surpoids.\n\n- Bonus aux dégats\n- Point de vie maximum\n- Saisie\n- Intimidation\n- Discrétion (impact négatif)", + base = json.constitution, + level = 0, + ), + CharacterSheet.Characteristic( + id = CharacterSheet.CharacteristicId.HEI, + label = "Taille", + description = "L’Intelligence représente la capacité de discernement du personnage. Elle ne mesure pas nécessairement la somme d’informations mémorisées, mais l’aptitude au raisonnement, l’acuité intellectuelle, la capacité à résoudre des problèmes et l’intuition.\n\n- Bonus d'apprentissage\n- Réflexe\n- Perception\n- Recherche\n- Empathie\n- Baratin\n- Premiers soins", + base = json.height, + level = 0, + ), + CharacterSheet.Characteristic( + id = CharacterSheet.CharacteristicId.INT, + label = "Intelligence", + description = "Le Pouvoir est une mesure presque intangible de la force de volonté, du dynamisme intérieur et de l’énergie spirituelle. Il représente également le potentiel magique du personnage.\n\n- Points de pouvoir maximum\n- Intimidation", + base = json.intelligence, + level = 0, + ), + CharacterSheet.Characteristic( + id = CharacterSheet.CharacteristicId.POW, + label = "Pouvoir", + description = "La Dextérité mesure la coordination œil-main, la vitesse physique et l’agilité générale. La DEX détermine à quelle vitesse un personnage peut agir en combat.\n\n- Initiative\n- Réflexe\n- Bagarre\n- Esquive\n- Lancer\n- Acrobatie\n- Discrétion\n- Escamotage\n- Premiers soins", + base = json.power, + level = 0, + ), + CharacterSheet.Characteristic( + id = CharacterSheet.CharacteristicId.CHA, + label = "Charisme", + description = "Il représente plusieurs aspects allant de la grâce à la beauté en passant par l’attraction que le personnage exerce sur les autres. Un personnage avec un CHA élevé se remarque dans une foule en raison d’une intangible combinaison de charme et de présence.\n\n- Empathie\n- Persuasion\n- Persuasion\n- Intimidation\n- Baratin\n- Marchandage\n- Discrétion", + base = json.charisma, + level = 0, + ), + ), damage = json.damage ?: 0, fatigue = json.fatigue ?: 0, diminished = json.diminished ?: 0, diff --git a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/factory/CharacterSheetJsonV2Factory.kt b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/factory/CharacterSheetJsonV2Factory.kt new file mode 100644 index 0000000..f92dc2e --- /dev/null +++ b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/factory/CharacterSheetJsonV2Factory.kt @@ -0,0 +1,85 @@ +package com.pixelized.shared.lwa.model.characterSheet.factory + +import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet +import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJsonV2 +import com.pixelized.shared.lwa.usecase.CharacterSheetUseCase + +class CharacterSheetJsonV2Factory( + private val characterSheetUseCase: CharacterSheetUseCase, +) { + fun convertFromJson( + json: CharacterSheetJsonV2, + ): CharacterSheet = characterSheetUseCase.run { + CharacterSheet( + id = json.id, + name = json.name, + job = json.job ?: "", + portrait = json.portrait, + thumbnail = json.thumbnail, + externalLink = json.externalLink, + level = json.level, + shouldLevelUp = json.shouldLevelUp ?: false, + characteristics = json.characteristics.map { + CharacterSheet.Characteristic( + id = it.id, + label = it.label, + description = it.description, + base = it.base, + level = it.level, + ) + }, + damage = json.damage ?: 0, + fatigue = json.fatigue ?: 0, + diminished = json.diminished ?: 0, + alterations = json.alterations ?: emptyList(), + commonSkills = json.skills.map { + CharacterSheet.Skill( + id = it.id, + label = it.label, + description = it.description, + base = it.base, + bonus = it.bonus, + level = it.level, + occupation = it.occupation, + used = it.used, + ) + }, + specialSkills = json.occupations.map { + CharacterSheet.Skill( + id = it.id, + label = it.label, + description = it.description, + base = it.base, + bonus = it.bonus, + level = it.level, + occupation = it.occupation, + used = it.used, + ) + }, + magicSkills = json.magics.map { + CharacterSheet.Skill( + id = it.id, + label = it.label, + description = it.description, + base = it.base, + bonus = it.bonus, + level = it.level, + occupation = it.occupation, + used = it.used, + ) + }, + actions = json.rolls.map { + CharacterSheet.Roll( + id = it.id, + label = it.label, + description = it.description, + canBeCritical = it.canBeCritical, + default = it.roll, + special = it.special, + critical = it.critical, + ) + }, + tags = json.tag ?: emptyList(), + ) + } +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/usecase/ExpressionUseCase.kt b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/usecase/ExpressionUseCase.kt index 57e9059..67d31a5 100644 --- a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/usecase/ExpressionUseCase.kt +++ b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/usecase/ExpressionUseCase.kt @@ -4,6 +4,13 @@ package com.pixelized.shared.lwa.usecase import com.pixelized.shared.lwa.model.AlteredCharacterSheet import com.pixelized.shared.lwa.model.alteration.FieldAlteration import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet +import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.CHA +import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.CON +import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.DEX +import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.HEI +import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.INT +import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.POW +import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.STR import com.pixelized.shared.lwa.parser.expression.Expression import com.pixelized.shared.lwa.parser.expression.ExpressionParser import com.pixelized.shared.lwa.parser.word.Word @@ -128,8 +135,8 @@ class ExpressionUseCase( Word.Type.BDC -> evaluate( expression = expressionParser.parse( characterSheetUseCase.meleeBonusDamage( - strength = sheet.strength, - height = sheet.height, + strength = sheet.characteristic(id = STR), + height = sheet.characteristic(id = HEI), ) ) ) @@ -137,19 +144,19 @@ class ExpressionUseCase( Word.Type.BDD -> evaluate( expression = expressionParser.parse( characterSheetUseCase.distanceBonusDamage( - strength = sheet.strength, - height = sheet.height, + strength = sheet.characteristic(id = STR), + height = sheet.characteristic(id = HEI), ) ) ) - Word.Type.STR -> sheet.strength - Word.Type.DEX -> sheet.dexterity - Word.Type.CON -> sheet.constitution - Word.Type.HEI -> sheet.height - Word.Type.INT -> sheet.intelligence - Word.Type.POW -> sheet.power - Word.Type.CHA -> sheet.charisma + Word.Type.STR -> sheet.characteristic(id = STR) + Word.Type.DEX -> sheet.characteristic(id = DEX) + Word.Type.CON -> sheet.characteristic(id = CON) + Word.Type.HEI -> sheet.characteristic(id = HEI) + Word.Type.INT -> sheet.characteristic(id = INT) + Word.Type.POW -> sheet.characteristic(id = POW) + Word.Type.CHA -> sheet.characteristic(id = CHA) } null -> 0