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

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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<Button, CityInfo?>()
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()
}