This commit is contained in:
Andres Gomez, Thomas (ITDV RL) 2025-11-29 10:25:05 +01:00
parent ce05e6a4c4
commit f6f2a8b4f8
11 changed files with 490 additions and 109 deletions

View file

@ -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.createLwaTextField
import com.pixelized.desktop.lwa.ui.composable.textfield.createLwaTextFieldFlow 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.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.character.edit.item.GMSkillFieldUio
import com.pixelized.desktop.lwa.ui.screen.admin.common.tag.GMTagFactory 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.desktop.lwa.utils.extention.unpack
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CommonSkillId.ACROBATICS_ID 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_base
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__throw_description 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.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 org.jetbrains.compose.resources.getString
import java.util.UUID import java.util.UUID
@ -132,20 +144,17 @@ class GMCharacterEditFactory(
level = form.level.unpack() level = form.level.unpack()
?: error("Missing character level"), ?: error("Missing character level"),
shouldLevelUp = form.levelUp.checked.value, shouldLevelUp = form.levelUp.checked.value,
strength = form.characteristics.strength.unpack() characteristics = form.characteristics.map { characteristic ->
?: error("Missing character strength"), val characteristicId: String = characteristic.id.unpack()
dexterity = form.characteristics.dexterity.unpack() ?: error("Missing characteristic id")
?: error("Missing character dexterity"), CharacterSheet.Characteristic(
constitution = form.characteristics.constitution.unpack() id = characteristicId,
?: error("Missing character constitution"), label = characteristic.label.unpack() ?: "",
height = form.characteristics.height.unpack() description = characteristic.description.unpack() ?: "",
?: error("Missing character height"), base = characteristic.base.unpack() ?: 0,
intelligence = form.characteristics.intelligence.unpack() level = characteristic.level.unpack() ?: 0,
?: error("Missing character intelligence"), )
power = form.characteristics.power.unpack() },
?: error("Missing character power"),
charisma = form.characteristics.charisma.unpack()
?: error("Missing character charisma"),
alterations = sheet?.alterations ?: emptyList(), alterations = sheet?.alterations ?: emptyList(),
damage = sheet?.damage ?: 0, damage = sheet?.damage ?: 0,
fatigue = sheet?.fatigue ?: 0, fatigue = sheet?.fatigue ?: 0,
@ -185,7 +194,6 @@ class GMCharacterEditFactory(
magicSkills = form.magicSkills.map { editedSkill -> magicSkills = form.magicSkills.map { editedSkill ->
val skillId: String = editedSkill.id.unpack() val skillId: String = editedSkill.id.unpack()
?: error("Missing skill id") ?: error("Missing skill id")
CharacterSheet.Skill( CharacterSheet.Skill(
id = skillId, id = skillId,
label = editedSkill.label.unpack() label = editedSkill.label.unpack()
@ -333,10 +341,18 @@ class GMCharacterEditFactory(
actions = sheet?.actions?.map { createAction(action = it) } ?: emptyList()) actions = sheet?.actions?.map { createAction(action = it) } ?: emptyList())
} }
private suspend fun createCharacteristic(
scope: CoroutineScope,
skill: CharacterSheet.Skill,
characteristics: List<GMCharacteristicFieldUio>,
): List<GMCharacteristicFieldUio> {
}
private suspend fun createCommonSkill( private suspend fun createCommonSkill(
scope: CoroutineScope, scope: CoroutineScope,
skill: CharacterSheet.Skill, skill: CharacterSheet.Skill,
characteristics: GMCharacterEditPageUio.CharacteristicsUio, characteristics: List<GMCharacteristicFieldUio>,
): GMSkillFieldUio { ): GMSkillFieldUio {
val baseLabel = getString(Res.string.character_sheet_edit__skills__base_label) val baseLabel = getString(Res.string.character_sheet_edit__skills__base_label)
val idFlow = createLwaTextFieldFlow( 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( private suspend fun commonSkillDescription(
skillId: String, skillId: String,
): String? { ): String? {
@ -639,10 +672,11 @@ class GMCharacterEditFactory(
private fun commonSkillBaseFlow( private fun commonSkillBaseFlow(
scope: CoroutineScope, scope: CoroutineScope,
characteristics: GMCharacterEditPageUio.CharacteristicsUio, characteristics: List<GMCharacteristicFieldUio>,
skillId: String, skillId: String,
): MutableStateFlow<String> { ): MutableStateFlow<String> {
val flow = combine( val flow = combine(
characteristics.map { it. }
characteristics.strength.valueFlow.map { it.toIntOrNull() ?: 0 }, characteristics.strength.valueFlow.map { it.toIntOrNull() ?: 0 },
characteristics.dexterity.valueFlow.map { it.toIntOrNull() ?: 0 }, characteristics.dexterity.valueFlow.map { it.toIntOrNull() ?: 0 },
characteristics.constitution.valueFlow.map { it.toIntOrNull() ?: 0 }, characteristics.constitution.valueFlow.map { it.toIntOrNull() ?: 0 },

View file

@ -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.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.GMActionField
import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.item.GMActionFieldUio 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.GMSkillField
import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.item.GMSkillFieldUio import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.item.GMSkillFieldUio
import com.pixelized.desktop.lwa.ui.screen.admin.common.tag.GMTagButton import com.pixelized.desktop.lwa.ui.screen.admin.common.tag.GMTagButton
@ -96,27 +98,13 @@ data class GMCharacterEditPageUio(
val externalLink: LwaTextFieldUio, val externalLink: LwaTextFieldUio,
val level: LwaTextFieldUio, val level: LwaTextFieldUio,
val levelUp: LwaCheckBoxUio, val levelUp: LwaCheckBoxUio,
val characteristics: CharacteristicsUio, val characteristics: List<GMCharacteristicFieldUio>,
val tags: MutableStateFlow<List<GMTagUio>>, val tags: MutableStateFlow<List<GMTagUio>>,
val commonSkills: List<GMSkillFieldUio>, val commonSkills: List<GMSkillFieldUio>,
val specialSkills: List<GMSkillFieldUio>, val specialSkills: List<GMSkillFieldUio>,
val magicSkills: List<GMSkillFieldUio>, val magicSkills: List<GMSkillFieldUio>,
val actions: List<GMActionFieldUio>, val actions: List<GMActionFieldUio>,
) { )
@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 @Stable
object GMCharacterEditPageDefault { object GMCharacterEditPageDefault {
@ -166,6 +154,13 @@ fun GMCharacterEditPage(
onTag = { tag -> onTag = { tag ->
viewModel.addTag(tag = tag) viewModel.addTag(tag = tag)
}, },
onCharacteristicAdd = {
},
onCharacteristicDelete = { index ->
focus.clearFocus(force = true)
scope.launch { viewModel.deleteCharacteristic(index = index) }
},
onSpecialSkillAdd = { onSpecialSkillAdd = {
focus.clearFocus(force = true) focus.clearFocus(force = true)
scope.launch { viewModel.addSpecialSkill() } scope.launch { viewModel.addSpecialSkill() }
@ -244,6 +239,8 @@ fun GMCharacterEditContent(
onSaveAs: () -> Unit, onSaveAs: () -> Unit,
onSave: () -> Unit, onSave: () -> Unit,
onTag: (GMTagUio) -> Unit, onTag: (GMTagUio) -> Unit,
onCharacteristicAdd: () -> Unit,
onCharacteristicDelete: (Int) -> Unit,
onSpecialSkillAdd: () -> Unit, onSpecialSkillAdd: () -> Unit,
onSpecialSkillDelete: (Int) -> Unit, onSpecialSkillDelete: (Int) -> Unit,
onMagicSkillAdd: () -> Unit, onMagicSkillAdd: () -> Unit,
@ -482,17 +479,17 @@ fun GMCharacterEditContent(
text = "Characteristics", text = "Characteristics",
) )
} }
items( itemsIndexed(
items = form.characteristics.values, items = form.characteristics,
key = { "characteristics-${it.labelFlow}" }, key = { _, item -> item.key },
) { characteristic -> ) { index, characteristic ->
LwaTextField( GMCharacteristicField(
modifier = Modifier modifier = Modifier
.animateItem() .animateItem()
.fillMaxWidth() .fillMaxWidth()
.padding(paddingValues = horizontalPadding), .padding(paddingValues = horizontalPadding),
field = characteristic, characteristic = characteristic,
singleLine = true, onDelete = { onCharacteristicDelete(index) },
) )
} }
item(key = "CommonSkillsTitle") { item(key = "CommonSkillsTitle") {

View file

@ -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( suspend fun deleteSpecialSkill(
index: Int, index: Int,
) { ) {

View file

@ -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",
)
}
}
}
}
}

View file

@ -3,7 +3,6 @@ package com.pixelized.shared.lwa.model
import com.pixelized.shared.lwa.model.alteration.FieldAlteration import com.pixelized.shared.lwa.model.alteration.FieldAlteration
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet 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.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.CON
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.DEX import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.DEX
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.DMG import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.DMG
@ -69,37 +68,24 @@ class AlteredCharacterSheet(
val level: Int val level: Int
get() = sheet.level + fieldAlterations[LVL].sum() get() = sheet.level + fieldAlterations[LVL].sum()
val strength: Int /**
get() = sheet.strength + fieldAlterations[STR].sum() * see CharacterSheet.CharacteristicId
*/
val dexterity: Int fun characteristic(id: String): Int =
get() = sheet.dexterity + fieldAlterations[DEX].sum() sheet.characteristics.firstOrNull { it.id == id }?.let { characteristic ->
characteristic.base + characteristic.level + fieldAlterations[id].sum()
val constitution: Int } ?: 0
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()
val maxHp: Int val maxHp: Int
get() = sheetUseCase.maxHp( get() = sheetUseCase.maxHp(
constitution = constitution, constitution = characteristic(id = CON),
height = height, height = characteristic(id = HEI),
level = level, level = level,
) + fieldAlterations[HP].sum() ) + fieldAlterations[HP].sum()
val maxPp: Int val maxPp: Int
get() = sheetUseCase.maxPp( get() = sheetUseCase.maxPp(
power = power, power = characteristic(id = POW),
) + fieldAlterations[PP].sum() ) + fieldAlterations[PP].sum()
val damage: Int val damage: Int
@ -125,19 +111,21 @@ class AlteredCharacterSheet(
val reflex: Int val reflex: Int
get() = sheetUseCase.reflex( get() = sheetUseCase.reflex(
strength = strength, strength = characteristic(id = STR),
dexterity = dexterity, dexterity = characteristic(id = DEX),
intelligence = intelligence, intelligence = characteristic(id = INT),
) + fieldAlterations[REFLEX].sum() ) + fieldAlterations[REFLEX].sum()
val initiative: Int val initiative: Int
get() = sheetUseCase.initiative(dexterity = dexterity) + fieldAlterations[INITIATIVE].sum() get() = sheetUseCase.initiative(
dexterity = characteristic(id = DEX)
) + fieldAlterations[INITIATIVE].sum()
val damageBonus: String val damageBonus: String
get() { get() {
val initial = sheetUseCase.meleeBonusDamage( val initial = sheetUseCase.meleeBonusDamage(
strength = strength, strength = characteristic(id = STR),
height = height, height = characteristic(id = HEI),
) )
return fieldAlterations[DMG] return fieldAlterations[DMG]
?.joinToString(separator = "+") { it.expression.toString() } ?.joinToString(separator = "+") { it.expression.toString() }
@ -147,12 +135,12 @@ class AlteredCharacterSheet(
val learning: Int val learning: Int
get() = sheetUseCase.learning( get() = sheetUseCase.learning(
intelligence = intelligence intelligence = characteristic(id = INT),
) + fieldAlterations[LB].sum() ) + fieldAlterations[LB].sum()
val hpGrow: Int val hpGrow: Int
get() = sheetUseCase.hpGrow( get() = sheetUseCase.hpGrow(
constitution = constitution, constitution = characteristic(id = CON),
) + fieldAlterations[GHP].sum() ) + fieldAlterations[GHP].sum()
// Helper method // Helper method

View file

@ -10,13 +10,7 @@ data class CharacterSheet(
val level: Int, val level: Int,
val shouldLevelUp: Boolean, val shouldLevelUp: Boolean,
// characteristics // characteristics
val strength: Int, val characteristics: List<Characteristic>,
val dexterity: Int,
val constitution: Int,
val height: Int,
val intelligence: Int,
val power: Int,
val charisma: Int,
// alterations // alterations
val damage: Int, // damage taken on the hp pool val damage: Int, // damage taken on the hp pool
val fatigue: Int, // damage taken on the pp pool val fatigue: Int, // damage taken on the pp pool
@ -35,6 +29,14 @@ data class CharacterSheet(
?: specialSkills.firstOrNull { it.id == id } ?: specialSkills.firstOrNull { it.id == id }
?: magicSkills.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( data class Skill(
val id: String, val id: String,
val label: String, val label: String,

View file

@ -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<Characteristic>,
// alterations
val damage: Int?,
val fatigue: Int?,
val diminished: Int?,
val alterations: List<String>?,
// skills
val skills: List<Skill>,
val occupations: List<Skill>,
val magics: List<Skill>,
// actions
val rolls: List<Roll>,
// tags
val tag: List<String>?,
) : 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?,
)
}

View file

@ -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.CharacterSheet
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJson import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJson
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJsonV1 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.model.characterSheet.CharacterSheetPreview
import com.pixelized.shared.lwa.protocol.rest.CharacterPreviewJson import com.pixelized.shared.lwa.protocol.rest.CharacterPreviewJson
class CharacterSheetJsonFactory( class CharacterSheetJsonFactory(
private val v1: CharacterSheetJsonV1Factory, private val v1: CharacterSheetJsonV1Factory,
private val v2: CharacterSheetJsonV2Factory,
) { ) {
fun convertFromJson( fun convertFromJson(
json: CharacterSheetJson, json: CharacterSheetJson,
): CharacterSheet { ): CharacterSheet {
return when (json) { return when (json) {
is CharacterSheetJsonV1 -> v1.convertFromJson(json = json) is CharacterSheetJsonV1 -> v1.convertFromJson(json = json)
is CharacterSheetJsonV2 -> v2.convertFromJson(json = json)
} }
} }
@ -23,7 +26,7 @@ class CharacterSheetJsonFactory(
fun convertToJson( fun convertToJson(
sheet: CharacterSheet, sheet: CharacterSheet,
): CharacterSheetJson { ): CharacterSheetJson {
val json = CharacterSheetJsonV1( val json = CharacterSheetJsonV2(
id = sheet.id, id = sheet.id,
name = sheet.name, name = sheet.name,
job = sheet.job, job = sheet.job,
@ -32,19 +35,21 @@ class CharacterSheetJsonFactory(
externalLink = sheet.externalLink, externalLink = sheet.externalLink,
level = sheet.level, level = sheet.level,
shouldLevelUp = sheet.shouldLevelUp, shouldLevelUp = sheet.shouldLevelUp,
strength = sheet.strength, characteristics = sheet.characteristics.map {
dexterity = sheet.dexterity, CharacterSheetJsonV2.Characteristic(
constitution = sheet.constitution, id = it.id,
height = sheet.height, label = it.label,
intelligence = sheet.intelligence, description = it.description,
power = sheet.power, base = it.base,
charisma = sheet.charisma, level = it.level,
)
},
damage = sheet.damage, damage = sheet.damage,
fatigue = sheet.fatigue, fatigue = sheet.fatigue,
diminished = sheet.diminished, diminished = sheet.diminished,
alterations = sheet.alterations, alterations = sheet.alterations,
skills = sheet.commonSkills.map { skills = sheet.commonSkills.map {
CharacterSheetJsonV1.Skill( CharacterSheetJsonV2.Skill(
id = it.id, id = it.id,
label = it.label, label = it.label,
description = it.description, description = it.description,
@ -56,7 +61,7 @@ class CharacterSheetJsonFactory(
) )
}, },
occupations = sheet.specialSkills.map { occupations = sheet.specialSkills.map {
CharacterSheetJsonV1.Skill( CharacterSheetJsonV2.Skill(
id = it.id, id = it.id,
label = it.label, label = it.label,
description = it.description, description = it.description,
@ -68,7 +73,7 @@ class CharacterSheetJsonFactory(
) )
}, },
magics = sheet.magicSkills.map { magics = sheet.magicSkills.map {
CharacterSheetJsonV1.Skill( CharacterSheetJsonV2.Skill(
id = it.id, id = it.id,
label = it.label, label = it.label,
description = it.description, description = it.description,
@ -80,7 +85,7 @@ class CharacterSheetJsonFactory(
) )
}, },
rolls = sheet.actions.map { rolls = sheet.actions.map {
CharacterSheetJsonV1.Roll( CharacterSheetJsonV2.Roll(
id = it.id, id = it.id,
label = it.label, label = it.label,
description = it.description, description = it.description,

View file

@ -19,13 +19,57 @@ class CharacterSheetJsonV1Factory(
externalLink = json.externalLink, externalLink = json.externalLink,
level = json.level, level = json.level,
shouldLevelUp = json.shouldLevelUp ?: false, shouldLevelUp = json.shouldLevelUp ?: false,
strength = json.strength, characteristics = listOf(
dexterity = json.dexterity, CharacterSheet.Characteristic(
constitution = json.constitution, id = CharacterSheet.CharacteristicId.STR,
height = json.height, label = "Force",
intelligence = json.intelligence, description = "La Force représente essentiellement la puissance musculaire du personnage. Elle ne décrit pas nécessairement la masse musculaire brute, mais lefficacité 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",
power = json.power, base = json.strength,
charisma = json.charisma, 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 quun 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 = "LIntelligence représente la capacité de discernement du personnage. Elle ne mesure pas nécessairement la somme dinformations mémorisées, mais laptitude au raisonnement, lacuité intellectuelle, la capacité à résoudre des problèmes et lintuition.\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 lagilité 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 lattraction que le personnage exerce sur les autres. Un personnage avec un CHA élevé se remarque dans une foule en raison dune 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, damage = json.damage ?: 0,
fatigue = json.fatigue ?: 0, fatigue = json.fatigue ?: 0,
diminished = json.diminished ?: 0, diminished = json.diminished ?: 0,

View file

@ -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(),
)
}
}

View file

@ -4,6 +4,13 @@ package com.pixelized.shared.lwa.usecase
import com.pixelized.shared.lwa.model.AlteredCharacterSheet import com.pixelized.shared.lwa.model.AlteredCharacterSheet
import com.pixelized.shared.lwa.model.alteration.FieldAlteration import com.pixelized.shared.lwa.model.alteration.FieldAlteration
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet 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.Expression
import com.pixelized.shared.lwa.parser.expression.ExpressionParser import com.pixelized.shared.lwa.parser.expression.ExpressionParser
import com.pixelized.shared.lwa.parser.word.Word import com.pixelized.shared.lwa.parser.word.Word
@ -128,8 +135,8 @@ class ExpressionUseCase(
Word.Type.BDC -> evaluate( Word.Type.BDC -> evaluate(
expression = expressionParser.parse( expression = expressionParser.parse(
characterSheetUseCase.meleeBonusDamage( characterSheetUseCase.meleeBonusDamage(
strength = sheet.strength, strength = sheet.characteristic(id = STR),
height = sheet.height, height = sheet.characteristic(id = HEI),
) )
) )
) )
@ -137,19 +144,19 @@ class ExpressionUseCase(
Word.Type.BDD -> evaluate( Word.Type.BDD -> evaluate(
expression = expressionParser.parse( expression = expressionParser.parse(
characterSheetUseCase.distanceBonusDamage( characterSheetUseCase.distanceBonusDamage(
strength = sheet.strength, strength = sheet.characteristic(id = STR),
height = sheet.height, height = sheet.characteristic(id = HEI),
) )
) )
) )
Word.Type.STR -> sheet.strength Word.Type.STR -> sheet.characteristic(id = STR)
Word.Type.DEX -> sheet.dexterity Word.Type.DEX -> sheet.characteristic(id = DEX)
Word.Type.CON -> sheet.constitution Word.Type.CON -> sheet.characteristic(id = CON)
Word.Type.HEI -> sheet.height Word.Type.HEI -> sheet.characteristic(id = HEI)
Word.Type.INT -> sheet.intelligence Word.Type.INT -> sheet.characteristic(id = INT)
Word.Type.POW -> sheet.power Word.Type.POW -> sheet.characteristic(id = POW)
Word.Type.CHA -> sheet.charisma Word.Type.CHA -> sheet.characteristic(id = CHA)
} }
null -> 0 null -> 0