Nuke your enemy! (#1318)

* Nuke your enemy!

* Fantasy tiles. Worker automaticly clears fallout.

* Some AI improvement for choosing wonder and military unit.

* Add nuclear weapon option.
This commit is contained in:
Duan Tao 2019-11-19 14:43:04 +08:00 committed by Yair Morgenstern
parent bfd6376612
commit 111030e457
31 changed files with 798 additions and 613 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 857 KiB

After

Width:  |  Height:  |  Size: 872 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 247 KiB

After

Width:  |  Height:  |  Size: 274 KiB

View File

@ -359,6 +359,12 @@
requiredBuildingInAllCities:"Library",
requiredTech:"Civil Service"
},
{
name:"Manhattan Project",
isNationalWonder:true,
uniques:["Enables nuclear weapon"],
requiredTech:"Nuclear Fission"
},
{
name:"Chichen Itza",
culture:1,

View File

@ -111,6 +111,16 @@
defenceBonus: -0.1,
occursOn:["Grassland"]
},
{
name:"Fallout",
type:"TerrainFeature",
food:-3,
production:-3,
gold:-3,
movementCost:2,
unbuildable:true,
defenceBonus: -0.15,
},
{
name:"Oasis",
type:"TerrainFeature",

View File

@ -104,13 +104,19 @@
terrainsCanBeBuiltOn:["Jungle"],
techRequired:"Bronze Working"
},
{
name:"Remove Fallout",
turnsToBuild:8,
terrainsCanBeBuiltOn:["Fallout"],
techRequired:"Agriculture"
},
{
name:"Remove Marsh",
turnsToBuild:6,
terrainsCanBeBuiltOn:["Marsh"],
techRequired:"Bronze Working"
},
// These are unique and have unique in-game checks related to them
{
name:"Remove Road",

View File

@ -457,6 +457,8 @@
Polish:"Akademia Narodowa"
Czech:"Národní Akademie"
}
"Manhattan Project":{
}
"Chichen Itza":{
Italian:"Chichen Itza"
@ -496,6 +498,9 @@
Czech:"Délka Zlatého věku se prodloužila o 50%"
}
"Enables nuclear weapon":{
}
"Lighthouse":{
Spanish:"faro"
Italian:"Faro"

View File

@ -1690,6 +1690,9 @@
Ukrainian:"Обстрілювати"
}
"NUKE":{
}
"Captured!":{// Shown in the battle table when attacking a civilian unit
Italian:"Cattura!"
Russian:"Захвачен!"

View File

@ -160,6 +160,9 @@
Czech:"Bažina"
}
"Fallout":{
}
"Oasis":{
Italian:"Oasi"
Russian:"Оазис"
@ -1040,6 +1043,9 @@
Ukrainian:"Висушити болото"
}
"Remove Fallout":{
},
"Ancient ruins":{
Italian:"Antiche rovine"
Romanian:"Ruine străvechi"

View File

@ -1291,6 +1291,9 @@
Czech:"[percent]% šance zabránit leteckým útokům"
}
"Requires Manhattan Project":{
},
"6 tiles in every direction always visible":{
Italian:"6 caselle in ogni direzione sempre visibili"
Simplified_Chinese:"全方向6格视野范围"
@ -1502,14 +1505,12 @@
Italian:"Missile guidato"
Czech:"Naváděná střela"
}
*/
"Nuclear Missile":{
Italian:"Missile nucleare"
Czech:"Jaderná raketa"
}
*/
////// Great units
"Great Artist":{

View File

@ -1003,6 +1003,19 @@
hurryCostModifier:20,
attackSound:"shot"
},
{
name:"Nuclear Missile",
unitType:"Missile",
movement:1,
strength:300,
rangedStrength:300,
range:12,
cost: 1000,
requiredTech:"Rocketry",
requiredResource:"Uranium",
uniques:["Requires Manhattan Project"],
hurryCostModifier:20,
},
{
name:"Landship",
unitType:"Armor",

View File

@ -93,7 +93,7 @@ class Automation {
(it.isCityCenter() && it.getOwner() != city.civInfo)
|| (it.militaryUnit != null && it.militaryUnit!!.civInfo != city.civInfo)
}) // there is absolutely no reason for you to make water units on this body of water.
militaryUnits = militaryUnits.filter { it.unitType.isLandUnit() }
militaryUnits = militaryUnits.filter { it.unitType.isLandUnit() || it.unitType.isAirUnit() }
val chosenUnit: BaseUnit
if(!city.civInfo.isAtWar() && city.civInfo.cities.any { it.getCenterTile().militaryUnit==null}

View File

@ -146,6 +146,10 @@ class ConstructionAutomation(val cityConstructions: CityConstructions){
if (preferredVictoryType == VictoryType.Scientific) return 1.5f
else return 1.3f
}
if (wonder.name == "Manhattan Project") {
if (preferredVictoryType == VictoryType.Domination) return 2f
else return 1.3f
}
if (wonder.isStatRelated(Stat.Happiness)) return 1.2f
if (wonder.isStatRelated(Stat.Production)) return 1.1f
return 1f

View File

@ -176,6 +176,7 @@ class WorkerAutomation(val unit: MapUnit) {
val improvementStringForResource : String ?= when {
tile.resource == null || !tile.hasViewableResource(civInfo) -> null
tile.terrainFeature == "Marsh" -> "Remove Marsh"
tile.terrainFeature == "Fallout" -> "Remove Fallout"
tile.terrainFeature == Constants.jungle -> "Remove Jungle"
tile.terrainFeature == Constants.forest && tile.getTileResource().improvement!="Camp" -> "Remove Forest"
else -> tile.getTileResource().improvement
@ -188,6 +189,7 @@ class WorkerAutomation(val unit: MapUnit) {
tile.containsUnfinishedGreatImprovement() -> null
tile.terrainFeature == Constants.jungle -> "Trading post"
tile.terrainFeature == "Marsh" -> "Remove Marsh"
tile.terrainFeature == "Fallout" -> "Remove Fallout"
tile.terrainFeature == "Oasis" -> null
tile.terrainFeature == Constants.forest -> "Lumber mill"
tile.baseTerrain == Constants.hill -> "Mine"

View File

@ -7,6 +7,7 @@ import com.unciv.logic.automation.UnitAutomation
import com.unciv.logic.city.CityInfo
import com.unciv.logic.civilization.AlertType
import com.unciv.logic.civilization.PopupAlert
import com.unciv.logic.map.RoadStatus
import com.unciv.logic.map.TileInfo
import com.unciv.models.gamebasics.unit.UnitType
import java.util.*
@ -40,7 +41,10 @@ class Battle(val gameInfo:GameInfo) {
var damageToDefender = BattleDamage().calculateDamageToDefender(attacker,defender)
var damageToAttacker = BattleDamage().calculateDamageToAttacker(attacker,defender)
if(defender.getUnitType().isCivilian() && attacker.isMelee()){
if (attacker.getUnitType().isMissileUnit()) {
nuclearBlast(attacker, defender)
}
else if(defender.getUnitType().isCivilian() && attacker.isMelee()){
captureCivilianUnit(attacker,defender)
}
else if (attacker.isRanged()) {
@ -95,6 +99,15 @@ class Battle(val gameInfo:GameInfo) {
if (attacker is MapUnitCombatant && attacker.unit.action != null
&& attacker.unit.action!!.startsWith("moveTo"))
attacker.unit.action = null
if (attacker is MapUnitCombatant) {
if (attacker.getUnitType().isMissileUnit()) {
attacker.unit.destroy()
} else if (attacker.unit.action != null
&& attacker.unit.action!!.startsWith("moveTo")) {
attacker.unit.action = null
}
}
}
private fun postBattleNotifications(attacker: ICombatant, defender: ICombatant, attackedTile: TileInfo) {
@ -282,6 +295,30 @@ class Battle(val gameInfo:GameInfo) {
capturedUnit.updateVisibleTiles()
}
private fun nuclearBlast(attacker: ICombatant, defender: ICombatant) {
for (tile in defender.getTile().getTilesInDistance(2)) {
if (tile.isCityCenter()) { //duantao: To Do
val city = tile.getCity()!!
city.health = 1
if (city.population.population <= 5) {
city.destroyCity()
} else {
city.population.population -= 5
city.population.unassignExtraPopulation()
continue
}
}
if (tile.militaryUnit != null) tile.militaryUnit!!.destroy()
if (tile.civilianUnit != null) tile.civilianUnit!!.destroy()
tile.improvement = null
tile.improvementInProgress = null
tile.turnsToImprovement = 0
tile.roadStatus = RoadStatus.None
if (tile.isLand) tile.terrainFeature = "Fallout"
}
}
private fun tryInterceptAirAttack(attacker:MapUnitCombatant, defender: ICombatant) {
val attackedTile = defender.getTile()
for (interceptor in defender.getCivInfo().getCivUnits().filter { it.canIntercept(attackedTile) }) {

View File

@ -189,7 +189,7 @@ class MapGenerator {
fun addRandomTerrainFeature(tileInfo: TileInfo) {
if (tileInfo.getBaseTerrain().canHaveOverlay && Math.random() > 0.7f) {
val secondaryTerrains = GameBasics.Terrains.values
.filter { it.type === TerrainType.TerrainFeature && it.occursOn!!.contains(tileInfo.baseTerrain) }
.filter { it.type === TerrainType.TerrainFeature && it.occursOn != null && it.occursOn!!.contains(tileInfo.baseTerrain) }
if (secondaryTerrains.any()) tileInfo.terrainFeature = secondaryTerrains.random().name
}
}

View File

@ -131,6 +131,10 @@ class BaseUnit : INamed, IConstruction {
if (obsoleteTech!=null && civInfo.tech.isResearched(obsoleteTech!!)) return "Obsolete by $obsoleteTech"
if (uniqueTo!=null && uniqueTo!=civInfo.civName) return "Unique to $uniqueTo"
if (GameBasics.Units.values.any { it.uniqueTo==civInfo.civName && it.replaces==name }) return "Our unique unit replaces this"
if (!civInfo.gameInfo.gameParameters.nuclearWeaponEnabled
&& (name == "Manhattan Project" || uniques.contains("Requires Manhattan Project"))) return "Disabled by setting"
if (uniques.contains("Requires Manhattan Project") && !civInfo.containsBuildingUnique("Enables nuclear weapon"))
return "Requires Manhattan Project"
if (requiredResource!=null && !civInfo.hasResource(requiredResource!!)) return "Requires [$requiredResource]"
if (name == Constants.settler && civInfo.isCityState()) return "No settler for city-states"
if (name == Constants.settler && civInfo.isOneCityChallenger()) return "No settler for players in One City Challenge"

View File

@ -16,7 +16,8 @@ enum class UnitType{
WaterSubmarine,
Fighter,
Bomber;
Bomber,
Missile;
fun isMelee(): Boolean {
return this == Melee
@ -59,5 +60,10 @@ enum class UnitType{
fun isAirUnit():Boolean{
return this==Bomber
|| this==Fighter
|| this==Missile
}
fun isMissileUnit():Boolean{
return this == Missile
}
}

View File

@ -17,7 +17,8 @@ class GameParameters { // Default values are the default new game
var mapType = MapType.pangaea
var noBarbarians = false
var oneCityChallenge = false
var noRuins = false
var nuclearWeaponEnabled = false
var noRuins = false;
var mapFileName: String? = null
var victoryTypes: ArrayList<VictoryType> = VictoryType.values().toCollection(ArrayList()) // By default, all victory types
var startingEra = TechEra.Ancient

View File

@ -160,7 +160,10 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera
val terrain = resource.terrainsCanBeFoundOn.first()
val terrainObject = GameBasics.Terrains[terrain]!!
if (terrainObject.type == TerrainType.TerrainFeature) {
tileInfo.baseTerrain = terrainObject.occursOn!!.first()
tileInfo.baseTerrain = when {
terrainObject.occursOn == null -> terrainObject.occursOn!!.first()
else -> "Grassland"
}
tileInfo.terrainFeature = terrain
} else tileInfo.baseTerrain = terrain
@ -177,7 +180,10 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera
for (terrain in GameBasics.Terrains.values) {
val tileInfo = TileInfo()
if (terrain.type == TerrainType.TerrainFeature) {
tileInfo.baseTerrain = terrain.occursOn!!.first()
tileInfo.baseTerrain = when {
terrain.occursOn == null -> terrain.occursOn!!.first()
else -> "Grassland"
}
tileInfo.terrainFeature = terrain.name
} else tileInfo.baseTerrain = terrain.name

View File

@ -28,6 +28,7 @@ class NewGameScreenOptionsTable(val newGameParameters: GameParameters, val onMul
addVictoryTypeCheckboxes()
addBarbariansCheckbox()
addOneCityChallengeCheckbox()
addNuclearWeaponCheckbox()
addNoRuinsCheckbox()
addIsOnlineMultiplayerCheckbox()
@ -56,6 +57,18 @@ class NewGameScreenOptionsTable(val newGameParameters: GameParameters, val onMul
})
add(oneCityChallengeCheckbox).colspan(2).row()
}
private fun addNuclearWeaponCheckbox() {
val nuclearWeaponCheckbox = CheckBox("Enable nuclear weapon".tr(), CameraStageBaseScreen.skin)
nuclearWeaponCheckbox.isChecked = newGameParameters.nuclearWeaponEnabled
nuclearWeaponCheckbox.addListener(object : ChangeListener() {
override fun changed(event: ChangeEvent?, actor: Actor?) {
newGameParameters.nuclearWeaponEnabled = nuclearWeaponCheckbox.isChecked
}
})
add(nuclearWeaponCheckbox).colspan(2).row()
}
private fun addNoRuinsCheckbox() {
val noRuinsCheckbox = CheckBox("No ancient ruins".tr(), CameraStageBaseScreen.skin)
noRuinsCheckbox.isChecked = newGameParameters.noRuins

View File

@ -151,7 +151,11 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
}
row().pad(5f)
val attackText : String = if (attacker is MapUnitCombatant) "Attack" else "Bombard"
val attackText : String = when {
attacker is MapUnitCombatant && attacker.getUnitType().isMissileUnit() -> "NUKE"
attacker is MapUnitCombatant -> "Attack"
else -> "Bombard"
}
val attackButton = TextButton(attackText.tr(), skin).apply { color= Color.RED }
var attackableEnemy : UnitAutomation.AttackableTile? = null

View File

@ -97,6 +97,8 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
* [APC](https://thenounproject.com/search/?q=apc&i=9965) By Luke Anthony Firth for Mechanized Infantry
* [Military vehicle](https://thenounproject.com/search/?q=Army%20rocket&i=23115) By Luke Anthony Firth For Rocket Artillery
* [Modern Armor](https://thenounproject.com/search/?q=tank&i=218) By Public Domain Nouns for Modern Armor
* [Manhattan Project](https://thenounproject.com/search/?q=Nuclear%20Bomb&i=2041074) By corpus delicti, GR
* [Nuclear Missile](https://thenounproject.com/marialuisa.iborra/collection/missiles-bombs/?i=1022574) By Lluisa Iborra, ES
### Great People