From 205f479ffe4613f6903be8e7a0715879f19d0448 Mon Sep 17 00:00:00 2001 From: Duan Tao Date: Tue, 1 Jun 2021 20:02:23 +0800 Subject: [PATCH] Declare & Revoke protection for city-state. (#3994) * Declare protection for city-state. * Text templates. * Better protector text for city-states. --- .../jsons/translations/template.properties | 4 +++ .../logic/automation/NextTurnAutomation.kt | 27 +++++++++++++-- .../logic/civilization/CivilizationInfo.kt | 24 ++++++++++++++ .../diplomacy/DiplomacyManager.kt | 11 +++++++ .../diplomacy/DiplomaticStatus.kt | 1 + .../src/com/unciv/ui/trade/DiplomacyScreen.kt | 33 ++++++++++++++++++- 6 files changed, 96 insertions(+), 4 deletions(-) diff --git a/android/assets/jsons/translations/template.properties b/android/assets/jsons/translations/template.properties index 55f83bbd61..26385de0e6 100644 --- a/android/assets/jsons/translations/template.properties +++ b/android/assets/jsons/translations/template.properties @@ -135,6 +135,10 @@ Provides 3 happiness at 30 Influence = Provides land units every 20 turns at 30 Influence = Gift [giftAmount] gold (+[influenceAmount] influence) = Relationship changes in another [turnsToRelationshipChange] turns = +Protected by = +Revoke Protection = +Pledge to protect = +Declare Protection of [cityStateName]? = Cultured = Maritime = diff --git a/core/src/com/unciv/logic/automation/NextTurnAutomation.kt b/core/src/com/unciv/logic/automation/NextTurnAutomation.kt index fa6b93f0e3..e58fad6401 100644 --- a/core/src/com/unciv/logic/automation/NextTurnAutomation.kt +++ b/core/src/com/unciv/logic/automation/NextTurnAutomation.kt @@ -45,6 +45,7 @@ object NextTurnAutomation { chooseTechToResearch(civInfo) automateCityBombardment(civInfo) useGold(civInfo) + protectCityStates(civInfo) automateUnits(civInfo) reassignWorkedTiles(civInfo) trainSettler(civInfo) @@ -140,6 +141,20 @@ object NextTurnAutomation { } } + private fun protectCityStates(civInfo: CivilizationInfo) { + for (state in civInfo.getKnownCivs().filter{!it.isDefeated() && it.isCityState()}) { + val diplomacyManager = state.getDiplomacyManager(civInfo.civName) + if(diplomacyManager.relationshipLevel() >= RelationshipLevel.Friend + && diplomacyManager.diplomaticStatus == DiplomaticStatus.Peace) + { + state.addProtectorCiv(civInfo) + } else if (diplomacyManager.relationshipLevel() < RelationshipLevel.Friend + && diplomacyManager.diplomaticStatus == DiplomaticStatus.Protector) { + state.removeProtectorCiv(civInfo) + } + } + } + private fun getFreeTechForCityStates(civInfo: CivilizationInfo) { // City-States automatically get all techs that at least half of the major civs know val researchableTechs = civInfo.gameInfo.ruleSet.technologies.keys @@ -346,9 +361,14 @@ object NextTurnAutomation { private fun motivationToAttack(civInfo: CivilizationInfo, otherCiv: CivilizationInfo): Int { val ourCombatStrength = Automation.evaluteCombatStrength(civInfo).toFloat() - val theirCombatStrength = Automation.evaluteCombatStrength(otherCiv) - if (theirCombatStrength > ourCombatStrength) return 0 + var theirCombatStrength = Automation.evaluteCombatStrength(otherCiv) + //for city-states, also consider there protectors + if(otherCiv.isCityState() and otherCiv.getProtectorCivs().isNotEmpty()) { + theirCombatStrength += otherCiv.getProtectorCivs().sumOf{Automation.evaluteCombatStrength(it)} + } + + if (theirCombatStrength > ourCombatStrength) return 0 fun isTileCanMoveThrough(tileInfo: TileInfo): Boolean { val owner = tileInfo.getOwner() @@ -410,7 +430,8 @@ object NextTurnAutomation { if (theirCity.getTiles().none { it.neighbors.any { it.getOwner() == theirCity.civInfo && it.getCity() != theirCity } }) modifierMap["Isolated city"] = 15 - if (otherCiv.isCityState()) modifierMap["City-state"] = -20 + //Maybe not needed if city-state has potential protectors? + if (otherCiv.isCityState()) modifierMap["City-state"] = -10 return modifierMap.values.sum() } diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index 6bbdbf1640..23031b4223 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -653,6 +653,30 @@ class CivilizationInfo { fun getAllyCiv() = allyCivName + fun getProtectorCivs() : List { + if(this.isMajorCiv()) return emptyList() + return diplomacy.values + .filter{!it.otherCiv().isDefeated() && it.diplomaticStatus == DiplomaticStatus.Protector} + .map{it->it.otherCiv()} + } + + fun addProtectorCiv(otherCiv: CivilizationInfo) { + if(!this.isCityState() or !otherCiv.isMajorCiv() or otherCiv.isDefeated()) return + if(!knows(otherCiv) or isAtWarWith(otherCiv)) return //Exception + + val diplomacy = getDiplomacyManager(otherCiv.civName) + diplomacy.diplomaticStatus = DiplomaticStatus.Protector + } + + fun removeProtectorCiv(otherCiv: CivilizationInfo) { + if(!this.isCityState() or !otherCiv.isMajorCiv() or otherCiv.isDefeated()) return + if(!knows(otherCiv) or isAtWarWith(otherCiv)) return //Exception + + val diplomacy = getDiplomacyManager(otherCiv.civName) + diplomacy.diplomaticStatus = DiplomaticStatus.Peace + diplomacy.influence -= 20 + } + fun updateAllyCivForCityState() { var newAllyName = "" if (!isCityState()) return diff --git a/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt b/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt index f688bd2b9b..9b69a917f7 100644 --- a/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt +++ b/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt @@ -182,6 +182,7 @@ class DiplomacyManager() { var restingPoint = 0f for (unique in otherCiv().getMatchingUniques("Resting point for Influence with City-States is increased by []")) restingPoint += unique.params[0].toInt() + if(diplomaticStatus == DiplomaticStatus.Protector) restingPoint += 5 return restingPoint } @@ -546,6 +547,16 @@ class DiplomacyManager() { } } } + + if (otherCiv.isCityState()) + { + for (thirdCiv in otherCiv.getProtectorCivs()) { + if (thirdCiv.knows(civInfo) + && thirdCiv.getDiplomacyManager(civInfo).canDeclareWar()) { + thirdCiv.getDiplomacyManager(civInfo).declareWar() + } + } + } } /** Should only be called from makePeace */ diff --git a/core/src/com/unciv/logic/civilization/diplomacy/DiplomaticStatus.kt b/core/src/com/unciv/logic/civilization/diplomacy/DiplomaticStatus.kt index 168f08ca34..2adc79db31 100644 --- a/core/src/com/unciv/logic/civilization/diplomacy/DiplomaticStatus.kt +++ b/core/src/com/unciv/logic/civilization/diplomacy/DiplomaticStatus.kt @@ -2,5 +2,6 @@ package com.unciv.logic.civilization.diplomacy enum class DiplomaticStatus{ Peace, + Protector, //city state's diplomacy for major civ can be marked as Protector, not vice versa. War } \ No newline at end of file diff --git a/core/src/com/unciv/ui/trade/DiplomacyScreen.kt b/core/src/com/unciv/ui/trade/DiplomacyScreen.kt index cdd51d8ead..2023288606 100644 --- a/core/src/com/unciv/ui/trade/DiplomacyScreen.kt +++ b/core/src/com/unciv/ui/trade/DiplomacyScreen.kt @@ -11,6 +11,7 @@ import com.unciv.logic.civilization.* import com.unciv.logic.civilization.diplomacy.DiplomacyFlags import com.unciv.logic.civilization.diplomacy.DiplomacyManager import com.unciv.logic.civilization.diplomacy.DiplomaticModifiers.* +import com.unciv.logic.civilization.diplomacy.DiplomaticStatus import com.unciv.logic.civilization.diplomacy.RelationshipLevel import com.unciv.logic.trade.TradeLogic import com.unciv.logic.trade.TradeOffer @@ -114,6 +115,12 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() { diplomacyTable.add(allyString.toLabel()).row() } + val protectors = otherCiv.getProtectorCivs() + if (protectors.size > 0) { + val protectorString = "{Protected by}: " + protectors.map{it.civName}.joinToString(", ") + diplomacyTable.add(protectorString.toLabel()).row() + } + val nextLevelString = when { otherCivDiplomacyManager.influence.toInt() < 30 -> "Reach 30 for friendship." ally == viewingCiv.civName -> "" @@ -156,8 +163,32 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() { diplomacyTable.add(giftButton).row() if (viewingCiv.gold < giftAmount || isNotPlayersTurn()) giftButton.disable() - val diplomacyManager = viewingCiv.getDiplomacyManager(otherCiv) + if (otherCivDiplomacyManager.diplomaticStatus == DiplomaticStatus.Protector){ + val RevokeProtectionButton = "Revoke Protection".toTextButton() + RevokeProtectionButton.onClick{ + YesNoPopup("Revoke protection for [${otherCiv.civName}]?".tr(), { + otherCiv.removeProtectorCiv(viewingCiv) + updateLeftSideTable() + updateRightSide(otherCiv) + }, this).open() + } + diplomacyTable.add(RevokeProtectionButton).row() + } else { + val ProtectionButton = "Pledge to protect".toTextButton() + ProtectionButton.onClick{ + YesNoPopup("Declare Protection of [${otherCiv.civName}]?".tr(), { + otherCiv.addProtectorCiv(viewingCiv) + updateLeftSideTable() + updateRightSide(otherCiv) + }, this).open() + } + if(viewingCiv.isAtWarWith(otherCiv)) { + ProtectionButton.disable() + } + diplomacyTable.add(ProtectionButton).row() + } + val diplomacyManager = viewingCiv.getDiplomacyManager(otherCiv) if (!viewingCiv.gameInfo.ruleSet.modOptions.uniques.contains(ModOptionsConstants.diplomaticRelationshipsCannotChange)) { if (viewingCiv.isAtWarWith(otherCiv)) { val peaceButton = "Negotiate Peace".toTextButton()