Support wild shape transformation (hp wise)

This commit is contained in:
Andres Gomez, Thomas (ITDV RL) 2024-06-04 14:16:16 +02:00
parent 483a8cf556
commit 1b97560dce
7 changed files with 138 additions and 55 deletions

View file

@ -0,0 +1,13 @@
package com.pixelized.rplexicon.business
import com.pixelized.rplexicon.data.model.alteration.Alteration
private const val WILD_SHAPE = "Forme sauvage"
fun isWildShape(alteration: Alteration): Boolean {
return isWildShape(alterationId = alteration.name)
}
fun isWildShape(alterationId: String): Boolean {
return alterationId.contains(WILD_SHAPE)
}

View file

@ -37,6 +37,10 @@ data class CharacterSheetFire(
@get:PropertyName("value")
@set:PropertyName("value")
var value: Int? = null,
@get:PropertyName("wild_shape")
@set:PropertyName("wild_shape")
var wildShape: Int? = null,
)
@Keep

View file

@ -142,7 +142,12 @@ class FirebaseRepository @Inject constructor(
fun getAlterationStatusSnapshot(key: AlterationStatus.Key): AlterationStatus.Value =
alterationStatus.value[key] ?: AlterationStatus.Value(false)
fun setCharacterHitPoint(character: String, value: Int, extra: Int) {
fun setCharacterHitPoint(
character: String,
value: Int? = characterFireSheet.value[character]?.hitPoint?.value,
extra: Int? = characterFireSheet.value[character]?.hitPoint?.additional,
wildShape: Int? = characterFireSheet.value[character]?.hitPoint?.wildShape,
) {
val reference = database.getReference(
"$PATH_CHARACTERS/$character/${CharacterSheetFire.HIT_POINT}"
)
@ -150,6 +155,7 @@ class FirebaseRepository @Inject constructor(
CharacterSheetFire.HitPoint(
additional = extra,
value = value,
wildShape = wildShape,
)
)
}

View file

@ -50,6 +50,13 @@ class ActiveAlterationRepository @Inject constructor(
fun getActiveAssignedAlterations(character: String?): Flow<List<Alteration>> =
activeAlterations.map { it[character] ?: emptyList() }
/**
* Returns the first element matching the given predicate, or null if element was not found.
*/
fun firstOrNull(character: String?, predicate: (Alteration) -> Boolean): Alteration? {
return activeAlterations.value[character]?.firstOrNull { predicate(it) }
}
companion object {
val ACTIVE = AlterationStatus.Value(value = true)
}

View file

@ -35,7 +35,10 @@ class CharacterSheetHeaderUioFactory @Inject constructor(
),
hitPoint = LabelPointUio(
label = R.string.character_sheet_title_hp,
value = convertToHitPointLabel(hitPoint = fireHeaderData),
value = convertToHitPointLabel(
fireHeaderData = fireHeaderData,
sheetHeaderData = sheetHeaderData,
),
max = sheetHeaderData?.hpMax?.let { "/ $it" } ?: " ",
),
dC = sheetHeaderData?.dc?.let {
@ -65,11 +68,22 @@ class CharacterSheetHeaderUioFactory @Inject constructor(
)
}
private fun convertToHitPointLabel(hitPoint: HeaderViewModel.FireHeaderData?): String {
return when {
hitPoint?.hp == null -> "?"
hitPoint.extra == 0 -> "${hitPoint.hp}"
else -> "${hitPoint.hp}+${hitPoint.extra}"
private fun convertToHitPointLabel(
fireHeaderData: HeaderViewModel.FireHeaderData?,
sheetHeaderData: HeaderViewModel.SheetHeaderData?,
): String {
return when (fireHeaderData?.wildShapeAlteration) {
null -> when {
fireHeaderData?.hp == null -> "?"
fireHeaderData.extraHp == 0 -> "${fireHeaderData.hp}"
else -> "${fireHeaderData.hp}+${fireHeaderData.extraHp}"
}
else -> when {
fireHeaderData?.wildShapeHp == null -> sheetHeaderData?.hpMax?.let { "$it" } ?: "?"
fireHeaderData.extraHp == 0 -> "${fireHeaderData.wildShapeHp}"
else -> "${fireHeaderData.wildShapeHp}+${fireHeaderData.extraHp}"
}
}
}
}

View file

@ -7,14 +7,15 @@ import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.pixelized.rplexicon.business.isWildShape
import com.pixelized.rplexicon.data.model.CharacterSheet
import com.pixelized.rplexicon.data.model.DiceThrow
import com.pixelized.rplexicon.data.model.Property
import com.pixelized.rplexicon.data.model.alteration.Alteration
import com.pixelized.rplexicon.data.model.alteration.AlterationStatus
import com.pixelized.rplexicon.data.network.CharacterSheetFire
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository
import com.pixelized.rplexicon.data.repository.character.ActiveAlterationRepository
import com.pixelized.rplexicon.data.repository.character.AlterationRepository
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
import com.pixelized.rplexicon.ui.composable.edit.HpPointDialogUio
import com.pixelized.rplexicon.ui.composable.edit.SkillEditDialogUio
@ -36,8 +37,8 @@ import javax.inject.Inject
class HeaderViewModel @Inject constructor(
private val headerFactory: CharacterSheetHeaderUioFactory,
private val firebaseRepository: FirebaseRepository,
private val activeAlterationRepository: ActiveAlterationRepository,
characterRepository: CharacterSheetRepository,
activeAlterationRepository: ActiveAlterationRepository,
savedStateHandle: SavedStateHandle,
) : ViewModel() {
val character = savedStateHandle.characterSheetArgument.name
@ -67,10 +68,13 @@ class HeaderViewModel @Inject constructor(
struct.sheet = sheets[character]
struct.alterationsStatus = alterations.toStatus()
}
.combine(firebaseRepository.getCharacter(character = character)) { _, fire ->
struct.fire = fire
}
.collect {
val (sheet, status) = struct
val (sheet, status, fire) = struct
if (sheet != null) {
val data = SheetHeaderData(
val headerCategories = SheetHeaderData(
hpMax = sheet.hitPoint + status[Property.HIT_POINT].sum,
characterClass = sheet.characterClass,
initiative = (sheet.dexterity + status[Property.DEXTERITY].sum).modifier + status[Property.INITIATIVE].sum,
@ -78,35 +82,27 @@ class HeaderViewModel @Inject constructor(
dc = sheet.dC,
)
withContext(Dispatchers.Main) {
sheetData.value = data
sheetData.value = headerCategories
}
val headerValues = FireHeaderData(
hp = fire.hitPoint?.value ?: 1,
extraHp = fire.hitPoint?.additional ?: 0,
wildShapeHp = fire.hitPoint?.wildShape ?: headerCategories.hpMax,
resource = fire.skills[sheet.resource],
deathSuccess = fire.death?.success ?: 0,
deathFailure = fire.death?.failure ?: 0,
wildShapeAlteration = activeAlterationRepository.firstOrNull(
character = character
) { isWildShape(it) },
)
withContext(Dispatchers.Main) {
fireData.value = headerValues
}
} else {
launch { characterRepository.fetchCharacterSheet() }
}
}
}
launch(context = Dispatchers.Default) {
val struct = HeaderValueStruct()
characterRepository.data
.combine(firebaseRepository.getCharacter(character = character)) { sheets, fire ->
struct.sheet = sheets[character]
struct.fire = fire
}
.collect {
val (sheet, fire) = struct
val data = FireHeaderData(
hp = fire.hitPoint?.value ?: 1,
resource = fire.skills[sheet?.resource],
extra = fire.hitPoint?.additional ?: 0,
deathSuccess = fire.death?.success ?: 0,
deathFailure = fire.death?.failure ?: 0,
)
withContext(Dispatchers.Main) {
fireData.value = data
}
}
}
}
}
@ -133,8 +129,11 @@ class HeaderViewModel @Inject constructor(
fun toggleHitPointDialog() {
_hitPointDialog.value = if (_hitPointDialog.value == null) {
HpPointDialogUio(
value = fireData.value?.hp ?: 10,
extra = fireData.value?.extra ?: 0,
value = when (fireData.value?.wildShapeAlteration) {
null -> fireData.value?.hp ?: 10
else -> fireData.value?.wildShapeHp ?: 1
},
extra = fireData.value?.extraHp ?: 0,
max = sheetData.value?.hpMax ?: 10,
)
} else {
@ -143,20 +142,53 @@ class HeaderViewModel @Inject constructor(
}
fun applyHitPointChange(hp: Int, extra: Int) {
val hpDownToZero = (fireData.value?.hp ?: 0) > 0 && hp == 0
val hpUpFromZero = (fireData.value?.hp ?: 0) == 0 && hp > 0
if (hpDownToZero || hpUpFromZero) {
firebaseRepository.setCharacterDeathCounter(
val wildShapeAlteration = fireData.value?.wildShapeAlteration
// check if we have a wild shape alteration activated.
if (wildShapeAlteration != null) {
// character is in wild shape form.
// check if we are down to 0 hp.
val hpDownToZero = (fireData.value?.wildShapeHp ?: 0) > 0 && hp == 0
if (hpDownToZero) {
// deactivate the wild shape alteration
firebaseRepository.setAlterationStatus(
key = AlterationStatus.Key(character, wildShapeAlteration.name),
value = AlterationStatus.Value(false),
)
// remove the wild shape hit point
firebaseRepository.setCharacterHitPoint(
character = character,
wildShape = null,
extra = extra,
)
} else {
// change the current wild shape hit point.
firebaseRepository.setCharacterHitPoint(
character = character,
wildShape = hp,
extra = extra,
)
}
} else {
// character is NOT in wild shape
// check if we are down to 0 hp or up from 0.
val hpDownToZero = (fireData.value?.hp ?: 0) > 0 && hp == 0
val hpUpFromZero = (fireData.value?.hp ?: 0) == 0 && hp > 0
if (hpDownToZero || hpUpFromZero) {
// set the death counter to 0
firebaseRepository.setCharacterDeathCounter(
character = character,
success = 0,
failure = 0,
)
}
// change the current hp of the character
firebaseRepository.setCharacterHitPoint(
character = character,
success = 0,
failure = 0,
value = hp,
extra = extra,
wildShape = null,
)
}
firebaseRepository.setCharacterHitPoint(
character = character,
value = hp,
extra = extra,
)
_hitPointDialog.value = null
}
@ -182,15 +214,10 @@ class HeaderViewModel @Inject constructor(
data class HeaderStruct(
var sheet: CharacterSheet? = null,
var alterationsStatus: Map<Property, List<Alteration.Status>> = emptyMap(),
)
class HeaderValueStruct(
var sheet: CharacterSheet? = null
) {
lateinit var fire: CharacterSheetFire
operator fun component1() = sheet
operator fun component2() = fire
operator fun component3() = fire
}
@Stable
@ -205,9 +232,11 @@ class HeaderViewModel @Inject constructor(
@Stable
data class FireHeaderData(
val hp: Int,
val extraHp: Int,
val wildShapeHp: Int?,
val resource: Int?,
val extra: Int,
val deathSuccess: Int,
val deathFailure: Int,
val wildShapeAlteration: Alteration?,
)
}

View file

@ -8,6 +8,7 @@ import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope
import com.pixelized.rplexicon.R
import com.pixelized.rplexicon.business.AlterationSortUseCase
import com.pixelized.rplexicon.business.isWildShape
import com.pixelized.rplexicon.data.model.CharacterSheet
import com.pixelized.rplexicon.data.model.Description
import com.pixelized.rplexicon.data.model.alteration.Alteration
@ -88,9 +89,18 @@ class AlterationViewModel @Inject constructor(
fun toggleAlteration(alteration: String) {
val key = AlterationStatus.Key(character = character, alteration = alteration)
val value = firebaseRepository.getAlterationStatusSnapshot(key = key)
// check if this is a wild shape alteration, if it is clear the hit point before activating it.
if (isWildShape(alteration) && !value.value) {
firebaseRepository.setCharacterHitPoint(
character = character,
wildShape = null,
)
}
// switch the alteration status
firebaseRepository.setAlterationStatus(
key = key,
value = firebaseRepository.getAlterationStatusSnapshot(key = key).switch(),
value = value.switch(),
)
}