Fixed crash with diplomacy screen and city-states with no cities

This commit is contained in:
yairm210 2021-08-11 19:53:21 +03:00
parent ca54fac555
commit 7c1c585801
3 changed files with 151 additions and 78 deletions

View File

@ -161,13 +161,14 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
val luxuriesProvidedByCityStates =
civInfo.getKnownCivs().asSequence()
.filter { it.isCityState() && it.getAllyCiv() == civInfo.civName }
.map { it.getCivResources().map { res -> res.resource } }
.flatten().distinct().count { it.resourceType === ResourceType.Luxury }
.flatMap { it.getCivResources().map { res -> res.resource } }
.distinct().count { it.resourceType === ResourceType.Luxury }
statMap["City-State Luxuries"] = happinessBonusForCityStateProvidedLuxuries * luxuriesProvidedByCityStates * happinessPerUniqueLuxury
val luxuriesAllOfWhichAreTradedAway = civInfo.detailedCivResources
.filter { it.amount < 0 && it.resource.resourceType == ResourceType.Luxury && (it.origin == "Trade" || it.origin == "Trade request")}
.filter { it.amount < 0 && it.resource.resourceType == ResourceType.Luxury
&& (it.origin == "Trade" || it.origin == "Trade request")}
.map { it.resource }
.filter { !ownedLuxuries.contains(it) }

View File

@ -371,10 +371,7 @@ class CivilizationInfo {
otherCiv.addNotification(meetString, cityStateLocation, NotificationIcon.Gold)
else
otherCiv.addNotification(meetString, NotificationIcon.Gold)
for (stat in giftAmount.toHashMap().filter { it.value != 0f })
otherCiv.addStat(stat.key, stat.value.toInt())
otherCiv.addStats(giftAmount)
}
fun discoverNaturalWonder(naturalWonderName: String) {

View File

@ -32,7 +32,7 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
private val leftSideTable = Table().apply { defaults().pad(10f) }
private val rightSideTable = Table()
private fun isNotPlayersTurn() = !UncivGame.Current.worldScreen.isPlayersTurn
init {
@ -52,14 +52,19 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
closeButton.labelCell.pad(10f)
closeButton.pack()
closeButton.y = stage.height - closeButton.height - 10
closeButton.x = (stage.width * 0.2f - closeButton.width) / 2 // center, leftSideTable.width not known yet
closeButton.x =
(stage.width * 0.2f - closeButton.width) / 2 // center, leftSideTable.width not known yet
stage.addActor(closeButton) // This must come after the split pane so it will be above, that the button will be clickable
}
private fun updateLeftSideTable() {
leftSideTable.clear()
for (civ in viewingCiv.gameInfo.civilizations
.filterNot { it.isDefeated() || it == viewingCiv || it.isBarbarian() || it.isSpectator() || !viewingCiv.knows(it) }) {
.filterNot {
it.isDefeated() || it == viewingCiv || it.isBarbarian() || it.isSpectator() || !viewingCiv.knows(
it
)
}) {
val civIndicator = ImageGetter.getNationIndicator(civ.nation, 100f)
@ -70,7 +75,8 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
civIndicator.addActor(relationship)
if (civ.isCityState() && civ.questManager.haveQuestsFor(viewingCiv)) {
val questIcon = ImageGetter.getImage("OtherIcons/Quest").surroundWithCircle(size = 30f, color = Color.GOLDENROD)
val questIcon = ImageGetter.getImage("OtherIcons/Quest")
.surroundWithCircle(size = 30f, color = Color.GOLDENROD)
civIndicator.addActor(questIcon)
questIcon.x = floor(civIndicator.width - questIcon.width)
}
@ -83,8 +89,11 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
fun updateRightSide(otherCiv: CivilizationInfo) {
rightSideTable.clear()
if (otherCiv.isCityState()) rightSideTable.add(ScrollPane(getCityStateDiplomacyTable(otherCiv)))
else rightSideTable.add(ScrollPane(getMajorCivDiplomacyTable(otherCiv))).height(stage.height)
if (otherCiv.isCityState()) rightSideTable.add(
ScrollPane(getCityStateDiplomacyTable(otherCiv))
)
else rightSideTable.add(ScrollPane(getMajorCivDiplomacyTable(otherCiv)))
.height(stage.height)
}
fun setTrade(civ: CivilizationInfo): TradeTable {
@ -118,8 +127,11 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
wrapper.add(supplyList.amount.toLabel())
resourcesTable.add(wrapper).padRight(20f)
wrapper.addTooltip(name, 18f)
wrapper.onClick {
val pedia = CivilopediaScreen(UncivGame.Current.gameInfo.ruleSet, link = "Resource/$name")
wrapper.onClick {
val pedia = CivilopediaScreen(
UncivGame.Current.gameInfo.ruleSet,
link = "Resource/$name"
)
UncivGame.Current.setScreen(pedia)
}
}
@ -162,14 +174,15 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
friendBonusLabelColor = Color.GREEN
// RelationshipChange = Ally -> Friend or Friend -> Favorable
val turnsToRelationshipChange = otherCivDiplomacyManager.getTurnsToRelationshipChange()
diplomacyTable.add("Relationship changes in another [$turnsToRelationshipChange] turns".toLabel()).row()
diplomacyTable.add("Relationship changes in another [$turnsToRelationshipChange] turns".toLabel())
.row()
} else
friendBonusLabelColor = Color.GRAY
val friendBonusLabel = friendBonusText.toLabel(friendBonusLabelColor)
.apply { setAlignment(Align.center) }
diplomacyTable.add(friendBonusLabel).row()
return diplomacyTable
}
@ -188,29 +201,10 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
diplomacyTable.add(giveGiftButton).row()
if (isNotPlayersTurn()) giveGiftButton.disable()
val improvableTiles = otherCiv.getCapital().getImprovableTiles().filterNot {it.getTileResource().resourceType == ResourceType.Bonus}.toList()
val improvements = otherCiv.gameInfo.ruleSet.tileImprovements.filter { it.value.turnsToBuild != 0 }
var needsImprovements = false
val improveTileButton = getImproveTilesButton(otherCiv, otherCivDiplomacyManager)
if (improveTileButton != null) diplomacyTable.add(improveTileButton).row()
for (improvableTile in improvableTiles)
for (tileImprovement in improvements.values)
if (improvableTile.canBuildImprovement(tileImprovement, otherCiv) && improvableTile.getTileResource().improvement == tileImprovement.name)
needsImprovements = true
val improveTileButton = "Gift Improvement".toTextButton()
improveTileButton.onClick {
rightSideTable.clear()
rightSideTable.add(ScrollPane(getImprovementGiftTable(otherCiv)))
}
if (isNotPlayersTurn() || otherCivDiplomacyManager.influence < 60 || !needsImprovements)
improveTileButton.disable()
diplomacyTable.add(improveTileButton).row()
if (otherCivDiplomacyManager.diplomaticStatus == DiplomaticStatus.Protector){
if (otherCivDiplomacyManager.diplomaticStatus == DiplomaticStatus.Protector) {
val revokeProtectionButton = "Revoke Protection".toTextButton()
revokeProtectionButton.onClick {
YesNoPopup("Revoke protection for [${otherCiv.civName}]?", {
@ -230,7 +224,7 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
updateRightSide(otherCiv)
}, this).open()
}
if(viewingCiv.isAtWarWith(otherCiv)) {
if (viewingCiv.isAtWarWith(otherCiv)) {
protectionButton.disable()
}
diplomacyTable.add(protectionButton).row()
@ -244,8 +238,18 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
peaceButton.onClick {
YesNoPopup("Peace with [${otherCiv.civName}]?", {
val tradeLogic = TradeLogic(viewingCiv, otherCiv)
tradeLogic.currentTrade.ourOffers.add(TradeOffer(Constants.peaceTreaty, TradeType.Treaty))
tradeLogic.currentTrade.theirOffers.add(TradeOffer(Constants.peaceTreaty, TradeType.Treaty))
tradeLogic.currentTrade.ourOffers.add(
TradeOffer(
Constants.peaceTreaty,
TradeType.Treaty
)
)
tradeLogic.currentTrade.theirOffers.add(
TradeOffer(
Constants.peaceTreaty,
TradeType.Treaty
)
)
tradeLogic.acceptTrade()
updateLeftSideTable()
updateRightSide(otherCiv)
@ -253,7 +257,8 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
}
diplomacyTable.add(peaceButton).row()
val cityStatesAlly = otherCiv.getAllyCiv()
val atWarWithItsAlly = viewingCiv.getKnownCivs().any { it.civName == cityStatesAlly && it.isAtWarWith(viewingCiv) }
val atWarWithItsAlly = viewingCiv.getKnownCivs()
.any { it.civName == cityStatesAlly && it.isAtWarWith(viewingCiv) }
if (isNotPlayersTurn() || atWarWithItsAlly) peaceButton.disable()
} else {
val declareWarButton = getDeclareWarButton(diplomacyManager, otherCiv)
@ -269,14 +274,50 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
return diplomacyTable
}
private fun getImproveTilesButton(
otherCiv: CivilizationInfo,
otherCivDiplomacyManager: DiplomacyManager
): TextButton? {
if (otherCiv.cities.isEmpty()) return null
val improvableTiles = otherCiv.getCapital().getImprovableTiles()
.filterNot { it.getTileResource().resourceType == ResourceType.Bonus }.toList()
val improvements =
otherCiv.gameInfo.ruleSet.tileImprovements.filter { it.value.turnsToBuild != 0 }
var needsImprovements = false
for (improvableTile in improvableTiles)
for (tileImprovement in improvements.values)
if (improvableTile.canBuildImprovement(
tileImprovement,
otherCiv
) && improvableTile.getTileResource().improvement == tileImprovement.name
)
needsImprovements = true
if (!needsImprovements) return null
val improveTileButton = "Gift Improvement".toTextButton()
improveTileButton.onClick {
rightSideTable.clear()
rightSideTable.add(ScrollPane(getImprovementGiftTable(otherCiv)))
}
if (isNotPlayersTurn() || otherCivDiplomacyManager.influence < 60 || !needsImprovements)
improveTileButton.disable()
return improveTileButton
}
private fun getGoldGiftTable(otherCiv: CivilizationInfo): Table {
val diplomacyTable = getCityStateDiplomacyTableHeader(otherCiv)
diplomacyTable.addSeparator()
for (giftAmount in listOf(250, 500, 1000)) {
val influenceAmount = viewingCiv.influenceGainedByGift(giftAmount)
val giftButton = "Gift [$giftAmount] gold (+[$influenceAmount] influence)".toTextButton()
val giftButton =
"Gift [$giftAmount] gold (+[$influenceAmount] influence)".toTextButton()
giftButton.onClick {
viewingCiv.giveGoldGift(otherCiv, giftAmount)
updateRightSide(otherCiv)
@ -284,7 +325,7 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
diplomacyTable.add(giftButton).row()
if (viewingCiv.gold < giftAmount || isNotPlayersTurn()) giftButton.disable()
}
val backButton = "Back".toTextButton()
backButton.onClick {
rightSideTable.clear()
@ -293,19 +334,23 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
diplomacyTable.add(backButton)
return diplomacyTable
}
private fun getImprovementGiftTable(otherCiv: CivilizationInfo): Table{
private fun getImprovementGiftTable(otherCiv: CivilizationInfo): Table {
val improvementGiftTable = getCityStateDiplomacyTableHeader(otherCiv)
improvementGiftTable.addSeparator()
val improvableTiles = otherCiv.getCapital().getImprovableTiles()
.filterNot { it.getTileResource().resourceType == ResourceType.Bonus }.toList()
val tileImprovements = otherCiv.gameInfo.ruleSet.tileImprovements.filter { it.value.turnsToBuild != 0 }
val tileImprovements =
otherCiv.gameInfo.ruleSet.tileImprovements.filter { it.value.turnsToBuild != 0 }
for (improvableTile in improvableTiles){
for (tileImprovement in tileImprovements.values){
for (improvableTile in improvableTiles) {
for (tileImprovement in tileImprovements.values) {
if (improvableTile.canBuildImprovement(tileImprovement, otherCiv) &&
improvableTile.getTileResource().improvement == tileImprovement.name) {
val improveTileButton = "Build [${tileImprovement}] on [${improvableTile.getTileResource()}] (200 Gold)".toTextButton()
improvableTile.getTileResource().improvement == tileImprovement.name
) {
val improveTileButton =
"Build [${tileImprovement}] on [${improvableTile.getTileResource()}] (200 Gold)".toTextButton()
improveTileButton.onClick {
viewingCiv.addGold(-200)
improvableTile.stopWorkingOnImprovement()
@ -342,7 +387,7 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
questTable.add(title.toLabel(fontSize = 24)).row()
questTable.add(description.toLabel().apply { wrap = true; setAlignment(Align.center) })
.width(stage.width / 2).row()
.width(stage.width / 2).row()
if (quest.duration > 0)
questTable.add("[${remainingTurns}] turns remaining".toLabel()).row()
@ -359,13 +404,14 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
diplomacyTable.defaults().pad(10f)
val helloText = if (otherCivDiplomacyManager.relationshipLevel() <= RelationshipLevel.Enemy)
otherCiv.nation.hateHello
else otherCiv.nation.neutralHello
otherCiv.nation.hateHello
else otherCiv.nation.neutralHello
val leaderIntroTable = LeaderIntroTable(otherCiv, helloText)
diplomacyTable.add(leaderIntroTable).row()
diplomacyTable.addSeparator()
val diplomaticRelationshipsCanChange = !viewingCiv.gameInfo.ruleSet.modOptions.uniques.contains(ModOptionsConstants.diplomaticRelationshipsCannotChange)
val diplomaticRelationshipsCanChange =
!viewingCiv.gameInfo.ruleSet.modOptions.uniques.contains(ModOptionsConstants.diplomaticRelationshipsCannotChange)
if (!viewingCiv.isAtWarWith(otherCiv)) {
val tradeButton = "Trade".toTextButton()
@ -402,14 +448,21 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
if (!viewingCiv.isAtWarWith(otherCiv)) {
if (!diplomacyManager.hasFlag(DiplomacyFlags.DeclarationOfFriendship)) {
val declareFriendshipButton = "Offer Declaration of Friendship ([30] turns)".toTextButton()
val declareFriendshipButton =
"Offer Declaration of Friendship ([30] turns)".toTextButton()
declareFriendshipButton.onClick {
otherCiv.popupAlerts.add(PopupAlert(AlertType.DeclarationOfFriendship, viewingCiv.civName))
otherCiv.popupAlerts.add(
PopupAlert(
AlertType.DeclarationOfFriendship,
viewingCiv.civName
)
)
declareFriendshipButton.disable()
}
diplomacyTable.add(declareFriendshipButton).row()
if (isNotPlayersTurn() || otherCiv.popupAlerts
.any { it.type == AlertType.DeclarationOfFriendship && it.value == viewingCiv.civName })
.any { it.type == AlertType.DeclarationOfFriendship && it.value == viewingCiv.civName }
)
declareFriendshipButton.disable()
}
@ -420,8 +473,10 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
val requiredGold = viewingCiv.getResearchAgreementCost()
researchAgreementButton.onClick {
val tradeTable = setTrade(otherCiv)
val researchAgreement = TradeOffer(Constants.researchAgreement, TradeType.Treaty, requiredGold)
val goldCostOfSignResearchAgreement = TradeOffer("Gold".tr(), TradeType.Gold, -requiredGold)
val researchAgreement =
TradeOffer(Constants.researchAgreement, TradeType.Treaty, requiredGold)
val goldCostOfSignResearchAgreement =
TradeOffer("Gold".tr(), TradeType.Gold, -requiredGold)
tradeTable.tradeLogic.currentTrade.theirOffers.add(researchAgreement)
tradeTable.tradeLogic.ourAvailableOffers.add(researchAgreement)
tradeTable.tradeLogic.ourAvailableOffers.add(goldCostOfSignResearchAgreement)
@ -436,7 +491,8 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
}
if (!diplomacyManager.hasFlag(DiplomacyFlags.Denunceation)
&& !diplomacyManager.hasFlag(DiplomacyFlags.DeclarationOfFriendship)) {
&& !diplomacyManager.hasFlag(DiplomacyFlags.DeclarationOfFriendship)
) {
val denounceButton = "Denounce ([30] turns)".toTextButton()
denounceButton.onClick {
YesNoPopup("Denounce [${otherCiv.civName}]?", {
@ -473,17 +529,22 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
return diplomacyTable
}
private fun getPromisesTable(diplomacyManager: DiplomacyManager, otherCivDiplomacyManager: DiplomacyManager): Table? {
private fun getPromisesTable(
diplomacyManager: DiplomacyManager,
otherCivDiplomacyManager: DiplomacyManager
): Table? {
val promisesTable = Table()
// Not for (flag in DiplomacyFlags.values()) - all other flags should result in DiplomaticModifiers or stay internal?
val flag = DiplomacyFlags.AgreedToNotSettleNearUs
if (otherCivDiplomacyManager.hasFlag(flag)) {
val text = "We promised not to settle near them ([${otherCivDiplomacyManager.getFlag(flag)}] turns remaining)"
val text =
"We promised not to settle near them ([${otherCivDiplomacyManager.getFlag(flag)}] turns remaining)"
promisesTable.add(text.toLabel(Color.LIGHT_GRAY)).row()
}
if (diplomacyManager.hasFlag(flag)) {
val text = "They promised not to settle near us ([${diplomacyManager.getFlag(flag)}] turns remaining)"
val text =
"They promised not to settle near us ([${diplomacyManager.getFlag(flag)}] turns remaining)"
promisesTable.add(text.toLabel(Color.LIGHT_GRAY)).row()
}
@ -533,7 +594,12 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
if (otherCiv.popupAlerts.any { it.type == AlertType.DemandToStopSettlingCitiesNear && it.value == viewingCiv.civName })
dontSettleCitiesButton.disable()
dontSettleCitiesButton.onClick {
otherCiv.popupAlerts.add(PopupAlert(AlertType.DemandToStopSettlingCitiesNear, viewingCiv.civName))
otherCiv.popupAlerts.add(
PopupAlert(
AlertType.DemandToStopSettlingCitiesNear,
viewingCiv.civName
)
)
dontSettleCitiesButton.disable()
}
demandsTable.add(dontSettleCitiesButton).row()
@ -545,8 +611,9 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
private fun getRelationshipTable(otherCivDiplomacyManager: DiplomacyManager): Table {
val relationshipTable = Table()
val opinionOfUs = if (otherCivDiplomacyManager.civInfo.isCityState()) otherCivDiplomacyManager.influence.toInt()
else otherCivDiplomacyManager.opinionOfOtherCiv().toInt()
val opinionOfUs =
if (otherCivDiplomacyManager.civInfo.isCityState()) otherCivDiplomacyManager.influence.toInt()
else otherCivDiplomacyManager.opinionOfOtherCiv().toInt()
relationshipTable.add("{Our relationship}: ".toLabel())
val relationshipLevel = otherCivDiplomacyManager.relationshipLevel()
@ -561,15 +628,19 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
relationshipTable.add(relationshipText.toLabel(relationshipColor)).row()
if (otherCivDiplomacyManager.civInfo.isCityState())
relationshipTable.add(
CityButton.getInfluenceBar(
otherCivDiplomacyManager.influence,
otherCivDiplomacyManager.relationshipLevel(),
200f, 10f)
CityButton.getInfluenceBar(
otherCivDiplomacyManager.influence,
otherCivDiplomacyManager.relationshipLevel(),
200f, 10f
)
).colspan(2).pad(5f)
return relationshipTable
}
private fun getDeclareWarButton(diplomacyManager: DiplomacyManager, otherCiv: CivilizationInfo): TextButton {
private fun getDeclareWarButton(
diplomacyManager: DiplomacyManager,
otherCiv: CivilizationInfo
): TextButton {
val declareWarButton = "Declare war".toTextButton()
declareWarButton.color = Color.RED
val turnsToPeaceTreaty = diplomacyManager.turnsToPeaceTreaty()
@ -589,7 +660,11 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
// response currently always gets "Very Well.", but that may expand in the future.
@Suppress("SameParameterValue")
private fun setRightSideFlavorText(otherCiv: CivilizationInfo, flavorText: String, response: String) {
private fun setRightSideFlavorText(
otherCiv: CivilizationInfo,
flavorText: String,
response: String
) {
val diplomacyTable = Table()
diplomacyTable.defaults().pad(10f)
diplomacyTable.add(LeaderIntroTable(otherCiv))
@ -598,8 +673,8 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
val responseButton = response.toTextButton()
val action = {
keyPressDispatcher.remove(KeyCharAndCode.SPACE)
updateRightSide(otherCiv)
keyPressDispatcher.remove(KeyCharAndCode.SPACE)
updateRightSide(otherCiv)
}
responseButton.onClick(action)
keyPressDispatcher[KeyCharAndCode.SPACE] = action
@ -609,4 +684,4 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
rightSideTable.add(diplomacyTable)
}
}
}