mirror of
https://github.com/yairm210/Unciv.git
synced 2025-02-11 11:28:03 +07:00
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:
parent
8b7804b19a
commit
a0cf30831c
@ -2,7 +2,7 @@
|
||||
|
||||
{
|
||||
"name": "Heal Instantly",
|
||||
"effect": "Heal this Unit by 50 HP; Doing so will consume this opportunity to choose a Promotion",
|
||||
"uniques": ["Heal this Unit by [50] HP", "Doing so will consume this opportunity to choose a Promotion"],
|
||||
"unitTypes": ["Melee","Mounted","Scout","Siege","Ranged","Armor","WaterMelee","WaterRanged","WaterSubmarine"]
|
||||
},
|
||||
|
||||
@ -52,14 +52,14 @@
|
||||
{
|
||||
"name": "Extended Range",
|
||||
"prerequisites": ["Accuracy III","Barrage III","Targeting II","Bombardment II", "Wolfpack II"],
|
||||
"effect": "+1 Range",
|
||||
"effect": "[+1] Range",
|
||||
"unitTypes": ["Ranged","Siege","WaterRanged","WaterSubmarine"]
|
||||
},
|
||||
{
|
||||
"name": "Indirect Fire",
|
||||
"prerequisites": ["Accuracy III","Barrage III"],
|
||||
"prerequisites": ["Accuracy III", "Barrage III", "Bombardment II", "Targeting II"],
|
||||
"effect": "Ranged attacks may be performed over obstacles",
|
||||
"unitTypes": ["Ranged","Siege"]
|
||||
"unitTypes": ["Ranged","Siege","WaterRanged"]
|
||||
},
|
||||
|
||||
// Melee, Mounted+Armor
|
||||
@ -112,7 +112,7 @@
|
||||
},
|
||||
{
|
||||
"name": "Formation I",
|
||||
"prerequisites": ["Shock II","Drill II"],
|
||||
"prerequisites": ["Shock II","Drill II"], // G&K also has Accuracy II & Barrage II as possible prerequisites for this, but I couldn't find a source for the unittypes
|
||||
"effect": "+[33]% Strength vs [Mounted]",
|
||||
"unitTypes": ["Melee","Mounted"]
|
||||
},
|
||||
@ -126,13 +126,15 @@
|
||||
{
|
||||
"name": "Blitz",
|
||||
"prerequisites": ["Shock III","Drill III"],
|
||||
"effect": "1 additional attack per turn",
|
||||
"effect": "[1] additional attacks per turn",
|
||||
"unitTypes": ["Melee","Mounted","Armor"]
|
||||
},
|
||||
{
|
||||
"name": "Woodsman",
|
||||
"prerequisites": ["Shock III","Drill III"],
|
||||
"effect": "Double movement rate through Forest and Jungle",
|
||||
"effect": "Double movement rate through Forest and Jungle",
|
||||
// This could be generalized: ["-[50]% movement costs through [Forest] tiles", "-[50]% movement costs through [Jungle] tiles"],
|
||||
// but with how getMovementCostBetweenAdjacentTiles() is optimized, that's difficult to implement.
|
||||
"unitTypes": ["Melee"]
|
||||
},
|
||||
{
|
||||
@ -143,33 +145,49 @@
|
||||
},
|
||||
{
|
||||
"name": "Medic",
|
||||
"prerequisites": ["Shock I", "Drill I", "Scouting II"],
|
||||
"effect": "This unit and all others in adjacent tiles heal 5 additional HP per turn",
|
||||
"prerequisites": ["Shock I", "Drill I", "Scouting II", "Survivalism II"],
|
||||
"uniques": ["[+5] HP when healing", "All adjacent units heal [5] HP when healing"],
|
||||
"unitTypes": ["Melee","Mounted","Scout"]
|
||||
},
|
||||
{
|
||||
"name": "Medic II",
|
||||
"prerequisites": ["Medic"],
|
||||
"effect": "This unit and all others in adjacent tiles heal 5 additional HP. This unit heals 5 additional HP outside of friendly territory.",
|
||||
"uniques": ["[+5] HP when healing", "All adjacent units heal [5] HP when healing",
|
||||
"[+5] HP when healing in [Foreign Land] tiles"],
|
||||
"unitTypes": ["Melee","Mounted","Scout"]
|
||||
},
|
||||
|
||||
// Scout
|
||||
{
|
||||
"name": "Scouting I",
|
||||
"effect": "+1 Visibility Range",
|
||||
"effect": "[+1] Visibility Range",
|
||||
"unitTypes": ["Scout"]
|
||||
},
|
||||
{
|
||||
"name": "Scouting II",
|
||||
"prerequisites": ["Scouting I"],
|
||||
"effect": "+1 Movement",
|
||||
"prerequisites": ["Scouting II"],
|
||||
"effect": "[+1] Visibility Range",
|
||||
"unitTypes": ["Scout"]
|
||||
},
|
||||
{
|
||||
"name": "Scouting III",
|
||||
"prerequisites": ["Scouting II"],
|
||||
"effect": "+1 Visibility Range",
|
||||
"prerequisites": ["Scouting I"],
|
||||
"effect": "[+1] Movement",
|
||||
"unitTypes": ["Scout"]
|
||||
},
|
||||
{
|
||||
"name": "Survivalism I",
|
||||
"uniques": ["[+5] HP when healing in [Foreign Land] tiles", "+[25]% Strength when defending"],
|
||||
"unitTypes": ["Scout"]
|
||||
},
|
||||
{
|
||||
"name": "Survivalism II",
|
||||
"uniques": ["[+5] HP when healing in [Foreign Land] tiles", "+[25]% Strength when defending"],
|
||||
"unitTypes": ["Scout"]
|
||||
},
|
||||
{
|
||||
"name": "Survivalism III",
|
||||
"uniques": ["Unit will heal every turn, even if it performs an action", "May withdraw before melee ([75]%)"], // This number is not based on any source
|
||||
"unitTypes": ["Scout"]
|
||||
},
|
||||
|
||||
@ -177,19 +195,19 @@
|
||||
// Water melee
|
||||
{
|
||||
"name": "Boarding Party I",
|
||||
"effect": "+[33]% Strength vs [water units]",
|
||||
"effect": "+[15]% Strength vs [water units]",
|
||||
"unitTypes": ["WaterMelee"]
|
||||
},
|
||||
{
|
||||
"name": "Boarding Party II",
|
||||
"prerequisites": ["Boarding Party I"],
|
||||
"effect": "+[33]% Strength vs [water units]",
|
||||
"effect": "+[15]% Strength vs [water units]",
|
||||
"unitTypes": ["WaterMelee"]
|
||||
},
|
||||
{
|
||||
"name": "Boarding Party III",
|
||||
"prerequisites": ["Boarding Party II"],
|
||||
"effect": "+[33]% Strength vs [water units]",
|
||||
"effect": "+[15]% Strength vs [water units]",
|
||||
"unitTypes": ["WaterMelee"]
|
||||
},
|
||||
|
||||
@ -339,7 +357,7 @@
|
||||
{
|
||||
"name": "Operational Range",
|
||||
"prerequisites": ["Interception I", /*"Dogfighting I",*/ "Siege I", "Bombardment I"],
|
||||
"effect": "+2 Range",
|
||||
"effect": "[+2] Range",
|
||||
"unitTypes": ["Fighter","Bomber"]
|
||||
},
|
||||
{
|
||||
@ -372,13 +390,13 @@
|
||||
"name": "Mobility",
|
||||
"prerequisites": ["Shock II","Drill II","Targeting I",
|
||||
"Bombardment I","Boarding Party I", "Coastal Raider I", "Wolfpack I"],
|
||||
"effect": "+1 Movement",
|
||||
"effect": "+[1] Movement",
|
||||
"unitTypes": ["Mounted","WaterMelee","WaterRanged","Armor","WaterSubmarine"]
|
||||
},
|
||||
{
|
||||
"name": "Sentry",
|
||||
"prerequisites": ["Accuracy I","Barrage I","Shock II","Drill II","Bombardment I","Targeting I","Boarding Party I","Coastal Raider I"],
|
||||
"effect": "+1 Visibility Range",
|
||||
"effect": "[+1] Visibility Range",
|
||||
"unitTypes": ["Melee","Mounted","WaterRanged","Armor","WaterMelee"]
|
||||
},
|
||||
{
|
||||
|
@ -251,7 +251,7 @@
|
||||
"requiredTech": "Bronze Working",
|
||||
"obsoleteTech": "Civil Service",
|
||||
"upgradesTo": "Pikeman",
|
||||
"uniques": ["+[50]% Strength vs [Mounted]","+10 HP when healing"],
|
||||
"uniques": ["+[50]% Strength vs [Mounted]","+[10] HP when healing"],
|
||||
"attackSound": "metalhit"
|
||||
},
|
||||
/*
|
||||
@ -493,7 +493,7 @@
|
||||
"requiredResource": "Horses",
|
||||
"upgradesTo": "Cavalry",
|
||||
"obsoleteTech": "Military Science",
|
||||
"uniques": ["Can move after attacking","No defensive terrain bonus", "Founds a new city", "+2 Visibility Range", "Defense bonus when embarked"],
|
||||
"uniques": ["Can move after attacking","No defensive terrain bonus", "Founds a new city", "[+2] Visibility Range", "Defense bonus when embarked"],
|
||||
"attackSound": "horse"
|
||||
//Conquistador should have no penalty attacking cities
|
||||
//Ability to found new cities can only be used on a foreign continent that does not contain the Spanish capital.
|
||||
@ -674,7 +674,7 @@
|
||||
"requiredTech": "Astronomy",
|
||||
"upgradesTo": "Ironclad",
|
||||
"obsoleteTech": "Combustion",
|
||||
"uniques": ["+1 Visibility Range","May withdraw before melee ([80]%)"],
|
||||
"uniques": ["[+1] Visibility Range", "May withdraw before melee ([80]%)"],
|
||||
"hurryCostModifier": 30
|
||||
},
|
||||
{
|
||||
@ -781,7 +781,7 @@
|
||||
"rangedStrength": 35,
|
||||
"cost": 185,
|
||||
"requiredResource": "Iron",
|
||||
"uniques": ["+1 Visibility Range"],
|
||||
"uniques": ["[+1] Visibility Range"],
|
||||
"requiredTech": "Navigation",
|
||||
"obsoleteTech": "Electronics",
|
||||
"upgradesTo": "Battleship",
|
||||
@ -812,7 +812,7 @@
|
||||
"requiredTech": "Metallurgy",
|
||||
"requiredResource": "Horses",
|
||||
"uniques": ["Can move after attacking","No defensive terrain bonus","Penalty vs City 33%",
|
||||
"+1 Visibility Range", "No movement cost to pillage"],
|
||||
"[+1] Visibility Range", "No movement cost to pillage"],
|
||||
"promotions": ["Formation I"],
|
||||
"upgradesTo": "Anti-Tank Gun",
|
||||
"obsoleteTech": "Combined Arms",
|
||||
@ -1289,7 +1289,7 @@
|
||||
"cost": 425,
|
||||
"requiredTech": "Telecommunications",
|
||||
"uniques": ["+[75]% Strength when attacking", "Invisible to others", "Can only attack water",
|
||||
"Can attack submarines", "Can enter ice tiles", "+1 Visibility Range", "Can carry [2] [Missile] units"]
|
||||
"Can attack submarines", "Can enter ice tiles", "[+1] Visibility Range", "Can carry [2] [Missile] units"]
|
||||
},
|
||||
{
|
||||
"name": "Mechanized Infantry",
|
||||
|
@ -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...
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user