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 ec3afcf..7019d5d 100644 --- a/app/src/main/java/com/pixelized/rplexicon/business/DiceThrowUseCase.kt +++ b/app/src/main/java/com/pixelized/rplexicon/business/DiceThrowUseCase.kt @@ -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?.flatAlterationBonus(): List { - 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}", ) } diff --git a/app/src/main/java/com/pixelized/rplexicon/data/model/Alteration.kt b/app/src/main/java/com/pixelized/rplexicon/data/model/Alteration.kt index 8708645..a641824 100644 --- a/app/src/main/java/com/pixelized/rplexicon/data/model/Alteration.kt +++ b/app/src/main/java/com/pixelized/rplexicon/data/model/Alteration.kt @@ -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 = emptyList(), - val bonus: List = emptyList(), + val dices: List = emptyList(), + val bonus: Flat? = null, ) } \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/data/model/AssignedSpell.kt b/app/src/main/java/com/pixelized/rplexicon/data/model/AssignedSpell.kt index 024fb34..90b11d7 100644 --- a/app/src/main/java/com/pixelized/rplexicon/data/model/AssignedSpell.kt +++ b/app/src/main/java/com/pixelized/rplexicon/data/model/AssignedSpell.kt @@ -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?, diff --git a/app/src/main/java/com/pixelized/rplexicon/data/model/Attack.kt b/app/src/main/java/com/pixelized/rplexicon/data/model/Attack.kt index c4d7c2a..8b81358 100644 --- a/app/src/main/java/com/pixelized/rplexicon/data/model/Attack.kt +++ b/app/src/main/java/com/pixelized/rplexicon/data/model/Attack.kt @@ -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 + } } } \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/data/model/ObjectAction.kt b/app/src/main/java/com/pixelized/rplexicon/data/model/ObjectAction.kt index bd61122..10a3e3f 100644 --- a/app/src/main/java/com/pixelized/rplexicon/data/model/ObjectAction.kt +++ b/app/src/main/java/com/pixelized/rplexicon/data/model/ObjectAction.kt @@ -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?, diff --git a/app/src/main/java/com/pixelized/rplexicon/data/model/Roll.kt b/app/src/main/java/com/pixelized/rplexicon/data/model/Roll.kt deleted file mode 100644 index e3f437b..0000000 --- a/app/src/main/java/com/pixelized/rplexicon/data/model/Roll.kt +++ /dev/null @@ -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, - val bonus: List, -) { - 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, - ) -} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/data/model/Skill.kt b/app/src/main/java/com/pixelized/rplexicon/data/model/Skill.kt index 3b33358..1ceecf9 100644 --- a/app/src/main/java/com/pixelized/rplexicon/data/model/Skill.kt +++ b/app/src/main/java/com/pixelized/rplexicon/data/model/Skill.kt @@ -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?, diff --git a/app/src/main/java/com/pixelized/rplexicon/data/model/Throw.kt b/app/src/main/java/com/pixelized/rplexicon/data/model/Throw.kt deleted file mode 100644 index 042d414..0000000 --- a/app/src/main/java/com/pixelized/rplexicon/data/model/Throw.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.pixelized.rplexicon.data.model - -class Throw( - val amount: Int, - val faces: Int, - val flat: Int, - val modifier: List, -) \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/data/model/roll/Dice.kt b/app/src/main/java/com/pixelized/rplexicon/data/model/roll/Dice.kt new file mode 100644 index 0000000..280f22e --- /dev/null +++ b/app/src/main/java/com/pixelized/rplexicon/data/model/roll/Dice.kt @@ -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) +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/data/model/roll/Flat.kt b/app/src/main/java/com/pixelized/rplexicon/data/model/roll/Flat.kt new file mode 100644 index 0000000..b220b7b --- /dev/null +++ b/app/src/main/java/com/pixelized/rplexicon/data/model/roll/Flat.kt @@ -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() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/data/model/roll/Throw.kt b/app/src/main/java/com/pixelized/rplexicon/data/model/roll/Throw.kt new file mode 100644 index 0000000..5063917 --- /dev/null +++ b/app/src/main/java/com/pixelized/rplexicon/data/model/roll/Throw.kt @@ -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, +) \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/data/parser/alteration/AlterationParser.kt b/app/src/main/java/com/pixelized/rplexicon/data/parser/alteration/AlterationParser.kt index eeefb54..3441c71 100644 --- a/app/src/main/java/com/pixelized/rplexicon/data/parser/alteration/AlterationParser.kt +++ b/app/src/main/java/com/pixelized/rplexicon/data/parser/alteration/AlterationParser.kt @@ -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) } } diff --git a/app/src/main/java/com/pixelized/rplexicon/data/parser/roll/DiceParser.kt b/app/src/main/java/com/pixelized/rplexicon/data/parser/roll/DiceParser.kt index eb872ad..42438e5 100644 --- a/app/src/main/java/com/pixelized/rplexicon/data/parser/roll/DiceParser.kt +++ b/app/src/main/java/com/pixelized/rplexicon/data/parser/roll/DiceParser.kt @@ -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 = - 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 { + 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() } } \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/data/parser/roll/FlatValueParser.kt b/app/src/main/java/com/pixelized/rplexicon/data/parser/roll/FlatValueParser.kt index 6bc40de..d8246f0 100644 --- a/app/src/main/java/com/pixelized/rplexicon/data/parser/roll/FlatValueParser.kt +++ b/app/src/main/java/com/pixelized/rplexicon/data/parser/roll/FlatValueParser.kt @@ -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("(? { - 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()) } } } \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/data/parser/roll/ModifierParser.kt b/app/src/main/java/com/pixelized/rplexicon/data/parser/roll/ModifierParser.kt index c948314..0642c44 100644 --- a/app/src/main/java/com/pixelized/rplexicon/data/parser/roll/ModifierParser.kt +++ b/app/src/main/java/com/pixelized/rplexicon/data/parser/roll/ModifierParser.kt @@ -31,7 +31,7 @@ class ModifierParser @Inject constructor( ) } - fun findAll(value: String): List { + fun parse(value: String): List { return MODIFIER_REGEX.findAll(value) .mapNotNull { propertyParser.parseProperty(it.value) } .toList() diff --git a/app/src/main/java/com/pixelized/rplexicon/data/parser/roll/ThrowParser.kt b/app/src/main/java/com/pixelized/rplexicon/data/parser/roll/ThrowParser.kt index d45b7a3..8f20f59 100644 --- a/app/src/main/java/com/pixelized/rplexicon/data/parser/roll/ThrowParser.kt +++ b/app/src/main/java/com/pixelized/rplexicon/data/parser/roll/ThrowParser.kt @@ -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), ) } } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/ObjectItem.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/ObjectItem.kt index 7e9a1ad..a3dbaa3 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/ObjectItem.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/ObjectItem.kt @@ -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 = { }, diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/preview/rememberObjectListStatePreview.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/preview/rememberObjectListStatePreview.kt index 752cbc6..139e90e 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/preview/rememberObjectListStatePreview.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/preview/rememberObjectListStatePreview.kt @@ -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(), + ), ), ) ) diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/factory/AttackUioFactory.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/factory/AttackUioFactory.kt index 6b099a9..ece8cff 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/factory/AttackUioFactory.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/factory/AttackUioFactory.kt @@ -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>, 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)}", ) } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/factory/SkillFactoryUioFactory.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/factory/SkillFactoryUioFactory.kt index 5a7cf51..dc9b551 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/factory/SkillFactoryUioFactory.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/factory/SkillFactoryUioFactory.kt @@ -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, 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 0fd33d7..c7330b5 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 @@ -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( diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/SpellsViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/SpellsViewModel.kt index 8162cb9..1f477b8 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/SpellsViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/SpellsViewModel.kt @@ -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 } } 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 253024c..782f687 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 @@ -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) } diff --git a/app/src/main/java/com/pixelized/rplexicon/utilitary/extentions/DiceEx.kt b/app/src/main/java/com/pixelized/rplexicon/utilitary/extentions/DiceEx.kt new file mode 100644 index 0000000..c1b9952 --- /dev/null +++ b/app/src/main/java/com/pixelized/rplexicon/utilitary/extentions/DiceEx.kt @@ -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) +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/utilitary/extentions/IntEx.kt b/app/src/main/java/com/pixelized/rplexicon/utilitary/extentions/IntEx.kt index 1353c92..9831116 100644 --- a/app/src/main/java/com/pixelized/rplexicon/utilitary/extentions/IntEx.kt +++ b/app/src/main/java/com/pixelized/rplexicon/utilitary/extentions/IntEx.kt @@ -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?): 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 "+" diff --git a/app/src/main/java/com/pixelized/rplexicon/utilitary/extentions/local/AlterationEx.kt b/app/src/main/java/com/pixelized/rplexicon/utilitary/extentions/local/AlterationEx.kt index c485293..0437677 100644 --- a/app/src/main/java/com/pixelized/rplexicon/utilitary/extentions/local/AlterationEx.kt +++ b/app/src/main/java/com/pixelized/rplexicon/utilitary/extentions/local/AlterationEx.kt @@ -14,7 +14,7 @@ fun List.toStatus(): Map> { } val List?.sum: Int - get() = this?.sumOf { alt -> alt.bonus.sumOf { it.value } } ?: 0 + get() = this?.sumOf { alt -> alt.bonus?.value ?: 0 } ?: 0 val List?.advantage: Boolean get() = this?.any { it.advantage } ?: false