Improvements in science display (#8990)

* Displaying science overflow

* The amount of science from research agreement notification

* Check tech progress at the start of a turn

* Fixed exception

* Better remainingScienceToTech calculation

* Multiple technologies can be researched in one turn

* Small improvements
This commit is contained in:
Gualdimar
2023-03-22 21:59:35 +02:00
committed by GitHub
parent 5da7592616
commit 51f37af1a2
4 changed files with 54 additions and 18 deletions

View File

@ -788,6 +788,7 @@ You need to restart the game for this change to take effect. =
# Notifications # Notifications
Research of [technologyName] has completed! = Research of [technologyName] has completed! =
We gained [amount] Science from Research Agreement =
[construction] has become obsolete and was removed from the queue in [cityName]! = [construction] has become obsolete and was removed from the queue in [cityName]! =
[construction] has become obsolete and was removed from the queue in [amount] cities! = [construction] has become obsolete and was removed from the queue in [amount] cities! =
[cityName] changed production from [oldUnit] to [newUnit] = [cityName] changed production from [oldUnit] to [newUnit] =

View File

@ -90,6 +90,19 @@ class TechManager : IsPartOfGameInfoSerialization {
fun getNumberOfTechsResearched(): Int = techsResearched.size fun getNumberOfTechsResearched(): Int = techsResearched.size
fun getOverflowScience(techName: String): Int {
return if (overflowScience == 0) 0
else (getScienceModifier(techName) * overflowScience).toInt()
}
private fun getScienceModifier(techName: String): Float { // https://forums.civfanatics.com/threads/the-mechanics-of-overflow-inflation.517970/
val techsResearchedKnownCivs = civInfo.getKnownCivs()
.count { it.isMajorCiv() && it.tech.isResearched(techName) }
val undefeatedCivs = civInfo.gameInfo.civilizations
.count { it.isMajorCiv() && !it.isDefeated() }
return 1 + techsResearchedKnownCivs / undefeatedCivs.toFloat() * 0.3f
}
private fun getRuleset() = civInfo.gameInfo.ruleset private fun getRuleset() = civInfo.gameInfo.ruleset
fun costOfTech(techName: String): Int { fun costOfTech(techName: String): Int {
@ -97,12 +110,7 @@ class TechManager : IsPartOfGameInfoSerialization {
if (civInfo.isHuman()) if (civInfo.isHuman())
techCost *= civInfo.getDifficulty().researchCostModifier techCost *= civInfo.getDifficulty().researchCostModifier
techCost *= civInfo.gameInfo.speed.scienceCostModifier techCost *= civInfo.gameInfo.speed.scienceCostModifier
val techsResearchedKnownCivs = civInfo.getKnownCivs() techCost /= getScienceModifier(techName)
.count { it.isMajorCiv() && it.tech.isResearched(techName) }
val undefeatedCivs = civInfo.gameInfo.civilizations
.count { it.isMajorCiv() && !it.isDefeated() }
// https://forums.civfanatics.com/threads/the-mechanics-of-overflow-inflation.517970/
techCost /= 1 + techsResearchedKnownCivs / undefeatedCivs.toFloat() * 0.3f
// https://civilization.fandom.com/wiki/Map_(Civ5) // https://civilization.fandom.com/wiki/Map_(Civ5)
val worldSizeModifier = with (civInfo.gameInfo.tileMap.mapParameters.mapSize) { val worldSizeModifier = with (civInfo.gameInfo.tileMap.mapParameters.mapSize) {
when { when {
@ -129,11 +137,18 @@ class TechManager : IsPartOfGameInfoSerialization {
fun researchOfTech(TechName: String?) = techsInProgress[TechName] ?: 0 fun researchOfTech(TechName: String?) = techsInProgress[TechName] ?: 0
// Was once duplicated as fun scienceSpentOnTech(tech: String): Int // Was once duplicated as fun scienceSpentOnTech(tech: String): Int
fun remainingScienceToTech(techName: String) = costOfTech(techName) - researchOfTech(techName) fun remainingScienceToTech(techName: String): Int {
val spareScience = if (canBeResearched(techName)) getOverflowScience(techName) else 0
return costOfTech(techName) - researchOfTech(techName) - spareScience
}
fun turnsToTech(techName: String) = when { fun turnsToTech(techName: String): String {
val remainingCost = remainingScienceToTech(techName).toDouble()
return when {
remainingCost <= 0f -> "0"
civInfo.stats.statsForNextTurn.science <= 0f -> "" civInfo.stats.statsForNextTurn.science <= 0f -> ""
else -> max(1, ceil(remainingScienceToTech(techName).toDouble() / civInfo.stats.statsForNextTurn.science).toInt()).toString() else -> max(1, ceil(remainingCost / civInfo.stats.statsForNextTurn.science).toInt()).toString()
}
} }
fun isResearched(techName: String): Boolean = techsResearched.contains(techName) fun isResearched(techName: String): Boolean = techsResearched.contains(techName)
@ -213,15 +228,15 @@ class TechManager : IsPartOfGameInfoSerialization {
var finalScienceToAdd = scienceForNewTurn var finalScienceToAdd = scienceForNewTurn
if (scienceFromResearchAgreements != 0) { if (scienceFromResearchAgreements != 0) {
finalScienceToAdd += scienceFromResearchAgreements() val scienceBoost = scienceFromResearchAgreements()
finalScienceToAdd += scienceBoost
scienceFromResearchAgreements = 0 scienceFromResearchAgreements = 0
civInfo.addNotification("We gained [$scienceBoost] Science from Research Agreement",
NotificationCategory.General,
NotificationIcon.Science)
} }
if (overflowScience != 0) { // https://forums.civfanatics.com/threads/the-mechanics-of-overflow-inflation.517970/ if (overflowScience != 0) {
val techsResearchedKnownCivs = civInfo.getKnownCivs() finalScienceToAdd += getOverflowScience(currentTechnologyName()!!)
.count { it.isMajorCiv() && it.tech.isResearched(currentTechnologyName()!!) }
val undefeatedCivs = civInfo.gameInfo.civilizations.count { it.isMajorCiv() && !it.isDefeated() }
val finalScienceFromOverflow = ((1 + techsResearchedKnownCivs / undefeatedCivs.toFloat() * 0.3f) * overflowScience).toInt()
finalScienceToAdd += finalScienceFromOverflow
overflowScience = 0 overflowScience = 0
} }
@ -241,6 +256,20 @@ class TechManager : IsPartOfGameInfoSerialization {
addTechnology(currentTechnology) addTechnology(currentTechnology)
} }
/**
* Checks whether the research on the current technology can be completed
* and, if so, completes the research.
*/
fun updateResearchProgress() {
val currentTechnology = currentTechnologyName() ?: return
val realOverflow = getOverflowScience(currentTechnology)
val scienceSpent = researchOfTech(currentTechnology) + realOverflow
if (scienceSpent >= costOfTech(currentTechnology)) {
overflowScience = 0
addScience(realOverflow)
}
}
fun getFreeTechnology(techName: String) { fun getFreeTechnology(techName: String) {
freeTechs-- freeTechs--
addTechnology(techName) addTechnology(techName)
@ -301,6 +330,7 @@ class TechManager : IsPartOfGameInfoSerialization {
} }
moveToNewEra() moveToNewEra()
updateResearchProgress()
} }
private fun obsoleteOldUnits(techName: String) { private fun obsoleteOldUnits(techName: String) {

View File

@ -30,6 +30,9 @@ class TurnManager(val civInfo: Civilization) {
civInfo.statsHistory.recordRankingStats(civInfo) civInfo.statsHistory.recordRankingStats(civInfo)
} }
if (civInfo.cities.isNotEmpty() && civInfo.gameInfo.ruleset.technologies.isNotEmpty())
civInfo.tech.updateResearchProgress()
civInfo.civConstructions.startTurn() civInfo.civConstructions.startTurn()
civInfo.attacksSinceTurnStart.clear() civInfo.attacksSinceTurnStart.clear()
civInfo.updateStatsForNextTurn() // for things that change when turn passes e.g. golden age, city state influence civInfo.updateStatsForNextTurn() // for things that change when turn passes e.g. golden age, city state influence

View File

@ -115,6 +115,8 @@ class TechPickerScreen(
} }
else civTech.techsToResearch = tempTechsToResearch else civTech.techsToResearch = tempTechsToResearch
civTech.updateResearchProgress()
game.settings.addCompletedTutorialTask("Pick technology") game.settings.addCompletedTutorialTask("Pick technology")
game.popScreen() game.popScreen()
@ -424,7 +426,7 @@ class TechPickerScreen(
} }
private fun getTechProgressLabel(techs: List<String>): String { private fun getTechProgressLabel(techs: List<String>): String {
val progress = techs.sumOf { tech -> civTech.researchOfTech(tech) } val progress = techs.sumOf { tech -> civTech.researchOfTech(tech) } + civTech.getOverflowScience(techs.first())
val techCost = techs.sumOf { tech -> civInfo.tech.costOfTech(tech) } val techCost = techs.sumOf { tech -> civInfo.tech.costOfTech(tech) }
return "(${progress}/${techCost})" return "(${progress}/${techCost})"
} }