This commit is contained in:
Yair Morgenstern 2021-06-03 19:08:39 +03:00
commit 7cc440a577
21 changed files with 154 additions and 65 deletions

View File

@ -5,6 +5,7 @@
[![Google Play](https://img.shields.io/static/v1?label=Google&message=Play&color=607D8B&logo=google-play)](https://play.google.com/store/apps/details?id=com.unciv.app) [![Google Play](https://img.shields.io/static/v1?label=Google&message=Play&color=607D8B&logo=google-play)](https://play.google.com/store/apps/details?id=com.unciv.app)
[![F-Droid](https://img.shields.io/f-droid/v/com.unciv.app)](https://f-droid.org/en/packages/com.unciv.app/) [![F-Droid](https://img.shields.io/f-droid/v/com.unciv.app)](https://f-droid.org/en/packages/com.unciv.app/)
[![itch.io](https://img.shields.io/static/v1?label=itch.io&message=Unciv&color=607D8B&logo=itch.io)](https://yairm210.itch.io/unciv) [![itch.io](https://img.shields.io/static/v1?label=itch.io&message=Unciv&color=607D8B&logo=itch.io)](https://yairm210.itch.io/unciv)
[![Flathub](https://img.shields.io/flathub/v/io.github.yairm210.unciv)](https://flathub.org/apps/details/io.github.yairm210.unciv)
[![Travis CI w/ Logo](https://img.shields.io/travis/yairm210/Unciv/master.svg?logo=travis)](https://travis-ci.com/yairm210/Unciv) [![Travis CI w/ Logo](https://img.shields.io/travis/yairm210/Unciv/master.svg?logo=travis)](https://travis-ci.com/yairm210/Unciv)
![Build and deploy](https://github.com/yairm210/Unciv/workflows/Build%20and%20deploy/badge.svg) ![Build and deploy](https://github.com/yairm210/Unciv/workflows/Build%20and%20deploy/badge.svg)
@ -79,6 +80,8 @@ Yes! Windows and Linux versions are available at [itch.io](https://yairm210.itch
If you have Java 8, and are familiar with the command line, there are (considerably smaller) JARs in [Releases](https://github.com/yairm210/UnCiv/releases) which you can run with `java -jar Unciv.jar`. This is also (currently) the only way to run the game on MacOS. If you have Java 8, and are familiar with the command line, there are (considerably smaller) JARs in [Releases](https://github.com/yairm210/UnCiv/releases) which you can run with `java -jar Unciv.jar`. This is also (currently) the only way to run the game on MacOS.
If you use Flatpaks, there's a Flatpak by [MayeulC](https://github.com/MayeulC) and you can know more about it [here](https://github.com/flathub/io.github.yairm210.unciv). Flathub link is available in the [Downloads](#downloads) section.
If you want to build it from sratch for some reason, [we have instructions for that as well](https://github.com/yairm210/Unciv/wiki/Building-locally-without-Android-Studio) If you want to build it from sratch for some reason, [we have instructions for that as well](https://github.com/yairm210/Unciv/wiki/Building-locally-without-Android-Studio)
## How about IOS? ## How about IOS?
@ -124,4 +127,9 @@ Multiplayer takes advantage of Dropbox, which is *non-free software*, for syncin
Single player does not use this feature. Single player does not use this feature.
## Downloads
| [![](https://static.itch.io/images/badge.svg)](https://yairm210.itch.io/unciv) | [![](https://play.google.com/intl/en_us/badges/images/generic/en-play-badge.png)](https://play.google.com/store/apps/details?id=com.unciv.app) | [![](https://fdroid.gitlab.io/artwork/badge/get-it-on.png)](https://f-droid.org/en/packages/com.unciv.app/) | [![](https://flathub.org/assets/badges/flathub-badge-en.svg)](https://flathub.org/apps/details/io.github.yairm210.unciv)
|--- |--- |--- |--- |
# [Credits and 3rd parties](docs/Credits.md) # [Credits and 3rd parties](docs/Credits.md)

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -487,132 +487,139 @@ Panzer
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
Persian Immortal Paratrooper
rotate: false rotate: false
xy: 1430, 308 xy: 1430, 308
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
Pikeman Persian Immortal
rotate: false rotate: false
xy: 1532, 410 xy: 1532, 410
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
Rifleman Pikeman
rotate: false rotate: false
xy: 1328, 105 xy: 1328, 105
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
Rocket Artillery Rifleman
rotate: false rotate: false
xy: 1430, 206 xy: 1430, 206
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
Samurai Rocket Artillery
rotate: false rotate: false
xy: 1532, 308 xy: 1532, 308
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
Scout Samurai
rotate: false rotate: false
xy: 1634, 410 xy: 1634, 410
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
Settler Scout
rotate: false rotate: false
xy: 1328, 3 xy: 1328, 3
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
Ship of the Line Settler
rotate: false rotate: false
xy: 1430, 104 xy: 1430, 104
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
Sipahi Ship of the Line
rotate: false rotate: false
xy: 1430, 2 xy: 1430, 2
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
Slinger Sipahi
rotate: false rotate: false
xy: 1532, 206 xy: 1532, 206
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
Spearman Slinger
rotate: false rotate: false
xy: 1634, 308 xy: 1634, 308
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
Stealth Bomber Spearman
rotate: false rotate: false
xy: 1736, 410 xy: 1736, 410
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
Submarine Stealth Bomber
rotate: false rotate: false
xy: 1532, 104 xy: 1532, 104
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
Swordsman Submarine
rotate: false rotate: false
xy: 1532, 2 xy: 1532, 2
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
Tank Swordsman
rotate: false rotate: false
xy: 1634, 206 xy: 1634, 206
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
Tercio Tank
rotate: false rotate: false
xy: 1736, 308 xy: 1736, 308
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
Trebuchet Tercio
rotate: false rotate: false
xy: 1838, 410 xy: 1838, 410
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
Triplane Trebuchet
rotate: false rotate: false
xy: 1634, 104 xy: 1634, 104
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
Triplane
rotate: false
xy: 1634, 2
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Trireme Trireme
rotate: false rotate: false
xy: 1736, 205 xy: 1736, 205
@ -622,49 +629,49 @@ Trireme
index: -1 index: -1
Turtle Ship Turtle Ship
rotate: false rotate: false
xy: 1634, 2 xy: 1838, 308
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
War Chariot War Chariot
rotate: false rotate: false
xy: 1838, 308 xy: 1940, 410
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
War Elephant War Elephant
rotate: false rotate: false
xy: 1940, 410 xy: 1736, 103
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
Warrior Warrior
rotate: false rotate: false
xy: 1736, 103 xy: 1838, 206
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
Work Boats Work Boats
rotate: false rotate: false
xy: 1838, 206 xy: 1940, 308
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
Worker Worker
rotate: false rotate: false
xy: 1940, 308 xy: 1838, 104
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
Zero Zero
rotate: false rotate: false
xy: 1838, 104 xy: 1838, 2
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 279 KiB

After

Width:  |  Height:  |  Size: 284 KiB

View File

@ -110,7 +110,7 @@
"isWonder": true, "isWonder": true,
"cost": 185, "cost": 185,
"greatPersonPoints": {"production": 1}, "greatPersonPoints": {"production": 1},
"uniques": ["+[10]% growth in all cities", "+[15]% Production when constructing [Ranged] units [in all cities]"], "uniques": ["+[10]% [Food] [in all cities]", "+[15]% Production when constructing [Ranged] units [in all cities]"],
"requiredTech": "Archery", "requiredTech": "Archery",
"quote": "'It is not so much for its beauty that the forest makes a claim upon men's hearts, as for that subtle something, that quality of air, that emanation from old trees, that so wonderfully changes and renews a weary spirit.' - Robert Louis Stevenson" "quote": "'It is not so much for its beauty that the forest makes a claim upon men's hearts, as for that subtle something, that quality of air, that emanation from old trees, that so wonderfully changes and renews a weary spirit.' - Robert Louis Stevenson"
}, },
@ -937,7 +937,7 @@
{ {
"name": "Manhattan Project", "name": "Manhattan Project",
"isNationalWonder": true, "isNationalWonder": true,
"uniques": ["Enables nuclear weapon"], "uniques": ["Enables nuclear weapon", "Triggers a global alert upon completion"],
"requiredTech": "Nuclear Fission" "requiredTech": "Nuclear Fission"
}, },
{ {
@ -1014,13 +1014,13 @@
"name": "SS Booster", "name": "SS Booster",
"requiredResource": "Aluminum", "requiredResource": "Aluminum",
"requiredTech": "Robotics", "requiredTech": "Robotics",
"uniques": ["Spaceship part", "Cannot be purchased"] "uniques": ["Spaceship part", "Triggers a global alert upon completion", "Cannot be purchased"]
}, },
{ {
"name": "Apollo Program", "name": "Apollo Program",
"cost": 1500, "cost": 1500,
"isNationalWonder": true, "isNationalWonder": true,
"uniques": ["Enables construction of Spaceship parts"], "uniques": ["Enables construction of Spaceship parts", "Triggers a global alert upon completion"],
"requiredTech": "Rocketry" "requiredTech": "Rocketry"
}, },
@ -1044,18 +1044,18 @@
"name": "SS Cockpit", "name": "SS Cockpit",
"requiredResource": "Aluminum", "requiredResource": "Aluminum",
"requiredTech": "Satellites", "requiredTech": "Satellites",
"uniques": ["Spaceship part", "Cannot be purchased"] "uniques": ["Spaceship part", "Triggers a global alert upon completion", "Cannot be purchased"]
}, },
{ {
"name": "SS Engine", "name": "SS Engine",
"requiredResource": "Aluminum", "requiredResource": "Aluminum",
"requiredTech": "Particle Physics", "requiredTech": "Particle Physics",
"uniques": ["Spaceship part", "Cannot be purchased"] "uniques": ["Spaceship part", "Triggers a global alert upon completion", "Cannot be purchased"]
}, },
{ {
"name": "SS Stasis Chamber", "name": "SS Stasis Chamber",
"requiredResource": "Aluminum", "requiredResource": "Aluminum",
"requiredTech": "Nanotechnology", "requiredTech": "Nanotechnology",
"uniques": ["Spaceship part", "Cannot be purchased"] "uniques": ["Spaceship part", "Triggers a global alert upon completion", "Cannot be purchased"]
} }
] ]

View File

@ -1152,7 +1152,6 @@
"uniques": ["+[20]% Strength in [Foreign Land]"], "uniques": ["+[20]% Strength in [Foreign Land]"],
"attackSound": "shot" "attackSound": "shot"
}, },
/*
{ {
"name": "Paratrooper", "name": "Paratrooper",
"unitType": "Melee", "unitType": "Melee",
@ -1160,11 +1159,10 @@
"strength": 40, "strength": 40,
"cost": 375, "cost": 375,
"requiredTech": "Radar", "requiredTech": "Radar",
"uniques": ["May Paradrop"], "uniques": ["May Paradrop up to [5] tiles from inside friendly territory"],
"attackSound": "shot" "attackSound": "shot"
// 65 strength in expansions, upgradesTo "XCOM Squad", "No Movement Cost to Pillage" in BNW // 65 strength in expansions, upgradesTo "XCOM Squad", "No Movement Cost to Pillage" in BNW
}, },
*/
{ {
"name": "Infantry", "name": "Infantry",
"unitType": "Melee", "unitType": "Melee",

View File

@ -515,6 +515,7 @@ Sleep = Slaap
Sleep until healed = Slaap tot geheeld Sleep until healed = Slaap tot geheeld
Moving = Bewegen Moving = Bewegen
Set up = Opstellen Set up = Opstellen
Paradrop = Parachutelanding
Upgrade to [unitType] ([goldCost] gold) = Waardeer [unitType] op ([goldCost] goud) Upgrade to [unitType] ([goldCost] gold) = Waardeer [unitType] op ([goldCost] goud)
Found city = Stad stichten Found city = Stad stichten
Promote = Promoveren Promote = Promoveren
@ -522,7 +523,7 @@ Health = Gezondheid
Disband unit = Eenheid opheffen Disband unit = Eenheid opheffen
Explore = Ontdekken Explore = Ontdekken
Stop exploration = Stop ontdekken Stop exploration = Stop ontdekken
Pillage = Plundering Pillage = Plunderen
Do you really want to disband this unit? = Wil je echt deze eenheid opheffen Do you really want to disband this unit? = Wil je echt deze eenheid opheffen
Disband this unit for [goldAmount] gold? = Deze eenheid ontbinden voor [goldAmount] goud? Disband this unit for [goldAmount] gold? = Deze eenheid ontbinden voor [goldAmount] goud?
Create [improvement] = Maak [improvement] Create [improvement] = Maak [improvement]
@ -919,7 +920,7 @@ Land = Land
Wounded = Gewond Wounded = Gewond
Marine = Marine Marine = Marine
Mobile SAM = Mobiele grond-lucht raket Mobile SAM = Mobiele grond-lucht raket
Paratrooper = Paracommando Paratrooper = Parachutist
Helicopter Gunship = Helicopter Wapenschip Helicopter Gunship = Helicopter Wapenschip
Atomic Bomb = Atoombom Atomic Bomb = Atoombom
Unbuildable = Onbouwbaar Unbuildable = Onbouwbaar

View File

@ -395,6 +395,8 @@ Cannot provide unit upkeep for [unitName] - unit has been disbanded! =
[cityName] is starving! = [cityName] is starving! =
[construction] has been built in [cityName] = [construction] has been built in [cityName] =
[wonder] has been built in a faraway land = [wonder] has been built in a faraway land =
[civName] has completed [construction]! =
An unknown civilization has completed [construction]! =
Work has started on [construction] = Work has started on [construction] =
[cityName] cannot continue work on [construction] = [cityName] cannot continue work on [construction] =
[cityName] has expanded its borders! = [cityName] has expanded its borders! =
@ -502,6 +504,7 @@ Sleep =
Sleep until healed = Sleep until healed =
Moving = Moving =
Set up = Set up =
Paradrop =
Upgrade to [unitType] ([goldCost] gold) = Upgrade to [unitType] ([goldCost] gold) =
Found city = Found city =
Promote = Promote =

View File

@ -57,6 +57,8 @@ object Constants {
const val unitActionSleepUntilHealed = "Sleep until healed" const val unitActionSleepUntilHealed = "Sleep until healed"
const val unitActionAutomation = "Automate" const val unitActionAutomation = "Automate"
const val unitActionExplore = "Explore" const val unitActionExplore = "Explore"
const val unitActionParadrop = "Paradrop"
const val futureTech = "Future Tech" const val futureTech = "Future Tech"
const val cancelImprovementOrder = "Cancel improvement order" const val cancelImprovementOrder = "Cancel improvement order"

View File

@ -62,7 +62,6 @@ class UncivGame(parameters: UncivGameParameters) : Game() {
var music: Music? = null var music: Music? = null
val musicLocation = "music/thatched-villagers.mp3" val musicLocation = "music/thatched-villagers.mp3"
private var isSizeRestored = false
var isInitialized = false var isInitialized = false
@ -118,7 +117,6 @@ class UncivGame(parameters: UncivGameParameters) : Game() {
thread(name="Music") { startMusic() } thread(name="Music") { startMusic() }
restoreSize()
if (settings.isFreshlyCreated) { if (settings.isFreshlyCreated) {
setScreen(LanguagePickerScreen()) setScreen(LanguagePickerScreen())
@ -129,14 +127,6 @@ class UncivGame(parameters: UncivGameParameters) : Game() {
crashController = CrashController.Impl(crashReportSender) crashController = CrashController.Impl(crashReportSender)
} }
fun restoreSize() {
if (!isSizeRestored && Gdx.app.type == Application.ApplicationType.Desktop && settings.windowState.height>39 && settings.windowState.width>39) {
isSizeRestored = true
Gdx.graphics.setWindowedMode(settings.windowState.width, settings.windowState.height)
}
}
fun loadGame(gameInfo: GameInfo) { fun loadGame(gameInfo: GameInfo) {
this.gameInfo = gameInfo this.gameInfo = gameInfo
ImageGetter.setNewRuleset(gameInfo.ruleSet) ImageGetter.setNewRuleset(gameInfo.ruleSet)

View File

@ -347,7 +347,16 @@ class CityConstructions {
cityInfo.civInfo.addNotification("[${construction.name}] has been built in [" + cityInfo.name + "]", cityInfo.civInfo.addNotification("[${construction.name}] has been built in [" + cityInfo.name + "]",
cityInfo.location, NotificationIcon.Construction, icon) cityInfo.location, NotificationIcon.Construction, icon)
} }
if (construction is Building && "Triggers a global alert upon completion" in construction.uniques) {
for (otherCiv in cityInfo.civInfo.gameInfo.civilizations) {
// No need to notify ourself, since we already got the building notification anyway
if (otherCiv == cityInfo.civInfo) continue
val completingCivDescription =
if (otherCiv.knows(cityInfo.civInfo)) "[${cityInfo.civInfo.civName}]" else "An unknown civilization"
otherCiv.addNotification("$completingCivDescription has completed [${construction.name}]!",
NotificationIcon.Construction, buildingIcon)
}
}
} }
fun addBuilding(buildingName: String) { fun addBuilding(buildingName: String) {

View File

@ -71,6 +71,9 @@ class MapUnit {
@Transient @Transient
var cannotEnterOceanTilesUntilAstronomy = false var cannotEnterOceanTilesUntilAstronomy = false
@Transient
var paradropRange = 0
lateinit var owner: String lateinit var owner: String
/** /**
@ -547,6 +550,9 @@ class MapUnit {
action = null // wake up when healed action = null // wake up when healed
} }
if (action == Constants.unitActionParadrop)
action = null
getCitadelDamage() getCitadelDamage()
getTerrainDamage() getTerrainDamage()
} }

View File

@ -2,6 +2,7 @@ package com.unciv.logic.map
import com.badlogic.gdx.math.Vector2 import com.badlogic.gdx.math.Vector2
import com.unciv.Constants import com.unciv.Constants
import com.unciv.logic.HexMath.getDistance
import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.civilization.CivilizationInfo
class UnitMovementAlgorithms(val unit:MapUnit) { class UnitMovementAlgorithms(val unit:MapUnit) {
@ -169,8 +170,8 @@ class UnitMovementAlgorithms(val unit:MapUnit) {
val currentTile = unit.getTile() val currentTile = unit.getTile()
if (currentTile == finalDestination) return currentTile if (currentTile == finalDestination) return currentTile
// head there directly // If we can fly, head there directly
if (unit.type.isAirUnit()) return finalDestination if (unit.type.isAirUnit() || unit.action == Constants.unitActionParadrop) return finalDestination
val distanceToTiles = getDistanceToTiles() val distanceToTiles = getDistanceToTiles()
@ -209,6 +210,8 @@ class UnitMovementAlgorithms(val unit:MapUnit) {
fun canReach(destination: TileInfo): Boolean { fun canReach(destination: TileInfo): Boolean {
if (unit.type.isAirUnit()) if (unit.type.isAirUnit())
return unit.currentTile.aerialDistanceTo(destination) <= unit.getRange()*2 return unit.currentTile.aerialDistanceTo(destination) <= unit.getRange()*2
if (unit.action == Constants.unitActionParadrop)
return getDistance(unit.currentTile.position, destination.position) <= unit.paradropRange && canParadropOn(destination)
return getShortestPath(destination).any() return getShortestPath(destination).any()
} }
@ -239,13 +242,27 @@ class UnitMovementAlgorithms(val unit:MapUnit) {
fun moveToTile(destination: TileInfo) { fun moveToTile(destination: TileInfo) {
if (destination == unit.getTile()) return // already here! if (destination == unit.getTile()) return // already here!
if (unit.type.isAirUnit()) { // they move differently from all other units if (unit.type.isAirUnit()) { // air units move differently from all other units
unit.action = null unit.action = null
unit.removeFromTile() unit.removeFromTile()
unit.isTransported = false // it has left the carrier by own means unit.isTransported = false // it has left the carrier by own means
unit.putInTile(destination) unit.putInTile(destination)
unit.currentMovement = 0f unit.currentMovement = 0f
return return
} else if (unit.action == Constants.unitActionParadrop) { // paratrooping move differently
unit.action = null
unit.removeFromTile()
unit.putInTile(destination)
unit.currentMovement -= 1f
// Check if unit maintenance changed
// Is also done for other units, but because we skip everything else, we have to manually check it
// The reasong we skip everything, is that otherwise `getPathToTile()` throws an exception
// As we can not reach our destination in a single turn
if (unit.canGarrison()
&& (unit.getTile().isCityCenter() || destination.isCityCenter())
&& unit.civInfo.hasUnique("Units in cities cost no Maintenance")
) unit.civInfo.updateStatsForNextTurn()
return
} }
val distanceToTiles = getDistanceToTiles() val distanceToTiles = getDistanceToTiles()
@ -326,7 +343,14 @@ class UnitMovementAlgorithms(val unit:MapUnit) {
} }
return false return false
} }
// Can a paratrooper land at this tile?
fun canParadropOn(destination: TileInfo): Boolean {
// Can only move to land tiles within range that are visible and not impassible
// Based on some testing done in the base game
if (!destination.isLand || destination.isImpassible() || !unit.civInfo.viewableTiles.contains(destination)) return false
return true
}
// This is the most called function in the entire game, // This is the most called function in the entire game,
// so multiple callees of this function have been optimized, // so multiple callees of this function have been optimized,

View File

@ -10,17 +10,18 @@ data class UnitAction(
enum class UnitActionType(val value: String) { enum class UnitActionType(val value: String) {
Automate("Automate"), Automate("Automate"),
StopMovement("Stop movement"),
StopAutomation("Stop automation"), StopAutomation("Stop automation"),
StopExploration("Stop exploration"), StopMovement("Stop movement"),
Sleep("Sleep"), Sleep("Sleep"),
SleepUntilHealed("Sleep until healed"), SleepUntilHealed("Sleep until healed"),
Fortify("Fortify"), Fortify("Fortify"),
FortifyUntilHealed("Fortify until healed"), FortifyUntilHealed("Fortify until healed"),
Explore("Explore"), Explore("Explore"),
StopExploration("Stop exploration"),
Promote("Promote"), Promote("Promote"),
Upgrade("Upgrade"), Upgrade("Upgrade"),
Pillage("Pillage"), Pillage("Pillage"),
Paradrop("Paradrop"),
SetUp("Set up"), SetUp("Set up"),
FoundCity("Found city"), FoundCity("Found city"),
ConstructImprovement("Construct improvement"), ConstructImprovement("Construct improvement"),

View File

@ -4,7 +4,7 @@ import com.badlogic.gdx.Application
import com.badlogic.gdx.Gdx import com.badlogic.gdx.Gdx
import com.unciv.logic.GameSaver import com.unciv.logic.GameSaver
data class WindowState (val width:Int=0, val height:Int=0) data class WindowState (val width: Int = 900, val height: Int = 600)
class GameSettings { class GameSettings {
var showWorkedTiles: Boolean = false var showWorkedTiles: Boolean = false

View File

@ -413,8 +413,8 @@ class Building : NamedStats(), IConstruction {
civInfo.victoryManager.currentsSpaceshipParts.add(name, 1) civInfo.victoryManager.currentsSpaceshipParts.add(name, 1)
return true return true
} }
cityConstructions.addBuilding(name)
cityConstructions.addBuilding(name)
val improvement = getImprovement(civInfo.gameInfo.ruleSet) val improvement = getImprovement(civInfo.gameInfo.ruleSet)
if (improvement != null) { if (improvement != null) {

View File

@ -218,7 +218,11 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
val turnsToGetThere = if (unit.type.isAirUnit()) { val turnsToGetThere = if (unit.type.isAirUnit()) {
if (unit.movement.canReach(tileInfo)) 1 if (unit.movement.canReach(tileInfo)) 1
else 0 else 0
} else unit.movement.getShortestPath(tileInfo).size // this is what takes the most time, tbh } else if (unit.action == Constants.unitActionParadrop) {
if (unit.movement.canReach(tileInfo)) 1
else 0
} else
unit.movement.getShortestPath(tileInfo).size // this is what takes the most time, tbh
unitToTurnsToTile[unit] = turnsToGetThere unitToTurnsToTile[unit] = turnsToGetThere
} }
@ -393,11 +397,15 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
} }
val isAirUnit = unit.type.isAirUnit() val isAirUnit = unit.type.isAirUnit()
val tilesInMoveRange = val moveTileOverlayColor = if (unit.action == Constants.unitActionParadrop) Color.BLUE else Color.WHITE
if (isAirUnit) val tilesInMoveRange =
unit.getTile().getTilesInDistanceRange(IntRange(1, unit.getRange() * 2)) if (isAirUnit)
else unit.getTile().getTilesInDistanceRange(IntRange(1, unit.getRange() * 2))
unit.movement.getDistanceToTiles().keys.asSequence() else if (unit.action == Constants.unitActionParadrop)
unit.getTile().getTilesInDistance(unit.paradropRange)
.filter { unit.movement.canParadropOn(it) }
else
unit.movement.getDistanceToTiles().keys.asSequence()
for (tile in tilesInMoveRange) { for (tile in tilesInMoveRange) {
for (tileToColor in tileGroups[tile]!!) { for (tileToColor in tileGroups[tile]!!) {
@ -411,7 +419,7 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
} }
if (unit.movement.canMoveTo(tile) || if (unit.movement.canMoveTo(tile) ||
unit.movement.isUnknownTileWeShouldAssumeToBePassable(tile) && !unit.type.isAirUnit()) unit.movement.isUnknownTileWeShouldAssumeToBePassable(tile) && !unit.type.isAirUnit())
tileToColor.showCircle(Color.WHITE, tileToColor.showCircle(moveTileOverlayColor,
if (UncivGame.Current.settings.singleTapMove || isAirUnit) 0.7f else 0.3f) if (UncivGame.Current.settings.singleTapMove || isAirUnit) 0.7f else 0.3f)
} }
} }

View File

@ -51,6 +51,7 @@ object UnitActions {
addPromoteAction(unit, actionList) addPromoteAction(unit, actionList)
addUnitUpgradeAction(unit, actionList) addUnitUpgradeAction(unit, actionList)
addPillageAction(unit, actionList, worldScreen) addPillageAction(unit, actionList, worldScreen)
addParadropAction(unit, actionList, worldScreen)
addSetupAction(unit, actionList) addSetupAction(unit, actionList)
addFoundCityAction(unit, actionList, tile) addFoundCityAction(unit, actionList, tile)
addWorkerActions(unit, actionList, tile, worldScreen, unitTable) addWorkerActions(unit, actionList, tile, worldScreen, unitTable)
@ -152,6 +153,26 @@ object UnitActions {
}.takeIf { unit.currentMovement > 0 && !isSetUp }) }.takeIf { unit.currentMovement > 0 && !isSetUp })
} }
private fun addParadropAction(unit: MapUnit, actionList: ArrayList<UnitAction>, worldScreen: WorldScreen) {
val paradropUniques = unit.getMatchingUniques("May Paradrop up to [] tiles from inside friendly territory")
if (!paradropUniques.any() || unit.isEmbarked()) return
unit.paradropRange = paradropUniques.maxOfOrNull { it.params[0] }!!.toInt()
actionList += UnitAction(UnitActionType.Paradrop,
isCurrentAction = unit.action == Constants.unitActionParadrop,
action = {
if (unit.action != Constants.unitActionParadrop) {
unit.action = Constants.unitActionParadrop
} else {
unit.action = null
}
}.takeIf {
unit.currentMovement == unit.getMaxMovement().toFloat() &&
unit.currentTile.isFriendlyTerritory(unit.civInfo) &&
!unit.isEmbarked()
})
}
private fun addPillageAction(unit: MapUnit, actionList: ArrayList<UnitAction>, worldScreen: WorldScreen) { private fun addPillageAction(unit: MapUnit, actionList: ArrayList<UnitAction>, worldScreen: WorldScreen) {
val pillageAction = getPillageAction(unit) val pillageAction = getPillageAction(unit)
if (pillageAction == null) return if (pillageAction == null) return

View File

@ -49,12 +49,13 @@ class UnitActionsTable(val worldScreen: WorldScreen) : Table() {
"Start Golden Age" -> return UnitIconAndKey(ImageGetter.getUnitIcon("Great Artist"), 'g') "Start Golden Age" -> return UnitIconAndKey(ImageGetter.getUnitIcon("Great Artist"), 'g')
"Hurry Wonder" -> return UnitIconAndKey(ImageGetter.getUnitIcon("Great Engineer"), 'g') "Hurry Wonder" -> return UnitIconAndKey(ImageGetter.getUnitIcon("Great Engineer"), 'g')
"Conduct Trade Mission" -> return UnitIconAndKey(ImageGetter.getUnitIcon("Great Merchant"), 'g') "Conduct Trade Mission" -> return UnitIconAndKey(ImageGetter.getUnitIcon("Great Merchant"), 'g')
"Construct road" -> return UnitIconAndKey(ImageGetter.getImprovementIcon("Road"), 'r')
"Paradrop" -> return UnitIconAndKey(ImageGetter.getUnitIcon("Paratrooper"), 'p')
"Set up" -> return UnitIconAndKey(ImageGetter.getUnitIcon("Catapult"), 't') "Set up" -> return UnitIconAndKey(ImageGetter.getUnitIcon("Catapult"), 't')
"Disband unit" -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/DisbandUnit"))
"Explore" -> return UnitIconAndKey(ImageGetter.getUnitIcon("Scout"), 'x') "Explore" -> return UnitIconAndKey(ImageGetter.getUnitIcon("Scout"), 'x')
"Stop exploration" -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/Stop"), 'x') "Stop exploration" -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/Stop"), 'x')
"Pillage" -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/Pillage"), 'p') "Pillage" -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/Pillage"), 'p')
"Construct road" -> return UnitIconAndKey(ImageGetter.getImprovementIcon("Road"), 'r') "Disband unit" -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/DisbandUnit"))
else -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/Star")) else -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/Star"))
} }
} }

View File

@ -6,10 +6,14 @@ import club.minnced.discord.rpc.DiscordRichPresence
import com.badlogic.gdx.Files import com.badlogic.gdx.Files
import com.badlogic.gdx.backends.lwjgl.LwjglApplication import com.badlogic.gdx.backends.lwjgl.LwjglApplication
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
import com.badlogic.gdx.files.FileHandle
import com.badlogic.gdx.graphics.Texture import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.tools.texturepacker.TexturePacker import com.badlogic.gdx.tools.texturepacker.TexturePacker
import com.unciv.JsonParser
import com.unciv.UncivGame import com.unciv.UncivGame
import com.unciv.UncivGameParameters import com.unciv.UncivGameParameters
import com.unciv.logic.GameSaver
import com.unciv.models.metadata.GameSettings
import com.unciv.models.translations.tr import com.unciv.models.translations.tr
import com.unciv.ui.utils.Fonts import com.unciv.ui.utils.Fonts
import io.ktor.application.* import io.ktor.application.*
@ -39,6 +43,11 @@ internal object DesktopLauncher {
config.addIcon("ExtraImages/Icon.png", Files.FileType.Internal) config.addIcon("ExtraImages/Icon.png", Files.FileType.Internal)
config.title = "Unciv" config.title = "Unciv"
config.useHDPI = true config.useHDPI = true
if (FileHandle(GameSaver.settingsFileName).exists()) {
val settings = JsonParser().getFromJson(GameSettings::class.java, FileHandle(GameSaver.settingsFileName))
config.width = settings.windowState.width
config.height = settings.windowState.height
}
val versionFromJar = DesktopLauncher.javaClass.`package`.specificationVersion ?: "Desktop" val versionFromJar = DesktopLauncher.javaClass.`package`.specificationVersion ?: "Desktop"

View File

@ -104,6 +104,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
* [Nuclear Missile](https://thenounproject.com/marialuisa.iborra/collection/missiles-bombs/?i=1022574) By Lluisa Iborra, ES * [Nuclear Missile](https://thenounproject.com/marialuisa.iborra/collection/missiles-bombs/?i=1022574) By Lluisa Iborra, ES
* Icon for Carrier made by [JackRainy](https://github.com/JackRainy), based on [Aircraft Carrier](https://thenounproject.com/icolabs/collection/flat-icons-transport/?i=2332914) By IcoLabs, BR * Icon for Carrier made by [JackRainy](https://github.com/JackRainy), based on [Aircraft Carrier](https://thenounproject.com/icolabs/collection/flat-icons-transport/?i=2332914) By IcoLabs, BR
* [Water Gun](https://thenounproject.com/term/water-gun/2121571) by ProSymbols for Marine * [Water Gun](https://thenounproject.com/term/water-gun/2121571) by ProSymbols for Marine
* [Parachute](https://thenounproject.com/term/parachute/2025018) by Nociconist for Paratrooper*
### Great People ### Great People