Add multiplayer turn sound notification (#6995)

* Refactor: Extract methods & reduce code duplication

* Refactor: Rename Sounds to SoundPlayer

* Refactor: Make UncivSound a data class

As far as I can see, UncivSoundConstants served no purpose

* Refactor: Reorder sounds

* Refactor: Split up ExtensionFunctions and move into own package

* Add multiplayer turn sound notification

* Refactor: Remove unnecessary double translation

* Refactor: Reduce code duplication

* Refactor: No if for boolean logic
This commit is contained in:
Timo T 2022-06-10 15:44:29 +02:00 committed by GitHub
parent 9918353c66
commit 3e6fc0e22a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
182 changed files with 1730 additions and 972 deletions

View File

@ -602,12 +602,16 @@ Resign =
Are you sure you want to resign? =
You can only resign if it's your turn =
[civName] resigned and is now controlled by AI =
Last refresh: [time] [timeUnit] ago =
Current Turn: [civName] since [time] [timeUnit] ago =
Last refresh: [duration] ago =
Current Turn: [civName] since [duration] ago =
Seconds =
Minutes =
Hours =
Days =
[amount] Seconds =
[amount] Minutes =
[amount] Hours =
[amount] Days =
Server limit reached! Please wait for [time] seconds =
File could not be found on the multiplayer server =
Unhandled problem, [errorMessage] =
@ -1395,7 +1399,7 @@ Doing this will reset your current user ID to the clipboard contents - are you s
ID successfully set! =
Invalid ID! =
# Multiplayer options menu
# Multiplayer options tab
Enable multiplayer status button in singleplayer games =
Update status of currently played game every: =
@ -1406,7 +1410,12 @@ Check connection to server =
Awaiting response... =
Success! =
Failed! =
Sound notification for when it's your turn in your currently open game: =
Sound notification for when it's your turn in any other game: =
Notification [number] =
Chimes =
Choir =
[unit] Attack Sound =
# Mods

Binary file not shown.

Binary file not shown.

View File

@ -1,7 +1,7 @@
package com.unciv
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.Input
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Touchable
import com.badlogic.gdx.scenes.scene2d.actions.Actions
import com.badlogic.gdx.scenes.scene2d.ui.Table
@ -14,22 +14,35 @@ import com.unciv.logic.map.MapSizeNew
import com.unciv.logic.map.MapType
import com.unciv.logic.map.mapgenerator.MapGenerator
import com.unciv.models.metadata.BaseRuleset
import com.unciv.models.ruleset.RulesetCache
import com.unciv.ui.multiplayer.MultiplayerScreen
import com.unciv.ui.mapeditor.*
import com.unciv.models.metadata.GameSetupInfo
import com.unciv.models.ruleset.RulesetCache
import com.unciv.ui.civilopedia.CivilopediaScreen
import com.unciv.ui.crashhandling.launchCrashHandling
import com.unciv.ui.crashhandling.postCrashHandlingRunnable
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.mapeditor.EditorMapHolder
import com.unciv.ui.mapeditor.MapEditorScreen
import com.unciv.ui.multiplayer.MultiplayerScreen
import com.unciv.ui.map.TileGroupMap
import com.unciv.ui.newgamescreen.NewGameScreen
import com.unciv.ui.pickerscreens.ModManagementScreen
import com.unciv.ui.popup.*
import com.unciv.ui.popup.ExitGamePopup
import com.unciv.ui.popup.Popup
import com.unciv.ui.popup.ToastPopup
import com.unciv.ui.popup.closeAllPopups
import com.unciv.ui.popup.hasOpenPopups
import com.unciv.ui.popup.popups
import com.unciv.ui.saves.LoadGameScreen
import com.unciv.ui.saves.QuickSave
import com.unciv.ui.utils.*
import com.unciv.ui.utils.AutoScrollPane
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.KeyCharAndCode
import com.unciv.ui.utils.UncivTooltip.Companion.addTooltip
import com.unciv.ui.utils.extensions.center
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.setFontSize
import com.unciv.ui.utils.extensions.surroundWithCircle
import com.unciv.ui.utils.extensions.toLabel
import com.unciv.ui.worldscreen.mainmenu.WorldScreenMenuPopup
import kotlin.math.min

View File

@ -9,18 +9,16 @@ import com.badlogic.gdx.utils.Align
import com.unciv.logic.GameInfo
import com.unciv.logic.GameSaver
import com.unciv.logic.civilization.PlayerType
import com.unciv.logic.multiplayer.OnlineMultiplayer
import com.unciv.models.metadata.GameSettings
import com.unciv.models.ruleset.RulesetCache
import com.unciv.models.tilesets.TileSetCache
import com.unciv.models.translations.Translations
import com.unciv.ui.LanguagePickerScreen
import com.unciv.ui.audio.GameSounds
import com.unciv.ui.audio.MusicController
import com.unciv.ui.audio.MusicMood
import com.unciv.ui.utils.*
import com.unciv.ui.worldscreen.PlayerReadyScreen
import com.unciv.ui.worldscreen.WorldScreen
import com.unciv.logic.multiplayer.OnlineMultiplayer
import com.unciv.ui.LanguagePickerScreen
import com.unciv.ui.audio.Sounds
import com.unciv.ui.audio.SoundPlayer
import com.unciv.ui.crashhandling.closeExecutors
import com.unciv.ui.crashhandling.launchCrashHandling
import com.unciv.ui.crashhandling.postCrashHandlingRunnable
@ -28,6 +26,11 @@ import com.unciv.ui.images.ImageGetter
import com.unciv.ui.multiplayer.LoadDeepLinkScreen
import com.unciv.ui.multiplayer.MultiplayerHelpers
import com.unciv.ui.popup.Popup
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.extensions.center
import com.unciv.ui.crashhandling.wrapCrashHandlingUnit
import com.unciv.ui.worldscreen.PlayerReadyScreen
import com.unciv.ui.worldscreen.WorldScreen
import com.unciv.utils.debug
import kotlinx.coroutines.runBlocking
import java.util.*
@ -103,6 +106,7 @@ class UncivGame(parameters: UncivGameParameters) : Game() {
*/
settings = gameSaver.getGeneralSettings() // needed for the screen
screen = LoadingScreen() // NOT dependent on any atlas or skin
GameSounds.init()
musicController = MusicController() // early, but at this point does only copy volume from settings
audioExceptionHelper?.installHooks(
musicController.getAudioLoopCallback(),
@ -194,23 +198,25 @@ class UncivGame(parameters: UncivGameParameters) : Game() {
}
private fun tryLoadDeepLinkedGame() = launchCrashHandling("LoadDeepLinkedGame") {
if (deepLinkedMultiplayerGame != null) {
if (deepLinkedMultiplayerGame == null) return@launchCrashHandling
postCrashHandlingRunnable {
setScreen(LoadDeepLinkScreen())
}
try {
onlineMultiplayer.loadGame(deepLinkedMultiplayerGame!!)
} catch (ex: Exception) {
postCrashHandlingRunnable {
setScreen(LoadDeepLinkScreen())
}
try {
onlineMultiplayer.loadGame(deepLinkedMultiplayerGame!!)
} catch (ex: Exception) {
postCrashHandlingRunnable {
val mainMenu = MainMenuScreen()
setScreen(mainMenu)
val popup = Popup(mainMenu)
popup.addGoodSizedLabel(MultiplayerHelpers.getLoadExceptionMessage(ex))
popup.row()
popup.addCloseButton()
popup.open()
}
val mainMenu = MainMenuScreen()
setScreen(mainMenu)
val popup = Popup(mainMenu)
popup.addGoodSizedLabel(MultiplayerHelpers.getLoadExceptionMessage(ex))
popup.row()
popup.addCloseButton()
popup.open()
}
} finally {
deepLinkedMultiplayerGame = null
}
}
@ -242,7 +248,7 @@ class UncivGame(parameters: UncivGameParameters) : Game() {
Gdx.input.inputProcessor = null // don't allow ANRs when shutting down, that's silly
cancelDiscordEvent?.invoke()
Sounds.clearCache()
SoundPlayer.clearCache()
if (::musicController.isInitialized) musicController.gracefulShutdown() // Do allow fade-out
closeExecutors()
@ -274,6 +280,8 @@ class UncivGame(parameters: UncivGameParameters) : Game() {
companion object {
lateinit var Current: UncivGame
fun isCurrentInitialized() = this::Current.isInitialized
fun isCurrentGame(gameId: String): Boolean = isCurrentInitialized() && Current.isGameInfoInitialized() && Current.gameInfo.gameId == gameId
fun isDeepLinkedGameLoading() = isCurrentInitialized() && Current.deepLinkedMultiplayerGame != null
}
}

View File

@ -8,7 +8,7 @@ import com.unciv.logic.map.TileInfo
import com.unciv.logic.map.TileMap
import com.unciv.models.metadata.GameSpeed
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.ui.utils.randomWeighted
import com.unciv.ui.utils.extensions.randomWeighted
import java.util.*
import kotlin.math.max
import kotlin.math.min

View File

@ -3,9 +3,13 @@ package com.unciv.logic.battle
import com.badlogic.gdx.math.Vector2
import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.utils.debug
import com.unciv.logic.city.CityInfo
import com.unciv.logic.civilization.*
import com.unciv.logic.civilization.AlertType
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.LocationAction
import com.unciv.logic.civilization.NotificationIcon
import com.unciv.logic.civilization.PlayerType
import com.unciv.logic.civilization.PopupAlert
import com.unciv.logic.civilization.diplomacy.DiplomaticModifiers
import com.unciv.logic.civilization.diplomacy.DiplomaticStatus
import com.unciv.logic.map.RoadStatus
@ -18,7 +22,8 @@ import com.unciv.models.ruleset.unique.Unique
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.stats.Stat
import com.unciv.models.stats.Stats
import com.unciv.ui.utils.toPercent
import com.unciv.ui.utils.extensions.toPercent
import com.unciv.utils.debug
import java.util.*
import kotlin.math.max
import kotlin.math.min

View File

@ -8,7 +8,7 @@ import com.unciv.models.ruleset.unique.Unique
import com.unciv.models.ruleset.unique.UniqueTarget
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.translations.tr
import com.unciv.ui.utils.toPercent
import com.unciv.ui.utils.extensions.toPercent
import java.util.*
import kotlin.collections.set
import kotlin.math.max

View File

@ -7,7 +7,7 @@ import com.unciv.models.UncivSound
import com.unciv.models.ruleset.unique.StateForConditionals
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.ruleset.unit.UnitType
import com.unciv.ui.utils.toPercent
import com.unciv.ui.utils.extensions.toPercent
import kotlin.math.pow
import kotlin.math.roundToInt
@ -54,14 +54,14 @@ class CityCombatant(val city: CityInfo) : ICombatant {
// The way all of this adds up...
// All ancient techs - 0.5 extra, Classical - 2.7, Medieval - 8, Renaissance - 17.5,
// Industrial - 32.4, Modern - 51, Atomic - 72.5, All - 118.3
// Garrisoned unit gives up to 20% of strength to city, health-dependant
if (cityTile.militaryUnit != null)
strength += cityTile.militaryUnit!!.baseUnit().strength * (cityTile.militaryUnit!!.health / 100f) * modConstants.cityStrengthFromGarrison
var buildingsStrength = city.cityConstructions.getBuiltBuildings().sumOf { it.cityStrength }.toFloat()
val stateForConditionals = StateForConditionals(getCivInfo(), city, ourCombatant = this, combatAction = combatAction)
for (unique in getCivInfo().getMatchingUniques(UniqueType.BetterDefensiveBuildings, stateForConditionals))
buildingsStrength *= unique.params[0].toPercent()
strength += buildingsStrength
@ -70,4 +70,4 @@ class CityCombatant(val city: CityInfo) : ICombatant {
}
override fun toString() = city.name // for debug
}
}

View File

@ -19,8 +19,8 @@ class MapUnitCombatant(val unit: MapUnit) : ICombatant {
override fun isInvisible(to: CivilizationInfo): Boolean = unit.isInvisible(to)
override fun canAttack(): Boolean = unit.canAttack()
override fun matchesCategory(category: String) = unit.matchesFilter(category)
override fun getAttackSound() = unit.baseUnit.attackSound.let {
if (it==null) UncivSound.Click else UncivSound.custom(it)
override fun getAttackSound() = unit.baseUnit.attackSound.let {
if (it == null) UncivSound.Click else UncivSound(it)
}
override fun takeDamage(damage: Int) {
@ -50,10 +50,10 @@ class MapUnitCombatant(val unit: MapUnit) : ICombatant {
return unit.name+" of "+unit.civInfo.civName
}
fun getMatchingUniques(uniqueType: UniqueType, conditionalState: StateForConditionals, checkCivUniques: Boolean): Sequence<Unique> =
fun getMatchingUniques(uniqueType: UniqueType, conditionalState: StateForConditionals, checkCivUniques: Boolean): Sequence<Unique> =
unit.getMatchingUniques(uniqueType, conditionalState, checkCivUniques)
fun hasUnique(uniqueType: UniqueType, conditionalState: StateForConditionals? = null): Boolean =
if (conditionalState == null) unit.hasUnique(uniqueType)
else unit.hasUnique(uniqueType, conditionalState)
}
}

View File

@ -6,7 +6,7 @@ import com.unciv.logic.automation.ConstructionAutomation
import com.unciv.logic.civilization.AlertType
import com.unciv.logic.civilization.NotificationIcon
import com.unciv.logic.civilization.PopupAlert
import com.unciv.logic.map.MapUnit // for Kdoc only
import com.unciv.logic.map.MapUnit
import com.unciv.logic.map.TileInfo
import com.unciv.models.ruleset.Building
import com.unciv.models.ruleset.Ruleset
@ -21,11 +21,9 @@ import com.unciv.models.translations.tr
import com.unciv.ui.civilopedia.CivilopediaCategories
import com.unciv.ui.civilopedia.FormattedLine
import com.unciv.ui.utils.Fonts
import com.unciv.ui.utils.withItem
import com.unciv.ui.utils.withoutItem
import com.unciv.ui.worldscreen.unit.UnitActions // for Kdoc only
import java.util.*
import kotlin.collections.ArrayList
import com.unciv.ui.utils.extensions.withItem
import com.unciv.ui.utils.extensions.withoutItem
import com.unciv.ui.worldscreen.unit.UnitActions
import kotlin.math.ceil
import kotlin.math.roundToInt

View File

@ -7,9 +7,9 @@ import com.unciv.logic.civilization.NotificationIcon
import com.unciv.logic.map.TileInfo
import com.unciv.models.ruleset.unique.LocalUniqueCache
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.ui.utils.toPercent
import com.unciv.ui.utils.withItem
import com.unciv.ui.utils.withoutItem
import com.unciv.ui.utils.extensions.toPercent
import com.unciv.ui.utils.extensions.withItem
import com.unciv.ui.utils.extensions.withoutItem
import kotlin.math.max
import kotlin.math.pow
import kotlin.math.roundToInt
@ -64,18 +64,18 @@ class CityExpansionManager {
val baseCost = 50
val distanceFromCenter = tileInfo.aerialDistanceTo(cityInfo.getCenterTile())
var cost = baseCost * (distanceFromCenter - 1) + tilesClaimed() * 5.0
for (unique in cityInfo.getMatchingUniques(UniqueType.TileCostPercentage)) {
if (cityInfo.matchesFilter(unique.params[1]))
cost *= unique.params[0].toPercent()
}
return cost.roundToInt()
}
fun getChoosableTiles() = cityInfo.getCenterTile().getTilesInDistance(5)
.filter { it.getOwner() == null }
fun chooseNewTileToOwn(): TileInfo? {
// Technically, in the original a random tile with the lowest score was selected
// However, doing this requires either caching it, which is way more work,

View File

@ -2,7 +2,6 @@
import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.utils.debug
import com.unciv.logic.battle.Battle
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.NotificationIcon
@ -12,7 +11,8 @@ import com.unciv.logic.trade.TradeLogic
import com.unciv.logic.trade.TradeOffer
import com.unciv.logic.trade.TradeType
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.ui.utils.withoutItem
import com.unciv.ui.utils.extensions.withoutItem
import com.unciv.utils.debug
import kotlin.math.max
import kotlin.math.min
import kotlin.math.roundToInt

View File

@ -7,13 +7,13 @@ import com.unciv.models.Religion
import com.unciv.models.metadata.GameSpeed
import com.unciv.models.ruleset.unique.Unique
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.ui.utils.toPercent
import com.unciv.ui.utils.extensions.toPercent
class CityInfoReligionManager {
@Transient
lateinit var cityInfo: CityInfo
// This needs to be kept track of for the
// This needs to be kept track of for the
// "[Stats] when a city adopts this religion for the first time" unique
val religionsAtSomePointAdopted: HashSet<String> = hashSetOf()
@ -21,7 +21,7 @@ class CityInfoReligionManager {
// Cached because using `updateNumberOfFollowers` to get this value resulted in many calls
@Transient
private val followers: Counter<String> = Counter()
@delegate:Transient
private val pressureFromAdjacentCities: Int by lazy {
when (cityInfo.civInfo.gameInfo.gameParameters.gameSpeed) {
@ -31,13 +31,13 @@ class CityInfoReligionManager {
GameSpeed.Marathon -> 2
}
}
var religionThisIsTheHolyCityOf: String? = null
var religionThisIsTheHolyCityOf: String? = null
init {
clearAllPressures()
}
fun clone(): CityInfoReligionManager {
val toReturn = CityInfoReligionManager()
toReturn.cityInfo = cityInfo
@ -47,7 +47,7 @@ class CityInfoReligionManager {
toReturn.religionThisIsTheHolyCityOf = religionThisIsTheHolyCityOf
return toReturn
}
fun setTransients(cityInfo: CityInfo) {
this.cityInfo = cityInfo
// We don't need to check for changes in the majority religion, and as this
@ -55,33 +55,33 @@ class CityInfoReligionManager {
// have any effect
updateNumberOfFollowers(false)
}
fun endTurn() {
getAffectedBySurroundingCities()
}
fun getUniques(): Sequence<Unique> {
val majorityReligion = getMajorityReligion() ?: return sequenceOf()
return majorityReligion.getFollowerUniques()
}
fun getPressures(): Counter<String> = pressures.clone()
private fun clearAllPressures() {
pressures.clear()
// We add pressure for following no religion
// Basically used as a failsafe so that there is always some religion,
// Basically used as a failsafe so that there is always some religion,
// and we don't suddenly divide by 0 somewhere
// Should be removed when updating the followers so it never becomes the majority religion,
// Should be removed when updating the followers so it never becomes the majority religion,
// `null` is used for that instead.
pressures.add(Constants.noReligionName, 100)
}
fun addPressure(religionName: String, amount: Int, shouldUpdateFollowers: Boolean = true) {
if (!cityInfo.civInfo.gameInfo.isReligionEnabled()) return // No religion, no pressures
pressures.add(religionName, amount)
if (shouldUpdateFollowers) {
updateNumberOfFollowers(shouldUpdateFollowers)
}
@ -96,12 +96,12 @@ class CityInfoReligionManager {
if (pressureFromAtheism != null) pressures[Constants.noReligionName] = pressureFromAtheism
updateNumberOfFollowers()
}
fun updatePressureOnPopulationChange(populationChangeAmount: Int) {
val majorityReligion =
if (getMajorityReligionName() != null) getMajorityReligionName()!!
else Constants.noReligionName
if (populationChangeAmount > 0) {
addPressure(majorityReligion, 100 * populationChangeAmount)
} else {
@ -112,18 +112,18 @@ class CityInfoReligionManager {
private fun triggerReligionAdoption(newMajorityReligion: String) {
val newMajorityReligionObject = cityInfo.civInfo.gameInfo.religions[newMajorityReligion]!!
cityInfo.civInfo.addNotification("Your city [${cityInfo.name}] was converted to [${newMajorityReligionObject.getReligionDisplayName()}]!", cityInfo.location, NotificationIcon.Faith)
if (newMajorityReligion in religionsAtSomePointAdopted) return
val religionOwningCiv = newMajorityReligionObject.getFounder()
if (religionOwningCiv.hasUnique(UniqueType.StatsWhenAdoptingReligionSpeed) || religionOwningCiv.hasUnique(UniqueType.StatsWhenAdoptingReligion)) {
val statsGranted =
val statsGranted =
(
religionOwningCiv.getMatchingUniques(UniqueType.StatsWhenAdoptingReligionSpeed)
religionOwningCiv.getMatchingUniques(UniqueType.StatsWhenAdoptingReligionSpeed)
+ religionOwningCiv.getMatchingUniques(UniqueType.StatsWhenAdoptingReligion)
).map { it.stats }
.reduce { acc, stats -> acc + stats }
for ((key, value) in statsGranted)
religionOwningCiv.addStat(key, value.toInt())
if (cityInfo.location in religionOwningCiv.exploredTiles)
@ -140,12 +140,12 @@ class CityInfoReligionManager {
}
religionsAtSomePointAdopted.add(newMajorityReligion)
}
private fun updateNumberOfFollowers(checkForReligionAdoption: Boolean = true) {
val oldMajorityReligion =
val oldMajorityReligion =
if (checkForReligionAdoption) getMajorityReligionName()
else null
followers.clear()
if (cityInfo.population.population <= 0) return
@ -172,7 +172,7 @@ class CityInfoReligionManager {
remainders[largestRemainder.key] = 0f
unallocatedPopulation -= 1
}
followers.remove(Constants.noReligionName)
if (checkForReligionAdoption) {
@ -182,24 +182,24 @@ class CityInfoReligionManager {
}
}
}
fun getNumberOfFollowers(): Counter<String> {
return followers.clone()
}
fun getFollowersOf(religion: String): Int? {
return followers[religion]
}
fun getFollowersOfMajorityReligion(): Int {
val majorityReligion = getMajorityReligionName() ?: return 0
return followers[majorityReligion]!!
}
fun getFollowersOfOtherReligionsThan(religion: String): Int {
return followers.filterNot { it.key == religion }.values.sum()
}
/** Removes all pantheons except for the one founded by the current owner of the city
* Should be called whenever a city changes hands, e.g. conquering and trading
*/
@ -207,7 +207,7 @@ class CityInfoReligionManager {
for (pressure in pressures.keys.toList()) { // Copy the keys because we might modify
if (pressure == Constants.noReligionName) continue
val correspondingReligion = cityInfo.civInfo.gameInfo.religions[pressure]!!
if (correspondingReligion.isPantheon()
if (correspondingReligion.isPantheon()
&& correspondingReligion.foundingCivName != cityInfo.civInfo.civName
) {
pressures.remove(pressure)
@ -225,7 +225,7 @@ class CityInfoReligionManager {
else -> null
}
}
fun getMajorityReligion(): Religion? {
return cityInfo.civInfo.gameInfo.religions[getMajorityReligionName()]
}
@ -233,40 +233,40 @@ class CityInfoReligionManager {
private fun getAffectedBySurroundingCities() {
if (!cityInfo.civInfo.gameInfo.isReligionEnabled()) return // No religion, no spreading
// We don't update the amount of followers yet, as only the end result should matter
// If multiple religions would become the majority religion due to pressure,
// If multiple religions would become the majority religion due to pressure,
// this will make it so we only receive a notification for the last one.
// Also, doing it like this increases performance :D
if (cityInfo.isHolyCity()) {
addPressure(religionThisIsTheHolyCityOf!!,5 * pressureFromAdjacentCities, false)
}
val allCitiesWithinSpreadRange =
cityInfo.civInfo.gameInfo.getCities()
.filter {
it != cityInfo
&& it.getCenterTile().aerialDistanceTo(cityInfo.getCenterTile()) <= it.religion.getSpreadRange()
it != cityInfo
&& it.getCenterTile().aerialDistanceTo(cityInfo.getCenterTile()) <= it.religion.getSpreadRange()
}
for (city in allCitiesWithinSpreadRange) {
val majorityReligionOfCity = city.religion.getMajorityReligionName() ?: continue
if (!cityInfo.civInfo.gameInfo.religions[majorityReligionOfCity]!!.isMajorReligion()) continue
addPressure(majorityReligionOfCity, city.religion.pressureAmountToAdjacentCities(cityInfo), false)
addPressure(majorityReligionOfCity, city.religion.pressureAmountToAdjacentCities(cityInfo), false)
}
updateNumberOfFollowers()
}
private fun getSpreadRange(): Int {
var spreadRange = 10
for (unique in cityInfo.getLocalMatchingUniques(UniqueType.ReligionSpreadDistance)) {
spreadRange += unique.params[0].toInt()
}
if (getMajorityReligion() != null) {
for (unique in getMajorityReligion()!!.getFounder().getMatchingUniques(UniqueType.ReligionSpreadDistance))
spreadRange += unique.params[0].toInt()
}
return spreadRange
}
@ -297,12 +297,12 @@ class CityInfoReligionManager {
if (cityInfo.getCenterTile().civilianUnit?.name == "Inquisitor") return true
return false
}
private fun pressureAmountToAdjacentCities(pressuredCity: CityInfo): Int {
var pressure = pressureFromAdjacentCities.toFloat()
// Follower beliefs of this religion
for (unique in cityInfo.getLocalMatchingUniques(UniqueType.NaturalReligionSpreadStrength)) {
for (unique in cityInfo.getLocalMatchingUniques(UniqueType.NaturalReligionSpreadStrength)) {
if (pressuredCity.matchesFilter(unique.params[1]))
pressure *= unique.params[0].toPercent()
}
@ -316,4 +316,4 @@ class CityInfoReligionManager {
return pressure.toInt()
}
}
}

View File

@ -9,12 +9,16 @@ import com.unciv.models.Counter
import com.unciv.models.ruleset.Building
import com.unciv.models.ruleset.GlobalUniques
import com.unciv.models.ruleset.ModOptionsConstants
import com.unciv.models.ruleset.unique.*
import com.unciv.models.ruleset.unique.LocalUniqueCache
import com.unciv.models.ruleset.unique.StateForConditionals
import com.unciv.models.ruleset.unique.Unique
import com.unciv.models.ruleset.unique.UniqueTarget
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.models.stats.Stat
import com.unciv.models.stats.StatMap
import com.unciv.models.stats.Stats
import com.unciv.ui.utils.toPercent
import com.unciv.ui.utils.extensions.toPercent
import kotlin.math.min

View File

@ -7,7 +7,7 @@ import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.stats.INamed
import com.unciv.models.stats.Stat
import com.unciv.ui.utils.Fonts
import com.unciv.ui.utils.toPercent
import com.unciv.ui.utils.extensions.toPercent
import kotlin.math.pow
import kotlin.math.roundToInt
@ -47,7 +47,7 @@ interface INonPerpetualConstruction : IConstruction, INamed, IHasUniques {
val rejectionReasons = getRejectionReasons(cityConstructions)
return rejectionReasons.all { it.rejectionReason == RejectionReason.Unbuildable }
}
fun canBePurchasedWithAnyStat(cityInfo: CityInfo): Boolean {
return Stat.values().any { canBePurchasedWithStat(cityInfo, it) }
}
@ -61,7 +61,7 @@ interface INonPerpetualConstruction : IConstruction, INamed, IHasUniques {
if (stat == Stat.Gold) return getBaseGoldCost(cityInfo.civInfo).toInt()
val conditionalState = StateForConditionals(civInfo = cityInfo.civInfo, cityInfo = cityInfo)
// Can be purchased for [amount] [Stat] [cityFilter]
val lowestCostUnique = getMatchingUniques(UniqueType.CanBePurchasedForAmountStat, conditionalState)
.filter { it.params[1] == stat.name && cityInfo.matchesFilter(it.params[2]) }
@ -145,7 +145,7 @@ class RejectionReasons: HashSet<RejectionReasonInstance>() {
RejectionReason.NoPlaceToPutUnit,
)
}
}
}
enum class RejectionReason(val shouldShow: Boolean, val errorMessage: String) {
@ -197,7 +197,7 @@ enum class RejectionReason(val shouldShow: Boolean, val errorMessage: String) {
NoSettlerForOneCityPlayers(false, "No settlers for city-states or one-city challengers"),
NoPlaceToPutUnit(true, "No space to place this unit");
fun toInstance(errorMessage: String = this.errorMessage,
shouldShow: Boolean = this.shouldShow): RejectionReasonInstance {
return RejectionReasonInstance(this, errorMessage, shouldShow)

View File

@ -2,14 +2,13 @@ package com.unciv.logic.city
import com.unciv.logic.automation.Automation
import com.unciv.logic.civilization.NotificationIcon
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
import com.unciv.logic.map.TileInfo
import com.unciv.models.Counter
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.stats.Stat
import com.unciv.ui.utils.toPercent
import com.unciv.ui.utils.withItem
import com.unciv.ui.utils.withoutItem
import com.unciv.ui.utils.extensions.toPercent
import com.unciv.ui.utils.extensions.withItem
import com.unciv.ui.utils.extensions.withoutItem
import kotlin.math.floor
import kotlin.math.pow

View File

@ -6,13 +6,13 @@ import com.unciv.logic.map.RoadStatus
import com.unciv.models.metadata.BASE_GAME_DURATION_TURNS
import com.unciv.models.ruleset.BeliefType
import com.unciv.models.ruleset.Policy
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.models.ruleset.unique.StateForConditionals
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.stats.Stat
import com.unciv.models.stats.StatMap
import com.unciv.models.stats.Stats
import com.unciv.ui.utils.toPercent
import com.unciv.ui.utils.extensions.toPercent
import kotlin.math.max
import kotlin.math.min
import kotlin.math.pow

View File

@ -13,11 +13,20 @@ import com.unciv.logic.civilization.RuinsManager.RuinsManager
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
import com.unciv.logic.civilization.diplomacy.DiplomacyManager
import com.unciv.logic.civilization.diplomacy.DiplomaticStatus
import com.unciv.logic.map.*
import com.unciv.logic.map.MapShape
import com.unciv.logic.map.MapUnit
import com.unciv.logic.map.TileInfo
import com.unciv.logic.map.UnitMovementAlgorithms
import com.unciv.logic.trade.TradeEvaluation
import com.unciv.logic.trade.TradeRequest
import com.unciv.models.Counter
import com.unciv.models.ruleset.*
import com.unciv.models.ruleset.Building
import com.unciv.models.ruleset.Difficulty
import com.unciv.models.ruleset.Era
import com.unciv.models.ruleset.ModOptionsConstants
import com.unciv.models.ruleset.Nation
import com.unciv.models.ruleset.Policy
import com.unciv.models.ruleset.Victory
import com.unciv.models.ruleset.tile.ResourceSupplyList
import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.models.ruleset.tile.TileResource
@ -29,8 +38,8 @@ import com.unciv.models.stats.Stat
import com.unciv.models.stats.Stats
import com.unciv.models.translations.tr
import com.unciv.ui.utils.MayaCalendar
import com.unciv.ui.utils.toPercent
import com.unciv.ui.utils.withItem
import com.unciv.ui.utils.extensions.toPercent
import com.unciv.ui.utils.extensions.withItem
import com.unciv.ui.victoryscreen.RankingType
import java.util.*
import kotlin.math.max

View File

@ -1,7 +1,7 @@
package com.unciv.logic.civilization
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.ui.utils.toPercent
import com.unciv.ui.utils.extensions.toPercent
class GoldenAgeManager {
@Transient
@ -47,4 +47,4 @@ class GoldenAgeManager {
}
}
}
}

View File

@ -9,7 +9,7 @@ import com.unciv.models.ruleset.unique.UniqueTriggerActivation
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.translations.equalsPlaceholderText
import com.unciv.models.translations.getPlaceholderParameters
import com.unciv.ui.utils.toPercent
import com.unciv.ui.utils.extensions.toPercent
import kotlin.math.pow
import kotlin.math.roundToInt

View File

@ -17,8 +17,8 @@ import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.models.translations.fillPlaceholders
import com.unciv.models.translations.getPlaceholderParameters
import com.unciv.models.translations.tr
import com.unciv.ui.utils.randomWeighted
import com.unciv.ui.utils.toPercent
import com.unciv.ui.utils.extensions.randomWeighted
import com.unciv.ui.utils.extensions.toPercent
import kotlin.math.max
import kotlin.random.Random

View File

@ -6,7 +6,7 @@ import com.unciv.models.Religion
import com.unciv.models.ruleset.Belief
import com.unciv.models.ruleset.BeliefType
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.ui.utils.toPercent
import com.unciv.ui.utils.extensions.toPercent
import kotlin.random.Random
class ReligionManager {

View File

@ -4,17 +4,15 @@ import com.unciv.logic.city.CityInfo
import com.unciv.logic.map.MapSize
import com.unciv.logic.map.RoadStatus
import com.unciv.models.ruleset.Era
import com.unciv.models.ruleset.tech.Technology
import com.unciv.models.ruleset.unique.UniqueMap
import com.unciv.models.ruleset.unique.UniqueTriggerActivation
import com.unciv.models.ruleset.tech.Technology
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.ui.utils.MayaCalendar
import com.unciv.ui.utils.toPercent
import com.unciv.ui.utils.withItem
import com.unciv.ui.utils.extensions.toPercent
import com.unciv.ui.utils.extensions.withItem
import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashSet
import kotlin.math.ceil
import kotlin.math.max
import kotlin.math.min
@ -49,7 +47,7 @@ class TechManager {
var freeTechs = 0
// For calculating score
var repeatingTechsResearched = 0
var repeatingTechsResearched = 0
/** For calculating Great Scientist yields - see https://civilization.fandom.com/wiki/Great_Scientist_(Civ5) */
var scienceOfLast8Turns = IntArray(8) { 0 }
@ -120,7 +118,7 @@ class TechManager {
fun researchOfTech(TechName: String?) = techsInProgress[TechName] ?: 0
// Was once duplicated as fun scienceSpentOnTech(tech: String): Int
fun remainingScienceToTech(techName: String) = costOfTech(techName) - researchOfTech(techName)
fun turnsToTech(techName: String) = when {

View File

@ -2,13 +2,19 @@ package com.unciv.logic.civilization.diplomacy
import com.badlogic.gdx.graphics.Color
import com.unciv.Constants
import com.unciv.logic.civilization.*
import com.unciv.logic.civilization.AlertType
import com.unciv.logic.civilization.CityStatePersonality
import com.unciv.logic.civilization.CityStateType
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.NotificationIcon
import com.unciv.logic.civilization.PlayerType
import com.unciv.logic.civilization.PopupAlert
import com.unciv.logic.trade.Trade
import com.unciv.logic.trade.TradeOffer
import com.unciv.logic.trade.TradeType
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.ruleset.tile.ResourceSupplyList
import com.unciv.ui.utils.toPercent
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.ui.utils.extensions.toPercent
import kotlin.math.ceil
import kotlin.math.max
import kotlin.math.min

View File

@ -12,17 +12,20 @@ import com.unciv.logic.city.RejectionReason
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.LocationAction
import com.unciv.logic.civilization.NotificationIcon
import com.unciv.models.helpers.UnitMovementMemoryType
import com.unciv.models.UnitActionType
import com.unciv.models.helpers.UnitMovementMemoryType
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.tile.TerrainType
import com.unciv.models.ruleset.tile.TileImprovement
import com.unciv.models.ruleset.unique.*
import com.unciv.models.ruleset.unique.StateForConditionals
import com.unciv.models.ruleset.unique.Unique
import com.unciv.models.ruleset.unique.UniqueMap
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.models.ruleset.unit.UnitType
import com.unciv.models.stats.Stats
import com.unciv.ui.utils.filterAndLogic
import com.unciv.ui.utils.toPercent
import com.unciv.ui.utils.extensions.filterAndLogic
import com.unciv.ui.utils.extensions.toPercent
import java.text.DecimalFormat
import kotlin.math.pow

View File

@ -8,14 +8,21 @@ import com.unciv.logic.city.CityInfo
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.PlayerType
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.tile.*
import com.unciv.models.ruleset.unique.*
import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.models.ruleset.tile.Terrain
import com.unciv.models.ruleset.tile.TerrainType
import com.unciv.models.ruleset.tile.TileImprovement
import com.unciv.models.ruleset.tile.TileResource
import com.unciv.models.ruleset.unique.LocalUniqueCache
import com.unciv.models.ruleset.unique.StateForConditionals
import com.unciv.models.ruleset.unique.Unique
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.stats.Stat
import com.unciv.models.stats.Stats
import com.unciv.models.translations.tr
import com.unciv.ui.civilopedia.FormattedLine
import com.unciv.ui.utils.Fonts
import com.unciv.ui.utils.toPercent
import com.unciv.ui.utils.extensions.toPercent
import kotlin.math.abs
import kotlin.math.min
import kotlin.random.Random

View File

@ -5,7 +5,10 @@ import com.badlogic.gdx.math.Vector2
import com.unciv.Constants
import com.unciv.logic.HexMath
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.map.*
import com.unciv.logic.map.MapResources
import com.unciv.logic.map.MapShape
import com.unciv.logic.map.TileInfo
import com.unciv.logic.map.TileMap
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.models.ruleset.tile.Terrain
@ -17,8 +20,12 @@ import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.stats.Stat
import com.unciv.models.translations.equalsPlaceholderText
import com.unciv.models.translations.getPlaceholderParameters
import com.unciv.ui.utils.randomWeighted
import kotlin.math.*
import com.unciv.ui.utils.extensions.randomWeighted
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
import kotlin.math.pow
import kotlin.math.roundToInt
import kotlin.random.Random
class MapRegions (val ruleset: Ruleset){

View File

@ -13,7 +13,7 @@ import com.unciv.models.metadata.GameSettings
import com.unciv.ui.crashhandling.CRASH_HANDLING_DAEMON_SCOPE
import com.unciv.ui.crashhandling.launchCrashHandling
import com.unciv.ui.crashhandling.postCrashHandlingRunnable
import com.unciv.ui.utils.isLargerThan
import com.unciv.ui.utils.extensions.isLargerThan
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.launchIn

View File

@ -8,7 +8,7 @@ import com.unciv.logic.event.EventBus
import com.unciv.logic.multiplayer.storage.FileStorageRateLimitReached
import com.unciv.logic.multiplayer.storage.OnlineMultiplayerGameSaver
import com.unciv.ui.crashhandling.postCrashHandlingRunnable
import com.unciv.ui.utils.isLargerThan
import com.unciv.ui.utils.extensions.isLargerThan
import java.io.FileNotFoundException
import java.time.Duration
import java.time.Instant

View File

@ -1,10 +1,14 @@
package com.unciv.logic.multiplayer.storage
import com.unciv.utils.debug
import com.unciv.json.json
import com.unciv.ui.utils.UncivDateFormat.parseDate
import com.unciv.ui.utils.extensions.UncivDateFormat.parseDate
import com.unciv.utils.Log
import java.io.*
import com.unciv.utils.debug
import java.io.BufferedReader
import java.io.DataOutputStream
import java.io.FileNotFoundException
import java.io.InputStream
import java.io.InputStreamReader
import java.net.HttpURLConnection
import java.net.URL
import java.nio.charset.Charset

View File

@ -9,7 +9,7 @@ import com.unciv.logic.civilization.diplomacy.RelationshipLevel
import com.unciv.models.ruleset.ModOptionsConstants
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.ui.utils.toPercent
import com.unciv.ui.utils.extensions.toPercent
import com.unciv.ui.victoryscreen.RankingType
import kotlin.math.min
import kotlin.math.sqrt

View File

@ -1,79 +1,34 @@
package com.unciv.models
private enum class UncivSoundConstants (val value: String) {
Click("click"),
Fortify("fortify"),
Promote("promote"),
Upgrade("upgrade"),
Setup("setup"),
Chimes("chimes"),
Coin("coin"),
Choir("choir"),
Fire("fire"),
Policy("policy"),
Paper("paper"),
Whoosh("whoosh"),
Bombard("bombard"),
Slider("slider"),
Construction("construction"),
Swap("swap"),
Silent(""),
Custom("")
}
/**
* Represents an Unciv Sound, either from a predefined set or custom with a specified filename.
*/
class UncivSound private constructor (
private val type: UncivSoundConstants,
filename: String? = null
) {
data class UncivSound(
/** The base filename without extension. */
val value: String = filename ?: type.value
/*
init {
// Checking contract "use non-custom *w/o* filename OR custom *with* one
// Removed due to private constructor
if ((type == UncivSoundConstants.Custom) == filename.isNullOrEmpty()) {
throw IllegalArgumentException("Invalid UncivSound constructor arguments")
}
}
*/
val fileName: String
) {
/** For serialization */
private constructor() : this("")
companion object {
val Click = UncivSound(UncivSoundConstants.Click)
val Fortify = UncivSound(UncivSoundConstants.Fortify)
val Promote = UncivSound(UncivSoundConstants.Promote)
val Upgrade = UncivSound(UncivSoundConstants.Upgrade)
val Setup = UncivSound(UncivSoundConstants.Setup)
val Chimes = UncivSound(UncivSoundConstants.Chimes)
val Coin = UncivSound(UncivSoundConstants.Coin)
val Choir = UncivSound(UncivSoundConstants.Choir)
val Policy = UncivSound(UncivSoundConstants.Policy)
val Paper = UncivSound(UncivSoundConstants.Paper)
val Whoosh = UncivSound(UncivSoundConstants.Whoosh)
val Bombard = UncivSound(UncivSoundConstants.Bombard)
val Slider = UncivSound(UncivSoundConstants.Slider)
val Construction = UncivSound(UncivSoundConstants.Construction)
val Swap = UncivSound(UncivSoundConstants.Swap)
val Silent = UncivSound(UncivSoundConstants.Silent)
val Fire = UncivSound(UncivSoundConstants.Fire)
/** Creates an UncivSound instance for a custom sound.
* @param filename The base filename without extension.
*/
fun custom(filename: String) = UncivSound(UncivSoundConstants.Custom, filename)
val Bombard = UncivSound("bombard")
val Chimes = UncivSound("chimes")
val Choir = UncivSound("choir")
val Click = UncivSound("click")
val Coin = UncivSound("coin")
val Construction = UncivSound("construction")
val Fire = UncivSound("fire")
val Fortify = UncivSound("fortify")
val Notification1 = UncivSound("notification1")
val Notification2 = UncivSound("notification2")
val Paper = UncivSound("paper")
val Policy = UncivSound("policy")
val Promote = UncivSound("promote")
val Setup = UncivSound("setup")
val Silent = UncivSound("")
val Slider = UncivSound("slider")
val Swap = UncivSound("swap")
val Upgrade = UncivSound("upgrade")
val Whoosh = UncivSound("whoosh")
}
// overrides ensure usability as hash key
override fun hashCode(): Int {
return type.hashCode() xor value.hashCode()
}
override fun equals(other: Any?): Boolean {
if (other == null || other !is UncivSound) return false
if (type != other.type) return false
return type != UncivSoundConstants.Custom || value == other.value
}
override fun toString(): String = value
}
}

View File

@ -4,11 +4,11 @@ import com.badlogic.gdx.Input
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Actor
import com.badlogic.gdx.utils.Align
import com.unciv.ui.utils.KeyCharAndCode
import com.unciv.ui.images.ImageGetter
import com.unciv.Constants
import com.unciv.models.translations.getPlaceholderParameters
import com.unciv.ui.utils.darken
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.utils.KeyCharAndCode
import com.unciv.ui.utils.extensions.darken
/** Unit Actions - class - carries dynamic data and actual execution.
@ -54,7 +54,7 @@ data class UnitAction(
}
/** Unit Actions - generic enum with static properties
*
*
* @param value _default_ label to display, can be overridden in UnitAction instantiation
* @param imageGetter optional lambda to get an Icon - `null` if icon is dependent on outside factors and needs special handling
* @param key keyboard binding - can be a [KeyCharAndCode], a [Char], or omitted.
@ -97,7 +97,7 @@ enum class UnitActionType(
{ imageGetPromote() }, 'o', UncivSound.Promote),
Upgrade("Upgrade",
null, 'u', UncivSound.Upgrade),
Pillage("Pillage",
Pillage("Pillage",
{ ImageGetter.getImage("OtherIcons/Pillage") }, 'p'),
Paradrop("Paradrop",
{ ImageGetter.getUnitIcon("Paratrooper") }, 'p'),

View File

@ -4,12 +4,14 @@ import com.badlogic.gdx.Application
import com.badlogic.gdx.Gdx
import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.models.UncivSound
import com.unciv.logic.multiplayer.FriendList
import com.unciv.ui.utils.Fonts
import java.text.Collator
import java.time.Duration
import java.util.*
import kotlin.collections.HashSet
import kotlin.reflect.KClass
import kotlin.reflect.KMutableProperty0
data class WindowState (val width: Int = 900, val height: Int = 600)
@ -167,5 +169,30 @@ class GameSettingsMultiplayer {
var statusButtonInSinglePlayer = false
var currentGameRefreshDelay = Duration.ofSeconds(10)
var allGameRefreshDelay = Duration.ofMinutes(5)
var currentGameTurnNotificationSound: UncivSound = UncivSound.Silent
var otherGameTurnNotificationSound: UncivSound = UncivSound.Silent
var hideDropboxWarning = false
}
enum class GameSetting(
val kClass: KClass<*>,
private val propertyGetter: (GameSettings) -> KMutableProperty0<*>
) {
// Uncomment these once they are refactored to send events on change
// MULTIPLAYER_USER_ID(String::class, { it.multiplayer::userId }),
// MULTIPLAYER_SERVER(String::class, { it.multiplayer::server }),
// MULTIPLAYER_STATUSBUTTON_IN_SINGLEPLAYER(Boolean::class, { it.multiplayer::statusButtonInSinglePlayer }),
// MULTIPLAYER_TURN_CHECKER_ENABLED(Boolean::class, { it.multiplayer::turnCheckerEnabled }),
// MULTIPLAYER_TURN_CHECKER_PERSISTENT_NOTIFICATION_ENABLED(Boolean::class, { it.multiplayer::turnCheckerPersistentNotificationEnabled }),
// MULTIPLAYER_HIDE_DROPBOX_WARNING(Boolean::class, { it.multiplayer::hideDropboxWarning }),
MULTIPLAYER_TURN_CHECKER_DELAY(Duration::class, { it.multiplayer::turnCheckerDelay }),
MULTIPLAYER_CURRENT_GAME_REFRESH_DELAY(Duration::class, { it.multiplayer::currentGameRefreshDelay }),
MULTIPLAYER_ALL_GAME_REFRESH_DELAY(Duration::class, { it.multiplayer::allGameRefreshDelay }),
MULTIPLAYER_CURRENT_GAME_TURN_NOTIFICATION_SOUND(UncivSound::class, { it.multiplayer::currentGameTurnNotificationSound }),
MULTIPLAYER_OTHER_GAME_TURN_NOTIFICATION_SOUND(UncivSound::class, { it.multiplayer::otherGameTurnNotificationSound });
/** **Warning:** It is the obligation of the caller to select the same type [T] that the [kClass] of this property has */
fun <T> getProperty(settings: GameSettings): KMutableProperty0<T> {
return propertyGetter(settings) as KMutableProperty0<T>
}
}

View File

@ -0,0 +1,13 @@
package com.unciv.models.metadata
import com.unciv.logic.event.Event
import com.unciv.models.UncivSound
/** **Warning:** this event is in the process of completion and **not** used for all settings yet! **Only the settings in [GameSetting] get events sent!** */
interface SettingsPropertyChanged : Event {
val gameSetting: GameSetting
}
interface SettingsPropertyUncivSoundChanged : SettingsPropertyChanged {
val value: UncivSound
}

View File

@ -1,19 +1,30 @@
package com.unciv.models.ruleset
import com.unciv.logic.city.*
import com.unciv.logic.city.CityConstructions
import com.unciv.logic.city.CityInfo
import com.unciv.logic.city.INonPerpetualConstruction
import com.unciv.logic.city.RejectionReason
import com.unciv.logic.city.RejectionReasons
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.models.Counter
import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.models.ruleset.tile.TileImprovement
import com.unciv.models.ruleset.unique.*
import com.unciv.models.ruleset.unique.LocalUniqueCache
import com.unciv.models.ruleset.unique.StateForConditionals
import com.unciv.models.ruleset.unique.Unique
import com.unciv.models.ruleset.unique.UniqueFlag
import com.unciv.models.ruleset.unique.UniqueParameterType
import com.unciv.models.ruleset.unique.UniqueTarget
import com.unciv.models.ruleset.unique.UniqueTriggerActivation
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.stats.Stat
import com.unciv.models.stats.Stats
import com.unciv.models.translations.fillPlaceholders
import com.unciv.models.translations.tr
import com.unciv.ui.civilopedia.FormattedLine
import com.unciv.ui.utils.Fonts
import com.unciv.ui.utils.getConsumesAmountString
import com.unciv.ui.utils.toPercent
import com.unciv.ui.utils.extensions.getConsumesAmountString
import com.unciv.ui.utils.extensions.toPercent
import kotlin.math.pow
@ -156,7 +167,7 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction {
if (maintenance != 0 && !isFree) lines += "{Maintenance cost}: $maintenance {Gold}"
if (showAdditionalInfo && missingCities.isNotEmpty()) {
// Could be red. But IMO that should be done by enabling GDX's ColorMarkupLanguage globally instead of adding a separate label.
lines += "\n" +
lines += "\n" +
"[${cityInfo.civInfo.getEquivalentBuilding(missingUnique!!.params[0])}] required:".tr() +
" " + missingCities.joinToString(", ") { "{${it.name}}" }
// Can't nest square bracket placeholders inside curlies, and don't see any way to define wildcard placeholders. So run translation explicitly on base text.
@ -164,7 +175,7 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction {
return lines.joinToString("\n") { it.tr() }.trim()
}
fun getStats(city: CityInfo,
fun getStats(city: CityInfo,
/* By default, do not cache - if we're getting stats for only one building this isn't efficient.
* Only use a cache if it was sent to us from outside, which means we can use the results for other buildings. */
localUniqueCache: LocalUniqueCache = LocalUniqueCache(false)): Stats {
@ -193,12 +204,12 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction {
fun getStatPercentageBonuses(cityInfo: CityInfo?, localUniqueCache: LocalUniqueCache = LocalUniqueCache(false)): Stats {
val stats = percentStatBonus?.clone() ?: Stats()
val civInfo = cityInfo?.civInfo ?: return stats // initial stats
for (unique in localUniqueCache.get("StatPercentFromObject", civInfo.getMatchingUniques(UniqueType.StatPercentFromObject))) {
if (matchesFilter(unique.params[2]))
stats.add(Stat.valueOf(unique.params[1]), unique.params[0].toFloat())
}
for (unique in localUniqueCache.get("AllStatsPercentFromObject", civInfo.getMatchingUniques(UniqueType.AllStatsPercentFromObject))) {
if (!matchesFilter(unique.params[1])) continue
for (stat in Stat.values()) {

View File

@ -3,10 +3,14 @@ package com.unciv.models.ruleset
import com.badlogic.gdx.graphics.Color
import com.unciv.logic.civilization.CityStateType
import com.unciv.logic.civilization.diplomacy.RelationshipLevel
import com.unciv.models.ruleset.unique.*
import com.unciv.models.ruleset.unique.IHasUniques
import com.unciv.models.ruleset.unique.StateForConditionals
import com.unciv.models.ruleset.unique.Unique
import com.unciv.models.ruleset.unique.UniqueTarget
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.ui.civilopedia.FormattedLine
import com.unciv.ui.utils.Fonts
import com.unciv.ui.utils.colorFromRGB
import com.unciv.ui.utils.extensions.colorFromRGB
class Era : RulesetObject(), IHasUniques {
var eraNumber: Int = -1

View File

@ -12,7 +12,7 @@ import com.unciv.models.translations.squareBraceRegex
import com.unciv.models.translations.tr
import com.unciv.ui.civilopedia.FormattedLine
import com.unciv.ui.utils.Fonts
import com.unciv.ui.utils.colorFromRGB
import com.unciv.ui.utils.extensions.colorFromRGB
class Nation : RulesetObject() {
var leaderName = ""
@ -37,16 +37,16 @@ class Nation : RulesetObject() {
var uniqueText = ""
var innerColor: List<Int>? = null
var startBias = ArrayList<String>()
var startIntroPart1 = ""
var startIntroPart2 = ""
/* Properties present in json but not yet implemented:
var adjective = ArrayList<String>()
*/
var favoredReligion: String? = null
@Transient
private lateinit var outerColorObject: Color
fun getOuterColor(): Color = outerColorObject
@ -118,7 +118,7 @@ class Nation : RulesetObject() {
val link = if ('[' !in it.value) it.value
else squareBraceRegex.find(it.value)!!.groups[1]!!.value
textList += FormattedLine(
(if (it.index == 0) "[Start bias:] " else "") + it.value.tr(), // extra tr because tr cannot nest {[]}
(if (it.index == 0) "[Start bias:] " else "") + it.value.tr(), // extra tr because tr cannot nest {[]}
link = "Terrain/$link",
indent = if (it.index == 0) 0 else 1,
iconCrossed = it.value.startsWith("Avoid "))
@ -170,7 +170,7 @@ class Nation : RulesetObject() {
if (allMercantileResources.isNotEmpty()) {
textList += FormattedLine()
textList += FormattedLine("The unique luxury is one of:")
allMercantileResources.forEach {
allMercantileResources.forEach {
textList += FormattedLine(it.name, it.makeLink(), indent = 1)
}
}

View File

@ -33,7 +33,7 @@ import com.unciv.models.stats.NamedStats
import com.unciv.models.stats.Stats
import com.unciv.models.translations.fillPlaceholders
import com.unciv.models.translations.tr
import com.unciv.ui.utils.colorFromRGB
import com.unciv.ui.utils.extensions.colorFromRGB
import com.unciv.ui.utils.getRelativeTextDistance
import com.unciv.utils.Log
import com.unciv.utils.debug

View File

@ -3,12 +3,12 @@ package com.unciv.models.ruleset
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.unciv.Constants
import com.unciv.models.stats.INamed
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.models.Counter
import com.unciv.models.stats.INamed
import com.unciv.models.translations.getPlaceholderParameters
import com.unciv.models.translations.getPlaceholderText
import com.unciv.ui.utils.toTextButton
import com.unciv.ui.utils.extensions.toTextButton
enum class MilestoneType(val text: String) {
@ -41,7 +41,7 @@ class Victory : INamed {
CityStates,
Score,
}
override var name = ""
val victoryScreenHeader = "Do things to win!"
val hiddenInVictoryScreen = false
@ -57,10 +57,10 @@ class Victory : INamed {
parts.add(spaceshipPart, 1)
parts
}
val victoryString = "Your civilization stands above all others! The exploits of your people shall be remembered until the end of civilization itself!"
val defeatString = "You have been defeated. Your civilization has been overwhelmed by its many foes. But your people do not despair, for they know that one day you shall return - and lead them forward to victory!"
fun enablesMaxTurns(): Boolean = milestoneObjects.any { it.type == MilestoneType.ScoreAfterTimeOut }
fun getThingsToFocus(civInfo: CivilizationInfo): Set<Focus> = milestoneObjects
.filter { !it.hasBeenCompletedBy(civInfo) }
@ -78,7 +78,7 @@ class Milestone(val uniqueDescription: String, private val parentVictory: Victor
incompleteSpaceshipParts.remove(civInfo.victoryManager.currentsSpaceshipParts)
return incompleteSpaceshipParts
}
fun hasBeenCompletedBy(civInfo: CivilizationInfo): Boolean {
return when (type!!) {
MilestoneType.BuiltBuilding ->
@ -101,9 +101,9 @@ class Milestone(val uniqueDescription: String, private val parentVictory: Victor
&& civInfo == civInfo.gameInfo.civilizations.maxByOrNull { it.calculateTotalScore() }
}
MilestoneType.WorldReligion -> {
civInfo.gameInfo.isReligionEnabled()
civInfo.gameInfo.isReligionEnabled()
&& civInfo.religionManager.religion != null
&& civInfo.gameInfo.civilizations.all {
&& civInfo.gameInfo.civilizations.all {
it.religionManager.isMajorityReligionForCiv(civInfo.religionManager.religion!!)
}
}
@ -116,11 +116,11 @@ class Milestone(val uniqueDescription: String, private val parentVictory: Victor
else textButton.color = Color.GRAY
return textButton
}
fun getVictoryScreenButtonHeaderText(completed: Boolean, civInfo: CivilizationInfo): String {
return when (type!!) {
MilestoneType.BuildingBuiltGlobally, MilestoneType.WinDiplomaticVote,
MilestoneType.ScoreAfterTimeOut, MilestoneType.BuiltBuilding ->
MilestoneType.BuildingBuiltGlobally, MilestoneType.WinDiplomaticVote,
MilestoneType.ScoreAfterTimeOut, MilestoneType.BuiltBuilding ->
uniqueDescription
MilestoneType.CompletePolicyBranches -> {
val amountToDo = params[0]
@ -148,9 +148,9 @@ class Milestone(val uniqueDescription: String, private val parentVictory: Victor
val incompleteSpaceshipParts = parentVictory.requiredSpaceshipPartsAsCounter.clone()
val amountToDo = incompleteSpaceshipParts.sumValues()
incompleteSpaceshipParts.remove(completeSpaceshipParts)
val amountDone = amountToDo - incompleteSpaceshipParts.sumValues()
"{$uniqueDescription} ($amountDone/$amountToDo)"
}
MilestoneType.WorldReligion -> {
@ -168,10 +168,10 @@ class Milestone(val uniqueDescription: String, private val parentVictory: Victor
}
}
}
fun getVictoryScreenButtons(completionStatus: Victory.CompletionStatus, civInfo: CivilizationInfo): List<TextButton> {
val headerButton = getMilestoneButton(
getVictoryScreenButtonHeaderText(completionStatus == Victory.CompletionStatus.Completed, civInfo),
getVictoryScreenButtonHeaderText(completionStatus == Victory.CompletionStatus.Completed, civInfo),
completionStatus == Victory.CompletionStatus.Completed
)
if (completionStatus == Victory.CompletionStatus.Completed || completionStatus == Victory.CompletionStatus.Incomplete) {
@ -182,12 +182,12 @@ class Milestone(val uniqueDescription: String, private val parentVictory: Victor
val buttons = mutableListOf(headerButton)
when (type) {
// No extra buttons necessary
MilestoneType.BuiltBuilding, MilestoneType.BuildingBuiltGlobally,
MilestoneType.ScoreAfterTimeOut, MilestoneType.WinDiplomaticVote -> {}
MilestoneType.BuiltBuilding, MilestoneType.BuildingBuiltGlobally,
MilestoneType.ScoreAfterTimeOut, MilestoneType.WinDiplomaticVote -> {}
MilestoneType.AddedSSPartsInCapital -> {
val completedSpaceshipParts = civInfo.victoryManager.currentsSpaceshipParts
val incompleteSpaceshipParts = getIncompleteSpaceshipParts(civInfo)
for (part in completedSpaceshipParts) {
repeat(part.value) {
buttons.add(getMilestoneButton(part.key, true))
@ -199,7 +199,7 @@ class Milestone(val uniqueDescription: String, private val parentVictory: Victor
}
}
}
MilestoneType.DestroyAllPlayers -> {
val majorCivs = civInfo.gameInfo.civilizations.filter { it.isMajorCiv() && it != civInfo }
for (civ in majorCivs) {
@ -209,7 +209,7 @@ class Milestone(val uniqueDescription: String, private val parentVictory: Victor
buttons.add(getMilestoneButton(milestoneText, !civ.isAlive()))
}
}
MilestoneType.CaptureAllCapitals -> {
val originalCapitals = civInfo.gameInfo.getCities().filter { it.isOriginalCapital }
for (city in originalCapitals) {
@ -219,7 +219,7 @@ class Milestone(val uniqueDescription: String, private val parentVictory: Victor
buttons.add(getMilestoneButton(milestoneText, city.civInfo == civInfo))
}
}
MilestoneType.CompletePolicyBranches -> {
for (branch in civInfo.gameInfo.ruleSet.policyBranches.values) {
val finisher = branch.policies.last().name
@ -241,7 +241,7 @@ class Milestone(val uniqueDescription: String, private val parentVictory: Victor
}
return buttons
}
fun getFocus(civInfo: CivilizationInfo): Victory.Focus {
val ruleset = civInfo.gameInfo.ruleSet
return when (type!!) {
@ -275,4 +275,4 @@ class Milestone(val uniqueDescription: String, private val parentVictory: Victor
MilestoneType.WorldReligion -> Victory.Focus.Faith
}
}
}
}

View File

@ -9,7 +9,7 @@ import com.unciv.models.ruleset.unique.UniqueFlag
import com.unciv.models.ruleset.unique.UniqueTarget
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.ui.civilopedia.FormattedLine
import com.unciv.ui.utils.colorFromRGB
import com.unciv.ui.utils.extensions.colorFromRGB
class Terrain : RulesetStatsObject() {
@ -43,7 +43,7 @@ class Terrain : RulesetStatsObject() {
// Shouldn't this just be a lazy property so it's automatically cached?
fun isRough(): Boolean = hasUnique(UniqueType.RoughTerrain)
/** Tests base terrains, features and natural wonders whether they should be treated as Land/Water.
* Currently only used for civilopedia display, as other code can test the tile itself.
*/

View File

@ -13,9 +13,8 @@ import com.unciv.models.ruleset.unique.UniqueTarget
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.translations.tr
import com.unciv.ui.civilopedia.FormattedLine
import com.unciv.ui.utils.toPercent
import com.unciv.ui.utils.extensions.toPercent
import com.unciv.ui.worldscreen.unit.UnitActions
import java.util.*
import kotlin.math.roundToInt
class TileImprovement : RulesetStatsObject() {

View File

@ -6,9 +6,10 @@ import com.unciv.models.ruleset.BeliefType
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.RulesetCache
import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.models.ruleset.unique.UniqueParameterType.Companion.guessTypeForTranslationWriter
import com.unciv.models.stats.Stat
import com.unciv.models.translations.TranslationFileWriter // for Kdoc only
import com.unciv.ui.utils.filterCompositeLogic
import com.unciv.models.translations.TranslationFileWriter
import com.unciv.ui.utils.extensions.filterCompositeLogic
// 'region' names beginning with an underscore are used here for a prettier "Structure window" - they go in front ot the rest.

View File

@ -1,6 +1,10 @@
package com.unciv.models.ruleset.unit
import com.unciv.logic.city.*
import com.unciv.logic.city.CityConstructions
import com.unciv.logic.city.CityInfo
import com.unciv.logic.city.INonPerpetualConstruction
import com.unciv.logic.city.RejectionReason
import com.unciv.logic.city.RejectionReasons
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.map.MapUnit
import com.unciv.models.ruleset.Ruleset
@ -13,12 +17,9 @@ import com.unciv.models.stats.Stat
import com.unciv.models.translations.tr
import com.unciv.ui.civilopedia.FormattedLine
import com.unciv.ui.utils.Fonts
import com.unciv.ui.utils.filterAndLogic
import com.unciv.ui.utils.getConsumesAmountString
import com.unciv.ui.utils.toPercent
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
import kotlin.collections.HashSet
import com.unciv.ui.utils.extensions.filterAndLogic
import com.unciv.ui.utils.extensions.getConsumesAmountString
import com.unciv.ui.utils.extensions.toPercent
import kotlin.math.pow
// This is BaseUnit because Unit is already a base Kotlin class and to avoid mixing the two up
@ -46,8 +47,8 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
var promotions = HashSet<String>()
var obsoleteTech: String? = null
var upgradesTo: String? = null
val specialUpgradesTo: String? by lazy {
getMatchingUniques(UniqueType.RuinsUpgrade).map { it.params[0] }.firstOrNull()
val specialUpgradesTo: String? by lazy {
getMatchingUniques(UniqueType.RuinsUpgrade).map { it.params[0] }.firstOrNull()
}
var replaces: String? = null
var uniqueTo: String? = null
@ -238,8 +239,8 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
unit.owner = civInfo.civName
// must be after setting name & civInfo because it sets the baseUnit according to the name
// and the civInfo is required for using `hasUnique` when determining its movement options
unit.setTransients(civInfo.gameInfo.ruleSet)
// and the civInfo is required for using `hasUnique` when determining its movement options
unit.setTransients(civInfo.gameInfo.ruleSet)
return unit
}
@ -259,7 +260,7 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
override fun canBePurchasedWithStat(cityInfo: CityInfo?, stat: Stat): Boolean {
if (cityInfo == null) return super.canBePurchasedWithStat(cityInfo, stat)
val conditionalState = StateForConditionals(civInfo = cityInfo.civInfo, cityInfo = cityInfo)
return (cityInfo.getMatchingUniques(UniqueType.BuyUnitsIncreasingCost, conditionalState)
.any {
it.params[2] == stat.name
@ -394,17 +395,17 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
val rejectionReasons = RejectionReasons()
val ruleSet = civInfo.gameInfo.ruleSet
if (requiredTech != null && !civInfo.tech.isResearched(requiredTech!!))
rejectionReasons.add(RejectionReason.RequiresTech.toInstance("$requiredTech not researched"))
if (requiredTech != null && !civInfo.tech.isResearched(requiredTech!!))
rejectionReasons.add(RejectionReason.RequiresTech.toInstance("$requiredTech not researched"))
if (obsoleteTech != null && civInfo.tech.isResearched(obsoleteTech!!))
rejectionReasons.add(RejectionReason.Obsoleted.toInstance("Obsolete by $obsoleteTech"))
if (uniqueTo != null && uniqueTo != civInfo.civName)
if (uniqueTo != null && uniqueTo != civInfo.civName)
rejectionReasons.add(RejectionReason.UniqueToOtherNation.toInstance("Unique to $uniqueTo"))
if (ruleSet.units.values.any { it.uniqueTo == civInfo.civName && it.replaces == name })
rejectionReasons.add(RejectionReason.ReplacedByOurUnique.toInstance("Our unique unit replaces this"))
if (!civInfo.gameInfo.gameParameters.nuclearWeaponsEnabled && isNuclearWeapon())
if (!civInfo.gameInfo.gameParameters.nuclearWeaponsEnabled && isNuclearWeapon())
rejectionReasons.add(RejectionReason.DisabledBySetting)
for (unique in uniqueObjects) {
@ -481,11 +482,11 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
// If this unit has special abilities that need to be kept track of, start doing so here
if (unit.hasUnique(UniqueType.ReligiousUnit) && civInfo.gameInfo.isReligionEnabled()) {
unit.religion =
unit.religion =
if (unit.hasUnique(UniqueType.TakeReligionOverBirthCity))
civInfo.religionManager.religion?.name
else cityConstructions.cityInfo.religion.getMajorityReligionName()
unit.setupAbilityUses(cityConstructions.cityInfo)
}
@ -509,7 +510,7 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
if (unit.matchesFilter(unique.params[0]))
XP += unique.params[1].toInt()
}
unit.promotions.XP = XP
unit.promotions.XP = XP
for (unique in cityConstructions.cityInfo.getMatchingUniques(UniqueType.UnitStartingPromotions)
.filter { cityConstructions.cityInfo.matchesFilter(it.params[1]) }) {
@ -613,7 +614,7 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
&& (uniqueObjects + getType().uniqueObjects)
.any { it.isOfType(UniqueType.Strength)
&& it.params[0].toInt() > 0
&& it.conditionals.any { conditional -> conditional.isOfType(UniqueType.ConditionalVsCity) }
&& it.conditionals.any { conditional -> conditional.isOfType(UniqueType.ConditionalVsCity) }
}
)

View File

@ -8,9 +8,8 @@ import com.unciv.models.stats.Stat
import com.unciv.models.stats.Stats
import com.unciv.utils.Log
import com.unciv.utils.debug
import java.time.temporal.ChronoUnit
import java.util.*
import kotlin.collections.HashMap
import kotlin.collections.LinkedHashSet
/**
* This collection holds all translations for the game.

View File

@ -2,12 +2,12 @@ package com.unciv.ui
import com.unciv.MainMenuScreen
import com.unciv.models.translations.tr
import com.unciv.ui.options.OptionsPopup
import com.unciv.ui.pickerscreens.PickerScreen
import com.unciv.ui.utils.enable
import com.unciv.ui.utils.onClick
import com.unciv.ui.utils.LanguageTable
import com.unciv.ui.utils.LanguageTable.Companion.addLanguageTables
import com.unciv.ui.options.OptionsPopup
import com.unciv.ui.utils.extensions.enable
import com.unciv.ui.utils.extensions.onClick
/** A [PickerScreen] to select a language, used once on the initial run after a fresh install.
* After that, [OptionsPopup] provides the functionality.

View File

@ -4,8 +4,8 @@ import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.g2d.Batch
import com.badlogic.gdx.scenes.scene2d.Stage
import com.badlogic.gdx.utils.viewport.Viewport
import com.unciv.ui.utils.wrapCrashHandling
import com.unciv.ui.utils.wrapCrashHandlingUnit
import com.unciv.ui.crashhandling.wrapCrashHandling
import com.unciv.ui.crashhandling.wrapCrashHandlingUnit
/** Main stage for the game. Safely brings the game to a [CrashScreen] if any event handlers throw an exception or an error that doesn't get otherwise handled. */

View File

@ -0,0 +1,43 @@
package com.unciv.ui.audio
import com.unciv.UncivGame
import com.unciv.logic.event.EventBus
import com.unciv.logic.multiplayer.MultiplayerGameUpdated
import com.unciv.logic.multiplayer.isUsersTurn
import com.unciv.models.metadata.SettingsPropertyUncivSoundChanged
/**
* Controls which sounds should be played when something happens while playing the game.
*/
object GameSounds {
private val events = EventBus.EventReceiver()
private val settings get() = UncivGame.Current.settings
private val mpSettings get() = settings.multiplayer
/**
* Has to be called for sounds to be played.
*/
fun init() {
playSettingsSounds()
playMultiplayerTurnNotification()
}
private fun playSettingsSounds() {
events.receive(SettingsPropertyUncivSoundChanged::class) {
SoundPlayer.play(it.value)
}
}
private fun playMultiplayerTurnNotification() {
events.receive(MultiplayerGameUpdated::class, { it.preview.isUsersTurn() }) {
if (UncivGame.isDeepLinkedGameLoading()) return@receive // This means we already arrived here through a turn notification, no need to notify again
val gameId = it.preview.gameId
val sound = if (UncivGame.isCurrentGame(gameId)) {
mpSettings.currentGameTurnNotificationSound
} else {
mpSettings.otherGameTurnNotificationSound
}
SoundPlayer.play(sound)
}
}
}

View File

@ -43,7 +43,7 @@ import java.io.File
* a handful of them in memory we should be able to get away with keeping them alive for the
* app lifetime - and we do dispose them when the app is disposed.
*/
object Sounds {
object SoundPlayer {
@Suppress("EnumEntryName")
private enum class SupportedExtensions { mp3, ogg, wav } // Per Gdx docs, no aac/m4a
@ -117,7 +117,7 @@ object Sounds {
else GetSoundResult(soundMap[sound]!!, false)
// Not cached - try loading it
val fileName = sound.value
val fileName = sound.fileName
var file: FileHandle? = null
for ( (modFolder, extension) in getFolders().flatMap {
// This is essentially a cross join. To operate on all combinations, we pack both lambda
@ -134,12 +134,12 @@ object Sounds {
@Suppress("LiftReturnOrAssignment")
if (file == null || !file.exists()) {
debug("Sound %s not found!", sound.value)
debug("Sound %s not found!", sound.fileName)
// remember that the actual file is missing
soundMap[sound] = null
return null
} else {
debug("Sound %s loaded from %s", sound.value, file.path())
debug("Sound %s loaded from %s", sound.fileName, file.path())
val newSound = Gdx.audio.newSound(file)
// Store Sound for reuse
soundMap[sound] = newSound
@ -147,7 +147,11 @@ object Sounds {
}
}
/** Find, cache and play a Sound
/**
* Find, cache and play a Sound.
*
* **Attention:** The [GameSounds] object has been set up to control playing all sounds of the game. Chances are that you shouldn't be calling this method
* from anywhere but [GameSounds].
*
* Sources are mods from a loaded game, then mods marked as permanent audiovisual,
* and lastly Unciv's own assets/sounds. Will fail silently if the sound file cannot be found.

View File

@ -6,7 +6,10 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.unciv.Constants
import com.unciv.logic.city.CityFocus
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.utils.*
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.ExpanderTab
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.toLabel
class CitizenManagementTable(val cityScreen: CityScreen) : Table(BaseScreen.skin) {
val city = cityScreen.city

View File

@ -8,7 +8,11 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.badlogic.gdx.utils.Align
import com.unciv.Constants
import com.unciv.logic.city.*
import com.unciv.logic.city.CityConstructions
import com.unciv.logic.city.CityInfo
import com.unciv.logic.city.IConstruction
import com.unciv.logic.city.INonPerpetualConstruction
import com.unciv.logic.city.PerpetualConstruction
import com.unciv.logic.map.TileInfo
import com.unciv.models.UncivSound
import com.unciv.models.ruleset.Building
@ -16,15 +20,29 @@ import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.models.stats.Stat
import com.unciv.models.translations.tr
import com.unciv.ui.audio.Sounds
import com.unciv.ui.audio.SoundPlayer
import com.unciv.ui.crashhandling.launchCrashHandling
import com.unciv.ui.crashhandling.postCrashHandlingRunnable
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.popup.Popup
import com.unciv.ui.popup.YesNoPopup
import com.unciv.ui.popup.closeAllPopups
import com.unciv.ui.utils.*
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.ExpanderTab
import com.unciv.ui.utils.UncivTooltip.Companion.addTooltip
import com.unciv.ui.utils.extensions.addBorder
import com.unciv.ui.utils.extensions.addCell
import com.unciv.ui.utils.extensions.addSeparator
import com.unciv.ui.utils.extensions.brighten
import com.unciv.ui.utils.extensions.darken
import com.unciv.ui.utils.extensions.disable
import com.unciv.ui.utils.extensions.getConsumesAmountString
import com.unciv.ui.utils.extensions.isEnabled
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.packIfNeeded
import com.unciv.ui.utils.extensions.surroundWithCircle
import com.unciv.ui.utils.extensions.toLabel
import com.unciv.ui.utils.extensions.toTextButton
import kotlin.math.max
import kotlin.math.min
import com.unciv.ui.utils.AutoScrollPane as ScrollPane
@ -409,7 +427,7 @@ class CityConstructionsTable(private val cityScreen: CityScreen) {
}
cityScreen.stopPickTileForCreatesOneImprovement()
Sounds.play(getConstructionSound(construction))
SoundPlayer.play(getConstructionSound(construction))
cityConstructions.addToQueue(construction.name)
if (!construction.shouldBeDisplayed(cityConstructions)) // For buildings - unlike units which can be queued multiple times
@ -533,7 +551,7 @@ class CityConstructionsTable(private val cityScreen: CityScreen) {
stat: Stat = Stat.Gold,
tile: TileInfo? = null
) {
Sounds.play(stat.purchaseSound)
SoundPlayer.play(stat.purchaseSound)
val city = cityScreen.city
if (!city.cityConstructions.purchaseConstruction(construction.name, selectedQueueEntry, false, stat, tile)) {
Popup(cityScreen).apply {

View File

@ -19,7 +19,16 @@ import com.unciv.ui.images.IconCircleGroup
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.popup.YesNoPopup
import com.unciv.ui.popup.closeAllPopups
import com.unciv.ui.utils.*
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.ExpanderTab
import com.unciv.ui.utils.extensions.addBorder
import com.unciv.ui.utils.extensions.addSeparator
import com.unciv.ui.utils.extensions.darken
import com.unciv.ui.utils.extensions.disable
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.surroundWithCircle
import com.unciv.ui.utils.extensions.toLabel
import com.unciv.ui.utils.extensions.toTextButton
import java.text.DecimalFormat
import com.unciv.ui.utils.AutoScrollPane as ScrollPane

View File

@ -12,7 +12,12 @@ import com.unciv.ui.images.IconCircleGroup
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.overviewscreen.EmpireOverviewCategories
import com.unciv.ui.overviewscreen.EmpireOverviewScreen
import com.unciv.ui.utils.*
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.ExpanderTab
import com.unciv.ui.utils.extensions.addSeparator
import com.unciv.ui.utils.extensions.addSeparatorVertical
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.toLabel
class CityReligionInfoTable(
private val religionManager: CityInfoReligionManager,
@ -67,7 +72,7 @@ class CityReligionInfoTable(
private fun getIconAndLabel(religionName: String?) =
getIconAndLabel(gameInfo.religions[religionName])
private fun getIconAndLabel(religion: Religion?): Pair<String, String> {
return if (religion == null) "Religion" to "None"
return if (religion == null) "Religion" to "None"
else religion.getIconName() to religion.getReligionDisplayName()
}
private fun linkedReligionIcon(iconName: String, religion: String?): IconCircleGroup {

View File

@ -19,7 +19,13 @@ import com.unciv.ui.images.ImageGetter
import com.unciv.ui.map.TileGroupMap
import com.unciv.ui.popup.ToastPopup
import com.unciv.ui.tilegroups.TileSetStrings
import com.unciv.ui.utils.*
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.ZoomableScrollPane
import com.unciv.ui.utils.extensions.center
import com.unciv.ui.utils.extensions.disable
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.packIfNeeded
import com.unciv.ui.utils.extensions.toTextButton
class CityScreen(
internal val city: CityInfo,

View File

@ -6,7 +6,8 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.utils.Align
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.popup.AskTextPopup
import com.unciv.ui.utils.*
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.toLabel
/** Widget for the City Screen -
* the panel at bottom center showing the city name and offering arrows to cycle through the cities. */

View File

@ -8,15 +8,20 @@ import com.unciv.models.UncivSound
import com.unciv.models.stats.Stat
import com.unciv.models.stats.Stats
import com.unciv.models.translations.tr
import com.unciv.ui.audio.Sounds
import com.unciv.ui.audio.SoundPlayer
import com.unciv.ui.civilopedia.CivilopediaScreen
import com.unciv.ui.civilopedia.FormattedLine.IconDisplay
import com.unciv.ui.civilopedia.MarkupRenderer
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.popup.YesNoPopup
import com.unciv.ui.popup.closeAllPopups
import com.unciv.ui.utils.*
import com.unciv.ui.utils.UncivTooltip.Companion.addTooltip
import com.unciv.ui.utils.extensions.darken
import com.unciv.ui.utils.extensions.disable
import com.unciv.ui.utils.extensions.isEnabled
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.toLabel
import com.unciv.ui.utils.extensions.toTextButton
import kotlin.math.roundToInt
class CityScreenTileTable(private val cityScreen: CityScreen): Table() {
@ -91,7 +96,7 @@ class CityScreenTileTable(private val cityScreen: CityScreen): Table() {
}
/** Ask whether user wants to buy [selectedTile] for gold.
*
*
* Used from onClick and keyboard dispatch, thus only minimal parameters are passed,
* and it needs to do all checks and the sound as appropriate.
*/
@ -108,7 +113,7 @@ class CityScreenTileTable(private val cityScreen: CityScreen): Table() {
YesNoPopup(
purchasePrompt,
action = {
Sounds.play(UncivSound.Coin)
SoundPlayer.play(UncivSound.Coin)
city.expansion.buyTile(selectedTile)
// preselect the next tile on city screen rebuild so bulk buying can go faster
UncivGame.Current.setScreen(CityScreen(city, initSelectedTile = city.expansion.chooseNewTileToOwn()))
@ -142,4 +147,4 @@ class CityScreenTileTable(private val cityScreen: CityScreen): Table() {
}
return statsTable
}
}
}

View File

@ -14,7 +14,13 @@ import com.unciv.models.stats.Stat
import com.unciv.models.translations.tr
import com.unciv.ui.civilopedia.CivilopediaScreen
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.utils.*
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.Fonts
import com.unciv.ui.utils.extensions.addSeparator
import com.unciv.ui.utils.extensions.colorFromRGB
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.surroundWithCircle
import com.unciv.ui.utils.extensions.toLabel
import kotlin.math.ceil
import kotlin.math.round
import com.unciv.ui.utils.AutoScrollPane as ScrollPane

View File

@ -4,11 +4,11 @@ import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.utils.Align
import com.unciv.logic.city.CityInfo
import com.unciv.logic.map.TileInfo
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.tilegroups.TileGroup
import com.unciv.ui.tilegroups.TileSetStrings
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.utils.centerX
import com.unciv.ui.utils.extensions.centerX
class CityTileGroup(private val city: CityInfo, tileInfo: TileInfo, tileSetStrings: TileSetStrings) : TileGroup(tileInfo,tileSetStrings) {

View File

@ -13,7 +13,10 @@ import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.models.translations.tr
import com.unciv.ui.civilopedia.CivilopediaScreen
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.utils.*
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.extensions.darken
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.surroundWithCircle
class ConstructionInfoTable(val cityScreen: CityScreen): Table() {
private val selectedConstructionTable = Table()

View File

@ -6,9 +6,15 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.utils.Align
import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.models.translations.tr
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.utils.*
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.ExpanderTab
import com.unciv.ui.utils.extensions.addBorder
import com.unciv.ui.utils.extensions.addSeparatorVertical
import com.unciv.ui.utils.extensions.darken
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.surroundWithCircle
import com.unciv.ui.utils.extensions.toLabel
class SpecialistAllocationTable(val cityScreen: CityScreen) : Table(BaseScreen.skin) {
val cityInfo = cityScreen.city

View File

@ -5,7 +5,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.HorizontalGroup
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.unciv.models.stats.Stats
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.utils.surroundWithCircle
import com.unciv.ui.utils.extensions.surroundWithCircle
class YieldGroup : HorizontalGroup() {
init {
@ -56,4 +56,4 @@ class YieldGroup : HorizontalGroup() {
table.pack()
return table
}
}
}

View File

@ -9,11 +9,11 @@ import com.unciv.logic.map.TileInfo
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.tile.Terrain
import com.unciv.models.ruleset.tile.TerrainType
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.tilegroups.TileGroup
import com.unciv.ui.tilegroups.TileSetStrings
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.utils.KeyCharAndCode
import com.unciv.ui.utils.surroundWithCircle
import com.unciv.ui.utils.extensions.surroundWithCircle
import java.io.File
/** Encapsulates the knowledge on how to get an icon for each of the Civilopedia categories */
@ -90,7 +90,7 @@ object CivilopediaImageGetters {
val belief = { name: String, size: Float ->
// Kludge until we decide how exactly to show Religions
fun getInvertedCircledReligionIcon(iconName: String, size: Float) =
ImageGetter.getCircledReligionIcon(iconName, size).apply {
ImageGetter.getCircledReligionIcon(iconName, size).apply {
circle.color = Color.WHITE
actor.color = Color.BLACK
}
@ -108,7 +108,7 @@ object CivilopediaImageGetters {
/** Enum used as keys for Civilopedia "pages" (categories).
*
* Note names are singular on purpose - a "link" allows both key and label
* Order of values determines ordering of the categories in the Civilopedia top bar
* Order of values determines ordering of the categories in the Civilopedia top bar
*
* @param label Translatable caption for the Civilopedia button
*/

View File

@ -4,18 +4,27 @@ import com.badlogic.gdx.Input
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Actor
import com.badlogic.gdx.scenes.scene2d.Touchable
import com.badlogic.gdx.scenes.scene2d.ui.*
import com.badlogic.gdx.scenes.scene2d.ui.Button
import com.badlogic.gdx.scenes.scene2d.ui.SplitPane
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.models.ruleset.*
import com.unciv.models.ruleset.Belief
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.unique.IHasUniques
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.stats.INamed
import com.unciv.models.translations.tr
import com.unciv.ui.images.IconTextButton
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.utils.*
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.Fonts
import com.unciv.ui.utils.KeyCharAndCode
import com.unciv.ui.utils.UncivTooltip.Companion.addTooltip
import com.unciv.ui.utils.extensions.colorFromRGB
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.toLabel
import com.unciv.ui.utils.extensions.toTextButton
import com.unciv.ui.utils.AutoScrollPane as ScrollPane
/** Screen displaying the Civilopedia
@ -299,7 +308,7 @@ class CivilopediaScreen(
}
private fun navigateEntries(direction: Int) {
//todo this is abusing a Map as Array - there must be a collection allowing both easy positional and associative access
//todo this is abusing a Map as Array - there must be a collection allowing both easy positional and associative access
val index = entryIndex.keys.indexOf(currentEntry)
if (index < 0) return selectEntry(entryIndex.keys.first(), true)
val newIndex = when (direction) {

View File

@ -12,11 +12,12 @@ import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.RulesetCache
import com.unciv.models.ruleset.unique.Unique
import com.unciv.models.stats.INamed
import com.unciv.ui.civilopedia.MarkupRenderer.render
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.addSeparator
import com.unciv.ui.utils.onClick
import com.unciv.ui.utils.toLabel
import com.unciv.ui.utils.extensions.addSeparator
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.toLabel
import com.unciv.utils.Log
import kotlin.math.max

View File

@ -1,7 +1,7 @@
package com.unciv.ui.crashhandling
import com.badlogic.gdx.Gdx
import com.unciv.ui.utils.wrapCrashHandlingUnit
import com.unciv.UncivGame
import kotlinx.coroutines.*
import java.util.concurrent.Executors
import java.util.concurrent.ThreadFactory
@ -72,4 +72,47 @@ fun launchCrashHandling(name: String, runAsDaemon: Boolean = true,
private fun getCoroutineContext(runAsDaemon: Boolean): CoroutineScope {
return if (runAsDaemon) CRASH_HANDLING_DAEMON_SCOPE else CRASH_HANDLING_SCOPE
}
}
/**
* Returns a wrapped version of a function that safely crashes the game to [CrashScreen] if an exception or error is thrown.
*
* In case an exception or error is thrown, the return will be null. Therefore the return type is always nullable.
*
* The game loop, threading, and event systems already use this to wrap nearly everything that can happen during the lifespan of the Unciv application.
*
* Therefore, it usually shouldn't be necessary to manually use this. See the note at the top of [CrashScreen].kt for details.
*
* @param postToMainThread Whether the [CrashScreen] should be opened by posting a runnable to the main thread, instead of directly. Set this to true if the function is going to run on any thread other than the main loop.
* @return Result from the function, or null if an exception is thrown.
* */
fun <R> (() -> R).wrapCrashHandling(
postToMainThread: Boolean = false
): () -> R?
= {
try {
this()
} catch (e: Throwable) {
if (postToMainThread) {
Gdx.app.postRunnable {
UncivGame.Current.setScreen(CrashScreen(e))
}
} else UncivGame.Current.setScreen(CrashScreen(e))
null
}
}
/**
* Returns a wrapped a version of a Unit-returning function which safely crashes the game to [CrashScreen] if an exception or error is thrown.
*
* The game loop, threading, and event systems already use this to wrap nearly everything that can happen during the lifespan of the Unciv application.
*
* Therefore, it usually shouldn't be necessary to manually use this. See the note at the top of [CrashScreen].kt for details.
*
* @param postToMainThread Whether the [CrashScreen] should be opened by posting a runnable to the main thread, instead of directly. Set this to true if the function is going to run on any thread other than the main loop.
* */
fun (() -> Unit).wrapCrashHandlingUnit(
postToMainThread: Boolean = false
): () -> Unit {
val wrappedReturning = this.wrapCrashHandling(postToMainThread)
// Don't instantiate a new lambda every time the return get called.
return { wrappedReturning() ?: Unit }
}

View File

@ -13,7 +13,12 @@ import com.unciv.models.ruleset.RulesetCache
import com.unciv.ui.images.IconTextButton
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.popup.ToastPopup
import com.unciv.ui.utils.*
import com.unciv.ui.utils.AutoScrollPane
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.extensions.addBorder
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.setFontSize
import com.unciv.ui.utils.extensions.toLabel
import com.unciv.utils.Log
import java.io.PrintWriter
import java.io.StringWriter

View File

@ -5,7 +5,7 @@ import com.badlogic.gdx.graphics.g2d.Batch
import com.badlogic.gdx.scenes.scene2d.Actor
import com.badlogic.gdx.scenes.scene2d.Group
import com.badlogic.gdx.utils.Align
import com.unciv.ui.utils.center
import com.unciv.ui.utils.extensions.center
class IconCircleGroup(size: Float, val actor: Actor, resizeActor: Boolean = true, color: Color = Color.WHITE): Group(){
val circle = ImageGetter.getCircle().apply {

View File

@ -8,7 +8,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Label
import com.badlogic.gdx.utils.Align
import com.unciv.Constants
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.toLabel
import com.unciv.ui.utils.extensions.toLabel
/**
* Translate a [String] and make a [Button] widget from it, with control over font size, font colour, an optional icon, and custom formatting.

View File

@ -25,6 +25,7 @@ import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.models.stats.Stats
import com.unciv.models.tilesets.TileSetCache
import com.unciv.ui.utils.*
import com.unciv.ui.utils.extensions.*
import com.unciv.utils.debug
import kotlin.math.atan2
import kotlin.math.max

View File

@ -1,7 +1,12 @@
package com.unciv.ui.mapeditor
import com.badlogic.gdx.math.Vector2
import com.badlogic.gdx.scenes.scene2d.*
import com.badlogic.gdx.scenes.scene2d.Action
import com.badlogic.gdx.scenes.scene2d.EventListener
import com.badlogic.gdx.scenes.scene2d.InputEvent
import com.badlogic.gdx.scenes.scene2d.InputListener
import com.badlogic.gdx.scenes.scene2d.Stage
import com.badlogic.gdx.scenes.scene2d.Touchable
import com.badlogic.gdx.scenes.scene2d.actions.Actions
import com.unciv.UncivGame
import com.unciv.logic.HexMath
@ -12,8 +17,8 @@ import com.unciv.ui.tilegroups.TileGroup
import com.unciv.ui.tilegroups.TileSetStrings
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.ZoomableScrollPane
import com.unciv.ui.utils.center
import com.unciv.ui.utils.onClick
import com.unciv.ui.utils.extensions.center
import com.unciv.ui.utils.extensions.onClick
/**

View File

@ -6,7 +6,6 @@ import com.unciv.ui.newgamescreen.GameOptionsTable
import com.unciv.ui.newgamescreen.IPreviousScreen
import com.unciv.ui.newgamescreen.PlayerPickerTable
import com.unciv.ui.pickerscreens.PickerScreen
import com.unciv.ui.utils.*
/**
* As of MapEditor V2, the editor no longer deals with GameParameters, **only** with MapParameters,

View File

@ -9,7 +9,11 @@ import com.unciv.logic.map.RoadStatus
import com.unciv.logic.map.TileInfo
import com.unciv.models.ruleset.Nation
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.tile.*
import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.models.ruleset.tile.Terrain
import com.unciv.models.ruleset.tile.TerrainType
import com.unciv.models.ruleset.tile.TileImprovement
import com.unciv.models.ruleset.tile.TileResource
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.translations.tr
import com.unciv.ui.civilopedia.FormattedLine
@ -18,7 +22,11 @@ import com.unciv.ui.images.ImageGetter
import com.unciv.ui.mapeditor.MapEditorEditTab.BrushHandlerType
import com.unciv.ui.tilegroups.TileGroup
import com.unciv.ui.tilegroups.TileSetStrings
import com.unciv.ui.utils.*
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.TabbedPager
import com.unciv.ui.utils.extensions.center
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.toLabel
internal interface IMapEditorEditSubTabs {
fun isDisabled(): Boolean

View File

@ -15,7 +15,12 @@ import com.unciv.ui.civilopedia.FormattedLine
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.mapeditor.MapEditorOptionsTab.TileMatchFuzziness
import com.unciv.ui.popup.ToastPopup
import com.unciv.ui.utils.*
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.KeyCharAndCode
import com.unciv.ui.utils.TabbedPager
import com.unciv.ui.utils.UncivSlider
import com.unciv.ui.utils.extensions.addSeparator
import com.unciv.ui.utils.extensions.toLabel
import com.unciv.utils.Log
class MapEditorEditTab(

View File

@ -9,9 +9,9 @@ import com.unciv.logic.MapSaver
import com.unciv.models.ruleset.RulesetCache
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.onClick
import com.unciv.ui.utils.pad
import com.unciv.ui.utils.toLabel
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.pad
import com.unciv.ui.utils.extensions.toLabel
class MapEditorFilesTable(
initWidth: Float,
@ -74,7 +74,7 @@ class MapEditorFilesTable(
var lastMod = ""
for ((index, entry) in sortedFiles.withIndex()) {
val (mod, mapFile) = entry
val (mod, mapFile) = entry
if (mod != lastMod) {
// One header per Mod
add(Table().apply {

View File

@ -15,7 +15,17 @@ import com.unciv.ui.images.ImageGetter
import com.unciv.ui.newgamescreen.MapParametersTable
import com.unciv.ui.popup.Popup
import com.unciv.ui.popup.ToastPopup
import com.unciv.ui.utils.*
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.KeyCharAndCode
import com.unciv.ui.utils.TabbedPager
import com.unciv.ui.utils.extensions.disable
import com.unciv.ui.utils.extensions.enable
import com.unciv.ui.utils.extensions.isEnabled
import com.unciv.ui.utils.extensions.onChange
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.toCheckBox
import com.unciv.ui.utils.extensions.toLabel
import com.unciv.ui.utils.extensions.toTextButton
import com.unciv.utils.Log
import kotlin.concurrent.thread

View File

@ -13,7 +13,13 @@ import com.unciv.models.translations.tr
import com.unciv.ui.popup.Popup
import com.unciv.ui.popup.ToastPopup
import com.unciv.ui.popup.YesNoPopup
import com.unciv.ui.utils.*
import com.unciv.ui.utils.AutoScrollPane
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.KeyCharAndCode
import com.unciv.ui.utils.TabbedPager
import com.unciv.ui.utils.extensions.isEnabled
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.toTextButton
import com.unciv.utils.Log
import kotlin.concurrent.thread

View File

@ -10,8 +10,14 @@ import com.unciv.models.ruleset.RulesetCache
import com.unciv.ui.newgamescreen.ModCheckboxTable
import com.unciv.ui.newgamescreen.TranslatedSelectBox
import com.unciv.ui.popup.Popup
import com.unciv.ui.utils.*
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.TabbedPager
import com.unciv.ui.utils.UncivTooltip.Companion.addTooltip
import com.unciv.ui.utils.extensions.isEnabled
import com.unciv.ui.utils.extensions.onChange
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.toLabel
import com.unciv.ui.utils.extensions.toTextButton
class MapEditorModsTab(
private val editorScreen: MapEditorScreen

View File

@ -8,7 +8,15 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.unciv.logic.MapSaver
import com.unciv.models.translations.tr
import com.unciv.ui.popup.ToastPopup
import com.unciv.ui.utils.*
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.KeyCharAndCode
import com.unciv.ui.utils.TabbedPager
import com.unciv.ui.utils.extensions.addSeparator
import com.unciv.ui.utils.extensions.isEnabled
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.toCheckBox
import com.unciv.ui.utils.extensions.toLabel
import com.unciv.ui.utils.extensions.toTextButton
class MapEditorOptionsTab(
private val editorScreen: MapEditorScreen

View File

@ -13,7 +13,14 @@ import com.unciv.models.translations.tr
import com.unciv.ui.popup.Popup
import com.unciv.ui.popup.ToastPopup
import com.unciv.ui.popup.YesNoPopup
import com.unciv.ui.utils.*
import com.unciv.ui.utils.AutoScrollPane
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.KeyCharAndCode
import com.unciv.ui.utils.TabbedPager
import com.unciv.ui.utils.extensions.isEnabled
import com.unciv.ui.utils.extensions.onChange
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.toTextButton
import kotlin.concurrent.thread
class MapEditorSaveTab(
@ -123,4 +130,4 @@ class MapEditorSaveTab(
}
}
}
}
}

View File

@ -5,7 +5,12 @@ import com.badlogic.gdx.graphics.Color
import com.unciv.MainMenuScreen
import com.unciv.UncivGame
import com.unciv.logic.HexMath
import com.unciv.logic.map.*
import com.unciv.logic.map.MapParameters
import com.unciv.logic.map.MapShape
import com.unciv.logic.map.MapSize
import com.unciv.logic.map.MapSizeNew
import com.unciv.logic.map.TileInfo
import com.unciv.logic.map.TileMap
import com.unciv.models.metadata.BaseRuleset
import com.unciv.models.metadata.GameSetupInfo
import com.unciv.models.ruleset.Ruleset
@ -15,7 +20,8 @@ import com.unciv.ui.images.ImageGetter
import com.unciv.ui.popup.ToastPopup
import com.unciv.ui.popup.YesNoPopup
import com.unciv.ui.tilegroups.TileGroup
import com.unciv.ui.utils.*
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.KeyCharAndCode
import com.unciv.ui.worldscreen.ZoomButtonPair

View File

@ -15,10 +15,18 @@ import com.unciv.models.stats.Stats
import com.unciv.models.translations.tr
import com.unciv.ui.civilopedia.CivilopediaScreen
import com.unciv.ui.civilopedia.FormattedLine
import com.unciv.ui.civilopedia.MarkupRenderer
import com.unciv.ui.civilopedia.FormattedLine.IconDisplay
import com.unciv.ui.civilopedia.MarkupRenderer
import com.unciv.ui.popup.ToastPopup
import com.unciv.ui.utils.*
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.ExpanderTab
import com.unciv.ui.utils.TabbedPager
import com.unciv.ui.utils.WrappableLabel
import com.unciv.ui.utils.extensions.addSeparator
import com.unciv.ui.utils.extensions.darken
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.pad
import com.unciv.ui.utils.extensions.toTextButton
class MapEditorViewTab(
private val editorScreen: MapEditorScreen

View File

@ -8,7 +8,10 @@ import com.unciv.logic.multiplayer.FriendList
import com.unciv.models.translations.tr
import com.unciv.ui.pickerscreens.PickerScreen
import com.unciv.ui.popup.ToastPopup
import com.unciv.ui.utils.*
import com.unciv.ui.utils.extensions.enable
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.toLabel
import com.unciv.ui.utils.extensions.toTextButton
import java.util.*
class AddFriendScreen(backScreen: ViewFriendsListScreen) : PickerScreen() {

View File

@ -7,11 +7,13 @@ import com.unciv.logic.IdChecker
import com.unciv.models.translations.tr
import com.unciv.ui.crashhandling.launchCrashHandling
import com.unciv.ui.crashhandling.postCrashHandlingRunnable
import com.unciv.ui.multiplayer.MultiplayerHelpers
import com.unciv.ui.pickerscreens.PickerScreen
import com.unciv.ui.popup.Popup
import com.unciv.ui.popup.ToastPopup
import com.unciv.ui.utils.*
import com.unciv.ui.utils.extensions.enable
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.toLabel
import com.unciv.ui.utils.extensions.toTextButton
import java.util.*
class AddMultiplayerGameScreen(backScreen: MultiplayerScreen) : PickerScreen() {

View File

@ -10,7 +10,10 @@ import com.unciv.models.translations.tr
import com.unciv.ui.pickerscreens.PickerScreen
import com.unciv.ui.popup.ToastPopup
import com.unciv.ui.popup.YesNoPopup
import com.unciv.ui.utils.*
import com.unciv.ui.utils.extensions.enable
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.toLabel
import com.unciv.ui.utils.extensions.toTextButton
import java.util.*
class EditFriendScreen(selectedFriend: FriendList.Friend, backScreen: ViewFriendsListScreen) : PickerScreen() {

View File

@ -4,14 +4,17 @@ import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.ui.TextField
import com.unciv.logic.multiplayer.OnlineMultiplayerGame
import com.unciv.models.translations.tr
import com.unciv.ui.pickerscreens.PickerScreen
import com.unciv.ui.utils.*
import com.unciv.ui.crashhandling.launchCrashHandling
import com.unciv.ui.crashhandling.postCrashHandlingRunnable
import com.unciv.ui.multiplayer.MultiplayerHelpers
import com.unciv.ui.pickerscreens.PickerScreen
import com.unciv.ui.popup.Popup
import com.unciv.ui.popup.ToastPopup
import com.unciv.ui.popup.YesNoPopup
import com.unciv.ui.utils.extensions.disable
import com.unciv.ui.utils.extensions.enable
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.toLabel
import com.unciv.ui.utils.extensions.toTextButton
/** Subscreen of MultiplayerScreen to edit and delete saves
* backScreen is used for getting back to the MultiplayerScreen so it doesn't have to be created over and over again */

View File

@ -6,7 +6,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup
import com.unciv.logic.multiplayer.FriendList
import com.unciv.ui.newgamescreen.PlayerPickerTable
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.onClick
import com.unciv.ui.utils.extensions.onClick
class FriendPickerList(
playerPicker: PlayerPickerTable,

View File

@ -17,13 +17,12 @@ import com.unciv.logic.multiplayer.MultiplayerGameUpdateEnded
import com.unciv.logic.multiplayer.MultiplayerGameUpdateFailed
import com.unciv.logic.multiplayer.MultiplayerGameUpdateStarted
import com.unciv.logic.multiplayer.MultiplayerGameUpdateSucceeded
import com.unciv.logic.multiplayer.MultiplayerGameUpdateUnchanged
import com.unciv.logic.multiplayer.MultiplayerGameUpdated
import com.unciv.logic.multiplayer.isUsersTurn
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.onClick
import com.unciv.ui.utils.setSize
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.setSize
class GameList(
onSelected: (String) -> Unit

View File

@ -2,8 +2,8 @@ package com.unciv.ui.multiplayer
import com.unciv.Constants
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.center
import com.unciv.ui.utils.toLabel
import com.unciv.ui.utils.extensions.center
import com.unciv.ui.utils.extensions.toLabel
class LoadDeepLinkScreen : BaseScreen() {
init {

View File

@ -11,7 +11,8 @@ import com.unciv.ui.crashhandling.launchCrashHandling
import com.unciv.ui.crashhandling.postCrashHandlingRunnable
import com.unciv.ui.popup.Popup
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.toCheckBox
import com.unciv.ui.utils.extensions.formatShort
import com.unciv.ui.utils.extensions.toCheckBox
import java.io.FileNotFoundException
import java.time.Duration
import java.time.Instant
@ -50,27 +51,15 @@ object MultiplayerHelpers {
descriptionText.appendLine(message.tr())
}
val lastUpdate = multiplayerGame.lastUpdate
descriptionText.appendLine("Last refresh: ${formattedElapsedTime(lastUpdate)} ago".tr())
descriptionText.appendLine("Last refresh: [${Duration.between(lastUpdate, Instant.now()).formatShort()}] ago".tr())
val preview = multiplayerGame.preview
if (preview?.currentPlayer != null) {
val currentTurnStartTime = Instant.ofEpochMilli(preview.currentTurnStartTime)
descriptionText.appendLine("Current Turn: [${preview.currentPlayer}] since ${formattedElapsedTime(currentTurnStartTime)} ago".tr())
descriptionText.appendLine("Current Turn: [${preview.currentPlayer}] since [${Duration.between(currentTurnStartTime, Instant.now()).formatShort()}] ago".tr())
}
return descriptionText
}
private fun formattedElapsedTime(lastUpdate: Instant): String {
val durationToNow = Duration.between(lastUpdate, Instant.now())
val elapsedMinutes = durationToNow.toMinutes()
if (elapsedMinutes < 120) return "[$elapsedMinutes] [Minutes]"
val elapsedHours = durationToNow.toHours()
if (elapsedHours < 48) {
return "[${elapsedHours}] [Hours]"
} else {
return "[${durationToNow.toDays()}] [Days]"
}
}
fun showDropboxWarning(screen: BaseScreen) {
if (!OnlineMultiplayer.usesDropbox() || UncivGame.Current.settings.multiplayer.hideDropboxWarning) return

View File

@ -7,16 +7,14 @@ import com.unciv.logic.event.EventBus
import com.unciv.logic.multiplayer.MultiplayerGameDeleted
import com.unciv.logic.multiplayer.OnlineMultiplayerGame
import com.unciv.models.translations.tr
import com.unciv.ui.multiplayer.GameList
import com.unciv.ui.multiplayer.MultiplayerHelpers
import com.unciv.ui.pickerscreens.PickerScreen
import com.unciv.ui.popup.Popup
import com.unciv.ui.popup.ToastPopup
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.disable
import com.unciv.ui.utils.enable
import com.unciv.ui.utils.onClick
import com.unciv.ui.utils.toTextButton
import com.unciv.ui.utils.extensions.disable
import com.unciv.ui.utils.extensions.enable
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.toTextButton
import com.unciv.ui.utils.AutoScrollPane as ScrollPane
class MultiplayerScreen(previousScreen: BaseScreen) : PickerScreen() {

View File

@ -4,7 +4,11 @@ import com.badlogic.gdx.scenes.scene2d.ui.*
import com.unciv.logic.multiplayer.FriendList
import com.unciv.ui.pickerscreens.PickerScreen
import com.unciv.ui.popup.Popup
import com.unciv.ui.utils.*
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.extensions.disable
import com.unciv.ui.utils.extensions.enable
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.toTextButton
import com.unciv.ui.utils.AutoScrollPane as ScrollPane
class ViewFriendsListScreen(previousScreen: BaseScreen) : PickerScreen() {

View File

@ -7,6 +7,7 @@ import com.badlogic.gdx.utils.Align
import com.unciv.Constants
import com.unciv.logic.multiplayer.FriendList
import com.unciv.ui.utils.*
import com.unciv.ui.utils.extensions.pad
class FriendTable(val friend: FriendList.Friend, width: Float, minHeight: Float)
: Table() {
@ -26,7 +27,7 @@ class FriendTable(val friend: FriendList.Friend, width: Float, minHeight: Float)
friendDisplayLabel.wrap = true
titleTable.add(friendDisplayLabel).width(friendDisplayNameMaxWidth)
} else {
titleTable.add(friendDisplayLabel).align(Align.center).pad(10f,0f)
titleTable.add(friendDisplayLabel).align(Align.center).pad(10f, 0f)
}
innerTable.add(titleTable).growX().fillY().row()

View File

@ -17,7 +17,11 @@ import com.unciv.ui.images.ImageGetter
import com.unciv.ui.multiplayer.MultiplayerHelpers
import com.unciv.ui.popup.Popup
import com.unciv.ui.popup.ToastPopup
import com.unciv.ui.utils.*
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.UncivSlider
import com.unciv.ui.utils.extensions.onChange
import com.unciv.ui.utils.extensions.toCheckBox
import com.unciv.ui.utils.extensions.toLabel
class GameOptionsTable(
val previousScreen: IPreviousScreen,

View File

@ -11,8 +11,8 @@ import com.unciv.logic.map.MapType
import com.unciv.models.ruleset.RulesetCache
import com.unciv.ui.popup.Popup
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.onChange
import com.unciv.ui.utils.toLabel
import com.unciv.ui.utils.extensions.onChange
import com.unciv.ui.utils.extensions.toLabel
class MapOptionsTable(private val newGameScreen: NewGameScreen): Table() {

View File

@ -6,8 +6,21 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.TextField
import com.badlogic.gdx.scenes.scene2d.ui.TextField.TextFieldFilter.DigitsOnlyFilter
import com.unciv.UncivGame
import com.unciv.logic.map.*
import com.unciv.ui.utils.*
import com.unciv.logic.map.MapParameters
import com.unciv.logic.map.MapResources
import com.unciv.logic.map.MapShape
import com.unciv.logic.map.MapSize
import com.unciv.logic.map.MapSizeNew
import com.unciv.logic.map.MapType
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.ExpanderTab
import com.unciv.ui.utils.UncivSlider
import com.unciv.ui.utils.extensions.onChange
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.pad
import com.unciv.ui.utils.extensions.toCheckBox
import com.unciv.ui.utils.extensions.toLabel
import com.unciv.ui.utils.extensions.toTextButton
/** Table for editing [mapParameters]
*

View File

@ -7,12 +7,16 @@ import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.RulesetCache
import com.unciv.models.translations.tr
import com.unciv.ui.popup.ToastPopup
import com.unciv.ui.utils.*
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.ExpanderTab
import com.unciv.ui.utils.extensions.onChange
import com.unciv.ui.utils.extensions.pad
import com.unciv.ui.utils.extensions.toCheckBox
/**
* A widget containing one expander for extension mods.
* A widget containing one expander for extension mods.
* Manages compatibility checks, warns or prevents incompatibilities.
*
*
* @param mods In/out set of active mods, modified in place
* @param baseRuleset The selected base Ruleset //todo clarify
* @param screen Parent screen, used only to show [ToastPopup]s
@ -51,8 +55,8 @@ class ModCheckboxTable(
}).padTop(padTop).growX().row()
}
}
fun setBaseRuleset(newBaseRuleset: String) { baseRuleset = newBaseRuleset }
fun setBaseRuleset(newBaseRuleset: String) { baseRuleset = newBaseRuleset }
fun disableAllCheckboxes() {
for (checkBox in extensionRulesetModButtons) {
checkBox.isChecked = false

View File

@ -11,7 +11,9 @@ import com.unciv.models.ruleset.Ruleset
import com.unciv.ui.civilopedia.FormattedLine.IconDisplay
import com.unciv.ui.civilopedia.MarkupRenderer
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.utils.*
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.WrappableLabel
import com.unciv.ui.utils.extensions.pad
// The ruleset also acts as a secondary parameter to determine if this is the right or self side of the player picker
class NationTable(val nation: Nation, width: Float, minHeight: Float, ruleset: Ruleset? = null)

View File

@ -8,7 +8,10 @@ import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup
import com.badlogic.gdx.utils.Array
import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.logic.*
import com.unciv.logic.GameInfo
import com.unciv.logic.GameStarter
import com.unciv.logic.IdChecker
import com.unciv.logic.MapSaver
import com.unciv.logic.civilization.PlayerType
import com.unciv.logic.map.MapType
import com.unciv.logic.multiplayer.OnlineMultiplayer
@ -23,7 +26,16 @@ import com.unciv.ui.pickerscreens.PickerScreen
import com.unciv.ui.popup.Popup
import com.unciv.ui.popup.ToastPopup
import com.unciv.ui.popup.YesNoPopup
import com.unciv.ui.utils.*
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.ExpanderTab
import com.unciv.ui.utils.extensions.addSeparator
import com.unciv.ui.utils.extensions.addSeparatorVertical
import com.unciv.ui.utils.extensions.disable
import com.unciv.ui.utils.extensions.enable
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.pad
import com.unciv.ui.utils.extensions.toLabel
import com.unciv.ui.utils.extensions.toTextButton
import java.net.URL
import java.util.*
import com.unciv.ui.utils.AutoScrollPane as ScrollPane
@ -210,10 +222,9 @@ class NewGameScreen(
}
private fun checkConnectionToMultiplayerServer(): Boolean {
val isDropbox = UncivGame.Current.settings.multiplayer.server == Constants.dropboxMultiplayerServer
return try {
val multiplayerServer = UncivGame.Current.settings.multiplayer.server
val u = URL(if (isDropbox) "https://content.dropboxapi.com" else multiplayerServer)
val u = URL(if (OnlineMultiplayer.usesDropbox()) "https://content.dropboxapi.com" else multiplayerServer)
val con = u.openConnection()
con.connectTimeout = 3000
con.connect()

View File

@ -1,6 +1,5 @@
package com.unciv.ui.newgamescreen
import com.unciv.ui.utils.AutoScrollPane as ScrollPane
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Group
@ -28,7 +27,9 @@ import com.unciv.ui.pickerscreens.PickerPane
import com.unciv.ui.pickerscreens.PickerScreen
import com.unciv.ui.popup.Popup
import com.unciv.ui.utils.*
import com.unciv.ui.utils.extensions.*
import java.util.*
import com.unciv.ui.utils.AutoScrollPane as ScrollPane
/**
* This [Table] is used to pick or edit players information for new game creation.

Some files were not shown because too many files have changed in this diff Show More