diff --git a/android/assets/jsons/translations/template.properties b/android/assets/jsons/translations/template.properties index 5389493f88..02d4d42523 100644 --- a/android/assets/jsons/translations/template.properties +++ b/android/assets/jsons/translations/template.properties @@ -1248,8 +1248,6 @@ Capture [cityName] = Our status = Global status = Rankings = - # The \n here means: put a newline (enter) here. If this is omitted, the sidebox in the diplomacy overview will become _really_ wide. - # Feel free to replace it with a space and put it between other words in your translation Demographics = Demographic = Rank = @@ -1257,6 +1255,8 @@ Value = Best = Average = Worst = +# The \n here means: put a newline (enter) here. If this is omitted, the sidebox in the diplomacy overview will become _really_ wide. +# Feel free to replace it with a space and put it between other words in your translation Turns until the next\ndiplomacy victory vote: [amount] = Choose a civ to vote for = Choose who should become the world leader and win a Diplomatic Victory! = diff --git a/core/src/com/unciv/logic/civilization/CivInfoTransientUpdater.kt b/core/src/com/unciv/logic/civilization/CivInfoTransientUpdater.kt index 321674f481..95db64fc4f 100644 --- a/core/src/com/unciv/logic/civilization/CivInfoTransientUpdater.kt +++ b/core/src/com/unciv/logic/civilization/CivInfoTransientUpdater.kt @@ -92,9 +92,9 @@ class CivInfoTransientUpdater(val civInfo: CivilizationInfo) { } for (spy in civInfo.espionageManager.spyList) { - val spyCity = spy.getLocation(civInfo.gameInfo) ?: continue - newViewableTiles.addAll(spyCity.getCenterTile().neighbors) - newViewableTiles.add(spyCity.getCenterTile()) + val spyCity = spy.getLocation() ?: continue + if (!spy.isSetUp()) continue // Can't see cities when you haven't set up yet + newViewableTiles.addAll(spyCity.getCenterTile().getTilesInDistance(1)) } civInfo.viewableTiles = newViewableTiles // to avoid concurrent modification problems diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index 6ce2e0437f..3083dc4c2d 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -993,6 +993,8 @@ class CivilizationInfo : IsPartOfGameInfoSerialization { religionManager.endTurn(nextTurnStats.faith.toInt()) totalFaithForContests += nextTurnStats.faith.toInt() + espionageManager.endTurn() + if (isMajorCiv()) greatPeople.addGreatPersonPoints(getGreatPersonPointsForNextTurn()) // City-states don't get great people! for (city in cities.toList()) { // a city can be removed while iterating (if it's being razed) so we need to iterate over a copy diff --git a/core/src/com/unciv/logic/civilization/EspionageManager.kt b/core/src/com/unciv/logic/civilization/EspionageManager.kt index ff9c234696..aa2dd986dc 100644 --- a/core/src/com/unciv/logic/civilization/EspionageManager.kt +++ b/core/src/com/unciv/logic/civilization/EspionageManager.kt @@ -5,10 +5,25 @@ import com.unciv.logic.GameInfo import com.unciv.logic.IsPartOfGameInfoSerialization import com.unciv.logic.city.CityInfo +enum class SpyAction(val stringName: String) { + None("None"), + Moving("Moving"), + EstablishNetwork("Establishing Network"), + StealingTech("Stealing Tech"), + RiggingElections("Rigging Elections"), + CounterIntelligence("Conducting Counter-intelligence") +} + + class Spy() : IsPartOfGameInfoSerialization { // `location == null` means that the spy is in its hideout var location: String? = null lateinit var name: String + var timeTillActionFinish = 0 + var action = SpyAction.None + + @Transient + lateinit var civInfo: CivilizationInfo constructor(name: String) : this() { this.name = name @@ -17,15 +32,60 @@ class Spy() : IsPartOfGameInfoSerialization { fun clone(): Spy { val toReturn = Spy(name) toReturn.location = location + toReturn.timeTillActionFinish = timeTillActionFinish + toReturn.action = action return toReturn } - fun getLocation(gameInfo: GameInfo): CityInfo? { - return gameInfo.getCities().firstOrNull { it.id == location } + fun setTransients(civInfo: CivilizationInfo) { + this.civInfo = civInfo } - fun getLocationName(gameInfo: GameInfo): String { - return getLocation(gameInfo)?.name ?: Constants.spyHideout + fun endTurn() { + --timeTillActionFinish + if (timeTillActionFinish != 0) return + + when (action) { + SpyAction.Moving -> { + action = SpyAction.EstablishNetwork + timeTillActionFinish = 3 // Dependent on cultural familiarity level if that is ever implemented + } + SpyAction.EstablishNetwork -> { + val location = getLocation()!! // This should be impossible to reach as going to the hideout sets your action to None. + action = + if (location.civInfo.isCityState()) { + SpyAction.RiggingElections + } else if (location.civInfo == civInfo) { + SpyAction.CounterIntelligence + } else { + SpyAction.StealingTech + } + } + else -> { + ++timeTillActionFinish // Not implemented yet, so don't do anything + } + } + } + + fun moveTo(cityInfo: CityInfo?) { + location = cityInfo?.id + if (cityInfo == null) { // Moving to spy hideout + action = SpyAction.None + timeTillActionFinish = 0 + return + } + action = SpyAction.Moving + timeTillActionFinish = 1 + } + + fun isSetUp() = action !in listOf(SpyAction.Moving, SpyAction.None, SpyAction.EstablishNetwork) + + fun getLocation(): CityInfo? { + return civInfo.gameInfo.getCities().firstOrNull { it.id == location } + } + + fun getLocationName(): String { + return getLocation()?.name ?: Constants.spyHideout } } @@ -48,6 +108,14 @@ class EspionageManager : IsPartOfGameInfoSerialization { fun setTransients(civInfo: CivilizationInfo) { this.civInfo = civInfo + for (spy in spyList) { + spy.setTransients(civInfo) + } + } + + fun endTurn() { + for (spy in spyList) + spy.endTurn() } private fun getSpyName(): String { diff --git a/core/src/com/unciv/models/ModConstants.kt b/core/src/com/unciv/models/ModConstants.kt index 33848a1b16..dca97c58b7 100644 --- a/core/src/com/unciv/models/ModConstants.kt +++ b/core/src/com/unciv/models/ModConstants.kt @@ -60,7 +60,7 @@ class ModConstants { // RiverGenerator: river frequency and length bounds var riverCountMultiplier = 0.01f var minRiverLength = 5 - var maxRiverLength = 666 // Do not set < max map radius + var maxRiverLength = 666 // Do not set to less than the maximal map radius fun merge(other: ModConstants) { if (other.maxXPfromBarbarians != defaults.maxXPfromBarbarians) maxXPfromBarbarians = other.maxXPfromBarbarians diff --git a/core/src/com/unciv/models/translations/TranslationFileWriter.kt b/core/src/com/unciv/models/translations/TranslationFileWriter.kt index b57e889c19..09be5049ba 100644 --- a/core/src/com/unciv/models/translations/TranslationFileWriter.kt +++ b/core/src/com/unciv/models/translations/TranslationFileWriter.kt @@ -4,6 +4,7 @@ import com.badlogic.gdx.Gdx import com.badlogic.gdx.files.FileHandle import com.unciv.json.fromJsonFile import com.unciv.json.json +import com.unciv.logic.civilization.SpyAction import com.unciv.models.metadata.BaseRuleset import com.unciv.models.metadata.LocaleCode import com.unciv.models.ruleset.* @@ -124,6 +125,10 @@ object TranslationFileWriter { for (uniqueTarget in UniqueTarget.values()) linesToTranslate.add("$uniqueTarget = ") + + for (spyAction in SpyAction.values()) { + linesToTranslate.add("$spyAction = ") + } } var countOfTranslatableLines = 0 diff --git a/core/src/com/unciv/ui/overviewscreen/EspionageOverviewScreen.kt b/core/src/com/unciv/ui/overviewscreen/EspionageOverviewScreen.kt index b3c59d5af7..3e06af75bb 100644 --- a/core/src/com/unciv/ui/overviewscreen/EspionageOverviewScreen.kt +++ b/core/src/com/unciv/ui/overviewscreen/EspionageOverviewScreen.kt @@ -9,10 +9,12 @@ import com.unciv.UncivGame import com.unciv.logic.city.CityInfo import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.civilization.Spy +import com.unciv.logic.civilization.SpyAction import com.unciv.models.translations.tr import com.unciv.ui.images.ImageGetter import com.unciv.ui.pickerscreens.PickerScreen import com.unciv.ui.utils.AutoScrollPane +import com.unciv.ui.utils.Fonts import com.unciv.ui.utils.KeyCharAndCode import com.unciv.ui.utils.extensions.addSeparator import com.unciv.ui.utils.extensions.addSeparatorVertical @@ -31,7 +33,6 @@ class EspionageOverviewScreen(val civInfo: CivilizationInfo) : PickerScreen(true private val spyScrollPane = AutoScrollPane(spySelectionTable) private val citySelectionTable = Table(skin) private val cityScrollPane = AutoScrollPane(citySelectionTable) - private val headerTable = Table(skin) private val middlePanes = Table(skin) private var selectedSpyButton: TextButton? = null @@ -41,9 +42,6 @@ class EspionageOverviewScreen(val civInfo: CivilizationInfo) : PickerScreen(true private var moveSpyHereButtons = hashMapOf() init { - topTable.add(headerTable) - topTable.addSeparator() - middlePanes.add(spyScrollPane) middlePanes.addSeparatorVertical() middlePanes.add(cityScrollPane) @@ -67,11 +65,16 @@ class EspionageOverviewScreen(val civInfo: CivilizationInfo) : PickerScreen(true private fun updateSpyList() { spySelectionTable.clear() - spySelectionTable.add("Spy".toLabel()).pad(5f) - spySelectionTable.add("Location".toLabel()).pad(5f).row() + spySelectionTable.add("Spy".toLabel()).pad(10f) + spySelectionTable.add("Location".toLabel()).pad(10f) + spySelectionTable.add("Action".toLabel()).pad(10f).row() for (spy in civInfo.espionageManager.spyList) { - spySelectionTable.add(spy.name.toLabel()).pad(5f) - spySelectionTable.add(spy.getLocationName(civInfo.gameInfo).toLabel()).pad(5f) + spySelectionTable.add(spy.name.toLabel()).pad(10f) + spySelectionTable.add(spy.getLocationName().toLabel()).pad(10f) + val actionString = + if (spy.action == SpyAction.None) SpyAction.None.stringName + else "[${spy.action.stringName}] ${spy.timeTillActionFinish}${Fonts.turn}" + spySelectionTable.add(actionString.toLabel()).pad(10f) val moveSpyButton = "Move".toTextButton() moveSpyButton.onClick { @@ -160,7 +163,7 @@ class EspionageOverviewScreen(val civInfo: CivilizationInfo) : PickerScreen(true val moveSpyHereButton = Button(skin) moveSpyHereButton.add(ImageGetter.getArrowImage(Align.left).apply { color = Color.WHITE }) moveSpyHereButton.onClick { - selectedSpy!!.location = city?.id + selectedSpy!!.moveTo(city) resetSelection() update() }