mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-05 15:59:50 +07:00
Revamped nukes again to closer match the original (#5892)
This commit is contained in:
@ -652,11 +652,7 @@ object Battle {
|
||||
|
||||
for (tile in hitTiles) {
|
||||
// Handle complicated effects
|
||||
when (strength) {
|
||||
1 -> nukeStrength1Effect(attacker, tile)
|
||||
2 -> nukeStrength2Effect(attacker, tile)
|
||||
else -> nukeStrength1Effect(attacker, tile)
|
||||
}
|
||||
doNukeExplosion(attacker, tile, strength)
|
||||
}
|
||||
|
||||
// Instead of postBattleAction() just destroy the unit, all other functions are not relevant
|
||||
@ -672,66 +668,48 @@ object Battle {
|
||||
attacker.unit.attacksThisTurn += 1
|
||||
}
|
||||
}
|
||||
|
||||
// todo: reduce extreme code duplication, parameterize probabilities where an unique already used
|
||||
private fun nukeStrength1Effect(attacker: MapUnitCombatant, tile: TileInfo) {
|
||||
|
||||
private fun doNukeExplosion(attacker: MapUnitCombatant, tile: TileInfo, nukeStrength: Int) {
|
||||
// https://forums.civfanatics.com/resources/unit-guide-modern-future-units-g-k.25628/
|
||||
// https://www.carlsguides.com/strategy/civilization5/units/aircraft-nukes.ph
|
||||
// Testing done by Ravignir
|
||||
// original source code: GenerateNuclearExplosionDamage(), ApplyNuclearExplosionDamage()
|
||||
|
||||
var damageModifierFromMissingResource = 1f
|
||||
val civResources = attacker.getCivInfo().getCivResourcesByName()
|
||||
for (resource in attacker.unit.baseUnit.getResourceRequirements().keys) {
|
||||
if (civResources[resource]!! < 0 && !attacker.getCivInfo().isBarbarian())
|
||||
damageModifierFromMissingResource *= 0.5f // I could not find a source for this number, but this felt about right
|
||||
}
|
||||
|
||||
// Decrease health & population of a hit city
|
||||
|
||||
// Damage city and reduce its population
|
||||
val city = tile.getCity()
|
||||
if (city != null && tile.position == city.location) {
|
||||
var populationLoss = city.population.population * (0.3 + Random().nextFloat() * 0.4)
|
||||
var populationLossReduced = false
|
||||
// Deprecated since 3.16.11
|
||||
for (unique in city.getLocalMatchingUniques("Population loss from nuclear attacks -[]%")) {
|
||||
populationLoss *= 1 - unique.params[0].toFloat() / 100f
|
||||
populationLossReduced = true
|
||||
}
|
||||
//
|
||||
for (unique in city.getMatchingUniques("Population loss from nuclear attacks []% []")) {
|
||||
if (!city.matchesFilter(unique.params[1])) continue
|
||||
populationLoss *= unique.params[0].toPercent()
|
||||
populationLossReduced = true
|
||||
}
|
||||
if (city.population.population < 5 && !populationLossReduced) {
|
||||
city.population.setPopulation(1) // For cities that cannot be destroyed, such as original capitals
|
||||
city.destroyCity()
|
||||
} else {
|
||||
city.population.addPopulation(-populationLoss.toInt())
|
||||
if (city.population.population < 1) city.population.setPopulation(1)
|
||||
city.population.unassignExtraPopulation()
|
||||
city.health -= ((0.5 + 0.25 * Random().nextFloat()) * city.health * damageModifierFromMissingResource).toInt()
|
||||
if (city.health < 1) city.health = 1
|
||||
}
|
||||
doNukeExplosionDamageToCity(city, nukeStrength, damageModifierFromMissingResource)
|
||||
postBattleNotifications(attacker, CityCombatant(city), city.getCenterTile())
|
||||
destroyIfDefeated(city.civInfo, attacker.getCivInfo())
|
||||
}
|
||||
|
||||
|
||||
// Damage and/or destroy units on the tile
|
||||
for (unit in tile.getUnits().toList()) { // toList so if it's destroyed there's no concurrent modification
|
||||
val defender = MapUnitCombatant(unit)
|
||||
if (defender.unit.isCivilian()) {
|
||||
unit.destroy() // destroy the unit
|
||||
} else {
|
||||
if (defender.unit.isCivilian() || nukeStrength >= 2) {
|
||||
unit.destroy()
|
||||
} else if (nukeStrength == 1) {
|
||||
defender.takeDamage(((40 + Random().nextInt(60)) * damageModifierFromMissingResource).toInt())
|
||||
} else if (nukeStrength == 0) {
|
||||
defender.takeDamage(((20 + Random().nextInt(30)) * damageModifierFromMissingResource).toInt())
|
||||
}
|
||||
postBattleNotifications(attacker, defender, defender.getTile())
|
||||
destroyIfDefeated(defender.getCivInfo(), attacker.getCivInfo())
|
||||
}
|
||||
|
||||
// Remove improvements, add fallout
|
||||
// Pillage improvements, remove roads, add fallout
|
||||
if (tile.improvement != null && !tile.getTileImprovement()!!.hasUnique(UniqueType.Indestructible)) {
|
||||
tile.turnsToImprovement = 2
|
||||
tile.improvementInProgress = tile.improvement
|
||||
tile.improvement = null
|
||||
}
|
||||
tile.improvementInProgress = null
|
||||
tile.turnsToImprovement = 0
|
||||
tile.roadStatus = RoadStatus.None
|
||||
if (tile.isLand && !tile.isImpassible() && !tile.terrainFeatures.contains("Fallout")) {
|
||||
if (tile.terrainFeatures.any { attacker.getCivInfo().gameInfo.ruleSet.terrains[it]!!.hasUnique(UniqueType.ResistsNukes) }) {
|
||||
@ -745,68 +723,33 @@ object Battle {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun nukeStrength2Effect(attacker: MapUnitCombatant, tile: TileInfo) {
|
||||
// https://forums.civfanatics.com/threads/unit-guide-modern-future-units-g-k.429987/#2
|
||||
// https://www.carlsguides.com/strategy/civilization5/units/aircraft-nukes.php
|
||||
// Testing done by Ravignir
|
||||
var damageModifierFromMissingResource = 1f
|
||||
val civResources = attacker.getCivInfo().getCivResourcesByName()
|
||||
for (resource in attacker.unit.baseUnit.getResourceRequirements().keys) {
|
||||
if (civResources[resource]!! < 0 && !attacker.getCivInfo().isBarbarian())
|
||||
damageModifierFromMissingResource *= 0.5f // I could not find a source for this number, but this felt about right
|
||||
|
||||
private fun doNukeExplosionDamageToCity(targetedCity: CityInfo, nukeStrength: Int, damageModifierFromMissingResource: Float) {
|
||||
if (nukeStrength > 1 && targetedCity.population.population < 5 && targetedCity.canBeDestroyed(true)) {
|
||||
targetedCity.destroyCity()
|
||||
return
|
||||
}
|
||||
val cityCombatant = CityCombatant(targetedCity)
|
||||
cityCombatant.takeDamage((cityCombatant.getHealth() * 0.5f * damageModifierFromMissingResource).toInt())
|
||||
|
||||
// Damage and/or destroy cities
|
||||
val city = tile.getCity()
|
||||
if (city != null && city.location == tile.position) {
|
||||
if (city.population.population < 5) {
|
||||
city.population.setPopulation(1) // For cities that cannot be destroyed, such as original capitals
|
||||
city.destroyCity()
|
||||
} else {
|
||||
var populationLoss = city.population.population * (0.6 + Random().nextFloat() * 0.2)
|
||||
var populationLossReduced = false
|
||||
for (unique in city.getMatchingUniques("Population loss from nuclear attacks []% []")) {
|
||||
if (!city.matchesFilter(unique.params[1]))
|
||||
populationLoss *= unique.params[0].toPercent()
|
||||
populationLossReduced = true
|
||||
}
|
||||
city.population.addPopulation(-populationLoss.toInt())
|
||||
if (city.population.population < 5 && populationLossReduced) city.population.setPopulation(5)
|
||||
if (city.population.population < 1) city.population.setPopulation(1)
|
||||
city.population.unassignExtraPopulation()
|
||||
city.health -= (0.5 * city.getMaxHealth() * damageModifierFromMissingResource).toInt()
|
||||
if (city.health < 1) city.health = 1
|
||||
var populationLoss = targetedCity.population.population *
|
||||
when (nukeStrength) {
|
||||
0 -> 0f
|
||||
1 -> (30 + Random().nextInt(40)) / 100f
|
||||
2 -> (60 + Random().nextInt(20)) / 100f
|
||||
else -> 1f
|
||||
}
|
||||
postBattleNotifications(attacker, CityCombatant(city), city.getCenterTile())
|
||||
destroyIfDefeated(city.civInfo, attacker.getCivInfo())
|
||||
}
|
||||
|
||||
// Destroy all hit units
|
||||
for (defender in tile.getUnits().toList()) { // toList to avoid concurrent modification exceptions
|
||||
defender.destroy()
|
||||
postBattleNotifications(attacker, MapUnitCombatant(defender), defender.currentTile)
|
||||
destroyIfDefeated(defender.civInfo, attacker.getCivInfo())
|
||||
}
|
||||
|
||||
// Remove improvements
|
||||
if (tile.improvement != null && !tile.getTileImprovement()!!.hasUnique(UniqueType.Indestructible)) {
|
||||
tile.improvement = null
|
||||
}
|
||||
tile.improvementInProgress = null
|
||||
tile.turnsToImprovement = 0
|
||||
tile.roadStatus = RoadStatus.None
|
||||
if (tile.isLand && !tile.isImpassible() && !tile.terrainFeatures.contains("Fallout")) {
|
||||
if (tile.terrainFeatures.any { attacker.getCivInfo().gameInfo.ruleSet.terrains[it]!!.hasUnique(UniqueType.ResistsNukes) }) {
|
||||
if (Random().nextFloat() < 0.25f) {
|
||||
tile.terrainFeatures.removeAll { attacker.getCivInfo().gameInfo.ruleSet.terrains[it]!!.hasUnique(UniqueType.DestroyableByNukes) }
|
||||
tile.terrainFeatures.add("Fallout")
|
||||
}
|
||||
} else if (Random().nextFloat() < 0.5f) {
|
||||
tile.terrainFeatures.removeAll { attacker.getCivInfo().gameInfo.ruleSet.terrains[it]!!.hasUnique(UniqueType.DestroyableByNukes) }
|
||||
tile.terrainFeatures.add("Fallout")
|
||||
// Deprecated since 3.16.11
|
||||
for (unique in targetedCity.getLocalMatchingUniques("Population loss from nuclear attacks -[]%")) {
|
||||
populationLoss *= 1 - unique.params[0].toFloat() / 100f
|
||||
}
|
||||
//
|
||||
for (unique in targetedCity.getMatchingUniques("Population loss from nuclear attacks []% []")) {
|
||||
if (!targetedCity.matchesFilter(unique.params[1])) continue
|
||||
populationLoss *= unique.params[0].toPercent()
|
||||
}
|
||||
targetedCity.population.addPopulation(-populationLoss.toInt())
|
||||
if (targetedCity.population.population < 1) targetedCity.population.setPopulation(1)
|
||||
}
|
||||
|
||||
private fun tryInterceptAirAttack(attacker: MapUnitCombatant, attackedTile:TileInfo, interceptingCiv:CivilizationInfo) {
|
||||
|
@ -23,17 +23,17 @@ Applicable to: Global, FollowerBelief, Improvement
|
||||
#### [stats] [cityFilter]
|
||||
Example: "[+1 Gold, +2 Production] [in all cities]"
|
||||
|
||||
Applicable to: Global
|
||||
Applicable to: Global, FollowerBelief
|
||||
|
||||
#### [stats] from every specialist [cityFilter]
|
||||
Example: "[+1 Gold, +2 Production] from every specialist [in all cities]"
|
||||
|
||||
Applicable to: Global
|
||||
Applicable to: Global, FollowerBelief
|
||||
|
||||
#### [stats] per [amount] population [cityFilter]
|
||||
Example: "[+1 Gold, +2 Production] per [20] population [in all cities]"
|
||||
|
||||
Applicable to: Global
|
||||
Applicable to: Global, FollowerBelief
|
||||
|
||||
#### [stats] in cities with [amount] or more population
|
||||
Example: "[+1 Gold, +2 Production] in cities with [20] or more population"
|
||||
@ -45,11 +45,6 @@ Example: "[+1 Gold, +2 Production] in cities on [Grassland] tiles"
|
||||
|
||||
Applicable to: Global, FollowerBelief
|
||||
|
||||
#### [stats] per turn from cities before [tech/policy]
|
||||
Example: "[+1 Gold, +2 Production] per turn from cities before [tech/policy]"
|
||||
|
||||
Applicable to: Global
|
||||
|
||||
#### [stats] whenever a Great Person is expended
|
||||
Example: "[+1 Gold, +2 Production] whenever a Great Person is expended"
|
||||
|
||||
@ -58,7 +53,7 @@ Applicable to: Global
|
||||
#### [stats] from [tileFilter] tiles [cityFilter]
|
||||
Example: "[+1 Gold, +2 Production] from [Farm] tiles [in all cities]"
|
||||
|
||||
Applicable to: Global
|
||||
Applicable to: Global, FollowerBelief
|
||||
|
||||
#### [stats] from [tileFilter] tiles without [tileFilter] [cityFilter]
|
||||
Example: "[+1 Gold, +2 Production] from [Farm] tiles without [Farm] [in all cities]"
|
||||
@ -73,7 +68,7 @@ Applicable to: Global, FollowerBelief
|
||||
#### [amount]% [stat]
|
||||
Example: "[20]% [Culture]"
|
||||
|
||||
Applicable to: Global
|
||||
Applicable to: Global, FollowerBelief
|
||||
|
||||
#### [amount]% [stat] from City-States
|
||||
Example: "[20]% [Culture] from City-States"
|
||||
@ -83,7 +78,7 @@ Applicable to: Global
|
||||
#### [amount]% [stat] [cityFilter]
|
||||
Example: "[20]% [Culture] [in all cities]"
|
||||
|
||||
Applicable to: Global
|
||||
Applicable to: Global, FollowerBelief
|
||||
|
||||
#### [amount]% Production when constructing [buildingFilter] wonders [cityFilter]
|
||||
Example: "[20]% Production when constructing [buildingFilter] wonders [in all cities]"
|
||||
@ -93,17 +88,17 @@ Applicable to: Global, FollowerBelief, Resource
|
||||
#### [amount]% Production when constructing [buildingFilter] buildings [cityFilter]
|
||||
Example: "[20]% Production when constructing [buildingFilter] buildings [in all cities]"
|
||||
|
||||
Applicable to: Global
|
||||
Applicable to: Global, FollowerBelief
|
||||
|
||||
#### [amount]% Production when constructing [baseUnitFilter] units [cityFilter]
|
||||
Example: "[20]% Production when constructing [Melee] units [in all cities]"
|
||||
|
||||
Applicable to: Global
|
||||
Applicable to: Global, FollowerBelief
|
||||
|
||||
#### [amount]% unhappiness from population [cityFilter]
|
||||
Example: "[20]% unhappiness from population [in all cities]"
|
||||
|
||||
Applicable to: Global
|
||||
Applicable to: Global, FollowerBelief
|
||||
|
||||
#### Military Units gifted from City-States start with [amount] XP
|
||||
Example: "Military Units gifted from City-States start with [20] XP"
|
||||
@ -154,7 +149,7 @@ Applicable to: Global
|
||||
#### [amount]% food consumption by specialists [cityFilter]
|
||||
Example: "[20]% food consumption by specialists [in all cities]"
|
||||
|
||||
Applicable to: Global
|
||||
Applicable to: Global, FollowerBelief
|
||||
|
||||
#### [amount]% of excess happiness converted to [stat]
|
||||
Example: "[20]% of excess happiness converted to [Culture]"
|
||||
@ -164,12 +159,12 @@ Applicable to: Global
|
||||
#### May buy [baseUnitFilter] units for [amount] [stat] [cityFilter] at an increasing price ([amount])
|
||||
Example: "May buy [Melee] units for [20] [Culture] [in all cities] at an increasing price ([20])"
|
||||
|
||||
Applicable to: Global
|
||||
Applicable to: Global, FollowerBelief
|
||||
|
||||
#### May buy [buildingFilter] buildings for [amount] [stat] [cityFilter] at an increasing price ([amount])
|
||||
Example: "May buy [buildingFilter] buildings for [20] [Culture] [in all cities] at an increasing price ([20])"
|
||||
|
||||
Applicable to: Global
|
||||
Applicable to: Global, FollowerBelief
|
||||
|
||||
#### May buy [baseUnitFilter] units for [amount] [stat] [cityFilter]
|
||||
Example: "May buy [Melee] units for [20] [Culture] [in all cities]"
|
||||
@ -201,6 +196,19 @@ Example: "May buy [buildingFilter] buildings with [Culture] for [20] times their
|
||||
|
||||
Applicable to: Global, FollowerBelief
|
||||
|
||||
#### Receive a free Great Person at the end of every [comment] (every 394 years), after researching [tech]. Each bonus person can only be chosen once.
|
||||
Example: "Receive a free Great Person at the end of every [comment] (every 394 years), after researching [tech]. Each bonus person can only be chosen once."
|
||||
|
||||
Applicable to: Global
|
||||
|
||||
#### Once The Long Count activates, the year on the world screen displays as the traditional Mayan Long Count.
|
||||
Applicable to: Global
|
||||
|
||||
#### Retain [amount]% of the happiness from a luxury after the last copy has been traded away
|
||||
Example: "Retain [20]% of the happiness from a luxury after the last copy has been traded away"
|
||||
|
||||
Applicable to: Global
|
||||
|
||||
#### Enables Research agreements
|
||||
Applicable to: Global
|
||||
|
||||
@ -210,6 +218,11 @@ Applicable to: Global
|
||||
#### Triggers a Cultural Victory upon completion
|
||||
Applicable to: Global
|
||||
|
||||
#### Cannot build [baseUnitFilter] units
|
||||
Example: "Cannot build [Melee] units"
|
||||
|
||||
Applicable to: Global
|
||||
|
||||
#### [amount]% Strength
|
||||
Example: "[20]% Strength"
|
||||
|
||||
@ -348,24 +361,6 @@ Applicable to: Global
|
||||
#### Will not be chosen for new games
|
||||
Applicable to: Nation
|
||||
|
||||
#### Receive a free Great Person at the end of every [comment] (every 394 years), after researching [tech]. Each bonus person can only be chosen once.
|
||||
Example: "Receive a free Great Person at the end of every [comment] (every 394 years), after researching [tech]. Each bonus person can only be chosen once."
|
||||
|
||||
Applicable to: Nation
|
||||
|
||||
#### Once The Long Count activates, the year on the world screen displays as the traditional Mayan Long Count.
|
||||
Applicable to: Nation
|
||||
|
||||
#### Retain [amount]% of the happiness from a luxury after the last copy has been traded away
|
||||
Example: "Retain [20]% of the happiness from a luxury after the last copy has been traded away"
|
||||
|
||||
Applicable to: Nation
|
||||
|
||||
#### Cannot build [baseUnitFilter] units
|
||||
Example: "Cannot build [Melee] units"
|
||||
|
||||
Applicable to: Nation
|
||||
|
||||
## FollowerBelief uniques
|
||||
#### [amount]% [stat] from every follower, up to [amount]%
|
||||
Example: "[20]% [Culture] from every follower, up to [20]%"
|
||||
@ -378,9 +373,6 @@ Example: "Earn [20]% of [Wounded] unit's [costOrStrength] as [Culture] when kill
|
||||
Applicable to: FollowerBelief
|
||||
|
||||
## Building uniques
|
||||
#### Remove extra unhappiness from annexed cities
|
||||
Applicable to: Building
|
||||
|
||||
#### Consumes [amount] [resource]
|
||||
Example: "Consumes [20] [Iron]"
|
||||
|
||||
@ -465,6 +457,9 @@ Applicable to: Building
|
||||
#### Unsellable
|
||||
Applicable to: Building
|
||||
|
||||
#### Remove extra unhappiness from annexed cities
|
||||
Applicable to: Building
|
||||
|
||||
#### Spaceship part
|
||||
Applicable to: Building, Unit
|
||||
|
||||
@ -1044,6 +1039,7 @@ Example: "<in all except [regionType] Regions>"
|
||||
Applicable to: Conditional
|
||||
|
||||
## Deprecated uniques
|
||||
- "[stats] per turn from cities before [tech/policy]" - Deprecated As of 3.18.14, replace with "[stats] [in all cities] <before discovering [tech]> OR [stats] [in all cities] <before adopting [policy]>"
|
||||
- "+[amount]% [stat] [cityFilter]" - Deprecated As of 3.17.10, replace with "[+amount]% [stat] [cityFilter]"
|
||||
- "+[amount]% [stat] in all cities" - Deprecated As of 3.17.10, replace with "[+amount]% [stat] [in all cities]"
|
||||
- "[amount]% [stat] while the empire is happy" - Deprecated As of 3.17.1, replace with "[amount]% [stat] [in all cities] <while the empire is happy>"
|
||||
|
Reference in New Issue
Block a user