Add support for the diminished state.
This commit is contained in:
parent
1fe75062b7
commit
d8ce46fe43
20 changed files with 337 additions and 155 deletions
|
|
@ -32,8 +32,8 @@ class CampaignRepository(
|
|||
}
|
||||
|
||||
fun characterInstance(
|
||||
chracterInstanceId: Campaign.CharacterInstance.Id,
|
||||
characterInstanceId: Campaign.CharacterInstance.Id,
|
||||
): Campaign.CharacterInstance {
|
||||
return campaignFlow.value.character(chracterInstanceId)
|
||||
return campaignFlow.value.character(characterInstanceId)
|
||||
}
|
||||
}
|
||||
|
|
@ -5,9 +5,10 @@ import com.pixelized.desktop.lwa.repository.network.NetworkRepository
|
|||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||
import com.pixelized.shared.lwa.model.campaign.CampaignJsonFactory
|
||||
import com.pixelized.shared.lwa.model.campaign.character
|
||||
import com.pixelized.shared.lwa.model.campaign.npc
|
||||
import com.pixelized.shared.lwa.protocol.websocket.Message
|
||||
import com.pixelized.shared.lwa.protocol.websocket.payload.CampaignMessage
|
||||
import com.pixelized.shared.lwa.protocol.websocket.payload.RestSynchronisation
|
||||
import com.pixelized.shared.lwa.protocol.websocket.payload.UpdatePlayerCharacteristicMessage
|
||||
import com.pixelized.shared.lwa.usecase.CampaignUseCase
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
@ -46,21 +47,7 @@ class CampaignStore(
|
|||
return data
|
||||
}
|
||||
|
||||
private fun updateCharacteristic(
|
||||
characterId: Campaign.CharacterInstance.Id,
|
||||
characteristic: Campaign.CharacterInstance.Characteristic,
|
||||
value: Int,
|
||||
) {
|
||||
val campaign = _campaignFlow.value
|
||||
val characters = campaign.characters.toMutableMap().also {
|
||||
it[characterId] = useCase.updateCharacteristic(
|
||||
character = campaign.character(id = characterId),
|
||||
characteristic = characteristic,
|
||||
value = value
|
||||
)
|
||||
}
|
||||
_campaignFlow.value = _campaignFlow.value.copy(characters = characters)
|
||||
}
|
||||
// region : WebSocket message Handling.
|
||||
|
||||
private suspend fun handleMessage(message: Message) {
|
||||
when (val payload = message.value) {
|
||||
|
|
@ -68,17 +55,89 @@ class CampaignStore(
|
|||
update()
|
||||
}
|
||||
|
||||
is UpdatePlayerCharacteristicMessage -> {
|
||||
val id = factory.convertFromV1(characterInstanceIdJson = payload.characterInstanceId)
|
||||
val characteristic = factory.convertFromV1(characteristicJson = payload.characteristic)
|
||||
updateCharacteristic(
|
||||
characterId = id,
|
||||
characteristic = characteristic,
|
||||
is CampaignMessage -> {
|
||||
val instanceId = Campaign.CharacterInstance.Id(
|
||||
characterSheetId = payload.characterSheetId,
|
||||
instanceId = payload.instanceId,
|
||||
)
|
||||
when (payload) {
|
||||
is CampaignMessage.UpdateCharacteristic -> updateCharacteristic(
|
||||
characterInstanceId = instanceId,
|
||||
characteristic = factory.convertFromV1(characteristicJson = payload.characteristic),
|
||||
value = payload.value,
|
||||
)
|
||||
|
||||
is CampaignMessage.UpdateDiminished -> updateDiminished(
|
||||
characterInstanceId = instanceId,
|
||||
diminished = payload.diminished,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateCharacteristic(
|
||||
characterInstanceId: Campaign.CharacterInstance.Id,
|
||||
characteristic: Campaign.CharacterInstance.Characteristic,
|
||||
value: Int,
|
||||
) {
|
||||
val campaign = _campaignFlow.value
|
||||
|
||||
when {
|
||||
campaign.characters.containsKey(characterInstanceId) -> {
|
||||
val characters = campaign.characters.toMutableMap().also {
|
||||
it[characterInstanceId] = useCase.updateCharacteristic(
|
||||
instance = campaign.character(id = characterInstanceId),
|
||||
characteristic = characteristic,
|
||||
value = value
|
||||
)
|
||||
}
|
||||
_campaignFlow.value = _campaignFlow.value.copy(characters = characters)
|
||||
}
|
||||
|
||||
campaign.npcs.containsKey(characterInstanceId) -> {
|
||||
val npcs = campaign.npcs.toMutableMap().also {
|
||||
it[characterInstanceId] = useCase.updateCharacteristic(
|
||||
instance = campaign.npc(id = characterInstanceId),
|
||||
characteristic = characteristic,
|
||||
value = value
|
||||
)
|
||||
}
|
||||
_campaignFlow.value = _campaignFlow.value.copy(npcs = npcs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateDiminished(
|
||||
characterInstanceId: Campaign.CharacterInstance.Id,
|
||||
diminished: Int,
|
||||
) {
|
||||
val campaign = _campaignFlow.value
|
||||
|
||||
when {
|
||||
campaign.characters.containsKey(characterInstanceId) -> {
|
||||
val characters = campaign.characters.toMutableMap().also {
|
||||
it[characterInstanceId] = useCase.updateDiminished(
|
||||
instance = campaign.character(id = characterInstanceId),
|
||||
diminished = diminished,
|
||||
)
|
||||
}
|
||||
_campaignFlow.value = _campaignFlow.value.copy(characters = characters)
|
||||
}
|
||||
|
||||
campaign.npcs.containsKey(characterInstanceId) -> {
|
||||
val npcs = campaign.npcs.toMutableMap().also {
|
||||
it[characterInstanceId] = useCase.updateDiminished(
|
||||
instance = campaign.npc(id = characterInstanceId),
|
||||
diminished = diminished,
|
||||
)
|
||||
}
|
||||
_campaignFlow.value = _campaignFlow.value.copy(npcs = npcs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ import com.pixelized.shared.lwa.model.campaign.Campaign
|
|||
import com.pixelized.shared.lwa.model.campaign.Campaign.CharacterInstance.Characteristic
|
||||
import com.pixelized.shared.lwa.model.campaign.CampaignJsonFactory
|
||||
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
|
||||
import com.pixelized.shared.lwa.protocol.websocket.payload.UpdatePlayerCharacteristicMessage
|
||||
import com.pixelized.shared.lwa.protocol.websocket.payload.CampaignMessage
|
||||
|
||||
class CharacterDetailCharacteristicDialogViewModel(
|
||||
private val characterSheetRepository: CharacterSheetRepository,
|
||||
|
|
@ -42,7 +42,7 @@ class CharacterDetailCharacteristicDialogViewModel(
|
|||
characterSheetId = characterInstanceId.characterSheetId,
|
||||
)
|
||||
val characterInstance: Campaign.CharacterInstance = campaignRepository.characterInstance(
|
||||
chracterInstanceId = characterInstanceId,
|
||||
characterInstanceId = characterInstanceId,
|
||||
)
|
||||
val alterations: Map<String, List<FieldAlteration>> = alterationRepository.alterations(
|
||||
characterInstanceId = characterInstanceId,
|
||||
|
|
@ -61,42 +61,33 @@ class CharacterDetailCharacteristicDialogViewModel(
|
|||
characteristic: Characteristic,
|
||||
value: Int,
|
||||
) {
|
||||
// fetch the linked character sheet
|
||||
// fetch the linked character sheet, if null stop exit this function.
|
||||
val sheet = characterSheetRepository.characterDetail(
|
||||
characterSheetId = characterInstanceId.characterSheetId,
|
||||
)
|
||||
) ?: return
|
||||
val alterations = alterationRepository.alterations(
|
||||
characterInstanceId = characterInstanceId,
|
||||
)
|
||||
// we need the maximum HP / Power that the character sheet have.
|
||||
if (sheet != null) {
|
||||
val alteredSheet = alteredCharacterSheetFactory.sheet(
|
||||
characterSheet = sheet,
|
||||
alterations = alterations,
|
||||
)
|
||||
// convert the data to json format
|
||||
val characterInstanceIdJson = campaignJsonFactory.convertToJson(
|
||||
id = characterInstanceId,
|
||||
)
|
||||
val characteristicJson = campaignJsonFactory.convertToJson(
|
||||
characteristic = characteristic,
|
||||
)
|
||||
// share the data through the websocket.
|
||||
network.share(
|
||||
payload = UpdatePlayerCharacteristicMessage(
|
||||
characterInstanceId = characterInstanceIdJson,
|
||||
payload = CampaignMessage.UpdateCharacteristic(
|
||||
characterSheetId = characterInstanceId.characterSheetId,
|
||||
instanceId = characterInstanceId.instanceId,
|
||||
characteristic = characteristicJson,
|
||||
value = when (characteristic) {
|
||||
Characteristic.Damage -> {
|
||||
alteredSheet.maxHp - value
|
||||
}
|
||||
|
||||
Characteristic.Power -> {
|
||||
alteredSheet.maxPp - value
|
||||
}
|
||||
Characteristic.Damage -> alteredSheet.maxHp - value
|
||||
Characteristic.Power -> alteredSheet.maxPp - value
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -181,11 +181,13 @@ fun CampaignScreen(
|
|||
DiminishedStatDialog(
|
||||
dialog = dismissedViewModel.diminishedDialog,
|
||||
onConfirm = { diminished ->
|
||||
scope.launch {
|
||||
dismissedViewModel.changeDiminished(
|
||||
dialog = diminished
|
||||
)
|
||||
blurController.hide()
|
||||
dismissedViewModel.hideDiminishedDialog()
|
||||
}
|
||||
},
|
||||
onDismissRequest = {
|
||||
blurController.hide()
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ class CharacterDetailFactory(
|
|||
return CharacterDetailHeaderUio(
|
||||
id = characterInstanceId,
|
||||
portrait = alteredCharacterSheet.portrait,
|
||||
diminished = characterInstance.diminished,
|
||||
name = alteredCharacterSheet.name,
|
||||
hp = "${maxHp - characterInstance.damage}",
|
||||
maxHp = "$maxHp",
|
||||
|
|
@ -71,6 +72,7 @@ class CharacterDetailFactory(
|
|||
suspend fun convertToCharacterDetailSheetUio(
|
||||
characterInstanceId: Campaign.CharacterInstance.Id,
|
||||
characterSheet: CharacterSheet?,
|
||||
characterInstance: Campaign.CharacterInstance,
|
||||
alterations: Map<String, List<FieldAlteration>>,
|
||||
): CharacterDetailSheetUio? {
|
||||
if (characterSheet == null) return null
|
||||
|
|
@ -94,7 +96,7 @@ class CharacterDetailFactory(
|
|||
characterSheetId = characterSheet.id,
|
||||
label = getString(Res.string.character_sheet__characteristics__str),
|
||||
rollAction = "1d100",
|
||||
rollSuccessValue = alteredCharacterSheet.strength * 5,
|
||||
rollSuccessValue = alteredCharacterSheet.strength * 5 - characterInstance.diminished,
|
||||
),
|
||||
),
|
||||
CharacterDetailSheetCharacteristicUio(
|
||||
|
|
@ -108,7 +110,7 @@ class CharacterDetailFactory(
|
|||
characterSheetId = characterSheet.id,
|
||||
label = getString(Res.string.character_sheet__characteristics__dex),
|
||||
rollAction = "1d100",
|
||||
rollSuccessValue = alteredCharacterSheet.dexterity * 5,
|
||||
rollSuccessValue = alteredCharacterSheet.dexterity * 5 - characterInstance.diminished,
|
||||
),
|
||||
),
|
||||
CharacterDetailSheetCharacteristicUio(
|
||||
|
|
@ -122,7 +124,7 @@ class CharacterDetailFactory(
|
|||
characterSheetId = characterSheet.id,
|
||||
label = getString(Res.string.character_sheet__characteristics__con),
|
||||
rollAction = "1d100",
|
||||
rollSuccessValue = alteredCharacterSheet.constitution * 5,
|
||||
rollSuccessValue = alteredCharacterSheet.constitution * 5 - characterInstance.diminished,
|
||||
),
|
||||
),
|
||||
CharacterDetailSheetCharacteristicUio(
|
||||
|
|
@ -136,7 +138,7 @@ class CharacterDetailFactory(
|
|||
characterSheetId = characterSheet.id,
|
||||
label = getString(Res.string.character_sheet__characteristics__hei),
|
||||
rollAction = "1d100",
|
||||
rollSuccessValue = alteredCharacterSheet.height * 5,
|
||||
rollSuccessValue = alteredCharacterSheet.height * 5 - characterInstance.diminished,
|
||||
),
|
||||
),
|
||||
CharacterDetailSheetCharacteristicUio(
|
||||
|
|
@ -150,7 +152,7 @@ class CharacterDetailFactory(
|
|||
characterSheetId = characterSheet.id,
|
||||
label = getString(Res.string.character_sheet__characteristics__int),
|
||||
rollAction = "1d100",
|
||||
rollSuccessValue = alteredCharacterSheet.intelligence * 5,
|
||||
rollSuccessValue = alteredCharacterSheet.intelligence * 5 - characterInstance.diminished,
|
||||
),
|
||||
),
|
||||
CharacterDetailSheetCharacteristicUio(
|
||||
|
|
@ -164,7 +166,7 @@ class CharacterDetailFactory(
|
|||
characterSheetId = characterSheet.id,
|
||||
label = getString(Res.string.character_sheet__characteristics__pow),
|
||||
rollAction = "1d100",
|
||||
rollSuccessValue = alteredCharacterSheet.power * 5,
|
||||
rollSuccessValue = alteredCharacterSheet.power * 5 - characterInstance.diminished,
|
||||
),
|
||||
),
|
||||
CharacterDetailSheetCharacteristicUio(
|
||||
|
|
@ -178,7 +180,7 @@ class CharacterDetailFactory(
|
|||
characterSheetId = characterSheet.id,
|
||||
label = getString(Res.string.character_sheet__characteristics__cha),
|
||||
rollAction = "1d100",
|
||||
rollSuccessValue = alteredCharacterSheet.charisma * 5,
|
||||
rollSuccessValue = alteredCharacterSheet.charisma * 5 - characterInstance.diminished,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -186,6 +188,7 @@ class CharacterDetailFactory(
|
|||
val value = expressionUseCase.computeSkillValue(
|
||||
sheet = characterSheet,
|
||||
skill = skill,
|
||||
diminished = characterInstance.diminished,
|
||||
alterations = alterations,
|
||||
)
|
||||
CharacterDetailSheetSkillUio(
|
||||
|
|
@ -212,6 +215,7 @@ class CharacterDetailFactory(
|
|||
val value = expressionUseCase.computeSkillValue(
|
||||
sheet = characterSheet,
|
||||
skill = skill,
|
||||
diminished = characterInstance.diminished,
|
||||
alterations = alterations,
|
||||
)
|
||||
CharacterDetailSheetSkillUio(
|
||||
|
|
@ -238,6 +242,7 @@ class CharacterDetailFactory(
|
|||
val value = expressionUseCase.computeSkillValue(
|
||||
sheet = characterSheet,
|
||||
skill = skill,
|
||||
diminished = characterInstance.diminished,
|
||||
alterations = alterations,
|
||||
)
|
||||
CharacterDetailSheetSkillUio(
|
||||
|
|
|
|||
|
|
@ -47,12 +47,14 @@ class CharacterDetailViewModel(
|
|||
initialValue = null,
|
||||
),
|
||||
sheet = combine(
|
||||
campaignRepository.characterInstanceFlow(id = characterInstanceId),
|
||||
characterSheetRepository.characterDetailFlow(characterId = characterInstanceId.characterSheetId),
|
||||
alterationRepository.alterationsFlow(characterId = characterInstanceId),
|
||||
) { characterSheet, alterations ->
|
||||
) { characterInstance, characterSheet, alterations ->
|
||||
characterDetailFactory.convertToCharacterDetailSheetUio(
|
||||
characterInstanceId = characterInstanceId,
|
||||
characterSheet = characterSheet,
|
||||
characterInstance = characterInstance,
|
||||
alterations = alterations,
|
||||
)
|
||||
}.stateIn(
|
||||
|
|
|
|||
|
|
@ -5,31 +5,37 @@ import androidx.compose.runtime.mutableStateOf
|
|||
import androidx.compose.ui.text.TextRange
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
|
||||
import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
|
||||
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.dialog.DiminishedStatDialogUio
|
||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||
import com.pixelized.shared.lwa.protocol.websocket.payload.CampaignMessage
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__diminished__label
|
||||
import org.jetbrains.compose.resources.getString
|
||||
|
||||
class CharacterDiminishedViewModel(
|
||||
private val characterSheetRepository: CharacterSheetRepository,
|
||||
private val campaignRepository: CampaignRepository,
|
||||
private val networkRepository: NetworkRepository,
|
||||
) : ViewModel() {
|
||||
|
||||
private val _diminishedDialog = mutableStateOf<DiminishedStatDialogUio?>(null)
|
||||
val diminishedDialog: State<DiminishedStatDialogUio?> get() = _diminishedDialog
|
||||
|
||||
suspend fun showDiminishedDialog(
|
||||
characterInstanceId: Campaign.CharacterInstance.Id?,
|
||||
characterInstanceId: Campaign.CharacterInstance.Id,
|
||||
) {
|
||||
if (characterInstanceId == null) return
|
||||
|
||||
val diminished = 0 // TODO repository.characterDiminishedFlow(id = id).value
|
||||
val characterInstance = campaignRepository.characterInstance(
|
||||
characterInstanceId = characterInstanceId,
|
||||
)
|
||||
val textFieldValue = mutableStateOf(
|
||||
TextFieldValue("$diminished", selection = TextRange(index = 0))
|
||||
TextFieldValue(
|
||||
text = "${characterInstance.diminished}",
|
||||
selection = TextRange(index = 0),
|
||||
)
|
||||
)
|
||||
_diminishedDialog.value = DiminishedStatDialogUio(
|
||||
id = characterInstanceId,
|
||||
characterInstanceId = characterInstanceId,
|
||||
label = getString(resource = Res.string.character_sheet__diminished__label),
|
||||
value = { textFieldValue.value },
|
||||
onValueChange = { value ->
|
||||
|
|
@ -45,12 +51,16 @@ class CharacterDiminishedViewModel(
|
|||
_diminishedDialog.value = null
|
||||
}
|
||||
|
||||
fun changeDiminished(dialog: DiminishedStatDialogUio) {
|
||||
val value = dialog.value().text.toIntOrNull() ?: 0
|
||||
// TODO
|
||||
// repository.setDiminishedForCharacter(
|
||||
// id = dialog.id,
|
||||
// diminished = value,
|
||||
// )
|
||||
suspend fun changeDiminished(
|
||||
dialog: DiminishedStatDialogUio,
|
||||
) {
|
||||
val diminished = dialog.value().text.toIntOrNull() ?: 0
|
||||
networkRepository.share(
|
||||
payload = CampaignMessage.UpdateDiminished(
|
||||
characterSheetId = dialog.characterInstanceId.characterSheetId,
|
||||
instanceId = dialog.characterInstanceId.instanceId,
|
||||
diminished = diminished,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +1,28 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.header
|
||||
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.SizeTransform
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.animation.slideOutVertically
|
||||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.foundation.clickable
|
||||
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.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.minimumInteractiveComponentSize
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
|
|
@ -19,6 +30,7 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
|
@ -40,6 +52,7 @@ import org.jetbrains.compose.resources.painterResource
|
|||
data class CharacterDetailHeaderUio(
|
||||
val id: Campaign.CharacterInstance.Id,
|
||||
val portrait: String?,
|
||||
val diminished: Int,
|
||||
val name: String,
|
||||
val hp: String,
|
||||
val maxHp: String,
|
||||
|
|
@ -74,6 +87,7 @@ fun CharacterDetailHeader(
|
|||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
)
|
||||
Box {
|
||||
IconButton(
|
||||
onClick = onDiminished,
|
||||
) {
|
||||
|
|
@ -84,6 +98,25 @@ fun CharacterDetailHeader(
|
|||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
AnimatedContent(
|
||||
modifier = Modifier.align(alignment = Alignment.BottomCenter),
|
||||
targetState = header.value?.diminished,
|
||||
transitionSpec = {
|
||||
val sign = if ((targetState ?: 0) > (initialState ?: 0)) 1 else -1
|
||||
val enter = fadeIn() + slideInVertically { 16 * sign }
|
||||
val exit = fadeOut() + slideOutVertically { -16 * sign }
|
||||
enter togetherWith exit using SizeTransform(clip = false)
|
||||
}
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.width(width = 48.dp),
|
||||
style = MaterialTheme.typography.caption,
|
||||
color = MaterialTheme.colors.onSurface,
|
||||
textAlign = TextAlign.Center,
|
||||
text = "${it?.takeIf { it > 0 } ?: " "}",
|
||||
)
|
||||
}
|
||||
}
|
||||
IconButton(
|
||||
onClick = onDismissRequest,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -216,6 +216,7 @@ class CharacterSheetFactory(
|
|||
value = skillUseCase.computeSkillValue(
|
||||
sheet = characterSheet,
|
||||
skill = skill,
|
||||
diminished = instance.diminished,
|
||||
alterations = alterations,
|
||||
),
|
||||
tooltips = skill.description?.let {
|
||||
|
|
@ -240,6 +241,7 @@ class CharacterSheetFactory(
|
|||
value = skillUseCase.computeSkillValue(
|
||||
sheet = characterSheet,
|
||||
skill = skill,
|
||||
diminished = instance.diminished,
|
||||
alterations = alterations,
|
||||
),
|
||||
used = skill.used,
|
||||
|
|
@ -258,6 +260,7 @@ class CharacterSheetFactory(
|
|||
value = skillUseCase.computeSkillValue(
|
||||
sheet = characterSheet,
|
||||
skill = skill,
|
||||
diminished = instance.diminished,
|
||||
alterations = alterations,
|
||||
),
|
||||
used = skill.used,
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ import org.jetbrains.compose.resources.stringResource
|
|||
|
||||
@Stable
|
||||
data class DiminishedStatDialogUio(
|
||||
val id: Campaign.CharacterInstance.Id,
|
||||
val characterInstanceId: Campaign.CharacterInstance.Id,
|
||||
val label: String,
|
||||
val value: () -> TextFieldValue,
|
||||
val onValueChange: (TextFieldValue) -> Unit,
|
||||
|
|
|
|||
|
|
@ -103,16 +103,18 @@ class CampaignService(
|
|||
|
||||
// Data manipulation through WebSocket.
|
||||
|
||||
suspend fun updateCharacterCharacteristic(
|
||||
suspend fun updateCharacteristic(
|
||||
characterInstanceId: Campaign.CharacterInstance.Id,
|
||||
characteristic: Campaign.CharacterInstance.Characteristic,
|
||||
value: Int,
|
||||
) {
|
||||
when {
|
||||
campaign.characters.containsKey(characterInstanceId) -> {
|
||||
// fetch all the current campaign character
|
||||
val characters = campaign.characters.toMutableMap()
|
||||
// update the corresponding character using the use case.
|
||||
characters[characterInstanceId] = useCase.updateCharacteristic(
|
||||
character = campaign.character(id = characterInstanceId),
|
||||
instance = campaign.character(id = characterInstanceId),
|
||||
characteristic = characteristic,
|
||||
value = value,
|
||||
)
|
||||
|
|
@ -122,16 +124,12 @@ class CampaignService(
|
|||
)
|
||||
}
|
||||
|
||||
suspend fun updateNpcCharacteristic(
|
||||
npcInstanceId: Campaign.CharacterInstance.Id,
|
||||
characteristic: Campaign.CharacterInstance.Characteristic,
|
||||
value: Int,
|
||||
) {
|
||||
campaign.npcs.containsKey(characterInstanceId) -> {
|
||||
// fetch all the current campaign character
|
||||
val npcs = campaign.npcs.toMutableMap()
|
||||
// update the corresponding character using the use case.
|
||||
npcs[npcInstanceId] = useCase.updateCharacteristic(
|
||||
character = campaign.npc(id = npcInstanceId),
|
||||
npcs[characterInstanceId] = useCase.updateCharacteristic(
|
||||
instance = campaign.npc(id = characterInstanceId),
|
||||
characteristic = characteristic,
|
||||
value = value,
|
||||
)
|
||||
|
|
@ -140,4 +138,42 @@ class CampaignService(
|
|||
campaign = campaign.copy(npcs = npcs)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun updateDiminished(
|
||||
characterInstanceId: Campaign.CharacterInstance.Id,
|
||||
diminished: Int,
|
||||
) {
|
||||
when {
|
||||
campaign.characters.containsKey(characterInstanceId) -> {
|
||||
// fetch all the current campaign character
|
||||
val characters = campaign.characters.toMutableMap()
|
||||
// update the corresponding character using the use case.
|
||||
characters[characterInstanceId] = useCase.updateDiminished(
|
||||
instance = campaign.character(id = characterInstanceId),
|
||||
diminished = diminished,
|
||||
)
|
||||
// save the campaign to the disk + update the flow.
|
||||
store.save(
|
||||
campaign = campaign.copy(characters = characters)
|
||||
)
|
||||
}
|
||||
|
||||
campaign.npcs.containsKey(characterInstanceId) -> {
|
||||
// fetch all the current campaign character
|
||||
val npcs = campaign.npcs.toMutableMap()
|
||||
// update the corresponding character using the use case.
|
||||
npcs[characterInstanceId] = useCase.updateDiminished(
|
||||
instance = campaign.npc(id = characterInstanceId),
|
||||
diminished = diminished,
|
||||
)
|
||||
// save the campaign to the disk + update the flow.
|
||||
store.save(
|
||||
campaign = campaign.copy(npcs = npcs)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,6 @@ import kotlinx.coroutines.Job
|
|||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.io.File
|
||||
|
||||
|
|
@ -18,7 +17,6 @@ class CampaignStore(
|
|||
private val factory: CampaignJsonFactory,
|
||||
private val json: Json,
|
||||
) {
|
||||
|
||||
private val flow = MutableStateFlow(value = Campaign.EMPTY)
|
||||
|
||||
init {
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@ package com.pixelized.server.lwa.server
|
|||
import com.pixelized.server.lwa.model.alteration.AlterationService
|
||||
import com.pixelized.server.lwa.model.campaign.CampaignService
|
||||
import com.pixelized.server.lwa.model.character.CharacterSheetService
|
||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||
import com.pixelized.shared.lwa.model.campaign.CampaignJsonFactory
|
||||
import com.pixelized.shared.lwa.protocol.websocket.Message
|
||||
import com.pixelized.shared.lwa.protocol.websocket.payload.CampaignMessage
|
||||
import com.pixelized.shared.lwa.protocol.websocket.payload.RestSynchronisation
|
||||
import com.pixelized.shared.lwa.protocol.websocket.payload.RollMessage
|
||||
import com.pixelized.shared.lwa.protocol.websocket.payload.UpdatePlayerCharacteristicMessage
|
||||
import com.pixelized.shared.lwa.protocol.websocket.payload.UpdateSkillUsageMessage
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
|
||||
|
|
@ -24,12 +25,23 @@ class Engine(
|
|||
|
||||
is RollMessage -> Unit // Nothing to do here.
|
||||
|
||||
is UpdatePlayerCharacteristicMessage -> {
|
||||
campaignService.updateCharacterCharacteristic(
|
||||
characterInstanceId = campaignJsonFactory.convertFromV1(characterInstanceIdJson = data.characterInstanceId),
|
||||
is CampaignMessage -> {
|
||||
val instanceId = Campaign.CharacterInstance.Id(
|
||||
characterSheetId = data.characterSheetId,
|
||||
instanceId = data.instanceId,
|
||||
)
|
||||
when (data) {
|
||||
is CampaignMessage.UpdateCharacteristic -> campaignService.updateCharacteristic(
|
||||
characterInstanceId = instanceId,
|
||||
characteristic = campaignJsonFactory.convertFromV1(characteristicJson = data.characteristic),
|
||||
value = data.value,
|
||||
)
|
||||
|
||||
is CampaignMessage.UpdateDiminished -> campaignService.updateDiminished(
|
||||
characterInstanceId = instanceId,
|
||||
diminished = data.diminished,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is UpdateSkillUsageMessage -> characterService.updateCharacterSkillUsage(
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ data class Campaign(
|
|||
) {
|
||||
data class CharacterInstance(
|
||||
val characteristic: Map<Characteristic, Int>,
|
||||
val diminished: Int,
|
||||
) {
|
||||
data class Id(
|
||||
val characterSheetId: String,
|
||||
|
|
@ -16,6 +17,13 @@ data class Campaign(
|
|||
Damage,
|
||||
Power,
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun empty() = CharacterInstance(
|
||||
characteristic = emptyMap(),
|
||||
diminished = 0,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
@ -27,15 +35,11 @@ data class Campaign(
|
|||
}
|
||||
|
||||
fun Campaign.character(id: Campaign.CharacterInstance.Id): Campaign.CharacterInstance {
|
||||
return characters[id] ?: Campaign.CharacterInstance(
|
||||
characteristic = emptyMap(),
|
||||
)
|
||||
return characters[id] ?: Campaign.CharacterInstance.empty()
|
||||
}
|
||||
|
||||
fun Campaign.npc(id: Campaign.CharacterInstance.Id): Campaign.CharacterInstance {
|
||||
return npcs[id] ?: Campaign.CharacterInstance(
|
||||
characteristic = emptyMap(),
|
||||
)
|
||||
return npcs[id] ?: Campaign.CharacterInstance.empty()
|
||||
}
|
||||
|
||||
val Campaign.CharacterInstance.level
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ class CampaignJsonFactory {
|
|||
characteristic = characterInstanceJson.characteristic
|
||||
.map { char -> convertFromV1(characteristicJson = char.key) to char.value }
|
||||
.toMap(),
|
||||
diminished = characterInstanceJson.diminished ?: 0,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -85,6 +86,7 @@ class CampaignJsonFactory {
|
|||
characteristic = data.characteristic
|
||||
.map { char -> convertToJson(characteristic = char.key) to char.value }
|
||||
.toMap(),
|
||||
diminished = data.diminished,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ data class CampaignJsonV1(
|
|||
@Serializable
|
||||
data class CharacterInstanceJson(
|
||||
val characteristic: Map<Characteristic, Int>,
|
||||
val diminished: Int?,
|
||||
) {
|
||||
enum class Characteristic {
|
||||
Damage,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
package com.pixelized.shared.lwa.protocol.websocket.payload
|
||||
|
||||
import com.pixelized.shared.lwa.model.campaign.CampaignJsonV1
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
sealed interface CampaignMessage : MessagePayload {
|
||||
val characterSheetId: String
|
||||
val instanceId: Int
|
||||
|
||||
@Serializable
|
||||
data class UpdateCharacteristic(
|
||||
override val characterSheetId: String,
|
||||
override val instanceId: Int,
|
||||
val characteristic: CampaignJsonV1.CharacterInstanceJson.Characteristic,
|
||||
val value: Int,
|
||||
) : CampaignMessage
|
||||
|
||||
@Serializable
|
||||
data class UpdateDiminished(
|
||||
override val characterSheetId: String,
|
||||
override val instanceId: Int,
|
||||
val diminished: Int,
|
||||
) : CampaignMessage
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
package com.pixelized.shared.lwa.protocol.websocket.payload
|
||||
|
||||
import com.pixelized.shared.lwa.model.campaign.CampaignJsonV1
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class UpdatePlayerCharacteristicMessage(
|
||||
val characterInstanceId: String,
|
||||
val characteristic: CampaignJsonV1.CharacterInstanceJson.Characteristic,
|
||||
val value: Int,
|
||||
) : MessagePayload
|
||||
|
|
@ -5,14 +5,23 @@ import com.pixelized.shared.lwa.model.campaign.Campaign
|
|||
class CampaignUseCase {
|
||||
|
||||
fun updateCharacteristic(
|
||||
character: Campaign.CharacterInstance,
|
||||
instance: Campaign.CharacterInstance,
|
||||
characteristic: Campaign.CharacterInstance.Characteristic,
|
||||
value: Int,
|
||||
): Campaign.CharacterInstance {
|
||||
return character.copy(
|
||||
characteristic = character.characteristic.toMutableMap().also {
|
||||
return instance.copy(
|
||||
characteristic = instance.characteristic.toMutableMap().also {
|
||||
it[characteristic] = value
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun updateDiminished(
|
||||
instance: Campaign.CharacterInstance,
|
||||
diminished: Int,
|
||||
): Campaign.CharacterInstance {
|
||||
return instance.copy(
|
||||
diminished = diminished,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@ class ExpressionUseCase(
|
|||
fun computeSkillValue(
|
||||
sheet: CharacterSheet,
|
||||
alterations: Map<String, List<FieldAlteration>>,
|
||||
diminished: Int,
|
||||
skill: CharacterSheet.Skill,
|
||||
): Int {
|
||||
val context = Context(
|
||||
|
|
@ -51,7 +52,7 @@ class ExpressionUseCase(
|
|||
context.evaluate(it.expression)
|
||||
} ?: 0
|
||||
|
||||
return max(base + bonus + level + alteration, 0)
|
||||
return max(base + bonus + level + alteration - diminished, 0)
|
||||
}
|
||||
|
||||
fun computeRoll(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue