mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-28 06:16:37 -04:00
City states give gold when met; updates to city state gold gifts (#4435)
* City States now give gold when met * City States can now receive different amounts of gold, and the amount of influence gained from gifts follows the base game * Implemented requested changes * Fixed tests
This commit is contained in:
parent
5925489c0b
commit
253e62de72
@ -137,6 +137,7 @@ Provides [amountOfCulture] culture at 30 Influence =
|
|||||||
Provides 3 food in capital and 1 food in other cities at 30 Influence =
|
Provides 3 food in capital and 1 food in other cities at 30 Influence =
|
||||||
Provides 3 happiness at 30 Influence =
|
Provides 3 happiness at 30 Influence =
|
||||||
Provides land units every 20 turns at 30 Influence =
|
Provides land units every 20 turns at 30 Influence =
|
||||||
|
Give a Gift =
|
||||||
Gift [giftAmount] gold (+[influenceAmount] influence) =
|
Gift [giftAmount] gold (+[influenceAmount] influence) =
|
||||||
Relationship changes in another [turnsToRelationshipChange] turns =
|
Relationship changes in another [turnsToRelationshipChange] turns =
|
||||||
Protected by =
|
Protected by =
|
||||||
@ -407,6 +408,8 @@ You have entered a Golden Age! =
|
|||||||
[n] sources of [resourceName] revealed, e.g. near [cityName] =
|
[n] sources of [resourceName] revealed, e.g. near [cityName] =
|
||||||
A [greatPerson] has been born in [cityName]! =
|
A [greatPerson] has been born in [cityName]! =
|
||||||
We have encountered [civName]! =
|
We have encountered [civName]! =
|
||||||
|
[cityStateName] has given us [stats] as a token of goodwill for meeting us =
|
||||||
|
[cityStateName] has given us [stats] as we are the first major civ to meet them =
|
||||||
Cannot provide unit upkeep for [unitName] - unit has been disbanded! =
|
Cannot provide unit upkeep for [unitName] - unit has been disbanded! =
|
||||||
[cityName] has grown! =
|
[cityName] has grown! =
|
||||||
[cityName] is starving! =
|
[cityName] is starving! =
|
||||||
|
@ -84,7 +84,7 @@ class CityInfoConquestFunctions(val city: CityInfo){
|
|||||||
// How can you conquer a city but not know the civ you conquered it from?!
|
// How can you conquer a city but not know the civ you conquered it from?!
|
||||||
// I don't know either, but some of our players have managed this, and crashed their game!
|
// I don't know either, but some of our players have managed this, and crashed their game!
|
||||||
if (!conqueringCiv.knows(oldCiv))
|
if (!conqueringCiv.knows(oldCiv))
|
||||||
conqueringCiv.meetCivilization(oldCiv)
|
conqueringCiv.makeCivilizationsMeet(oldCiv)
|
||||||
|
|
||||||
oldCiv.getDiplomacyManager(conqueringCiv)
|
oldCiv.getDiplomacyManager(conqueringCiv)
|
||||||
.addModifier(DiplomaticModifiers.CapturedOurCities, -aggroGenerated)
|
.addModifier(DiplomaticModifiers.CapturedOurCities, -aggroGenerated)
|
||||||
@ -145,7 +145,7 @@ class CityInfoConquestFunctions(val city: CityInfo){
|
|||||||
|
|
||||||
// In order to get "plus points" in Diplomacy, you have to establish diplomatic relations if you haven't yet
|
// In order to get "plus points" in Diplomacy, you have to establish diplomatic relations if you haven't yet
|
||||||
if (!conqueringCiv.knows(foundingCiv))
|
if (!conqueringCiv.knows(foundingCiv))
|
||||||
conqueringCiv.meetCivilization(foundingCiv)
|
conqueringCiv.makeCivilizationsMeet(foundingCiv)
|
||||||
|
|
||||||
if (foundingCiv.isMajorCiv()) {
|
if (foundingCiv.isMajorCiv()) {
|
||||||
foundingCiv.getDiplomacyManager(conqueringCiv)
|
foundingCiv.getDiplomacyManager(conqueringCiv)
|
||||||
|
@ -38,7 +38,7 @@ class CivInfoTransientUpdater(val civInfo: CivilizationInfo) {
|
|||||||
for (entry in viewedCivs) {
|
for (entry in viewedCivs) {
|
||||||
val metCiv = entry.key
|
val metCiv = entry.key
|
||||||
if (metCiv == civInfo || metCiv.isBarbarian() || civInfo.diplomacy.containsKey(metCiv.civName)) continue
|
if (metCiv == civInfo || metCiv.isBarbarian() || civInfo.diplomacy.containsKey(metCiv.civName)) continue
|
||||||
civInfo.meetCivilization(metCiv)
|
civInfo.makeCivilizationsMeet(metCiv)
|
||||||
civInfo.addNotification("We have encountered [" + metCiv.civName + "]!", entry.value.position, metCiv.civName, NotificationIcon.Diplomacy)
|
civInfo.addNotification("We have encountered [" + metCiv.civName + "]!", entry.value.position, metCiv.civName, NotificationIcon.Diplomacy)
|
||||||
metCiv.addNotification("We have encountered [" + civInfo.civName + "]!", entry.value.position, civInfo.civName, NotificationIcon.Diplomacy)
|
metCiv.addNotification("We have encountered [" + civInfo.civName + "]!", entry.value.position, civInfo.civName, NotificationIcon.Diplomacy)
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ import kotlin.collections.ArrayList
|
|||||||
import kotlin.collections.HashMap
|
import kotlin.collections.HashMap
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
import kotlin.math.pow
|
||||||
|
|
||||||
class CivilizationInfo {
|
class CivilizationInfo {
|
||||||
|
|
||||||
@ -328,18 +329,40 @@ class CivilizationInfo {
|
|||||||
return baseUnit
|
return baseUnit
|
||||||
}
|
}
|
||||||
|
|
||||||
fun meetCivilization(otherCiv: CivilizationInfo) {
|
fun makeCivilizationsMeet(otherCiv: CivilizationInfo) {
|
||||||
|
meetCiv(otherCiv)
|
||||||
|
otherCiv.meetCiv(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun meetCiv(otherCiv: CivilizationInfo) {
|
||||||
diplomacy[otherCiv.civName] = DiplomacyManager(this, otherCiv.civName)
|
diplomacy[otherCiv.civName] = DiplomacyManager(this, otherCiv.civName)
|
||||||
.apply { diplomaticStatus = DiplomaticStatus.Peace }
|
.apply { diplomaticStatus = DiplomaticStatus.Peace }
|
||||||
|
|
||||||
otherCiv.popupAlerts.add(PopupAlert(AlertType.FirstContact, civName))
|
otherCiv.popupAlerts.add(PopupAlert(AlertType.FirstContact, civName))
|
||||||
|
|
||||||
otherCiv.diplomacy[civName] = DiplomacyManager(otherCiv, civName)
|
if (isCurrentPlayer())
|
||||||
.apply { diplomaticStatus = DiplomaticStatus.Peace }
|
|
||||||
popupAlerts.add(PopupAlert(AlertType.FirstContact, otherCiv.civName))
|
|
||||||
|
|
||||||
if (isCurrentPlayer() || otherCiv.isCurrentPlayer())
|
|
||||||
UncivGame.Current.settings.addCompletedTutorialTask("Meet another civilization")
|
UncivGame.Current.settings.addCompletedTutorialTask("Meet another civilization")
|
||||||
|
|
||||||
|
if (!(isCityState() && otherCiv.isMajorCiv())) return
|
||||||
|
|
||||||
|
val cityStateLocation = if (cities.isEmpty()) null else getCapital().location
|
||||||
|
|
||||||
|
val giftAmount = Stats().add(Stat.Gold, 15f)
|
||||||
|
// Later, religious city-states will also gift gold, making this the better implementation
|
||||||
|
// For now, it might be overkill though.
|
||||||
|
var meetString = "[${civName}] has given us [${giftAmount}] as a token of goodwill for meeting us"
|
||||||
|
if (diplomacy.filter { it.value.otherCiv().isMajorCiv() }.count() == 1) {
|
||||||
|
giftAmount.timesInPlace(2f)
|
||||||
|
meetString = "[${civName}] has given us [${giftAmount}] as we are the first major civ to meet them"
|
||||||
|
}
|
||||||
|
if (cityStateLocation != null)
|
||||||
|
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())
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun discoverNaturalWonder(naturalWonderName: String) {
|
fun discoverNaturalWonder(naturalWonderName: String) {
|
||||||
@ -699,11 +722,32 @@ class CivilizationInfo {
|
|||||||
diplomacyManager.otherCiv().tradeRequests.remove(tradeRequest) // it would be really weird to get a trade request from a dead civ
|
diplomacyManager.otherCiv().tradeRequests.remove(tradeRequest) // it would be really weird to get a trade request from a dead civ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getResearchAgreementCost(): Int {
|
||||||
|
// https://forums.civfanatics.com/resources/research-agreements-bnw.25568/
|
||||||
|
val era = if (getEra() in gameInfo.ruleSet.eras) gameInfo.ruleSet.eras[getEra()]!! else Era()
|
||||||
|
return (era.researchAgreementCost * gameInfo.gameParameters.gameSpeed.modifier).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////// Functions specific to City State civilizations ////////////////////////
|
||||||
|
|
||||||
fun influenceGainedByGift(cityState: CivilizationInfo, giftAmount: Int): Int {
|
|
||||||
var influenceGained = giftAmount / 10f
|
fun influenceGainedByGift(giftAmount: Int): Int {
|
||||||
|
// https://github.com/Gedemon/Civ5-DLL/blob/aa29e80751f541ae04858b6d2a2c7dcca454201e/CvGameCoreDLL_Expansion1/CvMinorCivAI.cpp
|
||||||
|
// line 8681 and below
|
||||||
|
var influenceGained = giftAmount.toFloat().pow(1.01f) / 9.8f
|
||||||
|
val gameProgressApproximate = min(gameInfo.turns / (400f * gameInfo.gameParameters.gameSpeed.modifier), 1f)
|
||||||
|
influenceGained *= 1 - (2/3) * gameProgressApproximate
|
||||||
|
influenceGained *= when (gameInfo.gameParameters.gameSpeed) {
|
||||||
|
GameSpeed.Quick -> 1.25f
|
||||||
|
GameSpeed.Standard -> 1f
|
||||||
|
GameSpeed.Epic -> 0.75f
|
||||||
|
GameSpeed.Marathon -> 0.67f
|
||||||
|
}
|
||||||
for (unique in getMatchingUniques("Gifts of Gold to City-States generate []% more Influence"))
|
for (unique in getMatchingUniques("Gifts of Gold to City-States generate []% more Influence"))
|
||||||
influenceGained *= 1f + unique.params[0].toFloat() / 100f
|
influenceGained *= 1f + unique.params[0].toFloat() / 100f
|
||||||
|
influenceGained -= influenceGained % 5
|
||||||
|
if (influenceGained < 5f) influenceGained = 5f
|
||||||
return influenceGained.toInt()
|
return influenceGained.toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -711,17 +755,11 @@ class CivilizationInfo {
|
|||||||
if (!cityState.isCityState()) throw Exception("You can only gain influence with City-States!")
|
if (!cityState.isCityState()) throw Exception("You can only gain influence with City-States!")
|
||||||
addGold(-giftAmount)
|
addGold(-giftAmount)
|
||||||
cityState.addGold(giftAmount)
|
cityState.addGold(giftAmount)
|
||||||
cityState.getDiplomacyManager(this).influence += influenceGainedByGift(cityState, giftAmount)
|
cityState.getDiplomacyManager(this).influence += influenceGainedByGift(giftAmount)
|
||||||
cityState.updateAllyCivForCityState()
|
cityState.updateAllyCivForCityState()
|
||||||
updateStatsForNextTurn()
|
updateStatsForNextTurn()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getResearchAgreementCost(): Int {
|
|
||||||
// https://forums.civfanatics.com/resources/research-agreements-bnw.25568/
|
|
||||||
val era = if (getEra() in gameInfo.ruleSet.eras) gameInfo.ruleSet.eras[getEra()]!! else Era()
|
|
||||||
return (era.researchAgreementCost * gameInfo.gameParameters.gameSpeed.modifier).toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun gainMilitaryUnitFromCityState(otherCiv: CivilizationInfo) {
|
fun gainMilitaryUnitFromCityState(otherCiv: CivilizationInfo) {
|
||||||
val cities = NextTurnAutomation.getClosestCities(this, otherCiv)
|
val cities = NextTurnAutomation.getClosestCities(this, otherCiv)
|
||||||
val city = cities.city1
|
val city = cities.city1
|
||||||
|
@ -107,7 +107,7 @@ class TradeLogic(val ourCivilization:CivilizationInfo, val otherCivilization: Ci
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (offer.type == TradeType.Introduction)
|
if (offer.type == TradeType.Introduction)
|
||||||
to.meetCivilization(to.gameInfo.getCivilization(offer.name))
|
to.makeCivilizationsMeet(to.gameInfo.getCivilization(offer.name))
|
||||||
|
|
||||||
if (offer.type == TradeType.WarDeclaration) {
|
if (offer.type == TradeType.WarDeclaration) {
|
||||||
val nameOfCivToDeclareWarOn = offer.name
|
val nameOfCivToDeclareWarOn = offer.name
|
||||||
|
@ -29,7 +29,7 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
|
|||||||
|
|
||||||
private val leftSideTable = Table().apply { defaults().pad(10f) }
|
private val leftSideTable = Table().apply { defaults().pad(10f) }
|
||||||
private val rightSideTable = Table()
|
private val rightSideTable = Table()
|
||||||
|
|
||||||
private fun isNotPlayersTurn() = !UncivGame.Current.worldScreen.isPlayersTurn
|
private fun isNotPlayersTurn() = !UncivGame.Current.worldScreen.isPlayersTurn
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -92,8 +92,7 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
|
|||||||
return tradeTable
|
return tradeTable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getCityStateDiplomacyTableHeader(otherCiv: CivilizationInfo): Table {
|
||||||
private fun getCityStateDiplomacyTable(otherCiv: CivilizationInfo): Table {
|
|
||||||
val otherCivDiplomacyManager = otherCiv.getDiplomacyManager(viewingCiv)
|
val otherCivDiplomacyManager = otherCiv.getDiplomacyManager(viewingCiv)
|
||||||
|
|
||||||
val diplomacyTable = Table()
|
val diplomacyTable = Table()
|
||||||
@ -144,21 +143,26 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
|
|||||||
friendBonusLabelColor = Color.GRAY
|
friendBonusLabelColor = Color.GRAY
|
||||||
|
|
||||||
val friendBonusLabel = friendBonusText.toLabel(friendBonusLabelColor)
|
val friendBonusLabel = friendBonusText.toLabel(friendBonusLabelColor)
|
||||||
.apply { setAlignment(Align.center) }
|
.apply { setAlignment(Align.center) }
|
||||||
diplomacyTable.add(friendBonusLabel).row()
|
diplomacyTable.add(friendBonusLabel).row()
|
||||||
|
|
||||||
|
return diplomacyTable
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getCityStateDiplomacyTable(otherCiv: CivilizationInfo): Table {
|
||||||
|
val otherCivDiplomacyManager = otherCiv.getDiplomacyManager(viewingCiv)
|
||||||
|
|
||||||
|
val diplomacyTable = getCityStateDiplomacyTableHeader(otherCiv)
|
||||||
|
|
||||||
diplomacyTable.addSeparator()
|
diplomacyTable.addSeparator()
|
||||||
|
|
||||||
val giftAmount = 250
|
val giveGoldButton = "Give a Gift".toTextButton()
|
||||||
val influenceAmount = viewingCiv.influenceGainedByGift(otherCiv, giftAmount)
|
giveGoldButton.onClick {
|
||||||
val giftButton = "Gift [$giftAmount] gold (+[$influenceAmount] influence)".toTextButton()
|
rightSideTable.clear()
|
||||||
giftButton.onClick {
|
rightSideTable.add(ScrollPane(getGoldGiftTable(otherCiv)))
|
||||||
viewingCiv.giveGoldGift(otherCiv, giftAmount)
|
|
||||||
updateRightSide(otherCiv)
|
|
||||||
}
|
}
|
||||||
diplomacyTable.add(giftButton).row()
|
diplomacyTable.add(giveGoldButton).row()
|
||||||
if (viewingCiv.gold < giftAmount || isNotPlayersTurn()) giftButton.disable()
|
|
||||||
|
|
||||||
if (otherCivDiplomacyManager.diplomaticStatus == DiplomaticStatus.Protector){
|
if (otherCivDiplomacyManager.diplomaticStatus == DiplomaticStatus.Protector){
|
||||||
val revokeProtectionButton = "Revoke Protection".toTextButton()
|
val revokeProtectionButton = "Revoke Protection".toTextButton()
|
||||||
revokeProtectionButton.onClick {
|
revokeProtectionButton.onClick {
|
||||||
@ -216,6 +220,30 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
|
|||||||
|
|
||||||
return diplomacyTable
|
return diplomacyTable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
giftButton.onClick {
|
||||||
|
viewingCiv.giveGoldGift(otherCiv, giftAmount)
|
||||||
|
updateRightSide(otherCiv)
|
||||||
|
}
|
||||||
|
diplomacyTable.add(giftButton).row()
|
||||||
|
if (viewingCiv.gold < giftAmount || isNotPlayersTurn()) giftButton.disable()
|
||||||
|
}
|
||||||
|
|
||||||
|
val backButton = "Back".toTextButton()
|
||||||
|
backButton.onClick {
|
||||||
|
rightSideTable.clear()
|
||||||
|
rightSideTable.add(ScrollPane(getCityStateDiplomacyTable(otherCiv)))
|
||||||
|
}
|
||||||
|
diplomacyTable.add(backButton)
|
||||||
|
return diplomacyTable
|
||||||
|
}
|
||||||
|
|
||||||
private fun getQuestTable(assignedQuest: AssignedQuest): Table {
|
private fun getQuestTable(assignedQuest: AssignedQuest): Table {
|
||||||
val questTable = Table()
|
val questTable = Table()
|
||||||
|
@ -518,7 +518,7 @@ object UnitActions {
|
|||||||
val otherCiv = tile.getOwner()
|
val otherCiv = tile.getOwner()
|
||||||
if (otherCiv != null) {
|
if (otherCiv != null) {
|
||||||
// decrease relations for -10 pt/tile
|
// decrease relations for -10 pt/tile
|
||||||
if (!otherCiv.knows(unit.civInfo)) otherCiv.meetCivilization(unit.civInfo)
|
if (!otherCiv.knows(unit.civInfo)) otherCiv.makeCivilizationsMeet(unit.civInfo)
|
||||||
otherCiv.getDiplomacyManager(unit.civInfo).addModifier(DiplomaticModifiers.StealingTerritory, -10f)
|
otherCiv.getDiplomacyManager(unit.civInfo).addModifier(DiplomaticModifiers.StealingTerritory, -10f)
|
||||||
civsToNotify.add(otherCiv)
|
civsToNotify.add(otherCiv)
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package com.unciv.logic.civilization.diplomacy
|
|||||||
|
|
||||||
import com.unciv.logic.GameInfo
|
import com.unciv.logic.GameInfo
|
||||||
import com.unciv.logic.civilization.CivilizationInfo
|
import com.unciv.logic.civilization.CivilizationInfo
|
||||||
|
import com.unciv.models.ruleset.Nation
|
||||||
import com.unciv.testing.GdxTestRunner
|
import com.unciv.testing.GdxTestRunner
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
@ -23,11 +24,14 @@ class DiplomacyManagerTests {
|
|||||||
|
|
||||||
private fun meetByName(civilization: String, civilizationToMeet: String) {
|
private fun meetByName(civilization: String, civilizationToMeet: String) {
|
||||||
civilizations.getValue(civilization)
|
civilizations.getValue(civilization)
|
||||||
.meetCivilization(civilizations.getValue(civilizationToMeet))
|
.makeCivilizationsMeet(civilizations.getValue(civilizationToMeet))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setup() {
|
fun setup() {
|
||||||
|
// Add nations to test civilizations, as we need them to know that they are major civs
|
||||||
|
civilizations.values.forEach { it.nation = Nation() }
|
||||||
|
|
||||||
// Setup the GameInfo mock
|
// Setup the GameInfo mock
|
||||||
|
|
||||||
every { mockGameInfo.getCivilization(capture(slot)) } answers { civilizations.getValue(slot.captured) }
|
every { mockGameInfo.getCivilization(capture(slot)) } answers { civilizations.getValue(slot.captured) }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user