Add Object action in the character action sheet.

This commit is contained in:
Thomas Andres Gomez 2023-10-24 18:08:25 +02:00
parent f9b3adfee0
commit cd921ac16f
21 changed files with 416 additions and 10 deletions

View file

@ -12,6 +12,7 @@ import com.pixelized.rplexicon.repository.data.character.CharacterSheetRepositor
import com.pixelized.rplexicon.repository.data.character.DescriptionRepository
import com.pixelized.rplexicon.repository.data.character.EquipmentRepository
import com.pixelized.rplexicon.repository.data.character.InventoryRepository
import com.pixelized.rplexicon.repository.data.character.ObjectActionRepository
import com.pixelized.rplexicon.repository.data.character.SkillRepository
import com.pixelized.rplexicon.repository.data.character.SpellRepository
import com.pixelized.rplexicon.repository.data.lexicon.LexiconRepository
@ -35,6 +36,7 @@ class LauncherViewModel @Inject constructor(
alterationRepository: AlterationRepository,
characterSheetRepository: CharacterSheetRepository,
actionRepository: ActionRepository,
objectActionRepository: ObjectActionRepository,
spellRepository: SpellRepository,
skillRepository: SkillRepository,
descriptionRepository: DescriptionRepository,
@ -124,6 +126,14 @@ class LauncherViewModel @Inject constructor(
_error.emit(FetchErrorUio.Structure(type = Type.ACTION))
}
}
val objects = async {
try {
objectActionRepository.fetchObjectAction()
} catch (exception: Exception) {
Log.e(TAG, exception.message, exception)
_error.emit(FetchErrorUio.Structure(type = Type.OBJECT))
}
}
val spell = async {
try {
spellRepository.fetchSpells()
@ -142,7 +152,7 @@ class LauncherViewModel @Inject constructor(
}
awaitAll(lexicon, location, quest)
awaitAll(description, inventory, equipment, alteration, action, spell, skill)
awaitAll(description, inventory, equipment, alteration, action, objects, spell, skill)
isLoading = false
}

View file

@ -13,6 +13,7 @@ import com.pixelized.rplexicon.model.Throw
import com.pixelized.rplexicon.repository.data.character.ActionRepository
import com.pixelized.rplexicon.repository.data.character.AlterationRepository
import com.pixelized.rplexicon.repository.data.character.CharacterSheetRepository
import com.pixelized.rplexicon.repository.data.character.ObjectActionRepository
import com.pixelized.rplexicon.repository.data.character.SkillRepository
import com.pixelized.rplexicon.repository.data.character.SpellRepository
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollDiceUio
@ -42,6 +43,7 @@ class DiceThrowUseCase @Inject constructor(
private val application: Application,
private val characterSheetRepository: CharacterSheetRepository,
private val actionRepository: ActionRepository,
private val objectRepository: ObjectActionRepository,
private val spellRepository: SpellRepository,
private val skillRepository: SkillRepository,
private val alterationRepository: AlterationRepository,
@ -393,6 +395,21 @@ class DiceThrowUseCase @Inject constructor(
)
}
is DiceThrow.Object -> {
val action = objectRepository.find(
character = diceThrow.character,
item = diceThrow.item,
)
actionThrow(
character = sheet,
action = diceThrow.item,
diceThrow = action?.effect,
title = { getString(R.string.dice_roll_attack_hit_title, it) },
alterations = emptyMap(),
ability = null,
)
}
is DiceThrow.SpellAttack -> {
val spell = spellRepository.find(
character = diceThrow.character,
@ -664,7 +681,7 @@ class DiceThrowUseCase @Inject constructor(
diceThrow: Throw?,
title: Context.(action: String) -> String,
alterations: Map<Property, List<Alteration.Status>>,
ability: Property,
ability: Property?,
): DiceThrowResult {
// retrieve some wording.
val titleString = title(application, action)
@ -778,6 +795,17 @@ class DiceThrowUseCase @Inject constructor(
}
} ?: emptyList()
// check for flat dice bonus (ex: healing potion 2d4 + 2)
val flatBonus = diceThrow?.flat?.takeIf { it > 0 }?.let {
allValue.add(it)
listOf(
ThrowsCardUio.Detail(
title = application.getString(R.string.dice_roll_bonus_detail, action),
result = "$it",
)
)
}?: emptyList()
// build the result.
return DiceThrowResult(
dice = RollDiceUio(
@ -812,7 +840,7 @@ class DiceThrowUseCase @Inject constructor(
),
result = "${result.value}",
),
) + diceAlterationBonus + flatAlterationBonus + relatedStatBonus,
) + diceAlterationBonus + flatAlterationBonus + relatedStatBonus + flatBonus,
)
)
}

View file

@ -40,4 +40,5 @@ sealed class DiceThrow(val character: String) {
class SpellDamage(character: String, val spell: String) : DiceThrow(character)
class SpellEffect(character: String, val spell: String, val level: Int) : DiceThrow(character)
class Skill(character: String, val skill: String) : DiceThrow(character)
class Object(character: String, val item: String) : DiceThrow(character)
}

View file

@ -0,0 +1,6 @@
package com.pixelized.rplexicon.model
data class ObjectAction(
val name: String,
val effect: Throw?,
)

View file

@ -3,5 +3,6 @@ package com.pixelized.rplexicon.model
class Throw(
val amount: Int,
val faces: Int,
val flat: Int,
val modifier: List<Property>,
)

View file

@ -14,6 +14,7 @@ object CharacterBinder {
const val CHARACTER = "Feuille de personnage"
const val ATTACK = "Attaques"
const val OBJECT = "Objets"
const val MAGIC = "Magies"
const val SKILL = "Capacités"
const val MAGIC_LEXICON = "Lexique magique"

View file

@ -0,0 +1,40 @@
package com.pixelized.rplexicon.repository.data.character
import com.pixelized.rplexicon.model.ObjectAction
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
import com.pixelized.rplexicon.repository.data.CharacterBinder
import com.pixelized.rplexicon.repository.parser.ObjectActionParser
import com.pixelized.rplexicon.utilitary.Update
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class ObjectActionRepository @Inject constructor(
private val googleRepository: GoogleSheetServiceRepository,
private val parser: ObjectActionParser
) {
private val _data = MutableStateFlow<Map<String, List<ObjectAction>>>(emptyMap())
val data: StateFlow<Map<String, List<ObjectAction>>> get() = _data
var lastSuccessFullUpdate: Update = Update.INITIAL
private set
fun find(character: String?): List<ObjectAction> =
_data.value[character] ?: emptyList()
fun find(character: String?, item: String): ObjectAction? =
find(character).firstOrNull { it.name == item }
@Throws(IncompatibleSheetStructure::class, Exception::class)
suspend fun fetchObjectAction() {
googleRepository.fetch { sheet ->
val request = sheet.get(CharacterBinder.ID, CharacterBinder.OBJECT)
val data = parser.parse(data = request.execute())
_data.tryEmit(data)
lastSuccessFullUpdate = Update.currentTime()
}
}
}

View file

@ -0,0 +1,43 @@
package com.pixelized.rplexicon.repository.parser
import com.google.api.services.sheets.v4.model.ValueRange
import com.pixelized.rplexicon.model.ObjectAction
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
import javax.inject.Inject
class ObjectActionParser @Inject constructor(
private val throwParser: ThrowParser,
) {
@Throws(IncompatibleSheetStructure::class)
fun parse(data: ValueRange): Map<String, List<ObjectAction>> = parserScope {
val objects = hashMapOf<String, MutableList<ObjectAction>>()
data.forEachRow { index, row ->
when {
index == 0 -> updateStructure(row = row, columns = COLUMNS)
row.isNotEmpty() -> {
val character = row[0]?.toItem()
val name = row.parse(column = NAME)
val effect = throwParser.parse(value = row.parse(column = EFFECT))
if (character != null && name != null && effect != null) {
objects.getOrPut(character) { mutableListOf() }.add(
ObjectAction(
name = name,
effect = effect,
)
)
}
}
}
}
return@parserScope objects
}
companion object {
private const val NAME = "Nom"
private const val EFFECT = "Effet"
private val COLUMNS = listOf(NAME, EFFECT)
}
}

View file

@ -1,12 +1,14 @@
package com.pixelized.rplexicon.repository.parser
import com.pixelized.rplexicon.repository.parser.roll.DiceParser
import com.pixelized.rplexicon.repository.parser.roll.ModifierParser
import com.pixelized.rplexicon.model.Throw
import com.pixelized.rplexicon.repository.parser.roll.DiceParser
import com.pixelized.rplexicon.repository.parser.roll.FlatValueParser
import com.pixelized.rplexicon.repository.parser.roll.ModifierParser
import javax.inject.Inject
class ThrowParser @Inject constructor(
private val diceParser: DiceParser,
private val flatValueParser: FlatValueParser,
private val modifierParser: ModifierParser,
) {
fun parse(value: String?): Throw? {
@ -14,9 +16,11 @@ class ThrowParser @Inject constructor(
val dice = diceParser.findAll(value = value).firstOrNull()
if (dice != null) {
val modifier = modifierParser.findAll(value = value)
val flat = flatValueParser.parse(value = value)
return Throw(
amount = dice.count,
faces = dice.faces,
flat = flat,
modifier = modifier,
)
}

View file

@ -6,7 +6,12 @@ import javax.inject.Inject
class FlatValueParser @Inject constructor() {
companion object {
private val FLAT_REGEX = Regex("(?<!d|\\d)(-?\\d+)(?!d)")
private val FLAT_REGEX = Regex("(?<!d)([-+]?\\s?\\d+)(?!d)")
}
fun parse(value: String): Int {
return FLAT_REGEX.findAll(value)
.sumOf { it.value.replace(" ", "").toIntOrNull() ?: 0 }
}
fun findAll(title: String, value: String): List<Roll.Bonus> {

View file

@ -28,6 +28,7 @@ sealed class FetchErrorUio {
DESCRIPTION,
EQUIPMENT,
INVENTORY,
OBJECT,
SKILL,
SPELL,
LEXICON,
@ -53,6 +54,7 @@ fun HandleFetchError(
FetchErrorUio.Structure.Type.DESCRIPTION -> R.string.error_structure_description
FetchErrorUio.Structure.Type.EQUIPMENT -> R.string.error_structure_equipment
FetchErrorUio.Structure.Type.INVENTORY -> R.string.error_structure_inventory
FetchErrorUio.Structure.Type.OBJECT -> R.string.error_structure_objects
FetchErrorUio.Structure.Type.SKILL -> R.string.error_structure_skill
FetchErrorUio.Structure.Type.SPELL -> R.string.error_structure_spell
FetchErrorUio.Structure.Type.LEXICON -> R.string.error_structure_lexicon

View file

@ -68,6 +68,9 @@ import com.pixelized.rplexicon.ui.screens.character.composable.character.StatUio
import com.pixelized.rplexicon.ui.screens.character.pages.actions.ActionPage
import com.pixelized.rplexicon.ui.screens.character.pages.actions.ActionPagePreview
import com.pixelized.rplexicon.ui.screens.character.pages.actions.AttacksViewModel
import com.pixelized.rplexicon.ui.screens.character.pages.actions.HeaderViewModel
import com.pixelized.rplexicon.ui.screens.character.pages.actions.ObjectsViewModel
import com.pixelized.rplexicon.ui.screens.character.pages.actions.SkillsViewModel
import com.pixelized.rplexicon.ui.screens.character.pages.actions.SpellsViewModel
import com.pixelized.rplexicon.ui.screens.character.pages.alteration.AlterationPage
import com.pixelized.rplexicon.ui.screens.character.pages.alteration.AlterationPagePreview
@ -93,8 +96,11 @@ fun CharacterSheetScreen(
viewModel: CharacterSheetViewModel = hiltViewModel(),
inventoryViewModel: InventoryViewModel = hiltViewModel(),
proficiencyViewModel: ProficiencyViewModel = hiltViewModel(),
headerViewModel: HeaderViewModel = hiltViewModel(),
attacksViewModel: AttacksViewModel = hiltViewModel(),
objectsViewModel: ObjectsViewModel = hiltViewModel(),
spellsViewModel: SpellsViewModel = hiltViewModel(),
skillViewModel: SkillsViewModel = hiltViewModel(),
alterationsViewModel: AlterationViewModel = hiltViewModel(),
) {
val snack = LocalSnack.current
@ -153,8 +159,11 @@ fun CharacterSheetScreen(
actions = {
ActionPage(
sheetState = sheetState,
headerViewModel = headerViewModel,
attacksViewModel = attacksViewModel,
objectsViewModel = objectsViewModel,
spellsViewModel = spellsViewModel,
skillViewModel = skillViewModel,
)
},
alterations = {

View file

@ -13,6 +13,7 @@ import com.pixelized.rplexicon.repository.data.character.CharacterSheetRepositor
import com.pixelized.rplexicon.repository.data.character.DescriptionRepository
import com.pixelized.rplexicon.repository.data.character.EquipmentRepository
import com.pixelized.rplexicon.repository.data.character.InventoryRepository
import com.pixelized.rplexicon.repository.data.character.ObjectActionRepository
import com.pixelized.rplexicon.repository.data.character.SkillRepository
import com.pixelized.rplexicon.repository.data.character.SpellRepository
import com.pixelized.rplexicon.ui.composable.error.FetchErrorUio
@ -35,6 +36,7 @@ class CharacterSheetViewModel @Inject constructor(
private val inventoryRepository: InventoryRepository,
private val equipmentRepository: EquipmentRepository,
private val actionRepository: ActionRepository,
private val objectRepository: ObjectActionRepository,
private val spellRepository: SpellRepository,
private val skillRepository: SkillRepository,
private val firebaseRepository: FirebaseRepository,
@ -124,6 +126,16 @@ class CharacterSheetViewModel @Inject constructor(
}
}
}
val objects = async {
if (force || objectRepository.lastSuccessFullUpdate.shouldUpdate()) {
try {
objectRepository.fetchObjectAction()
} catch (exception: Exception) {
Log.e(TAG, exception.message, exception)
_error.emit(FetchErrorUio.Structure(type = Type.OBJECT))
}
}
}
val spells = async {
if (force || spellRepository.lastSuccessFullUpdate.shouldUpdate()) {
try {
@ -144,7 +156,7 @@ class CharacterSheetViewModel @Inject constructor(
}
}
}
awaitAll(description, alterations, inventory, equipment, actions, spells, skill)
awaitAll(description, alterations, inventory, equipment, actions, objects, spells, skill)
_isLoading.value = false
}

View file

@ -0,0 +1,114 @@
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.BorderStroke
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontStyle
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
@Stable
data class ObjectItemUio(
val name: String,
val original: String?,
)
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun ObjectItem(
modifier: Modifier = Modifier,
padding: PaddingValues = PaddingValues(top = 4.dp, bottom = 4.dp, start = 16.dp, end = 16.dp),
item: ObjectItemUio,
onObject: (String) -> Unit,
onUse: (String) -> Unit,
) {
Row(
modifier = Modifier
.clickable { onObject(item.name) }
.padding(paddingValues = padding)
.then(other = modifier),
horizontalArrangement = Arrangement.spacedBy(space = 12.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Column(
modifier = Modifier.weight(weight = 1f)
) {
FlowRow(
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
) {
Text(
modifier = Modifier.alignByBaseline(),
style = MaterialTheme.typography.bodyMedium,
fontWeight = FontWeight.Bold,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
text = item.name,
)
item.original?.let {
Text(
modifier = Modifier.alignByBaseline(),
style = MaterialTheme.typography.labelSmall,
fontWeight = FontWeight.Light,
fontStyle = FontStyle.Italic,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
text = it,
)
}
}
}
OutlinedButton(
border = BorderStroke(
width = 1.dp,
color = MaterialTheme.colorScheme.primary,
),
onClick = { onUse(item.name) },
) {
Text(
text = stringResource(id = R.string.character_sheet_action_spell_cast),
)
}
}
}
@Composable
@Preview(uiMode = UI_MODE_NIGHT_NO)
@Preview(uiMode = UI_MODE_NIGHT_YES)
private fun ObjectItemPreview() {
LexiconTheme {
Surface {
ObjectItem(
modifier = Modifier.fillMaxWidth(),
item = ObjectItemUio(
name = "Potion de guérison",
original = "Healing potion",
),
onObject = { },
onUse = { },
)
}
}
}

View file

@ -0,0 +1,20 @@
package com.pixelized.rplexicon.ui.screens.character.composable.preview
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import com.pixelized.rplexicon.ui.screens.character.composable.actions.ObjectItemUio
@Composable
@Stable
fun rememberObjectListStatePreview() = remember {
mutableStateOf(
listOf(
ObjectItemUio(
name = "Potion de guérison",
original = "Healing potion",
),
)
)
}

View file

@ -17,13 +17,10 @@ import androidx.compose.material.ModalBottomSheetState
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
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.LocalRollOverlay
import com.pixelized.rplexicon.R
@ -35,6 +32,8 @@ import com.pixelized.rplexicon.ui.navigation.screens.navigateToSpellDetail
import com.pixelized.rplexicon.ui.screens.character.composable.actions.Attack
import com.pixelized.rplexicon.ui.screens.character.composable.actions.AttackUio
import com.pixelized.rplexicon.ui.screens.character.composable.actions.GenericHeader
import com.pixelized.rplexicon.ui.screens.character.composable.actions.ObjectItem
import com.pixelized.rplexicon.ui.screens.character.composable.actions.ObjectItemUio
import com.pixelized.rplexicon.ui.screens.character.composable.actions.SkillItem
import com.pixelized.rplexicon.ui.screens.character.composable.actions.SkillItemUio
import com.pixelized.rplexicon.ui.screens.character.composable.actions.Spell
@ -46,6 +45,7 @@ import com.pixelized.rplexicon.ui.screens.character.composable.character.Charact
import com.pixelized.rplexicon.ui.screens.character.composable.character.CharacterSheetHeaderUio
import com.pixelized.rplexicon.ui.screens.character.composable.preview.rememberAttackListStatePreview
import com.pixelized.rplexicon.ui.screens.character.composable.preview.rememberCharacterHeaderStatePreview
import com.pixelized.rplexicon.ui.screens.character.composable.preview.rememberObjectListStatePreview
import com.pixelized.rplexicon.ui.screens.character.composable.preview.rememberSpellListStatePreview
import com.pixelized.rplexicon.ui.theme.LexiconTheme
import kotlinx.coroutines.launch
@ -56,6 +56,7 @@ fun ActionPage(
sheetState: ModalBottomSheetState,
headerViewModel: HeaderViewModel = hiltViewModel(),
attacksViewModel: AttacksViewModel = hiltViewModel(),
objectsViewModel: ObjectsViewModel = hiltViewModel(),
spellsViewModel: SpellsViewModel = hiltViewModel(),
skillViewModel: SkillsViewModel = hiltViewModel(),
) {
@ -67,6 +68,7 @@ fun ActionPage(
modifier = Modifier.fillMaxSize(),
header = headerViewModel.header,
attacks = attacksViewModel.attacks,
objects = objectsViewModel.objects,
tokens = skillViewModel.skills,
spells = spellsViewModel.spells,
onHitPoint = headerViewModel::toggleHitPointDialog,
@ -82,6 +84,15 @@ fun ActionPage(
overlay.showOverlay()
}
},
onObject = {
},
onUseObject = { id ->
objectsViewModel.onUse(id)?.let {
overlay.prepareRoll(diceThrow = it)
overlay.showOverlay()
}
},
onSkillCount = {
skillViewModel.showSkillEditDialog(item = it)
},
@ -151,11 +162,14 @@ fun ActionsPageContent(
lazyListState: LazyListState = rememberLazyListState(),
header: State<CharacterSheetHeaderUio?>,
attacks: State<List<AttackUio>>,
objects: State<List<ObjectItemUio>>,
tokens: State<List<SkillItemUio>>,
spells: State<List<Pair<SpellHeaderUio, List<SpellUio>>>>,
onHitPoint: () -> Unit,
onAttackHit: (id: String) -> Unit,
onAttackDamage: (id: String) -> Unit,
onObject: (id: String) -> Unit,
onUseObject: (id: String) -> Unit,
onSkillThrow: (SkillItemUio) -> Unit,
onSkillCount: (SkillItemUio) -> Unit,
onSkillInfo: (SkillItemUio) -> Unit,
@ -195,6 +209,24 @@ fun ActionsPageContent(
}
}
if (objects.value.isNotEmpty()) {
stickyHeader {
GenericHeader(
label = R.string.character_sheet_title_objects,
)
}
items(items = objects.value) {
ObjectItem(
item = it,
onObject = onObject,
onUse = onUseObject,
)
}
items(count = 1) {
Spacer(modifier = Modifier.height(height = 16.dp))
}
}
if (tokens.value.isNotEmpty()) {
stickyHeader {
GenericHeader(
@ -248,11 +280,14 @@ fun ActionPagePreview() {
modifier = Modifier.fillMaxSize(),
header = rememberCharacterHeaderStatePreview(),
attacks = rememberAttackListStatePreview(),
objects = rememberObjectListStatePreview(),
tokens = rememberTokenListStatePreview(),
spells = rememberSpellListStatePreview(),
onHitPoint = { },
onAttackHit = { },
onAttackDamage = { },
onObject = { },
onUseObject = { },
onSkillCount = { },
onSkillThrow = { },
onSkillInfo = { },

View file

@ -0,0 +1,60 @@
package com.pixelized.rplexicon.ui.screens.character.pages.actions
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.pixelized.rplexicon.model.DiceThrow
import com.pixelized.rplexicon.repository.data.character.DescriptionRepository
import com.pixelized.rplexicon.repository.data.character.ObjectActionRepository
import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument
import com.pixelized.rplexicon.ui.screens.character.composable.actions.ObjectItemUio
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject
@HiltViewModel
class ObjectsViewModel @Inject constructor(
private val objectsRepository: ObjectActionRepository,
private val descriptionRepository: DescriptionRepository,
savedStateHandle: SavedStateHandle,
) : ViewModel() {
val character = savedStateHandle.characterSheetArgument.name
private val _objects = mutableStateOf<List<ObjectItemUio>>(emptyList())
val objects: State<List<ObjectItemUio>> get() = _objects
init {
viewModelScope.launch(Dispatchers.IO) {
objectsRepository.data.collect { objects ->
val data = objects[character]?.map {
ObjectItemUio(
name = it.name,
original = descriptionRepository.find(name = it.name)?.original
)
} ?: emptyList()
withContext(Dispatchers.Main) {
_objects.value = data
}
}
}
}
fun onObject(name: String) {
}
fun onUse(name: String): DiceThrow? {
val item = objectsRepository.find(character = character, item = name)
return item?.let {
DiceThrow.Object(
character = character,
item = it.name,
)
}
}
}

View file

@ -78,6 +78,8 @@ class AlterationFactory @Inject constructor(
listOf(Property.PHYSICAL_RANGE_ATTACK) + (action?.hit?.modifier ?: emptyList())
}
is DiceThrow.Object -> emptyList()
is DiceThrow.PhysicalRangeDamage -> {
val action = actionRepository.find(diceThrow.character, action = diceThrow.weapon)
listOf(Property.PHYSICAL_RANGE_DAMAGE) + (action?.damage?.modifier ?: emptyList())

View file

@ -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.character.ActionRepository
import com.pixelized.rplexicon.repository.data.character.ObjectActionRepository
import com.pixelized.rplexicon.repository.data.character.SkillRepository
import com.pixelized.rplexicon.repository.data.character.SpellRepository
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollDiceUio
@ -11,6 +12,7 @@ import javax.inject.Inject
class DiceFactory @Inject constructor(
private val actionRepository: ActionRepository,
private val objectActionRepository: ObjectActionRepository,
private val skillRepository: SkillRepository,
private val spellRepository: SpellRepository,
) {
@ -50,6 +52,13 @@ class DiceFactory @Inject constructor(
RollDiceUio(icon = it)
}
is DiceThrow.Object -> objectActionRepository.find(
character = diceThrow.character,
item = diceThrow.item,
)?.effect?.faces?.icon?.let {
RollDiceUio(icon = it)
}
else -> RollDiceUio(icon = R.drawable.ic_d20_24)
}
}

View file

@ -11,6 +11,7 @@
<string name="error_structure_description">La structure de la feuille de description semble avoir changé et n\'est plus compatible avec cette application.</string>
<string name="error_structure_equipment">La structure de la feuille d\'équipement semble avoir changé et n\'est plus compatible avec cette application.</string>
<string name="error_structure_inventory">La structure de la feuille d\'inventaire semble avoir changé et n\'est plus compatible avec cette application.</string>
<string name="error_structure_objects">La structure de la feuille d\'actions (object) semble avoir changé et n\'est plus compatible avec cette application.</string>
<string name="error_structure_skill">La structure de la feuille des talents semble avoir changé et n\'est plus compatible avec cette application.</string>
<string name="error_structure_spell">La structure de la feuille des sorts semble avoir changé et n\'est plus compatible avec cette application.</string>
<string name="error_structure_lexicon">La structure du lexique semble avoir changé et n\'est plus compatible avec cette application.</string>
@ -99,6 +100,7 @@
<string name="character_sheet_title_proficiencies">Maîtrises</string>
<string name="character_sheet_title_skills">Capacités</string>
<string name="character_sheet_title_attacks">Attaques</string>
<string name="character_sheet_title_objects">Objets</string>
<string name="character_sheet_title_inventory">Inventaire</string>
<string name="character_sheet_title_equipment">Equipement</string>
<string name="character_sheet_stat_strength">Force</string>

View file

@ -11,6 +11,7 @@
<string name="error_structure_description">The description sheet structure appears to have changed and is no longer compatible with this application</string>
<string name="error_structure_equipment">The equipment sheet structure appears to have changed and is no longer compatible with this application</string>
<string name="error_structure_inventory">The inventory sheet structure appears to have changed and is no longer compatible with this application</string>
<string name="error_structure_objects">The objects sheet structure appears to have changed and is no longer compatible with this application</string>
<string name="error_structure_skill">The skill sheet structure appears to have changed and is no longer compatible with this application</string>
<string name="error_structure_spell">The spell sheet structure appears to have changed and is no longer compatible with this application</string>
<string name="error_structure_lexicon">The lexicon sheet structure appears to have changed and is no longer compatible with this application</string>
@ -98,6 +99,7 @@
<string name="character_sheet_title_saving_throws">Saving Throws</string>
<string name="character_sheet_title_proficiencies">Proficiencies</string>
<string name="character_sheet_title_attacks">Attacks</string>
<string name="character_sheet_title_objects">Objects</string>
<string name="character_sheet_title_skills">Skills</string>
<string name="character_sheet_title_inventory">Inventory</string>
<string name="character_sheet_title_equipment">Equipment</string>