mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-28 14:24:43 -04:00
Submarines are now visible to adjacent units, and once turned visible, can be attacked by all enemy units (#5001)
* Submarines are now visible to adjacent units, and once turned visible, can attack be all enemy units * Deprecation & translation of unique saving
This commit is contained in:
parent
7dd7e0b278
commit
85e4a68ea1
@ -50,7 +50,7 @@
|
|||||||
{
|
{
|
||||||
"name": "Submarine",
|
"name": "Submarine",
|
||||||
"movementType": "Water",
|
"movementType": "Water",
|
||||||
"uniques": ["Can enter ice tiles", "Invisible to others"]
|
"uniques": ["Can enter ice tiles", "Invisible to non-adjacent units", "Can see invisible [Submarine] units"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Aircraft Carrier",
|
"name": "Aircraft Carrier",
|
||||||
|
@ -1034,7 +1034,7 @@
|
|||||||
"cost": 325,
|
"cost": 325,
|
||||||
"requiredTech": "Refrigeration",
|
"requiredTech": "Refrigeration",
|
||||||
"upgradesTo": "Nuclear Submarine",
|
"upgradesTo": "Nuclear Submarine",
|
||||||
"uniques": ["+[75]% Strength when attacking", "Can only attack [Water] tiles", "Can attack submarines"],
|
"uniques": ["+[75]% Strength when attacking", "Can only attack [Water] tiles"],
|
||||||
"attackSound": "torpedo"
|
"attackSound": "torpedo"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -1173,7 +1173,7 @@
|
|||||||
"interceptRange": 2,
|
"interceptRange": 2,
|
||||||
"cost": 375,
|
"cost": 375,
|
||||||
"requiredTech": "Combustion",
|
"requiredTech": "Combustion",
|
||||||
"uniques": ["Can attack submarines", "[40]% chance to intercept air attacks",
|
"uniques": ["Can see invisible [Submarine] units", "[40]% chance to intercept air attacks",
|
||||||
"May withdraw before melee ([80]%)", "+[100]% Strength vs [submarine units]"],
|
"May withdraw before melee ([80]%)", "+[100]% Strength vs [submarine units]"],
|
||||||
"attackSound": "shipguns"
|
"attackSound": "shipguns"
|
||||||
},
|
},
|
||||||
@ -1391,8 +1391,7 @@
|
|||||||
"rangedStrength": 85,
|
"rangedStrength": 85,
|
||||||
"cost": 425,
|
"cost": 425,
|
||||||
"requiredTech": "Telecommunications",
|
"requiredTech": "Telecommunications",
|
||||||
"uniques": ["+[75]% Strength when attacking", "Can only attack [Water] tiles", "Can attack submarines",
|
"uniques": ["+[75]% Strength when attacking", "Can only attack [Water] tiles", "[+1] Visibility Range", "Can carry [2] [Missile] units"],
|
||||||
"[+1] Visibility Range", "Can carry [2] [Missile] units"],
|
|
||||||
"attackSound": "torpedo"
|
"attackSound": "torpedo"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -1414,7 +1413,7 @@
|
|||||||
"interceptRange": 2,
|
"interceptRange": 2,
|
||||||
"cost": 425,
|
"cost": 425,
|
||||||
"requiredTech": "Robotics",
|
"requiredTech": "Robotics",
|
||||||
"uniques": ["[100]% chance to intercept air attacks", "Can attack submarines",
|
"uniques": ["[100]% chance to intercept air attacks", "Can see invisible [Submarine] units",
|
||||||
"Ranged attacks may be performed over obstacles", "Can carry [3] [Missile] units",
|
"Ranged attacks may be performed over obstacles", "Can carry [3] [Missile] units",
|
||||||
"+[100]% Strength vs [submarine units]"],
|
"+[100]% Strength vs [submarine units]"],
|
||||||
"attackSound": "shipguns"
|
"attackSound": "shipguns"
|
||||||
|
@ -1170,3 +1170,4 @@ Only available after [] turns =
|
|||||||
This Unit upgrades for free =
|
This Unit upgrades for free =
|
||||||
[stats] when a city adopts this religion for the first time =
|
[stats] when a city adopts this religion for the first time =
|
||||||
Never destroyed when the city is captured =
|
Never destroyed when the city is captured =
|
||||||
|
Invisible to others =
|
@ -169,7 +169,7 @@ class GameInfo {
|
|||||||
it.militaryUnit != null && it.militaryUnit!!.civInfo != thisPlayer
|
it.militaryUnit != null && it.militaryUnit!!.civInfo != thisPlayer
|
||||||
&& thisPlayer.isAtWarWith(it.militaryUnit!!.civInfo)
|
&& thisPlayer.isAtWarWith(it.militaryUnit!!.civInfo)
|
||||||
&& (it.getOwner() == thisPlayer || it.neighbors.any { neighbor -> neighbor.getOwner() == thisPlayer }
|
&& (it.getOwner() == thisPlayer || it.neighbors.any { neighbor -> neighbor.getOwner() == thisPlayer }
|
||||||
&& (!it.militaryUnit!!.isInvisible() || viewableInvisibleTiles.contains(it.position)))
|
&& (!it.militaryUnit!!.isInvisible(thisPlayer) || viewableInvisibleTiles.contains(it.position)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// enemy units ON our territory
|
// enemy units ON our territory
|
||||||
|
@ -95,15 +95,11 @@ object BattleHelper {
|
|||||||
)
|
)
|
||||||
return false
|
return false
|
||||||
|
|
||||||
//only submarine and destroyer can attack submarine
|
// Only units with the right unique can view submarines (or other invisible units) from more then one tile away.
|
||||||
//garrisoned submarine can be attacked by anyone, or the city will be in invincible
|
// Garrisoned invisible units can be attacked by anyone, as else the city will be in invincible.
|
||||||
if (tileCombatant.isInvisible() && !tile.isCityCenter()) {
|
if (tileCombatant.isInvisible(combatant.getCivInfo()) && !tile.isCityCenter()) {
|
||||||
if (combatant is MapUnitCombatant
|
return combatant is MapUnitCombatant
|
||||||
&& combatant.unit.hasUnique("Can attack submarines")
|
&& combatant.getCivInfo().viewableInvisibleUnitsTiles.map { it.position }.contains(tile.position)
|
||||||
&& combatant.getCivInfo().viewableInvisibleUnitsTiles.map { it.position }.contains(tile.position)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ class CityCombatant(val city: CityInfo) : ICombatant {
|
|||||||
override fun getTile(): TileInfo = city.getCenterTile()
|
override fun getTile(): TileInfo = city.getCenterTile()
|
||||||
override fun getName(): String = city.name
|
override fun getName(): String = city.name
|
||||||
override fun isDefeated(): Boolean = city.health == 1
|
override fun isDefeated(): Boolean = city.health == 1
|
||||||
override fun isInvisible(): Boolean = false
|
override fun isInvisible(to: CivilizationInfo): Boolean = false
|
||||||
override fun canAttack(): Boolean = city.canBombard()
|
override fun canAttack(): Boolean = city.canBombard()
|
||||||
override fun matchesCategory(category: String) = category == "City" || category == "All"
|
override fun matchesCategory(category: String) = category == "City" || category == "All"
|
||||||
override fun getAttackSound() = UncivSound.Bombard
|
override fun getAttackSound() = UncivSound.Bombard
|
||||||
|
@ -16,7 +16,7 @@ interface ICombatant{
|
|||||||
fun isDefeated():Boolean
|
fun isDefeated():Boolean
|
||||||
fun getCivInfo(): CivilizationInfo
|
fun getCivInfo(): CivilizationInfo
|
||||||
fun getTile(): TileInfo
|
fun getTile(): TileInfo
|
||||||
fun isInvisible(): Boolean
|
fun isInvisible(to: CivilizationInfo): Boolean
|
||||||
fun canAttack(): Boolean
|
fun canAttack(): Boolean
|
||||||
fun matchesCategory(category:String): Boolean
|
fun matchesCategory(category:String): Boolean
|
||||||
fun getAttackSound(): UncivSound
|
fun getAttackSound(): UncivSound
|
||||||
|
@ -13,7 +13,7 @@ class MapUnitCombatant(val unit: MapUnit) : ICombatant {
|
|||||||
override fun getTile(): TileInfo = unit.getTile()
|
override fun getTile(): TileInfo = unit.getTile()
|
||||||
override fun getName(): String = unit.name
|
override fun getName(): String = unit.name
|
||||||
override fun isDefeated(): Boolean = unit.health <= 0
|
override fun isDefeated(): Boolean = unit.health <= 0
|
||||||
override fun isInvisible(): Boolean = unit.isInvisible()
|
override fun isInvisible(to: CivilizationInfo): Boolean = unit.isInvisible(to)
|
||||||
override fun canAttack(): Boolean = unit.canAttack()
|
override fun canAttack(): Boolean = unit.canAttack()
|
||||||
override fun matchesCategory(category:String) = unit.matchesFilter(category)
|
override fun matchesCategory(category:String) = unit.matchesFilter(category)
|
||||||
override fun getAttackSound() = unit.baseUnit.attackSound.let {
|
override fun getAttackSound() = unit.baseUnit.attackSound.let {
|
||||||
@ -36,7 +36,7 @@ class MapUnitCombatant(val unit: MapUnit) : ICombatant {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getUnitType(): UnitType {
|
override fun getUnitType(): UnitType {
|
||||||
return unit.type!!
|
return unit.type
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
|
@ -12,12 +12,28 @@ class CivInfoTransientUpdater(val civInfo: CivilizationInfo) {
|
|||||||
|
|
||||||
val newViewableInvisibleTiles = HashSet<TileInfo>()
|
val newViewableInvisibleTiles = HashSet<TileInfo>()
|
||||||
newViewableInvisibleTiles.addAll(civInfo.getCivUnits()
|
newViewableInvisibleTiles.addAll(civInfo.getCivUnits()
|
||||||
.filter { it.hasUnique("Can attack submarines") }
|
// "Can attack submarines" unique deprecated since 3.16.9
|
||||||
.flatMap { it.viewableTiles.asSequence() })
|
.filter { attacker -> attacker.hasUnique("Can see invisible [] units") || attacker.hasUnique("Can attack submarines") }
|
||||||
|
.flatMap { attacker ->
|
||||||
|
attacker.viewableTiles
|
||||||
|
.asSequence()
|
||||||
|
.filter { tile ->
|
||||||
|
( tile.militaryUnit != null
|
||||||
|
&& attacker.getMatchingUniques("Can see invisible [] units")
|
||||||
|
.any { unique -> tile.militaryUnit!!.matchesFilter(unique.params[0]) }
|
||||||
|
) || (
|
||||||
|
tile.militaryUnit != null
|
||||||
|
// "Can attack submarines" unique deprecated since 3.16.9
|
||||||
|
&& attacker.hasUnique("Can attack submarines")
|
||||||
|
&& tile.militaryUnit!!.matchesFilter("Submarine")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
civInfo.viewableInvisibleUnitsTiles = newViewableInvisibleTiles
|
civInfo.viewableInvisibleUnitsTiles = newViewableInvisibleTiles
|
||||||
|
|
||||||
|
|
||||||
// updating the viewable tiles also affects the explored tiles, obvs
|
// updating the viewable tiles also affects the explored tiles, obviously.
|
||||||
// So why don't we play switcharoo with the explored tiles as well?
|
// So why don't we play switcharoo with the explored tiles as well?
|
||||||
// Well, because it gets REALLY LARGE so it's a lot of memory space,
|
// Well, because it gets REALLY LARGE so it's a lot of memory space,
|
||||||
// and we never actually iterate on the explored tiles (only check contains()),
|
// and we never actually iterate on the explored tiles (only check contains()),
|
||||||
|
@ -354,9 +354,13 @@ class MapUnit {
|
|||||||
return currentTile.isWater
|
return currentTile.isWater
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isInvisible(): Boolean {
|
fun isInvisible(to: CivilizationInfo): Boolean {
|
||||||
if (hasUnique("Invisible to others"))
|
if (hasUnique("Invisible to others"))
|
||||||
return true
|
return true
|
||||||
|
if (hasUnique("Invisible to non-adjacent units"))
|
||||||
|
return getTile().getTilesInDistance(1).none {
|
||||||
|
it.getOwner() == to || it.getUnits().any { unit -> unit.owner == to.civName }
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -637,7 +637,7 @@ open class TileInfo {
|
|||||||
val unitsInTile = getUnits()
|
val unitsInTile = getUnits()
|
||||||
if (unitsInTile.none()) return false
|
if (unitsInTile.none()) return false
|
||||||
if (unitsInTile.first().civInfo != viewingCiv &&
|
if (unitsInTile.first().civInfo != viewingCiv &&
|
||||||
unitsInTile.firstOrNull { it.isInvisible() } != null) {
|
unitsInTile.firstOrNull { it.isInvisible(viewingCiv) } != null) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -74,14 +74,14 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
|
|||||||
val attackerCiv = worldScreen.viewingCiv
|
val attackerCiv = worldScreen.viewingCiv
|
||||||
val defender: ICombatant? = Battle.getMapCombatantOfTile(selectedTile)
|
val defender: ICombatant? = Battle.getMapCombatantOfTile(selectedTile)
|
||||||
|
|
||||||
if(defender==null ||
|
if (defender == null || (!includeFriendly && defender.getCivInfo() == attackerCiv))
|
||||||
!includeFriendly && defender.getCivInfo()==attackerCiv )
|
|
||||||
return null // no enemy combatant in tile
|
return null // no enemy combatant in tile
|
||||||
|
|
||||||
val canSeeDefender = if(UncivGame.Current.viewEntireMapForDebug) true
|
val canSeeDefender =
|
||||||
|
if (UncivGame.Current.viewEntireMapForDebug) true
|
||||||
else {
|
else {
|
||||||
when {
|
when {
|
||||||
defender.isInvisible() -> attackerCiv.viewableInvisibleUnitsTiles.contains(selectedTile)
|
defender.isInvisible(attackerCiv) -> attackerCiv.viewableInvisibleUnitsTiles.contains(selectedTile)
|
||||||
defender.isCity() -> attackerCiv.exploredTiles.contains(selectedTile.position)
|
defender.isCity() -> attackerCiv.exploredTiles.contains(selectedTile.position)
|
||||||
else -> attackerCiv.viewableTiles.contains(selectedTile)
|
else -> attackerCiv.viewableTiles.contains(selectedTile)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user