Updated promotions - make more generalizable, update to G&K (#4292)

* Generalized the "Heal Instantly" promotion

* Extended "Indirect Fire" to WaterRanged units, conform the main game

* Generalized Extend Range, Operational Range

* Generalized "logistics"

* Typo

* Generalized the healing from "Medic"

* Implemented requested changes

* Generalized "[amount] Movement"; "[amount] Visibility Range"

* Added survavalism promotions

* Updated Boarding Party strength bonus values to G&K

* Implemented requested changes
This commit is contained in:
Xander Lenstra
2021-06-30 16:09:02 +02:00
committed by GitHub
parent 8b7804b19a
commit a0cf30831c
6 changed files with 112 additions and 53 deletions

View File

@ -6,7 +6,6 @@ import com.unciv.logic.city.CityInfo
import com.unciv.logic.civilization.*
import com.unciv.logic.civilization.diplomacy.DiplomaticModifiers
import com.unciv.logic.civilization.diplomacy.DiplomaticStatus
import com.unciv.logic.map.MapUnit
import com.unciv.logic.map.RoadStatus
import com.unciv.logic.map.TileInfo
import com.unciv.models.AttackableTile
@ -15,7 +14,6 @@ import com.unciv.models.ruleset.unit.UnitType
import com.unciv.models.stats.Stat
import com.unciv.models.translations.tr
import java.util.*
import kotlin.math.min
import kotlin.math.max
/**
@ -250,8 +248,7 @@ object Battle {
private fun reduceAttackerMovementPointsAndAttacks(attacker: ICombatant, defender: ICombatant) {
if (attacker is MapUnitCombatant) {
val unit = attacker.unit
if (unit.hasUnique("Can move after attacking")
|| (unit.hasUnique("1 additional attack per turn") && unit.attacksThisTurn == 0)) {
if (unit.hasUnique("Can move after attacking") || unit.maxAttacksPerTurn() > unit.attacksThisTurn) {
// if it was a melee attack and we won, then the unit ALREADY got movement points deducted,
// for the movement to the enemy's tile!
// and if it's an air unit, it only has 1 movement anyway, so...

View File

@ -141,8 +141,11 @@ class MapUnit {
if (isEmbarked()) return getEmbarkedMovement()
var movement = baseUnit.movement
movement += getUniques().count { it.text == "+1 Movement" }
movement += getMatchingUniques("[] Movement").sumBy { it.params[0].toInt() }
// Deprecated since 3.15.6
movement += getUniques().count { it.text == "+1 Movement" }
//
// Deprecated since 3.14.17
if (type.isMilitary() && type.isWaterUnit() && civInfo.hasUnique("All military naval units receive +1 movement and +1 sight")) {
movement += 1
@ -206,15 +209,21 @@ class MapUnit {
*/
private fun getVisibilityRange(): Int {
var visibilityRange = 2
visibilityRange += getUniques().count { it.text == "+1 Visibility Range" }
for (unique in civInfo.getMatchingUniques("+[] Sight for all [] units"))
if (matchesFilter(unique.params[1]))
visibilityRange += unique.params[0].toInt()
if (hasUnique("+2 Visibility Range")) visibilityRange += 2 // This shouldn't be stackable
visibilityRange += getMatchingUniques("[] Visibility Range").sumBy { it.params[0].toInt() }
if (hasUnique("Limited Visibility")) visibilityRange -= 1
// Deprecated since 3.15.6
visibilityRange += getUniques().count { it.text == "+1 Visibility Range" }
if (hasUnique("+2 Visibility Range")) visibilityRange += 2 // This shouldn't be stackable
//
// Deprecated since 3.15.1
if (civInfo.hasUnique("+1 Sight for all land military units") && type.isMilitary() && type.isLandUnit())
visibilityRange += 1
if (civInfo.hasUnique("+1 Sight for all land military units") && type.isMilitary() && type.isLandUnit())
visibilityRange += 1
//
// Deprecated since 3.14.17
if (type.isMilitary() && type.isWaterUnit() && civInfo.hasUnique("All military naval units receive +1 movement and +1 sight"))
@ -273,18 +282,28 @@ class MapUnit {
return true
}
fun maxAttacksPerTurn(): Int {
var maxAttacksPerTurn = 1 + getMatchingUniques("[] additional attacks per turn").sumBy { it.params[0].toInt() }
// Deprecated since 3.15.6
if (hasUnique("+1 additional attack per turn"))
maxAttacksPerTurn++
//
return maxAttacksPerTurn
}
fun canAttack(): Boolean {
if (currentMovement == 0f) return false
if (attacksThisTurn > 0 && !hasUnique("1 additional attack per turn")) return false
if (attacksThisTurn > 1) return false
return true
return attacksThisTurn < maxAttacksPerTurn()
}
fun getRange(): Int {
if (type.isMelee()) return 1
var range = baseUnit().range
if (hasUnique("+1 Range")) range++
if (hasUnique("+2 Range")) range += 2
// Deprecated since 3.15.6
if (hasUnique("+1 Range")) range++
if (hasUnique("+2 Range")) range += 2
//
range += getMatchingUniques("[] Range").sumBy { it.params[0].toInt() }
return range
}
@ -375,8 +394,11 @@ class MapUnit {
private fun adjacentHealingBonus(): Int {
var healingBonus = 0
if (hasUnique("This unit and all others in adjacent tiles heal 5 additional HP per turn")) healingBonus += 5
if (hasUnique("This unit and all others in adjacent tiles heal 5 additional HP. This unit heals 5 additional HP outside of friendly territory.")) healingBonus += 5
healingBonus += getMatchingUniques("All adjacent units heal [] HP when healing").sumBy { it.params[0].toInt() }
// Deprecated since 3.15.6
if (hasUnique("This unit and all others in adjacent tiles heal 5 additional HP per turn")) healingBonus += 5
if (hasUnique("This unit and all others in adjacent tiles heal 5 additional HP. This unit heals 5 additional HP outside of friendly territory.")) healingBonus += 5
//
return healingBonus
}
@ -507,7 +529,11 @@ class MapUnit {
var amountToHealBy = rankTileForHealing(getTile())
if (amountToHealBy == 0) return
if (hasUnique("+10 HP when healing")) amountToHealBy += 10
// Deprecated since 3.15.6
if (hasUnique("+10 HP when healing")) amountToHealBy += 10
//
amountToHealBy += getMatchingUniques("[] HP when healing").sumBy { it.params[0].toInt() }
val maxAdjacentHealingBonus = currentTile.getTilesInDistance(1)
.flatMap { it.getUnits().asSequence() }.map { it.adjacentHealingBonus() }.maxOrNull()
if (maxAdjacentHealingBonus != null)
@ -535,11 +561,20 @@ class MapUnit {
else -> 5 // Enemy territory
}
if (hasUnique("This unit and all others in adjacent tiles heal 5 additional HP. This unit heals 5 additional HP outside of friendly territory.")
&& !isFriendlyTerritory
&& healing > 0
)// Additional healing from medic is only applied when the unit is able to heal
healing += 5
// Deprecated since 3.15.6
if (hasUnique("This unit and all others in adjacent tiles heal 5 additional HP. This unit heals 5 additional HP outside of friendly territory.")
&& !isFriendlyTerritory
&& healing > 0
)// Additional healing from medic is only applied when the unit is able to heal
healing += 5
//
if (healing > 0) {
for (unique in getMatchingUniques("[] HP when healing in [] tiles")) {
if (tileInfo.matchesFilter(unique.params[1])) {
healing += unique.params[0].toInt()
}
}
}
return healing
}

View File

@ -415,8 +415,8 @@ open class TileInfo {
naturalWonder -> true
"Open terrain" -> !isRoughTerrain()
"Rough terrain" -> isRoughTerrain()
"Foreign Land" -> observingCiv != null && !isFriendlyTerritory(observingCiv)
"Friendly Land" -> observingCiv != null && isFriendlyTerritory(observingCiv)
"Foreign Land", "Foreign" -> observingCiv != null && !isFriendlyTerritory(observingCiv)
"Friendly Land", "Friendly" -> observingCiv != null && isFriendlyTerritory(observingCiv)
resource -> observingCiv != null && hasViewableResource(observingCiv)
else -> {
if (terrainFeatures.contains(filter)) return true

View File

@ -26,8 +26,12 @@ class UnitPromotions{
numberOfPromotions++
}
if(promotionName=="Heal Instantly") unit.healBy(50)
else promotions.add(promotionName)
val promotion = unit.civInfo.gameInfo.ruleSet.unitPromotions[promotionName]!!
doDirectPromotionEffects(promotion)
// This usage of a promotion name as its identifier is deprecated since 3.15.6
if (promotionName != "Heal Instantly" && promotion.uniqueObjects.none { it.placeholderText == "Doing so will consume this opportunity to choose a Promotion" })
promotions.add(promotionName)
unit.updateUniques()
@ -36,6 +40,11 @@ class UnitPromotions{
// So, if the addPromotion was triggered from there, simply don't update
unit.updateVisibleTiles() // some promotions/uniques give the unit bonus sight
}
fun doDirectPromotionEffects(promotion: Promotion) {
for (unique in promotion.uniqueObjects.filter { it.placeholderText == "Heal this unit by [] HP"})
unit.healBy(unique.params[0].toInt())
}
fun getAvailablePromotions(): List<Promotion> {
return unit.civInfo.gameInfo.ruleSet.unitPromotions.values