Defeated civilizations don't use spies (#11785)

* Fixed a crash when rigging a city-state election the turn before meeting them

* Civilizations move their spies back to the hideout when defeated

* Players can't move spies when defeated

* Removed some weird indents
This commit is contained in:
Oskar Niesen 2024-06-19 09:23:42 -05:00 committed by GitHub
parent f52245865c
commit dff8133a7a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 34 additions and 23 deletions

View File

@ -909,6 +909,8 @@ class Civilization : IsPartOfGameInfoSerialization {
for (tradeRequest in diplomacyManager.otherCiv().tradeRequests.filter { it.requestingCiv == civName })
diplomacyManager.otherCiv().tradeRequests.remove(tradeRequest) // it would be really weird to get a trade request from a dead civ
}
if (gameInfo.isEspionageEnabled())
espionageManager.removeAllSpies()
}
fun updateProximity(otherCiv: Civilization, preCalculated: Proximity? = null): Proximity = cache.updateProximity(otherCiv, preCalculated)

View File

@ -77,7 +77,7 @@ class CityStateFunctions(val civInfo: Civilization) {
fun getVotesFromSpy(spy: Spy?): Float {
if (spy == null) return 20f
var votes = (civInfo.getDiplomacyManager(spy.civInfo)!!.influence / 2)
var votes = (civInfo.getDiplomacyManagerOrMeet(spy.civInfo).influence / 2)
votes += (spy.getSkillModifierPercent() * spy.getEfficiencyModifier()).toFloat() // ranges from 30 to 90
return votes
}

View File

@ -45,7 +45,8 @@ class EspionageManager : IsPartOfGameInfoSerialization {
fun getSpyName(): String {
val usedSpyNames = spyList.map { it.name }.toHashSet()
val validSpyNames = civInfo.nation.spyNames.filter { it !in usedSpyNames }
return validSpyNames.randomOrNull() ?: "Spy ${spyList.size+1}" // +1 as non-programmers count from 1
return validSpyNames.randomOrNull()
?: "Spy ${spyList.size + 1}" // +1 as non-programmers count from 1
}
fun addSpy(): Spy {
@ -100,4 +101,12 @@ class EspionageManager : IsPartOfGameInfoSerialization {
fun getIdleSpies(): List<Spy> {
return spyList.filterTo(mutableListOf()) { it.isIdle() }
}
/**
* Takes all spies away from their cities.
* Called when the civ is destroyed.
*/
fun removeAllSpies() {
spyList.forEach { it.moveTo(null) }
}
}

View File

@ -85,9 +85,9 @@ class EspionageOverviewScreen(val civInfo: Civilization, val worldScreen: WorldS
spySelectionTable.add(spy.name.toLabel())
spySelectionTable.add(spy.rank.toLabel())
spySelectionTable.add(spy.getLocationName().toLabel())
val actionString = if (spy.action.showTurns)
val actionString = if (spy.action.showTurns)
"[${spy.action.displayString}] ${spy.turnsRemainingForAction}${Fonts.turn}"
else spy.action.displayString
else spy.action.displayString
spySelectionTable.add(actionString.toLabel())
val moveSpyButton = "Move".toTextButton()
@ -97,7 +97,7 @@ class EspionageOverviewScreen(val civInfo: Civilization, val worldScreen: WorldS
moveSpyButton.onRightClick {
onSpyRightClicked(spy)
}
if (!worldScreen.canChangeState || !spy.isAlive()) {
if (!worldScreen.canChangeState || !spy.isAlive() || civInfo.isDefeated()) {
// Spectators aren't allowed to move the spies of the Civs they are viewing
moveSpyButton.disable()
}
@ -124,18 +124,18 @@ class EspionageOverviewScreen(val civInfo: Civilization, val worldScreen: WorldS
// Then add all cities
val sortedCities = civInfo.gameInfo.getCities()
.filter { civInfo.hasExplored(it.getCenterTile()) }
.sortedWith(
compareBy<City> {
it.civ != civInfo
}.thenBy {
it.civ.isCityState()
}.thenBy(collator) {
it.civ.civName.tr(hideIcons = true)
}.thenBy(collator) {
it.name.tr(hideIcons = true)
}
)
.filter { civInfo.hasExplored(it.getCenterTile()) }
.sortedWith(
compareBy<City> {
it.civ != civInfo
}.thenBy {
it.civ.isCityState()
}.thenBy(collator) {
it.civ.civName.tr(hideIcons = true)
}.thenBy(collator) {
it.name.tr(hideIcons = true)
}
)
for (city in sortedCities) {
addCityToSelectionTable(city)
}
@ -143,7 +143,7 @@ class EspionageOverviewScreen(val civInfo: Civilization, val worldScreen: WorldS
private fun addCityToSelectionTable(city: City) {
citySelectionTable.add(ImageGetter.getNationPortrait(city.civ.nation, 30f))
.padLeft(20f)
.padLeft(20f)
val label = city.name.toLabel(hideIcons = true)
label.onClick {
worldScreen.game.popScreen() // If a detour to this screen (i.e. not directly from worldScreen) is made possible, use resetToWorldScreen instead
@ -193,7 +193,7 @@ class EspionageOverviewScreen(val civInfo: Civilization, val worldScreen: WorldS
add(starTable).center().padLeft(-4f)
// Spectators aren't allowed to move the spies of the Civs they are viewing
if (worldScreen.canChangeState && spy.isAlive()) {
if (worldScreen.canChangeState && spy.isAlive() && !civInfo.isDefeated()) {
onClick {
onSpyClicked(moveSpyButtons[spy]!!, spy)
}
@ -252,7 +252,7 @@ class EspionageOverviewScreen(val civInfo: Civilization, val worldScreen: WorldS
button.setDirection(Align.right)
} else {
button.isVisible = city == null // hideout
|| !city.espionage.hasSpyOf(civInfo)
|| !city.espionage.hasSpyOf(civInfo)
button.setDirection(Align.left)
}
}
@ -285,9 +285,9 @@ class EspionageOverviewScreen(val civInfo: Civilization, val worldScreen: WorldS
val spy = selectedSpy!!
if (!isCurrentAction) {
ConfirmPopup(this@EspionageOverviewScreen,
"Do you want to stage a coup in [${city.civ.civName}] with a " +
"[${(selectedSpy!!.getCoupChanceOfSuccess(false) * 100f).toInt()}]% " +
"chance of success?", "Stage Coup") {
"Do you want to stage a coup in [${city.civ.civName}] with a " +
"[${(selectedSpy!!.getCoupChanceOfSuccess(false) * 100f).toInt()}]% " +
"chance of success?", "Stage Coup") {
spy.setAction(SpyAction.Coup, 1)
fist.color = Color.DARK_GRAY
update()