Updated the culture victory so it now requires the Utopia Project to be built (#4060)

* Added the Utopia Project for the culture victory; AI will now build it

* Forgot to credit the icon

* Fixed a few minor issues

* Improved code quality; added translatable notifications

* Fixed mistakes; improved quality

* Changed a label

* Revert a small change which is no longer necessary

* Reverted the revert of a small change which is no longer necessary

* Made requsted changes
This commit is contained in:
Xander Lenstra
2021-06-14 13:48:22 +02:00
committed by GitHub
parent 07a43f3f1a
commit 1c21573a42
13 changed files with 79 additions and 19 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -732,45 +732,52 @@ University
orig: 100, 100
offset: 0, 0
index: -1
Walls
Utopia Project
rotate: false
xy: 1430, 920
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Walls of Babylon
Walls
rotate: false
xy: 614, 2
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Wat
Walls of Babylon
rotate: false
xy: 716, 104
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Water Mill
Wat
rotate: false
xy: 818, 206
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Windmill
Water Mill
rotate: false
xy: 920, 308
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Workshop
Windmill
rotate: false
xy: 1022, 410
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Workshop
rotate: false
xy: 1124, 512
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 KiB

After

Width:  |  Height:  |  Size: 248 KiB

View File

@ -1046,4 +1046,14 @@
"requiredTech": "Nanotechnology",
"uniques": ["Spaceship part", "Triggers a global alert upon completion", "Cannot be purchased"]
}
// All Era's
{
"name": "Utopia Project",
"cost": 1500,
"isNationalWonder": true,
"uniques": ["Hidden until [5] social policy branches have been completed", "Triggers a global alert upon build start",
"Triggers a Cultural Victory upon completion", "Hidden when cultural victory is disabled"]
}
]

View File

@ -404,6 +404,9 @@ Cannot provide unit upkeep for [unitName] - unit has been disbanded! =
[wonder] has been built in a faraway land =
[civName] has completed [construction]! =
An unknown civilization has completed [construction]! =
The city of [cityname] has started constructing [construction]! =
[civilization] has started constructing [construction]! =
An unknown civilization has started constructing [construction]! =
Work has started on [construction] =
[cityName] cannot continue work on [construction] =
[cityName] has expanded its borders! =

View File

@ -12,6 +12,7 @@ import com.unciv.models.ruleset.Building
import com.unciv.models.ruleset.VictoryType
import com.unciv.models.stats.Stat
import kotlin.math.min
import kotlin.math.roundToInt
import kotlin.math.sqrt
class ConstructionAutomation(val cityConstructions: CityConstructions){
@ -155,8 +156,8 @@ class ConstructionAutomation(val cityConstructions: CityConstructions){
.filter { it.isStatRelated(Stat.Culture) }.minByOrNull { it.cost }
if (cultureBuilding != null) {
var modifier = 0.5f
if(cityInfo.cityStats.currentCityStats.culture==0f) // It won't grow if we don't help it
modifier=0.8f
if (cityInfo.cityStats.currentCityStats.culture == 0f) // It won't grow if we don't help it
modifier = 0.8f
if (preferredVictoryType == VictoryType.Cultural) modifier = 1.6f
addChoice(relativeCostEffectiveness, cultureBuilding.name, modifier)
}
@ -166,8 +167,6 @@ class ConstructionAutomation(val cityConstructions: CityConstructions){
val spaceshipPart = buildableNotWonders.firstOrNull { it.uniques.contains("Spaceship part") }
if (spaceshipPart != null) {
var modifier = 1.5f
if (cityInfo.cityStats.currentCityStats.culture == 0f) // It won't grow if we don't help it
modifier = 0.8f
if (preferredVictoryType == VictoryType.Scientific) modifier = 2f
addChoice(relativeCostEffectiveness, spaceshipPart.name, modifier)
}
@ -187,6 +186,11 @@ class ConstructionAutomation(val cityConstructions: CityConstructions){
if (preferredVictoryType == VictoryType.Cultural
&& wonder.name in listOf("Sistine Chapel", "Eiffel Tower", "Cristo Redentor", "Neuschwanstein", "Sydney Opera House"))
return 3f
// Only start building if we are the city that would complete it the soonest
if (wonder.uniques.contains("Triggers a Cultural Victory upon completion") && cityInfo == civInfo.cities.minByOrNull {
it.cityConstructions.turnsToConstruction(wonder.name)
}!!)
return 10f
if (wonder.isStatRelated(Stat.Science)) {
if (allTechsAreResearched) return .5f
if (preferredVictoryType == VictoryType.Scientific) return 1.5f

View File

@ -231,7 +231,10 @@ class CityConstructions {
fun turnsToConstruction(constructionName: String, useStoredProduction: Boolean = true): Int {
val workLeft = getRemainingWork(constructionName, useStoredProduction)
if (workLeft <= productionOverflow) // we might have done more work than actually necessary (if <0) - possible if circumstances cause buildings to be cheaper later
if (workLeft < 0) // This most often happens when a production is more than finished in a multiplayer game while its not your turn
return 0 // So we finish it at the start of the next turn. This could technically also happen when we lower production costs during our turn,
// but distinguishing those two cases is difficult, and the second one is much rarer than the first
if (workLeft <= productionOverflow) // if we already have stored up enough production to finish it directly
return 1 // we'll finish this next turn
val cityStatsForConstruction: Stats
@ -304,6 +307,9 @@ class CityConstructions {
validateInProgressConstructions()
if (getConstruction(currentConstructionFromQueue) !is PerpetualConstruction) {
if (getWorkDone(currentConstructionFromQueue) == 0) {
constructionBegun(getConstruction(currentConstructionFromQueue))
}
addProductionPoints(cityStats.production.roundToInt() + productionOverflow)
productionOverflow = 0
}
@ -362,6 +368,25 @@ class CityConstructions {
}
}
private fun constructionBegun(construction: IConstruction) {
if (construction !is Building) return;
if (construction.uniqueObjects.none { it.placeholderText == "Triggers a global alert upon build start" }) return
val buildingIcon = "BuildingIcons/${construction.name}"
for (otherCiv in cityInfo.civInfo.gameInfo.civilizations) {
if (otherCiv == cityInfo.civInfo) continue
when {
(otherCiv.exploredTiles.contains(cityInfo.location) && otherCiv != cityInfo.civInfo) ->
otherCiv.addNotification("The city of [${cityInfo.name}] has started constructing [${construction.name}]!",
cityInfo.location, NotificationIcon.Construction, buildingIcon)
(otherCiv.knows(cityInfo.civInfo)) ->
otherCiv.addNotification("[${cityInfo.civInfo.civName}] has started constructing [${construction.name}]!",
NotificationIcon.Construction, buildingIcon)
else -> otherCiv.addNotification("An unknown civilization has started constructing [${construction.name}]!",
NotificationIcon.Construction, buildingIcon)
}
}
}
private fun constructionComplete(construction: IConstruction) {
construction.postBuildEvent(this)
if (construction.name in inProgressConstructions)
@ -386,7 +411,7 @@ class CityConstructions {
cityInfo.civInfo.addNotification("[${construction.name}] has been built in [" + cityInfo.name + "]",
cityInfo.location, NotificationIcon.Construction, icon)
}
if (construction is Building && "Triggers a global alert upon completion" in construction.uniques) {
if (construction is Building && construction.uniqueObjects.any { it.placeholderText == "Triggers a global alert upon completion" } ) {
for (otherCiv in cityInfo.civInfo.gameInfo.civilizations) {
// No need to notify ourself, since we already got the building notification anyway
if (otherCiv == cityInfo.civInfo) continue

View File

@ -168,6 +168,7 @@ class CivilizationInfo {
fun isAlive(): Boolean = !isDefeated()
fun hasEverBeenFriendWith(otherCiv: CivilizationInfo): Boolean = getDiplomacyManager(otherCiv).everBeenFriends()
fun hasMetCivTerritory(otherCiv: CivilizationInfo): Boolean = otherCiv.getCivTerritory().any { it in exploredTiles }
fun getCompletedPolicyBranchesCount(): Int = policies.adoptedPolicies.count { it.endsWith("Complete") }
private fun getCivTerritory() = cities.asSequence().flatMap { it.tiles.asSequence() }
fun victoryType(): VictoryType {

View File

@ -36,7 +36,7 @@ class VictoryManager {
fun hasWonScientificVictory() = hasVictoryType(VictoryType.Scientific) && spaceshipPartsRemaining() == 0
fun hasWonCulturalVictory() = hasVictoryType(VictoryType.Cultural)
&& civInfo.policies.adoptedPolicies.count { it.endsWith("Complete") } > 4
&& civInfo.hasUnique("Triggers a Cultural Victory upon completion")
fun hasWonDominationVictory(): Boolean {
return hasVictoryType(VictoryType.Domination)

View File

@ -352,6 +352,16 @@ class Building : NamedStats(), IConstruction {
&& civInfo.cities.any { !it.isPuppet && !it.cityConstructions.containsBuildingOrEquivalent(unique.params[0]) })
return "Requires a [${civInfo.getEquivalentBuilding(unique.params[0])}] in all cities" // replace with civ-specific building for user
}
"Hidden until [] social policy branches have been completed" -> {
if (construction.cityInfo.civInfo.getCompletedPolicyBranchesCount() < unique.params[0].toInt()) {
return "Should not be displayed"
}
}
"Hidden when cultural victory is disabled" -> {
if ( !civInfo.gameInfo.gameParameters.victoryTypes.contains(VictoryType.Cultural)) {
return "Hidden when cultural victory is disabled"
}
}
}
if (requiredBuilding != null && !construction.containsBuildingOrEquivalent(requiredBuilding!!)) {
@ -383,7 +393,7 @@ class Building : NamedStats(), IConstruction {
if (!civInfo.gameInfo.gameParameters.victoryTypes.contains(VictoryType.Scientific)
&& "Enables construction of Spaceship parts" in uniques)
return "Can't construct spaceship parts if scientific victory is not enabled!"
return ""
}
@ -410,7 +420,6 @@ class Building : NamedStats(), IConstruction {
}
}
if (providesFreeBuilding != null && !cityConstructions.containsBuildingOrEquivalent(providesFreeBuilding!!)) {
var buildingToAdd = providesFreeBuilding!!
@ -469,4 +478,4 @@ class Building : NamedStats(), IConstruction {
resourceRequirements[unique.params[1]] = unique.params[0].toInt()
return resourceRequirements
}
}
}

View File

@ -198,7 +198,7 @@ class BaseUnit : INamed, IConstruction {
var XP = cityConstructions.getBuiltBuildings().sumBy { it.xpForNewUnits }
for (unique in cityConstructions.cityInfo.cityConstructions.builtBuildingUniqueMap
for (unique in cityConstructions.builtBuildingUniqueMap
.getUniques("New [] units start with [] Experience in this city")
+ civInfo.getMatchingUniques("New [] units start with [] Experience")) {
if (unit.matchesFilter(unique.params[0]))
@ -206,7 +206,7 @@ class BaseUnit : INamed, IConstruction {
}
unit.promotions.XP = XP
for (unique in cityConstructions.cityInfo.cityConstructions.builtBuildingUniqueMap
for (unique in cityConstructions.builtBuildingUniqueMap
.getUniques("All newly-trained [] units in this city receive the [] promotion")) {
val filter = unique.params[0]
val promotion = unique.params[1]

View File

@ -123,7 +123,7 @@ class VictoryScreen(val worldScreen: WorldScreen) : PickerScreen() {
if (dominationVictoryEnabled) myVictoryStatusTable.add(conquestVictoryColumn())
myVictoryStatusTable.row()
if (scientificVictoryEnabled) myVictoryStatusTable.add("Complete all the spaceship parts\n to win!".toLabel())
if (culturalVictoryEnabled) myVictoryStatusTable.add("Complete 5 policy branches\n to win!".toLabel())
if (culturalVictoryEnabled) myVictoryStatusTable.add("Complete 5 policy branches and build\n the Utopia Project to win!".toLabel())
if (dominationVictoryEnabled) myVictoryStatusTable.add("Destroy all enemies\n to win!".toLabel())
contentsTable.clear()

View File

@ -284,6 +284,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
* [Rocket](https://thenounproject.com/term/rocket/937173/) By BomSymbols for SS Cockpit
* [Engine](https://thenounproject.com/term/engine/1877958/) By Andre for SS Engine
* [Chamber](https://thenounproject.com/term/chamber/1242689/) By IYIKON for SS Stasis Chamber
* [Illuminati](https://thenounproject.com/term/illuminati/1617812) by emilegraphics for the Utopia Project
## Social Policies