Made all the other constants determining the strength of cities moddable (#5940)

This commit is contained in:
Xander Lenstra 2022-01-10 22:55:22 +01:00 committed by GitHub
parent 93a109b082
commit d809f3a132
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 52 additions and 28 deletions

View File

@ -831,7 +831,7 @@
"culture": 3,
"cityStrength": 12,
"isWonder": true,
"uniques": ["Defensive buildings in all cities are 25% more effective"],
"uniques": ["[+25]% City Strength from defensive buildings"],
"requiredTech": "Metallurgy",
"quote": "'The Law is a fortress on a hill that armies cannot take or floods wash away.' - The Prophet Muhammed"
},

View File

@ -694,7 +694,7 @@
"culture": 3,
"cityStrength": 12,
"isWonder": true,
"uniques": ["Defensive buildings in all cities are 25% more effective"],
"uniques": ["[+25]% City Strength from defensive buildings"],
"requiredTech": "Acoustics",
"quote": "'The Law is a fortress on a hill that armies cannot take or floods wash away.' - The Prophet Muhammed"
},

View File

@ -4,6 +4,7 @@ import com.unciv.logic.city.CityInfo
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.map.TileInfo
import com.unciv.models.UncivSound
import com.unciv.models.ruleset.unique.StateForConditionals
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.ruleset.unit.UnitType
import kotlin.math.pow
@ -30,37 +31,41 @@ class CityCombatant(val city: CityInfo) : ICombatant {
}
override fun getUnitType(): UnitType = UnitType.City
override fun getAttackingStrength(): Int = (getCityStrength() * 0.75).roundToInt()
override fun getAttackingStrength(): Int = (getCityStrength(CombatAction.Attack) * 0.75).roundToInt()
override fun getDefendingStrength(): Int {
if (isDefeated()) return 1
return getCityStrength()
}
fun getCityStrength(): Int { // Civ fanatics forum, from a modder who went through the original code
fun getCityStrength(combatAction: CombatAction = CombatAction.Defend): Int { // Civ fanatics forum, from a modder who went through the original code
val modConstants = getCivInfo().gameInfo.ruleSet.modOptions.constants
var strength = 8f
strength += (city.population.population / 5) * 2 // Each 5 pop gives 2 defence
var strength = modConstants.cityStrengthBase
strength += (city.population.population * modConstants.cityStrengthPerPop) // Each 5 pop gives 2 defence
val cityTile = city.getCenterTile()
for (unique in cityTile.getAllTerrains().flatMap { it.getMatchingUniques(UniqueType.GrantsCityStrength) })
strength += unique.params[0].toInt()
// as tech progresses so does city strength
val techCount = getCivInfo().gameInfo.ruleSet.technologies.count()
val techsPercentKnown: Float = if (techCount > 0) city.civInfo.tech.techsResearched.count().toFloat() / techCount else 0.5f // for mods with no tech
strength += (techsPercentKnown * modConstants.cityStrengthFromTechsMultiplier).pow(modConstants.cityStrengthFromTechsExponent).toFloat()
strength += (techsPercentKnown * modConstants.cityStrengthFromTechsMultiplier).pow(modConstants.cityStrengthFromTechsExponent) * modConstants.cityStrengthFromTechsFullMultiplier
// The way all of this adds up...
// All ancient techs - 0.5 extra, Classical - 2.7, Medieval - 8, Renaissance - 17.5,
// Industrial - 32.4, Modern - 51, Atomic - 72.5, All - 118.3
// 100% of the way through the game provides an extra 50.00
// Garrisoned unit gives up to 20% of strength to city, health-dependant
if (cityTile.militaryUnit != null)
strength += cityTile.militaryUnit!!.baseUnit().strength * (cityTile.militaryUnit!!.health / 100f) * 0.2f
strength += cityTile.militaryUnit!!.baseUnit().strength * (cityTile.militaryUnit!!.health / 100f) * modConstants.cityStrengthFromGarrison
var buildingsStrength = city.cityConstructions.getBuiltBuildings().sumOf { it.cityStrength }.toFloat()
if (getCivInfo().hasUnique("Defensive buildings in all cities are 25% more effective"))
buildingsStrength *= 1.25f
val stateForConditionals = StateForConditionals(getCivInfo(), city, ourCombatant = this, combatAction = combatAction)
// Deprecated since 3.18.17
if (getCivInfo().hasUnique(UniqueType.DefensiveBuilding25, stateForConditionals))
buildingsStrength *= 1.25f
//
for (unique in getCivInfo().getMatchingUniques(UniqueType.BetterDefensiveBuildings, stateForConditionals))
buildingsStrength *= unique.params[0].toInt()
strength += buildingsStrength
return strength.roundToInt()

View File

@ -872,7 +872,7 @@ class CityInfo {
fun getForceEvaluation(): Int {
// Same as for units, so higher values count more
return CityCombatant(this).getCityStrength().toFloat().pow(1.5f).toInt()
return CityCombatant(this).getDefendingStrength().toFloat().pow(1.5f).toInt()
}

View File

@ -5,9 +5,17 @@ class ModConstants {
var maxXPfromBarbarians = 30
// Formula for city Strength:
// Strength = baseStrength * (%techs * multiplier) ^ exponent
// If no techs exist in this ruleset, %techs = 0.5
// Strength = baseStrength + strengthPerPop + strengthFromTiles +
// ((%techs * multiplier) ^ exponent) * fullMultiplier +
// (garrisonBonus * garrisonUnitStrength * garrisonUnitHealth/100) +
// defensiveBuildingStrength
// where %techs is the percentage of techs in the tech tree that are complete
// If no techs exist in this ruleset, %techs = 0.5 (=50%)
val cityStrengthBase = 8.0
val cityStrengthPerPop = 0.4
val cityStrengthFromTechsMultiplier = 5.5
val cityStrengthFromTechsExponent = 2.8
val cityStrengthFromTechsFullMultiplier = 1.0
val cityStrengthFromGarrison = 0.2
}

View File

@ -178,6 +178,10 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget, val flags:
CannotBuildUnits("Cannot build [baseUnitFilter] units", UniqueTarget.Global),
BetterDefensiveBuildings("[amount]% City Strength from defensive buildings", UniqueTarget.Global),
@Deprecated("As of 3.18.17", ReplaceWith("[+25]% City Strength from defensive buildings"))
DefensiveBuilding25("Defensive buildings in all cities are 25% more effective", UniqueTarget.Global),
//endregion Global uniques
@ -189,6 +193,10 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget, val flags:
CanBePurchasedForAmountStat("Can be purchased for [amount] [stat] [cityFilter]", UniqueTarget.Building, UniqueTarget.Unit),
MaxNumberBuildable("Limited to [amount] per Civilization", UniqueTarget.Building, UniqueTarget.Unit),
HiddenBeforeAmountPolicies("Hidden until [amount] social policy branches have been completed", UniqueTarget.Building, UniqueTarget.Unit),
NotDisplayedWithout("Not displayed as an available construction without [buildingName/tech/resource/policy]", UniqueTarget.Building, UniqueTarget.Unit),
//UniqueType added in 3.18.4
@Deprecated("As of 3.16.11", ReplaceWith("Not displayed as an available construction without [buildingName]"), DeprecationLevel.WARNING)
NotDisplayedUnlessOtherBuildingBuilt("Not displayed as an available construction unless [buildingName] is built", UniqueTarget.Building),
//endregion
@ -201,10 +209,7 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget, val flags:
RequiresAnotherBuilding("Requires a [buildingName] in this city", UniqueTarget.Building),
RequiresBuildingInAllCities("Requires a [buildingName] in all cities", UniqueTarget.Building),
NotDisplayedWithout("Not displayed as an available construction without [buildingName/tech/resource/policy]", UniqueTarget.Building, UniqueTarget.Unit),
//UniqueType added in 3.18.4
@Deprecated("As of 3.16.11", ReplaceWith("Not displayed as an available construction without [buildingName]"), DeprecationLevel.WARNING)
NotDisplayedUnlessOtherBuildingBuilt("Not displayed as an available construction unless [buildingName] is built", UniqueTarget.Building),
MustBeOn("Must be on [terrainFilter]", UniqueTarget.Building),
MustNotBeOn("Must not be on [terrainFilter]", UniqueTarget.Building),
@ -498,7 +503,7 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget, val flags:
HiddenAfterGreatProphet("Hidden after generating a Great Prophet", UniqueTarget.Ruins),
AvailableAfterCertainTurns("Only available after [amount] turns", UniqueTarget.Ruins),
HiddenWithoutVictoryType("Hidden when [victoryType] Victory is disabled", UniqueTarget.Building, UniqueTarget.Unit),
// region DEPRECATED AND REMOVED

View File

@ -231,7 +231,7 @@ class CityButton(val city: CityInfo, private val tileGroup: WorldTileGroup): Tab
label.toBack() // this is so the label is rendered right before the population group,
// so we save the font texture and avoid another texture switch
val cityStrength = CityCombatant(city).getCityStrength()
val cityStrength = CityCombatant(city).getDefendingStrength()
val cityStrengthLabel =
"${Fonts.strength}$cityStrength".toLabel(city.civInfo.nation.getInnerColor(), 10)
if (!forPopup) {

View File

@ -197,7 +197,7 @@ class UnitTable(val worldScreen: WorldScreen) : Table(){
unitDescriptionTable.clear()
unitDescriptionTable.defaults().pad(2f).padRight(5f)
unitDescriptionTable.add("Strength".tr())
unitDescriptionTable.add(CityCombatant(city).getCityStrength().toString()).row()
unitDescriptionTable.add(CityCombatant(city).getDefendingStrength().toString()).row()
unitDescriptionTable.add("Bombard strength".tr())
unitDescriptionTable.add(CityCombatant(city).getAttackingStrength().toString()).row()

View File

@ -223,6 +223,11 @@ Example: "Cannot build [Melee] units"
Applicable to: Global
#### [amount]% City Strength from defensive buildings
Example: "[20]% City Strength from defensive buildings"
Applicable to: Global
#### [amount]% Strength
Example: "[20]% Strength"
@ -417,6 +422,11 @@ Example: "Hidden until [20] social policy branches have been completed"
Applicable to: Building, Unit
#### Not displayed as an available construction without [buildingName/tech/resource/policy]
Example: "Not displayed as an available construction without [buildingName/tech/resource/policy]"
Applicable to: Building, Unit
#### Cost increases by [amount] per owned city
Example: "Cost increases by [20] per owned city"
@ -437,11 +447,6 @@ Example: "Requires a [Library] in all cities"
Applicable to: Building
#### Not displayed as an available construction without [buildingName/tech/resource/policy]
Example: "Not displayed as an available construction without [buildingName/tech/resource/policy]"
Applicable to: Building, Unit
#### Must be on [terrainFilter]
Example: "Must be on [Grassland]"
@ -1087,6 +1092,7 @@ Applicable to: Conditional
- "-[amount]% food consumption by specialists [cityFilter]" - Deprecated As of 3.18.2, replace with "[-amount]% food consumption by specialists [cityFilter]"
- "50% of excess happiness added to culture towards policies" - Deprecated As of 3.18.2, replace with "[50]% of excess happiness converted to [Culture]"
- "May buy [baseUnitFilter] units for [amount] [stat] [cityFilter] starting from the [era] at an increasing price ([amount])" - Deprecated As of 3.17.9, replace with "May buy [baseUnitFilter] units for [amount] [stat] [cityFilter] at an increasing price ([amount]) <starting from the [era]>"
- "Defensive buildings in all cities are 25% more effective" - Deprecated As of 3.18.17, replace with "[+25]% City Strength from defensive buildings"
- "[mapUnitFilter] units gain [amount]% more Experience from combat" - Deprecated As of 3.18.12, replace with "[amount]% XP gained from combat <for [mapUnitFilter] units>"
- "[amount]% maintenance costs for [mapUnitFilter] units" - Deprecated As of 3.18.14, replace with "[amount]% maintenance costs <for [mapUnitFilter] units>"
- "Immediately creates the cheapest available cultural building in each of your first [amount] cities for free" - Deprecated As of 3.16.15 - removed 3.18.4, replace with "Provides the cheapest [stat] building in your first [amount] cities for free"