mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-26 13:27:22 -04:00
Updated Freedom branch to G&K (#4142)
* Updated Freedom branch to G&K * Hotfix for autocracy policy that I accidentally added already * Implemented recommended changes (mostly) * Implemented recommended changes * Implemented recommended changes better
This commit is contained in:
parent
87810b8ce8
commit
1d18c418e7
@ -360,33 +360,33 @@
|
||||
},
|
||||
{
|
||||
"name": "Universal Suffrage",
|
||||
"uniques": ["[+1 Production] per [5] population in all cities"],
|
||||
"uniques": ["+[33]% Defensive Strength for cities"],
|
||||
"row": 1,
|
||||
"column": 3
|
||||
},
|
||||
{
|
||||
"name": "Civil Society",
|
||||
"uniques": ["-50% food consumption by specialists"],
|
||||
"uniques": ["-[50]% food consumption by specialists"],
|
||||
"row": 1,
|
||||
"column": 5
|
||||
},
|
||||
{
|
||||
"name": "Free Speech",
|
||||
"uniques": ["[+1 Culture] per [2] population in all cities"],
|
||||
"uniques": ["[8] units cost no maintenance"],
|
||||
"requires": ["Constitution"],
|
||||
"row": 2,
|
||||
"column": 1
|
||||
},
|
||||
{
|
||||
"name": "Democracy",
|
||||
"uniques": ["Specialists produce half normal unhappiness"],
|
||||
"uniques": ["Specialists only produce [50]% of normal unhappiness"],
|
||||
"requires": ["Civil Society"],
|
||||
"row": 2,
|
||||
"column": 5
|
||||
},
|
||||
{
|
||||
"name": "Freedom Complete",
|
||||
"uniques": ["Tile yield from Great Improvements +100%", "Golden Age length increased by [50]%"]
|
||||
"uniques": ["+[100]% yield from [Great Improvements]", "Golden Age length increased by [50]%"]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -167,50 +167,57 @@ object BattleDamage {
|
||||
return modifiers
|
||||
}
|
||||
|
||||
fun getDefenceModifiers(attacker: ICombatant, defender: MapUnitCombatant): Counter<String> {
|
||||
fun getDefenceModifiers(attacker: ICombatant, defender: ICombatant): Counter<String> {
|
||||
val modifiers = getGeneralModifiers(defender, attacker)
|
||||
val tile = defender.getTile()
|
||||
|
||||
if (defender is MapUnitCombatant) {
|
||||
|
||||
if (defender.unit.isEmbarked()) {
|
||||
// embarked units get no defensive modifiers apart from this unique
|
||||
if (defender.unit.hasUnique("Defense bonus when embarked") ||
|
||||
defender.getCivInfo().hasUnique("Embarked units can defend themselves")
|
||||
if (defender.unit.isEmbarked()) {
|
||||
// embarked units get no defensive modifiers apart from this unique
|
||||
if (defender.unit.hasUnique("Defense bonus when embarked") ||
|
||||
defender.getCivInfo().hasUnique("Embarked units can defend themselves")
|
||||
)
|
||||
modifiers["Embarked"] = 100
|
||||
|
||||
return modifiers
|
||||
}
|
||||
|
||||
modifiers.putAll(getTileSpecificModifiers(defender, tile))
|
||||
|
||||
val tileDefenceBonus = tile.getDefensiveBonus()
|
||||
if (!defender.unit.hasUnique("No defensive terrain bonus") && tileDefenceBonus > 0
|
||||
|| !defender.unit.hasUnique("No defensive terrain penalty") && tileDefenceBonus < 0
|
||||
)
|
||||
modifiers["Embarked"] = 100
|
||||
modifiers["Tile"] = (tileDefenceBonus * 100).toInt()
|
||||
|
||||
return modifiers
|
||||
if (attacker.isRanged()) {
|
||||
val defenceVsRanged = 25 * defender.unit.getUniques()
|
||||
.count { it.text == "+25% Defence against ranged attacks" }
|
||||
if (defenceVsRanged > 0) modifiers["defence vs ranged"] = defenceVsRanged
|
||||
}
|
||||
|
||||
for (unique in defender.unit.getMatchingUniques("+[]% Strength when defending")) {
|
||||
modifiers.add("Defender Bonus", unique.params[0].toInt())
|
||||
}
|
||||
|
||||
for (unique in defender.unit.getMatchingUniques("+[]% defence in [] tiles")) {
|
||||
if (tile.matchesUniqueFilter(unique.params[1]))
|
||||
modifiers["[${unique.params[1]}] defence"] = unique.params[0].toInt()
|
||||
}
|
||||
|
||||
if (defender.unit.isFortified())
|
||||
modifiers["Fortification"] = 20 * defender.unit.getFortificationTurns()
|
||||
} else if (defender is CityCombatant) {
|
||||
|
||||
modifiers["Defensive Bonus"] = defender.city.civInfo.getMatchingUniques("+[]% Defensive strength for cities")
|
||||
.map { it.params[0].toFloat() / 100f }.sum().toInt()
|
||||
|
||||
}
|
||||
|
||||
modifiers.putAll(getTileSpecificModifiers(defender, tile))
|
||||
|
||||
val tileDefenceBonus = tile.getDefensiveBonus()
|
||||
if (!defender.unit.hasUnique("No defensive terrain bonus") && tileDefenceBonus > 0
|
||||
|| !defender.unit.hasUnique("No defensive terrain penalty") && tileDefenceBonus < 0
|
||||
)
|
||||
modifiers["Tile"] = (tileDefenceBonus * 100).toInt()
|
||||
|
||||
if (attacker.isRanged()) {
|
||||
val defenceVsRanged = 25 * defender.unit.getUniques()
|
||||
.count { it.text == "+25% Defence against ranged attacks" }
|
||||
if (defenceVsRanged > 0) modifiers["defence vs ranged"] = defenceVsRanged
|
||||
}
|
||||
|
||||
for (unique in defender.unit.getMatchingUniques("+[]% Strength when defending")) {
|
||||
modifiers.add("Defender Bonus", unique.params[0].toInt())
|
||||
}
|
||||
|
||||
for (unique in defender.unit.getMatchingUniques("+[]% defence in [] tiles")) {
|
||||
if (tile.matchesUniqueFilter(unique.params[1]))
|
||||
modifiers["[${unique.params[1]}] defence"] = unique.params[0].toInt()
|
||||
}
|
||||
|
||||
|
||||
if (defender.unit.isFortified())
|
||||
modifiers["Fortification"] = 20 * defender.unit.getFortificationTurns()
|
||||
|
||||
return modifiers
|
||||
}
|
||||
|
||||
|
||||
private fun getTileSpecificModifiers(unit: MapUnitCombatant, tile: TileInfo): Counter<String> {
|
||||
val modifiers = Counter<String>()
|
||||
|
||||
@ -269,8 +276,7 @@ object BattleDamage {
|
||||
tileToAttackFrom: TileInfo?,
|
||||
defender: ICombatant
|
||||
): Float {
|
||||
val attackModifier =
|
||||
modifiersToMultiplicationBonus(getAttackModifiers(attacker, defender))
|
||||
val attackModifier = modifiersToMultiplicationBonus(getAttackModifiers(attacker, defender))
|
||||
return attacker.getAttackingStrength() * attackModifier
|
||||
}
|
||||
|
||||
@ -279,9 +285,7 @@ object BattleDamage {
|
||||
* Includes defence modifiers
|
||||
*/
|
||||
private fun getDefendingStrength(attacker: ICombatant, defender: ICombatant): Float {
|
||||
var defenceModifier = 1f
|
||||
if (defender is MapUnitCombatant) defenceModifier =
|
||||
modifiersToMultiplicationBonus(getDefenceModifiers(attacker, defender))
|
||||
val defenceModifier = modifiersToMultiplicationBonus(getDefenceModifiers(attacker, defender))
|
||||
return defender.getDefendingStrength() * defenceModifier
|
||||
}
|
||||
|
||||
|
@ -174,15 +174,24 @@ class CityStats {
|
||||
if (!civInfo.isPlayerCivilization())
|
||||
unhappinessModifier *= civInfo.gameInfo.getDifficulty().aiUnhappinessModifier
|
||||
|
||||
var unhappinessFromCity = -3f // -3 happiness per city
|
||||
var unhappinessFromCity = -3f // -3 happiness per city
|
||||
if (civInfo.hasUnique("Unhappiness from number of Cities doubled"))
|
||||
unhappinessFromCity *= 2f//doubled for the Indian
|
||||
unhappinessFromCity *= 2f //doubled for the Indian
|
||||
|
||||
newHappinessList["Cities"] = unhappinessFromCity * unhappinessModifier
|
||||
|
||||
var unhappinessFromCitizens = cityInfo.population.population.toFloat()
|
||||
if (civInfo.hasUnique("Specialists produce half normal unhappiness"))
|
||||
unhappinessFromCitizens -= cityInfo.population.getNumberOfSpecialists() * 0.5f
|
||||
var unhappinessFromSpecialists = cityInfo.population.getNumberOfSpecialists().toFloat()
|
||||
|
||||
for (unique in civInfo.getMatchingUniques("Specialists only produce []% of normal unhappiness")) {
|
||||
unhappinessFromSpecialists *= (1f - unique.params[0].toFloat() / 100f)
|
||||
}
|
||||
// Deprecated since 3.15
|
||||
if (civInfo.hasUnique("Specialists produce half normal unhappiness"))
|
||||
unhappinessFromSpecialists *= 0.5f
|
||||
//
|
||||
|
||||
unhappinessFromCitizens -= cityInfo.population.getNumberOfSpecialists().toFloat() - unhappinessFromSpecialists
|
||||
|
||||
if (cityInfo.isPuppet)
|
||||
unhappinessFromCitizens *= 1.5f
|
||||
@ -297,8 +306,7 @@ class CityStats {
|
||||
for (unique in uniques.filter { it.placeholderText == "+[]% [] []"})
|
||||
if (cityInfo.matchesFilter(unique.params[2]))
|
||||
stats.add(Stat.valueOf(unique.params[1]), unique.params[0].toFloat())
|
||||
|
||||
|
||||
|
||||
for (unique in uniques.filter { it.placeholderText == "+[]% Production when constructing []" }) {
|
||||
if (constructionMatchesFilter(currentConstruction, unique.params[1]))
|
||||
stats.production += unique.params[0].toInt()
|
||||
@ -391,7 +399,7 @@ class CityStats {
|
||||
fun update(currentConstruction: IConstruction = cityInfo.cityConstructions.getCurrentConstruction()) {
|
||||
|
||||
val citySpecificUniques: Sequence<Unique> = cityInfo.cityConstructions.builtBuildingUniqueMap.getAllUniques()
|
||||
.filter { it.params.isNotEmpty() && it.params.last()=="in this city" }
|
||||
.filter { it.params.isNotEmpty() && it.params.last() == "in this city" }
|
||||
// We need to compute Tile yields before happiness
|
||||
updateBaseStatList()
|
||||
updateCityHappiness()
|
||||
@ -505,8 +513,16 @@ class CityStats {
|
||||
|
||||
private fun updateFoodEaten() {
|
||||
foodEaten = cityInfo.population.population.toFloat() * 2
|
||||
if (cityInfo.civInfo.hasUnique("-50% food consumption by specialists"))
|
||||
foodEaten -= cityInfo.population.getNumberOfSpecialists()
|
||||
var foodEatenBySpecialists = 2f * cityInfo.population.getNumberOfSpecialists()
|
||||
|
||||
for (unique in cityInfo.civInfo.getMatchingUniques("-[]% food consumption by specialists"))
|
||||
foodEatenBySpecialists *= 1f - unique.params[0].toFloat() / 100f
|
||||
|
||||
// Deprecated since 3.15
|
||||
if (cityInfo.civInfo.hasUnique("-50% food consumption by specialists"))
|
||||
foodEatenBySpecialists *= 0.5f
|
||||
//
|
||||
|
||||
foodEaten -= 2f * cityInfo.population.getNumberOfSpecialists() - foodEatenBySpecialists
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,11 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
|
||||
|
||||
private fun getUnitMaintenance(): Int {
|
||||
val baseUnitCost = 0.5f
|
||||
val freeUnits = 3
|
||||
var freeUnits = 3
|
||||
for (unique in civInfo.getMatchingUniques("[] units cost no maintenance")) {
|
||||
freeUnits += unique.params[0].toInt()
|
||||
}
|
||||
|
||||
var unitsToPayFor = civInfo.getCivUnits()
|
||||
if (civInfo.hasUnique("Units in cities cost no Maintenance"))
|
||||
// Only land military units can truly "garrison"
|
||||
@ -39,7 +43,15 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
|
||||
cost = cost.pow(1 + gameProgress / 3) // Why 3? To spread 1 to 1.33
|
||||
if (!civInfo.isPlayerCivilization())
|
||||
cost *= civInfo.gameInfo.getDifficulty().aiUnitMaintenanceModifier
|
||||
if (civInfo.hasUnique("-33% unit upkeep costs")) cost *= 0.66f
|
||||
|
||||
for (unique in civInfo.getMatchingUniques("-[]% unit upkeep costs")) {
|
||||
cost *= 1f - unique.params[0].toFloat() / 100f
|
||||
}
|
||||
|
||||
// Deprecated since 3.15
|
||||
if (civInfo.hasUnique("-33% unit upkeep costs")) cost *= 0.67f
|
||||
//
|
||||
|
||||
return cost.toInt()
|
||||
}
|
||||
|
||||
|
@ -286,24 +286,21 @@ open class TileInfo {
|
||||
|
||||
if (city != null) {
|
||||
val cityWideUniques = city.cityConstructions.builtBuildingUniqueMap.getUniques("[] from [] tiles in this city")
|
||||
val civWideUniques = city.civInfo.getMatchingUniques("[] from every []")
|
||||
val improvementUniques = improvement.uniqueObjects.filter {
|
||||
it.placeholderText == "[] on [] tiles once [] is discovered"
|
||||
&& observingCiv.tech.isResearched(it.params[2])
|
||||
}
|
||||
for (unique in cityWideUniques + civWideUniques + improvementUniques) {
|
||||
if (improvement.name == unique.params[1]
|
||||
|| unique.params[1] == "Great Improvement" && improvement.isGreatImprovement()
|
||||
|| unique.params[1] == "Fresh water" && isAdjacentToFreshwater
|
||||
|| unique.params[1] == "non-fresh water" && !isAdjacentToFreshwater
|
||||
)
|
||||
for (unique in cityWideUniques + improvementUniques) {
|
||||
if (matchesUniqueFilter(unique.params[1]))
|
||||
stats.add(unique.stats)
|
||||
}
|
||||
}
|
||||
|
||||
if (containsGreatImprovement()
|
||||
&& observingCiv.hasUnique("Tile yield from Great Improvements +100%"))
|
||||
stats.add(improvement) // again, for the double effect
|
||||
for (unique in city.civInfo.getMatchingUniques("[] from every []")) {
|
||||
if (improvement.matchesFilter(unique.params[1])) {
|
||||
stats.add(unique.stats)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unique in improvement.uniqueObjects)
|
||||
if (unique.placeholderText == "[] for each adjacent []") {
|
||||
@ -315,7 +312,16 @@ open class TileInfo {
|
||||
}
|
||||
stats.add(unique.stats.times(numberOfBonuses.toFloat()))
|
||||
}
|
||||
|
||||
|
||||
for (unique in observingCiv.getMatchingUniques("+[]% yield from []"))
|
||||
if (improvement.matchesFilter(unique.params[0]))
|
||||
stats.timesInPlace(1f + unique.params[1].toFloat() / 100f)
|
||||
|
||||
// Deprecated since 3.15
|
||||
if (containsGreatImprovement() && observingCiv.hasUnique("Tile yield from Great Improvements +100%"))
|
||||
stats.timesInPlace(2f)
|
||||
//
|
||||
|
||||
return stats
|
||||
}
|
||||
|
||||
@ -386,23 +392,28 @@ open class TileInfo {
|
||||
* Implementation of _`tileFilter`_
|
||||
* @see <a href="https://github.com/yairm210/Unciv/wiki/uniques#user-content-tilefilter">tileFilter</a>
|
||||
*/
|
||||
fun matchesUniqueFilter(filter: String, civInfo: CivilizationInfo? = null): Boolean {
|
||||
return filter == "All"
|
||||
|| filter == baseTerrain
|
||||
|| filter == "River" && isAdjacentToRiver()
|
||||
|| terrainFeatures.contains(filter)
|
||||
|| baseTerrainObject.uniques.contains(filter)
|
||||
|| improvement == filter
|
||||
|| resource == filter
|
||||
|| resource != null && getTileResource().resourceType.name + " resource" == filter
|
||||
|| filter == "Water" && isWater
|
||||
|| filter == "Land" && isLand
|
||||
|| filter == "Coastal" && isCoastalTile()
|
||||
|| filter == naturalWonder
|
||||
|| terrainFeatures.isNotEmpty() && getTerrainFeatures().last().uniques.contains(filter)
|
||||
|| civInfo != null && hasViewableResource(civInfo) && resource == filter
|
||||
|| filter == "Foreign Land" && civInfo != null && !isFriendlyTerritory(civInfo)
|
||||
|| filter == "Friendly Land" && civInfo != null && isFriendlyTerritory(civInfo)
|
||||
fun matchesUniqueFilter(filter: String, civInfo: CivilizationInfo? = null): Boolean {
|
||||
return when (filter) {
|
||||
"All" -> true
|
||||
"Water" -> isWater
|
||||
"Land" -> isLand
|
||||
"Coastal" -> isCoastalTile()
|
||||
"River" -> isAdjacentToRiver()
|
||||
"Fresh water" -> isAdjacentToFreshwater
|
||||
"non-fresh water" -> !isAdjacentToFreshwater
|
||||
improvement -> true
|
||||
naturalWonder -> true
|
||||
"Foreign Land" -> civInfo != null && !isFriendlyTerritory(civInfo)
|
||||
"Friendly Land" -> civInfo != null && isFriendlyTerritory(civInfo)
|
||||
else -> {
|
||||
if (terrainFeatures.contains(filter)) return true
|
||||
if (baseTerrainObject.uniques.contains(filter)) return true
|
||||
if (terrainFeatures.isNotEmpty() && getTerrainFeatures().last().uniques.contains(filter)) return true
|
||||
if (resource != null && getTileResource().resourceType.name + " resource" == filter) return true
|
||||
if (civInfo != null && hasViewableResource(civInfo) && resource == filter) return true
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun hasImprovementInProgress() = improvementInProgress != null
|
||||
|
@ -94,5 +94,14 @@ class TileImprovement : NamedStats() {
|
||||
&& it.params[0] == name
|
||||
}.any()
|
||||
}
|
||||
|
||||
fun matchesFilter(filter: String): Boolean {
|
||||
return when (filter) {
|
||||
name -> true
|
||||
"All" -> true
|
||||
"Great Improvement" -> isGreatImprovement()
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,6 +64,12 @@ open class Stats() {
|
||||
for (stat in Stat.values()) hashMap[stat] = number * hashMap[stat]!!
|
||||
return Stats(hashMap)
|
||||
}
|
||||
|
||||
fun timesInPlace(number: Float) {
|
||||
val hashMap = toHashMap()
|
||||
for (stat in Stat.values()) hashMap[stat] = number * hashMap[stat]!!
|
||||
setStats(hashMap)
|
||||
}
|
||||
|
||||
fun isEmpty() = equals(Stats())
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user