Add characterSheet and Campaing to the server.

This commit is contained in:
Thomas Andres Gomez 2025-02-22 21:25:08 +01:00
parent 1e5f0d88ae
commit 495768e5fe
53 changed files with 879 additions and 513 deletions

View file

@ -1,6 +1,8 @@
package com.pixelized.shared.lwa
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheetJsonFactory
import com.pixelized.shared.lwa.model.campaign.CampaignJsonFactory
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJsonFactory
import com.pixelized.shared.lwa.usecase.CampaignUseCase
import com.pixelized.shared.lwa.usecase.CharacterSheetUseCase
import kotlinx.serialization.json.Json
import org.koin.core.module.dsl.factoryOf
@ -26,9 +28,11 @@ val toolsDependencies
val factoryDependencies
get() = module {
factoryOf(::CharacterSheetJsonFactory)
factoryOf(::CampaignJsonFactory)
}
val useCaseDependencies
get() = module {
factoryOf(::CharacterSheetUseCase)
factoryOf(::CampaignUseCase)
}

View file

@ -34,4 +34,13 @@ fun characterStorePath(
OperatingSystem.Windows -> "${storePath(os = os)}characters\\"
OperatingSystem.Macintosh -> "${storePath(os = os)}characters/"
}
}
fun campaignPath(
os: OperatingSystem = OperatingSystem.current,
): String {
return when (os) {
OperatingSystem.Windows -> "${storePath(os = os)}campaign\\"
OperatingSystem.Macintosh -> "${storePath(os = os)}campaign/"
}
}

View file

@ -0,0 +1,34 @@
package com.pixelized.shared.lwa.model.campaign
data class Campaign(
val characters: Map<String, CharacterInstance>,
) {
data class CharacterInstance(
val characteristic: Map<Characteristic, Int>,
val usedSkill: List<String>,
) {
enum class Characteristic {
Damage,
Power,
}
}
companion object {
val EMPTY = Campaign(
characters = emptyMap(),
)
}
}
fun Campaign.character(id: String): Campaign.CharacterInstance {
return characters[id] ?: Campaign.CharacterInstance(
characteristic = emptyMap(),
usedSkill = emptyList(),
)
}
val Campaign.CharacterInstance.damage
get() = characteristic[Campaign.CharacterInstance.Characteristic.Damage] ?: 0
val Campaign.CharacterInstance.power
get() = characteristic[Campaign.CharacterInstance.Characteristic.Power] ?: 0

View file

@ -1,4 +1,4 @@
package com.pixelized.shared.lwa.model.campaign.model
package com.pixelized.shared.lwa.model.campaign
import kotlinx.serialization.Serializable

View file

@ -0,0 +1,48 @@
package com.pixelized.shared.lwa.model.campaign
class CampaignJsonFactory {
fun convertFromJson(
json: CampaignJson,
): Campaign {
return when (json) {
is CampaignJsonV1 -> convertFromV1(json = json)
}
}
private fun convertFromV1(
json: CampaignJsonV1,
): Campaign {
return Campaign(
characters = json.characters.map { entry ->
entry.key to Campaign.CharacterInstance(
characteristic = entry.value.characteristic.map { char ->
when (char.key) {
CampaignJsonV1.CharacterInstanceJson.Characteristic.Damage -> Campaign.CharacterInstance.Characteristic.Damage
CampaignJsonV1.CharacterInstanceJson.Characteristic.Power -> Campaign.CharacterInstance.Characteristic.Power
} to char.value
}.toMap(),
usedSkill = entry.value.usedSkill,
)
}.toMap()
)
}
fun convertToJson(
data: Campaign,
): CampaignJson {
return CampaignJsonV1(
characters = data.characters.map { entry ->
entry.key to CampaignJsonV1.CharacterInstanceJson(
characteristic = entry.value.characteristic.map { char ->
when (char.key) {
Campaign.CharacterInstance.Characteristic.Damage -> CampaignJsonV1.CharacterInstanceJson.Characteristic.Damage
Campaign.CharacterInstance.Characteristic.Power -> CampaignJsonV1.CharacterInstanceJson.Characteristic.Power
} to char.value
}.toMap(),
usedSkill = entry.value.usedSkill,
)
}.toMap()
)
}
}

View file

@ -0,0 +1,20 @@
package com.pixelized.shared.lwa.model.campaign
import kotlinx.serialization.Serializable
@Serializable
data class CampaignJsonV1(
val characters: Map<String, CharacterInstanceJson>,
) : CampaignJson {
@Serializable
data class CharacterInstanceJson(
val characteristic: Map<Characteristic, Int>,
val usedSkill: List<String>,
) {
enum class Characteristic {
Damage,
Power,
}
}
}

View file

@ -1,9 +0,0 @@
package com.pixelized.shared.lwa.model.campaign
import com.pixelized.shared.lwa.model.campaign.model.CampaignFactory
class CampaignRepository(
private val factory: CampaignFactory,
) {
}

View file

@ -1,11 +0,0 @@
package com.pixelized.shared.lwa.model.campaign.model
data class Campaign(
val characters: List<CharacterInstance>,
) {
data class CharacterInstance(
val damage: Int,
val usedPower: Int,
val usedMovement: Int,
)
}

View file

@ -1,39 +0,0 @@
package com.pixelized.shared.lwa.model.campaign.model
class CampaignFactory {
fun convertFromJson(
json: CampaignJson,
): Campaign {
return when (json) {
is CampaignJsonV1 -> convertFromV1(json = json)
}
}
private fun convertFromV1(
json: CampaignJsonV1,
): Campaign {
return Campaign(
characters = json.characters.map {
Campaign.CharacterInstance(
damage = it.damage,
usedPower = it.usedPower,
usedMovement = it.usedMovement,
)
}
)
}
private fun convertToJson(
data: Campaign,
): CampaignJson {
return CampaignJsonV1(
characters = data.characters.map {
CampaignJsonV1.CharacterInstanceJson(
damage = it.damage,
usedPower = it.usedPower,
usedMovement = it.usedMovement,
)
}
)
}
}

View file

@ -1,15 +0,0 @@
package com.pixelized.shared.lwa.model.campaign.model
import kotlinx.serialization.Serializable
@Serializable
data class CampaignJsonV1(
val characters: List<CharacterInstanceJson>,
) : CampaignJson {
@Serializable
data class CharacterInstanceJson(
val damage: Int,
val usedPower: Int,
val usedMovement: Int,
)
}

View file

@ -1,10 +1,11 @@
package com.pixelized.shared.lwa.model.characterSheet.model
package com.pixelized.shared.lwa.model.characterSheet
data class CharacterSheet(
val id: String,
val name: String,
val portrait: String?,
val thumbnail: String?,
val level: Int,
// characteristics
val strength: Int,
val dexterity: Int,
@ -14,21 +15,12 @@ data class CharacterSheet(
val power: Int,
val charisma: Int,
// sub characteristics
val overrideMovement: Boolean,
val movement: Int,
val currentHp: Int,
val overrideMaxHp: Boolean,
val maxHp: Int,
val currentPp: Int,
val overrideMaxPP: Boolean,
val maxPp: Int,
val overrideDamageBonus: Boolean,
val hp: Int,
val pp: Int,
val damageBonus: String,
val overrideArmor: Boolean,
val armor: Int,
val overrideLearning: Boolean,
val learning: Int,
val overrideHpGrow: Boolean,
val hpGrow: Int,
// skills
val commonSkills: List<Skill>,
@ -43,7 +35,7 @@ data class CharacterSheet(
val description: String?,
val base: String,
val bonus: String?,
val level: String?,
val level: Int,
val occupation: Boolean,
val used: Boolean,
)
@ -51,6 +43,8 @@ data class CharacterSheet(
data class Roll(
val id: String,
val label: String,
val description: String?,
val canBeCritical: Boolean,
val roll: String,
)

View file

@ -1,4 +1,4 @@
package com.pixelized.shared.lwa.model.characterSheet.model
package com.pixelized.shared.lwa.model.characterSheet
import kotlinx.serialization.Serializable

View file

@ -1,4 +1,4 @@
package com.pixelized.shared.lwa.model.characterSheet.model
package com.pixelized.shared.lwa.model.characterSheet
import com.pixelized.shared.lwa.usecase.CharacterSheetUseCase
@ -22,6 +22,7 @@ class CharacterSheetJsonFactory(
name = json.name,
portrait = json.portrait,
thumbnail = json.thumbnail,
level = json.level,
strength = json.strength,
dexterity = json.dexterity,
constitution = json.constitution,
@ -29,28 +30,26 @@ class CharacterSheetJsonFactory(
intelligence = json.intelligence,
power = json.power,
charisma = json.charisma,
overrideMovement = json.movement != null,
movement = json.movement ?: defaultMovement(),
currentHp = json.currentHp,
overrideMaxHp = json.maxHp != null,
maxHp = json.maxHp ?: defaultMaxHp(
movement = defaultMovement(),
hp = defaultMaxHp(
constitution = json.constitution,
height = json.height,
level = json.level
),
currentPp = json.currentPP,
overrideMaxPP = json.maxPP != null,
maxPp = json.maxPP ?: defaultMaxPower(power = json.power),
overrideDamageBonus = json.damageBonus != null,
damageBonus = json.damageBonus ?: defaultDamageBonus(
pp = defaultMaxPower(
power = json.power,
),
damageBonus = defaultDamageBonus(
strength = json.strength,
height = json.height,
),
overrideArmor = json.armor != null,
armor = json.armor ?: defaultArmor(),
overrideLearning = json.learning != null,
learning = json.learning ?: defaultLearning(intelligence = json.intelligence),
overrideHpGrow = json.hpGrowf != null,
hpGrow = json.hpGrowf ?: defaultHpGrow(constitution = json.constitution),
armor = defaultArmor(),
learning = defaultLearning(
intelligence = json.intelligence,
),
hpGrow = defaultHpGrow(
constitution = json.constitution,
),
commonSkills = json.skills.map {
CharacterSheet.Skill(
id = it.id,
@ -91,6 +90,8 @@ class CharacterSheetJsonFactory(
CharacterSheet.Roll(
id = it.id,
label = it.label,
description = it.description,
canBeCritical = it.canBeCritical,
roll = it.roll,
)
},
@ -105,6 +106,7 @@ class CharacterSheetJsonFactory(
name = sheet.name,
thumbnail = sheet.thumbnail,
portrait = sheet.portrait,
level = sheet.level,
strength = sheet.strength,
dexterity = sheet.dexterity,
constitution = sheet.constitution,
@ -112,15 +114,6 @@ class CharacterSheetJsonFactory(
intelligence = sheet.intelligence,
power = sheet.power,
charisma = sheet.charisma,
movement = if (sheet.overrideMovement) sheet.movement else null,
currentHp = sheet.currentHp,
maxHp = if (sheet.overrideMaxHp) sheet.maxHp else null,
currentPP = sheet.currentPp,
maxPP = if (sheet.overrideMaxPP) sheet.maxPp else null,
damageBonus = if (sheet.overrideDamageBonus) sheet.damageBonus else null,
armor = if (sheet.overrideArmor) sheet.armor else null,
learning = if (sheet.overrideLearning) sheet.learning else null,
hpGrowf = if (sheet.overrideHpGrow) sheet.hpGrow else null,
skills = sheet.commonSkills.map {
CharacterSheetJsonV1.Skill(
id = it.id,
@ -161,6 +154,8 @@ class CharacterSheetJsonFactory(
CharacterSheetJsonV1.Roll(
id = it.id,
label = it.label,
description = it.description,
canBeCritical = it.canBeCritical,
roll = it.roll,
)
},

View file

@ -1,4 +1,4 @@
package com.pixelized.shared.lwa.model.characterSheet.model
package com.pixelized.shared.lwa.model.characterSheet
import kotlinx.serialization.Serializable
@ -8,6 +8,7 @@ data class CharacterSheetJsonV1(
val name: String,
val portrait: String?,
val thumbnail: String?,
val level: Int,
// characteristics
val strength: Int,
val dexterity: Int,
@ -16,16 +17,6 @@ data class CharacterSheetJsonV1(
val intelligence: Int,
val power: Int,
val charisma: Int,
// sub characteristics
val movement: Int?,
val currentHp: Int,
val maxHp: Int?,
val currentPP: Int,
val maxPP: Int?,
val damageBonus: String?,
val armor: Int?,
val learning: Int?,
val hpGrowf: Int?,
// skills
val skills: List<Skill>,
// occupations
@ -43,7 +34,7 @@ data class CharacterSheetJsonV1(
val description: String?,
val base: String,
val bonus: String?,
val level: String?,
val level: Int,
val occupation: Boolean,
val used: Boolean,
)
@ -52,6 +43,8 @@ data class CharacterSheetJsonV1(
data class Roll(
val id: String,
val label: String,
val description: String?,
val canBeCritical: Boolean,
val roll: String,
)
}

View file

@ -1,5 +1,7 @@
package com.pixelized.shared.lwa.protocol
enum class MessageType {
Roll
Roll,
UpdateSkillUsage,
UpdatePlayerCharacteristic,
}

View file

@ -0,0 +1,3 @@
package com.pixelized.shared.lwa.protocol.payload
sealed interface MessagePayload

View file

@ -1,4 +1,4 @@
package com.pixelized.shared.lwa.protocol.roll
package com.pixelized.shared.lwa.protocol.payload
import kotlinx.serialization.Serializable
@ -10,4 +10,4 @@ data class RollMessage(
val rollDifficulty: String?,
val rollValue: Int,
val rollSuccessLimit: Int?,
)
) : MessagePayload

View file

@ -0,0 +1,11 @@
package com.pixelized.shared.lwa.protocol.payload
import com.pixelized.shared.lwa.model.campaign.Campaign
import kotlinx.serialization.Serializable
@Serializable
data class UpdatePlayerCharacteristicMessage(
val characterId: String,
val characteristic: Campaign.CharacterInstance.Characteristic,
val value: Int,
) : MessagePayload

View file

@ -0,0 +1,9 @@
package com.pixelized.shared.lwa.protocol.payload
import kotlinx.serialization.Serializable
@Serializable
data class UpdateSkillUsageMessage(
val characterId: String,
val skillId: String,
) : MessagePayload

View file

@ -0,0 +1,18 @@
package com.pixelized.shared.lwa.usecase
import com.pixelized.shared.lwa.model.campaign.Campaign
class CampaignUseCase {
fun updateCharacteristic(
character: Campaign.CharacterInstance,
characteristic: Campaign.CharacterInstance.Characteristic,
value: Int,
): Campaign.CharacterInstance {
return character.copy(
characteristic = character.characteristic.toMutableMap().also {
it[characteristic] = value
}
)
}
}

View file

@ -1,5 +1,6 @@
package com.pixelized.shared.lwa.usecase
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
import kotlin.math.ceil
import kotlin.math.max
@ -14,8 +15,10 @@ class CharacterSheetUseCase {
fun defaultMaxHp(
constitution: Int,
height: Int,
level: Int,
): Int {
return (ceil((constitution + height) / 2f).toInt())
val add = max(defaultHpGrow(constitution = constitution) * (level - 1), 0)
return (ceil((constitution + height) / 2f).toInt()) + add
}
fun defaultMaxPower(
@ -53,4 +56,33 @@ class CharacterSheetUseCase {
fun defaultHpGrow(constitution: Int): Int {
return (constitution / 3)
}
fun updateSkillUsage(
character: CharacterSheet,
skillId: String,
): CharacterSheet {
return character.copy(
commonSkills = character.commonSkills.map { skill ->
if (skill.id == skillId) {
skill.copy(used = skill.used.not())
} else {
skill
}
},
specialSkills = character.specialSkills.map { skill ->
if (skill.id == skillId) {
skill.copy(used = skill.used.not())
} else {
skill
}
},
magicSkills = character.magicSkills.map { skill ->
if (skill.id == skillId) {
skill.copy(used = skill.used.not())
} else {
skill
}
}
)
}
}