This commit is contained in:
Andres Gomez, Thomas (ITDV RL) 2025-11-29 10:25:05 +01:00
parent ce05e6a4c4
commit f6f2a8b4f8
11 changed files with 490 additions and 109 deletions

View file

@ -3,7 +3,6 @@ package com.pixelized.shared.lwa.model
import com.pixelized.shared.lwa.model.alteration.FieldAlteration
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.ARMOR
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.CHA
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.CON
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.DEX
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.DMG
@ -69,37 +68,24 @@ class AlteredCharacterSheet(
val level: Int
get() = sheet.level + fieldAlterations[LVL].sum()
val strength: Int
get() = sheet.strength + fieldAlterations[STR].sum()
val dexterity: Int
get() = sheet.dexterity + fieldAlterations[DEX].sum()
val constitution: Int
get() = sheet.constitution + fieldAlterations[CON].sum()
val height: Int
get() = sheet.height + fieldAlterations[HEI].sum()
val intelligence: Int
get() = sheet.intelligence + fieldAlterations[INT].sum()
val power: Int
get() = sheet.power + fieldAlterations[POW].sum()
val charisma: Int
get() = sheet.charisma + fieldAlterations[CHA].sum()
/**
* see CharacterSheet.CharacteristicId
*/
fun characteristic(id: String): Int =
sheet.characteristics.firstOrNull { it.id == id }?.let { characteristic ->
characteristic.base + characteristic.level + fieldAlterations[id].sum()
} ?: 0
val maxHp: Int
get() = sheetUseCase.maxHp(
constitution = constitution,
height = height,
constitution = characteristic(id = CON),
height = characteristic(id = HEI),
level = level,
) + fieldAlterations[HP].sum()
val maxPp: Int
get() = sheetUseCase.maxPp(
power = power,
power = characteristic(id = POW),
) + fieldAlterations[PP].sum()
val damage: Int
@ -125,19 +111,21 @@ class AlteredCharacterSheet(
val reflex: Int
get() = sheetUseCase.reflex(
strength = strength,
dexterity = dexterity,
intelligence = intelligence,
strength = characteristic(id = STR),
dexterity = characteristic(id = DEX),
intelligence = characteristic(id = INT),
) + fieldAlterations[REFLEX].sum()
val initiative: Int
get() = sheetUseCase.initiative(dexterity = dexterity) + fieldAlterations[INITIATIVE].sum()
get() = sheetUseCase.initiative(
dexterity = characteristic(id = DEX)
) + fieldAlterations[INITIATIVE].sum()
val damageBonus: String
get() {
val initial = sheetUseCase.meleeBonusDamage(
strength = strength,
height = height,
strength = characteristic(id = STR),
height = characteristic(id = HEI),
)
return fieldAlterations[DMG]
?.joinToString(separator = "+") { it.expression.toString() }
@ -147,12 +135,12 @@ class AlteredCharacterSheet(
val learning: Int
get() = sheetUseCase.learning(
intelligence = intelligence
intelligence = characteristic(id = INT),
) + fieldAlterations[LB].sum()
val hpGrow: Int
get() = sheetUseCase.hpGrow(
constitution = constitution,
constitution = characteristic(id = CON),
) + fieldAlterations[GHP].sum()
// Helper method

View file

@ -10,13 +10,7 @@ data class CharacterSheet(
val level: Int,
val shouldLevelUp: Boolean,
// characteristics
val strength: Int,
val dexterity: Int,
val constitution: Int,
val height: Int,
val intelligence: Int,
val power: Int,
val charisma: Int,
val characteristics: List<Characteristic>,
// alterations
val damage: Int, // damage taken on the hp pool
val fatigue: Int, // damage taken on the pp pool
@ -35,6 +29,14 @@ data class CharacterSheet(
?: specialSkills.firstOrNull { it.id == id }
?: magicSkills.firstOrNull { it.id == id }
data class Characteristic(
val id: String,
val label: String,
val description: String?,
val base: Int,
val level: Int,
)
data class Skill(
val id: String,
val label: String,

View file

@ -0,0 +1,63 @@
package com.pixelized.shared.lwa.model.characterSheet
import kotlinx.serialization.Serializable
@Serializable
data class CharacterSheetJsonV2(
override val id: String,
override val name: String,
val job: String?,
val portrait: String?,
val thumbnail: String?,
val externalLink: String?,
val level: Int,
val shouldLevelUp: Boolean?,
// characteristics
val characteristics: List<Characteristic>,
// alterations
val damage: Int?,
val fatigue: Int?,
val diminished: Int?,
val alterations: List<String>?,
// skills
val skills: List<Skill>,
val occupations: List<Skill>,
val magics: List<Skill>,
// actions
val rolls: List<Roll>,
// tags
val tag: List<String>?,
) : CharacterSheetJson {
@Serializable
data class Characteristic(
val id: String,
val label: String,
val description: String?,
val base: Int,
val level: Int,
)
@Serializable
data class Skill(
val id: String,
val label: String,
val description: String?,
val base: String,
val bonus: String?,
val level: Int,
val occupation: Boolean,
val used: Boolean,
)
@Serializable
data class Roll(
val id: String,
val label: String,
val description: String?,
val canBeCritical: Boolean,
val roll: String,
val special: String?,
val critical: String?,
)
}

View file

@ -3,18 +3,21 @@ package com.pixelized.shared.lwa.model.characterSheet.factory
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJson
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJsonV1
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJsonV2
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetPreview
import com.pixelized.shared.lwa.protocol.rest.CharacterPreviewJson
class CharacterSheetJsonFactory(
private val v1: CharacterSheetJsonV1Factory,
private val v2: CharacterSheetJsonV2Factory,
) {
fun convertFromJson(
json: CharacterSheetJson,
): CharacterSheet {
return when (json) {
is CharacterSheetJsonV1 -> v1.convertFromJson(json = json)
is CharacterSheetJsonV2 -> v2.convertFromJson(json = json)
}
}
@ -23,7 +26,7 @@ class CharacterSheetJsonFactory(
fun convertToJson(
sheet: CharacterSheet,
): CharacterSheetJson {
val json = CharacterSheetJsonV1(
val json = CharacterSheetJsonV2(
id = sheet.id,
name = sheet.name,
job = sheet.job,
@ -32,19 +35,21 @@ class CharacterSheetJsonFactory(
externalLink = sheet.externalLink,
level = sheet.level,
shouldLevelUp = sheet.shouldLevelUp,
strength = sheet.strength,
dexterity = sheet.dexterity,
constitution = sheet.constitution,
height = sheet.height,
intelligence = sheet.intelligence,
power = sheet.power,
charisma = sheet.charisma,
characteristics = sheet.characteristics.map {
CharacterSheetJsonV2.Characteristic(
id = it.id,
label = it.label,
description = it.description,
base = it.base,
level = it.level,
)
},
damage = sheet.damage,
fatigue = sheet.fatigue,
diminished = sheet.diminished,
alterations = sheet.alterations,
skills = sheet.commonSkills.map {
CharacterSheetJsonV1.Skill(
CharacterSheetJsonV2.Skill(
id = it.id,
label = it.label,
description = it.description,
@ -56,7 +61,7 @@ class CharacterSheetJsonFactory(
)
},
occupations = sheet.specialSkills.map {
CharacterSheetJsonV1.Skill(
CharacterSheetJsonV2.Skill(
id = it.id,
label = it.label,
description = it.description,
@ -68,7 +73,7 @@ class CharacterSheetJsonFactory(
)
},
magics = sheet.magicSkills.map {
CharacterSheetJsonV1.Skill(
CharacterSheetJsonV2.Skill(
id = it.id,
label = it.label,
description = it.description,
@ -80,7 +85,7 @@ class CharacterSheetJsonFactory(
)
},
rolls = sheet.actions.map {
CharacterSheetJsonV1.Roll(
CharacterSheetJsonV2.Roll(
id = it.id,
label = it.label,
description = it.description,

View file

@ -19,13 +19,57 @@ class CharacterSheetJsonV1Factory(
externalLink = json.externalLink,
level = json.level,
shouldLevelUp = json.shouldLevelUp ?: false,
strength = json.strength,
dexterity = json.dexterity,
constitution = json.constitution,
height = json.height,
intelligence = json.intelligence,
power = json.power,
charisma = json.charisma,
characteristics = listOf(
CharacterSheet.Characteristic(
id = CharacterSheet.CharacteristicId.STR,
label = "Force",
description = "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",
base = json.strength,
level = 0,
),
CharacterSheet.Characteristic(
id = CharacterSheet.CharacteristicId.DEX,
label = "Dextérité",
description = "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",
base = json.dexterity,
level = 0,
),
CharacterSheet.Characteristic(
id = CharacterSheet.CharacteristicId.CON,
label = "Constitution",
description = "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)",
base = json.constitution,
level = 0,
),
CharacterSheet.Characteristic(
id = CharacterSheet.CharacteristicId.HEI,
label = "Taille",
description = "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",
base = json.height,
level = 0,
),
CharacterSheet.Characteristic(
id = CharacterSheet.CharacteristicId.INT,
label = "Intelligence",
description = "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",
base = json.intelligence,
level = 0,
),
CharacterSheet.Characteristic(
id = CharacterSheet.CharacteristicId.POW,
label = "Pouvoir",
description = "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",
base = json.power,
level = 0,
),
CharacterSheet.Characteristic(
id = CharacterSheet.CharacteristicId.CHA,
label = "Charisme",
description = "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",
base = json.charisma,
level = 0,
),
),
damage = json.damage ?: 0,
fatigue = json.fatigue ?: 0,
diminished = json.diminished ?: 0,

View file

@ -0,0 +1,85 @@
package com.pixelized.shared.lwa.model.characterSheet.factory
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJsonV2
import com.pixelized.shared.lwa.usecase.CharacterSheetUseCase
class CharacterSheetJsonV2Factory(
private val characterSheetUseCase: CharacterSheetUseCase,
) {
fun convertFromJson(
json: CharacterSheetJsonV2,
): CharacterSheet = characterSheetUseCase.run {
CharacterSheet(
id = json.id,
name = json.name,
job = json.job ?: "",
portrait = json.portrait,
thumbnail = json.thumbnail,
externalLink = json.externalLink,
level = json.level,
shouldLevelUp = json.shouldLevelUp ?: false,
characteristics = json.characteristics.map {
CharacterSheet.Characteristic(
id = it.id,
label = it.label,
description = it.description,
base = it.base,
level = it.level,
)
},
damage = json.damage ?: 0,
fatigue = json.fatigue ?: 0,
diminished = json.diminished ?: 0,
alterations = json.alterations ?: emptyList(),
commonSkills = json.skills.map {
CharacterSheet.Skill(
id = it.id,
label = it.label,
description = it.description,
base = it.base,
bonus = it.bonus,
level = it.level,
occupation = it.occupation,
used = it.used,
)
},
specialSkills = json.occupations.map {
CharacterSheet.Skill(
id = it.id,
label = it.label,
description = it.description,
base = it.base,
bonus = it.bonus,
level = it.level,
occupation = it.occupation,
used = it.used,
)
},
magicSkills = json.magics.map {
CharacterSheet.Skill(
id = it.id,
label = it.label,
description = it.description,
base = it.base,
bonus = it.bonus,
level = it.level,
occupation = it.occupation,
used = it.used,
)
},
actions = json.rolls.map {
CharacterSheet.Roll(
id = it.id,
label = it.label,
description = it.description,
canBeCritical = it.canBeCritical,
default = it.roll,
special = it.special,
critical = it.critical,
)
},
tags = json.tag ?: emptyList(),
)
}
}

View file

@ -4,6 +4,13 @@ package com.pixelized.shared.lwa.usecase
import com.pixelized.shared.lwa.model.AlteredCharacterSheet
import com.pixelized.shared.lwa.model.alteration.FieldAlteration
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.CHA
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.CON
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.DEX
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.HEI
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.INT
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.POW
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.STR
import com.pixelized.shared.lwa.parser.expression.Expression
import com.pixelized.shared.lwa.parser.expression.ExpressionParser
import com.pixelized.shared.lwa.parser.word.Word
@ -128,8 +135,8 @@ class ExpressionUseCase(
Word.Type.BDC -> evaluate(
expression = expressionParser.parse(
characterSheetUseCase.meleeBonusDamage(
strength = sheet.strength,
height = sheet.height,
strength = sheet.characteristic(id = STR),
height = sheet.characteristic(id = HEI),
)
)
)
@ -137,19 +144,19 @@ class ExpressionUseCase(
Word.Type.BDD -> evaluate(
expression = expressionParser.parse(
characterSheetUseCase.distanceBonusDamage(
strength = sheet.strength,
height = sheet.height,
strength = sheet.characteristic(id = STR),
height = sheet.characteristic(id = HEI),
)
)
)
Word.Type.STR -> sheet.strength
Word.Type.DEX -> sheet.dexterity
Word.Type.CON -> sheet.constitution
Word.Type.HEI -> sheet.height
Word.Type.INT -> sheet.intelligence
Word.Type.POW -> sheet.power
Word.Type.CHA -> sheet.charisma
Word.Type.STR -> sheet.characteristic(id = STR)
Word.Type.DEX -> sheet.characteristic(id = DEX)
Word.Type.CON -> sheet.characteristic(id = CON)
Word.Type.HEI -> sheet.characteristic(id = HEI)
Word.Type.INT -> sheet.characteristic(id = INT)
Word.Type.POW -> sheet.characteristic(id = POW)
Word.Type.CHA -> sheet.characteristic(id = CHA)
}
null -> 0