City-state allies with most influencing civ. (#1291)

* City-state allies with most influencing civ.

* More notifications for alliance. More intense status update.

* Fix a crash about lateinit tiles.

* More reasonable civInfo.setTransients.
This commit is contained in:
Duan Tao
2019-11-05 18:23:21 +08:00
committed by Yair Morgenstern
parent 2e9b1e6de6
commit 1e403442f7
9 changed files with 157 additions and 29 deletions

View File

@ -669,6 +669,15 @@
Czech:"Vliv: "
}
"Reach 30 for friendship.":{
}
"Reach highest influence above 60 for alliance.":{
}
"Ally: ":{
}
////// Trade
"Trade":{

View File

@ -778,4 +778,9 @@
Ukrainian:"[nation]: відмова не будувати міста поруч з нами!"
}
"We have allied with [nation].": {
}
"We have lost alliance with [nation].": {
}
}

View File

@ -246,9 +246,9 @@ class GameInfo {
}
}
for (civInfo in civilizations) civInfo.setNationTransient()
for (civInfo in civilizations) civInfo.setTransients()
for (civInfo in civilizations) civInfo.updateSightAndResources()
for (civInfo in civilizations){
for(unit in civInfo.getCivUnits())

View File

@ -125,32 +125,9 @@ class CityInfo {
for (tileInfo in getTiles().filter { it.resource != null }) {
val resource = tileInfo.getTileResource()
if (resource.revealedBy!=null && !civInfo.tech.isResearched(resource.revealedBy!!)) continue
// Even if the improvement exists (we conquered an enemy city or somesuch) or we have a city on it, we won't get the resource until the correct tech is researched
if (resource.improvement!=null){
val improvement = GameBasics.TileImprovements[resource.improvement!!]!!
if(improvement.techRequired!=null && !civInfo.tech.isResearched(improvement.techRequired!!)) continue
}
if (resource.improvement == tileInfo.improvement || tileInfo.isCityCenter()
// Per https://gaming.stackexchange.com/questions/53155/do-manufactories-and-customs-houses-sacrifice-the-strategic-or-luxury-resources
|| (resource.resourceType==ResourceType.Strategic && tileInfo.containsGreatImprovement())){
var amountToAdd = 1
if(resource.resourceType == ResourceType.Strategic){
amountToAdd = 2
if(civInfo.policies.isAdopted("Facism")) amountToAdd*=2
if(civInfo.nation.unique=="Strategic Resources provide +1 Production, and Horses, Iron and Uranium Resources provide double quantity"
&& resource.name in listOf("Horses","Iron","Uranium"))
amountToAdd *= 2
if(resource.name=="Oil" && civInfo.nation.unique=="+1 Gold from each Trade Route, Oil resources provide double quantity")
amountToAdd *= 2
}
if(resource.resourceType == ResourceType.Luxury
&& containsBuildingUnique("Provides 1 extra copy of each improved luxury resource near this City"))
amountToAdd*=2
cityResources.add(resource, amountToAdd, "Tiles")
val amount = getTileResourceAmount(tileInfo)
if (amount > 0) {
cityResources.add(resource, amount, "Tiles")
}
}
@ -163,6 +140,52 @@ class CityInfo {
return cityResources
}
fun getCityResourcesForAlly(): ResourceSupplyList {
val cityResources = ResourceSupplyList()
for (tileInfo in getTiles().filter { it.resource != null }) {
val resource = tileInfo.getTileResource()
val amount = getTileResourceAmount(tileInfo)
if (amount > 0) {
cityResources.add(resource, amount, "City-States")
}
}
return cityResources
}
fun getTileResourceAmount(tileInfo: TileInfo): Int {
if (tileInfo.resource == null) return 0
val resource = tileInfo.getTileResource()
if (resource.revealedBy!=null && !civInfo.tech.isResearched(resource.revealedBy!!)) return 0
// Even if the improvement exists (we conquered an enemy city or somesuch) or we have a city on it, we won't get the resource until the correct tech is researched
if (resource.improvement!=null){
val improvement = GameBasics.TileImprovements[resource.improvement!!]!!
if(improvement.techRequired!=null && !civInfo.tech.isResearched(improvement.techRequired!!)) return 0
}
if (resource.improvement == tileInfo.improvement || tileInfo.isCityCenter()
// Per https://gaming.stackexchange.com/questions/53155/do-manufactories-and-customs-houses-sacrifice-the-strategic-or-luxury-resources
|| (resource.resourceType==ResourceType.Strategic && tileInfo.containsGreatImprovement())){
var amountToAdd = 1
if(resource.resourceType == ResourceType.Strategic){
amountToAdd = 2
if(civInfo.policies.isAdopted("Facism")) amountToAdd*=2
if(civInfo.nation.unique=="Strategic Resources provide +1 Production, and Horses, Iron and Uranium Resources provide double quantity"
&& resource.name in listOf("Horses","Iron","Uranium"))
amountToAdd *= 2
if(resource.name=="Oil" && civInfo.nation.unique=="+1 Gold from each Trade Route, Oil resources provide double quantity")
amountToAdd *= 2
}
if(resource.resourceType == ResourceType.Luxury
&& containsBuildingUnique("Provides 1 extra copy of each improved luxury resource near this City"))
amountToAdd*=2
return amountToAdd
}
return 0
}
fun getBuildingUniques(): List<String> = cityConstructions.getBuiltBuildings().flatMap { it.uniques }
fun containsBuildingUnique(unique:String) = cityConstructions.getBuiltBuildings().any { it.uniques.contains(unique) }

View File

@ -25,6 +25,15 @@ class CivInfoTransientUpdater(val civInfo: CivilizationInfo){
val neighboringUnownedTiles = ownedTiles.flatMap { it.neighbors.asSequence().filter { it.getOwner()!=civInfo } }
newViewableTiles.addAll(neighboringUnownedTiles)
newViewableTiles.addAll(civInfo.getCivUnits().asSequence().flatMap { it.viewableTiles.asSequence()})
if (!civInfo.isCityState()) {
for (otherCiv in civInfo.getKnownCivs()) {
if (otherCiv.getAllyCiv() == civInfo.civName) {
newViewableTiles.addAll(otherCiv.cities.asSequence().flatMap { it.getTiles().asSequence() })
}
}
}
civInfo.viewableTiles = newViewableTiles // to avoid concurrent modification problems
val newViewableInvisibleTiles = HashSet<TileInfo>()
@ -138,6 +147,17 @@ class CivInfoTransientUpdater(val civInfo: CivilizationInfo){
fun updateDetailedCivResources() {
val newDetailedCivResources = ResourceSupplyList()
for (city in civInfo.cities) newDetailedCivResources.add(city.getCityResources())
if (!civInfo.isCityState()) {
for (otherCiv in civInfo.getKnownCivs()) {
if (otherCiv.getAllyCiv() == civInfo.civName) {
for (city in otherCiv.cities) {
newDetailedCivResources.add(city.getCityResourcesForAlly())
}
}
}
}
for (dip in civInfo.diplomacy.values) newDetailedCivResources.add(dip.resourcesFromTrade())
for(resource in civInfo.getCivUnits().mapNotNull { it.baseUnit.requiredResource }.map { GameBasics.TileResources[it]!! })
newDetailedCivResources.add(resource,-1,"Units")

View File

@ -58,6 +58,7 @@ class CivilizationInfo {
var diplomacy = HashMap<String, DiplomacyManager>()
var notifications = ArrayList<Notification>()
val popupAlerts = ArrayList<PopupAlert>()
var allyCivName = ""
//** for trades here, ourOffers is the current civ's offers, and theirOffers is what the requesting civ offers */
val tradeRequests = ArrayList<TradeRequest>()
@ -87,6 +88,7 @@ class CivilizationInfo {
toReturn.goldenAges = goldenAges.clone()
toReturn.greatPeople = greatPeople.clone()
toReturn.victoryManager = victoryManager.clone()
toReturn.allyCivName = allyCivName
for (diplomacyManager in diplomacy.values.map { it.clone() })
toReturn.diplomacy.put(diplomacyManager.otherCivName, diplomacyManager)
toReturn.cities = cities.map { it.clone() }
@ -325,6 +327,9 @@ class CivilizationInfo {
cityInfo.civInfo = this // must be before the city's setTransients because it depends on the tilemap, that comes from the currentPlayerCivInfo
cityInfo.setTransients()
}
}
fun updateSightAndResources() {
updateViewableTiles()
updateHasActiveGreatWall()
updateDetailedCivResources()
@ -394,6 +399,7 @@ class CivilizationInfo {
goldenAges.endTurn(getHappiness())
getCivUnits().forEach { it.endTurn() }
diplomacy.values.forEach{it.nextTurn()}
updateAllyCivForCityState()
updateHasActiveGreatWall()
}
@ -459,6 +465,7 @@ class CivilizationInfo {
if(!otherCiv.isCityState()) throw Exception("You can only gain influence with city states!")
gold -= giftAmount
otherCiv.getDiplomacyManager(this).influence += giftAmount/10
otherCiv.updateAllyCivForCityState()
updateStatsForNextTurn()
}
@ -471,5 +478,36 @@ class CivilizationInfo {
addNotification("[${otherCiv.civName}] gave us a [${militaryUnit.name}] as gift near [${city.name}]!", null, Color.GREEN)
}
fun getAllyCiv(): String {
return allyCivName
}
fun updateAllyCivForCityState() {
var newAllyName = ""
if (!isCityState()) return
val maxInfluence = diplomacy.filter{ !it.value.otherCiv().isCityState() && !it.value.otherCiv().isDefeated() }.maxBy { it.value.influence }
if (maxInfluence != null && maxInfluence.value.influence >= 60) {
newAllyName = maxInfluence.key
}
if (allyCivName != newAllyName) {
val oldAllyName = allyCivName
allyCivName = newAllyName
if (newAllyName != "") {
val newAllyCiv = gameInfo.getCivilization(newAllyName)
newAllyCiv.addNotification("We have allied with [${civName}].", Color.GREEN)
newAllyCiv.updateViewableTiles()
newAllyCiv.updateDetailedCivResources()
}
if (oldAllyName != "") {
val oldAllyCiv = gameInfo.getCivilization(oldAllyName)
oldAllyCiv.addNotification("We have lost alliance with [${civName}].", Color.RED)
oldAllyCiv.updateViewableTiles()
oldAllyCiv.updateDetailedCivResources()
}
}
}
//endregion
}

View File

@ -342,6 +342,22 @@ class DiplomacyManager() {
}
}
otherCivDiplomacy.removeFlag(DiplomacyFlags.DeclarationOfFriendship)
if (otherCiv.isCityState()) otherCiv.updateAllyCivForCityState()
if (!civInfo.isCityState()) {
for (thirdCiv in civInfo.getKnownCivs()) {
if (thirdCiv.isCityState() && thirdCiv.getAllyCiv() == civInfo.civName && thirdCiv.getDiplomacyManager(otherCiv).canDeclareWar()) {
thirdCiv.getDiplomacyManager(otherCiv).declareWar()
}
}
}
if (!otherCiv.isCityState()) {
for (thirdCiv in otherCiv.getKnownCivs()) {
if (thirdCiv.isCityState() && thirdCiv.getAllyCiv() == otherCiv.civName && thirdCiv.getDiplomacyManager(civInfo).canDeclareWar()) {
thirdCiv.getDiplomacyManager(civInfo).declareWar()
}
}
}
}
fun makePeace(){

View File

@ -2,6 +2,7 @@ package com.unciv.models.gamebasics
import com.badlogic.gdx.graphics.Color
import com.unciv.logic.civilization.CityStateType
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.models.stats.INamed
import com.unciv.ui.utils.colorFromRGB

View File

@ -95,9 +95,25 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
diplomacyTable.defaults().pad(10f)
diplomacyTable.add(otherCiv.getLeaderDisplayName().toLabel(fontSize = 24)).row()
diplomacyTable.add(("Type: ".tr() + otherCiv.getCityStateType().toString().tr()).toLabel()).row()
diplomacyTable.add(("Influence: ".tr() + otherCivDiplomacyManager.influence.toInt() + "/30").toLabel()).row()
otherCiv.updateAllyCivForCityState()
val ally = otherCiv.getAllyCiv()
if (ally != "")
{
diplomacyTable.add(("Ally: ".tr() + ally!!.tr() + " " + "Influence: ".tr()
+ otherCiv.getDiplomacyManager(ally).influence.toString().tr()).toLabel()).row()
}
val nextLevelString: String
if (otherCivDiplomacyManager.influence.toInt() < 30) {
nextLevelString = "Reach 30 for friendship."
} else if (ally == viewingCiv.civName) {
nextLevelString = ""
} else {
nextLevelString = "Reach highest influence above 60 for alliance."
}
diplomacyTable.add(getRelationshipTable(otherCivDiplomacyManager)).row()
if (nextLevelString != "") {
diplomacyTable.add(nextLevelString.tr().toLabel()).row()
}
val friendBonusText = when (otherCiv.getCityStateType()) {
CityStateType.Cultured -> ("Provides [" + (3 * (viewingCiv.getEra().ordinal + 1)).toString() + "] culture at [30] Influence").tr()