Implemented "Don't settle cities near us", which goes both ways - a good basis for further demands (#831)

This commit is contained in:
Yair Morgenstern
2019-06-07 13:04:18 +03:00
parent 96cb7a5646
commit f713d266db
8 changed files with 132 additions and 27 deletions

View File

@ -126,7 +126,7 @@
Portuguese:"Dessa vez não."
}
"Excellent!":{ // AI statement after we accept a trade they proposed, and when we meet a city state
"Excellent!":{ // AI statement after we accept a trade they proposed, and when we meet a city state, and our response when they agree to our diplomatic demand
Italian:"Eccellente!"
Simplified_Chinese:"好极了!和和气气才是生财之道。"
French:"Excellent!"
@ -358,8 +358,18 @@
French:"Vous avez dénoncé nos ennemies"
}
// Demands
"Demands":{}
"Please don't settle new cities near us.":{}
"Very well, we shall look for new lands to settle.":{}
"We shall do as we please.":{}
"You betrayed your promise to not settle cities near us":{}
"You refused to stop settling cities near us":{}
"We noticed your new city near our borders, despite your promise. This will have....implications.":{}
////// Trade

View File

@ -147,7 +147,8 @@ class GameInfo {
for (civ in civilizations.filter { !it.isBarbarianCivilization() && !it.isDefeated() }) {
allResearchedTechs.retainAll(civ.tech.techsResearched)
}
val unitList = GameBasics.Units.values.filter { !it.unitType.isCivilian() && it.uniqueTo == null }
val unitList = GameBasics.Units.values
.filter { !it.unitType.isCivilian() && it.uniqueTo == null }
.filter{ allResearchedTechs.contains(it.requiredTech)
&& (it.obsoleteTech == null || !allResearchedTechs.contains(it.obsoleteTech!!)) }

View File

@ -1,7 +1,6 @@
package com.unciv.logic.automation
import com.unciv.Constants
import com.unciv.logic.city.CityInfo
import com.unciv.logic.civilization.*
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
import com.unciv.logic.civilization.diplomacy.DiplomaticModifiers
@ -22,6 +21,7 @@ class NextTurnAutomation{
offerPeaceTreaty(civInfo)
exchangeTechs(civInfo)
exchangeLuxuries(civInfo)
issueRequests(civInfo)
}
chooseTechToResearch(civInfo)
@ -36,6 +36,7 @@ class NextTurnAutomation{
civInfo.popupAlerts.clear() // AIs don't care about popups.
}
private fun buyBuildingOrUnit(civInfo: CivilizationInfo) {
//allow AI spending money to purchase building & unit
for (city in civInfo.cities.sortedByDescending{ it.population.population }) {
@ -349,17 +350,30 @@ class NextTurnAutomation{
}
fun onCitySettledNearBorders(civInfo: CivilizationInfo, newCity: CityInfo){
val diplomacyManager = civInfo.getDiplomacyManager(newCity.civInfo)
if(diplomacyManager.hasFlag(DiplomacyFlags.IgnoreThemSettlingNearUs)) return
if(diplomacyManager.hasFlag(DiplomacyFlags.AgreedToNotSettleNearUs)){
newCity.civInfo.popupAlerts.add(PopupAlert(AlertType.CitySettledNearOtherCivDespiteOurPromise, civInfo.civName))
diplomacyManager.setFlag(DiplomacyFlags.IgnoreThemSettlingNearUs,200)
diplomacyManager.setModifier(DiplomaticModifiers.BetrayedPromiseToNotSettleCitiesNearUs,-20f)
}
else{
newCity.civInfo.popupAlerts.add(PopupAlert(AlertType.CitySettledNearOtherCiv, civInfo.civName))
private fun issueRequests(civInfo: CivilizationInfo) {
for(otherCiv in civInfo.getKnownCivs().filter { it.isMajorCiv() }){
val diploManager = civInfo.getDiplomacyManager(otherCiv)
if(diploManager.hasFlag(DiplomacyFlags.SettledCitiesNearUs))
onCitySettledNearBorders(civInfo,otherCiv)
}
}
fun onCitySettledNearBorders(civInfo: CivilizationInfo, otherCiv:CivilizationInfo){
val diplomacyManager = civInfo.getDiplomacyManager(otherCiv)
when {
diplomacyManager.hasFlag(DiplomacyFlags.IgnoreThemSettlingNearUs) -> {}
diplomacyManager.hasFlag(DiplomacyFlags.AgreedToNotSettleNearUs) -> {
otherCiv.popupAlerts.add(PopupAlert(AlertType.CitySettledNearOtherCivDespiteOurPromise, civInfo.civName))
diplomacyManager.setFlag(DiplomacyFlags.IgnoreThemSettlingNearUs,200)
diplomacyManager.setModifier(DiplomaticModifiers.BetrayedPromiseToNotSettleCitiesNearUs,-20f)
}
else -> {
val threatLevel = Automation().threatAssessment(civInfo,otherCiv)
if(threatLevel<ThreatLevel.High) // don't piss them off for no reason please.
otherCiv.popupAlerts.add(PopupAlert(AlertType.CitySettledNearOtherCiv, civInfo.civName))
}
}
diplomacyManager.removeFlag(DiplomacyFlags.SettledCitiesNearUs)
}
}

View File

@ -3,6 +3,7 @@ package com.unciv.logic.automation
import com.unciv.UnCivGame
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.GreatPersonManager
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
import com.unciv.logic.map.MapUnit
import com.unciv.logic.map.TileInfo
import com.unciv.models.stats.Stats
@ -81,7 +82,15 @@ class SpecificUnitAutomation{
if(unit.getTile().militaryUnit==null) return // Don't move until you're accompanied by a military unit
val tilesNearCities = unit.civInfo.gameInfo.civilizations.flatMap { it.cities }
.flatMap { it.getCenterTile().getTilesInDistance(3) }.toHashSet()
.flatMap {
val distanceAwayFromCity =
if (it.civInfo.knows(unit.civInfo.civName)
&& it.civInfo.getDiplomacyManager(unit.civInfo).hasFlag(DiplomacyFlags.WeAgreedNotToSettleNearThem))
6
else 3
it.getCenterTile().getTilesInDistance(distanceAwayFromCity)
}
.toHashSet()
// This is to improve performance - instead of ranking each tile in the area up to 19 times, do it once.
val nearbyTileRankings = unit.getTile().getTilesInDistance(7)

View File

@ -4,6 +4,7 @@ import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.math.Vector2
import com.unciv.Constants
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
import com.unciv.logic.map.RoadStatus
import com.unciv.logic.map.TileInfo
import com.unciv.logic.map.TileMap
@ -39,7 +40,7 @@ class CityInfo {
var hasSoldBuildingThisTurn = false
constructor() // for json parsing, we need to have a default constructor
constructor(civInfo: CivilizationInfo, cityLocation: Vector2) {
constructor(civInfo: CivilizationInfo, cityLocation: Vector2) { // new city!
this.civInfo = civInfo
this.location = cityLocation
setTransients()
@ -78,6 +79,15 @@ class CityInfo {
workedTiles = hashSetOf() //reassign 1st working tile
population.autoAssignPopulation()
cityStats.update()
val citiesWithin6Tiles = civInfo.gameInfo.civilizations.filter { it.isMajorCiv() && it!=civInfo }
.flatMap { it.cities }
.filter { it.getCenterTile().arialDistanceTo(getCenterTile()) <= 6 }
val civsWithCloseCities = citiesWithin6Tiles.map { it.civInfo }.distinct()
.filter { it.exploredTiles.contains(location) }
for(otherCiv in civsWithCloseCities)
otherCiv.getDiplomacyManager(civInfo).setFlag(DiplomacyFlags.SettledCitiesNearUs,30)
}
//region pure functions

View File

@ -29,7 +29,9 @@ enum class DiplomacyFlags{
DeclarationOfFriendship,
Denunceation,
BorderConflict,
SettledCitiesNearUs,
AgreedToNotSettleNearUs,
WeAgreedNotToSettleNearThem,
IgnoreThemSettlingNearUs
}
@ -41,6 +43,7 @@ enum class DiplomaticModifiers{
BetrayedDeclarationOfFriendship,
Denunciation,
DenouncedOurAllies,
RefusedToNotSettleCitiesNearUs,
BetrayedPromiseToNotSettleCitiesNearUs,
YearsOfPeace,
@ -48,7 +51,8 @@ enum class DiplomaticModifiers{
DeclarationOfFriendship,
DeclaredFriendshipWithOurAllies,
DenouncedOurEnemies,
OpenBorders
OpenBorders,
FulfilledPromiseToNotSettleCitiesNearUs
}
class DiplomacyManager() {
@ -241,7 +245,10 @@ class DiplomacyManager() {
revertToZero(DiplomaticModifiers.DeclaredWarOnUs,1/8f) // this disappears real slow - it'll take 160 turns to really forget, this is war declaration we're talking about
revertToZero(DiplomaticModifiers.WarMongerer,1/2f) // warmongering gives a big negative boost when it happens but they're forgotten relatively quickly, like WWII amirite
revertToZero(DiplomaticModifiers.CapturedOurCities,1/4f) // if you captured our cities, though, that's harder to forget
revertToZero(DiplomaticModifiers.BetrayedDeclarationOfFriendship,1/2f) // if you captured our cities, though, that's harder to forget
revertToZero(DiplomaticModifiers.BetrayedDeclarationOfFriendship,1/8f) // That's a bastardly thing to do
revertToZero(DiplomaticModifiers.RefusedToNotSettleCitiesNearUs,1/4f)
revertToZero(DiplomaticModifiers.BetrayedPromiseToNotSettleCitiesNearUs,1/8f) // That's a bastardly thing to do
if(!hasFlag(DiplomacyFlags.DeclarationOfFriendship))
revertToZero(DiplomaticModifiers.DeclarationOfFriendship, 1/2f) //decreases slowly and will revert to full if it is declared later
@ -249,6 +256,8 @@ class DiplomacyManager() {
flagsCountdown[flag] = flagsCountdown[flag]!! - 1
if(flagsCountdown[flag]==0) {
flagsCountdown.remove(flag)
if(flag==DiplomacyFlags.AgreedToNotSettleNearUs.name)
addModifier(DiplomaticModifiers.FulfilledPromiseToNotSettleCitiesNearUs,10f)
}
}

View File

@ -7,6 +7,8 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.unciv.Constants
import com.unciv.UnCivGame
import com.unciv.logic.automation.Automation
import com.unciv.logic.automation.ThreatLevel
import com.unciv.logic.civilization.CityStateType
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
@ -78,10 +80,10 @@ class DiplomacyScreen:CameraStageBaseScreen() {
}
}
fun updateRightSide(civ: CivilizationInfo){
fun updateRightSide(otherCiv: CivilizationInfo){
rightSideTable.clear()
if(civ.isCityState()) rightSideTable.add(getCityStateDiplomacyTable(civ))
else rightSideTable.add(getMajorCivDiplomacyTable(civ))
if(otherCiv.isCityState()) rightSideTable.add(getCityStateDiplomacyTable(otherCiv))
else rightSideTable.add(getMajorCivDiplomacyTable(otherCiv))
}
fun setTrade(civ: CivilizationInfo): TradeTable {
@ -209,7 +211,7 @@ class DiplomacyScreen:CameraStageBaseScreen() {
val declareFriendshipButton = TextButton("Declare Friendship ([30] turns)".tr(),skin)
declareFriendshipButton.onClick {
diplomacyManager.signDeclarationOfFriendship()
setRightSideFlavorText(otherCiv,"May our nations forever remain united!".tr(),"Indeed!".tr())
setRightSideFlavorText(otherCiv,"May our nations forever remain united!","Indeed!")
}
diplomacyTable.add(declareFriendshipButton).row()
}
@ -219,7 +221,7 @@ class DiplomacyScreen:CameraStageBaseScreen() {
val denounceButton = TextButton("Denounce ([30] turns)".tr(),skin)
denounceButton.onClick {
diplomacyManager.denounce()
setRightSideFlavorText(otherCiv,"We will remember this.".tr(),"Very well.".tr())
setRightSideFlavorText(otherCiv,"We will remember this.","Very well.")
}
diplomacyTable.add(denounceButton).row()
}
@ -228,6 +230,12 @@ class DiplomacyScreen:CameraStageBaseScreen() {
diplomacyTable.add(declareWarButton).row()
}
val demandsButton = TextButton("Demands".tr(),skin)
demandsButton.onClick {
rightSideTable.clear();
rightSideTable.add(getDemandsTable(currentPlayerCiv,otherCiv))
}
diplomacyTable.add(demandsButton).row()
diplomacyTable.add(getRelationshipTable(otherCivDiplomacyManager)).row()
@ -248,6 +256,8 @@ class DiplomacyScreen:CameraStageBaseScreen() {
DenouncedOurAllies -> "You have denounced our allies"
DenouncedOurEnemies -> "You have denounced our enemies"
BetrayedPromiseToNotSettleCitiesNearUs -> "You betrayed your promise to not settle cities near us"
RefusedToNotSettleCitiesNearUs -> "You refused to stop settling cities near us"
FulfilledPromiseToNotSettleCitiesNearUs -> "You fulfilled your promise to stop settling cities near us!"
}
text = text.tr() + " "
if (modifier.value > 0) text += "+"
@ -260,6 +270,23 @@ class DiplomacyScreen:CameraStageBaseScreen() {
return diplomacyTable
}
private fun getDemandsTable(currentPlayerCiv: CivilizationInfo, otherCiv: CivilizationInfo): Table {
val demandsTable = Table()
demandsTable.defaults().pad(10f)
val dontSettleCitiesButton = TextButton("Please don't settle new cities near us.".tr(),skin)
dontSettleCitiesButton.onClick {
val threatLevel = Automation().threatAssessment(otherCiv,currentPlayerCiv)
if(threatLevel>ThreatLevel.Medium){
setRightSideFlavorText(otherCiv,"Very well, we shall look for new lands to settle.","Excellent!")
otherCiv.getDiplomacyManager(currentPlayerCiv).setFlag(DiplomacyFlags.WeAgreedNotToSettleNearThem,100)
}
else setRightSideFlavorText(otherCiv,"We shall do as we please.","Very well.")
}
demandsTable.add(dontSettleCitiesButton).row()
demandsTable.add(TextButton("Close".tr(),skin).onClick { updateRightSide(otherCiv) })
return demandsTable
}
fun getRelationshipTable(otherCivDiplomacyManager: DiplomacyManager): Table {
val relationshipTable = Table()
@ -305,7 +332,7 @@ class DiplomacyScreen:CameraStageBaseScreen() {
diplomacyTable.addSeparator()
diplomacyTable.add(flavorText.toLabel()).row()
val responseButton = TextButton(response,skin)
val responseButton = TextButton(response.tr(),skin)
responseButton.onClick { updateRightSide(otherCiv) }
diplomacyTable.add(responseButton)

View File

@ -4,17 +4,24 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.unciv.logic.civilization.AlertType
import com.unciv.logic.civilization.PopupAlert
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
import com.unciv.logic.civilization.diplomacy.DiplomaticModifiers
import com.unciv.models.gamebasics.Nation
import com.unciv.models.gamebasics.tr
import com.unciv.ui.utils.addSeparator
import com.unciv.ui.utils.onClick
import com.unciv.ui.utils.toLabel
import com.unciv.ui.worldscreen.optionstable.PopupTable
import kotlin.random.Random
class AlertPopup(val worldScreen: WorldScreen, val popupAlert: PopupAlert): PopupTable(worldScreen){
fun getCloseButton(text:String): TextButton {
fun getCloseButton(text: String, action: (() -> Unit)?=null): TextButton {
val button = TextButton(text.tr(), skin)
button.onClick { close(); worldScreen.shouldUpdate=true }
button.onClick {
if(action!=null) action()
worldScreen.shouldUpdate=true
close()
}
return button
}
@ -47,7 +54,6 @@ class AlertPopup(val worldScreen: WorldScreen, val popupAlert: PopupAlert): Popu
val translatedNation = civ.getTranslatedNation()
if (civ.isCityState()) {
addLeaderName(translatedNation)
val cityStateType = civ.getCityStateType()
addGoodSizedLabel("We have encountered the City-State of [${translatedNation.getNameTranslation()}]!").row()
add(getCloseButton("Excellent!"))
} else {
@ -74,7 +80,26 @@ class AlertPopup(val worldScreen: WorldScreen, val popupAlert: PopupAlert): Popu
responseTable.add(getCloseButton("Never!"))
add(responseTable)
}
AlertType.CitySettledNearOtherCiv -> {
val otherciv= worldScreen.gameInfo.getCivilization(popupAlert.value)
val otherCivDiploManager = otherciv.getDiplomacyManager(worldScreen.currentPlayerCiv)
val translatedNation = otherciv.getTranslatedNation()
addLeaderName(translatedNation)
addGoodSizedLabel("Please don't settle new cities near us.").row()
add(getCloseButton("Very well, we shall look for new lands to settle."){
otherCivDiploManager.setFlag(DiplomacyFlags.AgreedToNotSettleNearUs,100+ Random.nextInt(-20,20))
}).row()
add(getCloseButton("We shall do as we please.") {
otherCivDiploManager.addModifier(DiplomaticModifiers.RefusedToNotSettleCitiesNearUs,-10f)
}).row()
}
AlertType.CitySettledNearOtherCivDespiteOurPromise -> {
val otherciv= worldScreen.gameInfo.getCivilization(popupAlert.value)
val translatedNation = otherciv.getTranslatedNation()
addLeaderName(translatedNation)
addGoodSizedLabel("We noticed your new city near our borders, despite your promise. This will have....implications.").row()
add(getCloseButton("Very well."))
}
}
open()
isOpen = true