mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-09 23:39:40 +07:00
Basic version of EspionageManger
, added a unique to gain spies (#7641)
* Handfull of comment questions, small refactorings * Code changes * Reworded a unique, removed a file * Added spy names for all nations, minor consistency change * Removed debug output * Added an empty constructor so gdx can reconstruct it
This commit is contained in:
@ -155,6 +155,7 @@ class CivilizationInfo : IsPartOfGameInfoSerialization {
|
||||
var religionManager = ReligionManager()
|
||||
var goldenAges = GoldenAgeManager()
|
||||
var greatPeople = GreatPersonManager()
|
||||
var espionageManager = EspionageManager()
|
||||
var victoryManager = VictoryManager()
|
||||
var ruinsManager = RuinsManager()
|
||||
var diplomacy = HashMap<String, DiplomacyManager>()
|
||||
@ -261,6 +262,7 @@ class CivilizationInfo : IsPartOfGameInfoSerialization {
|
||||
toReturn.goldenAges = goldenAges.clone()
|
||||
toReturn.greatPeople = greatPeople.clone()
|
||||
toReturn.ruinsManager = ruinsManager.clone()
|
||||
toReturn.espionageManager = espionageManager.clone()
|
||||
toReturn.victoryManager = victoryManager.clone()
|
||||
toReturn.allyCivName = allyCivName
|
||||
for (diplomacyManager in diplomacy.values.map { it.clone() })
|
||||
@ -833,6 +835,8 @@ class CivilizationInfo : IsPartOfGameInfoSerialization {
|
||||
diplomacyManager.updateHasOpenBorders()
|
||||
}
|
||||
|
||||
espionageManager.setTransients(this)
|
||||
|
||||
victoryManager.civInfo = this
|
||||
|
||||
thingsToFocusOnForVictory = getPreferredVictoryTypeObject()?.getThingsToFocus(this) ?: setOf()
|
||||
|
50
core/src/com/unciv/logic/civilization/EspionageManager.kt
Normal file
50
core/src/com/unciv/logic/civilization/EspionageManager.kt
Normal file
@ -0,0 +1,50 @@
|
||||
package com.unciv.logic.civilization
|
||||
|
||||
import com.unciv.logic.IsPartOfGameInfoSerialization
|
||||
|
||||
class Spy() : IsPartOfGameInfoSerialization {
|
||||
lateinit var name: String
|
||||
|
||||
constructor(name: String) : this() {
|
||||
this.name = name
|
||||
}
|
||||
|
||||
fun clone(): Spy {
|
||||
return Spy(name)
|
||||
}
|
||||
}
|
||||
|
||||
class EspionageManager : IsPartOfGameInfoSerialization {
|
||||
|
||||
var spyCount = 0
|
||||
var spyList = mutableListOf<Spy>()
|
||||
var erasSpyEarnedFor = mutableListOf<String>()
|
||||
|
||||
@Transient
|
||||
lateinit var civInfo: CivilizationInfo
|
||||
|
||||
fun clone(): EspionageManager {
|
||||
val toReturn = EspionageManager()
|
||||
toReturn.spyCount = spyCount
|
||||
toReturn.spyList.addAll(spyList.map { it.clone() })
|
||||
toReturn.erasSpyEarnedFor.addAll(erasSpyEarnedFor)
|
||||
return toReturn
|
||||
}
|
||||
|
||||
fun setTransients(civInfo: CivilizationInfo) {
|
||||
this.civInfo = civInfo
|
||||
}
|
||||
|
||||
private fun getSpyName(): String {
|
||||
val usedSpyNames = spyList.map { it.name }.toHashSet()
|
||||
val validSpyNames = civInfo.nation.spyNames.filter { it !in usedSpyNames }
|
||||
if (validSpyNames.isEmpty()) { return "Spy ${spyList.size+1}" } // +1 as non-programmers count from 1
|
||||
return validSpyNames.random()
|
||||
}
|
||||
|
||||
fun addSpy(): String {
|
||||
val spyName = getSpyName()
|
||||
spyList.add(Spy(spyName))
|
||||
return spyName
|
||||
}
|
||||
}
|
@ -14,28 +14,30 @@ import com.unciv.ui.worldscreen.WorldScreen
|
||||
|
||||
object NotificationIcon {
|
||||
// Remember: The typical white-on-transparency icon will not be visible on Notifications
|
||||
|
||||
const val Barbarians = "ImprovementIcons/Barbarian encampment"
|
||||
const val Citadel = "ImprovementIcons/Citadel"
|
||||
const val City = "ImprovementIcons/City center"
|
||||
const val CityState = "OtherIcons/CityState"
|
||||
const val Crosshair = "OtherIcons/CrosshairB"
|
||||
const val Culture = "StatIcons/Culture"
|
||||
const val Construction = "StatIcons/Production"
|
||||
const val Growth = "StatIcons/Population"
|
||||
const val War = "OtherIcons/Pillage"
|
||||
const val Trade = "StatIcons/Acquire"
|
||||
const val Science = "StatIcons/Science"
|
||||
const val Gold = "StatIcons/Gold"
|
||||
const val Death = "OtherIcons/DisbandUnit"
|
||||
const val Diplomacy = "OtherIcons/Diplomacy"
|
||||
const val City = "ImprovementIcons/City center"
|
||||
const val Citadel = "ImprovementIcons/Citadel"
|
||||
const val Faith = "StatIcons/Faith"
|
||||
const val Food = "StatIcons/Food"
|
||||
const val Gold = "StatIcons/Gold"
|
||||
const val Growth = "StatIcons/Population"
|
||||
const val Happiness = "StatIcons/Happiness"
|
||||
const val Population = "StatIcons/Population"
|
||||
const val CityState = "OtherIcons/CityState"
|
||||
const val Production = "StatIcons/Production"
|
||||
const val Food = "StatIcons/Food"
|
||||
const val Faith = "StatIcons/Faith"
|
||||
const val Crosshair = "OtherIcons/CrosshairB"
|
||||
const val Scout = "UnitIcons/Scout"
|
||||
const val Ruins = "ImprovementIcons/Ancient ruins"
|
||||
const val Barbarians = "ImprovementIcons/Barbarian encampment"
|
||||
const val Question = "OtherIcons/Question"
|
||||
const val Ruins = "ImprovementIcons/Ancient ruins"
|
||||
const val Science = "StatIcons/Science"
|
||||
const val Scout = "UnitIcons/Scout"
|
||||
const val Spy = "OtherIcons/Spy"
|
||||
const val Trade = "StatIcons/Acquire"
|
||||
const val War = "OtherIcons/Pillage"
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -193,15 +193,13 @@ class PolicyManager : IsPartOfGameInfoSerialization {
|
||||
}
|
||||
}
|
||||
|
||||
// Todo make this a triggerable unique for other objects
|
||||
for (unique in policy.getMatchingUniques(UniqueType.OneTimeGlobalAlert)) {
|
||||
triggerGlobalAlerts(
|
||||
policy, unique.params[0]
|
||||
)
|
||||
triggerGlobalAlerts(policy, unique.params[0])
|
||||
}
|
||||
|
||||
for (unique in policy.uniqueObjects) UniqueTriggerActivation.triggerCivwideUnique(
|
||||
unique, civInfo
|
||||
)
|
||||
for (unique in policy.uniqueObjects)
|
||||
UniqueTriggerActivation.triggerCivwideUnique(unique, civInfo)
|
||||
|
||||
// This ALSO has the side-effect of updating the CivInfo statForNextTurn so we don't need to call it explicitly
|
||||
for (cityInfo in civInfo.cities) cityInfo.cityStats.update()
|
||||
@ -223,7 +221,7 @@ class PolicyManager : IsPartOfGameInfoSerialization {
|
||||
) {
|
||||
var extraNotificationTextCopy = extraNotificationText
|
||||
if (extraNotificationText != "") {
|
||||
extraNotificationTextCopy = "\n${extraNotificationText}"
|
||||
extraNotificationTextCopy = " ${extraNotificationText}"
|
||||
}
|
||||
for (civ in civInfo.gameInfo.civilizations.filter { it.isMajorCiv() }) {
|
||||
if (civ == civInfo) continue
|
||||
|
@ -1,4 +1,5 @@
|
||||
package com.unciv.logic.civilization.RuinsManager
|
||||
// Why is this the only file in its own package?
|
||||
|
||||
import com.unciv.logic.IsPartOfGameInfoSerialization
|
||||
import com.unciv.logic.civilization.CivilizationInfo
|
||||
|
@ -238,9 +238,6 @@ class TechManager : IsPartOfGameInfoSerialization {
|
||||
}
|
||||
|
||||
fun addTechnology(techName: String) {
|
||||
techsInProgress.remove(techName)
|
||||
|
||||
val previousEra = civInfo.getEra()
|
||||
techsResearched.add(techName)
|
||||
|
||||
// this is to avoid concurrent modification problems
|
||||
@ -262,19 +259,6 @@ class TechManager : IsPartOfGameInfoSerialization {
|
||||
civInfo.addNotification("Research of [$techName] has completed!", TechAction(techName), NotificationIcon.Science, techName)
|
||||
civInfo.popupAlerts.add(PopupAlert(AlertType.TechResearched, techName))
|
||||
|
||||
val currentEra = civInfo.getEra()
|
||||
if (previousEra != currentEra) {
|
||||
civInfo.addNotification("You have entered the [$currentEra]!", NotificationIcon.Science)
|
||||
if (civInfo.isMajorCiv()) {
|
||||
for (knownCiv in civInfo.getKnownCivs()) {
|
||||
knownCiv.addNotification("[${civInfo.civName}] has entered the [$currentEra]!", civInfo.civName, NotificationIcon.Science)
|
||||
}
|
||||
}
|
||||
for (it in getRuleset().policyBranches.values.filter { it.era == currentEra.name && civInfo.policies.isAdoptable(it) }) {
|
||||
civInfo.addNotification("[" + it.name + "] policy branch unlocked!", NotificationIcon.Culture)
|
||||
}
|
||||
}
|
||||
|
||||
if (civInfo.playerType == PlayerType.Human) {
|
||||
for (revealedResource in getRuleset().tileResources.values.filter { techName == it.revealedBy }) {
|
||||
civInfo.gameInfo.notifyExploredResources(civInfo, revealedResource.name, 5, false)
|
||||
@ -334,7 +318,23 @@ class TechManager : IsPartOfGameInfoSerialization {
|
||||
civInfo.addNotification("You have unlocked [The Long Count]!", MayaLongCountAction(), MayaCalendar.notificationIcon)
|
||||
}
|
||||
|
||||
val previousEra = civInfo.getEra()
|
||||
updateEra()
|
||||
val currentEra = civInfo.getEra()
|
||||
if (previousEra != currentEra) {
|
||||
civInfo.addNotification("You have entered the [$currentEra]!", NotificationIcon.Science)
|
||||
if (civInfo.isMajorCiv()) {
|
||||
for (knownCiv in civInfo.getKnownCivs()) {
|
||||
knownCiv.addNotification("[${civInfo.civName}] has entered the [$currentEra]!", civInfo.civName, NotificationIcon.Science)
|
||||
}
|
||||
}
|
||||
for (policyBranch in getRuleset().policyBranches.values.filter { it.era == currentEra.name && civInfo.policies.isAdoptable(it) }) {
|
||||
civInfo.addNotification("[" + policyBranch.name + "] policy branch unlocked!", NotificationIcon.Culture)
|
||||
}
|
||||
for (unique in currentEra.uniqueObjects) {
|
||||
UniqueTriggerActivation.triggerCivwideUnique(unique, civInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateEra() {
|
||||
|
@ -48,6 +48,8 @@ class Nation : RulesetObject() {
|
||||
var adjective = ArrayList<String>()
|
||||
*/
|
||||
|
||||
var spyNames = ArrayList<String>()
|
||||
|
||||
var favoredReligion: String? = null
|
||||
|
||||
@Transient
|
||||
|
@ -13,6 +13,11 @@ import com.unciv.models.ruleset.unique.UniqueTarget
|
||||
* @see com.unciv.models.TutorialTrigger
|
||||
*/
|
||||
class Tutorial : RulesetObject() {
|
||||
// Why does this override RulesetObject()? The only unique it overrides is `Will not be displayed in Civilopedia`,
|
||||
// so allowing it access to the full power of uniques is completely unnecessary.
|
||||
// (Also, what even would it mean for this to have uniques like "[+10]% Production"? When should it even apply.)
|
||||
// imo just having a flag for this (and maybe one if religion is disabled, but even then, that should be a ruleset choice) should suffice.
|
||||
// -xlenstra
|
||||
override var name = "" // overridden only to have the name seen first by TranslationFileWriter
|
||||
|
||||
/** These lines will be displayed (when the Tutorial is _triggered_) one after another,
|
||||
|
@ -477,8 +477,26 @@ object UniqueTriggerActivation {
|
||||
return true
|
||||
}
|
||||
|
||||
FreeStatBuildings, FreeSpecificBuildings ->
|
||||
OneTimeGlobalSpiesWhenEnteringEra -> {
|
||||
if (!civInfo.isMajorCiv()) return false
|
||||
val currentEra = civInfo.getEra().name
|
||||
for (otherCiv in civInfo.gameInfo.getAliveMajorCivs()) {
|
||||
if (currentEra !in otherCiv.espionageManager.erasSpyEarnedFor) {
|
||||
val spyName = otherCiv.espionageManager.addSpy()
|
||||
otherCiv.espionageManager.erasSpyEarnedFor.add(currentEra)
|
||||
if (otherCiv == civInfo || otherCiv.knows(civInfo))
|
||||
otherCiv.addNotification("We have recruited [${spyName}] as a spy!", NotificationIcon.Spy)
|
||||
else
|
||||
otherCiv.addNotification("After an unknown civilization entered the [${currentEra}], we have recruited [${spyName}] as a spy!", NotificationIcon.Spy)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
FreeStatBuildings, FreeSpecificBuildings -> {
|
||||
civInfo.civConstructions.tryAddFreeBuildings()
|
||||
return true // not fully correct
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ enum class UniqueTarget(val inheritsFrom: UniqueTarget? = null) {
|
||||
// Civilization-specific
|
||||
Nation(Global),
|
||||
Era(Global),
|
||||
Speed(Global),
|
||||
Tech(Global),
|
||||
Policy(Global),
|
||||
FounderBelief(Global),
|
||||
@ -46,6 +45,7 @@ enum class UniqueTarget(val inheritsFrom: UniqueTarget? = null) {
|
||||
Ruins(Triggerable),
|
||||
|
||||
// Other
|
||||
Speed,
|
||||
Tutorial,
|
||||
CityState,
|
||||
ModOptions,
|
||||
@ -314,7 +314,6 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
|
||||
TriggersAlertOnCompletion("Triggers a global alert upon completion", UniqueTarget.Building, UniqueTarget.Unit),
|
||||
//endregion
|
||||
|
||||
|
||||
///////////////////////////////////////// region BUILDING UNIQUES /////////////////////////////////////////
|
||||
|
||||
|
||||
@ -351,7 +350,6 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
|
||||
CreatesOneImprovement("Creates a [improvementName] improvement on a specific tile", UniqueTarget.Building),
|
||||
//endregion
|
||||
|
||||
|
||||
///////////////////////////////////////// region UNIT UNIQUES /////////////////////////////////////////
|
||||
|
||||
FoundCity("Founds a new city", UniqueTarget.Unit),
|
||||
@ -685,7 +683,8 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
|
||||
OneTimeRevealSpecificMapTiles("Reveal up to [amount/'all'] [tileFilter] within a [amount] tile radius", UniqueTarget.Ruins),
|
||||
OneTimeRevealCrudeMap("From a randomly chosen tile [amount] tiles away from the ruins, reveal tiles up to [amount] tiles away with [amount]% chance", UniqueTarget.Ruins),
|
||||
OneTimeTriggerVoting("Triggers voting for the Diplomatic Victory", UniqueTarget.Triggerable), // used in Building
|
||||
OneTimeGlobalAlert("Triggers the following global alert: [comment]", UniqueTarget.Triggerable), // used in Policy
|
||||
OneTimeGlobalAlert("Triggers the following global alert: [comment]", UniqueTarget.Policy), // used in Policy
|
||||
OneTimeGlobalSpiesWhenEnteringEra("Every major Civilization gains a spy once a civilization enters this era", UniqueTarget.Era),
|
||||
|
||||
OneTimeUnitHeal("Heal this unit by [amount] HP", UniqueTarget.Promotion),
|
||||
OneTimeUnitGainXP("This Unit gains [amount] XP", UniqueTarget.Ruins),
|
||||
|
Reference in New Issue
Block a user