Spies now show their current action and take time to move and set up (#7776)

* Spies now show their current action and take time to move and set up

* Fixed tests

* Reviews

* More reviews
This commit is contained in:
Xander Lenstra
2022-09-19 15:13:57 +02:00
committed by GitHub
parent d05b3d376b
commit 7f365423e1
7 changed files with 97 additions and 19 deletions

View File

@ -1248,8 +1248,6 @@ Capture [cityName] =
Our status = Our status =
Global status = Global status =
Rankings = 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 = Demographics =
Demographic = Demographic =
Rank = Rank =
@ -1257,6 +1255,8 @@ Value =
Best = Best =
Average = Average =
Worst = 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] = Turns until the next\ndiplomacy victory vote: [amount] =
Choose a civ to vote for = Choose a civ to vote for =
Choose who should become the world leader and win a Diplomatic Victory! = Choose who should become the world leader and win a Diplomatic Victory! =

View File

@ -92,9 +92,9 @@ class CivInfoTransientUpdater(val civInfo: CivilizationInfo) {
} }
for (spy in civInfo.espionageManager.spyList) { for (spy in civInfo.espionageManager.spyList) {
val spyCity = spy.getLocation(civInfo.gameInfo) ?: continue val spyCity = spy.getLocation() ?: continue
newViewableTiles.addAll(spyCity.getCenterTile().neighbors) if (!spy.isSetUp()) continue // Can't see cities when you haven't set up yet
newViewableTiles.add(spyCity.getCenterTile()) newViewableTiles.addAll(spyCity.getCenterTile().getTilesInDistance(1))
} }
civInfo.viewableTiles = newViewableTiles // to avoid concurrent modification problems civInfo.viewableTiles = newViewableTiles // to avoid concurrent modification problems

View File

@ -993,6 +993,8 @@ class CivilizationInfo : IsPartOfGameInfoSerialization {
religionManager.endTurn(nextTurnStats.faith.toInt()) religionManager.endTurn(nextTurnStats.faith.toInt())
totalFaithForContests += nextTurnStats.faith.toInt() totalFaithForContests += nextTurnStats.faith.toInt()
espionageManager.endTurn()
if (isMajorCiv()) greatPeople.addGreatPersonPoints(getGreatPersonPointsForNextTurn()) // City-states don't get great people! 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 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

View File

@ -5,10 +5,25 @@ import com.unciv.logic.GameInfo
import com.unciv.logic.IsPartOfGameInfoSerialization import com.unciv.logic.IsPartOfGameInfoSerialization
import com.unciv.logic.city.CityInfo 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 { class Spy() : IsPartOfGameInfoSerialization {
// `location == null` means that the spy is in its hideout // `location == null` means that the spy is in its hideout
var location: String? = null var location: String? = null
lateinit var name: String lateinit var name: String
var timeTillActionFinish = 0
var action = SpyAction.None
@Transient
lateinit var civInfo: CivilizationInfo
constructor(name: String) : this() { constructor(name: String) : this() {
this.name = name this.name = name
@ -17,15 +32,60 @@ class Spy() : IsPartOfGameInfoSerialization {
fun clone(): Spy { fun clone(): Spy {
val toReturn = Spy(name) val toReturn = Spy(name)
toReturn.location = location toReturn.location = location
toReturn.timeTillActionFinish = timeTillActionFinish
toReturn.action = action
return toReturn return toReturn
} }
fun getLocation(gameInfo: GameInfo): CityInfo? { fun setTransients(civInfo: CivilizationInfo) {
return gameInfo.getCities().firstOrNull { it.id == location } this.civInfo = civInfo
} }
fun getLocationName(gameInfo: GameInfo): String { fun endTurn() {
return getLocation(gameInfo)?.name ?: Constants.spyHideout --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) { fun setTransients(civInfo: CivilizationInfo) {
this.civInfo = civInfo this.civInfo = civInfo
for (spy in spyList) {
spy.setTransients(civInfo)
}
}
fun endTurn() {
for (spy in spyList)
spy.endTurn()
} }
private fun getSpyName(): String { private fun getSpyName(): String {

View File

@ -60,7 +60,7 @@ class ModConstants {
// RiverGenerator: river frequency and length bounds // RiverGenerator: river frequency and length bounds
var riverCountMultiplier = 0.01f var riverCountMultiplier = 0.01f
var minRiverLength = 5 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) { fun merge(other: ModConstants) {
if (other.maxXPfromBarbarians != defaults.maxXPfromBarbarians) maxXPfromBarbarians = other.maxXPfromBarbarians if (other.maxXPfromBarbarians != defaults.maxXPfromBarbarians) maxXPfromBarbarians = other.maxXPfromBarbarians

View File

@ -4,6 +4,7 @@ import com.badlogic.gdx.Gdx
import com.badlogic.gdx.files.FileHandle import com.badlogic.gdx.files.FileHandle
import com.unciv.json.fromJsonFile import com.unciv.json.fromJsonFile
import com.unciv.json.json import com.unciv.json.json
import com.unciv.logic.civilization.SpyAction
import com.unciv.models.metadata.BaseRuleset import com.unciv.models.metadata.BaseRuleset
import com.unciv.models.metadata.LocaleCode import com.unciv.models.metadata.LocaleCode
import com.unciv.models.ruleset.* import com.unciv.models.ruleset.*
@ -124,6 +125,10 @@ object TranslationFileWriter {
for (uniqueTarget in UniqueTarget.values()) for (uniqueTarget in UniqueTarget.values())
linesToTranslate.add("$uniqueTarget = ") linesToTranslate.add("$uniqueTarget = ")
for (spyAction in SpyAction.values()) {
linesToTranslate.add("$spyAction = ")
}
} }
var countOfTranslatableLines = 0 var countOfTranslatableLines = 0

View File

@ -9,10 +9,12 @@ import com.unciv.UncivGame
import com.unciv.logic.city.CityInfo import com.unciv.logic.city.CityInfo
import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.Spy import com.unciv.logic.civilization.Spy
import com.unciv.logic.civilization.SpyAction
import com.unciv.models.translations.tr import com.unciv.models.translations.tr
import com.unciv.ui.images.ImageGetter import com.unciv.ui.images.ImageGetter
import com.unciv.ui.pickerscreens.PickerScreen import com.unciv.ui.pickerscreens.PickerScreen
import com.unciv.ui.utils.AutoScrollPane import com.unciv.ui.utils.AutoScrollPane
import com.unciv.ui.utils.Fonts
import com.unciv.ui.utils.KeyCharAndCode import com.unciv.ui.utils.KeyCharAndCode
import com.unciv.ui.utils.extensions.addSeparator import com.unciv.ui.utils.extensions.addSeparator
import com.unciv.ui.utils.extensions.addSeparatorVertical 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 spyScrollPane = AutoScrollPane(spySelectionTable)
private val citySelectionTable = Table(skin) private val citySelectionTable = Table(skin)
private val cityScrollPane = AutoScrollPane(citySelectionTable) private val cityScrollPane = AutoScrollPane(citySelectionTable)
private val headerTable = Table(skin)
private val middlePanes = Table(skin) private val middlePanes = Table(skin)
private var selectedSpyButton: TextButton? = null private var selectedSpyButton: TextButton? = null
@ -41,9 +42,6 @@ class EspionageOverviewScreen(val civInfo: CivilizationInfo) : PickerScreen(true
private var moveSpyHereButtons = hashMapOf<Button, CityInfo?>() private var moveSpyHereButtons = hashMapOf<Button, CityInfo?>()
init { init {
topTable.add(headerTable)
topTable.addSeparator()
middlePanes.add(spyScrollPane) middlePanes.add(spyScrollPane)
middlePanes.addSeparatorVertical() middlePanes.addSeparatorVertical()
middlePanes.add(cityScrollPane) middlePanes.add(cityScrollPane)
@ -67,11 +65,16 @@ class EspionageOverviewScreen(val civInfo: CivilizationInfo) : PickerScreen(true
private fun updateSpyList() { private fun updateSpyList() {
spySelectionTable.clear() spySelectionTable.clear()
spySelectionTable.add("Spy".toLabel()).pad(5f) spySelectionTable.add("Spy".toLabel()).pad(10f)
spySelectionTable.add("Location".toLabel()).pad(5f).row() spySelectionTable.add("Location".toLabel()).pad(10f)
spySelectionTable.add("Action".toLabel()).pad(10f).row()
for (spy in civInfo.espionageManager.spyList) { for (spy in civInfo.espionageManager.spyList) {
spySelectionTable.add(spy.name.toLabel()).pad(5f) spySelectionTable.add(spy.name.toLabel()).pad(10f)
spySelectionTable.add(spy.getLocationName(civInfo.gameInfo).toLabel()).pad(5f) 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() val moveSpyButton = "Move".toTextButton()
moveSpyButton.onClick { moveSpyButton.onClick {
@ -160,7 +163,7 @@ class EspionageOverviewScreen(val civInfo: CivilizationInfo) : PickerScreen(true
val moveSpyHereButton = Button(skin) val moveSpyHereButton = Button(skin)
moveSpyHereButton.add(ImageGetter.getArrowImage(Align.left).apply { color = Color.WHITE }) moveSpyHereButton.add(ImageGetter.getArrowImage(Align.left).apply { color = Color.WHITE })
moveSpyHereButton.onClick { moveSpyHereButton.onClick {
selectedSpy!!.location = city?.id selectedSpy!!.moveTo(city)
resetSelection() resetSelection()
update() update()
} }