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, ) data class WeaponUiInfo( val name: String?, val description: String?, val iconPath: String?, val haveEquipButton: Boolean ) fun extractToWeaponEntity(weaponFileName: String, weaponData: List, modId: Long, modFolderData: String, modDictionary: Map): 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): 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, armorTypes: Set, 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 = armourDamage.getRgdTableByName("armour_piercing_types")!!.mapNotNull { armour_piercing -> if (armour_piercing.name.contains("entry")) { val entry = armour_piercing.value as List 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, modDictionary: Map, 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) } }