Clean up old roll code + refactor some ugly stuff.

This commit is contained in:
Andres Gomez, Thomas (ITDV RL) 2024-06-01 22:39:20 +02:00
parent 8808040e14
commit 8841529b31
26 changed files with 251 additions and 244 deletions

View file

@ -9,7 +9,8 @@ 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.Skill
import com.pixelized.rplexicon.data.model.Throw
import com.pixelized.rplexicon.data.model.roll.Flat
import com.pixelized.rplexicon.data.model.roll.Throw
import com.pixelized.rplexicon.data.network.NetworkThrow
import com.pixelized.rplexicon.data.repository.character.ActionRepository
import com.pixelized.rplexicon.data.repository.character.AlterationRepository
@ -19,6 +20,7 @@ import com.pixelized.rplexicon.data.repository.character.SkillRepository
import com.pixelized.rplexicon.data.repository.character.SpellRepository
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollDiceUio
import com.pixelized.rplexicon.utilitary.extentions.icon
import com.pixelized.rplexicon.utilitary.extentions.toLabel
import com.pixelized.rplexicon.utilitary.extentions.local.advantage
import com.pixelized.rplexicon.utilitary.extentions.local.base
import com.pixelized.rplexicon.utilitary.extentions.local.critical
@ -34,7 +36,6 @@ import com.pixelized.rplexicon.utilitary.extentions.local.sum
import com.pixelized.rplexicon.utilitary.extentions.local.toStatus
import com.pixelized.rplexicon.utilitary.extentions.masteryMultiplier
import com.pixelized.rplexicon.utilitary.extentions.modifier
import com.pixelized.rplexicon.utilitary.extentions.toLabel
import javax.inject.Inject
import kotlin.math.abs
import kotlin.math.max
@ -748,7 +749,7 @@ class DiceThrowUseCase @Inject constructor(
// compute the amount of main dice to throw.
val amount = if (status.isCritical) {
diceThrow?.amount?.times(2)?.let {
diceThrow?.dice?.count?.times(2)?.let {
if (ability == Property.PHYSICAL_MELEE_DAMAGE && status.isSavageAttacks)
it.plus(1) else it
}?.let {
@ -756,12 +757,12 @@ class DiceThrowUseCase @Inject constructor(
it.plus(1) else it
}
} else {
diceThrow?.amount
diceThrow?.dice?.count
}
// main roll
val result = roll(
amount = amount ?: 1,
faces = diceThrow?.faces ?: 20,
faces = diceThrow?.dice?.faces ?: 20,
advantage = advantage,
disadvantage = disadvantage,
emphasis = emphasis,
@ -791,7 +792,7 @@ class DiceThrowUseCase @Inject constructor(
// build the result.
return DiceThrowResult(
dice = RollDiceUio(
icon = diceThrow?.faces?.icon ?: R.drawable.ic_d20_24,
icon = diceThrow?.dice?.icon ?: R.drawable.ic_d20_24,
isCriticalSuccess = canMakeCriticalRoll && result.value == 20,
isCriticalFailure = canMakeCriticalRoll && result.value == 1,
result = rollResult,
@ -800,7 +801,7 @@ class DiceThrowUseCase @Inject constructor(
timestamp = System.currentTimeMillis(),
title = titleString.uppercase(),
highlight = action.uppercase(),
face = diceThrow?.faces ?: 20,
face = diceThrow?.dice?.faces ?: 20,
isCriticalSuccess = canMakeCriticalRoll && result.value == 20,
isCriticalFailure = canMakeCriticalRoll && result.value == 1,
roll = allValue.toLabel(),
@ -809,11 +810,11 @@ class DiceThrowUseCase @Inject constructor(
NetworkThrow.Detail(
title = action,
throws = NetworkThrow.Throw(
dice = diceThrow?.faces?.icon ?: R.drawable.ic_d20_24,
dice = diceThrow?.dice?.icon ?: R.drawable.ic_d20_24,
advantage = advantage,
disadvantage = disadvantage,
emphasis = emphasis,
roll = "${diceThrow?.amount}d${diceThrow?.faces}",
roll = "${diceThrow?.dice?.count}d${diceThrow?.dice?.faces}",
result = result.label,
),
result = "${result.value}",
@ -840,8 +841,8 @@ class DiceThrowUseCase @Inject constructor(
val emphasis = status[Property.SPELL_EFFECT].emphasis
// main roll
val result = roll(
amount = spell?.effect?.amount ?: 1,
faces = spell?.effect?.faces ?: 4,
amount = spell?.effect?.dice?.count ?: 1,
faces = spell?.effect?.dice?.faces ?: 4,
advantage = advantage,
disadvantage = disadvantage,
emphasis = emphasis,
@ -849,12 +850,12 @@ class DiceThrowUseCase @Inject constructor(
critical = status[Property.SPELL_EFFECT].critical,
)
// fetch and build a list of additionnal level effect.
// fetch and build a list of additional level effect.
val levelBonus = if (spell?.level != null) {
((spell.spell.level + 1)..level).map {
val localRoll = roll(
amount = spell.level.amount,
faces = spell.level.faces,
amount = spell.level.dice.count,
faces = spell.level.dice.faces,
advantage = advantage,
disadvantage = disadvantage,
emphasis = emphasis,
@ -864,8 +865,8 @@ class DiceThrowUseCase @Inject constructor(
NetworkThrow.Detail(
title = application.getString(R.string.spell_level_chooser_label, "$it"),
throws = NetworkThrow.Throw(
dice = spell.level.faces.icon,
roll = "${spell.level.amount}d${spell.level.faces}",
dice = spell.level.dice.icon,
roll = spell.level.dice.toLabel(),
advantage = advantage,
disadvantage = disadvantage,
emphasis = emphasis,
@ -890,22 +891,22 @@ class DiceThrowUseCase @Inject constructor(
// build the result.
return DiceThrowResult(
dice = RollDiceUio(
icon = (spell?.effect?.faces ?: 4).icon,
icon = spell?.effect?.dice?.icon ?: R.drawable.ic_d4_24,
result = rollResult,
),
throws = NetworkThrow(
timestamp = System.currentTimeMillis(),
title = titleString.uppercase(),
highlight = spellName.uppercase(),
face = spell?.effect?.faces ?: 4,
face = spell?.effect?.dice?.faces ?: 4,
roll = allValue.toLabel(),
result = rollResult,
details = listOf(
NetworkThrow.Detail(
title = spellName,
throws = NetworkThrow.Throw(
dice = (spell?.effect?.faces ?: 4).icon,
roll = "${spell?.effect?.amount ?: 1}d${spell?.effect?.faces ?: 4}",
dice = spell?.effect?.dice?.icon ?: R.drawable.ic_d4_24,
roll = spell?.effect?.dice?.toLabel() ?: "1d4",
advantage = advantage,
disadvantage = disadvantage,
emphasis = emphasis,
@ -934,8 +935,8 @@ class DiceThrowUseCase @Inject constructor(
val emphasis = status[Property.SKILL].emphasis
// main roll
val result = roll(
amount = skill?.effect?.amount ?: 1,
faces = skill?.effect?.faces ?: 4,
amount = skill?.effect?.dice?.count ?: 1,
faces = skill?.effect?.dice?.faces ?: 4,
advantage = advantage,
disadvantage = disadvantage,
emphasis = emphasis,
@ -961,22 +962,22 @@ class DiceThrowUseCase @Inject constructor(
// build the result.
return DiceThrowResult(
dice = RollDiceUio(
icon = (skill?.effect?.faces ?: 4).icon,
icon = skill?.effect?.dice?.icon ?: R.drawable.ic_d4_24,
result = rollResult,
),
throws = NetworkThrow(
timestamp = System.currentTimeMillis(),
title = titleString.uppercase(),
highlight = spellName?.uppercase() ?: "",
face = skill?.effect?.faces ?: 4,
face = skill?.effect?.dice?.faces ?: 4,
roll = allValue.toLabel(),
result = rollResult,
details = listOf(
NetworkThrow.Detail(
title = spellName ?: "",
throws = NetworkThrow.Throw(
dice = (skill?.effect?.faces ?: 4).icon,
roll = "${skill?.effect?.amount ?: 1}d${skill?.effect?.faces ?: 4}",
dice = skill?.effect?.dice?.icon ?: R.drawable.ic_d4_24,
roll = skill?.effect?.dice?.toLabel() ?: "1d4",
advantage = advantage,
disadvantage = disadvantage,
emphasis = emphasis,
@ -1054,15 +1055,17 @@ class DiceThrowUseCase @Inject constructor(
}
}
private fun Int.flatBonus(name: String?): NetworkThrow.Detail? {
allValue.add(this)
return if (this != 0) {
NetworkThrow.Detail(
title = context.getString(R.string.dice_roll_bonus_detail, name),
result = "$this",
)
} else {
null
private fun Flat.flatBonus(name: String?): NetworkThrow.Detail? {
return when {
value != 0 -> {
allValue.add(value)
NetworkThrow.Detail(
title = context.getString(R.string.dice_roll_bonus_detail, name),
result = "$value",
)
}
else -> null
}
}
@ -1082,9 +1085,9 @@ class DiceThrowUseCase @Inject constructor(
critical = status.critical,
)
NetworkThrow.Detail(
title = dice.title ?: "",
title = status.name,
throws = NetworkThrow.Throw(
dice = dice.faces.icon,
dice = dice.icon,
advantage = dice.advantage,
disadvantage = dice.disadvantage,
emphasis = dice.emphasis,
@ -1101,11 +1104,11 @@ class DiceThrowUseCase @Inject constructor(
* Fetch any flat number related bonus and build a ThrowsCardUio.Detail for each.
*/
fun List<Alteration.Status>?.flatAlterationBonus(): List<NetworkThrow.Detail> {
return this?.flatMap { status ->
status.bonus.map { bonus ->
return this?.mapNotNull { status ->
status.bonus?.let { bonus ->
allValue.add(bonus.value)
NetworkThrow.Detail(
title = bonus.title,
title = status.name,
result = "${bonus.value}",
)
}

View file

@ -1,6 +1,8 @@
package com.pixelized.rplexicon.data.model
import android.net.Uri
import com.pixelized.rplexicon.data.model.roll.Dice
import com.pixelized.rplexicon.data.model.roll.Flat
data class Alteration(
val icon: Uri?,
@ -19,7 +21,7 @@ data class Alteration(
val amateurism: Boolean = false,
val fail: Boolean = false,
val critical: Boolean = false,
val dices: List<Roll.Dice> = emptyList(),
val bonus: List<Roll.Bonus> = emptyList(),
val dices: List<Dice> = emptyList(),
val bonus: Flat? = null,
)
}

View file

@ -1,5 +1,7 @@
package com.pixelized.rplexicon.data.model
import com.pixelized.rplexicon.data.model.roll.Throw
data class AssignedSpell(
val hit: Throw?,
val effect: Throw?,

View file

@ -1,6 +1,7 @@
package com.pixelized.rplexicon.data.model
import android.net.Uri
import com.pixelized.rplexicon.data.model.roll.Throw
data class Attack(
val icon: Uri?,
@ -13,6 +14,11 @@ data class Attack(
) {
enum class Type(val key: String) {
PHYSICAL_MELEE_ATTACK("Mêlée"),
PHYSICAL_RANGE_ATTACK("Distance"),
PHYSICAL_RANGE_ATTACK("Distance");
fun toProperty(): Property = when (this) {
PHYSICAL_MELEE_ATTACK -> Property.PHYSICAL_MELEE_ATTACK
PHYSICAL_RANGE_ATTACK -> Property.PHYSICAL_RANGE_ATTACK
}
}
}

View file

@ -1,6 +1,7 @@
package com.pixelized.rplexicon.data.model
import android.net.Uri
import com.pixelized.rplexicon.data.model.roll.Throw
data class ObjectAction(
val prefix: String?,

View file

@ -1,26 +0,0 @@
package com.pixelized.rplexicon.data.model
data class Roll(
val character: String,
val canUseCriticalDice: Boolean,
val title: String,
val highlight: String? = null,
val dices: List<Dice>,
val bonus: List<Bonus>,
) {
data class Dice(
val title: String? = null,
val advantage: Boolean = false,
val disadvantage: Boolean = false,
val emphasis: Boolean,
val count: Int,
val faces: Int,
) {
val label: String = "${count}d${faces}"
}
data class Bonus(
val title: String,
val value: Int,
)
}

View file

@ -1,6 +1,7 @@
package com.pixelized.rplexicon.data.model
import android.net.Uri
import com.pixelized.rplexicon.data.model.roll.Throw
data class Skill(
val icon: Uri?,

View file

@ -1,8 +0,0 @@
package com.pixelized.rplexicon.data.model
class Throw(
val amount: Int,
val faces: Int,
val flat: Int,
val modifier: List<Property>,
)

View file

@ -0,0 +1,14 @@
package com.pixelized.rplexicon.data.model.roll
import com.pixelized.rplexicon.utilitary.extentions.toLabel
data class Dice(
val sign: Int = 1,
val advantage: Boolean = false,
val disadvantage: Boolean = false,
val emphasis: Boolean = false,
val count: Int,
val faces: Int,
) {
override fun toString(): String = toLabel(ignoreSign = false)
}

View file

@ -0,0 +1,11 @@
package com.pixelized.rplexicon.data.model.roll
import com.pixelized.rplexicon.utilitary.extentions.toLabel
data class Flat(
val value: Int,
) {
override fun toString(): String {
return value.toLabel()
}
}

View file

@ -0,0 +1,9 @@
package com.pixelized.rplexicon.data.model.roll
import com.pixelized.rplexicon.data.model.Property
class Throw(
val dice: Dice,
val flat: Flat?,
val modifier: List<Property>,
)

View file

@ -25,56 +25,37 @@ class AlterationParser @Inject constructor(
sheet.forEachRowIndexed { index, row ->
when (index) {
0 -> updateStructure(
row = row,
columns = COLUMNS,
)
0 -> updateStructure(row = row, columns = COLUMNS)
else -> {
val name = row.parse(column = NAME)
val source = row.parse(column = SOURCE)
val target = row.parse(column = TARGET)
val alteration = if (name != null && source != null && target != null) {
Alteration(
if (name != null && source != null && target != null) {
val alteration = Alteration(
icon = row.parseUri(column = ICON),
name = name,
source = source,
target = target,
status = properties
.mapNotNull { property ->
val value = row.parse(column = column(property.key))
if (value?.isNotEmpty() == true) {
property to parseAlterationStatus(
name = name,
value = value
)
} else {
null
}
}
.toMap(),
status = properties.mapNotNull { property ->
val column = column(property.key)
row.parse(column = column)
?.takeIf { it.isNotEmpty() }
?.let { parseAlterationStatus(name = name, value = it) }
?.let { property to it }
}.toMap(),
)
} else {
null
}
if (alteration != null) {
if (alteration.target == EFFECT && alteration.source == EFFECT) {
alterations
.getOrPut(alteration.name) { mutableListOf() }
.add(alteration)
} else {
characterSheets
.filter { // check if the alteration is applicable to the character
alteration.target.let { target ->
target == ALL || target == it.name || target == it.race || it.characterClass.any { it.value == target }
}
characterSheets
.filter { // check if the alteration is applicable to the character
alteration.target.let { target ->
target == ALL || target == it.name || target == it.race || it.characterClass.any { it.value == target }
}
.forEach { sheet -> // check the default alteration state for that character
alterations
.getOrPut(sheet.name) { mutableListOf() }
.add(alteration)
}
}
}
.forEach { sheet -> // check the default alteration state for that character
alterations
.getOrPut(sheet.name) { mutableListOf() }
.add(alteration)
}
}
}
}
@ -83,25 +64,21 @@ class AlterationParser @Inject constructor(
return@parserScope alterations
}
private fun parseAlterationStatus(name: String, value: String): Alteration.Status =
when (value) {
ADVANTAGE -> Alteration.Status(name = name, advantage = true)
DISADVANTAGE -> Alteration.Status(name = name, disadvantage = true)
EMPHASIS -> Alteration.Status(name = name, emphasis = true)
MASTERY -> Alteration.Status(name = name, mastery = true)
EXPERTISE -> Alteration.Status(name = name, expertise = true)
AMATEURISM -> Alteration.Status(name = name, amateurism = true)
FAIL -> Alteration.Status(name = name, fail = true)
CRITICAL -> Alteration.Status(name = name, critical = true)
else -> {
Alteration.Status(
name = name,
dices = diceParser.findAll(title = name, value = value),
bonus = flatParser.findAll(title = name, value = value),
)
}
}
private fun parseAlterationStatus(name: String, value: String) = when (value) {
ADVANTAGE -> Alteration.Status(name = name, advantage = true)
DISADVANTAGE -> Alteration.Status(name = name, disadvantage = true)
EMPHASIS -> Alteration.Status(name = name, emphasis = true)
MASTERY -> Alteration.Status(name = name, mastery = true)
EXPERTISE -> Alteration.Status(name = name, expertise = true)
AMATEURISM -> Alteration.Status(name = name, amateurism = true)
FAIL -> Alteration.Status(name = name, fail = true)
CRITICAL -> Alteration.Status(name = name, critical = true)
else -> Alteration.Status(
name = name,
dices = diceParser.parse(value = value),
bonus = flatParser.parse(value = value),
)
}
companion object {
private const val ALL = "Tous"
@ -113,12 +90,11 @@ class AlterationParser @Inject constructor(
private const val AMATEURISM = "ama"
private const val FAIL = "fail"
private const val CRITICAL = "crit"
private const val EFFECT = "Effet"
private val ICON = column("Icone")
private val NAME = column("Altération")
private val TARGET = column("Cible")
private val SOURCE = column("Source")
private val ICON = column("Icone")
private val COLUMNS
get() = listOf(NAME, SOURCE, TARGET, ICON) + Property.entries.map { column(it.key) }
}

View file

@ -1,28 +1,27 @@
package com.pixelized.rplexicon.data.parser.roll
import com.pixelized.rplexicon.data.model.Roll
import com.pixelized.rplexicon.data.model.roll.Dice
import javax.inject.Inject
class DiceParser @Inject constructor() {
companion object {
private val DICE_REGEX = Regex("(a|adv|d|dis|e|emp)*(\\d+)d(\\d+)")
private val DICE_REGEX = Regex("([-+])?\\s*([ade])?(\\d+)*d(\\d+)")
}
fun findAll(title: String? = null, value: String): List<Roll.Dice> =
DICE_REGEX.findAll(value).map { it.parse(title = title) }.toList()
private fun MatchResult.parse(
title: String? = null,
): Roll.Dice {
val (status, count, faces) = destructured
return Roll.Dice(
title = title,
advantage = status == "a" || status == "adv",
disadvantage = status == "d" || status == "dis",
emphasis = status == "e" || status == "emp",
count = count.toIntOrNull() ?: 0,
faces = faces.toIntOrNull() ?: 0,
)
fun parse(value: String): List<Dice> {
return DICE_REGEX.findAll(value)
.map {
val (sign, status, count, faces) = it.destructured
Dice(
sign = if (sign == "-") -1 else 1,
advantage = status == "a",
disadvantage = status == "d",
emphasis = status == "e",
count = count.toIntOrNull() ?: 1,
faces = faces.toIntOrNull() ?: 0,
)
}
.toList()
}
}

View file

@ -1,6 +1,6 @@
package com.pixelized.rplexicon.data.parser.roll
import com.pixelized.rplexicon.data.model.Roll
import com.pixelized.rplexicon.data.model.roll.Flat
import javax.inject.Inject
class FlatValueParser @Inject constructor() {
@ -9,21 +9,11 @@ class FlatValueParser @Inject constructor() {
private val FLAT_REGEX = Regex("(?<!d)([+-]\\s?\\d+)(?!d)|^\\d+\$")
}
fun parse(value: String): Int {
fun parse(value: String): Flat? {
return FLAT_REGEX.findAll(value)
.sumOf { it.value.replace(" ", "").toIntOrNull() ?: 0 }
}
fun findAll(title: String, value: String): List<Roll.Bonus> {
return FLAT_REGEX.findAll(value).map { it.parse(title = title) }.toList()
}
private fun MatchResult.parse(
title: String,
): Roll.Bonus {
return Roll.Bonus(
title = title,
value = value.toIntOrNull() ?: 0,
)
.mapNotNull { it.value.replace(" ", "").toIntOrNull() }
.toList()
.takeIf { it.isNotEmpty() }
?.let { Flat(value = it.sum()) }
}
}

View file

@ -31,7 +31,7 @@ class ModifierParser @Inject constructor(
)
}
fun findAll(value: String): List<Property> {
fun parse(value: String): List<Property> {
return MODIFIER_REGEX.findAll(value)
.mapNotNull { propertyParser.parseProperty(it.value) }
.toList()

View file

@ -1,6 +1,6 @@
package com.pixelized.rplexicon.data.parser.roll
import com.pixelized.rplexicon.data.model.Throw
import com.pixelized.rplexicon.data.model.roll.Throw
import javax.inject.Inject
class ThrowParser @Inject constructor(
@ -10,15 +10,12 @@ class ThrowParser @Inject constructor(
) {
fun parse(value: String?): Throw? {
if (value != null) {
val dice = diceParser.findAll(value = value).firstOrNull()
val dice = diceParser.parse(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,
dice = dice,
flat = flatValueParser.parse(value = value),
modifier = modifierParser.parse(value = value),
)
}
}

View file

@ -28,7 +28,9 @@ 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.data.model.Throw
import com.pixelized.rplexicon.data.model.roll.Dice
import com.pixelized.rplexicon.data.model.roll.Flat
import com.pixelized.rplexicon.data.model.roll.Throw
import com.pixelized.rplexicon.ui.composable.AsyncImage
import com.pixelized.rplexicon.ui.theme.LexiconTheme
@ -116,7 +118,11 @@ private fun ObjectItemPreview() {
prefix = "Parchemin de ",
name = "Bénédiction",
original = "Blessing",
effect = Throw(1, 1, 0, emptyList()),
effect = Throw(
dice = Dice(count = 1, faces = 1),
flat = Flat(value = 0),
modifier = emptyList(),
),
),
onObject = { },
onUse = { },

View file

@ -4,7 +4,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import com.pixelized.rplexicon.data.model.Throw
import com.pixelized.rplexicon.data.model.roll.Dice
import com.pixelized.rplexicon.data.model.roll.Flat
import com.pixelized.rplexicon.data.model.roll.Throw
import com.pixelized.rplexicon.ui.screens.character.composable.actions.ObjectItemUio
@Composable
@ -24,7 +26,11 @@ fun rememberObjectListStatePreview() = remember {
prefix = "Parchemin de",
name = "Bénédiction",
original = "Blessing",
effect = Throw(1, 1, 0, emptyList()),
effect = Throw(
dice = Dice(count = 1, faces = 1),
flat = Flat(value = 0),
modifier = emptyList(),
),
),
)
)

View file

@ -7,6 +7,7 @@ import com.pixelized.rplexicon.data.model.CharacterSheet
import com.pixelized.rplexicon.data.model.Property
import com.pixelized.rplexicon.ui.screens.character.composable.actions.AttackUio
import com.pixelized.rplexicon.utilitary.extentions.icon
import com.pixelized.rplexicon.utilitary.extentions.toLabel
import com.pixelized.rplexicon.utilitary.extentions.modifier
import javax.inject.Inject
@ -17,16 +18,13 @@ class AttackUioFactory @Inject constructor() {
alterations: Map<Property, List<Alteration.Status>>,
attack: Attack,
): AttackUio {
val hit = attack.hit?.let { dice ->
val hit = attack.hit?.let { diceThrow ->
// compute alteration for attack type.
val hitAlteration: Int = alterations[when (attack.type) {
Attack.Type.PHYSICAL_MELEE_ATTACK -> Property.PHYSICAL_MELEE_ATTACK
Attack.Type.PHYSICAL_RANGE_ATTACK -> Property.PHYSICAL_RANGE_ATTACK
}]?.sumOf {
it.bonus.sumOf { bonus -> bonus.value }
} ?: 0
val hitAlteration: Int = alterations[attack.type.toProperty()]
?.sumOf { it.bonus?.value ?: 0 }
?: 0
// compute stats modifier
val modifier = dice.modifier.sumOf {
val modifier = diceThrow.modifier.sumOf {
when (it) {
Property.PROFICIENCY -> characterSheet.proficiency
Property.STRENGTH -> characterSheet.strength.modifier
@ -36,21 +34,18 @@ class AttackUioFactory @Inject constructor() {
} + hitAlteration
// Build the UIO.
AttackUio.Dice(
icon = dice.faces.icon,
label = "${dice.amount}d${dice.faces}${if (modifier > 0) "+$modifier" else ""}",
icon = diceThrow.dice.icon,
label = "${diceThrow.dice.toLabel()}${modifier.toLabel(true)}",
)
}
val damage = attack.damage?.let { dice ->
val damage = attack.damage?.let { diceThrow ->
// compute alteration for attack type.
val damageAlteration: Int = alterations[when (attack.type) {
Attack.Type.PHYSICAL_MELEE_ATTACK -> Property.PHYSICAL_MELEE_DAMAGE
Attack.Type.PHYSICAL_RANGE_ATTACK -> Property.PHYSICAL_RANGE_DAMAGE
}]?.sumOf {
it.bonus.sumOf { bonus -> bonus.value }
} ?: 0
val damageAlteration: Int = alterations[attack.type.toProperty()]
?.sumOf { it.bonus?.value ?: 0 }
?: 0
// compute stats modifier
val modifier = dice.modifier.sumOf {
val modifier = diceThrow.modifier.sumOf {
when (it) {
Property.PROFICIENCY -> characterSheet.proficiency
Property.STRENGTH -> characterSheet.strength.modifier
@ -60,8 +55,8 @@ class AttackUioFactory @Inject constructor() {
} + damageAlteration
// Build the UIO.
AttackUio.Dice(
icon = dice.faces.icon,
label = "${dice.amount}d${dice.faces}${if (modifier > 0) "+$modifier" else ""}",
icon = diceThrow.dice.icon,
label = "${diceThrow.dice.toLabel()}${modifier.toLabel(true)}",
)
}

View file

@ -7,11 +7,11 @@ import com.pixelized.rplexicon.data.network.CharacterSheetFire
import com.pixelized.rplexicon.data.repository.character.DescriptionRepository
import com.pixelized.rplexicon.ui.screens.character.composable.actions.SkillItemUio
import com.pixelized.rplexicon.utilitary.extentions.icon
import com.pixelized.rplexicon.utilitary.extentions.toLabel
import com.pixelized.rplexicon.utilitary.extentions.local.base
import com.pixelized.rplexicon.utilitary.extentions.local.primary
import com.pixelized.rplexicon.utilitary.extentions.local.secondary
import com.pixelized.rplexicon.utilitary.extentions.modifier
import com.pixelized.rplexicon.utilitary.extentions.toLabel
import javax.inject.Inject
class SkillFactoryUioFactory @Inject constructor(
@ -40,7 +40,7 @@ class SkillFactoryUioFactory @Inject constructor(
else -> 0
}
} ?: 0
val effectFlat = skill.effect?.flat ?: 0
val effectFlat = skill.effect?.flat?.value ?: 0
val modifier = effectModifier + effectFlat
SkillItemUio(
@ -51,8 +51,8 @@ class SkillFactoryUioFactory @Inject constructor(
cost = skill.cost,
effect = skill.effect?.let {
SkillItemUio.Dice(
icon = it.faces.icon,
label = "${skill.effect.amount}d${skill.effect.faces}${if (modifier > 0) modifier.toLabel() else ""}",
icon = it.dice.icon,
label = "${skill.effect.dice.toLabel()}${modifier.toLabel(true)}",
)
},
value = fire?.skills?.get(skill.name) ?: 0,

View file

@ -1,12 +1,12 @@
package com.pixelized.rplexicon.ui.screens.character.factory
import androidx.compose.animation.core.spring
import com.pixelized.rplexicon.data.model.AssignedSpell
import com.pixelized.rplexicon.data.model.CharacterSheet
import com.pixelized.rplexicon.data.model.Property
import com.pixelized.rplexicon.data.repository.character.DescriptionRepository
import com.pixelized.rplexicon.ui.screens.character.composable.actions.SpellUio
import com.pixelized.rplexicon.utilitary.extentions.icon
import com.pixelized.rplexicon.utilitary.extentions.toLabel
import com.pixelized.rplexicon.utilitary.extentions.modifier
import javax.inject.Inject
@ -19,8 +19,8 @@ class SpellUioFactory @Inject constructor(
characterSheet: CharacterSheet,
warlockSpellLevel: Int?,
): SpellUio {
val hit = assignedSpell.hit?.let { dice ->
val modifier = dice.modifier.sumOf {
val hit = assignedSpell.hit?.let { diceThrow ->
val modifier = diceThrow.modifier.sumOf {
when (it) {
Property.PROFICIENCY -> characterSheet.proficiency
Property.INTELLIGENCE -> characterSheet.intelligence.modifier
@ -30,12 +30,12 @@ class SpellUioFactory @Inject constructor(
}
}
SpellUio.Dice(
icon = dice.faces.icon,
label = "${dice.amount}d${dice.faces}${if (modifier > 0) "+$modifier" else ""}",
icon = diceThrow.dice.icon,
label = "${diceThrow.dice.toLabel()}${modifier.toLabel(true)}",
)
}
val effect = assignedSpell.effect?.let { dice ->
val modifier = dice.modifier.sumOf {
val effect = assignedSpell.effect?.let { diceThrow ->
val modifier = diceThrow.modifier.sumOf {
when (it) {
Property.PROFICIENCY -> characterSheet.proficiency
Property.STRENGTH -> characterSheet.strength.modifier
@ -46,31 +46,32 @@ class SpellUioFactory @Inject constructor(
Property.CHARISMA -> characterSheet.charisma.modifier
else -> 0
}
} + dice.flat
} + (diceThrow.flat?.value ?: 0)
val level = assignedSpell.level
val delta = warlockSpellLevel?.minus(assignedSpell.spell.level) ?: 0
if (warlockSpellLevel == null || level == null || delta <= 0) {
// default case of non warlock character of the spell don't scale
SpellUio.Dice(
icon = dice.faces.icon,
label = "${dice.amount}d${dice.faces}${if (modifier > 0) "+$modifier" else ""}",
icon = diceThrow.dice.icon,
label = "${diceThrow.dice.toLabel()}${modifier.toLabel(true)}",
)
} else if (diceThrow.dice.faces == level.dice.faces) {
// warlock character, upscale the spell to warlock spell level
val upscaleModifier = modifier + (level.flat?.value ?: 0) * delta
val diceCount = diceThrow.dice.count + level.dice.count * delta
SpellUio.Dice(
icon = diceThrow.dice.icon,
label = "${diceCount}d${diceThrow.dice.faces}${upscaleModifier.toLabel(true)}",
)
} else {
// warlock character, upscale the spell to warlock spell level
if (dice.faces == level.faces) {
val upscaleModifier = modifier + level.flat * delta
SpellUio.Dice(
icon = dice.faces.icon,
label = "${dice.amount + level.amount * delta}d${dice.faces}${if (upscaleModifier > 0) "+$upscaleModifier" else ""}",
)
} else {
SpellUio.Dice(
icon = dice.faces.icon,
label = "${dice.amount}d${dice.faces}${modifier.takeIf { it > 0 }?.let { "+$it" } ?: ""} + " +
"${level.amount}d${level.faces * delta}${(level.flat * delta).takeIf { it > 0 }?.let { "+$it" } ?: ""}",
)
}
// warlock character, case where the dice use to upscale is not the one from the spell.
val deltaModifier = level.flat?.value?.times(delta) ?: 0
SpellUio.Dice(
icon = diceThrow.dice.icon,
label = "${diceThrow.dice.toLabel()}${modifier.toLabel(true)}" +
"+ ${level.dice.count * delta}d${level.dice.faces}${deltaModifier.toLabel(true)}",
)
}
}
return SpellUio(

View file

@ -12,7 +12,7 @@ import com.pixelized.rplexicon.data.model.AssignedSpell
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.Throw
import com.pixelized.rplexicon.data.model.roll.Throw
import com.pixelized.rplexicon.data.network.CharacterSheetFire
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
@ -28,12 +28,14 @@ import com.pixelized.rplexicon.utilitary.extentions.local.firstSpellSlot
import com.pixelized.rplexicon.utilitary.extentions.local.highestSpellLevel
import com.pixelized.rplexicon.utilitary.extentions.local.spell
import com.pixelized.rplexicon.utilitary.extentions.modifier
import com.pixelized.rplexicon.utilitary.extentions.signLabel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject
import kotlin.math.abs
import kotlin.math.max
@HiltViewModel
@ -101,7 +103,7 @@ class SpellsViewModel @Inject constructor(
spell = name,
)
if (assignedSpell != null && character != null && characterFire != null) {
val icon = assignedSpell.effect?.faces?.icon ?: R.drawable.ic_d20_24
val icon = assignedSpell.effect?.dice?.icon ?: R.drawable.ic_d20_24
val base = assignedSpell.effect?.toString(character = character, level = 1) ?: ""
_preparedSpellLevel.value = SpellChooserUio(
name = name,
@ -177,9 +179,9 @@ class SpellsViewModel @Inject constructor(
private fun Throw.toString(character: CharacterSheet, level: Int = 0): String? {
val modifierLabel = modifier
.sumOf { modifier -> modifier.toValue(character = character) }
.let { if (it > 0) "+${it * level}" else "" }
.let { if (it != 0) "${it.signLabel}${abs(it) * level}" else "" }
return when (level > 0) {
true -> "${amount * level}d${faces}${modifierLabel}"
true -> "${dice.count * level}d${dice.faces}${modifierLabel}"
else -> null
}
}

View file

@ -20,42 +20,42 @@ class DiceFactory @Inject constructor(
is DiceThrow.PhysicalMeleeDamage -> actionRepository.find(
character = diceThrow.character,
action = diceThrow.weapon
)?.damage?.faces?.icon?.let {
)?.damage?.dice?.icon?.let {
RollDiceUio(icon = it)
}
is DiceThrow.PhysicalRangeDamage -> actionRepository.find(
character = diceThrow.character,
action = diceThrow.weapon
)?.damage?.faces?.icon?.let {
)?.damage?.dice?.icon?.let {
RollDiceUio(icon = it)
}
is DiceThrow.Skill -> skillRepository.find(
character = diceThrow.character,
skill = diceThrow.skill
)?.effect?.faces?.icon?.let {
)?.effect?.dice?.icon?.let {
RollDiceUio(icon = it)
}
is DiceThrow.SpellDamage -> spellRepository.findAssignedSpell(
character = diceThrow.character,
spell = diceThrow.spell
)?.effect?.faces?.icon?.let {
)?.effect?.dice?.icon?.let {
RollDiceUio(icon = it)
}
is DiceThrow.SpellEffect -> spellRepository.findAssignedSpell(
character = diceThrow.character,
spell = diceThrow.spell
)?.effect?.faces?.icon?.let {
)?.effect?.dice?.icon?.let {
RollDiceUio(icon = it)
}
is DiceThrow.Object -> objectActionRepository.find(
character = diceThrow.character,
item = diceThrow.item,
)?.effect?.faces?.icon?.let {
)?.effect?.dice?.icon?.let {
RollDiceUio(icon = it)
}

View file

@ -0,0 +1,18 @@
package com.pixelized.rplexicon.utilitary.extentions
import androidx.annotation.DrawableRes
import com.pixelized.rplexicon.data.model.roll.Dice
val Dice.icon: Int
@DrawableRes
get() = faces.icon
fun Dice.toLabel(ignoreSign: Boolean = true): String = buildString {
if (!ignoreSign) append(sign.signLabel)
if (advantage) append("a")
if (disadvantage) append("d")
if (emphasis) append("e")
append(count)
append("d")
append(faces)
}

View file

@ -1,6 +1,7 @@
package com.pixelized.rplexicon.utilitary.extentions
import android.net.Uri
import androidx.annotation.DrawableRes
import com.pixelized.rplexicon.BuildConfig
import com.pixelized.rplexicon.R
import com.pixelized.rplexicon.data.model.Alteration
@ -11,6 +12,7 @@ import kotlin.math.floor
import kotlin.math.max
val Int.icon
@DrawableRes
get() = when (this) {
4 -> R.drawable.ic_d4_24
6 -> R.drawable.ic_d6_24
@ -30,8 +32,8 @@ fun Int?.masteryMultiplier(status: List<Alteration.Status>?): Int {
}
}
fun Int.toLabel(): String =
"${this.signLabel}${abs(this)}"
fun Int.toLabel(excludeZero: Boolean = false): String =
if (excludeZero && this == 0) "" else "${this.signLabel}${abs(this)}"
val Int.signLabel: String
get() = if (this < 0) "-" else "+"

View file

@ -14,7 +14,7 @@ fun List<Alteration>.toStatus(): Map<Property, List<Alteration.Status>> {
}
val List<Alteration.Status>?.sum: Int
get() = this?.sumOf { alt -> alt.bonus.sumOf { it.value } } ?: 0
get() = this?.sumOf { alt -> alt.bonus?.value ?: 0 } ?: 0
val List<Alteration.Status>?.advantage: Boolean
get() = this?.any { it.advantage } ?: false