From 81b74cd03fd6651f3f3eeee740a801da4afa2452 Mon Sep 17 00:00:00 2001 From: Thomas Andres Gomez Date: Mon, 9 Oct 2023 17:35:44 +0200 Subject: [PATCH] Fix skill throw bonus. --- .../rplexicon/business/DiceThrowUseCase.kt | 40 +++++++++- .../composable/actions/AlterationHeader.kt | 74 +++++++++++++++++++ .../composable/actions/AttackHeader.kt | 4 +- .../composable/actions/SkillHeader.kt | 5 +- .../character/factory/SpellUioFactory.kt | 3 + .../pages/actions/SkillsViewModel.kt | 44 +++++++++-- .../pages/alteration/AlterationPage.kt | 6 ++ .../rplexicon/ui/screens/rolls/RollOverlay.kt | 4 +- .../ui/screens/rolls/factory/DiceFactory.kt | 9 +++ app/src/main/res/values-fr/strings.xml | 7 +- app/src/main/res/values/strings.xml | 7 +- 11 files changed, 178 insertions(+), 25 deletions(-) create mode 100644 app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/AlterationHeader.kt diff --git a/app/src/main/java/com/pixelized/rplexicon/business/DiceThrowUseCase.kt b/app/src/main/java/com/pixelized/rplexicon/business/DiceThrowUseCase.kt index 977860a..93fbfec 100644 --- a/app/src/main/java/com/pixelized/rplexicon/business/DiceThrowUseCase.kt +++ b/app/src/main/java/com/pixelized/rplexicon/business/DiceThrowUseCase.kt @@ -442,6 +442,8 @@ class DiceThrowUseCase @Inject constructor( skill = diceThrow.skill, ) skillThrow( + character = sheet, + alterations = alterations, skill = skill, ) } @@ -908,6 +910,8 @@ class DiceThrowUseCase @Inject constructor( } private fun skillThrow( + character: CharacterSheet, + alterations: Map>, skill: Skill?, ): DiceThrowResult { // retrieve some wording. @@ -924,6 +928,40 @@ class DiceThrowUseCase @Inject constructor( ) allValue.add(result.value) + // fetch and build the associated characteristic + val relatedStatBonus = skill?.effect?.modifier?.mapNotNull { property -> + when (property) { + Property.STRENGTH -> (character.strength + alterations[property].sum).modifier + Property.DEXTERITY -> (character.dexterity + alterations[property].sum).modifier + Property.CONSTITUTION -> (character.constitution + alterations[property].sum).modifier + Property.INTELLIGENCE -> (character.intelligence + alterations[property].sum).modifier + Property.WISDOM -> (character.wisdom + alterations[property].sum).modifier + Property.CHARISMA -> (character.charisma + alterations[property].sum).modifier + Property.PROFICIENCY -> character.proficiency + else -> null + }?.let { value -> + val titleLabel = if (property == Property.PROFICIENCY) { + application.getString(R.string.dice_roll_mastery_proficiency, skill) + } else { + val label = when (property) { + Property.STRENGTH -> application.getString(R.string.character_sheet_stat_strength) + Property.DEXTERITY -> application.getString(R.string.character_sheet_stat_dexterity) + Property.CONSTITUTION -> application.getString(R.string.character_sheet_stat_constitution) + Property.INTELLIGENCE -> application.getString(R.string.character_sheet_stat_intelligence) + Property.WISDOM -> application.getString(R.string.character_sheet_stat_wisdom) + Property.CHARISMA -> application.getString(R.string.character_sheet_stat_charisma) + else -> "" + } + application.getString(R.string.dice_roll_bonus_detail, label) + } + allValue.add(value) + ThrowsCardUio.Detail( + title = titleLabel, + result = "$value", + ) + } + } ?: emptyList() + // build the result. return DiceThrowResult( dice = RollDiceUio( @@ -946,7 +984,7 @@ class DiceThrowUseCase @Inject constructor( ), result = "${result.value}", ), - ), + ) + relatedStatBonus, ) ) } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/AlterationHeader.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/AlterationHeader.kt new file mode 100644 index 0000000..e04ab54 --- /dev/null +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/AlterationHeader.kt @@ -0,0 +1,74 @@ +package com.pixelized.rplexicon.ui.screens.character.composable.actions + +import android.content.res.Configuration.UI_MODE_NIGHT_NO +import android.content.res.Configuration.UI_MODE_NIGHT_YES +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Divider +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.pixelized.rplexicon.R +import com.pixelized.rplexicon.ui.theme.LexiconTheme +import com.pixelized.rplexicon.utilitary.extentions.lexicon + + +@Composable +fun AlterationHeader( + modifier: Modifier = Modifier, + padding: PaddingValues = PaddingValues(horizontal = 16.dp), +) { + Column( + modifier = modifier, + ) { + Surface( + modifier = Modifier.fillMaxWidth(), + ) { + Text( + modifier = Modifier.padding(paddingValues = padding), + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Bold, + overflow = TextOverflow.Ellipsis, + maxLines = 1, + text = stringResource(id = R.string.character_sheet_title_alteration).let { + AnnotatedString( + text = it, + spanStyles = listOf( + AnnotatedString.Range( + item = MaterialTheme.lexicon.typography.bodyDropCapSpan, + start = 0, + end = Integer.min(1, it.length), + ) + ) + ) + }, + ) + } + Divider( + modifier = Modifier.padding(paddingValues = padding), + color = MaterialTheme.lexicon.colorScheme.placeholder, + ) + } +} + + +@Composable +@Preview(uiMode = UI_MODE_NIGHT_NO) +@Preview(uiMode = UI_MODE_NIGHT_YES) +private fun AlterationPreview() { + LexiconTheme { + Surface { + AlterationHeader() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/AttackHeader.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/AttackHeader.kt index 124cb3b..3d7d47d 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/AttackHeader.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/AttackHeader.kt @@ -40,7 +40,7 @@ fun AttackHeader( fontWeight = FontWeight.Bold, overflow = TextOverflow.Ellipsis, maxLines = 1, - text = stringResource(id = R.string.character_sheet_attack_title).let { + text = stringResource(id = R.string.character_sheet_title_attacks).let { AnnotatedString( text = it, spanStyles = listOf( @@ -65,7 +65,7 @@ fun AttackHeader( @Composable @Preview(uiMode = UI_MODE_NIGHT_NO) @Preview(uiMode = UI_MODE_NIGHT_YES) -private fun SkillHeaderPreview() { +private fun AttackHeaderPreview() { LexiconTheme { Surface { SkillHeader() diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/SkillHeader.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/SkillHeader.kt index ccb4c91..0b6f4a6 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/SkillHeader.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/SkillHeader.kt @@ -2,18 +2,15 @@ package com.pixelized.rplexicon.ui.screens.character.composable.actions import android.content.res.Configuration.UI_MODE_NIGHT_NO import android.content.res.Configuration.UI_MODE_NIGHT_YES -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.material3.Divider import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString @@ -43,7 +40,7 @@ fun SkillHeader( fontWeight = FontWeight.Bold, overflow = TextOverflow.Ellipsis, maxLines = 1, - text = stringResource(id = R.string.character_sheet_skill_title).let { + text = stringResource(id = R.string.character_sheet_title_skills).let { AnnotatedString( text = it, spanStyles = listOf( diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/factory/SpellUioFactory.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/factory/SpellUioFactory.kt index cb21f12..25d3622 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/factory/SpellUioFactory.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/factory/SpellUioFactory.kt @@ -31,6 +31,9 @@ class SpellUioFactory @Inject constructor() { val modifier = dice.modifier.sumOf { when (it) { Property.PROFICIENCY -> characterSheet.proficiency + Property.STRENGTH -> characterSheet.strength.modifier + Property.DEXTERITY -> characterSheet.dexterity.modifier + Property.CONSTITUTION -> characterSheet.constitution.modifier Property.INTELLIGENCE -> characterSheet.intelligence.modifier Property.WISDOM -> characterSheet.wisdom.modifier Property.CHARISMA -> characterSheet.charisma.modifier diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/SkillsViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/SkillsViewModel.kt index 424454d..d3c9011 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/SkillsViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/SkillsViewModel.kt @@ -6,14 +6,20 @@ import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope +import com.pixelized.rplexicon.model.CharacterSheet +import com.pixelized.rplexicon.model.CharacterSheetFire import com.pixelized.rplexicon.model.DiceThrow +import com.pixelized.rplexicon.model.Property +import com.pixelized.rplexicon.model.Skill import com.pixelized.rplexicon.repository.authentication.FirebaseRepository +import com.pixelized.rplexicon.repository.data.CharacterSheetRepository import com.pixelized.rplexicon.repository.data.DescriptionRepository import com.pixelized.rplexicon.repository.data.SkillRepository import com.pixelized.rplexicon.ui.composable.edit.SkillEditDialogUio import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument import com.pixelized.rplexicon.ui.screens.character.composable.actions.SkillItemUio import com.pixelized.rplexicon.utilitary.extentions.icon +import com.pixelized.rplexicon.utilitary.extentions.modifier import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.combine @@ -23,6 +29,7 @@ import javax.inject.Inject @HiltViewModel class SkillsViewModel @Inject constructor( + private val sheetRepository: CharacterSheetRepository, private val skillRepository: SkillRepository, private val firebaseRepository: FirebaseRepository, private val descriptionRepository: DescriptionRepository, @@ -43,15 +50,30 @@ class SkillsViewModel @Inject constructor( init { viewModelScope.launch { launch(Dispatchers.IO) { - skillRepository.skills - .combine(firebaseRepository.getCharacter(character = character)) { sheets, fire -> - sheets[character] to fire + sheetRepository.data + .combine(skillRepository.skills) { sheets, skills -> + Struct(sheet = sheets[character], skill = skills[character] ?: emptyList()) + } + .combine(firebaseRepository.getCharacter(character = character)) { data, fire -> + data.apply { this.fire = fire } } .collect { data -> - val (values, fire) = data + val (character, values, fire) = data - val skills = values?.map { skill -> + val skills = values.map { skill -> val description = descriptionRepository.find(name = skill.name) + val modifier = skill.effect?.modifier?.sumOf { + when (it) { + Property.PROFICIENCY -> character?.proficiency ?: 0 + Property.STRENGTH -> character?.strength?.modifier ?: 0 + Property.DEXTERITY -> character?.dexterity?.modifier ?: 0 + Property.CONSTITUTION -> character?.constitution?.modifier ?: 0 + Property.INTELLIGENCE -> character?.intelligence?.modifier ?: 0 + Property.WISDOM -> character?.wisdom?.modifier ?: 0 + Property.CHARISMA -> character?.charisma?.modifier ?: 0 + else -> 0 + } + } ?: 0 SkillItemUio( label = skill.name, translate = description?.original, @@ -60,14 +82,14 @@ class SkillsViewModel @Inject constructor( effect = skill.effect?.let { SkillItemUio.Dice( icon = it.faces.icon, - label = "${it.amount}d${it.faces}", + label = "${skill.effect.amount}d${skill.effect.faces}${if (modifier > 0) "+$modifier" else ""}", ) }, - value = fire.skills[skill.name], + value = fire?.skills?.get(skill.name) ?: 0, max = skill.amount, haveDetail = description?.description != null, ) - } ?: emptyList() + } withContext(Dispatchers.Main) { _skills.value = skills @@ -116,4 +138,10 @@ class SkillsViewModel @Inject constructor( firebaseRepository.setSkill(character = character, name = id, value = value) hideSkillEditDialog() } + + data class Struct( + val sheet: CharacterSheet?, + val skill: List, + var fire: CharacterSheetFire? = null + ) } \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/alteration/AlterationPage.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/alteration/AlterationPage.kt index 8d633f3..4716fa0 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/alteration/AlterationPage.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/alteration/AlterationPage.kt @@ -2,6 +2,7 @@ package com.pixelized.rplexicon.ui.screens.character.pages.alteration import android.content.res.Configuration.UI_MODE_NIGHT_NO import android.content.res.Configuration.UI_MODE_NIGHT_YES +import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.lazy.LazyColumn @@ -17,6 +18,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import androidx.hilt.navigation.compose.hiltViewModel +import com.pixelized.rplexicon.ui.screens.character.composable.actions.AlterationHeader import com.pixelized.rplexicon.ui.screens.character.composable.actions.AlterationItem import com.pixelized.rplexicon.ui.screens.character.composable.actions.AlterationItemUio import com.pixelized.rplexicon.ui.screens.rolls.preview.rememberRollAlterations @@ -48,6 +50,7 @@ fun AlterationPage( ) } +@OptIn(ExperimentalFoundationApi::class) @Composable fun AlterationPageContent( modifier: Modifier = Modifier, @@ -59,6 +62,9 @@ fun AlterationPageContent( modifier = modifier, contentPadding = PaddingValues(top = 8.dp, bottom = 16.dp), ) { + stickyHeader { + AlterationHeader() + } items(items = alterations.value) { AlterationItem( modifier = Modifier.fillMaxWidth(), diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/RollOverlay.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/RollOverlay.kt index fef0f82..ad0f463 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/RollOverlay.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/RollOverlay.kt @@ -164,7 +164,7 @@ private fun RollOverlayContent( Text( modifier = Modifier.padding(horizontal = 16.dp), style = MaterialTheme.typography.titleMedium, - text = stringResource(id = R.string.dice_roll_alteraton_action).let { + text = stringResource(id = R.string.dice_roll_alteration_action).let { AnnotatedString( text = it, spanStyles = listOf( @@ -246,7 +246,7 @@ private fun RollOverlayContent( TextButton(onClick = onMenu) { Text( modifier = Modifier.padding(horizontal = 8.dp), - text = stringResource(id = R.string.dice_roll_alteraton_action), + text = stringResource(id = R.string.dice_roll_alteration_action), ) } } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/factory/DiceFactory.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/factory/DiceFactory.kt index 9ce7a57..bef1b4c 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/factory/DiceFactory.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/factory/DiceFactory.kt @@ -3,6 +3,7 @@ package com.pixelized.rplexicon.ui.screens.rolls.factory import com.pixelized.rplexicon.R import com.pixelized.rplexicon.model.DiceThrow import com.pixelized.rplexicon.repository.data.ActionRepository +import com.pixelized.rplexicon.repository.data.SkillRepository import com.pixelized.rplexicon.repository.data.SpellRepository import com.pixelized.rplexicon.ui.screens.rolls.composable.RollDiceUio import com.pixelized.rplexicon.utilitary.extentions.icon @@ -10,6 +11,7 @@ import javax.inject.Inject class DiceFactory @Inject constructor( private val actionRepository: ActionRepository, + private val skillRepository: SkillRepository, private val spellRepository: SpellRepository, ) { fun convertDiceThrow(diceThrow: DiceThrow) = when (diceThrow) { @@ -27,6 +29,13 @@ class DiceFactory @Inject constructor( RollDiceUio(icon = it) } + is DiceThrow.Skill -> skillRepository.find( + character = diceThrow.character, + skill = diceThrow.skill + )?.effect?.faces?.icon?.let { + RollDiceUio(icon = it) + } + is DiceThrow.SpellDamage -> spellRepository.find( character = diceThrow.character, spell = diceThrow.spell diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index d0f635f..9bf2089 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -82,7 +82,8 @@ Initiative Jet de sauvegarde Maîtrises - Actions + Capacités + Attaques Altérations Force FOR @@ -118,8 +119,6 @@ Lancer Sorts mineurs Sorts de niveau %1$s - Capacités - Attaques Maîtrise \"%1$s\" Expertise \"%1$s\" @@ -135,7 +134,7 @@ Jet de sort : \"%1$s" Jet de dommage : \"%1$s\" Critique - Alterations + Alterations Jet de sauvegarde : %1$s Sauvegarde de \"%1$s\" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 24d595c..555cb08 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -82,7 +82,8 @@ Initiative Saving Throws Proficiencies - Actions + Attacks + Skills Alterations Strength STR @@ -118,8 +119,6 @@ Cast Cantrip Spell level %1$s - Skills - Attacks %1$s proficiency %1$s expertise @@ -135,7 +134,7 @@ %1$s hit %1$s damage Critical - Altérations + Alterations %1$s saving throw %1$s save