Add Reflex and Initiative sub characteristic

This commit is contained in:
Thomas Andres Gomez 2025-03-26 19:31:09 +01:00
parent 51e63202e3
commit cded2e9d86
10 changed files with 155 additions and 12 deletions

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:pathData="M400,920v-360L40,560l400,-400h360v360L400,920ZM640,567 L720,487v-247L473,240l-80,80h247v247ZM480,727l80,-80v-247L313,400l-80,80h247v247Z"
android:fillColor="#5f6368"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:pathData="M520,920v-240l-84,-80 -40,176 -276,-56 16,-80 192,40 64,-324 -72,28v136h-80v-188l158,-68q35,-15 51.5,-19.5T480,240q21,0 39,11t29,29l40,64q26,42 70.5,69T760,440v80q-66,0 -123.5,-27.5T540,420l-24,120 84,80v300h-80ZM540,220q-33,0 -56.5,-23.5T460,140q0,-33 23.5,-56.5T540,60q33,0 56.5,23.5T620,140q0,33 -23.5,56.5T540,220Z"
android:fillColor="#5f6368"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:pathData="M402,920q-30,0 -56,-13.5T303,868L48,495l24,-23q19,-19 45,-22t47,12l116,81v-383q0,-17 11.5,-28.5T320,120q17,0 28.5,11.5T360,160v537L212,593l157,229q5,8 14,13t19,5h278q33,0 56.5,-23.5T760,760v-560q0,-17 11.5,-28.5T800,160q17,0 28.5,11.5T840,200v560q0,66 -47,113T680,920L402,920ZM440,480v-400q0,-17 11.5,-28.5T480,40q17,0 28.5,11.5T520,80v400h-80ZM600,480v-360q0,-17 11.5,-28.5T640,80q17,0 28.5,11.5T680,120v360h-80ZM486,660Z"
android:fillColor="#5f6368"/>
</vector>

View file

@ -153,6 +153,8 @@
<string name="character_sheet__sub_characteristics__armor">Armure</string>
<string name="character_sheet__sub_characteristics__learning">Bonus d'apprentissage</string>
<string name="character_sheet__sub_characteristics__hp_grow">Bonus de PV</string>
<string name="character_sheet__sub_characteristics__reflex">Réflexe</string>
<string name="character_sheet__sub_characteristics__initiative">Initiative</string>
<string name="character_sheet__skills__common_title">Compétences communes</string>
<string name="character_sheet__skills__special_title">Compétences spéciales</string>
<string name="character_sheet__skills__magic_title">Compétences magiques</string>
@ -160,12 +162,12 @@
<string name="character_sheet__delete_dialog__description">Êtes-vous sûr de vouloir supprimer "%1$s" ?</string>
<string name="tooltip__characteristics__characteristics">Les caractéristiques constituent les aptitudes innées dun personnage comme son intelligence, sa force, son charisme, etc. Elles ne sont pas acquises, mais peuvent être parfois augmentées par un entraînement ou une utilisation réussie. Les caractéristiques des humains normaux varient de 2 (niveau extrêmement bas) à 20 (maximum du potentiel humain), avec une moyenne de 10 ou 11. Plus une caractéristique est élevée plus le personnage est puissant dans cette aptitude.\nÀ la création de votre personnage, répartissez les valeurs suivantes dans les différentes caractéristiques : 15, 15, 13, 11, 10, 9 et 7.</string>
<string name="tooltip__characteristics__strength">La Force représente essentiellement la puissance musculaire du personnage. Elle ne décrit pas nécessairement la masse musculaire brute, mais lefficacité avec laquelle le personnage exerce ses muscles pour accomplir des actions physiques pénibles.\n\n- Bonus aux dégats\n- Athlétisme\n- Lancer\n- Saisie</string>
<string name="tooltip__characteristics__strength">La Force représente essentiellement la puissance musculaire du personnage. Elle ne décrit pas nécessairement la masse musculaire brute, mais lefficacité avec laquelle le personnage exerce ses muscles pour accomplir des actions physiques pénibles.\n\n- Bonus aux dégats\n- Réflexe\n- Athlétisme\n- Lancer\n- Saisie</string>
<string name="tooltip__characteristics__constitution">La Constitution est une mesure de la ténacité et de la résilience du personnage. Elle sert à résister aux maladies. Mais son aspect le plus important réside dans la détermination du nombre de dommages quun personnage peut supporter avant de succomber.\n\n- Point de vie maximum\n- Athlétisme\n- Acrobatie</string>
<string name="tooltip__characteristics__height">La Taille est une mesure de la masse du personnage. Elle ne représente pas forcément la taille en centimètres, mais une idée générale de sa masse physique. Un personnage à la TAI élevée peut être très grand et mince, ou petit et massif, ou de taille moyenne en surpoids.\n\n- Bonus aux dégats\n- Point de vie maximum\n- Saisie\n- Intimidation\n- Discrétion (impact négatif)</string>
<string name="tooltip__characteristics__intelligence">LIntelligence représente la capacité de discernement du personnage. Elle ne mesure pas nécessairement la somme dinformations mémorisées, mais laptitude au raisonnement, lacuité intellectuelle, la capacité à résoudre des problèmes et lintuition.\n\n- Bonus d'apprentissage\n- Perception\n- Recherche\n- Empathie\n- Baratin\n- Premiers soins</string>
<string name="tooltip__characteristics__intelligence">LIntelligence représente la capacité de discernement du personnage. Elle ne mesure pas nécessairement la somme dinformations mémorisées, mais laptitude au raisonnement, lacuité intellectuelle, la capacité à résoudre des problèmes et lintuition.\n\n- Bonus d'apprentissage\n- Réflexe\n- Perception\n- Recherche\n- Empathie\n- Baratin\n- Premiers soins</string>
<string name="tooltip__characteristics__power">Le Pouvoir est une mesure presque intangible de la force de volonté, du dynamisme intérieur et de lénergie spirituelle. Il représente également le potentiel magique du personnage.\n\n- Points de pouvoir maximum\n- Intimidation</string>
<string name="tooltip__characteristics__dexterity">La Dextérité mesure la coordination œil-main, la vitesse physique et lagilité générale. La DEX détermine à quelle vitesse un personnage peut agir en combat.\n\n- Initiative\n- Bagarre\n- Esquive\n- Lancer\n- Acrobatie\n- Discrétion\n- Escamotage\n- Premiers soins</string>
<string name="tooltip__characteristics__dexterity">La Dextérité mesure la coordination œil-main, la vitesse physique et lagilité générale. La DEX détermine à quelle vitesse un personnage peut agir en combat.\n\n- Initiative\n- Réflexe\n- Bagarre\n- Esquive\n- Lancer\n- Acrobatie\n- Discrétion\n- Escamotage\n- Premiers soins</string>
<string name="tooltip__characteristics__charisma">Il représente plusieurs aspects allant de la grâce à la beauté en passant par lattraction que le personnage exerce sur les autres. Un personnage avec un CHA élevé se remarque dans une foule en raison dune intangible combinaison de charme et de présence.\n\n- Empathie\n- Persuasion\n- Persuasion\n- Intimidation\n- Baratin\n- Marchandage\n- Discrétion</string>
<string name="tooltip__sub_characteristics__movement">Le Déplacement (DEP) est une valeur de jeu qui détermine la distance que peut parcourir un personnage en un round de combat. Tous les humains ont un DEP de 10. Le DEP a une valeur réelle flexible, mais généralement, chaque point de DEP équivaut à un déplacement dun mètre. En course, un point équivaut à trois mètres.</string>
<string name="tooltip__sub_characteristics__hit_point">Les points de vie (PV) sont égaux à la somme CON+TAI du personnage, divisée par deux (arrondie au supérieur). Ils sont soustraits lorsque le personnage subit des dommages. Quand les points de vie tombent à 0, le personnage sombre dans linconscience. S'il reste inconscient trop longtemps, il meurt. Tous les points de vie régénèrent naturellement après une nuit de repos.</string>
@ -174,6 +176,8 @@
<string name="tooltip__sub_characteristics__armor">Une armure protège son porteur des blessures. Lorsquun personnage est touché en combat par une attaque non magique, soustrayez les points darmure aux points de dégâts infligés. Les dommages au-delà de la protection de larmure surpassent celle-ci et sont infligés au personnage, réduisant ses points de vie actuels.</string>
<string name="tooltip__sub_characteristics__learning">Plus un personnage est intelligent, plus il assimile rapidement les connaissances et plus il digère son expérience efficacement. Ce modificateur s'applique au score des compétences nouvellement acquises et aux jets d'expériences. Il est égal à (INT - 10) x 2 avec une valeur minimale de zéro.</string>
<string name="tooltip__sub_characteristics__hp_grow">Plus un personnage est de bonne constitution, plus son corps se renforce rapidement. Ce modificateur indique le nombre de "PV" maximum que le personnage gagne à chaque progression. Il est égal à CON / 3, arrondi à l'inférieur.</string>
<string name="tooltip__sub_characteristics__reflex">Les réflexes représentent la capacité d'un personnage à réagir promptement. Ils ont pour valeur : (FOR+DEX+INT)/3 (arrondis à l'inférieur).</string>
<string name="tooltip__sub_characteristics__initiative">L'initiative est la valeur qui détermine l'ordre dans lequel les participants d'un combat jouent. Par défaut elle est égale à leur Dextérité.</string>
<string name="network__title">Configuration de la table</string>
<string name="network__player_name__label">Nom du joueur</string>

View file

@ -35,6 +35,7 @@ import com.pixelized.desktop.lwa.ui.composable.blur.BlurContentController
import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterDetailCharacteristicDialogViewModel
import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterSheetCharacteristicDialogUio
import com.pixelized.desktop.lwa.ui.composable.character.diminished.CharacterSheetDiminishedViewModel
import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.header.CharacterDetailHeader
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.header.CharacterDetailHeaderUio
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheet
@ -99,6 +100,12 @@ fun CharacterDetailPanel(
)
}
},
onReflex = {
scope.launch {
val result = roll.showRollOverlay(roll = it)
println("result: $result")
}
},
onCharacteristic = {
scope.launch {
val result = roll.showRollOverlay(roll = it.roll)
@ -137,6 +144,7 @@ fun CharacterDetailAnimatedPanel(
onDiminished: (characterSheetId: String) -> Unit,
onHp: (characterSheetId: String) -> Unit,
onPp: (characterSheetId: String) -> Unit,
onReflex: (RollAction.Uio) -> Unit,
onCharacteristic: (CharacterDetailSheetCharacteristicUio) -> Unit,
onSkill: (CharacterDetailSheetSkillUio) -> Unit,
onUseSkill: (CharacterDetailSheetSkillUio) -> Unit,
@ -167,6 +175,7 @@ fun CharacterDetailAnimatedPanel(
onDiminished = { onDiminished(it.characterSheetId) },
onHp = { onHp(it.characterSheetId) },
onPp = { onPp(it.characterSheetId) },
onReflex = onReflex,
onCharacteristic = onCharacteristic,
onSkill = onSkill,
onUseSkill = onUseSkill,
@ -189,6 +198,7 @@ fun CharacterDetailContent(
onDiminished: () -> Unit,
onHp: () -> Unit,
onPp: () -> Unit,
onReflex: (RollAction.Uio) -> Unit,
onCharacteristic: (CharacterDetailSheetCharacteristicUio) -> Unit,
onSkill: (CharacterDetailSheetSkillUio) -> Unit,
onUseSkill: (CharacterDetailSheetSkillUio) -> Unit,
@ -210,6 +220,7 @@ fun CharacterDetailContent(
onDiminished = onDiminished,
onHp = onHp,
onPp = onPp,
onReflex = onReflex,
)
CharacterDetailSheet(
modifier = Modifier

View file

@ -24,9 +24,11 @@ import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_cha
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__damage_bonus
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__hit_point
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__hp_grow
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__initiative
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__learning
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__movement
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__power_point
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__reflex
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__charisma
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__constitution
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__dexterity
@ -38,9 +40,11 @@ import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteris
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__bonus_damage
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__hit_point
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__hp_grow
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__initiative
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__learning
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__movement
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__power_point
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__reflex
import org.jetbrains.compose.resources.getString
import java.text.Collator
@ -106,6 +110,22 @@ class CharacterDetailFactory(
title = getString(Res.string.character_sheet__sub_characteristics__learning),
description = getString(Res.string.tooltip__sub_characteristics__learning)
),
reflex = "${alteredCharacterSheet.reflex}",
reflexTooltip = TooltipUio(
title = getString(Res.string.character_sheet__sub_characteristics__reflex),
description = getString(Res.string.tooltip__sub_characteristics__reflex)
),
reflexRoll = RollAction.Uio.BoundedRollActionUio(
characterSheetId = characterSheetId,
label = getString(Res.string.character_sheet__sub_characteristics__reflex),
rollAction = "1d100",
rollSuccessValue = alteredCharacterSheet.reflex * 5,
),
initiative = "${alteredCharacterSheet.initiative}",
initiativeTooltip = TooltipUio(
title = getString(Res.string.character_sheet__sub_characteristics__initiative),
description = getString(Res.string.tooltip__sub_characteristics__initiative)
),
)
}

View file

@ -35,8 +35,8 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipLayout
import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipUio
import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction
import com.pixelized.desktop.lwa.ui.theme.lwa
import com.pixelized.shared.lwa.model.campaign.Campaign
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.character_sheet__level
import lwacharactersheet.composeapp.generated.resources.ic_close_24dp
@ -48,6 +48,9 @@ import lwacharactersheet.composeapp.generated.resources.ic_shield_24dp
import lwacharactersheet.composeapp.generated.resources.ic_skull_24dp
import lwacharactersheet.composeapp.generated.resources.ic_swords_24dp
import lwacharactersheet.composeapp.generated.resources.ic_water_drop_24dp
import lwacharactersheet.composeapp.generated.resources.ic_pan_tool_24dp
import lwacharactersheet.composeapp.generated.resources.ic_azm_24dp
import lwacharactersheet.composeapp.generated.resources.ic_directions_run_24dp
import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource
@ -74,6 +77,11 @@ data class CharacterDetailHeaderUio(
val growTooltip: TooltipUio,
val learn: String,
val learnTooltip: TooltipUio,
val reflex: String,
val reflexTooltip: TooltipUio,
val reflexRoll: RollAction.Uio,
val initiative: String,
val initiativeTooltip: TooltipUio,
)
@OptIn(ExperimentalFoundationApi::class)
@ -86,6 +94,7 @@ fun CharacterDetailHeader(
onDiminished: () -> Unit,
onHp: () -> Unit,
onPp: () -> Unit,
onReflex: (RollAction.Uio) -> Unit,
) {
Column(
modifier = modifier,
@ -157,7 +166,7 @@ fun CharacterDetailHeader(
}
Row(
modifier = Modifier.padding(horizontal = 16.dp),
horizontalArrangement = Arrangement.spacedBy(space = 16.dp),
horizontalArrangement = Arrangement.spacedBy(space = 10.dp),
) {
TooltipLayout(
tooltip = header.value?.hpTooltip,
@ -220,6 +229,50 @@ fun CharacterDetailHeader(
Spacer(modifier = Modifier.weight(1f))
TooltipLayout(
tooltip = header.value?.reflexTooltip,
) {
Row(
modifier = Modifier
.clip(shape = CircleShape)
.clickable { header.value?.reflexRoll?.let(onReflex) },
verticalAlignment = Alignment.Bottom,
) {
Icon(
modifier = Modifier
.padding(bottom = 4.dp, end = 2.dp)
.size(size = iconSize),
painter = painterResource(Res.drawable.ic_pan_tool_24dp),
contentDescription = null
)
Text(
modifier = Modifier.alignByBaseline(),
style = MaterialTheme.typography.h6,
color = MaterialTheme.lwa.colorScheme.base.primary,
text = header.value?.reflex ?: "",
)
}
}
TooltipLayout(
tooltip = header.value?.initiativeTooltip,
) {
Row(
verticalAlignment = Alignment.Bottom,
) {
Icon(
modifier = Modifier
.padding(bottom = 4.dp, end = 2.dp)
.size(size = iconSize),
painter = painterResource(Res.drawable.ic_azm_24dp),
contentDescription = null
)
Text(
modifier = Modifier.alignByBaseline(),
style = MaterialTheme.typography.h6,
text = header.value?.initiative ?: "",
)
}
}
TooltipLayout(
tooltip = header.value?.movTooltip,
) {
@ -230,7 +283,7 @@ fun CharacterDetailHeader(
modifier = Modifier
.padding(bottom = 4.dp, end = 2.dp)
.size(size = iconSize),
painter = painterResource(Res.drawable.ic_near_me),
painter = painterResource(Res.drawable.ic_directions_run_24dp),
contentDescription = null,
)
Text(

View file

@ -10,6 +10,7 @@ import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.Characterist
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.GHP
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.HEI
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.HP
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.INITIATIVE
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.INT
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.LB
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.LVL
@ -17,6 +18,7 @@ import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.Characterist
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.PORTRAIT
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.POW
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.PP
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.REFLEX
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.STR
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.THUMBNAIL
import com.pixelized.shared.lwa.parser.expression.Expression
@ -86,12 +88,6 @@ class AlteredCharacterSheet(
val charisma: Int
get() = sheet.charisma + fieldAlterations[CHA].sum()
val movement: Int
get() = sheetUseCase.movement() + fieldAlterations[MOV].sum()
val armor: Int
get() = sheetUseCase.armor() + fieldAlterations[ARMOR].sum()
val maxHp: Int
get() = sheetUseCase.maxHp(
constitution = constitution,
@ -116,6 +112,22 @@ class AlteredCharacterSheet(
val alterations: List<String>
get() = sheet.alterations
val movement: Int
get() = sheetUseCase.movement() + fieldAlterations[MOV].sum()
val armor: Int
get() = sheetUseCase.armor() + fieldAlterations[ARMOR].sum()
val reflex: Int
get() = sheetUseCase.reflex(
strength = strength,
dexterity = dexterity,
intelligence = intelligence,
) + fieldAlterations[REFLEX].sum()
val initiative: Int
get() = sheetUseCase.initiative(dexterity = dexterity) + fieldAlterations[INITIATIVE].sum()
val damageBonus: String
get() {
val initial = sheetUseCase.meleeBonusDamage(

View file

@ -64,6 +64,8 @@ data class CharacterSheet(
const val PP = "PP"
const val DMG = "DMG"
const val ARMOR = "ARMOR"
const val REFLEX = "REFLEX"
const val INITIATIVE = "INITIATIVE"
const val LB = "LEARNING"
const val GHP = "HP_GROW"
}

View file

@ -11,6 +11,20 @@ class CharacterSheetUseCase {
fun movement(): Int = 10
fun reflex(
strength: Int,
dexterity: Int,
intelligence: Int,
): Int {
return (strength + dexterity + intelligence) / 3
}
fun initiative(
dexterity: Int,
): Int {
return dexterity
}
fun maxHp(
constitution: Int,
height: Int,