mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-23 03:23:17 -04:00
Unique: May Paradrop to [tileFilter] tiles up to [positiveAmount] tiles away
(#13586)
* Paradrop: Allow mods to enable paradropping from outside friendly territory * Fix Paratrooper range in Vanilla * Keep support for the deprecated unique * Update docs * Allow setting a destination tileFilter for Paradrops * Apply suggestion from @RobLoach * Apply suggestion from @RobLoach * Update language for paradrop
This commit is contained in:
parent
4819cf1053
commit
9b4ed0d4ff
@ -1362,7 +1362,7 @@
|
|||||||
"strength": 65,
|
"strength": 65,
|
||||||
"cost": 375,
|
"cost": 375,
|
||||||
"requiredTech": "Radar",
|
"requiredTech": "Radar",
|
||||||
"uniques": ["May Paradrop up to [5] tiles from inside friendly territory", "Never appears as a Barbarian unit"],
|
"uniques": ["May Paradrop to [Land] tiles up to [5] tiles away <in [{Friendly} {Land}] tiles>", "Never appears as a Barbarian unit"],
|
||||||
"attackSound": "shot"
|
"attackSound": "shot"
|
||||||
// upgradesTo "XCOM Squad", "No Movement Cost to Pillage" in BNW
|
// upgradesTo "XCOM Squad", "No Movement Cost to Pillage" in BNW
|
||||||
},
|
},
|
||||||
|
@ -1039,7 +1039,7 @@
|
|||||||
"strength": 65,
|
"strength": 65,
|
||||||
"cost": 375,
|
"cost": 375,
|
||||||
"requiredTech": "Radar",
|
"requiredTech": "Radar",
|
||||||
"uniques": ["May Paradrop up to [5] tiles from inside friendly territory", "Never appears as a Barbarian unit"],
|
"uniques": ["May Paradrop to [Land] tiles up to [5] tiles away <in [{Friendly} {Land}] tiles>", "Never appears as a Barbarian unit"],
|
||||||
"attackSound": "shot"
|
"attackSound": "shot"
|
||||||
// upgradesTo "XCOM Squad", "No Movement Cost to Pillage" in BNW
|
// upgradesTo "XCOM Squad", "No Movement Cost to Pillage" in BNW
|
||||||
},
|
},
|
||||||
|
@ -59,7 +59,9 @@ class MapUnitCache(private val mapUnit: MapUnit) {
|
|||||||
var canEnterCityStates: Boolean = false
|
var canEnterCityStates: Boolean = false
|
||||||
var costToDisembark: Float? = null
|
var costToDisembark: Float? = null
|
||||||
var costToEmbark: Float? = null
|
var costToEmbark: Float? = null
|
||||||
var paradropRange = 0
|
|
||||||
|
/** A hashmap where the key represents the tileFilter, and the value is how far away the tile could be */
|
||||||
|
val paradropDestinationTileFilters = mutableMapOf<String, Int>()
|
||||||
|
|
||||||
var hasUniqueToBuildImprovements = false // not canBuildImprovements to avoid confusion
|
var hasUniqueToBuildImprovements = false // not canBuildImprovements to avoid confusion
|
||||||
var hasUniqueToCreateWaterImprovements = false
|
var hasUniqueToCreateWaterImprovements = false
|
||||||
|
@ -289,7 +289,7 @@ class UnitMovement(val unit: MapUnit) {
|
|||||||
unit.baseUnit.movesLikeAirUnits ->
|
unit.baseUnit.movesLikeAirUnits ->
|
||||||
unit.currentTile.aerialDistanceTo(destination) <= unit.getMaxMovementForAirUnits()
|
unit.currentTile.aerialDistanceTo(destination) <= unit.getMaxMovementForAirUnits()
|
||||||
unit.isPreparingParadrop() ->
|
unit.isPreparingParadrop() ->
|
||||||
unit.currentTile.aerialDistanceTo(destination) <= unit.cache.paradropRange && canParadropOn(destination)
|
canParadropOn(destination, unit.currentTile.aerialDistanceTo(destination))
|
||||||
else ->
|
else ->
|
||||||
specificFunction(destination) // Note: Could pass destination as implicit closure from outer fun to lambda, but explicit is clearer
|
specificFunction(destination) // Note: Could pass destination as implicit closure from outer fun to lambda, but explicit is clearer
|
||||||
}
|
}
|
||||||
@ -303,9 +303,10 @@ class UnitMovement(val unit: MapUnit) {
|
|||||||
unit.cache.cannotMove -> sequenceOf(unit.getTile())
|
unit.cache.cannotMove -> sequenceOf(unit.getTile())
|
||||||
unit.baseUnit.movesLikeAirUnits ->
|
unit.baseUnit.movesLikeAirUnits ->
|
||||||
unit.getTile().getTilesInDistanceRange(IntRange(1, unit.getMaxMovementForAirUnits()))
|
unit.getTile().getTilesInDistanceRange(IntRange(1, unit.getMaxMovementForAirUnits()))
|
||||||
unit.isPreparingParadrop() ->
|
unit.isPreparingParadrop() -> {
|
||||||
unit.getTile().getTilesInDistance(unit.cache.paradropRange)
|
unit.getTile().getTilesInDistance(unit.cache.paradropDestinationTileFilters.maxOf { it.value } )
|
||||||
.filter { unit.movement.canParadropOn(it) }
|
.filter { unit.movement.canParadropOn(it, it.aerialDistanceTo(unit.getTile())) }
|
||||||
|
}
|
||||||
includeOtherEscortUnit && unit.isEscorting() -> {
|
includeOtherEscortUnit && unit.isEscorting() -> {
|
||||||
val otherUnitTiles = unit.getOtherEscortUnit()!!.movement.getReachableTilesInCurrentTurn(false).toSet()
|
val otherUnitTiles = unit.getOtherEscortUnit()!!.movement.getReachableTilesInCurrentTurn(false).toSet()
|
||||||
unit.movement.getDistanceToTiles().filter { otherUnitTiles.contains(it.key) }.keys.asSequence()
|
unit.movement.getDistanceToTiles().filter { otherUnitTiles.contains(it.key) }.keys.asSequence()
|
||||||
@ -636,12 +637,19 @@ class UnitMovement(val unit: MapUnit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Can a paratrooper land at this tile?
|
// Can a paratrooper land at this tile?
|
||||||
private fun canParadropOn(destination: Tile): Boolean {
|
private fun canParadropOn(destination: Tile, distance: Int): Boolean {
|
||||||
if (unit.cache.cannotMove) return false
|
if (unit.cache.cannotMove) return false
|
||||||
// Can only move to land tiles within range that are visible and not impassible
|
|
||||||
|
// Can only move to tiles within range that are visible and not impassible
|
||||||
// Based on some testing done in the base game
|
// Based on some testing done in the base game
|
||||||
if (!destination.isLand || destination.isImpassible() || !unit.civ.viewableTiles.contains(destination)) return false
|
if (destination.isImpassible() || !unit.civ.viewableTiles.contains(destination)) return false
|
||||||
return true
|
|
||||||
|
// The destination is valid if any of the `tileFilters` match, and is within range
|
||||||
|
for ((tileFilter, distanceAllowed) in unit.cache.paradropDestinationTileFilters) {
|
||||||
|
if (distance <= distanceAllowed && destination.matchesFilter(tileFilter, unit.civ)) return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -377,7 +377,9 @@ enum class UniqueType(
|
|||||||
PreventSpreadingReligion("Prevents spreading of religion to the city it is next to", UniqueTarget.Unit),
|
PreventSpreadingReligion("Prevents spreading of religion to the city it is next to", UniqueTarget.Unit),
|
||||||
RemoveOtherReligions("Removes other religions when spreading religion", UniqueTarget.Unit),
|
RemoveOtherReligions("Removes other religions when spreading religion", UniqueTarget.Unit),
|
||||||
|
|
||||||
MayParadrop("May Paradrop up to [amount] tiles from inside friendly territory", UniqueTarget.Unit),
|
@Deprecated("As of 4.17.4", ReplaceWith("May Paradrop to [Land] tiles up to [positiveAmount] tiles away <in [{Friendly} {Land}] tiles>"), DeprecationLevel.WARNING)
|
||||||
|
MayParadropOld("May Paradrop up to [positiveAmount] tiles from inside friendly territory", UniqueTarget.Unit),
|
||||||
|
MayParadrop("May Paradrop to [tileFilter] tiles up to [positiveAmount] tiles away", UniqueTarget.Unit),
|
||||||
CanAirsweep("Can perform Air Sweep", UniqueTarget.Unit),
|
CanAirsweep("Can perform Air Sweep", UniqueTarget.Unit),
|
||||||
|
|
||||||
CanSpeedupConstruction("Can speed up construction of a building", UniqueTarget.Unit),
|
CanSpeedupConstruction("Can speed up construction of a building", UniqueTarget.Unit),
|
||||||
|
@ -545,6 +545,8 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
|
|||||||
|
|
||||||
UniqueType.MayParadrop // Paradrop - 25% bonus
|
UniqueType.MayParadrop // Paradrop - 25% bonus
|
||||||
-> power += power / 4
|
-> power += power / 4
|
||||||
|
UniqueType.MayParadropOld // ParadropOld - 25% bonus
|
||||||
|
-> power += power / 4
|
||||||
UniqueType.MustSetUp // Must set up - 20 % penalty
|
UniqueType.MustSetUp // Must set up - 20 % penalty
|
||||||
-> power -= power / 5
|
-> power -= power / 5
|
||||||
UniqueType.AdditionalAttacks // Extra attacks - 20% bonus per extra attack
|
UniqueType.AdditionalAttacks // Extra attacks - 20% bonus per extra attack
|
||||||
|
@ -142,10 +142,29 @@ object UnitActionsFromUniques {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun getParadropActions(unit: MapUnit, tile: Tile): Sequence<UnitAction> {
|
internal fun getParadropActions(unit: MapUnit, tile: Tile): Sequence<UnitAction> {
|
||||||
val paradropUniques =
|
unit.cache.paradropDestinationTileFilters.clear()
|
||||||
unit.getMatchingUniques(UniqueType.MayParadrop)
|
|
||||||
if (!paradropUniques.any() || unit.isEmbarked()) return emptySequence()
|
// Support the old paradrop unique, going from Friendly Land to any Land tile
|
||||||
unit.cache.paradropRange = paradropUniques.maxOfOrNull { it.params[0] }!!.toInt()
|
val paradropOldUniques = unit.getMatchingUniques(UniqueType.MayParadropOld)
|
||||||
|
if (paradropOldUniques.any() && !unit.isEmbarked() && !unit.getTile().isWater && unit.getTile().isFriendlyTerritory(unit.civ)) {
|
||||||
|
unit.cache.paradropDestinationTileFilters["Land"] = paradropOldUniques.maxOf { it.params[0] }.toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve all parardrop uniques, considering the state of the unit
|
||||||
|
val paradropUniques = unit.getMatchingUniques(UniqueType.MayParadrop, unit.cache.state)
|
||||||
|
|
||||||
|
// Construct the list of possible destination tile filters, keeping the largest distance
|
||||||
|
for (unique in paradropUniques) {
|
||||||
|
val tileFilter = unique.params[0]
|
||||||
|
val distance = unique.params[1].toInt()
|
||||||
|
val existingDistance = unit.cache.paradropDestinationTileFilters[tileFilter]
|
||||||
|
if (existingDistance == null || distance > existingDistance) {
|
||||||
|
unit.cache.paradropDestinationTileFilters[tileFilter] = distance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unit.cache.paradropDestinationTileFilters.isEmpty()) return emptySequence()
|
||||||
|
|
||||||
return sequenceOf(UnitAction(UnitActionType.Paradrop,
|
return sequenceOf(UnitAction(UnitActionType.Paradrop,
|
||||||
isCurrentAction = unit.isPreparingParadrop(),
|
isCurrentAction = unit.isPreparingParadrop(),
|
||||||
useFrequency = 60f, // While it is important to see, it isn't nessesary used a lot
|
useFrequency = 60f, // While it is important to see, it isn't nessesary used a lot
|
||||||
@ -153,9 +172,7 @@ object UnitActionsFromUniques {
|
|||||||
if (unit.isPreparingParadrop()) unit.action = null
|
if (unit.isPreparingParadrop()) unit.action = null
|
||||||
else unit.action = UnitActionType.Paradrop.value
|
else unit.action = UnitActionType.Paradrop.value
|
||||||
}.takeIf {
|
}.takeIf {
|
||||||
!unit.hasUnitMovedThisTurn() &&
|
!unit.hasUnitMovedThisTurn()
|
||||||
tile.isFriendlyTerritory(unit.civ) &&
|
|
||||||
!tile.isWater
|
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1861,8 +1861,8 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
|
|||||||
??? example "Removes other religions when spreading religion"
|
??? example "Removes other religions when spreading religion"
|
||||||
Applicable to: Unit
|
Applicable to: Unit
|
||||||
|
|
||||||
??? example "May Paradrop up to [amount] tiles from inside friendly territory"
|
??? example "May Paradrop to [tileFilter] tiles up to [positiveAmount] tiles away"
|
||||||
Example: "May Paradrop up to [3] tiles from inside friendly territory"
|
Example: "May Paradrop to [Farm] tiles up to [3] tiles away"
|
||||||
|
|
||||||
Applicable to: Unit
|
Applicable to: Unit
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user