2025-03-15 21:47:51 +03:00

170 lines
7.4 KiB
Kotlin

package com.dowstats.service.w40k
import com.dowstats.data.entities.ArmorType
import com.dowstats.data.entities.Weapon
import com.dowstats.data.entities.WeaponArmorPiercing
import com.dowstats.data.repositories.ArmorTypeRepository
import com.dowstats.data.rgd.RgdData
import com.dowstats.data.rgd.RgdDataUtil.getBooleanByName
import com.dowstats.data.rgd.RgdDataUtil.getDoubleByName
import com.dowstats.data.rgd.RgdDataUtil.getIntByName
import com.dowstats.data.rgd.RgdDataUtil.getRgdTableByName
import com.dowstats.data.rgd.RgdDataUtil.getStringByName
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import java.io.File
import java.nio.file.Path
import kotlin.io.path.exists
@Service
class WeaponRgdExtractService @Autowired constructor(
private val armorTypeRepository: ArmorTypeRepository,
private val iconsService: IconsService,
private val modAttribPathService: ModAttribPathService,
) {
val log = LoggerFactory.getLogger(WeaponRgdExtractService::class.java)
data class BuildCost(
val requisition: Int?,
val power: Int?,
val seconds: Int?
)
data class ArmourDamage(
val minDamage: Double,
val maxDamage: Double,
val minDamageValue: Double,
val moraleDamage: Double,
val armourPiercing: List<WeaponArmorPiercing>,
)
data class WeaponUiInfo(
val name: String?,
val description: String?,
val iconPath: String?,
val haveEquipButton: Boolean
)
fun extractToWeaponEntity(weaponFileName: String, weaponData: List<RgdData>, modId: Long, modFolderData: String, modDictionary: Map<Int, String>): Weapon? {
val armorTypes = armorTypeRepository.findAll().toSet()
val weapon = Weapon()
weapon.filename = weaponFileName
val weaponUiData = getWeaponNameAndDescription(weaponData, modDictionary, modFolderData)
weapon.name = weaponUiData.name
weapon.icon = weaponUiData.iconPath
weapon.description = weaponUiData.description
weapon.haveEquipButton = weaponUiData.haveEquipButton
weapon.hotkeyName = weaponData.getStringByName("ui_hotkey_name")
val cost = getCost(weaponData)
weapon.costRequisition = cost.requisition ?: 0
weapon.costPower = cost.power ?: 0
weapon.costTimeSeconds = cost.seconds ?: 0
weapon.accuracy = weaponData.getDoubleByName("accuracy")
weapon.accuracyReductionMoving = weaponData.getDoubleByName("accuracy_reduction_when_moving")
weapon.maxRange = weaponData.getDoubleByName("max_range")
weapon.reloadTime = weaponData.getDoubleByName("reload_time")
weapon.setupTime = weaponData.getDoubleByName("setup_time")
weapon.isMeleeWeapon = weaponData.getBooleanByName("melee_weapon") ?: false
weapon.canAttackAir = weaponData.getBooleanByName("can_attack_air_units") ?: false
weapon.canAttackGround = weaponData.getBooleanByName("can_attack_ground_units") ?: false
val armourDamage = getArmourDamage(weaponData, armorTypes, weapon)
weapon.minDamageValue = armourDamage.minDamageValue
weapon.minDamage = armourDamage.minDamage
weapon.maxDamage = armourDamage.maxDamage
weapon.moraleDamage = armourDamage.moraleDamage
weapon.weaponPiercings = armourDamage.armourPiercing
weapon.modId = modId
return if(weapon.minDamage == 0.0 && weapon.maxDamage == 0.0 && weapon.moraleDamage == 0.0){
null
} else weapon
}
private fun getCost(weaponData: List<RgdData>): BuildCost {
val costTable = weaponData.getRgdTableByName("cost")
val costTime = costTable?.getIntByName("time_seconds")
val costCost = costTable?.getRgdTableByName("cost")
val power = costCost?.getIntByName("power")
val requisition = costCost?.getIntByName("requisition")
return BuildCost(requisition, power, costTime)
}
private fun getArmourDamage(weaponData: List<RgdData>, armorTypes: Set<ArmorType>, thisWeapon: Weapon): ArmourDamage {
val armourDamage = weaponData.getRgdTableByName("area_effect")
?.getRgdTableByName("weapon_damage")
?.getRgdTableByName("armour_damage")!!
val minDamage = armourDamage.getDoubleByName("min_damage")!!
val maxDamage = armourDamage.getDoubleByName("max_damage")!!
val minDamageValue = armourDamage.getDoubleByName("min_damage_value")!!
val moraleDamage = armourDamage.getDoubleByName("morale_damage")!!
val defaultArmourPiercing = armourDamage.getDoubleByName("armour_piercing")
val weaponDmgMap: Map<String, Double> =
armourDamage.getRgdTableByName("armour_piercing_types")!!.mapNotNull { armour_piercing ->
if (armour_piercing.name.contains("entry")) {
val entry = armour_piercing.value as List<RgdData>
val dmgType = entry.getRgdTableByName("armour_type")?.getStringByName("\$REF")?.replace("type_armour\\tp_","")?.replace(".lua","")
val dmgValue = entry.getDoubleByName("armour_piercing_value")
dmgType!! to dmgValue!!
} else null
}.toMap()
val armoursPiercing = armorTypes.map {
val weaponArmourPiercing = WeaponArmorPiercing()
weaponArmourPiercing.weapon = thisWeapon
weaponArmourPiercing.armorType = it
weaponArmourPiercing.piercingValue = (weaponDmgMap[it.id] ?: defaultArmourPiercing)?.toBigDecimal()
weaponArmourPiercing
}
return ArmourDamage(minDamage, maxDamage, minDamageValue, moraleDamage, armoursPiercing)
}
private fun getWeaponNameAndDescription(weaponData: List<RgdData>, modDictionary: Map<Int, String>, modFolderData: String): WeaponUiInfo {
val weaponUiInfo = weaponData.getRgdTableByName("ui_info")
val nameRef = weaponUiInfo?.getStringByName("screen_name_id")?.replace("$", "")
val name = nameRef?.let { try { modDictionary[it.toInt()] } catch (e: Exception) { null } }
val descriptionRefs = weaponUiInfo?.getRgdTableByName("help_text_list")
?.map{(it.value as String).replace("$", "")}
?.filter{it != "0" && it != "tables\\text_table.lua" && it != ""}
?.sortedBy { try { it.toInt() } catch (e: Exception) { 0 } }
val description = try {
descriptionRefs?.map { try { modDictionary[it.toInt()] } catch (e: Exception) { "" } }?.joinToString ( "\n" )
} catch(e:Exception) {
log.warn("Error parsing ui description", e)
null
}
val icon = try {
val iconPath = weaponUiInfo?.getStringByName("icon_name")
?.replace("/", File.separator)
val tgaIconPath = iconPath?.let {
val modIcon = modAttribPathService.getIconPath(modFolderData, it)
if(Path.of(modIcon).exists()) modIcon else
modAttribPathService.getIconPath(modAttribPathService.pathToWanilaData, it)
}
tgaIconPath?.let { iconsService.convertTgaToJpegImage(iconPath, it) }
} catch (e: Exception) {
log.error("Error parsing ui icon path", e)
null
}
val haveUpgradeButton = weaponUiInfo?.getBooleanByName("no_button")?.let { !it } ?: false
return WeaponUiInfo(name, description, icon, haveUpgradeButton)
}
}