Alteration rework.
This commit is contained in:
parent
c5874fcc8c
commit
e01aa0893c
36 changed files with 1777 additions and 1088 deletions
|
|
@ -0,0 +1,939 @@
|
|||
package com.pixelized.rplexicon.business
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.model.Alteration
|
||||
import com.pixelized.rplexicon.model.AssignedSpell
|
||||
import com.pixelized.rplexicon.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.model.DiceThrow
|
||||
import com.pixelized.rplexicon.model.Property
|
||||
import com.pixelized.rplexicon.model.Throw
|
||||
import com.pixelized.rplexicon.repository.data.ActionRepository
|
||||
import com.pixelized.rplexicon.repository.data.AlterationRepository
|
||||
import com.pixelized.rplexicon.repository.data.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.repository.data.SpellRepository
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollDiceUio
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowsCardUio
|
||||
import com.pixelized.rplexicon.utilitary.extentions.icon
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.advantage
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.disadvantage
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.fail
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.isBrutalCritical
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.isCritical
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.isSavageAttacks
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.sum
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.toStatus
|
||||
import com.pixelized.rplexicon.utilitary.extentions.modifier
|
||||
import com.pixelized.rplexicon.utilitary.extentions.toLabel
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
data class DiceThrowResult(
|
||||
val dice: RollDiceUio,
|
||||
val card: ThrowsCardUio,
|
||||
)
|
||||
|
||||
@Suppress("KotlinConstantConditions")
|
||||
class DiceThrowUseCase @Inject constructor(
|
||||
private val application: Application,
|
||||
private val characterSheetRepository: CharacterSheetRepository,
|
||||
private val actionRepository: ActionRepository,
|
||||
private val spellRepository: SpellRepository,
|
||||
private val alterationRepository: AlterationRepository,
|
||||
) {
|
||||
fun roll(diceThrow: DiceThrow, alterationId: List<String>): DiceThrowResult? {
|
||||
val sheet = characterSheetRepository.find(name = diceThrow.character)
|
||||
val alterations = alterationRepository.getAlterations(character = diceThrow.character)
|
||||
.filter { alterationId.contains(it.name) }
|
||||
.toStatus()
|
||||
|
||||
return if (sheet != null) {
|
||||
when (diceThrow) {
|
||||
is DiceThrow.Initiative -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_title_initiative) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_dexterity) },
|
||||
ability = Property.INITIATIVE,
|
||||
relatedStat = Property.DEXTERITY,
|
||||
)
|
||||
|
||||
is DiceThrow.Strength -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_stat_strength) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_strength) },
|
||||
ability = Property.STRENGTH_THROW,
|
||||
relatedStat = Property.STRENGTH,
|
||||
)
|
||||
|
||||
is DiceThrow.Dexterity -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_stat_dexterity) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_dexterity) },
|
||||
ability = Property.DEXTERITY_THROW,
|
||||
relatedStat = Property.DEXTERITY,
|
||||
)
|
||||
|
||||
is DiceThrow.Constitution -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_stat_constitution) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_constitution) },
|
||||
ability = Property.CONSTITUTION_THROW,
|
||||
relatedStat = Property.CONSTITUTION,
|
||||
)
|
||||
|
||||
is DiceThrow.Intelligence -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_stat_intelligence) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_intelligence) },
|
||||
ability = Property.INTELLIGENCE_THROW,
|
||||
relatedStat = Property.INTELLIGENCE,
|
||||
)
|
||||
|
||||
is DiceThrow.Wisdom -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_stat_wisdom) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_wisdom) },
|
||||
ability = Property.WISDOM_THROW,
|
||||
relatedStat = Property.WISDOM
|
||||
)
|
||||
|
||||
is DiceThrow.Charisma -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_stat_charisma) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_charisma) },
|
||||
ability = Property.CHARISMA_THROW,
|
||||
relatedStat = Property.CHARISMA
|
||||
)
|
||||
|
||||
is DiceThrow.StrengthSavingThrow -> savingThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_stat_strength) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_strength) },
|
||||
ability = Property.STRENGTH_SAVING_THROW,
|
||||
relatedStat = Property.STRENGTH,
|
||||
)
|
||||
|
||||
is DiceThrow.DexteritySavingThrow -> savingThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_stat_dexterity) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_dexterity) },
|
||||
ability = Property.DEXTERITY_SAVING_THROW,
|
||||
relatedStat = Property.DEXTERITY,
|
||||
)
|
||||
|
||||
is DiceThrow.ConstitutionSavingThrow -> savingThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_stat_constitution) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_constitution) },
|
||||
ability = Property.CONSTITUTION_SAVING_THROW,
|
||||
relatedStat = Property.CONSTITUTION,
|
||||
)
|
||||
|
||||
is DiceThrow.IntelligenceSavingThrow -> savingThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_stat_intelligence) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_intelligence) },
|
||||
ability = Property.INTELLIGENCE_SAVING_THROW,
|
||||
relatedStat = Property.INTELLIGENCE,
|
||||
)
|
||||
|
||||
is DiceThrow.WisdomSavingThrow -> savingThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_stat_wisdom) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_wisdom) },
|
||||
ability = Property.WISDOM_SAVING_THROW,
|
||||
relatedStat = Property.WISDOM
|
||||
)
|
||||
|
||||
is DiceThrow.CharismaSavingThrow -> savingThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_stat_charisma) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_charisma) },
|
||||
ability = Property.CHARISMA_SAVING_THROW,
|
||||
relatedStat = Property.CHARISMA
|
||||
)
|
||||
|
||||
is DiceThrow.Acrobatics -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_proficiency_acrobatics) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_dexterity) },
|
||||
ability = Property.ACROBATICS,
|
||||
relatedStat = Property.DEXTERITY,
|
||||
)
|
||||
|
||||
is DiceThrow.AnimalHandling -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_proficiency_animal_handling) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_wisdom) },
|
||||
ability = Property.ANIMAL_HANDLING,
|
||||
relatedStat = Property.WISDOM,
|
||||
)
|
||||
|
||||
is DiceThrow.Arcana -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_proficiency_arcana) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_intelligence) },
|
||||
ability = Property.ARCANA,
|
||||
relatedStat = Property.INTELLIGENCE,
|
||||
)
|
||||
|
||||
is DiceThrow.Athletics -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_proficiency_athletics) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_strength) },
|
||||
ability = Property.ATHLETICS,
|
||||
relatedStat = Property.STRENGTH,
|
||||
)
|
||||
|
||||
is DiceThrow.Deception -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_proficiency_deception) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_charisma) },
|
||||
ability = Property.DECEPTION,
|
||||
relatedStat = Property.CHARISMA,
|
||||
)
|
||||
|
||||
is DiceThrow.History -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_proficiency_history) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_intelligence) },
|
||||
ability = Property.HISTORY,
|
||||
relatedStat = Property.INTELLIGENCE,
|
||||
)
|
||||
|
||||
is DiceThrow.Insight -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_proficiency_insight) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_wisdom) },
|
||||
ability = Property.INSIGHT,
|
||||
relatedStat = Property.WISDOM,
|
||||
)
|
||||
|
||||
is DiceThrow.Intimidation -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_proficiency_intimidation) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_charisma) },
|
||||
ability = Property.INTIMIDATION,
|
||||
relatedStat = Property.CHARISMA,
|
||||
)
|
||||
|
||||
is DiceThrow.Investigation -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_proficiency_investigation) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_intelligence) },
|
||||
ability = Property.INVESTIGATION,
|
||||
relatedStat = Property.INTELLIGENCE,
|
||||
)
|
||||
|
||||
is DiceThrow.Medicine -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_proficiency_medicine) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_wisdom) },
|
||||
ability = Property.MEDICINE,
|
||||
relatedStat = Property.WISDOM,
|
||||
)
|
||||
|
||||
is DiceThrow.Nature -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_proficiency_nature) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_intelligence) },
|
||||
ability = Property.NATURE,
|
||||
relatedStat = Property.INTELLIGENCE,
|
||||
)
|
||||
|
||||
is DiceThrow.Perception -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_proficiency_perception) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_wisdom) },
|
||||
ability = Property.PERSUASION,
|
||||
relatedStat = Property.WISDOM,
|
||||
)
|
||||
|
||||
is DiceThrow.Performance -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_proficiency_performance) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_charisma) },
|
||||
ability = Property.PERFORMANCE,
|
||||
relatedStat = Property.CHARISMA,
|
||||
)
|
||||
|
||||
is DiceThrow.Persuasion -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_proficiency_persuasion) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_charisma) },
|
||||
ability = Property.PERSUASION,
|
||||
relatedStat = Property.CHARISMA,
|
||||
)
|
||||
|
||||
is DiceThrow.Religion -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_proficiency_religion) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_intelligence) },
|
||||
ability = Property.RELIGION,
|
||||
relatedStat = Property.INTELLIGENCE,
|
||||
)
|
||||
|
||||
is DiceThrow.SleightOfHand -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_proficiency_sleight_of_hand) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_dexterity) },
|
||||
ability = Property.SLEIGHT_OF_HAND,
|
||||
relatedStat = Property.DEXTERITY,
|
||||
)
|
||||
|
||||
is DiceThrow.Stealth -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_proficiency_stealth) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_dexterity) },
|
||||
ability = Property.STEALTH,
|
||||
relatedStat = Property.DEXTERITY,
|
||||
)
|
||||
|
||||
is DiceThrow.Survival -> abilityThrow(
|
||||
character = sheet,
|
||||
alterations = alterations,
|
||||
abilityLabel = { getString(R.string.character_sheet_proficiency_survival) },
|
||||
relatedLabel = { getString(R.string.character_sheet_stat_wisdom) },
|
||||
ability = Property.SURVIVAL,
|
||||
relatedStat = Property.WISDOM,
|
||||
)
|
||||
|
||||
is DiceThrow.PhysicalMeleeAttack -> {
|
||||
val action = actionRepository.find(
|
||||
character = diceThrow.character,
|
||||
action = diceThrow.weapon,
|
||||
)
|
||||
actionThrow(
|
||||
character = sheet,
|
||||
action = diceThrow.weapon,
|
||||
diceThrow = action?.hit,
|
||||
title = { getString(R.string.dice_roll_attack_hit_title, it) },
|
||||
alterations = alterations,
|
||||
ability = Property.PHYSICAL_MELEE_ATTACK,
|
||||
)
|
||||
}
|
||||
|
||||
is DiceThrow.PhysicalMeleeDamage -> {
|
||||
val action = actionRepository.find(
|
||||
character = diceThrow.character,
|
||||
action = diceThrow.weapon,
|
||||
)
|
||||
actionThrow(
|
||||
character = sheet,
|
||||
action = diceThrow.weapon,
|
||||
diceThrow = action?.damage,
|
||||
title = { getString(R.string.dice_roll_attack_hit_title, it) },
|
||||
alterations = alterations,
|
||||
ability = Property.PHYSICAL_MELEE_DAMAGE,
|
||||
)
|
||||
}
|
||||
|
||||
is DiceThrow.PhysicalRangeAttack -> {
|
||||
val action = actionRepository.find(
|
||||
character = diceThrow.character,
|
||||
action = diceThrow.weapon,
|
||||
)
|
||||
actionThrow(
|
||||
character = sheet,
|
||||
action = diceThrow.weapon,
|
||||
diceThrow = action?.hit,
|
||||
title = { getString(R.string.dice_roll_attack_hit_title, it) },
|
||||
alterations = alterations,
|
||||
ability = Property.PHYSICAL_RANGE_ATTACK,
|
||||
)
|
||||
}
|
||||
|
||||
is DiceThrow.PhysicalRangeDamage -> {
|
||||
val action = actionRepository.find(
|
||||
character = diceThrow.character,
|
||||
action = diceThrow.weapon,
|
||||
)
|
||||
actionThrow(
|
||||
character = sheet,
|
||||
action = diceThrow.weapon,
|
||||
diceThrow = action?.damage,
|
||||
title = { getString(R.string.dice_roll_attack_hit_title, it) },
|
||||
alterations = alterations,
|
||||
ability = Property.PHYSICAL_RANGE_DAMAGE,
|
||||
)
|
||||
}
|
||||
|
||||
is DiceThrow.SpellAttack -> {
|
||||
val spell = spellRepository.find(
|
||||
character = diceThrow.character,
|
||||
spell = diceThrow.spell,
|
||||
)
|
||||
actionThrow(
|
||||
character = sheet,
|
||||
action = diceThrow.spell,
|
||||
diceThrow = spell?.hit,
|
||||
title = { getString(R.string.dice_roll_spell_hit_title, it) },
|
||||
alterations = alterations,
|
||||
ability = Property.SPELL_ATTACK,
|
||||
)
|
||||
}
|
||||
|
||||
is DiceThrow.SpellDamage -> {
|
||||
val spell = spellRepository.find(
|
||||
character = diceThrow.character,
|
||||
spell = diceThrow.spell,
|
||||
)
|
||||
actionThrow(
|
||||
character = sheet,
|
||||
action = diceThrow.spell,
|
||||
diceThrow = spell?.effect,
|
||||
title = { getString(R.string.dice_roll_spell_damage_title, it) },
|
||||
alterations = alterations,
|
||||
ability = Property.SPELL_DAMAGE,
|
||||
)
|
||||
}
|
||||
|
||||
is DiceThrow.SpellEffect -> {
|
||||
val spell = spellRepository.find(
|
||||
character = diceThrow.character,
|
||||
spell = diceThrow.spell,
|
||||
)
|
||||
spellThrow(
|
||||
character = sheet,
|
||||
spell = spell,
|
||||
level = diceThrow.level,
|
||||
alterations = alterations,
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun abilityThrow(
|
||||
character: CharacterSheet,
|
||||
alterations: Map<Property, List<Alteration.Status>>,
|
||||
abilityLabel: Context.() -> String,
|
||||
relatedLabel: Context.() -> String?,
|
||||
ability: Property,
|
||||
relatedStat: Property,
|
||||
): DiceThrowResult = rollAbility(
|
||||
character = character,
|
||||
alterations = alterations,
|
||||
abilityTitle = { getString(R.string.dice_roll_check_title, it) },
|
||||
abilityLabel = abilityLabel,
|
||||
relatedTitle = { label -> getString(R.string.dice_roll_bonus_detail, label) },
|
||||
relatedLabel = relatedLabel,
|
||||
ability = ability,
|
||||
relatedStat = relatedStat,
|
||||
)
|
||||
|
||||
private fun savingThrow(
|
||||
character: CharacterSheet,
|
||||
alterations: Map<Property, List<Alteration.Status>>,
|
||||
abilityLabel: Context.() -> String,
|
||||
relatedLabel: Context.() -> String?,
|
||||
ability: Property,
|
||||
relatedStat: Property,
|
||||
): DiceThrowResult = rollAbility(
|
||||
character = character,
|
||||
alterations = alterations,
|
||||
abilityTitle = { getString(R.string.dice_roll_saving_throw_title, it) },
|
||||
abilityLabel = abilityLabel,
|
||||
relatedTitle = { getString(R.string.dice_roll_saving_throw_detail, it) },
|
||||
relatedLabel = relatedLabel,
|
||||
ability = ability,
|
||||
relatedStat = relatedStat,
|
||||
)
|
||||
|
||||
private fun rollAbility(
|
||||
character: CharacterSheet,
|
||||
alterations: Map<Property, List<Alteration.Status>>,
|
||||
abilityTitle: Context.(label: String) -> String,
|
||||
abilityLabel: Context.() -> String,
|
||||
relatedTitle: Context.(label: String) -> String?,
|
||||
relatedLabel: Context.() -> String?,
|
||||
ability: Property,
|
||||
relatedStat: Property,
|
||||
): DiceThrowResult {
|
||||
// retrieve some wording.
|
||||
val abilityLabelString = abilityLabel(application)
|
||||
val abilityTitleString = abilityTitle(application, abilityLabelString)
|
||||
|
||||
// create a list destined to contain all the values (rolled + bonus)
|
||||
val allValue = mutableListOf<Int>()
|
||||
|
||||
// check if the roll is affected by some status.
|
||||
val advantage = alterations[ability].advantage
|
||||
val disadvantage = alterations[ability].disadvantage
|
||||
val fail = alterations[ability].fail
|
||||
|
||||
// main roll
|
||||
val result = roll(advantage = advantage, disadvantage = disadvantage, fail = fail)
|
||||
allValue.add(result.value)
|
||||
|
||||
// fetch and build a list of dice roll base on alterations.
|
||||
val diceAlterationBonus = alterations[ability]?.flatMap { status ->
|
||||
status.dices.map { dice ->
|
||||
val localRoll = roll(
|
||||
amount = dice.count,
|
||||
faces = dice.faces,
|
||||
advantage = dice.advantage,
|
||||
disadvantage = dice.disadvantage,
|
||||
fail = dice.fail
|
||||
)
|
||||
allValue.add(localRoll.value)
|
||||
ThrowsCardUio.Detail(
|
||||
title = dice.title,
|
||||
throws = ThrowsCardUio.Throw(
|
||||
dice = dice.faces.icon,
|
||||
advantage = dice.advantage,
|
||||
disadvantage = dice.disadvantage,
|
||||
roll = "${dice.count}d${dice.faces}",
|
||||
result = localRoll.label,
|
||||
),
|
||||
result = "${localRoll.value}",
|
||||
)
|
||||
}
|
||||
} ?: emptyList()
|
||||
|
||||
// fetch and build a list of flat bonus
|
||||
val flatAlterationBonus = alterations[ability]?.flatMap { status ->
|
||||
status.bonus.map { bonus ->
|
||||
allValue.add(bonus.value)
|
||||
ThrowsCardUio.Detail(
|
||||
title = bonus.title,
|
||||
result = "${bonus.value}",
|
||||
)
|
||||
}
|
||||
} ?: emptyList()
|
||||
|
||||
// fetch and build the associated characteristic
|
||||
val relatedStatBonus = when (relatedStat) {
|
||||
Property.STRENGTH -> (character.strength + alterations[relatedStat].sum).modifier
|
||||
Property.DEXTERITY -> (character.dexterity + alterations[relatedStat].sum).modifier
|
||||
Property.CONSTITUTION -> (character.constitution + alterations[relatedStat].sum).modifier
|
||||
Property.INTELLIGENCE -> (character.intelligence + alterations[relatedStat].sum).modifier
|
||||
Property.WISDOM -> (character.wisdom + alterations[relatedStat].sum).modifier
|
||||
Property.CHARISMA -> (character.charisma + alterations[relatedStat].sum).modifier
|
||||
Property.PROFICIENCY -> character.proficiency
|
||||
else -> null
|
||||
}?.let { value ->
|
||||
val relatedLabelString = relatedLabel(application)
|
||||
val relatedTitleString = relatedLabelString?.let { relatedTitle(application, it) }
|
||||
if (relatedTitleString != null) {
|
||||
allValue.add(value)
|
||||
listOf(
|
||||
ThrowsCardUio.Detail(
|
||||
title = relatedTitleString,
|
||||
result = "$value",
|
||||
)
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} ?: emptyList()
|
||||
|
||||
// fetch and build the mastery bonus
|
||||
val mastery = when (ability) {
|
||||
Property.STRENGTH_SAVING_THROW -> character.strengthSavingThrows
|
||||
Property.DEXTERITY_SAVING_THROW -> character.dexteritySavingThrows
|
||||
Property.CONSTITUTION_SAVING_THROW -> character.constitutionSavingThrows
|
||||
Property.INTELLIGENCE_SAVING_THROW -> character.intelligenceSavingThrows
|
||||
Property.WISDOM_SAVING_THROW -> character.wisdomSavingThrows
|
||||
Property.CHARISMA_SAVING_THROW -> character.charismaSavingThrows
|
||||
Property.ACROBATICS -> character.acrobatics
|
||||
Property.ANIMAL_HANDLING -> character.animalHandling
|
||||
Property.ARCANA -> character.arcana
|
||||
Property.ATHLETICS -> character.athletics
|
||||
Property.DECEPTION -> character.deception
|
||||
Property.HISTORY -> character.history
|
||||
Property.INSIGHT -> character.insight
|
||||
Property.INTIMIDATION -> character.intimidation
|
||||
Property.INVESTIGATION -> character.investigation
|
||||
Property.MEDICINE -> character.medicine
|
||||
Property.NATURE -> character.nature
|
||||
Property.PERCEPTION -> character.perception
|
||||
Property.PERFORMANCE -> character.performance
|
||||
Property.PERSUASION -> character.persuasion
|
||||
Property.RELIGION -> character.religion
|
||||
Property.SLEIGHT_OF_HAND -> character.sleightOfHand
|
||||
Property.STEALTH -> character.stealth
|
||||
Property.SURVIVAL -> character.survival
|
||||
else -> null
|
||||
}?.let { multiplier ->
|
||||
val mastery = character.proficiency * multiplier
|
||||
allValue.add(mastery)
|
||||
listOf(
|
||||
ThrowsCardUio.Detail(
|
||||
title = application.getString(
|
||||
when (multiplier) {
|
||||
2 -> R.string.dice_roll_expertise_bonus
|
||||
else -> R.string.dice_roll_proficiency_bonus
|
||||
}
|
||||
),
|
||||
result = "$mastery",
|
||||
),
|
||||
)
|
||||
} ?: emptyList()
|
||||
|
||||
// build the result.
|
||||
return DiceThrowResult(
|
||||
dice = RollDiceUio(
|
||||
isCriticalSuccess = result.value == 20,
|
||||
isCriticalFailure = result.value == 1,
|
||||
result = "${result.value}",
|
||||
),
|
||||
card = ThrowsCardUio(
|
||||
title = abilityTitleString.uppercase(),
|
||||
highlight = abilityLabelString.uppercase(),
|
||||
dice = R.drawable.ic_d20_24,
|
||||
roll = allValue.toLabel(),
|
||||
result = "${
|
||||
when (result.value) {
|
||||
20 -> 20
|
||||
1 -> 1
|
||||
else -> allValue.sum()
|
||||
}
|
||||
}",
|
||||
isCriticalSuccess = result.value == 20,
|
||||
isCriticalFailure = result.value == 1,
|
||||
details = listOf(
|
||||
ThrowsCardUio.Detail(
|
||||
title = abilityTitleString,
|
||||
throws = ThrowsCardUio.Throw(
|
||||
dice = R.drawable.ic_d20_24,
|
||||
advantage = advantage,
|
||||
disadvantage = disadvantage,
|
||||
roll = "1d20",
|
||||
result = result.label,
|
||||
),
|
||||
result = "${result.value}",
|
||||
),
|
||||
) + diceAlterationBonus + flatAlterationBonus + relatedStatBonus + mastery,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun actionThrow(
|
||||
character: CharacterSheet,
|
||||
action: String,
|
||||
diceThrow: Throw?,
|
||||
title: Context.(action: String) -> String,
|
||||
alterations: Map<Property, List<Alteration.Status>>,
|
||||
ability: Property,
|
||||
): DiceThrowResult {
|
||||
// retrieve some wording.
|
||||
val titleString = title(application, action)
|
||||
|
||||
val canMakeCriticalRoll =
|
||||
ability == Property.PHYSICAL_MELEE_ATTACK || ability == Property.PHYSICAL_RANGE_ATTACK || ability == Property.SPELL_ATTACK
|
||||
|
||||
var criticalDiceMultiplier = 2
|
||||
if (ability == Property.PHYSICAL_MELEE_DAMAGE) {
|
||||
if (alterations.isSavageAttacks) criticalDiceMultiplier++
|
||||
if (alterations.isBrutalCritical) criticalDiceMultiplier++
|
||||
}
|
||||
|
||||
// create a list destined to contain all the values (rolled + bonus)
|
||||
val allValue = mutableListOf<Int>()
|
||||
|
||||
// check if the roll is affected by some status.
|
||||
val advantage = alterations[ability].advantage
|
||||
val disadvantage = alterations[ability].disadvantage
|
||||
val fail = alterations[ability].fail
|
||||
|
||||
// main roll
|
||||
val result = roll(
|
||||
amount = diceThrow?.amount ?: 1,
|
||||
faces = diceThrow?.faces ?: 20,
|
||||
advantage = advantage,
|
||||
disadvantage = disadvantage,
|
||||
fail = fail,
|
||||
critical = if (alterations.isCritical) criticalDiceMultiplier else 1,
|
||||
)
|
||||
allValue.add(result.value)
|
||||
|
||||
// fetch and build a list of dice roll base on alterations.
|
||||
val diceAlterationBonus = alterations[ability]?.flatMap { status ->
|
||||
status.dices.map { dice ->
|
||||
val localRoll = roll(
|
||||
amount = dice.count,
|
||||
faces = dice.faces,
|
||||
advantage = dice.advantage,
|
||||
disadvantage = dice.disadvantage,
|
||||
fail = dice.fail
|
||||
)
|
||||
allValue.add(localRoll.value)
|
||||
ThrowsCardUio.Detail(
|
||||
title = dice.title,
|
||||
throws = ThrowsCardUio.Throw(
|
||||
dice = dice.faces.icon,
|
||||
advantage = dice.advantage,
|
||||
disadvantage = dice.disadvantage,
|
||||
roll = "${dice.count}d${dice.faces}",
|
||||
result = localRoll.label,
|
||||
),
|
||||
result = "${localRoll.value}",
|
||||
)
|
||||
}
|
||||
} ?: emptyList()
|
||||
|
||||
// fetch and build a list of flat bonus
|
||||
val flatAlterationBonus = alterations[ability]?.flatMap { status ->
|
||||
status.bonus.map { bonus ->
|
||||
allValue.add(bonus.value)
|
||||
ThrowsCardUio.Detail(
|
||||
title = bonus.title,
|
||||
result = "${bonus.value}",
|
||||
)
|
||||
}
|
||||
} ?: emptyList()
|
||||
|
||||
// fetch and build the associated characteristic
|
||||
val relatedStatBonus = diceThrow?.modifier?.mapNotNull { property ->
|
||||
when (property) {
|
||||
Property.STRENGTH -> (character.strength + alterations[property].sum).modifier
|
||||
Property.DEXTERITY -> (character.dexterity + alterations[property].sum).modifier
|
||||
Property.CONSTITUTION -> (character.constitution + alterations[property].sum).modifier
|
||||
Property.INTELLIGENCE -> (character.intelligence + alterations[property].sum).modifier
|
||||
Property.WISDOM -> (character.wisdom + alterations[property].sum).modifier
|
||||
Property.CHARISMA -> (character.charisma + alterations[property].sum).modifier
|
||||
Property.PROFICIENCY -> character.proficiency
|
||||
else -> null
|
||||
}?.let { value ->
|
||||
val titleLabel = if (property == Property.PROFICIENCY) {
|
||||
application.getString(R.string.dice_roll_mastery_proficiency, action)
|
||||
} else {
|
||||
val label = when (property) {
|
||||
Property.STRENGTH -> application.getString(R.string.character_sheet_stat_strength)
|
||||
Property.DEXTERITY -> application.getString(R.string.character_sheet_stat_dexterity)
|
||||
Property.CONSTITUTION -> application.getString(R.string.character_sheet_stat_constitution)
|
||||
Property.INTELLIGENCE -> application.getString(R.string.character_sheet_stat_intelligence)
|
||||
Property.WISDOM -> application.getString(R.string.character_sheet_stat_wisdom)
|
||||
Property.CHARISMA -> application.getString(R.string.character_sheet_stat_charisma)
|
||||
else -> ""
|
||||
}
|
||||
application.getString(R.string.dice_roll_bonus_detail, label)
|
||||
}
|
||||
allValue.add(value)
|
||||
ThrowsCardUio.Detail(
|
||||
title = titleLabel,
|
||||
result = "$value",
|
||||
)
|
||||
}
|
||||
} ?: emptyList()
|
||||
|
||||
// build the result.
|
||||
return DiceThrowResult(
|
||||
dice = RollDiceUio(
|
||||
icon = diceThrow?.faces?.icon ?: R.drawable.ic_d20_24,
|
||||
isCriticalSuccess = canMakeCriticalRoll && result.value == 20,
|
||||
isCriticalFailure = canMakeCriticalRoll && result.value == 1,
|
||||
result = "${result.value}",
|
||||
),
|
||||
card = ThrowsCardUio(
|
||||
title = titleString.uppercase(),
|
||||
highlight = action,
|
||||
dice = diceThrow?.faces?.icon ?: R.drawable.ic_d20_24,
|
||||
isCriticalSuccess = canMakeCriticalRoll && result.value == 20,
|
||||
isCriticalFailure = canMakeCriticalRoll && result.value == 1,
|
||||
roll = allValue.toLabel(),
|
||||
result = "${
|
||||
when {
|
||||
canMakeCriticalRoll && result.value == 20 -> 20
|
||||
canMakeCriticalRoll && result.value == 1 -> 1
|
||||
else -> allValue.sum()
|
||||
}
|
||||
}",
|
||||
details = listOf(
|
||||
ThrowsCardUio.Detail(
|
||||
title = action,
|
||||
throws = ThrowsCardUio.Throw(
|
||||
dice = diceThrow?.faces?.icon ?: R.drawable.ic_d20_24,
|
||||
advantage = advantage,
|
||||
disadvantage = disadvantage,
|
||||
roll = "${diceThrow?.amount}d${diceThrow?.faces}",
|
||||
result = result.label,
|
||||
),
|
||||
result = "${result.value}",
|
||||
),
|
||||
) + diceAlterationBonus + flatAlterationBonus + relatedStatBonus,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun spellThrow(
|
||||
character: CharacterSheet,
|
||||
spell: AssignedSpell?,
|
||||
level: Int,
|
||||
alterations: Map<Property, List<Alteration.Status>>,
|
||||
): DiceThrowResult {
|
||||
// retrieve some wording.
|
||||
val spellName = spell?.spell?.name ?: ""
|
||||
val titleString = application.getString(R.string.dice_roll_spell_cast, spellName)
|
||||
|
||||
// create a list destined to contain all the values (rolled + bonus)
|
||||
val allValue = mutableListOf<Int>()
|
||||
|
||||
// main roll
|
||||
val result = roll(
|
||||
amount = spell?.effect?.amount ?: 1,
|
||||
faces = spell?.effect?.faces ?: 4,
|
||||
)
|
||||
allValue.add(result.value)
|
||||
|
||||
// fetch and build a list of additionnal 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,
|
||||
)
|
||||
allValue.add(localRoll.value)
|
||||
ThrowsCardUio.Detail(
|
||||
title = application.getString(R.string.spell_level_chooser_label, "$it"),
|
||||
throws = ThrowsCardUio.Throw(
|
||||
dice = spell.level.faces.icon,
|
||||
roll = "${spell.level.amount}d${spell.level.faces}",
|
||||
result = localRoll.label,
|
||||
),
|
||||
result = "${localRoll.value}",
|
||||
)
|
||||
}
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
|
||||
// fetch and build the associated characteristic
|
||||
val relatedStatBonus = spell?.effect?.modifier?.mapNotNull { property ->
|
||||
when (property) {
|
||||
Property.STRENGTH -> (character.strength + alterations[property].sum).modifier
|
||||
Property.DEXTERITY -> (character.dexterity + alterations[property].sum).modifier
|
||||
Property.CONSTITUTION -> (character.constitution + alterations[property].sum).modifier
|
||||
Property.INTELLIGENCE -> (character.intelligence + alterations[property].sum).modifier
|
||||
Property.WISDOM -> (character.wisdom + alterations[property].sum).modifier
|
||||
Property.CHARISMA -> (character.charisma + alterations[property].sum).modifier
|
||||
Property.PROFICIENCY -> character.proficiency
|
||||
else -> null
|
||||
}?.let { value ->
|
||||
val titleLabel = if (property == Property.PROFICIENCY) {
|
||||
application.getString(R.string.dice_roll_mastery_proficiency, spell)
|
||||
} else {
|
||||
val label = when (property) {
|
||||
Property.STRENGTH -> application.getString(R.string.character_sheet_stat_strength)
|
||||
Property.DEXTERITY -> application.getString(R.string.character_sheet_stat_dexterity)
|
||||
Property.CONSTITUTION -> application.getString(R.string.character_sheet_stat_constitution)
|
||||
Property.INTELLIGENCE -> application.getString(R.string.character_sheet_stat_intelligence)
|
||||
Property.WISDOM -> application.getString(R.string.character_sheet_stat_wisdom)
|
||||
Property.CHARISMA -> application.getString(R.string.character_sheet_stat_charisma)
|
||||
else -> ""
|
||||
}
|
||||
application.getString(R.string.dice_roll_bonus_detail, label)
|
||||
}
|
||||
allValue.add(value)
|
||||
ThrowsCardUio.Detail(
|
||||
title = titleLabel,
|
||||
result = "$value",
|
||||
)
|
||||
}
|
||||
} ?: emptyList()
|
||||
|
||||
// build the result.
|
||||
return DiceThrowResult(
|
||||
dice = RollDiceUio(
|
||||
icon = (spell?.effect?.faces ?: 4).icon,
|
||||
result = "${result.value}",
|
||||
),
|
||||
card = ThrowsCardUio(
|
||||
title = titleString.uppercase(),
|
||||
highlight = spellName,
|
||||
dice = (spell?.effect?.faces ?: 4).icon,
|
||||
roll = allValue.toLabel(),
|
||||
result = "${allValue.sum()}",
|
||||
details = listOf(
|
||||
ThrowsCardUio.Detail(
|
||||
title = spellName,
|
||||
throws = ThrowsCardUio.Throw(
|
||||
dice = (spell?.effect?.faces ?: 4).icon,
|
||||
roll = "${spell?.effect?.amount ?: 1}d${spell?.effect?.faces ?: 4}",
|
||||
result = result.label,
|
||||
),
|
||||
result = "${result.value}",
|
||||
),
|
||||
) + levelBonus + relatedStatBonus,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun roll(
|
||||
amount: Int = 1,
|
||||
faces: Int = 20,
|
||||
advantage: Boolean = false,
|
||||
disadvantage: Boolean = false,
|
||||
fail: Boolean = false,
|
||||
critical: Int = 1,
|
||||
): DiceRollResult {
|
||||
return when {
|
||||
advantage && !disadvantage -> {
|
||||
val roll = List(amount * critical) { random(faces, fail) to random(faces, fail) }
|
||||
DiceRollResult(
|
||||
label = roll.joinToString(" + ") { "${it.first}~${it.second}" },
|
||||
value = roll.sumOf { max(it.first, it.second) },
|
||||
)
|
||||
}
|
||||
|
||||
disadvantage && !advantage -> {
|
||||
val roll = List(amount * critical) { random(faces, fail) to random(faces, fail) }
|
||||
DiceRollResult(
|
||||
label = roll.joinToString(" + ") { "${it.first}~${it.second}" },
|
||||
value = roll.sumOf { min(it.first, it.second) },
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
val roll = List(amount * critical) { random(faces, fail) }
|
||||
DiceRollResult(
|
||||
label = roll.toLabel(),
|
||||
value = roll.sum(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun random(faces: Int, fail: Boolean): Int =
|
||||
if (fail) 1 else (Math.random() * faces + 1).toInt()
|
||||
|
||||
private data class DiceRollResult(
|
||||
val label: String,
|
||||
val value: Int,
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue