From b0081aae16554d414f95770545f3da4e2b4c0eeb Mon Sep 17 00:00:00 2001 From: anibus Date: Sat, 14 Mar 2026 15:04:21 +0300 Subject: [PATCH] - Add death explosions info - Add mob bonus info - Reworked abilities, add child objects - Add unit morale break behaviour --- src/main/kotlin/com/dowstats/Metadata.kt | 31 +++-- .../controllers/ModVersionsController.kt | 2 +- .../com/dowstats/data/dto/AreaEffect.kt | 2 - .../controllers/AbilityArmorPiercingDto.kt | 8 -- ...rmorPiercingDto.kt => ArmorPiercingDto.kt} | 2 +- .../data/dto/controllers/DeathExplosionDto.kt | 17 +++ .../data/dto/controllers/RequirementDto.kt | 15 +++ .../data/dto/controllers/SergeantDto.kt | 2 + .../data/dto/controllers/UnitFullDto.kt | 3 + .../data/dto/controllers/WeaponDto.kt | 2 +- .../dto/controllers/ability/AbilityDto.kt | 27 ++++- .../controllers/building/BuildingFullDto.kt | 1 + .../dowstats/data/entities/ModifiersBase.kt | 2 - .../dowstats/data/entities/ability/Ability.kt | 10 +- .../entities/ability/AbilityEnvironment.kt | 74 ++++++++++++ .../entities/ability/AbilityRequirements.kt | 1 + .../data/entities/building/Building.kt | 13 +- .../entities/deathexplosion/DeathExplosion.kt | 48 ++++++++ .../DeathExplosionArmorPiercing.kt | 28 +++++ .../deathexplosion/DeathExplosionModifiers.kt | 19 +++ .../dowstats/data/entities/sergant/Sergant.kt | 12 +- .../dowstats/data/entities/unit/DowUnit.kt | 17 ++- .../entities/unit/UnitMoraleBrakeModifiers.kt | 19 +++ .../entities/weapon/WeaponArmorPiercing.kt | 4 +- .../AbilityEnvironmentRepository.kt | 15 +++ .../data/repositories/AbilityRepository.kt | 2 + .../data/repositories/UnitRepository.kt | 3 + .../service/datamaps/AbilityService.kt | 55 +++++++-- .../datamaps/DowBuildingMappingService.kt | 6 +- .../datamaps/RequirementsMappingComponent.kt | 112 +++++++++++++++--- .../ModStorageIntegrationService.kt | 4 +- .../AbilityEnvironmentRgdExtractService.kt | 90 ++++++++++++++ .../service/w40k/AbilityRgdExtractService.kt | 6 +- .../w40k/BuildingAddonRgdExtractService.kt | 2 +- .../service/w40k/BuildingRgdExtractService.kt | 31 ++--- .../service/w40k/CommonParseRgdService.kt | 35 +++++- .../w40k/DeathExplosionRgdExtractService.kt | 93 +++++++++++++++ .../service/w40k/ModAttribPathService.kt | 3 + .../dowstats/service/w40k/ModParserService.kt | 77 ++++++++---- .../service/w40k/ResearchRgdExtractService.kt | 2 +- .../service/w40k/SergantRgdExtractService.kt | 28 ++--- .../service/w40k/UnitRgdExtractService.kt | 53 +++++---- .../service/w40k/WeaponRgdExtractService.kt | 2 +- .../procedures/delete_mod_data_procedure.sql | 10 ++ .../schema/ability_environment_abilities.json | 66 +++++++++++ .../ability_environment_death_explosion.json | 66 +++++++++++ .../db/0.0.5/schema/ability_environments.json | 109 +++++++++++++++++ .../schema/building_death_explosion.json | 66 +++++++++++ .../resources/db/0.0.5/schema/buildings.json | 25 ++++ .../death_explosion_armors_piercing.json | 76 ++++++++++++ .../schema/death_explosion_modifiers.json | 89 ++++++++++++++ .../db/0.0.5/schema/death_explosions.json | 81 +++++++++++++ .../schema/sergeant_death_explosion.json | 66 +++++++++++ .../resources/db/0.0.5/schema/sergeants.json | 25 ++++ .../db/0.0.5/schema/unit_death_explosion.json | 66 +++++++++++ .../schema/unit_morale_break_modifiers.json | 84 +++++++++++++ src/main/resources/db/0.0.5/schema/units.json | 25 ++++ src/main/resources/db/changelog-master.json | 56 +++++++++ 58 files changed, 1737 insertions(+), 151 deletions(-) delete mode 100644 src/main/kotlin/com/dowstats/data/dto/controllers/AbilityArmorPiercingDto.kt rename src/main/kotlin/com/dowstats/data/dto/controllers/{WeaponArmorPiercingDto.kt => ArmorPiercingDto.kt} (80%) create mode 100644 src/main/kotlin/com/dowstats/data/dto/controllers/DeathExplosionDto.kt create mode 100644 src/main/kotlin/com/dowstats/data/entities/ability/AbilityEnvironment.kt create mode 100644 src/main/kotlin/com/dowstats/data/entities/deathexplosion/DeathExplosion.kt create mode 100644 src/main/kotlin/com/dowstats/data/entities/deathexplosion/DeathExplosionArmorPiercing.kt create mode 100644 src/main/kotlin/com/dowstats/data/entities/deathexplosion/DeathExplosionModifiers.kt create mode 100644 src/main/kotlin/com/dowstats/data/entities/unit/UnitMoraleBrakeModifiers.kt create mode 100644 src/main/kotlin/com/dowstats/data/repositories/AbilityEnvironmentRepository.kt create mode 100644 src/main/kotlin/com/dowstats/service/w40k/AbilityEnvironmentRgdExtractService.kt create mode 100644 src/main/kotlin/com/dowstats/service/w40k/DeathExplosionRgdExtractService.kt create mode 100644 src/main/resources/db/0.0.5/procedures/delete_mod_data_procedure.sql create mode 100644 src/main/resources/db/0.0.5/schema/ability_environment_abilities.json create mode 100644 src/main/resources/db/0.0.5/schema/ability_environment_death_explosion.json create mode 100644 src/main/resources/db/0.0.5/schema/ability_environments.json create mode 100644 src/main/resources/db/0.0.5/schema/building_death_explosion.json create mode 100644 src/main/resources/db/0.0.5/schema/buildings.json create mode 100644 src/main/resources/db/0.0.5/schema/death_explosion_armors_piercing.json create mode 100644 src/main/resources/db/0.0.5/schema/death_explosion_modifiers.json create mode 100644 src/main/resources/db/0.0.5/schema/death_explosions.json create mode 100644 src/main/resources/db/0.0.5/schema/sergeant_death_explosion.json create mode 100644 src/main/resources/db/0.0.5/schema/sergeants.json create mode 100644 src/main/resources/db/0.0.5/schema/unit_death_explosion.json create mode 100644 src/main/resources/db/0.0.5/schema/unit_morale_break_modifiers.json create mode 100644 src/main/resources/db/0.0.5/schema/units.json diff --git a/src/main/kotlin/com/dowstats/Metadata.kt b/src/main/kotlin/com/dowstats/Metadata.kt index 712a410..8654f13 100644 --- a/src/main/kotlin/com/dowstats/Metadata.kt +++ b/src/main/kotlin/com/dowstats/Metadata.kt @@ -5,18 +5,25 @@ object Metadata { const val USER_ROLE = "USER" object Requirements { - val REFERENCE_REQUIREMENT_NONE = "requirements\\required_none.lua" - val REFERENCE_REQUIREMENT_POP = "requirements\\required_total_pop.lua" - val REFERENCE_REQUIREMENT_ADDON = "requirements\\local_required_addon.lua" - val REFERENCE_GLOBAL_REQUIREMENT_ADDON = "requirements\\global_required_addon.lua" - val REFERENCE_REQUIREMENT_STRUCTURE_EITHER = "requirements\\required_structure_either.lua" - val REFERENCE_REQUIREMENT_STRUCTURE = "requirements\\required_structure.lua" - val REFERENCE_REQUIREMENT_RESEARCH = "requirements\\required_research.lua" - val REFERENCE_REQUIREMENT_OWNERSHIP = "requirements\\required_ownership.lua" - val REFERENCE_REQUIREMENT_CAP = "requirements\\required_cap.lua" - val REFERENCE_REQUIREMENT_SQUAD_CAP = "requirements\\required_squad_cap.lua" - val REFERENCE_REQUIREMENT_CUM_SQUAD_CAP = "requirements\\required_cumulative_squad_cap.lua" - val REFERENCE_REQUIREMENT_STRUCTURE_RATIO = "requirements\\required_structure_ratio.lua" + val REFERENCE_REQUIREMENT_NONE = "required_none" + val REFERENCE_REQUIREMENT_MOB_BONUS = "required_mobvalue" + val REFERENCE_REQUIREMENT_STRUCTURE_EXCLUSIVE = "required_structure_exclusive" + val REFERENCE_LOCAL_REQUIRED_ADDON_EXCLUSIVE = "local_required_addon_exclusive" + val REFERENCE_REQUIREMENT_SQUAD = "required_squad" + val REFERENCE_REQUIRED_RESEARCH_EITHER = "required_research_either" + val REFERENCE_REQUIREMENT_POP = "required_total_pop" + val REFERENCE_REQUIREMENT_ADDON = "local_required_addon" + val REFERENCE_GLOBAL_REQUIREMENT_ADDON = "global_required_addon" + val REFERENCE_REQUIREMENT_STRUCTURE_EITHER = "required_structure_either" + val REFERENCE_REQUIREMENT_STRUCTURE = "required_structure" + val REFERENCE_REQUIREMENT_RESEARCH = "required_research" + val REFERENCE_REQUIREMENT_OWNERSHIP = "required_ownership" + val REFERENCE_REQUIREMENT_STRUCTURE_RATIO = "required_structure_ratio" + + // выводится в юнита + val REFERENCE_REQUIREMENT_CAP = "required_cap" + val REFERENCE_REQUIREMENT_SQUAD_CAP = "required_squad_cap" + val REFERENCE_REQUIREMENT_CUM_SQUAD_CAP = "required_cumulative_squad_cap" } } \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/controllers/ModVersionsController.kt b/src/main/kotlin/com/dowstats/controllers/ModVersionsController.kt index 2feb871..88b7b94 100644 --- a/src/main/kotlin/com/dowstats/controllers/ModVersionsController.kt +++ b/src/main/kotlin/com/dowstats/controllers/ModVersionsController.kt @@ -19,7 +19,7 @@ class ModVersionsController @Autowired constructor( ) { @GetMapping - fun getModVersions(req: HttpServletRequest): List { + fun getModVersions(): List { return modRepository.findAll().toList() } diff --git a/src/main/kotlin/com/dowstats/data/dto/AreaEffect.kt b/src/main/kotlin/com/dowstats/data/dto/AreaEffect.kt index f370e05..9c2fef4 100644 --- a/src/main/kotlin/com/dowstats/data/dto/AreaEffect.kt +++ b/src/main/kotlin/com/dowstats/data/dto/AreaEffect.kt @@ -1,7 +1,5 @@ package com.dowstats.data.dto -import com.dowstats.data.entities.weapon.WeaponModifiers - data class AreaEffect( val minDamage: Double, val maxDamage: Double, diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/AbilityArmorPiercingDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/AbilityArmorPiercingDto.kt deleted file mode 100644 index 9602750..0000000 --- a/src/main/kotlin/com/dowstats/data/dto/controllers/AbilityArmorPiercingDto.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.dowstats.data.dto.controllers - -import java.math.BigDecimal - -data class AbilityArmorPiercingDto( - val armorType: ArmorTypeDto?, - val piercingValue: BigDecimal, -) diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/WeaponArmorPiercingDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/ArmorPiercingDto.kt similarity index 80% rename from src/main/kotlin/com/dowstats/data/dto/controllers/WeaponArmorPiercingDto.kt rename to src/main/kotlin/com/dowstats/data/dto/controllers/ArmorPiercingDto.kt index 9d129b9..4a39f7a 100644 --- a/src/main/kotlin/com/dowstats/data/dto/controllers/WeaponArmorPiercingDto.kt +++ b/src/main/kotlin/com/dowstats/data/dto/controllers/ArmorPiercingDto.kt @@ -2,7 +2,7 @@ package com.dowstats.data.dto.controllers import java.math.BigDecimal -data class WeaponArmorPiercingDto( +data class ArmorPiercingDto( val armorType: ArmorTypeDto?, val piercingValue: BigDecimal, ) diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/DeathExplosionDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/DeathExplosionDto.kt new file mode 100644 index 0000000..2f3e34d --- /dev/null +++ b/src/main/kotlin/com/dowstats/data/dto/controllers/DeathExplosionDto.kt @@ -0,0 +1,17 @@ +package com.dowstats.data.dto.controllers + +data class DeathExplosionDto( + val id: Long?, + var globalChance: Double?, + var chance: Double?, + val minDamage: Double?, + val maxDamage: Double?, + val minDamageValue: Double?, + val moraleDamage: Double?, + val damageRadius: Double?, + val throwForceMin: Double?, + val throwForceMax: Double?, + val modId: Long?, + val modifiers: List, + val armorPiercing: List, +) diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/RequirementDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/RequirementDto.kt index 2703c5d..f92b458 100644 --- a/src/main/kotlin/com/dowstats/data/dto/controllers/RequirementDto.kt +++ b/src/main/kotlin/com/dowstats/data/dto/controllers/RequirementDto.kt @@ -8,10 +8,15 @@ data class RequirementDto ( val requirementBuildings: Set, val requirementBuildingsEither: Set, val requirementResearches: Set, + val requirementSquads: Set, + val requirementResearchesEither: Set, val requireAddon: BuildingAddonShortDto?, val requirementsGlobalAddons: Set?, val requiredTotalPop: Int?, val limitByBuilding: RequirementLimitByBuildingDto?, + val mobBonus: RequirementMobBonusDto?, + val requirementStructureExclusive: BuildingShortDto?, + val requirementAddonExclusive: BuildingAddonShortDto?, val requiredOwnership: Set, val replaceWhenDone: Boolean = false, ) @@ -21,7 +26,17 @@ data class RequirementResearchDto( val researchMustNotBeComplete: Boolean, ) +data class RequirementSquadsDto( + val squad: EntityCompressDto, + val count: Int, +) + data class RequirementLimitByBuildingDto( val building: BuildingShortDto, val limit: Int, +) + +data class RequirementMobBonusDto( + val mobvalueRequired: Double, + val proximityRequired: Int, ) \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/SergeantDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/SergeantDto.kt index 709e55c..e37f9eb 100644 --- a/src/main/kotlin/com/dowstats/data/dto/controllers/SergeantDto.kt +++ b/src/main/kotlin/com/dowstats/data/dto/controllers/SergeantDto.kt @@ -20,6 +20,7 @@ data class SergeantDto( val faithIncome: Double?, val powerIncome: Double?, val requisitionIncome: Double?, + val mobValue: Double?, val health: Int?, val armour: Double?, val healthRegeneration: Double?, @@ -31,6 +32,7 @@ data class SergeantDto( val sightRadius: Int?, val detectRadius: Int?, val icon: String?, + val deathExplosions: Set, val weapons: List?, val abilities: Set?, val affectedResearches: Set, diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/UnitFullDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/UnitFullDto.kt index bb10e65..10d08b4 100644 --- a/src/main/kotlin/com/dowstats/data/dto/controllers/UnitFullDto.kt +++ b/src/main/kotlin/com/dowstats/data/dto/controllers/UnitFullDto.kt @@ -23,6 +23,7 @@ data class UnitFullDto( val faithIncome: Double?, val powerIncome: Double?, val requisitionIncome: Double?, + val mobValue: Double?, val capInfantry: Int?, val capSupport: Int?, val squadStartSize: Int?, @@ -52,6 +53,7 @@ data class UnitFullDto( val maxSergeants: Int?, val icon: String?, val modId: Long, + val deathExplosions: Set, val sergeants: Set?, val weapons: Set?, val abilities: Set?, @@ -59,6 +61,7 @@ data class UnitFullDto( val affectedResearches: Set, val affectedAddons: Set, val modifiers: List, + val moraleBrakeModifiers: List, var affectedData: AffectedDataDto, val requirements: RequirementDto?, val hotkey: String?, diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/WeaponDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/WeaponDto.kt index 5765723..55a8196 100644 --- a/src/main/kotlin/com/dowstats/data/dto/controllers/WeaponDto.kt +++ b/src/main/kotlin/com/dowstats/data/dto/controllers/WeaponDto.kt @@ -30,7 +30,7 @@ data class WeaponDto( val icon: String?, val showInReinforce: Boolean, val modId: Long?, - val weaponArmorPiercing: List, + val weaponArmorPiercing: List, val affectedResearches: Set, val affectedAddons: Set, val modifiers: List, diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/ability/AbilityDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/ability/AbilityDto.kt index e1286cf..a80ece8 100644 --- a/src/main/kotlin/com/dowstats/data/dto/controllers/ability/AbilityDto.kt +++ b/src/main/kotlin/com/dowstats/data/dto/controllers/ability/AbilityDto.kt @@ -1,11 +1,32 @@ package com.dowstats.data.dto.controllers.ability -import com.dowstats.data.dto.controllers.AbilityArmorPiercingDto import com.dowstats.data.dto.controllers.AffectedDataDto +import com.dowstats.data.dto.controllers.ArmorPiercingDto import com.dowstats.data.dto.controllers.ArmorTypeDto +import com.dowstats.data.dto.controllers.DeathExplosionDto import com.dowstats.data.dto.controllers.ModifierDto import com.dowstats.data.dto.controllers.RequirementDto +data class AbilityEnvironmentDto( + var id: Long, + var modId: Long, + var filename: String, + var name: String?, + var description: String?, + var icon: String?, + var health: Int?, + var armour: Double?, + var healthRegeneration: Double?, + var moveSpeed: Int?, + var sightRadius: Int?, + var detectRadius: Int?, + var lifetime: Double?, + val armorType: ArmorTypeDto?, + val armorType2: ArmorTypeDto?, + val abilities: Set, + val deathExplosions: Set, +) + data class AbilityDto( val id: Long?, val modId: Long?, @@ -26,7 +47,6 @@ data class AbilityDto( val rechargeTimerGlobal: Boolean?, val refreshTime: Double?, val durationTime: Double?, - val spawnedEntityName: String?, val radius: Double?, val minDamage: Double?, val minDamageValue: Double?, @@ -41,5 +61,6 @@ data class AbilityDto( val requirements: RequirementDto?, var affectedData: AffectedDataDto, val targetFilter: List, - val piercings: List + val piercings: List, + val abilityEnvironment: AbilityEnvironmentDto?, ) \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/data/dto/controllers/building/BuildingFullDto.kt b/src/main/kotlin/com/dowstats/data/dto/controllers/building/BuildingFullDto.kt index a79e027..0c6d7c7 100644 --- a/src/main/kotlin/com/dowstats/data/dto/controllers/building/BuildingFullDto.kt +++ b/src/main/kotlin/com/dowstats/data/dto/controllers/building/BuildingFullDto.kt @@ -30,6 +30,7 @@ data class BuildingFullDto( var repairMax: Int?, var icon: String?, var modId: Long?, + val deathExplosions: Set, var addons: List?, val abilities: Set?, var researches: List?, diff --git a/src/main/kotlin/com/dowstats/data/entities/ModifiersBase.kt b/src/main/kotlin/com/dowstats/data/entities/ModifiersBase.kt index cd49991..9c6b210 100644 --- a/src/main/kotlin/com/dowstats/data/entities/ModifiersBase.kt +++ b/src/main/kotlin/com/dowstats/data/entities/ModifiersBase.kt @@ -56,8 +56,6 @@ open class ModifiersBase { this.probabilityOfApplying = rgdData.getDoubleByName("probability_of_applying") return this } - } - } diff --git a/src/main/kotlin/com/dowstats/data/entities/ability/Ability.kt b/src/main/kotlin/com/dowstats/data/entities/ability/Ability.kt index 07ab554..368aacc 100644 --- a/src/main/kotlin/com/dowstats/data/entities/ability/Ability.kt +++ b/src/main/kotlin/com/dowstats/data/entities/ability/Ability.kt @@ -1,12 +1,13 @@ package com.dowstats.data.entities.ability -import com.dowstats.data.dto.controllers.AbilityArmorPiercingDto import com.dowstats.data.dto.controllers.AffectedDataDto +import com.dowstats.data.dto.controllers.ArmorPiercingDto import com.dowstats.data.dto.controllers.EntityCompressDtoObject.compressDto import com.dowstats.data.dto.controllers.RequirementDto import com.dowstats.data.dto.controllers.SergeantUnitShortDtoObject.toShortDtoSet import com.dowstats.data.dto.controllers.WeaponUnitShortDtoObject.toShortDtoSet import com.dowstats.data.dto.controllers.ability.AbilityDto +import com.dowstats.data.dto.controllers.ability.AbilityEnvironmentDto import com.dowstats.data.dto.controllers.ability.AbilityShortDto import com.dowstats.data.entities.Activation import com.dowstats.data.entities.AreaEffect @@ -24,7 +25,6 @@ import java.math.BigDecimal @Table(name = "abilities") class Ability { - @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long? = null @@ -120,7 +120,7 @@ class Ability { fun toShortDto() = AbilityShortDto(id, name, filename, icon, uiIndexHint, activation?.name) - fun toDto(requirements: RequirementDto?, childAbility: AbilityDto?): AbilityDto = AbilityDto( + fun toDto(requirements: RequirementDto?, childAbility: AbilityDto?, abilityEnvironmentDto: AbilityEnvironmentDto?): AbilityDto = AbilityDto( id = id, modId = modId, filename = filename, @@ -140,7 +140,6 @@ class Ability { rechargeTimerGlobal = rechargeTimerGlobal, refreshTime = refreshTime, durationTime = durationTime, - spawnedEntityName = spawnedEntityName, radius = radius, minDamage = minDamage, minDamageValue = minDamageValue, @@ -160,7 +159,8 @@ class Ability { affectedOnWeapons.toShortDtoSet(), ), targetFilter = abilityTargetFilters.map { it.toDto() }, - piercings = abilityPiercings.map { AbilityArmorPiercingDto(it.armorType?.toDto(), it.piercingValue ?: BigDecimal.ZERO) } + piercings = abilityPiercings.map { ArmorPiercingDto(it.armorType?.toDto(), it.piercingValue ?: BigDecimal.ZERO) }, + abilityEnvironmentDto, ) } diff --git a/src/main/kotlin/com/dowstats/data/entities/ability/AbilityEnvironment.kt b/src/main/kotlin/com/dowstats/data/entities/ability/AbilityEnvironment.kt new file mode 100644 index 0000000..bf0b96c --- /dev/null +++ b/src/main/kotlin/com/dowstats/data/entities/ability/AbilityEnvironment.kt @@ -0,0 +1,74 @@ +package com.dowstats.data.entities.ability + +import com.dowstats.data.dto.controllers.ability.AbilityEnvironmentDto +import com.dowstats.data.entities.ArmorType +import com.dowstats.data.entities.deathexplosion.DeathExplosion +import jakarta.persistence.* + + +@Entity +@Table(name = "ability_environments") +class AbilityEnvironment { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + var id: Long? = null + + var modId: Long? = null + var filename: String? = null + var name: String? = null + + var description: String? = null + + var icon: String? = null + + var health: Int? = null + var armour: Double? = null + var healthRegeneration: Double? = null + + var moveSpeed: Int? = null + var sightRadius: Int? = null + var detectRadius: Int? = null + + var lifetime: Double? = null + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "armour_type_id") + var armorType: ArmorType? = null + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "armour_type_2_id") + var armorType2: ArmorType? = null + + @ManyToMany(cascade = [CascadeType.ALL]) + @JoinTable(name = "ability_environment_abilities", + joinColumns = [JoinColumn(name = "ability_environment_id")], + inverseJoinColumns = [JoinColumn(name = "ability_id")]) + var abilities: MutableSet = mutableSetOf() + + @OneToMany(cascade = [CascadeType.ALL]) + @JoinTable(name = "ability_environment_death_explosion", + joinColumns = [JoinColumn(name = "ability_environment_id")], + inverseJoinColumns = [JoinColumn(name = "death_explosion_id")]) + var deathExplosions: MutableSet = mutableSetOf() + + fun toDto(): AbilityEnvironmentDto = AbilityEnvironmentDto( + id!!, + modId!!, + filename!!, + name, + description, + icon, + health, + armour, + healthRegeneration, + moveSpeed, + sightRadius, + detectRadius, + lifetime, + armorType?.toDto(), + armorType2?.toDto(), + abilities.map { it.toShortDto() }.toSet(), + deathExplosions.filter { (it.chance ?: 0.0) > 0.0 }.map { it.toDto(modId!!) }.toSet(), + ) +} diff --git a/src/main/kotlin/com/dowstats/data/entities/ability/AbilityRequirements.kt b/src/main/kotlin/com/dowstats/data/entities/ability/AbilityRequirements.kt index e81514c..59b4712 100644 --- a/src/main/kotlin/com/dowstats/data/entities/ability/AbilityRequirements.kt +++ b/src/main/kotlin/com/dowstats/data/entities/ability/AbilityRequirements.kt @@ -12,4 +12,5 @@ class AbilityRequirements : RequirementBase() { @JoinColumn(name = "ability_id", nullable = false) @JsonIgnore var ability: Ability? = null + } diff --git a/src/main/kotlin/com/dowstats/data/entities/building/Building.kt b/src/main/kotlin/com/dowstats/data/entities/building/Building.kt index b838ef2..c3828b6 100644 --- a/src/main/kotlin/com/dowstats/data/entities/building/Building.kt +++ b/src/main/kotlin/com/dowstats/data/entities/building/Building.kt @@ -18,6 +18,7 @@ import com.dowstats.data.entities.sergant.Sergeant import com.dowstats.data.entities.weapon.Weapon import com.dowstats.data.entities.weapon.Weapon.HardpointPosition import com.dowstats.data.entities.addon.BuildingAddon +import com.dowstats.data.entities.deathexplosion.DeathExplosion import com.dowstats.data.entities.research.Research import jakarta.persistence.* @@ -67,6 +68,7 @@ class Building { var faithIncome: Double? = null var powerIncome: Double? = null var requisitionIncome: Double? = null + var buildingLimit: Int? = null @OneToMany(mappedBy = "building", cascade = [CascadeType.ALL]) var addons: MutableSet? = null @@ -77,6 +79,12 @@ class Building { @OneToMany(mappedBy = "building", cascade = [CascadeType.ALL]) var modifiers: MutableSet = mutableSetOf() + @OneToMany(cascade = [CascadeType.ALL]) + @JoinTable(name = "building_death_explosion", + joinColumns = [JoinColumn(name = "building_id")], + inverseJoinColumns = [JoinColumn(name = "death_explosion_id")]) + var deathExplosions: MutableSet = mutableSetOf() + @ManyToMany @JoinTable(name = "buildings_units", joinColumns = [JoinColumn(name = "building_id")], @@ -188,8 +196,9 @@ class Building { repairMax, icon, modId!!, - buildingAddons, - abilities.map { it.toShortDto() }.toSet(), + deathExplosions.map { it.toDto(modId!!) }.toSet(), + buildingAddons?.sortedBy { it.name }, + abilities.map { it.toShortDto() }.sortedBy { it.name }.toSet(), researches, modifiers.map { it.toDto() }, AffectedDataDto( diff --git a/src/main/kotlin/com/dowstats/data/entities/deathexplosion/DeathExplosion.kt b/src/main/kotlin/com/dowstats/data/entities/deathexplosion/DeathExplosion.kt new file mode 100644 index 0000000..c4fc921 --- /dev/null +++ b/src/main/kotlin/com/dowstats/data/entities/deathexplosion/DeathExplosion.kt @@ -0,0 +1,48 @@ +package com.dowstats.data.entities.deathexplosion + +import com.dowstats.data.dto.controllers.ArmorPiercingDto +import com.dowstats.data.dto.controllers.DeathExplosionDto +import jakarta.persistence.* +import java.math.BigDecimal + + +@Entity +@Table(name = "death_explosions") +class DeathExplosion { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + var id: Long? = null + var globalChance: Double? = null + var chance: Double? = null + var minDamage: Double? = null + var maxDamage: Double? = null + var minDamageValue: Double? = null + var moraleDamage: Double? = null + var radius: Double? = null + var throwForceMin: Double? = null + var throwForceMax: Double? = null + + + @OneToMany(mappedBy = "deathExplosion", cascade = [CascadeType.ALL]) + var explosionModifiers: MutableSet = mutableSetOf() + + @OneToMany(mappedBy="deathExplosion", cascade = [(CascadeType.ALL)]) + var explosionPiercings: MutableSet = mutableSetOf() + + fun toDto(modId: Long): DeathExplosionDto = DeathExplosionDto( + id!!, + globalChance, + chance, + minDamage, + maxDamage, + minDamageValue, + moraleDamage, + radius, + throwForceMin, + throwForceMax, + modId, + explosionModifiers.map { it.toDto() }, + explosionPiercings.map { ArmorPiercingDto(it.armorType?.toDto(), it.piercingValue ?: BigDecimal.ZERO) } + ) +} diff --git a/src/main/kotlin/com/dowstats/data/entities/deathexplosion/DeathExplosionArmorPiercing.kt b/src/main/kotlin/com/dowstats/data/entities/deathexplosion/DeathExplosionArmorPiercing.kt new file mode 100644 index 0000000..2d0f7d4 --- /dev/null +++ b/src/main/kotlin/com/dowstats/data/entities/deathexplosion/DeathExplosionArmorPiercing.kt @@ -0,0 +1,28 @@ +package com.dowstats.data.entities.deathexplosion + +import com.dowstats.data.entities.ArmorType +import com.fasterxml.jackson.annotation.JsonIgnore +import java.math.BigDecimal +import jakarta.persistence.* + + +@Entity +@Table(name = "death_explosion_armors_piercing") +class DeathExplosionArmorPiercing { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + var id: Long? = null + + @ManyToOne + @JsonIgnore + @JoinColumn(name = "death_explosion_id") + var deathExplosion: DeathExplosion? = null + + @ManyToOne + @JoinColumn(name = "armor_type_id") + var armorType: ArmorType? = null + + var piercingValue: BigDecimal? = null + +} diff --git a/src/main/kotlin/com/dowstats/data/entities/deathexplosion/DeathExplosionModifiers.kt b/src/main/kotlin/com/dowstats/data/entities/deathexplosion/DeathExplosionModifiers.kt new file mode 100644 index 0000000..bc8bee0 --- /dev/null +++ b/src/main/kotlin/com/dowstats/data/entities/deathexplosion/DeathExplosionModifiers.kt @@ -0,0 +1,19 @@ +package com.dowstats.data.entities.deathexplosion + +import com.dowstats.data.entities.ModifiersBase +import com.fasterxml.jackson.annotation.JsonIgnore +import jakarta.persistence.* + + +@Entity +@Table(name = "death_explosion_modifiers") +class DeathExplosionModifiers : ModifiersBase() { + + @ManyToOne + @JoinColumn(name = "death_explosion_id", nullable = false) + @JsonIgnore + var deathExplosion: DeathExplosion? = null + + var maxLifeTime: Double? = null + +} diff --git a/src/main/kotlin/com/dowstats/data/entities/sergant/Sergant.kt b/src/main/kotlin/com/dowstats/data/entities/sergant/Sergant.kt index d3a4685..a428f2f 100644 --- a/src/main/kotlin/com/dowstats/data/entities/sergant/Sergant.kt +++ b/src/main/kotlin/com/dowstats/data/entities/sergant/Sergant.kt @@ -12,6 +12,7 @@ import com.dowstats.data.entities.ability.Ability import com.dowstats.data.entities.weapon.Weapon.HardpointPosition import com.dowstats.data.entities.addon.BuildingAddon import com.dowstats.data.entities.building.Building +import com.dowstats.data.entities.deathexplosion.DeathExplosion import com.dowstats.data.entities.research.Research import com.dowstats.data.entities.unit.DowUnit import com.dowstats.data.entities.weapon.Weapon @@ -64,6 +65,7 @@ class Sergeant { var faithIncome: Double? = null var powerIncome: Double? = null var requisitionIncome: Double? = null + var mobValue: Double? = null var modId: Long? = null @@ -73,6 +75,12 @@ class Sergeant { @OneToMany(mappedBy = "sergeant", cascade = [CascadeType.ALL]) var weapons: MutableSet? = null + @OneToMany(cascade = [CascadeType.ALL]) + @JoinTable(name = "sergeant_death_explosion", + joinColumns = [JoinColumn(name = "sergeant_id")], + inverseJoinColumns = [JoinColumn(name = "death_explosion_id")]) + var deathExplosions: MutableSet = mutableSetOf() + @ManyToMany @JoinTable(name = "sergeant_abilities", joinColumns = [JoinColumn(name = "sergeant_id")], @@ -163,6 +171,7 @@ class Sergeant { faithIncome, powerIncome, requisitionIncome, + mobValue, health, armour, healthRegeneration, @@ -174,8 +183,9 @@ class Sergeant { sightRadius, detectRadius, icon, + deathExplosions.map { it.toDto(modId!!) }.toSet(), weapons.toList(), - abilities.sortedWith ( compareBy { it.activation?.id }.thenBy{ it.uiIndexHint.let { 0 - it } }).map { it.toShortDto() }.toSet(), + abilities.sortedWith ( compareBy { it.activation?.id }.thenBy{ it.uiIndexHint.let { 0 - it } }.thenBy{ it.name}).map { it.toShortDto() }.toSet(), affectedResearches.map { it.toResearchShortDto() }.toSet(), sergeantModifiers.map { it.toDto() }.sortedBy { it.target }, AffectedDataDto( diff --git a/src/main/kotlin/com/dowstats/data/entities/unit/DowUnit.kt b/src/main/kotlin/com/dowstats/data/entities/unit/DowUnit.kt index 05966b5..b1e1912 100644 --- a/src/main/kotlin/com/dowstats/data/entities/unit/DowUnit.kt +++ b/src/main/kotlin/com/dowstats/data/entities/unit/DowUnit.kt @@ -10,6 +10,7 @@ import com.dowstats.data.entities.ability.Ability import com.dowstats.data.entities.sergant.Sergeant import com.dowstats.data.entities.addon.BuildingAddon import com.dowstats.data.entities.building.Building +import com.dowstats.data.entities.deathexplosion.DeathExplosion import com.dowstats.data.entities.research.Research import com.dowstats.data.entities.research.ResearchModifiers import com.dowstats.data.entities.weapon.Weapon @@ -79,6 +80,7 @@ class DowUnit { var faithIncome: Double? = null var powerIncome: Double? = null var requisitionIncome: Double? = null + var mobValue: Double? = null var haveReinforceMenu: Boolean = false var uiIndexHint: Int = 0 var uiHotkeyName: String? = null @@ -91,12 +93,19 @@ class DowUnit { @OneToMany(mappedBy = "unit", cascade = [CascadeType.ALL]) var weapons: MutableSet? = null + @OneToMany(cascade = [CascadeType.ALL]) + @JoinTable(name = "unit_death_explosion", + joinColumns = [JoinColumn(name = "unit_id")], + inverseJoinColumns = [JoinColumn(name = "death_explosion_id")]) + var deathExplosions: MutableSet = mutableSetOf() + @ManyToMany @JoinTable(name = "unit_abilities", joinColumns = [JoinColumn(name = "unit_id")], inverseJoinColumns = [JoinColumn(name = "ability_id")]) var abilities: MutableSet = mutableSetOf() + @ManyToMany @JoinTable(name = "researches_affected_units", joinColumns = [JoinColumn(name = "unit_id")], @@ -161,6 +170,9 @@ class DowUnit { @OneToMany(mappedBy = "unit", cascade = [CascadeType.ALL]) var unitModifiers: MutableSet = mutableSetOf() + @OneToMany(mappedBy = "unit", cascade = [CascadeType.ALL]) + var unitMoraleBrakeModifiers: MutableSet = mutableSetOf() + @OneToMany(mappedBy = "unit", cascade = [CascadeType.ALL]) var unitRequirements: MutableSet = mutableSetOf() @@ -182,6 +194,7 @@ class DowUnit { faithIncome, powerIncome, requisitionIncome, + mobValue, capInfantry, capSupport, squadStartSize, @@ -211,13 +224,15 @@ class DowUnit { maxSergeants, icon, modId!!, + deathExplosions.map { it.toDto(modId!!) }.toSet(), sergeantsDtos, weapons, - abilities.sortedWith ( compareBy { it.activation?.id }.thenBy{ it.uiIndexHint.let { 0 - it } }).map { it.toShortDto() }.toSet(), + abilities.sortedWith ( compareBy { it.activation?.id }.thenBy{ it.uiIndexHint.let { 0 - it } }.thenBy{ it.name}.thenBy{ it.filename}).map { it.toShortDto() }.toSet(), haveReinforceMenu, affectedResearches.map { it.toResearchShortDto() }.toSet(), affectedAddons.map { it.toShortDto() }.toSet(), unitModifiers.map { it.toDto() }.sortedBy { it.target }, + unitMoraleBrakeModifiers.map { it.toDto() }.sortedBy { it.target }, AffectedDataDto( affectedOnUnits.map { it.compressDto() }.toSet(), affectedOnSergeants.toShortDtoSet(), diff --git a/src/main/kotlin/com/dowstats/data/entities/unit/UnitMoraleBrakeModifiers.kt b/src/main/kotlin/com/dowstats/data/entities/unit/UnitMoraleBrakeModifiers.kt new file mode 100644 index 0000000..f8a398c --- /dev/null +++ b/src/main/kotlin/com/dowstats/data/entities/unit/UnitMoraleBrakeModifiers.kt @@ -0,0 +1,19 @@ +package com.dowstats.data.entities.unit + +import com.dowstats.data.dto.controllers.ModifierDto +import com.dowstats.data.entities.ModifiersBase +import com.dowstats.data.entities.building.Building +import com.fasterxml.jackson.annotation.JsonIgnore +import jakarta.persistence.* + + +@Entity +@Table(name = "unit_morale_break_modifiers") +class UnitMoraleBrakeModifiers : ModifiersBase() { + + @ManyToOne + @JoinColumn(name = "unit_id", nullable = false) + @JsonIgnore + var unit: DowUnit? = null + +} diff --git a/src/main/kotlin/com/dowstats/data/entities/weapon/WeaponArmorPiercing.kt b/src/main/kotlin/com/dowstats/data/entities/weapon/WeaponArmorPiercing.kt index d419113..6c91a94 100644 --- a/src/main/kotlin/com/dowstats/data/entities/weapon/WeaponArmorPiercing.kt +++ b/src/main/kotlin/com/dowstats/data/entities/weapon/WeaponArmorPiercing.kt @@ -1,6 +1,6 @@ package com.dowstats.data.entities.weapon -import com.dowstats.data.dto.controllers.WeaponArmorPiercingDto +import com.dowstats.data.dto.controllers.ArmorPiercingDto import com.dowstats.data.entities.ArmorType import com.fasterxml.jackson.annotation.JsonIgnore import java.math.BigDecimal @@ -26,7 +26,7 @@ class WeaponArmorPiercing { var piercingValue: BigDecimal? = null - fun toDto() = WeaponArmorPiercingDto( + fun toDto() = ArmorPiercingDto( armorType?.toDto(), piercingValue?:BigDecimal.ZERO, ) diff --git a/src/main/kotlin/com/dowstats/data/repositories/AbilityEnvironmentRepository.kt b/src/main/kotlin/com/dowstats/data/repositories/AbilityEnvironmentRepository.kt new file mode 100644 index 0000000..5913ae2 --- /dev/null +++ b/src/main/kotlin/com/dowstats/data/repositories/AbilityEnvironmentRepository.kt @@ -0,0 +1,15 @@ +package com.dowstats.data.repositories + +import com.dowstats.data.entities.unit.DowUnit +import com.dowstats.data.entities.Race +import com.dowstats.data.entities.ability.Ability +import com.dowstats.data.entities.ability.AbilityEnvironment +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.* + +interface AbilityEnvironmentRepository : CrudRepository { + + fun findAllByModId(modId: Long): List + + fun deleteAllByModId(modId: Long) +} \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/data/repositories/AbilityRepository.kt b/src/main/kotlin/com/dowstats/data/repositories/AbilityRepository.kt index 8f5ce4e..92d6791 100644 --- a/src/main/kotlin/com/dowstats/data/repositories/AbilityRepository.kt +++ b/src/main/kotlin/com/dowstats/data/repositories/AbilityRepository.kt @@ -10,5 +10,7 @@ interface AbilityRepository : CrudRepository { fun findAllByModId(modId: Long): List + fun findFirstByModIdAndFilenameIn(modId: Long, fileNames: List): Ability + fun deleteAllByModId(modId: Long) } \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/data/repositories/UnitRepository.kt b/src/main/kotlin/com/dowstats/data/repositories/UnitRepository.kt index 506fab2..1b968bc 100644 --- a/src/main/kotlin/com/dowstats/data/repositories/UnitRepository.kt +++ b/src/main/kotlin/com/dowstats/data/repositories/UnitRepository.kt @@ -2,6 +2,7 @@ package com.dowstats.data.repositories import com.dowstats.data.entities.unit.DowUnit import com.dowstats.data.entities.Race +import com.dowstats.data.entities.addon.BuildingAddon import org.springframework.data.jpa.repository.Query import org.springframework.data.repository.* @@ -18,5 +19,7 @@ interface UnitRepository : CrudRepository { """) fun findByModIdAndRace(modId: Long, race: Race?): List + fun findFirstByModIdAndFilenameSquad(modId: Long, fileName: String): DowUnit? + fun deleteAllByModIdAndRaceId(modId: Long, raceId: String) } \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/service/datamaps/AbilityService.kt b/src/main/kotlin/com/dowstats/service/datamaps/AbilityService.kt index d11e8cd..8ea3f7d 100644 --- a/src/main/kotlin/com/dowstats/service/datamaps/AbilityService.kt +++ b/src/main/kotlin/com/dowstats/service/datamaps/AbilityService.kt @@ -2,8 +2,9 @@ package com.dowstats.service.datamaps import com.dowstats.data.dto.controllers.RequirementDto import com.dowstats.data.dto.controllers.ability.AbilityDto -import com.dowstats.data.dto.controllers.research.ResearchDto import com.dowstats.data.entities.ability.Ability +import com.dowstats.data.entities.ability.AbilityEnvironment +import com.dowstats.data.repositories.AbilityEnvironmentRepository import com.dowstats.data.repositories.AbilityRepository import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Service @@ -11,6 +12,7 @@ import org.springframework.stereotype.Service @Service class AbilityService @Autowired constructor( val abilityRepository: AbilityRepository, + val abilityEnvironmentRepository: AbilityEnvironmentRepository, val requirementsMappingComponent: RequirementsMappingComponent, ) { @@ -20,17 +22,52 @@ class AbilityService @Autowired constructor( .getRequirements(ability.abilityRequirements.toList() , modId) - if(ability.childAbilityName == null) return ability.toDto(requirements, null) else { - val allAbilities = abilityRepository.findAllByModId(modId) - return toDtoWithChild(requirements, allAbilities, ability) + val allAbilityEnvironments = abilityEnvironmentRepository.findAllByModId(modId) + + val spawnedAbilityEnvironment: AbilityEnvironment? = + getSpawnedAbilityEnvironment(allAbilityEnvironments, ability.spawnedEntityName) + + + if(ability.childAbilityName == null || ability.childAbilityName == "") return ability.toDto(requirements, null, spawnedAbilityEnvironment?.toDto()) else { + + return toDtoWithChild(requirements, modId,allAbilityEnvironments, ability) } } - fun toDtoWithChild(requirements: RequirementDto?, allAbilities: List, ability: Ability): AbilityDto = - if(ability.childAbilityName == null || ability.childAbilityName == "") ability.toDto(requirements, null) else { - ability.toDto(requirements, - toDtoWithChild(requirements, allAbilities, - allAbilities.first { it.filename?.replace(".rgd", "") == ability.childAbilityName }) + fun toDtoWithChild(requirements: RequirementDto?, + modId: Long, + allAbilityEnvironments: List, + ability: Ability): AbilityDto { + + val spawnedAbilityEnvironment: AbilityEnvironment? = + getSpawnedAbilityEnvironment(allAbilityEnvironments, ability.spawnedEntityName) + return if (ability.childAbilityName == null || ability.childAbilityName == "") + ability.toDto(requirements, null, spawnedAbilityEnvironment?.toDto()) + else { + val searchChild = ability.childAbilityName?.replace(".lua", "")?.replace("abilities\\", "")!! + ability.toDto( + requirements, + toDtoWithChild( + requirements, modId, allAbilityEnvironments, + abilityRepository.findFirstByModIdAndFilenameIn(modId, listOf(searchChild, searchChild + ".rgd") )), + spawnedAbilityEnvironment?.toDto() ) } + } + + private fun getSpawnedAbilityEnvironment(allAbilityEnvironments: List, spawnedEntityName: String?): AbilityEnvironment? { + + val spawnedObject = spawnedEntityName?.split("\\")?.last() + ?.replace(".lua", "") + ?.replace(".rgd", "") + + return spawnedObject?.let { + allAbilityEnvironments.firstOrNull { + it.filename?.split("\\")?.last() + ?.replace(".lua", "") + ?.replace(".rgd", "") == spawnedObject + } + } + } + } \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/service/datamaps/DowBuildingMappingService.kt b/src/main/kotlin/com/dowstats/service/datamaps/DowBuildingMappingService.kt index 434cfd8..6a876fd 100644 --- a/src/main/kotlin/com/dowstats/service/datamaps/DowBuildingMappingService.kt +++ b/src/main/kotlin/com/dowstats/service/datamaps/DowBuildingMappingService.kt @@ -36,11 +36,11 @@ class DowBuildingMappingService @Autowired constructor( val buildingAddons = building.addons?.sortedBy { it.uiIndexHint }?.map { addon -> - val replaceWhenDone = addon.addonRequirements?.find { it.reference == Requirements.REFERENCE_REQUIREMENT_ADDON }?.replaceWhenDone ?: false + val replaceWhenDone = addon.addonRequirements?.find { it.reference ==Requirements.REFERENCE_REQUIREMENT_ADDON } + ?.replaceWhenDone ?: false val requirement = requirementsMappingComponent .getRequirements(addon.addonRequirements?.toList() ?: emptyList(), - building.modId!!, - building.addons?.toList() ?: emptyList() + building.modId!! ) addon.toDto(requirement?.copy( diff --git a/src/main/kotlin/com/dowstats/service/datamaps/RequirementsMappingComponent.kt b/src/main/kotlin/com/dowstats/service/datamaps/RequirementsMappingComponent.kt index 02375a6..4da3df4 100644 --- a/src/main/kotlin/com/dowstats/service/datamaps/RequirementsMappingComponent.kt +++ b/src/main/kotlin/com/dowstats/service/datamaps/RequirementsMappingComponent.kt @@ -1,37 +1,41 @@ package com.dowstats.service.datamaps import com.dowstats.Metadata.Requirements +import com.dowstats.data.dto.controllers.EntityCompressDtoObject.compressDto import com.dowstats.data.dto.controllers.RequirementDto import com.dowstats.data.dto.controllers.RequirementLimitByBuildingDto +import com.dowstats.data.dto.controllers.RequirementMobBonusDto import com.dowstats.data.dto.controllers.RequirementResearchDto +import com.dowstats.data.dto.controllers.RequirementSquadsDto import com.dowstats.data.entities.RequirementBase -import com.dowstats.data.entities.addon.BuildingAddon import com.dowstats.data.repositories.AddonRepository import com.dowstats.data.repositories.BuildingRepository import com.dowstats.data.repositories.ResearchRepository +import com.dowstats.data.repositories.UnitRepository import com.dowstats.service.datamaps.CommonMapping.toBuildingShortDto import org.springframework.stereotype.Component @Component class RequirementsMappingComponent( val addonRepository: AddonRepository, + val unitRepository: UnitRepository, val buildingRepository: BuildingRepository, val researchRepository: ResearchRepository, ) { - fun getRequirements(requirements : List, modId: Long, thisBuildingAddons: List = emptyList()) : RequirementDto? { + fun getRequirements(requirements : List, modId: Long) : RequirementDto? { val requireCap = - requirements.find { it.reference == Requirements.REFERENCE_REQUIREMENT_POP }?.value?.toDouble() + requirements.find { it.reference?.getPureReference() == Requirements.REFERENCE_REQUIREMENT_POP }?.value?.toDouble() ?.toInt()?.let { if(it == 0) null else it } val requiredOwnership = - requirements.filter { it.reference == Requirements.REFERENCE_REQUIREMENT_OWNERSHIP } + requirements.filter { it.reference?.getPureReference() == Requirements.REFERENCE_REQUIREMENT_OWNERSHIP } .mapNotNull { rro -> rro.value }.toSet() val requirementAddon = - requirements.find { it.reference == Requirements.REFERENCE_REQUIREMENT_ADDON }?.value?.let { + requirements.find { it.reference?.getPureReference() == Requirements.REFERENCE_REQUIREMENT_ADDON }?.value?.let { val addonFileName = it.split("\\").last().replace(".lua", ".rgd") addonFileName.let { addonRepository.findFirstByModIdAndFilename( @@ -41,8 +45,24 @@ class RequirementsMappingComponent( } } + val requirementSquads = + requirements.filter { it.reference?.getPureReference() == Requirements.REFERENCE_REQUIREMENT_SQUAD}.mapNotNull {req -> + val unitName = req.value?.split(";")?.first()?.split("\\")?.last()?.replace(".lua", ".rgd") + unitName?.let { + unitRepository.findFirstByModIdAndFilenameSquad( + modId, + it.split("\\").last().replace(".lua", ".rgd") + )?.compressDto()?.let { + RequirementSquadsDto( + it, + req.value?.split(";")?.last()?.toInt() ?: 1 + ) + } + } + }.toSet() + val requirementAddonGlobal = - requirements.filter { it.reference == Requirements.REFERENCE_GLOBAL_REQUIREMENT_ADDON } + requirements.filter { it.reference?.getPureReference() == Requirements.REFERENCE_GLOBAL_REQUIREMENT_ADDON } .mapNotNull { rgra -> val addonFileName = rgra.value?.split("\\")?.last()?.replace(".lua", ".rgd") addonFileName?.let { @@ -54,14 +74,14 @@ class RequirementsMappingComponent( }.toSet() val requirementBuildings = - requirements.filter { it.reference == Requirements.REFERENCE_REQUIREMENT_STRUCTURE }.mapNotNull { + requirements.filter { it.reference?.getPureReference() == Requirements.REFERENCE_REQUIREMENT_STRUCTURE }.mapNotNull { val buildingFileName = it.value?.split("\\")?.last()?.replace(".lua", ".rgd") buildingFileName?.let { buildingRepository.findByModIdAndFilename(modId, buildingFileName) } }.distinct().toBuildingShortDto().toSet() - val limitByBuilding = requirements.find { it.reference == Requirements.REFERENCE_REQUIREMENT_STRUCTURE_RATIO }?.let { + val limitByBuilding = requirements.find { it.reference?.getPureReference() == Requirements.REFERENCE_REQUIREMENT_STRUCTURE_RATIO }?.let { val buildingFileName = it.value?.split(";")?.first()?.replace(".lua", ".rgd") val limitPerBuilding = it.value?.split(";")?.last()?.toInt() ?: 0 @@ -76,7 +96,7 @@ class RequirementsMappingComponent( } val requirementBuildingsEither = - requirements.find { it.reference == Requirements.REFERENCE_REQUIREMENT_STRUCTURE_EITHER }?.let { + requirements.find { it.reference?.getPureReference() == Requirements.REFERENCE_REQUIREMENT_STRUCTURE_EITHER }?.let { it.value?.split(";")?.mapNotNull { bPath -> buildingRepository.findByModIdAndFilename( modId, @@ -86,7 +106,7 @@ class RequirementsMappingComponent( }?.toBuildingShortDto()?.toSet() ?: emptySet() val requirementResearches = - requirements.filter { it.reference == Requirements.REFERENCE_REQUIREMENT_RESEARCH }.mapNotNull { + requirements.filter { it.reference?.getPureReference() == Requirements.REFERENCE_REQUIREMENT_RESEARCH }.mapNotNull { val research = it.value?.split(";")?.first() val mustNotBeCompleteStr = it.value?.split(";")?.last() val researchFileName = research?.split("\\")?.last()?.replace(".lua", ".rgd")?.let { @@ -100,23 +120,87 @@ class RequirementsMappingComponent( } }.toSet() - return if (requireCap != null || - requirementAddon != null || - requirementBuildings.isNotEmpty() || + val requirementResearchEither = + requirements.filter { it.reference?.getPureReference() == Requirements.REFERENCE_REQUIRED_RESEARCH_EITHER }.mapNotNull { + it.value?.split(";")?.mapNotNull { r -> + val researchFileName = r.split("\\").last().replace(".lua", ".rgd").let {resFile -> + if(resFile.endsWith(".rgd")) resFile else "$resFile.rgd" + } + + researchRepository.findFirstByModIdAndFilename(modId, researchFileName)?.toResearchShortDto()?.let { + RequirementResearchDto(it, false) + } + } + }.flatten().toSet() + + + val requirementMobBonus = + requirements.find { it.reference?.getPureReference() == Requirements.REFERENCE_REQUIREMENT_MOB_BONUS }?.let { + RequirementMobBonusDto( + it.value?.split(";")?.first()?.toDouble() ?: 0.0, + runCatching { + it.value?.split(";")?.last()?.toInt() + }.getOrNull() ?: 0 + ) + + } + + val requirementStructureExclusive = + requirements.find { it.reference?.getPureReference() == Requirements.REFERENCE_REQUIREMENT_STRUCTURE_EXCLUSIVE }?.let { + it.value?.let { bPath -> + buildingRepository.findByModIdAndFilename( + modId, + bPath.split("\\").last().replace(".lua", ".rgd") + ) + } + }?.toBuildingShortDto() + + val requirementAddonExclusive = + requirements.find { it.reference?.getPureReference() == Requirements.REFERENCE_LOCAL_REQUIRED_ADDON_EXCLUSIVE }?.let { + it.value?.let { addonPath -> + addonRepository.findFirstByModIdAndFilename( + modId, + addonPath.split("\\").last().replace(".lua", ".rgd") + ) + } + }?.toShortDto() + + return if (requirementBuildings.isNotEmpty() || requirementBuildingsEither.isNotEmpty() || requirementResearches.isNotEmpty() || - requirementAddonGlobal.isNotEmpty() + requirementSquads.isNotEmpty() || + requirementResearchEither.isNotEmpty() || + requirementAddon != null || + requirementAddonGlobal.isNotEmpty() || + requireCap != null || + limitByBuilding != null || + requirementMobBonus != null || + requirementStructureExclusive != null || + requirementAddonExclusive != null || + requiredOwnership.isNotEmpty() ) { RequirementDto( requirementBuildings, requirementBuildingsEither, requirementResearches, + requirementSquads, + requirementResearchEither, requirementAddon, requirementAddonGlobal, requireCap, limitByBuilding, + requirementMobBonus, + requirementStructureExclusive, + requirementAddonExclusive, requiredOwnership ) } else null } + + fun String.getPureReference(): String = + this.split("\\").last() + .replace(".lua", "") + .replace(".rgd", "") + + } \ No newline at end of file diff --git a/src/main/kotlin/com/dowstats/service/integrations/ModStorageIntegrationService.kt b/src/main/kotlin/com/dowstats/service/integrations/ModStorageIntegrationService.kt index eaa4cf8..d142e50 100644 --- a/src/main/kotlin/com/dowstats/service/integrations/ModStorageIntegrationService.kt +++ b/src/main/kotlin/com/dowstats/service/integrations/ModStorageIntegrationService.kt @@ -39,7 +39,7 @@ class ModStorageIntegrationService( fun requestAvailableMods() { log.info("Requesting available mods") - val urlString = "http://crosspick.ru/dow_stats_client/dow_stats_balance_mod/mods.txt" + val urlString = "http://89.108.83.108/dow_stats_client/dow_stats_balance_mod/mods.txt" val connection = URL(urlString).openConnection() connection.setRequestProperty("X-Key", modStorageConfig.key) val inputStream: InputStream = connection.getInputStream() @@ -183,7 +183,7 @@ class ModStorageIntegrationService( private fun downloadAndExtractMod(modTechName: String, version: String) { log.info("Downloading mod $modTechName") - val urlString = "http://crosspick.ru/dow_stats_client/dow_stats_balance_mod/$modTechName.zip" + val urlString = "http://89.108.83.108/dow_stats_client/dow_stats_balance_mod/$modTechName.zip" val connection = URL(urlString).openConnection() connection.setRequestProperty("X-Key", modStorageConfig.key) val inputStream: InputStream = connection.getInputStream() diff --git a/src/main/kotlin/com/dowstats/service/w40k/AbilityEnvironmentRgdExtractService.kt b/src/main/kotlin/com/dowstats/service/w40k/AbilityEnvironmentRgdExtractService.kt new file mode 100644 index 0000000..e0bed02 --- /dev/null +++ b/src/main/kotlin/com/dowstats/service/w40k/AbilityEnvironmentRgdExtractService.kt @@ -0,0 +1,90 @@ +package com.dowstats.service.w40k + +import com.dowstats.data.entities.ArmorType +import com.dowstats.data.entities.Mod +import com.dowstats.data.entities.ability.Ability +import com.dowstats.data.entities.ability.AbilityEnvironment +import com.dowstats.data.rgd.RgdData +import com.dowstats.data.rgd.RgdDataUtil.getDoubleByName +import com.dowstats.data.rgd.RgdDataUtil.getRgdTableByName +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service + +@Service +class AbilityEnvironmentRgdExtractService @Autowired constructor( + private val commonParseRgdService: CommonParseRgdService, + private val deathExplosionRgdExtractService: DeathExplosionRgdExtractService, +) { + + val log = LoggerFactory.getLogger(AbilityEnvironmentRgdExtractService::class.java) + + fun extractToAbilityEnvironmentEntity( + fileName: String, + abilityEnvironmentData: List, + mod: Mod, + modFolderData: String, + abilities: Set, + armorTypes: Set, + modDictionary: Map + ): AbilityEnvironment? { + + val abilityEnvironment = AbilityEnvironment() + abilityEnvironment.filename = fileName + abilityEnvironment.modId = mod.id + + val uiInfo = abilityEnvironmentData.getRgdTableByName("ui_ext")?.getRgdTableByName("ui_info") + val uiData = uiInfo?.let { + commonParseRgdService.getUiInfo( + uiInfo, + modDictionary, + modFolderData, + mod, + log, + ) + } + + abilityEnvironment.name = uiData?.name + abilityEnvironment.description = uiData?.description + abilityEnvironment.icon = uiData?.iconPath + + val healthExt = abilityEnvironmentData.getRgdTableByName("health_ext") + abilityEnvironment.health = healthExt?.getDoubleByName("hitpoints")?.toInt() + abilityEnvironment.armour = healthExt?.getDoubleByName("armour")?.minus(100) + abilityEnvironment.healthRegeneration = healthExt?.getDoubleByName("regeneration_rate") + + abilityEnvironment.moveSpeed = getSpeed(abilityEnvironmentData) + abilityEnvironment.sightRadius = getSightRadius(abilityEnvironmentData) + abilityEnvironment.detectRadius = getDetectRadius(abilityEnvironmentData) + + abilityEnvironment.lifetime = getLifetime(abilityEnvironmentData) + + abilityEnvironment.armorType = commonParseRgdService.getArmorType(abilityEnvironmentData, armorTypes, "type_armour") + abilityEnvironment.armorType2 = commonParseRgdService.getArmorType(abilityEnvironmentData, armorTypes, "type_armour_2") + + abilityEnvironment.abilities.addAll(commonParseRgdService.getAbilities(abilityEnvironmentData, abilities).toMutableSet()) + abilityEnvironment.deathExplosions.addAll(deathExplosionRgdExtractService.getDeathExplosions(abilityEnvironmentData, armorTypes).toMutableSet()) + + return abilityEnvironment + } + + private fun getSpeed(abilityEnvironmentData: List): Int? = abilityEnvironmentData + .getRgdTableByName("moving_ext") + ?.getDoubleByName("speed_max") + ?.toInt() + + private fun getSightRadius(abilityEnvironmentData: List): Int? = abilityEnvironmentData + .getRgdTableByName("sight_ext") + ?.getDoubleByName("sight_radius") + ?.toInt() + + private fun getDetectRadius(abilityEnvironmentData: List): Int? = abilityEnvironmentData + .getRgdTableByName("sight_ext") + ?.getDoubleByName("keen_sight_radius") + ?.toInt() + + private fun getLifetime(abilityEnvironmentData: List): Double? = abilityEnvironmentData + .getRgdTableByName("suicide_ext") + ?.getDoubleByName("lifetime") + +} diff --git a/src/main/kotlin/com/dowstats/service/w40k/AbilityRgdExtractService.kt b/src/main/kotlin/com/dowstats/service/w40k/AbilityRgdExtractService.kt index e65f89e..ee8058c 100644 --- a/src/main/kotlin/com/dowstats/service/w40k/AbilityRgdExtractService.kt +++ b/src/main/kotlin/com/dowstats/service/w40k/AbilityRgdExtractService.kt @@ -77,7 +77,7 @@ class AbilityRgdExtractService @Autowired constructor( ability.refreshTime = abilityData.getDoubleByName("refresh_time") ability.durationTime = abilityData.getDoubleByName("duration_time") - ability.spawnedEntityName = abilityData.getStringByName("spawn_entity_name") + ability.spawnedEntityName = abilityData.getStringByName("spawned_entity_name") // Damage & Area Effect @@ -153,7 +153,9 @@ class AbilityRgdExtractService @Autowired constructor( return abilityData.getRgdTableByName("requirements")?.mapNotNull { r -> if (r.name.contains("required_")) { val rTable = r.value as List - if (rTable.getStringByName("\$REF") == Metadata.Requirements.REFERENCE_REQUIREMENT_NONE) null else { + if (rTable.getStringByName("\$REF")?.contains(Metadata.Requirements.REFERENCE_REQUIREMENT_NONE) == true) + null + else { AbilityRequirements().also { it.ability = ability it.reference = rTable.getStringByName("\$REF") diff --git a/src/main/kotlin/com/dowstats/service/w40k/BuildingAddonRgdExtractService.kt b/src/main/kotlin/com/dowstats/service/w40k/BuildingAddonRgdExtractService.kt index e21843d..cbc0b92 100644 --- a/src/main/kotlin/com/dowstats/service/w40k/BuildingAddonRgdExtractService.kt +++ b/src/main/kotlin/com/dowstats/service/w40k/BuildingAddonRgdExtractService.kt @@ -79,7 +79,7 @@ class BuildingAddonRgdExtractService @Autowired constructor( return requirements?.mapNotNull { r -> if (r.name.contains("required_")) { val rTable = r.value as List - if (rTable.getStringByName("\$REF") == Metadata.Requirements.REFERENCE_REQUIREMENT_NONE) null else { + if (rTable.getStringByName("\$REF")?.contains(Metadata.Requirements.REFERENCE_REQUIREMENT_NONE) == true) null else { AddonRequirements().also { it.addon = addon it.reference = rTable.getStringByName("\$REF") diff --git a/src/main/kotlin/com/dowstats/service/w40k/BuildingRgdExtractService.kt b/src/main/kotlin/com/dowstats/service/w40k/BuildingRgdExtractService.kt index 7e256c0..91f1e09 100644 --- a/src/main/kotlin/com/dowstats/service/w40k/BuildingRgdExtractService.kt +++ b/src/main/kotlin/com/dowstats/service/w40k/BuildingRgdExtractService.kt @@ -26,6 +26,7 @@ import org.springframework.stereotype.Service class BuildingRgdExtractService @Autowired constructor( private val addonRgdExtractService: BuildingAddonRgdExtractService, private val commonParseRgdService: CommonParseRgdService, + private val deathExplosionRgdExtractService: DeathExplosionRgdExtractService, ) { val log = LoggerFactory.getLogger(BuildingRgdExtractService::class.java) @@ -54,7 +55,6 @@ class BuildingRgdExtractService @Autowired constructor( race: Race, modFolderData: String, mod: Mod, - races: List, armorTypes: Set, addonsRgdData: Map>, ): BuildingDataToSave { @@ -62,8 +62,8 @@ class BuildingRgdExtractService @Autowired constructor( val building = Building() building.race = race - building.armorType = getBuildingArmourType(buildingData, armorTypes, "type_armour") ?: throw Exception("Cant get armor type") - building.armorType2 = getBuildingArmourType(buildingData, armorTypes, "type_armour_2") + building.armorType = commonParseRgdService.getArmorType(buildingData, armorTypes, "type_armour") ?: throw Exception("Cant get armor type") + building.armorType2 = commonParseRgdService.getArmorType(buildingData, armorTypes, "type_armour_2") building.filename = fileName val uiExt = buildingData.getRgdTableByName("ui_ext") ?: throw Exception("Could not find ui_ext at $fileName") @@ -100,6 +100,8 @@ class BuildingRgdExtractService @Autowired constructor( building.repairMax = healthData.maxRepaires + building.buildingLimit = getLimit(buildingData) + building.units = getUnits(buildingData, units).toMutableSet() building.researches = getResearches(buildingData, researches).toMutableSet() @@ -109,6 +111,8 @@ class BuildingRgdExtractService @Autowired constructor( building.abilities = commonParseRgdService.getAbilities(buildingData, abilities).toMutableSet() + building.deathExplosions.addAll(deathExplosionRgdExtractService.getDeathExplosions(buildingData, armorTypes).toMutableSet()) + val addons = getAddons(buildingData) building.addons = addons?.mapNotNull {addonFileName -> val addonRgdData = addonsRgdData[addonFileName] @@ -134,17 +138,16 @@ class BuildingRgdExtractService @Autowired constructor( return BuildingDataToSave(building, buildingWeapons) } + private fun getLimit(buildingData: List): Int? { + val requirements = buildingData.getRgdTableByName("requirement_ext") + ?.getRgdTableByName("requirements") - private fun getBuildingArmourType( - unitData: List, - armorTypes: Iterable, - armorTypeTableName: String - ): ArmorType? { - val armorType = unitData.getRgdTableByName("type_ext") - ?.getRgdTableByName(armorTypeTableName) - ?.getStringByName("\$REF") - - return armorTypes.find { it.id == armorType?.replace("type_armour\\tp_", "")?.replace(".lua", "") } + return requirements?.map { + if (it.type == 100) { + val reqirementData = it.value as List + reqirementData.find {it.name == "max_cap"}?.value as Double? + } else null + }?.filterNotNull()?.firstOrNull()?.toInt() } private fun getHealthData(buildingData: List): HealthData { @@ -245,7 +248,7 @@ class BuildingRgdExtractService @Autowired constructor( return requirements?.mapNotNull { r -> if (r.name.contains("required_")) { val rTable = r.value as List - if (rTable.getStringByName("\$REF") == Metadata.Requirements.REFERENCE_REQUIREMENT_NONE) null else { + if (rTable.getStringByName("\$REF")?.contains(Metadata.Requirements.REFERENCE_REQUIREMENT_NONE) == true) null else { BuildingRequirements().also { it.building = building it.reference = rTable.getStringByName("\$REF") diff --git a/src/main/kotlin/com/dowstats/service/w40k/CommonParseRgdService.kt b/src/main/kotlin/com/dowstats/service/w40k/CommonParseRgdService.kt index ce0bb35..84d3318 100644 --- a/src/main/kotlin/com/dowstats/service/w40k/CommonParseRgdService.kt +++ b/src/main/kotlin/com/dowstats/service/w40k/CommonParseRgdService.kt @@ -5,6 +5,7 @@ import com.dowstats.data.dto.AreaEffect import com.dowstats.data.dto.BuildCost import com.dowstats.data.dto.ResourceIncome import com.dowstats.data.dto.UiInfo +import com.dowstats.data.entities.ArmorType import com.dowstats.data.entities.Mod import com.dowstats.data.entities.ability.Ability import com.dowstats.data.rgd.RgdData @@ -24,7 +25,8 @@ class CommonParseRgdService @Autowired constructor( ) { - fun getRequirementReference(ref: String?, rTable: List, fileName: String, log: Logger): String? = when (ref) { + fun getRequirementReference(ref: String?, rTable: List, fileName: String, log: Logger): String? = + when (ref?.getPureReference()) { Requirements.REFERENCE_REQUIREMENT_POP -> rTable.getDoubleByName("population_required").toString() Requirements.REFERENCE_REQUIREMENT_ADDON -> rTable.getStringByName("addon_name") Requirements.REFERENCE_GLOBAL_REQUIREMENT_ADDON -> rTable.getStringByName("global_addon_name") @@ -33,12 +35,20 @@ class CommonParseRgdService @Autowired constructor( Requirements.REFERENCE_REQUIREMENT_STRUCTURE -> rTable.getStringByName("structure_name") Requirements.REFERENCE_REQUIREMENT_RESEARCH -> rTable.getStringByName("research_name") + ";" + rTable.getBooleanByName("research_must_not_be_complete") + Requirements.REFERENCE_REQUIRED_RESEARCH_EITHER -> rTable.getStringByName("research_name_either") + ";" + + rTable.getStringByName("research_name_or") Requirements.REFERENCE_REQUIREMENT_OWNERSHIP -> rTable.getStringByName("own_name") Requirements.REFERENCE_REQUIREMENT_CAP -> rTable.getIntByName("max_cap").toString() Requirements.REFERENCE_REQUIREMENT_SQUAD_CAP -> rTable.getIntByName("max_squad_cap").toString() Requirements.REFERENCE_REQUIREMENT_CUM_SQUAD_CAP -> rTable.getIntByName("max_cumulative_squad_cap").toString() Requirements.REFERENCE_REQUIREMENT_STRUCTURE_RATIO -> rTable.getStringByName("required_structure_name") + ";" + rTable.getIntByName("this_structure_count").toString() + Requirements.REFERENCE_REQUIREMENT_MOB_BONUS -> rTable.getDoubleByName("mobvalue_required").toString() + ";" + + rTable.getIntByName("proximity_required").toString() + Requirements.REFERENCE_REQUIREMENT_STRUCTURE_EXCLUSIVE -> rTable.getStringByName("structure_name_exclusive") + Requirements.REFERENCE_LOCAL_REQUIRED_ADDON_EXCLUSIVE -> rTable.getStringByName("mutually_exclusive_with") + Requirements.REFERENCE_REQUIREMENT_SQUAD -> rTable.getStringByName("squad_name") + ";" + + rTable.getIntByName("min_count") else -> { log.warn("Unknown requirement reference $ref at $fileName") null @@ -104,6 +114,21 @@ class CommonParseRgdService @Autowired constructor( return UiInfo(name, description, icon) } + fun getArmorType( + entityData: List, + armorTypes: Iterable, + armorTypeTableName: String + ): ArmorType? { + val armorType = entityData.getRgdTableByName("type_ext") + ?.getRgdTableByName(armorTypeTableName) + ?.getStringByName("\$REF") + + return armorTypes.find { it.id == armorType + ?.replace("TYPE_Armour\\tp_", "") + ?.replace("type_armour\\tp_", "") + ?.replace(".lua", "") } + } + fun getAreaEffectData(areaEffectData: List): AreaEffect { val areaEffectInformation = areaEffectData.getRgdTableByName("area_effect_information") @@ -163,18 +188,22 @@ class CommonParseRgdService @Autowired constructor( ) } - fun getAbilities(modelData: List?, abilities: Set): List = modelData + fun getAbilities(entityData: List?, abilities: Set): List = entityData ?.getRgdTableByName("ability_ext") ?.getRgdTableByName("abilities") ?.mapNotNull { ability -> if (ability.name.contains("ability_")) { - val abilityFileName = (ability.value as String?)?.let{ + val abilityFileName = (ability.value as String?)?.let { it.replace("abilities\\", "").replace(".lua", "").replace(".rgd", "") } abilities.find { it.filename?.replace(".rgd", "") == abilityFileName } } else null } ?: emptyList() + fun String.getPureReference(): String = + this.split("\\").last() + .replace(".lua", "") + .replace(".rgd", "") } diff --git a/src/main/kotlin/com/dowstats/service/w40k/DeathExplosionRgdExtractService.kt b/src/main/kotlin/com/dowstats/service/w40k/DeathExplosionRgdExtractService.kt new file mode 100644 index 0000000..c1394f2 --- /dev/null +++ b/src/main/kotlin/com/dowstats/service/w40k/DeathExplosionRgdExtractService.kt @@ -0,0 +1,93 @@ +package com.dowstats.service.w40k + +import com.dowstats.data.dto.AreaEffect +import com.dowstats.data.entities.ArmorType +import com.dowstats.data.entities.ModifiersBase.ModifiersBaseCompanion.fillDataFromRgdTable +import com.dowstats.data.entities.ModifiersBase.ModifiersBaseCompanion.filterUseless +import com.dowstats.data.entities.deathexplosion.DeathExplosion +import com.dowstats.data.entities.deathexplosion.DeathExplosionArmorPiercing +import com.dowstats.data.entities.deathexplosion.DeathExplosionModifiers +import com.dowstats.data.entities.weapon.WeaponArmorPiercing +import com.dowstats.data.rgd.RgdData +import com.dowstats.data.rgd.RgdDataUtil.getDoubleByName +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.math.BigDecimal +import kotlin.collections.get +import kotlin.toBigDecimal + +@Service +class DeathExplosionRgdExtractService @Autowired constructor( + private val commonParseRgdService: CommonParseRgdService, +) { + + val log = LoggerFactory.getLogger(DeathExplosionRgdExtractService::class.java) + + fun getDeathExplosions( + entityData: List, + armorTypes: Set, + ): List { + val rootExplosion = entityData.getRgdTableByName("death_explosion_ext") + val globalChance = rootExplosion?.getDoubleByName("chance") + + fun getExplosionModifiers(explosionPartRoot: List?, deathExplosion: DeathExplosion): List = + explosionPartRoot + ?.getRgdTableByName("area_effect") + ?.getRgdTableByName("weapon_damage") + ?.getRgdTableByName("modifiers") + ?.mapNotNull { m -> + if (m.name.contains("modifier_")) { + val mTable = m.value as List + val modifier = mTable.getRgdTableByName("modifier") + val maxLifetime = mTable.getDoubleByName("max_lifetime") + if (modifier?.getStringByName("\$REF") == "modifiers\\no_modifier.lua" || modifier == null) null else { + DeathExplosionModifiers().also { + it.deathExplosion = deathExplosion + it.maxLifeTime = maxLifetime + }.fillDataFromRgdTable(modifier) + } + } else null + }?.filterUseless() ?: emptyList() + + fun getExplosionArmorPiercings(areaEffectData: AreaEffect, deathExplosion: DeathExplosion): List = armorTypes.map { + val deathExplosionArmorPiercing = DeathExplosionArmorPiercing() + deathExplosionArmorPiercing.deathExplosion = deathExplosion + deathExplosionArmorPiercing.armorType = it + val piercingValue = + (areaEffectData.weaponDmgMap[it.id] ?: areaEffectData.defaultArmorPiercing).toBigDecimal() + deathExplosionArmorPiercing.piercingValue = + piercingValue.let { pv -> if (pv <= BigDecimal(100)) pv else BigDecimal(100) } + deathExplosionArmorPiercing + } + + return rootExplosion?.getRgdTableByName("death_explosions") + ?.mapNotNull { explosion -> + if (explosion.name.contains("death_explosion")) { + val explosionPartRoot = explosion.value as List + val chance = explosionPartRoot.getDoubleByName("chance") + val areaEffect = explosionPartRoot.getRgdTableByName("area_effect")?.let { commonParseRgdService.getAreaEffectData(it) } + + DeathExplosion().also { + it.globalChance = globalChance + it.chance = chance + it.minDamage = areaEffect?.minDamage + it.maxDamage = areaEffect?.maxDamage + it.minDamageValue = areaEffect?.minDamageValue + it.moraleDamage = areaEffect?.moraleDamage + it.radius = areaEffect?.damageRadius + it.throwForceMin = areaEffect?.throwForceMin + it.throwForceMax = areaEffect?.throwForceMax + it.explosionModifiers += getExplosionModifiers(explosionPartRoot, it) + areaEffect?.let{ ae -> + it.explosionPiercings += getExplosionArmorPiercings(ae, it) + } + } + + } else null + } ?: emptyList() + + } +} diff --git a/src/main/kotlin/com/dowstats/service/w40k/ModAttribPathService.kt b/src/main/kotlin/com/dowstats/service/w40k/ModAttribPathService.kt index 345b265..548166a 100644 --- a/src/main/kotlin/com/dowstats/service/w40k/ModAttribPathService.kt +++ b/src/main/kotlin/com/dowstats/service/w40k/ModAttribPathService.kt @@ -29,6 +29,9 @@ class ModAttribPathService @Autowired constructor( fun getAbilitiesAttribsPath(modFolderData: String): String = "$modFolderData${File.separator}attrib${File.separator}abilities" + fun getAbilityEnvironmentsAttribsPath(modFolderData: String): String = + "$modFolderData${File.separator}attrib${File.separator}ebps${File.separator}environment${File.separator}gameplay" + fun getResearchAttribsPath(modFolderData: String): String = "$modFolderData${File.separator}attrib${File.separator}research" diff --git a/src/main/kotlin/com/dowstats/service/w40k/ModParserService.kt b/src/main/kotlin/com/dowstats/service/w40k/ModParserService.kt index a4e0dcb..6550db3 100644 --- a/src/main/kotlin/com/dowstats/service/w40k/ModParserService.kt +++ b/src/main/kotlin/com/dowstats/service/w40k/ModParserService.kt @@ -2,6 +2,7 @@ package com.dowstats.service.w40k import com.dowstats.data.entities.* import com.dowstats.data.entities.ability.Ability +import com.dowstats.data.entities.ability.AbilityEnvironment import com.dowstats.data.entities.building.BuildingWeapon import com.dowstats.data.entities.building.BuildingWeaponKey import com.dowstats.data.entities.research.Research @@ -25,24 +26,26 @@ import kotlin.io.path.name @Service class ModParserService @Autowired constructor( - val rgdParserService: RgdParserService, - val unitRgdExtractService: UnitRgdExtractService, - val researchRgdExtractService: ResearchRgdExtractService, - val raceRepository: RaceRepository, - val armorTypeRepository: ArmorTypeRepository, - val areaEffectRepository: AreaEffectRepository, - val areaFilterRepository: AreaFilterRepository, - val activationRepository: ActivationRepository, - val unitRepository: UnitRepository, - val sergeantRepository: SergeantRepository, - val abilityRgdExtractService: AbilityRgdExtractService, - val abilityRepository: AbilityRepository, - val weaponRgdExtractService: WeaponRgdExtractService, - val weaponRepository: WeaponRepository, - val modAttribPathService: ModAttribPathService, - val buildingRepository: BuildingRepository, - val buildingExtractService: BuildingRgdExtractService, - val postParsingService: PostParsingService, + private val rgdParserService: RgdParserService, + private val unitRgdExtractService: UnitRgdExtractService, + private val researchRgdExtractService: ResearchRgdExtractService, + private val raceRepository: RaceRepository, + private val armorTypeRepository: ArmorTypeRepository, + private val areaEffectRepository: AreaEffectRepository, + private val areaFilterRepository: AreaFilterRepository, + private val activationRepository: ActivationRepository, + private val unitRepository: UnitRepository, + private val sergeantRepository: SergeantRepository, + private val abilityRgdExtractService: AbilityRgdExtractService, + private val abilityEnvironmentRgdExtractService: AbilityEnvironmentRgdExtractService, + private val abilityEnvironmentRepository: AbilityEnvironmentRepository, + private val abilityRepository: AbilityRepository, + private val weaponRgdExtractService: WeaponRgdExtractService, + private val weaponRepository: WeaponRepository, + private val modAttribPathService: ModAttribPathService, + private val buildingRepository: BuildingRepository, + private val buildingExtractService: BuildingRgdExtractService, + private val postParsingService: PostParsingService, private val researchRepository: ResearchRepository, private val modRepository: ModRepository, ) { @@ -103,10 +106,13 @@ class ModParserService @Autowired constructor( val weapons = saveWeapons(modFolderData, mod, armorTypes, enrichedModDictionary) val abilities = saveAbilities(modFolderData, mod, activations, areaEffects, areaFilters, armorTypes, enrichedModDictionary) + val researches = saveResearches(modFolderData, mod, enrichedModDictionary) saveUnits(modFolderData, weapons, abilities, racesList, armorTypes, mod, enrichedModDictionary) saveBuildings(modFolderData, weapons, abilities, researches, racesList, armorTypes, mod, enrichedModDictionary) + saveAbilityEnvironments(modFolderData, mod, abilities, armorTypes, enrichedModDictionary) + modRepository.removeCampaignEntities(mod.id!!) postParsingService.bindResearch(mod) log.info("Complete parse mod ${mod.technicalName}:${mod.version}") @@ -367,7 +373,6 @@ class ModParserService @Autowired constructor( race, modFolderData, mod, - races, armorTypes, addonsRgdData, ) @@ -408,7 +413,7 @@ class ModParserService @Autowired constructor( private fun getAddonsRgdData(modFolderData: String): Map> { val classicAddons = - rgdParserService.parseFolderToRgdFiles("${modAttribPathService.pathToWanilaData}/attrib/addons") + rgdParserService.parseFolderToRgdFiles("${modAttribPathService.pathToWanilaData}${File.separator}attrib${File.separator}addons") val modAddons = rgdParserService.parseFolderToRgdFiles(modAttribPathService.getAddonAttribsPath(modFolderData)) @@ -419,7 +424,7 @@ class ModParserService @Autowired constructor( private fun saveWeapons(modFolderData: String, mod: Mod, armorTypes: Set, modDictionary: Map): Set { val classicWeapons = - rgdParserService.parseFolderToRgdFiles("${modAttribPathService.pathToWanilaData}/attrib/weapon") + rgdParserService.parseFolderToRgdFiles("${modAttribPathService.pathToWanilaData}${File.separator}attrib${File.separator}weapon") val modWeapons = rgdParserService.parseFolderToRgdFiles(modAttribPathService.getWeaponAttribsPath(modFolderData)) @@ -445,7 +450,7 @@ class ModParserService @Autowired constructor( armorTypes: Set, modDictionary: Map): Set { val classicAbilities = - rgdParserService.parseFolderToRgdFiles("${modAttribPathService.pathToWanilaData}/attrib/abilities") + rgdParserService.parseFolderToRgdFiles("${modAttribPathService.pathToWanilaData}${File.separator}attrib${File.separator}abilities") val modAbilities = rgdParserService.parseFolderToRgdFiles(modAttribPathService.getAbilitiesAttribsPath(modFolderData)) @@ -470,6 +475,34 @@ class ModParserService @Autowired constructor( } } + private fun saveAbilityEnvironments(modFolderData: String, + mod: Mod, + abilities: Set, + armorTypes: Set, + modDictionary: Map): Set { + val classicAbilityEnvironments = + rgdParserService.parseFolderToRgdFiles("${modAttribPathService.pathToWanilaData}${File.separator}attrib${File.separator}ebps${File.separator}environment${File.separator}gameplay") + + val modAbilityEnvironments = + rgdParserService.parseFolderToRgdFiles(modAttribPathService.getAbilityEnvironmentsAttribsPath(modFolderData)) + + val allAbilityEnvironments = classicAbilityEnvironments + modAbilityEnvironments + + val abilityEnvironmentsToSave = allAbilityEnvironments.mapNotNull { + abilityEnvironmentRgdExtractService.extractToAbilityEnvironmentEntity(it.key, it.value, mod, + modFolderData, + abilities, + armorTypes, + modDictionary, + ) + } + + return try { + abilityEnvironmentRepository.saveAll(abilityEnvironmentsToSave).toSet() + } catch (e: Exception) { + throw e + } + } } diff --git a/src/main/kotlin/com/dowstats/service/w40k/ResearchRgdExtractService.kt b/src/main/kotlin/com/dowstats/service/w40k/ResearchRgdExtractService.kt index be55e30..f21a87b 100644 --- a/src/main/kotlin/com/dowstats/service/w40k/ResearchRgdExtractService.kt +++ b/src/main/kotlin/com/dowstats/service/w40k/ResearchRgdExtractService.kt @@ -77,7 +77,7 @@ class ResearchRgdExtractService @Autowired constructor( return requirements?.mapNotNull { r -> if (r.name.contains("required_")) { val rTable = r.value as List - if (rTable.getStringByName("\$REF") == Metadata.Requirements.REFERENCE_REQUIREMENT_NONE) null else { + if (rTable.getStringByName("\$REF")?.contains(Metadata.Requirements.REFERENCE_REQUIREMENT_NONE) == true) null else { ResearchRequirements().also { it.research = research it.reference = rTable.getStringByName("\$REF") diff --git a/src/main/kotlin/com/dowstats/service/w40k/SergantRgdExtractService.kt b/src/main/kotlin/com/dowstats/service/w40k/SergantRgdExtractService.kt index 7c621c6..7e7f8c3 100644 --- a/src/main/kotlin/com/dowstats/service/w40k/SergantRgdExtractService.kt +++ b/src/main/kotlin/com/dowstats/service/w40k/SergantRgdExtractService.kt @@ -22,6 +22,7 @@ import org.springframework.stereotype.Service @Service class SergeantRgdExtractService @Autowired constructor( private val commonParseRgdService: CommonParseRgdService, + private val deathExplosionRgdExtractService: DeathExplosionRgdExtractService, ) { val log = LoggerFactory.getLogger(SergeantRgdExtractService::class.java) @@ -66,8 +67,8 @@ class SergeantRgdExtractService @Autowired constructor( sergeant.buildCostSouls = buildCost.souls sergeant.buildCostTime = buildCost.time - sergeant.armorType = getUnitArmorType(sergeantData, armorTypes, "type_armour") ?: throw Exception("Cant get armor type") - sergeant.armorType2 = getUnitArmorType(sergeantData, armorTypes, "type_armour_2") + sergeant.armorType = commonParseRgdService.getArmorType(sergeantData, armorTypes, "type_armour") ?: throw Exception("Cant get armor type") + sergeant.armorType2 = commonParseRgdService.getArmorType(sergeantData, armorTypes, "type_armour_2") sergeant.filename = fileName val uiExt = sergeantData.getRgdTableByName("ui_ext") ?: throw Exception("Could not find ui_ext at $fileName") @@ -94,6 +95,8 @@ class SergeantRgdExtractService @Autowired constructor( sergeant.powerIncome = incomeData.power sergeant.requisitionIncome = incomeData.requisition + sergeant.mobValue = getMobValue(sergeantData) + sergeant.sightRadius = getSightRadius(sergeantData)?.toInt() sergeant.detectRadius = getDetectRadius(sergeantData)?.toInt() @@ -108,6 +111,8 @@ class SergeantRgdExtractService @Autowired constructor( sergeant.abilities = commonParseRgdService.getAbilities(sergeantData, abilities).toMutableSet() + sergeant.deathExplosions.addAll(deathExplosionRgdExtractService.getDeathExplosions(sergeantData, armorTypes).toMutableSet()) + val sergeantWeapons = getSergeantWeapons(sergeantData)?.mapNotNull { weaponData -> weapons.find { it.filename == weaponData.weaponFilename + ".rgd" @@ -119,19 +124,6 @@ class SergeantRgdExtractService @Autowired constructor( return Pair(sergeant, sergeantWeapons) } - private fun getUnitArmorType( - unitData: List, - armorTypes: Iterable, - armorTypeTableName: String - ): ArmorType? { - val armorType = unitData.getRgdTableByName("type_ext") - ?.getRgdTableByName(armorTypeTableName) - ?.getStringByName("\$REF") - - return armorTypes.find { it.id == armorType?.replace("type_armour\\tp_", "")?.replace(".lua", "") } - } - - private fun getHealthAndMoraleDeathPenaltyData(unitData: List): HealthAndMoraleDeathData { val healthExt = unitData.getRgdTableByName("health_ext") return HealthAndMoraleDeathData( @@ -142,6 +134,10 @@ class SergeantRgdExtractService @Autowired constructor( ) } + private fun getMobValue(squadData: List): Double? = + squadData.getRgdTableByName("mob_ext") + ?.getDoubleByName("mob_value") + private fun getMassData(unitData: List): MassData { val massDataRgd = unitData @@ -199,7 +195,7 @@ class SergeantRgdExtractService @Autowired constructor( return requirements?.mapNotNull { r -> if (r.name.contains("required_")) { val rTable = r.value as List - if (rTable.getStringByName("\$REF") == Metadata.Requirements.REFERENCE_REQUIREMENT_NONE) null else { + if (rTable.getStringByName("\$REF")?.contains(Metadata.Requirements.REFERENCE_REQUIREMENT_NONE) == true) null else { SergeantRequirements().also { it.sergeant = sergeant it.reference = rTable.getStringByName("\$REF") diff --git a/src/main/kotlin/com/dowstats/service/w40k/UnitRgdExtractService.kt b/src/main/kotlin/com/dowstats/service/w40k/UnitRgdExtractService.kt index 3800cc9..e23d138 100644 --- a/src/main/kotlin/com/dowstats/service/w40k/UnitRgdExtractService.kt +++ b/src/main/kotlin/com/dowstats/service/w40k/UnitRgdExtractService.kt @@ -11,9 +11,9 @@ import com.dowstats.data.entities.ability.Ability import com.dowstats.data.entities.sergant.Sergeant import com.dowstats.data.entities.unit.DowUnit import com.dowstats.data.entities.unit.UnitModifiers +import com.dowstats.data.entities.unit.UnitMoraleBrakeModifiers import com.dowstats.data.entities.unit.UnitRequirements import com.dowstats.data.entities.weapon.Weapon -import com.dowstats.data.entities.weapon.WeaponModifiers import com.dowstats.data.rgd.RgdData import com.dowstats.data.rgd.RgdDataUtil.getBooleanByName import com.dowstats.data.rgd.RgdDataUtil.getDoubleByName @@ -28,6 +28,7 @@ import org.springframework.stereotype.Service class UnitRgdExtractService @Autowired constructor( private val commonParseRgdService: CommonParseRgdService, private val sergeantRgdExtractService: SergeantRgdExtractService, + private val deathExplosionRgdExtractService: DeathExplosionRgdExtractService, ) { val log = LoggerFactory.getLogger(UnitRgdExtractService::class.java) @@ -49,6 +50,7 @@ class UnitRgdExtractService @Autowired constructor( val max: Double?, val broken: Double?, val regeneration: Double?, + val unitMoraleBrakeModifiers: List, ) data class SergeantData( @@ -82,8 +84,8 @@ class UnitRgdExtractService @Autowired constructor( val unitRace = races.find { it.id == race } ?: throw Exception("Cant get race $race") unit.race = unitRace - unit.armorType = getUnitArmorType(unitData, armorTypes, "type_armour") ?: throw Exception("Cant get armor type") - unit.armorType2 = getUnitArmorType(unitData, armorTypes, "type_armour_2") + unit.armorType = commonParseRgdService.getArmorType(unitData, armorTypes, "type_armour") ?: throw Exception("Cant get armor type") + unit.armorType2 = commonParseRgdService.getArmorType(unitData, armorTypes, "type_armour_2") val squadUiInfo = squadData.getRgdTableByName("squad_ui_ext") ?.getRgdTableByName("ui_info") ?: throw Exception("Could not find ui_info at $fileNameSquad") @@ -130,10 +132,11 @@ class UnitRgdExtractService @Autowired constructor( unit.powerIncome = incomeData.power unit.requisitionIncome = incomeData.requisition - val moraleData = getMoraleData(squadData) + val moraleData = getMoraleData(unit, squadData) unit.moraleMax = moraleData.max?.toInt() unit.moraleBroken = moraleData.broken?.toInt() unit.moraleRegeneration = moraleData.regeneration?.toInt() + unit.unitMoraleBrakeModifiers = moraleData.unitMoraleBrakeModifiers.toMutableSet() unit.moveSpeed = getUnitSpeed(unitData)?.toInt() unit.sightRadius = getSightRadius(unitData)?.toInt() @@ -152,10 +155,14 @@ class UnitRgdExtractService @Autowired constructor( unit.reinforceCostSouls = reinforceCostData.souls unit.reinforceTime = reinforceCostData.time + unit.mobValue = getMobValue(unitData) + unit.unitModifiers = geUnitModifiers(unit, unitData, squadData).toMutableSet() unit.unitRequirements = getUnitRequirements(unit, squadData).toMutableSet() unit.abilities = commonParseRgdService.getAbilities(unitData, abilities).toMutableSet() + unit.deathExplosions.addAll(deathExplosionRgdExtractService.getDeathExplosions(unitData, armorTypes).toMutableSet()) + val sergeantsData = getSergeantsData(squadData) @@ -194,21 +201,6 @@ class UnitRgdExtractService @Autowired constructor( return baseUnitPath?.split("\\")?.last()?.replace(".lua", ".rgd") } - private fun getUnitArmorType( - unitData: List, - armorTypes: Iterable, - armorTypeTableName: String - ): ArmorType? { - val armorType = unitData.getRgdTableByName("type_ext") - ?.getRgdTableByName(armorTypeTableName) - ?.getStringByName("\$REF") - - return armorTypes.find { it.id == armorType - ?.replace("TYPE_Armour\\tp_", "") - ?.replace("type_armour\\tp_", "") - ?.replace(".lua", "") } - } - private fun getBuildCost(unitData: List, squadData: List): BuildCost { val cost = commonParseRgdService.getBuildCost(unitData.getRgdTableByName("cost_ext")?.getRgdTableByName("time_cost")) @@ -284,14 +276,31 @@ class UnitRgdExtractService @Autowired constructor( } - private fun getMoraleData(squadData: List): MoraleData { + private fun getMoraleData(unit: DowUnit, squadData: List): MoraleData { val moraleData = squadData.getRgdTableByName("squad_morale_ext") val max = moraleData?.getDoubleByName("max") val broken = moraleData?.getDoubleByName("broken_min_morale") val regeneration = moraleData?.getDoubleByName("rate_per_second") - return MoraleData(max, broken, regeneration) + + val unitMoraleBreakModifiers = moraleData?.getRgdTableByName("broken_modifiers")?.mapNotNull { m -> + if (m.name.contains("modifier_")) { + val mTable = m.value as List + if (mTable.getStringByName("\$REF") == "modifiers\\no_modifier.lua" || + mTable.getStringByName("\$REF") == "modifiers\\morale_break_event.lua") null else { + UnitMoraleBrakeModifiers().also { + it.unit = unit + }.fillDataFromRgdTable(mTable) + } + } else null + } ?: emptyList() + + return MoraleData(max, broken, regeneration, unitMoraleBreakModifiers) } + private fun getMobValue(unitData: List): Double? = + unitData.getRgdTableByName("mob_ext") + ?.getDoubleByName("mob_value") + private fun getMassData(unitData: List): MassData { val massDataRgd = unitData .getRgdTableByName("special_attack_physics_ext") @@ -420,7 +429,7 @@ class UnitRgdExtractService @Autowired constructor( return requirements?.mapNotNull { r -> if (r.name.contains("required_")) { val rTable = r.value as List - if (rTable.getStringByName("\$REF") == Metadata.Requirements.REFERENCE_REQUIREMENT_NONE) null else { + if (rTable.getStringByName("\$REF")?.contains(Metadata.Requirements.REFERENCE_REQUIREMENT_NONE) == true) null else { UnitRequirements().also { it.unit = unit it.reference = rTable.getStringByName("\$REF") diff --git a/src/main/kotlin/com/dowstats/service/w40k/WeaponRgdExtractService.kt b/src/main/kotlin/com/dowstats/service/w40k/WeaponRgdExtractService.kt index 24acd9c..f0d4663 100644 --- a/src/main/kotlin/com/dowstats/service/w40k/WeaponRgdExtractService.kt +++ b/src/main/kotlin/com/dowstats/service/w40k/WeaponRgdExtractService.kt @@ -117,7 +117,7 @@ class WeaponRgdExtractService @Autowired constructor( if (r.name.contains("required_")) { try { val rTable = r.value as List - if (rTable.getStringByName("\$REF") == Metadata.Requirements.REFERENCE_REQUIREMENT_NONE) null else { + if (rTable.getStringByName("\$REF")?.contains(Metadata.Requirements.REFERENCE_REQUIREMENT_NONE) == true) null else { WeaponRequirements().also { it.weapon = weapon it.reference = rTable.getStringByName("\$REF") diff --git a/src/main/resources/db/0.0.5/procedures/delete_mod_data_procedure.sql b/src/main/resources/db/0.0.5/procedures/delete_mod_data_procedure.sql new file mode 100644 index 0000000..a4157c5 --- /dev/null +++ b/src/main/resources/db/0.0.5/procedures/delete_mod_data_procedure.sql @@ -0,0 +1,10 @@ +CREATE OR REPLACE PROCEDURE delete_mod_data(mod_id_p bigint) + LANGUAGE SQL +AS $$ +DELETE FROM units WHERE mod_id = mod_id_p; +DELETE FROM buildings WHERE mod_id = mod_id_p; +DELETE FROM weapons WHERE mod_id = mod_id_p; +DELETE FROM abilities WHERE mod_id = mod_id_p; +DELETE FROM researches WHERE mod_id = mod_id_p; +DELETE FROM ability_environments WHERE mod_id = mod_id_p; +$$; \ No newline at end of file diff --git a/src/main/resources/db/0.0.5/schema/ability_environment_abilities.json b/src/main/resources/db/0.0.5/schema/ability_environment_abilities.json new file mode 100644 index 0000000..1ad9c2e --- /dev/null +++ b/src/main/resources/db/0.0.5/schema/ability_environment_abilities.json @@ -0,0 +1,66 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Add ability_environment_abilities table", + "author": "anibus", + "changes": [ + { + "createTable": { + "tableName": "ability_environment_abilities", + "columns": [ + { + "column": { + "name": "ability_environment_id", + "type": "int", + "constraints": { + "nullable": false + } + } + }, + { + "column": { + "name": "ability_id", + "type": "int", + "constraints": { + "nullable": false + } + } + } + ] + } + }, + { + "addUniqueConstraint": { + "columnNames": "ability_environment_id, ability_id", + "constraintName": "uc_ability_environment_abilities", + "tableName": "ability_environment_abilities" + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "ability_environment_id", + "baseTableName": "ability_environment_abilities", + "constraintName": "fk_ability_environment_ability_environment_abilities", + "referencedColumnNames": "id", + "referencedTableName": "ability_environments", + "onDelete": "CASCADE" + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "ability_id", + "baseTableName": "ability_environment_abilities", + "constraintName": "fk_abilities_ability_environment_abilities", + "referencedColumnNames": "id", + "referencedTableName": "abilities", + "onDelete": "CASCADE" + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/0.0.5/schema/ability_environment_death_explosion.json b/src/main/resources/db/0.0.5/schema/ability_environment_death_explosion.json new file mode 100644 index 0000000..ef053a1 --- /dev/null +++ b/src/main/resources/db/0.0.5/schema/ability_environment_death_explosion.json @@ -0,0 +1,66 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Add ability_environment_death_explosion table", + "author": "anibus", + "changes": [ + { + "createTable": { + "tableName": "ability_environment_death_explosion", + "columns": [ + { + "column": { + "name": "ability_environment_id", + "type": "int", + "constraints": { + "nullable": false + } + } + }, + { + "column": { + "name": "death_explosion_id", + "type": "int", + "constraints": { + "nullable": false + } + } + } + ] + } + }, + { + "addUniqueConstraint": { + "columnNames": "ability_environment_id, death_explosion_id", + "constraintName": "uc_ability_environment_death_explosion", + "tableName": "ability_environment_death_explosion" + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "ability_environment_id", + "baseTableName": "ability_environment_death_explosion", + "constraintName": "fk_ability_environment_ability_environment_death_explosion", + "referencedColumnNames": "id", + "referencedTableName": "ability_environments", + "onDelete": "CASCADE" + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "death_explosion_id", + "baseTableName": "ability_environment_death_explosion", + "constraintName": "fk_death_explosion_ability_environment_death_explosion", + "referencedColumnNames": "id", + "referencedTableName": "death_explosions", + "onDelete": "CASCADE" + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/0.0.5/schema/ability_environments.json b/src/main/resources/db/0.0.5/schema/ability_environments.json new file mode 100644 index 0000000..a1ef7f9 --- /dev/null +++ b/src/main/resources/db/0.0.5/schema/ability_environments.json @@ -0,0 +1,109 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Add ability environments table", + "author": "anibus", + "changes": [ + { + "createTable": { + "tableName": "ability_environments", + "columns": [ + { + "column": { + "name": "id", + "type": "int", + "autoIncrement": true, + "constraints": { + "primaryKey": true, + "nullable": false + } + } + }, + { + "column": { + "name": "filename", + "type": "varchar(255)", + "constraints": { + "nullable": false + } + } + },{ + "column": { + "name": "name", + "type": "varchar(4096)" + } + },{ + "column": { + "name": "description", + "type": "varchar(5000)" + } + },{ + "column": { + "name": "health", + "type": "int" + } + },{ + "column": { + "name": "health_regeneration", + "type": "number" + } + },{ + "column": { + "name": "lifetime", + "type": "number" + } + },{ + "column": { + "name": "armour", + "type": "number" + } + },{ + "column": { + "name": "armour_type_id", + "type": "varchar(50)" + } + },{ + "column": { + "name": "armour_type_2_id", + "type": "varchar(50)" + } + },{ + "column": { + "name": "move_speed", + "type": "int" + } + },{ + "column": { + "name": "sight_radius", + "type": "int" + } + },{ + "column": { + "name": "detect_radius", + "type": "int" + } + }, + { + "column": { + "name": "mod_id", + "type": "int", + "constraints": { + "nullable": false + } + } + }, + { + "column": { + "name": "icon", + "type": "varchar(128)" + } + } + ] + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/0.0.5/schema/building_death_explosion.json b/src/main/resources/db/0.0.5/schema/building_death_explosion.json new file mode 100644 index 0000000..665cfcb --- /dev/null +++ b/src/main/resources/db/0.0.5/schema/building_death_explosion.json @@ -0,0 +1,66 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Add building_death_explosion table", + "author": "anibus", + "changes": [ + { + "createTable": { + "tableName": "building_death_explosion", + "columns": [ + { + "column": { + "name": "building_id", + "type": "int", + "constraints": { + "nullable": false + } + } + }, + { + "column": { + "name": "death_explosion_id", + "type": "int", + "constraints": { + "nullable": false + } + } + } + ] + } + }, + { + "addUniqueConstraint": { + "columnNames": "building_id, death_explosion_id", + "constraintName": "uc_building_death_explosion", + "tableName": "building_death_explosion" + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "building_id", + "baseTableName": "building_death_explosion", + "constraintName": "fk_buildings_building_death_explosion", + "referencedColumnNames": "id", + "referencedTableName": "buildings", + "onDelete": "CASCADE" + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "death_explosion_id", + "baseTableName": "building_death_explosion", + "constraintName": "fk_death_explosions_building_death_explosion", + "referencedColumnNames": "id", + "referencedTableName": "death_explosions", + "onDelete": "CASCADE" + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/0.0.5/schema/buildings.json b/src/main/resources/db/0.0.5/schema/buildings.json new file mode 100644 index 0000000..2b96176 --- /dev/null +++ b/src/main/resources/db/0.0.5/schema/buildings.json @@ -0,0 +1,25 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Add limit column to buildings", + "author": "anibus", + "changes": [ + { + "addColumn": { + "columns": [ + { + "column": { + "name": "building_limit", + "type": "int" + } + } + ], + "tableName": "buildings" + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/0.0.5/schema/death_explosion_armors_piercing.json b/src/main/resources/db/0.0.5/schema/death_explosion_armors_piercing.json new file mode 100644 index 0000000..032b66a --- /dev/null +++ b/src/main/resources/db/0.0.5/schema/death_explosion_armors_piercing.json @@ -0,0 +1,76 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Add death_explosion_armors_piercing table", + "author": "anibus", + "changes": [ + { + "createTable": { + "tableName": "death_explosion_armors_piercing", + "columns": [{ + "column": { + "name": "id", + "type": "int", + "autoIncrement": true, + "constraints": { + "primaryKey": true, + "nullable": false + } + } + }, + { + "column": { + "name": "death_explosion_id", + "type": "int", + "constraints": { + "primaryKey": true, + "nullable": false + } + } + }, + { + "column": { + "name": "armor_type_id", + "type": "varchar(50)", + "constraints": { + "primaryKey": true, + "nullable": false + } + } + },{ + "column": { + "name": "piercing_value", + "type": "number", + "constraints": { + "nullable": false + } + } + },{ + "addForeignKeyConstraint": + { + "constraintName": "fk_death_explosion_death_explosion_armors_piercing", + "baseColumnNames": "death_explosion_id", + "baseTableName": "death_explosion_armors_piercing", + "referencedColumnNames": "id", + "referencedTableName": "death_explosions", + "onDelete": "CASCADE" + } + },{ + "addForeignKeyConstraint": + { + "constraintName": "fk_armor_types_death_explosion_armors_piercing", + "baseColumnNames": "armor_type_id", + "baseTableName": "death_explosion_armors_piercing", + "referencedColumnNames": "id", + "referencedTableName": "armor_types" + } + } + ] + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/0.0.5/schema/death_explosion_modifiers.json b/src/main/resources/db/0.0.5/schema/death_explosion_modifiers.json new file mode 100644 index 0000000..fdb9f6a --- /dev/null +++ b/src/main/resources/db/0.0.5/schema/death_explosion_modifiers.json @@ -0,0 +1,89 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Add death_explosion_modifiers table", + "author": "anibus", + "changes": [ + { + "createTable": { + "tableName": "death_explosion_modifiers", + "columns": [ + { + "column": { + "name": "id", + "type": "int", + "autoIncrement": true, + "constraints": { + "primaryKey": true, + "nullable": false + } + } + },{ + "column": { + "name": "reference", + "type": "varchar(255)" + } + },{ + "column": { + "name": "usage_type", + "type": "varchar(255)" + } + },{ + "column": { + "name": "value", + "type": "number" + } + },{ + "column": { + "name": "target", + "type": "varchar(255)" + } + },{ + "column": { + "name": "probability_of_applying", + "type": "number" + } + },{ + "column": { + "name": "exclusive", + "type": "boolean" + } + },{ + "column": { + "name": "application_type", + "type": "varchar(255)" + } + },{ + "column": { + "name": "max_life_time", + "type": "number" + } + },{ + "column": { + "name": "death_explosion_id", + "type": "int", + "constraints": { + "nullable": false + } + } + } + ] + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "death_explosion_id", + "baseTableName": "death_explosion_modifiers", + "constraintName": "fk_death_explosion_death_explosion_modifiers", + "referencedColumnNames": "id", + "referencedTableName": "death_explosions", + "onDelete": "CASCADE" + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/0.0.5/schema/death_explosions.json b/src/main/resources/db/0.0.5/schema/death_explosions.json new file mode 100644 index 0000000..0a27e15 --- /dev/null +++ b/src/main/resources/db/0.0.5/schema/death_explosions.json @@ -0,0 +1,81 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Add death_explosions table", + "author": "anibus", + "changes": [ + { + "createTable": { + "tableName": "death_explosions", + "columns": [ + { + "column": { + "name": "id", + "type": "int", + "autoIncrement": true, + "constraints": { + "primaryKey": true, + "nullable": false + } + } + },{ + "column": { + "name": "order", + "type": "number" + } + },{ + "column": { + "name": "global_chance", + "type": "number" + } + },{ + "column": { + "name": "chance", + "type": "number" + } + },{ + "column": { + "name": "radius", + "type": "number" + } + },{ + "column": { + "name": "min_damage", + "type": "number" + } + },{ + "column": { + "name": "min_damage_value", + "type": "number" + } + },{ + "column": { + "name": "max_damage", + "type": "number" + } + },{ + "column": { + "name": "morale_damage", + "type": "number" + } + },{ + "column": { + "name": "throw_force_min", + "type": "number" + } + }, + { + "column": { + "name": "throw_force_max", + "type": "number" + } + } + ] + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/0.0.5/schema/sergeant_death_explosion.json b/src/main/resources/db/0.0.5/schema/sergeant_death_explosion.json new file mode 100644 index 0000000..1f50494 --- /dev/null +++ b/src/main/resources/db/0.0.5/schema/sergeant_death_explosion.json @@ -0,0 +1,66 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Add sergeant_death_explosion table", + "author": "anibus", + "changes": [ + { + "createTable": { + "tableName": "sergeant_death_explosion", + "columns": [ + { + "column": { + "name": "sergeant_id", + "type": "int", + "constraints": { + "nullable": false + } + } + }, + { + "column": { + "name": "death_explosion_id", + "type": "int", + "constraints": { + "nullable": false + } + } + } + ] + } + }, + { + "addUniqueConstraint": { + "columnNames": "sergeant_id, death_explosion_id", + "constraintName": "uc_sergeant_death_explosion", + "tableName": "sergeant_death_explosion" + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "sergeant_id", + "baseTableName": "sergeant_death_explosion", + "constraintName": "fk_sergeant_id_sergeant_death_explosion", + "referencedColumnNames": "id", + "referencedTableName": "sergeants", + "onDelete": "CASCADE" + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "death_explosion_id", + "baseTableName": "sergeant_death_explosion", + "constraintName": "fk_death_explosion_sergeant_death_explosion", + "referencedColumnNames": "id", + "referencedTableName": "death_explosions", + "onDelete": "CASCADE" + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/0.0.5/schema/sergeants.json b/src/main/resources/db/0.0.5/schema/sergeants.json new file mode 100644 index 0000000..ed5e0ca --- /dev/null +++ b/src/main/resources/db/0.0.5/schema/sergeants.json @@ -0,0 +1,25 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Add mob bonus columns to sergeants", + "author": "anibus", + "changes": [ + { + "addColumn": { + "columns": [ + { + "column": { + "name": "mob_value", + "type": "number" + } + } + ], + "tableName": "sergeants" + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/0.0.5/schema/unit_death_explosion.json b/src/main/resources/db/0.0.5/schema/unit_death_explosion.json new file mode 100644 index 0000000..e1953f2 --- /dev/null +++ b/src/main/resources/db/0.0.5/schema/unit_death_explosion.json @@ -0,0 +1,66 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Add unit_death_explosion table", + "author": "anibus", + "changes": [ + { + "createTable": { + "tableName": "unit_death_explosion", + "columns": [ + { + "column": { + "name": "unit_id", + "type": "int", + "constraints": { + "nullable": false + } + } + }, + { + "column": { + "name": "death_explosion_id", + "type": "int", + "constraints": { + "nullable": false + } + } + } + ] + } + }, + { + "addUniqueConstraint": { + "columnNames": "unit_id, death_explosion_id", + "constraintName": "uc_unit_death_explosion", + "tableName": "unit_death_explosion" + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "unit_id", + "baseTableName": "unit_death_explosion", + "constraintName": "fk_units_unit_death_explosion", + "referencedColumnNames": "id", + "referencedTableName": "units", + "onDelete": "CASCADE" + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "death_explosion_id", + "baseTableName": "unit_death_explosion", + "constraintName": "fk_death_explosions_unit_death_explosion", + "referencedColumnNames": "id", + "referencedTableName": "death_explosions", + "onDelete": "CASCADE" + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/0.0.5/schema/unit_morale_break_modifiers.json b/src/main/resources/db/0.0.5/schema/unit_morale_break_modifiers.json new file mode 100644 index 0000000..b3c78a0 --- /dev/null +++ b/src/main/resources/db/0.0.5/schema/unit_morale_break_modifiers.json @@ -0,0 +1,84 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Add unit_morale_break_modifiers table", + "author": "anibus", + "changes": [ + { + "createTable": { + "tableName": "unit_morale_break_modifiers", + "columns": [ + { + "column": { + "name": "id", + "type": "int", + "autoIncrement": true, + "constraints": { + "primaryKey": true, + "nullable": false + } + } + },{ + "column": { + "name": "reference", + "type": "varchar(255)" + } + },{ + "column": { + "name": "usage_type", + "type": "varchar(255)" + } + },{ + "column": { + "name": "value", + "type": "number" + } + },{ + "column": { + "name": "target", + "type": "varchar(255)" + } + },{ + "column": { + "name": "probability_of_applying", + "type": "number" + } + },{ + "column": { + "name": "exclusive", + "type": "boolean" + } + },{ + "column": { + "name": "application_type", + "type": "varchar(255)" + } + },{ + "column": { + "name": "unit_id", + "type": "int", + "constraints": { + "nullable": false + } + } + } + ] + } + }, + { + "addForeignKeyConstraint": + { + "baseColumnNames": "unit_id", + "baseTableName": "unit_morale_break_modifiers", + "constraintName": "fk_units_unit_morale_break_modifiers", + "referencedColumnNames": "id", + "referencedTableName": "units", + "onDelete": "CASCADE" + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/0.0.5/schema/units.json b/src/main/resources/db/0.0.5/schema/units.json new file mode 100644 index 0000000..a2725f0 --- /dev/null +++ b/src/main/resources/db/0.0.5/schema/units.json @@ -0,0 +1,25 @@ +{ + "databaseChangeLog": [ + { + "changeSet": { + "id": "Add mob bonus to units", + "author": "anibus", + "changes": [ + { + "addColumn": { + "columns": [ + { + "column": { + "name": "mob_value", + "type": "number" + } + } + ], + "tableName": "units" + } + } + ] + } + } + ] +} diff --git a/src/main/resources/db/changelog-master.json b/src/main/resources/db/changelog-master.json index b96527d..19ce301 100644 --- a/src/main/resources/db/changelog-master.json +++ b/src/main/resources/db/changelog-master.json @@ -389,6 +389,62 @@ "include": { "file": "db/0.0.4/data/area_filter.json" } + },{ + "include": { + "file": "db/0.0.5/schema/buildings.json" + } + },{ + "include": { + "file": "db/0.0.5/schema/unit_morale_break_modifiers.json" + } + },{ + "include": { + "file": "db/0.0.5/schema/ability_environments.json" + } + },{ + "include": { + "file": "db/0.0.5/schema/ability_environment_abilities.json" + } + },{ + "include": { + "file": "db/0.0.5/schema/death_explosions.json" + } + },{ + "include": { + "file": "db/0.0.5/schema/death_explosion_modifiers.json" + } + },{ + "include": { + "file": "db/0.0.5/schema/death_explosion_armors_piercing.json" + } + },{ + "include": { + "file": "db/0.0.5/schema/unit_death_explosion.json" + } + },{ + "include": { + "file": "db/0.0.5/schema/sergeant_death_explosion.json" + } + },{ + "include": { + "file": "db/0.0.5/schema/building_death_explosion.json" + } + },{ + "include": { + "file": "db/0.0.5/schema/ability_environment_death_explosion.json" + } + },{ + "include": { + "file": "db/0.0.5/schema/units.json" + } + },{ + "include": { + "file": "db/0.0.5/schema/sergeants.json" + } + },{ + "include": { + "file": "db/0.0.5/procedures/delete_mod_data_procedure.sql" + } } ] }