1203 lines
No EOL
54 KiB
Kotlin
1203 lines
No EOL
54 KiB
Kotlin
package com.pixelized.rplexicon.business
|
|
|
|
import android.app.Application
|
|
import android.content.Context
|
|
import com.pixelized.rplexicon.R
|
|
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.Skill
|
|
import com.pixelized.rplexicon.data.model.alteration.Alteration
|
|
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
|
|
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
|
|
import com.pixelized.rplexicon.data.repository.character.ObjectActionRepository
|
|
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.local.advantage
|
|
import com.pixelized.rplexicon.utilitary.extentions.local.base
|
|
import com.pixelized.rplexicon.utilitary.extentions.local.critical
|
|
import com.pixelized.rplexicon.utilitary.extentions.local.disadvantage
|
|
import com.pixelized.rplexicon.utilitary.extentions.local.emphasis
|
|
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.primary
|
|
import com.pixelized.rplexicon.utilitary.extentions.local.secondary
|
|
import com.pixelized.rplexicon.utilitary.extentions.local.sum
|
|
import com.pixelized.rplexicon.utilitary.extentions.local.tertiary
|
|
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 kotlinx.coroutines.flow.firstOrNull
|
|
import javax.inject.Inject
|
|
import kotlin.math.abs
|
|
import kotlin.math.max
|
|
import kotlin.math.min
|
|
import kotlin.random.Random
|
|
|
|
data class DiceThrowResult(
|
|
val dice: RollDiceUio,
|
|
val throws: NetworkThrow,
|
|
)
|
|
|
|
@Suppress("KotlinConstantConditions")
|
|
class DiceThrowUseCase @Inject constructor(
|
|
private val application: Application,
|
|
private val characterSheetRepository: CharacterSheetRepository,
|
|
private val actionRepository: ActionRepository,
|
|
private val objectRepository: ObjectActionRepository,
|
|
private val spellRepository: SpellRepository,
|
|
private val skillRepository: SkillRepository,
|
|
private val alterationRepository: AlterationRepository,
|
|
) {
|
|
suspend fun roll(
|
|
diceThrow: DiceThrow,
|
|
isThrowHidden: Boolean,
|
|
alterationId: List<String>,
|
|
): DiceThrowResult? {
|
|
val sheet = characterSheetRepository.find(name = diceThrow.character)
|
|
val alterations =
|
|
alterationRepository.getAssignedAlterations(diceThrow.character).firstOrNull()
|
|
?.filter { alterationId.contains(it.name) } ?: emptyList()
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
is DiceThrow.DeathSavingThrow -> savingThrow(
|
|
character = sheet,
|
|
alterations = alterations,
|
|
abilityLabel = { getString(R.string.character_sheet_stat_death) },
|
|
relatedLabel = { getString(R.string.character_sheet_stat_death) },
|
|
ability = Property.DEATH_SAVING_THROW,
|
|
relatedStat = null,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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.PERCEPTION,
|
|
relatedStat = Property.WISDOM,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
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_damage_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_damage_title, it) },
|
|
alterations = alterations,
|
|
ability = Property.PHYSICAL_RANGE_DAMAGE,
|
|
)
|
|
}
|
|
|
|
is DiceThrow.Object -> {
|
|
val action = objectRepository.find(
|
|
character = diceThrow.character,
|
|
item = diceThrow.item,
|
|
)
|
|
actionThrow(
|
|
character = sheet,
|
|
action = diceThrow.item,
|
|
diceThrow = action?.effect,
|
|
title = { getString(R.string.dice_roll_use_object, it) },
|
|
alterations = alterations,
|
|
ability = Property.OBJECT_EFFECT,
|
|
)
|
|
}
|
|
|
|
is DiceThrow.SpellAttack -> {
|
|
val spell = spellRepository.findAssignedSpell(
|
|
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.findAssignedSpell(
|
|
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.findAssignedSpell(
|
|
character = diceThrow.character,
|
|
spell = diceThrow.spell,
|
|
)
|
|
spellThrow(
|
|
character = sheet,
|
|
spell = spell,
|
|
level = diceThrow.level,
|
|
alterations = alterations,
|
|
)
|
|
}
|
|
|
|
is DiceThrow.Skill -> {
|
|
val skill = skillRepository.find(
|
|
character = diceThrow.character,
|
|
skill = diceThrow.skill,
|
|
)
|
|
skillThrow(
|
|
character = sheet,
|
|
alterations = alterations,
|
|
skill = skill,
|
|
)
|
|
}
|
|
}
|
|
} else {
|
|
null
|
|
}
|
|
}
|
|
|
|
private fun abilityThrow(
|
|
character: CharacterSheet,
|
|
alterations: List<Alteration>,
|
|
abilityLabel: Context.() -> String,
|
|
relatedLabel: Context.() -> String?,
|
|
ability: Property,
|
|
relatedStat: Property,
|
|
isThrowHidden: Boolean,
|
|
): 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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
private fun savingThrow(
|
|
character: CharacterSheet,
|
|
alterations: List<Alteration>,
|
|
abilityLabel: Context.() -> String,
|
|
relatedLabel: Context.() -> String?,
|
|
ability: Property,
|
|
relatedStat: Property?,
|
|
isThrowHidden: Boolean,
|
|
): 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,
|
|
isThrowHidden = isThrowHidden,
|
|
)
|
|
|
|
private fun rollAbility(
|
|
character: CharacterSheet,
|
|
alterations: List<Alteration>,
|
|
abilityTitle: Context.(label: String) -> String,
|
|
abilityLabel: Context.() -> String,
|
|
relatedTitle: Context.(label: String) -> String?,
|
|
relatedLabel: Context.() -> String?,
|
|
ability: Property,
|
|
relatedStat: Property?,
|
|
isThrowHidden: Boolean,
|
|
): DiceThrowResult {
|
|
with(ThrowScope(context = application, character = character, alterations = alterations)) {
|
|
// retrieve some wording.
|
|
val abilityLabelString = abilityLabel(application)
|
|
val abilityTitleString = abilityTitle(application, abilityLabelString)
|
|
|
|
// check if the roll is affected by some status.
|
|
val advantage = status[ability].advantage
|
|
val disadvantage = status[ability].disadvantage
|
|
val emphasis = status[ability].emphasis
|
|
// main roll
|
|
val result = roll(
|
|
advantage = advantage,
|
|
disadvantage = disadvantage,
|
|
emphasis = emphasis,
|
|
fail = status[ability].fail,
|
|
critical = status[ability].critical,
|
|
)
|
|
|
|
// fetch and build a list of dice roll base on alterations.
|
|
val diceAlterationBonus = status[ability].alterationsBonus()
|
|
|
|
// fetch and build a list of flat bonus
|
|
val flatAlterationBonus = status[ability].flatAlterationBonus()
|
|
|
|
// fetch and build the associated characteristic
|
|
val relatedStatBonus = when (relatedStat) {
|
|
Property.STRENGTH -> (character.strength + status[relatedStat].sum).modifier
|
|
Property.DEXTERITY -> (character.dexterity + status[relatedStat].sum).modifier
|
|
Property.CONSTITUTION -> (character.constitution + status[relatedStat].sum).modifier
|
|
Property.INTELLIGENCE -> (character.intelligence + status[relatedStat].sum).modifier
|
|
Property.WISDOM -> (character.wisdom + status[relatedStat].sum).modifier
|
|
Property.CHARISMA -> (character.charisma + status[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(
|
|
NetworkThrow.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 {
|
|
val multiplier = it.masteryMultiplier(status = status[ability])
|
|
val mastery = character.proficiency * multiplier
|
|
allValue.add(mastery)
|
|
listOf(
|
|
NetworkThrow.Detail(
|
|
title = application.getString(
|
|
when (multiplier) {
|
|
2 -> R.string.dice_roll_expertise_bonus
|
|
else -> R.string.dice_roll_proficiency_bonus
|
|
}
|
|
),
|
|
result = "$mastery",
|
|
),
|
|
)
|
|
} ?: emptyList()
|
|
|
|
// compute the final roll result
|
|
val rollResult = when (result.value) {
|
|
1, 20 -> "${result.value}"
|
|
else -> "${allValue.sum()}"
|
|
}
|
|
|
|
// build the result.
|
|
return DiceThrowResult(
|
|
dice = RollDiceUio(
|
|
isCriticalSuccess = result.value == 20,
|
|
isCriticalFailure = result.value == 1,
|
|
result = rollResult,
|
|
),
|
|
throws = NetworkThrow(
|
|
timestamp = System.currentTimeMillis(),
|
|
title = abilityTitleString.uppercase(),
|
|
highlight = abilityLabelString.uppercase(),
|
|
hidden = isThrowHidden,
|
|
face = 20,
|
|
roll = allValue.toLabel(),
|
|
result = rollResult,
|
|
isCriticalSuccess = result.value == 20,
|
|
isCriticalFailure = result.value == 1,
|
|
details = listOf(
|
|
NetworkThrow.Detail(
|
|
title = abilityTitleString,
|
|
throws = NetworkThrow.Throw(
|
|
dice = R.drawable.ic_d20_24,
|
|
advantage = advantage,
|
|
disadvantage = disadvantage,
|
|
emphasis = emphasis,
|
|
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: List<Alteration>,
|
|
ability: Property?,
|
|
): DiceThrowResult {
|
|
with(ThrowScope(context = application, character = character, alterations = alterations)) {
|
|
// retrieve some wording.
|
|
val titleString = title(application, action)
|
|
|
|
// check if this throw can be a critical success of failure.
|
|
val canMakeCriticalRoll = when (ability) {
|
|
Property.PHYSICAL_MELEE_ATTACK -> true
|
|
Property.PHYSICAL_RANGE_ATTACK -> true
|
|
Property.SPELL_ATTACK -> true
|
|
else -> false
|
|
}
|
|
|
|
// check if the roll is affected by some status.
|
|
val advantage = status[ability].advantage
|
|
val disadvantage = status[ability].disadvantage
|
|
val emphasis = status[ability].emphasis
|
|
|
|
// compute the amount of main dice to throw.
|
|
val amount = if (status.isCritical) {
|
|
diceThrow?.dice?.count?.times(2)?.let {
|
|
if (ability == Property.PHYSICAL_MELEE_DAMAGE && status.isSavageAttacks) it.plus(
|
|
1
|
|
) else it
|
|
}?.let {
|
|
if (ability == Property.PHYSICAL_MELEE_DAMAGE && status.isBrutalCritical) it.plus(
|
|
1
|
|
) else it
|
|
}
|
|
} else {
|
|
diceThrow?.dice?.count
|
|
}
|
|
// main roll
|
|
val result = roll(
|
|
amount = amount ?: 1,
|
|
faces = diceThrow?.dice?.faces ?: 20,
|
|
advantage = advantage,
|
|
disadvantage = disadvantage,
|
|
emphasis = emphasis,
|
|
fail = status[ability].fail,
|
|
critical = status[ability].critical,
|
|
)
|
|
|
|
// fetch and build a list of dice roll base on alterations.
|
|
val diceAlterationBonus = status[ability].alterationsBonus()
|
|
|
|
// fetch and build a list of flat bonus
|
|
val flatAlterationBonus = status[ability].flatAlterationBonus()
|
|
|
|
// fetch and build the associated characteristic
|
|
val relatedStatBonus = diceThrow.statBonus(name = action)
|
|
|
|
// check for flat dice bonus (ex: healing potion 2d4 + 2)
|
|
val relatedFlatBonus = diceThrow.flatBonus(name = action)
|
|
|
|
// compute the final roll result
|
|
val rollResult = when {
|
|
canMakeCriticalRoll && result.value == 20 -> "20"
|
|
canMakeCriticalRoll && result.value == 1 -> "1"
|
|
else -> "${allValue.sum()}"
|
|
}
|
|
|
|
// build the result.
|
|
return DiceThrowResult(
|
|
dice = RollDiceUio(
|
|
icon = diceThrow?.dice?.icon ?: R.drawable.ic_d20_24,
|
|
isCriticalSuccess = canMakeCriticalRoll && result.value == 20,
|
|
isCriticalFailure = canMakeCriticalRoll && result.value == 1,
|
|
result = rollResult,
|
|
),
|
|
throws = NetworkThrow(
|
|
timestamp = System.currentTimeMillis(),
|
|
title = titleString.uppercase(),
|
|
highlight = action.uppercase(),
|
|
face = diceThrow?.dice?.faces ?: 20,
|
|
isCriticalSuccess = canMakeCriticalRoll && result.value == 20,
|
|
isCriticalFailure = canMakeCriticalRoll && result.value == 1,
|
|
roll = allValue.toLabel(),
|
|
result = rollResult,
|
|
details = listOf(
|
|
NetworkThrow.Detail(
|
|
title = action,
|
|
throws = NetworkThrow.Throw(
|
|
dice = diceThrow?.dice?.icon ?: R.drawable.ic_d20_24,
|
|
advantage = advantage,
|
|
disadvantage = disadvantage,
|
|
emphasis = emphasis,
|
|
roll = "${diceThrow?.dice?.count}d${diceThrow?.dice?.faces}",
|
|
result = result.label,
|
|
),
|
|
result = "${result.value}",
|
|
),
|
|
) + diceAlterationBonus + flatAlterationBonus + relatedStatBonus + relatedFlatBonus,
|
|
),
|
|
)
|
|
}
|
|
}
|
|
|
|
private fun spellThrow(
|
|
character: CharacterSheet,
|
|
spell: AssignedSpell?,
|
|
level: Int,
|
|
alterations: List<Alteration>,
|
|
): DiceThrowResult {
|
|
with(ThrowScope(context = application, character = character, alterations = alterations)) {
|
|
// retrieve some wording.
|
|
val spellName = spell?.spell?.name ?: ""
|
|
val titleString = application.getString(R.string.dice_roll_spell_cast, spellName)
|
|
|
|
val advantage = status[Property.SPELL_EFFECT].advantage
|
|
val disadvantage = status[Property.SPELL_EFFECT].disadvantage
|
|
val emphasis = status[Property.SPELL_EFFECT].emphasis
|
|
// main roll
|
|
val result = roll(
|
|
amount = spell?.effect?.dice?.count ?: 1,
|
|
faces = spell?.effect?.dice?.faces ?: 4,
|
|
advantage = advantage,
|
|
disadvantage = disadvantage,
|
|
emphasis = emphasis,
|
|
fail = status[Property.SPELL_EFFECT].fail,
|
|
critical = status[Property.SPELL_EFFECT].critical,
|
|
)
|
|
|
|
// fetch and build a list of additional level effect.
|
|
val levelBonus = if (spell?.level?.dice != null) {
|
|
((spell.spell.level + 1)..level).map {
|
|
val localRoll = roll(
|
|
amount = spell.level.dice.count,
|
|
faces = spell.level.dice.faces,
|
|
advantage = advantage,
|
|
disadvantage = disadvantage,
|
|
emphasis = emphasis,
|
|
fail = status[Property.SPELL_EFFECT].fail,
|
|
critical = status[Property.SPELL_EFFECT].critical,
|
|
)
|
|
NetworkThrow.Detail(
|
|
title = application.getString(R.string.spell_level_chooser_label, "$it"),
|
|
throws = NetworkThrow.Throw(
|
|
dice = spell.level.dice.icon,
|
|
roll = spell.level.dice.toLabel(),
|
|
advantage = advantage,
|
|
disadvantage = disadvantage,
|
|
emphasis = emphasis,
|
|
result = localRoll.label,
|
|
),
|
|
result = "${localRoll.value}",
|
|
)
|
|
}
|
|
} else {
|
|
emptyList()
|
|
}
|
|
|
|
// fetch and build the associated characteristic
|
|
val relatedStatBonus = spell?.effect.statBonus(name = spellName)
|
|
|
|
// fetch and build a list of flat bonus
|
|
val relatedFlatBonus = spell?.effect?.flatBonus(name = spellName) ?: emptyList()
|
|
|
|
// compute the final roll result
|
|
val rollResult = "${allValue.sum()}"
|
|
|
|
// build the result.
|
|
return DiceThrowResult(
|
|
dice = RollDiceUio(
|
|
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?.dice?.faces ?: 4,
|
|
roll = allValue.toLabel(),
|
|
result = rollResult,
|
|
details = listOf(
|
|
NetworkThrow.Detail(
|
|
title = spellName,
|
|
throws = NetworkThrow.Throw(
|
|
dice = spell?.effect?.dice?.icon ?: R.drawable.ic_d4_24,
|
|
roll = spell?.effect?.dice?.toLabel() ?: "1d4",
|
|
advantage = advantage,
|
|
disadvantage = disadvantage,
|
|
emphasis = emphasis,
|
|
result = result.label,
|
|
),
|
|
result = "${result.value}",
|
|
),
|
|
) + levelBonus + relatedStatBonus + relatedFlatBonus,
|
|
),
|
|
)
|
|
}
|
|
}
|
|
|
|
private fun skillThrow(
|
|
character: CharacterSheet,
|
|
alterations: List<Alteration>,
|
|
skill: Skill?,
|
|
): DiceThrowResult {
|
|
with(ThrowScope(context = application, character = character, alterations = alterations)) {
|
|
// retrieve some wording.
|
|
val spellName = skill?.name
|
|
val titleString = application.getString(R.string.dice_roll_spell_cast, spellName)
|
|
|
|
val advantage = status[Property.SKILL].advantage
|
|
val disadvantage = status[Property.SKILL].disadvantage
|
|
val emphasis = status[Property.SKILL].emphasis
|
|
// main roll
|
|
val result = roll(
|
|
amount = skill?.effect?.dice?.count ?: 1,
|
|
faces = skill?.effect?.dice?.faces ?: 4,
|
|
advantage = advantage,
|
|
disadvantage = disadvantage,
|
|
emphasis = emphasis,
|
|
fail = status[Property.SKILL].fail,
|
|
critical = status[Property.SKILL].critical,
|
|
)
|
|
|
|
// fetch and build a list of dice roll base on alterations.
|
|
val diceAlterationBonus = status[Property.SKILL].alterationsBonus()
|
|
|
|
// fetch and build a list of flat bonus
|
|
val flatAlterationBonus = status[Property.SKILL].flatAlterationBonus()
|
|
|
|
// fetch and build the associated characteristic, proficiency or level
|
|
val relatedStatBonus = skill?.effect.statBonus(name = skill?.name)
|
|
|
|
// fetch and build a list of flat bonus
|
|
val relatedFlatBonus = skill?.effect.flatBonus(name = skill?.name)
|
|
|
|
// compute the final roll result
|
|
val rollResult = "${allValue.sum()}"
|
|
|
|
// build the result.
|
|
return DiceThrowResult(
|
|
dice = RollDiceUio(
|
|
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?.dice?.faces ?: 4,
|
|
roll = allValue.toLabel(),
|
|
result = rollResult,
|
|
details = listOf(
|
|
NetworkThrow.Detail(
|
|
title = spellName ?: "",
|
|
throws = NetworkThrow.Throw(
|
|
dice = skill?.effect?.dice?.icon ?: R.drawable.ic_d4_24,
|
|
roll = skill?.effect?.dice?.toLabel() ?: "1d4",
|
|
advantage = advantage,
|
|
disadvantage = disadvantage,
|
|
emphasis = emphasis,
|
|
result = result.label,
|
|
),
|
|
result = "${result.value}",
|
|
),
|
|
) + diceAlterationBonus + flatAlterationBonus + relatedStatBonus + relatedFlatBonus,
|
|
),
|
|
)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper class to track rolls and declare helper method.
|
|
*/
|
|
private class ThrowScope(
|
|
val context: Context,
|
|
val allValue: MutableList<Int> = mutableListOf(),
|
|
val character: CharacterSheet,
|
|
val alterations: List<Alteration>,
|
|
) {
|
|
val status = this.alterations.toStatus()
|
|
|
|
/**
|
|
* Fetch any stats / proficiency / level related bonus and build a ThrowsCardUio.Detail for each.
|
|
*/
|
|
fun Throw?.statBonus(name: String?): List<NetworkThrow.Detail> {
|
|
return this?.modifier?.mapNotNull { it.statBonus(name = name) } ?: emptyList()
|
|
}
|
|
|
|
/**
|
|
* Fetch any flat bonus related to the throw.
|
|
*/
|
|
fun Throw?.flatBonus(name: String?): List<NetworkThrow.Detail> {
|
|
return this?.flat?.flatBonus(name)?.let { listOf(it) } ?: emptyList()
|
|
}
|
|
|
|
private fun Property.statBonus(name: String?): NetworkThrow.Detail? {
|
|
return when (this) {
|
|
Property.STRENGTH -> (character.strength + this@ThrowScope.status[this].sum).modifier
|
|
Property.DEXTERITY -> (character.dexterity + this@ThrowScope.status[this].sum).modifier
|
|
Property.CONSTITUTION -> (character.constitution + this@ThrowScope.status[this].sum).modifier
|
|
Property.INTELLIGENCE -> (character.intelligence + this@ThrowScope.status[this].sum).modifier
|
|
Property.WISDOM -> (character.wisdom + this@ThrowScope.status[this].sum).modifier
|
|
Property.CHARISMA -> (character.charisma + this@ThrowScope.status[this].sum).modifier
|
|
Property.PROFICIENCY -> character.proficiency
|
|
Property.LEVEL -> character.level.base
|
|
Property.LEVEL_PC -> character.level.primary
|
|
Property.LEVEL_SC -> character.level.secondary
|
|
Property.LEVEL_TC -> character.level.tertiary
|
|
else -> null
|
|
}?.let { value ->
|
|
val titleLabel = if (this == Property.PROFICIENCY) {
|
|
context.getString(R.string.dice_roll_mastery_proficiency, name)
|
|
} else {
|
|
val label = when (this) {
|
|
Property.STRENGTH -> context.getString(R.string.character_sheet_stat_strength)
|
|
Property.DEXTERITY -> context.getString(R.string.character_sheet_stat_dexterity)
|
|
Property.CONSTITUTION -> context.getString(R.string.character_sheet_stat_constitution)
|
|
Property.INTELLIGENCE -> context.getString(R.string.character_sheet_stat_intelligence)
|
|
Property.WISDOM -> context.getString(R.string.character_sheet_stat_wisdom)
|
|
Property.CHARISMA -> context.getString(R.string.character_sheet_stat_charisma)
|
|
Property.LEVEL -> context.getString(R.string.character_sheet_stat_level)
|
|
Property.LEVEL_PC -> context.getString(R.string.character_sheet_stat_level_pc)
|
|
Property.LEVEL_SC -> context.getString(R.string.character_sheet_stat_level_sc)
|
|
Property.LEVEL_TC -> context.getString(R.string.character_sheet_stat_level_tc)
|
|
else -> ""
|
|
}
|
|
context.getString(R.string.dice_roll_bonus_detail, label)
|
|
}
|
|
allValue.add(value)
|
|
NetworkThrow.Detail(
|
|
title = titleLabel,
|
|
result = "$value",
|
|
)
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fetch any alteration related bonus and build a ThrowsCardUio.Detail for each.
|
|
*/
|
|
fun List<Alteration.Status>?.alterationsBonus(): List<NetworkThrow.Detail> {
|
|
return this?.flatMap { status ->
|
|
status.dices.map { dice ->
|
|
val localRoll = roll(
|
|
amount = if (this@ThrowScope.status.isCritical) dice.count * 2 else dice.count,
|
|
faces = dice.faces,
|
|
advantage = dice.advantage,
|
|
disadvantage = dice.disadvantage,
|
|
emphasis = dice.emphasis,
|
|
fail = status.fail,
|
|
critical = status.critical,
|
|
)
|
|
NetworkThrow.Detail(
|
|
title = status.name,
|
|
throws = NetworkThrow.Throw(
|
|
dice = dice.icon,
|
|
advantage = dice.advantage,
|
|
disadvantage = dice.disadvantage,
|
|
emphasis = dice.emphasis,
|
|
roll = "${dice.count}d${dice.faces}",
|
|
result = localRoll.label,
|
|
),
|
|
result = "${localRoll.value}",
|
|
)
|
|
}
|
|
} ?: emptyList()
|
|
}
|
|
|
|
/**
|
|
* Fetch any flat number related bonus and build a ThrowsCardUio.Detail for each.
|
|
*/
|
|
fun List<Alteration.Status>?.flatAlterationBonus(): List<NetworkThrow.Detail> {
|
|
return this?.mapNotNull { status ->
|
|
status.bonus?.let { bonus ->
|
|
allValue.add(bonus.value)
|
|
NetworkThrow.Detail(
|
|
title = status.name,
|
|
result = "${bonus.value}",
|
|
)
|
|
}
|
|
} ?: emptyList()
|
|
}
|
|
|
|
/**
|
|
* Make a roll of dices.
|
|
* @param amount the number of dice.
|
|
* @param faces the number of faces on the dices.
|
|
* @param advantage does the throws have advantage (roll 2 keep max)
|
|
* @param disadvantage does the throws have disadvantage (roll 2 keep min)
|
|
* @param emphasis does the throw have emphasis (roll 2, keep furthest away from 10)
|
|
* @param fail force the result to be 1
|
|
* @param critical force the result to amount.
|
|
*/
|
|
fun roll(
|
|
amount: Int = 1,
|
|
faces: Int = 20,
|
|
advantage: Boolean = false,
|
|
disadvantage: Boolean = false,
|
|
emphasis: Boolean,
|
|
fail: Boolean = false,
|
|
critical: Boolean = false,
|
|
): DiceRollResult {
|
|
val result = when {
|
|
advantage && !disadvantage -> {
|
|
val roll = List(amount) {
|
|
val first = random(faces = faces, fail = fail, critical = critical)
|
|
val second = random(faces = faces, fail = fail, critical = critical)
|
|
first to second
|
|
}
|
|
DiceRollResult(
|
|
label = roll.joinToString(" + ") { "${it.first}~${it.second}" },
|
|
value = roll.sumOf { max(it.first, it.second) },
|
|
)
|
|
}
|
|
|
|
!advantage && disadvantage -> {
|
|
val roll = List(amount) {
|
|
val first = random(faces = faces, fail = fail, critical = critical)
|
|
val second = random(faces = faces, fail = fail, critical = critical)
|
|
first to second
|
|
}
|
|
DiceRollResult(
|
|
label = roll.joinToString(" + ") { "${it.first}~${it.second}" },
|
|
value = roll.sumOf { min(it.first, it.second) },
|
|
)
|
|
}
|
|
|
|
!advantage && !disadvantage && emphasis -> {
|
|
val roll = List(amount) {
|
|
var first: Int
|
|
var second: Int
|
|
do {
|
|
first = random(faces = faces, fail = fail, critical = critical)
|
|
second = random(faces = faces, fail = fail, critical = critical)
|
|
} while (abs(first - 10) == abs(second - 10))
|
|
|
|
if (abs(first - 10) < abs(second - 10)) {
|
|
second to first
|
|
} else {
|
|
first to second
|
|
}
|
|
}
|
|
DiceRollResult(
|
|
label = roll.joinToString(" + ") { "${it.first}~${it.second}" },
|
|
value = roll.sumOf { it.first },
|
|
)
|
|
}
|
|
|
|
else -> {
|
|
val roll = List(amount) {
|
|
random(faces = faces, fail = fail, critical = critical)
|
|
}
|
|
DiceRollResult(
|
|
label = roll.toLabel(),
|
|
value = roll.sum(),
|
|
)
|
|
}
|
|
}
|
|
allValue.add(result.value)
|
|
return result
|
|
}
|
|
|
|
private fun random(faces: Int, fail: Boolean, critical: Boolean): Int = when {
|
|
fail && !critical -> 1
|
|
critical && !fail -> faces
|
|
else -> Random.nextInt(from = 1, until = faces + 1)
|
|
}
|
|
}
|
|
|
|
private data class DiceRollResult(
|
|
val label: String,
|
|
val value: Int,
|
|
)
|
|
} |