A mishmash of different fixes: Unit uniques and promotions, happiness calculation, etc.

This commit is contained in:
Yair Morgenstern 2020-08-24 10:58:14 +03:00
parent 21c8336563
commit 6ff712b625
9 changed files with 27 additions and 31 deletions

View File

@ -786,7 +786,7 @@
"culture": 1, "culture": 1,
"isWonder": true, "isWonder": true,
"greatPersonPoints": {"production": 2}, "greatPersonPoints": {"production": 2},
"uniques": ["+1 Production from specialists"], "uniques": ["[+1 Production] from every specialist"],
"requiredTech": "Replaceable Parts", "requiredTech": "Replaceable Parts",
"quote": "'Give me your tired, your poor, your huddled masses yearning to breathe free, the wretched refuse of your teeming shore. Send these, the homeless, tempest-tossed to me, I lift my lamp beside the golden door!' - Emma Lazarus" "quote": "'Give me your tired, your poor, your huddled masses yearning to breathe free, the wretched refuse of your teeming shore. Send these, the homeless, tempest-tossed to me, I lift my lamp beside the golden door!' - Emma Lazarus"
}, },

View File

@ -8,7 +8,7 @@
{ {
"name": "Aristocracy", "name": "Aristocracy",
"effect": "+15% production when constructing wonders, +1 happiness for every 10 citizens in a city", "effect": "+15% production when constructing wonders, +1 happiness for every 10 citizens in a city",
"uniques": ["+[15]% Production when constructing [Wonders]", "+1 happiness for every 10 citizens in a city"], "uniques": ["+[15]% Production when constructing [Wonders]", "[+1 Happiness] per [10] population in all cities"],
"row": 1, "row": 1,
"column": 1 "column": 1
}, },

View File

@ -451,6 +451,6 @@
}, },
{ {
"name": "Slinger Withdraw", // only for Slinger and subsequent upgrades "name": "Slinger Withdraw", // only for Slinger and subsequent upgrades
"effect": "May withdraw before melee (133%)" "effect": "May withdraw before melee ([133]%)"
} }
] ]

View File

@ -656,7 +656,7 @@
"requiredTech": "Astronomy", "requiredTech": "Astronomy",
"upgradesTo": "Ironclad", "upgradesTo": "Ironclad",
"obsoleteTech": "Combustion", "obsoleteTech": "Combustion",
"uniques": ["+1 Visibility Range","May withdraw before melee"], "uniques": ["+1 Visibility Range","May withdraw before melee ([50]%)"],
"hurryCostModifier": 20 "hurryCostModifier": 20
}, },
{ {
@ -1071,7 +1071,7 @@
"interceptRange": 2, "interceptRange": 2,
"cost": 375, "cost": 375,
"requiredTech": "Combustion", "requiredTech": "Combustion",
"uniques": ["Can attack submarines", "[40]% chance to intercept air attacks", "May withdraw before melee"], // todo: add bonus vs submarines "uniques": ["Can attack submarines", "[40]% chance to intercept air attacks", "May withdraw before melee ([50]%)"], // todo: add bonus vs submarines
"hurryCostModifier": 20 "hurryCostModifier": 20
}, },
{ {

View File

@ -26,7 +26,6 @@ Get =
Hydro Plant = Hydro Plant =
+1 population in each city = +1 population in each city =
+1 happiness in each city =
# Diplomacy,Trade,Nations # Diplomacy,Trade,Nations

View File

@ -11,6 +11,7 @@ import com.unciv.logic.civilization.diplomacy.DiplomaticModifiers
import com.unciv.logic.map.RoadStatus import com.unciv.logic.map.RoadStatus
import com.unciv.logic.map.TileInfo import com.unciv.logic.map.TileInfo
import com.unciv.models.AttackableTile import com.unciv.models.AttackableTile
import com.unciv.models.ruleset.Unique
import com.unciv.models.ruleset.unit.UnitType import com.unciv.models.ruleset.unit.UnitType
import java.util.* import java.util.*
import kotlin.math.max import kotlin.math.max
@ -49,8 +50,8 @@ object Battle {
// Withdraw from melee ability // Withdraw from melee ability
if (attacker is MapUnitCombatant && attacker.isMelee() && defender is MapUnitCombatant ) { if (attacker is MapUnitCombatant && attacker.isMelee() && defender is MapUnitCombatant ) {
val withdraw = defender.unit.getUniques().firstOrNull { it.text.startsWith("May withdraw before melee")} val withdraw = defender.unit.getMatchingUniques("May withdraw before melee ([]%)").firstOrNull()
if (withdraw != null && doWithdrawFromMeleeAbility(attacker, defender, withdraw.text)) return if (withdraw != null && doWithdrawFromMeleeAbility(attacker, defender, withdraw)) return
} }
val isAlreadyDefeatedCity = defender is CityCombatant && defender.isDefeated() val isAlreadyDefeatedCity = defender is CityCombatant && defender.isDefeated()
@ -411,7 +412,7 @@ object Battle {
} }
} }
private fun doWithdrawFromMeleeAbility(attacker: ICombatant, defender: ICombatant, withdraw: String): Boolean { private fun doWithdrawFromMeleeAbility(attacker: ICombatant, defender: ICombatant, withdrawUnique: Unique): Boolean {
// Some notes... // Some notes...
// unit.getUniques() is a union of baseunit uniques and promotion effects. // unit.getUniques() is a union of baseunit uniques and promotion effects.
// according to some strategy guide the slinger's withdraw ability is inherited on upgrade, // according to some strategy guide the slinger's withdraw ability is inherited on upgrade,
@ -427,9 +428,8 @@ object Battle {
// Promotions have no effect as per what I could find in available documentation // Promotions have no effect as per what I could find in available documentation
val attackBaseUnit = attacker.unit.baseUnit val attackBaseUnit = attacker.unit.baseUnit
val defendBaseUnit = defender.unit.baseUnit val defendBaseUnit = defender.unit.baseUnit
val withdrawMatch = Regex("""\((\d+)%\)""").find(withdraw) val baseChance = withdrawUnique.params[0].toFloat()
val percentChance = ( val percentChance = (baseChance
(if(withdrawMatch!=null) withdrawMatch.groups[1]!!.value.toFloat() else 50f)
* defendBaseUnit.strength / attackBaseUnit.strength * defendBaseUnit.strength / attackBaseUnit.strength
* defendBaseUnit.movement / attackBaseUnit.movement).toInt() * defendBaseUnit.movement / attackBaseUnit.movement).toInt()
// Roll the dice - note the effect of the surroundings, namely how much room there is to evade to, // Roll the dice - note the effect of the surroundings, namely how much room there is to evade to,

View File

@ -189,6 +189,11 @@ object BattleDamage {
val carrierDefenceBonus = 0.25f * defender.unit.getUniques().count { it.text == "+25% Combat Bonus when defending" } val carrierDefenceBonus = 0.25f * defender.unit.getUniques().count { it.text == "+25% Combat Bonus when defending" }
if (carrierDefenceBonus > 0) modifiers["Armor Plating"] = carrierDefenceBonus if (carrierDefenceBonus > 0) modifiers["Armor Plating"] = carrierDefenceBonus
for(unique in defender.unit.getMatchingUniques("+[]% defence in [] tiles")) {
if (tile.baseTerrain == unique.params[1] || tile.terrainFeature == unique.params[1])
modifiers["[${unique.params[1]}] defence"] = unique.params[0].toFloat() / 100
}
if (defender.unit.isFortified()) if (defender.unit.isFortified())
modifiers["Fortification"] = 0.2f * defender.unit.getFortificationTurns() modifiers["Fortification"] = 0.2f * defender.unit.getFortificationTurns()

View File

@ -200,14 +200,10 @@ class CityStats {
newHappinessList["Population"] = -unhappinessFromCitizens * unhappinessModifier newHappinessList["Population"] = -unhappinessFromCitizens * unhappinessModifier
var happinessFromPolicies = 0f var happinessFromPolicies = 0f
if (civInfo.hasUnique("+1 happiness for every 10 citizens in a city"))
happinessFromPolicies += (cityInfo.population.population / 10).toFloat()
if (civInfo.hasUnique("+1 gold and -1 unhappiness for every 2 citizens in capital")
&& cityInfo.isCapital())
happinessFromPolicies += (cityInfo.population.population / 2).toFloat()
if (civInfo.hasUnique("+1 happiness for every city connected to capital") if (civInfo.hasUnique("+1 happiness for every city connected to capital")
&& cityInfo.isConnectedToCapital()) && cityInfo.isConnectedToCapital())
happinessFromPolicies += 1f happinessFromPolicies += 1f
happinessFromPolicies += getStatsFromUniques(civInfo.policies.policyUniques.getAllUniques()).happiness
if (cityInfo.getCenterTile().militaryUnit != null) if (cityInfo.getCenterTile().militaryUnit != null)
for (unique in civInfo.getMatchingUniques("[] in all cities with a garrison")) for (unique in civInfo.getMatchingUniques("[] in all cities with a garrison"))
@ -220,8 +216,7 @@ class CityStats {
val happinessFromBuildings = cityInfo.cityConstructions.getStats().happiness.toInt().toFloat() val happinessFromBuildings = cityInfo.cityConstructions.getStats().happiness.toInt().toFloat()
newHappinessList["Buildings"] = happinessFromBuildings newHappinessList["Buildings"] = happinessFromBuildings
if (civInfo.hasUnique("+1 happiness in each city")) newHappinessList["Wonders"] = getStatsFromUniques(civInfo.getBuildingUniques()).happiness
newHappinessList["Wonders"] = 1f
newHappinessList["Tile yields"] = getStatsFromTiles().happiness newHappinessList["Tile yields"] = getStatsFromTiles().happiness
@ -243,8 +238,7 @@ class CityStats {
for(unique in cityInfo.civInfo.getMatchingUniques("[] from every specialist")) for(unique in cityInfo.civInfo.getMatchingUniques("[] from every specialist"))
stats.add(Stats.parse(unique.params[0])) stats.add(Stats.parse(unique.params[0]))
if (cityInfo.civInfo.hasUnique("+1 Production from specialists"))
stats.production += 1
return stats return stats
} }
@ -267,8 +261,10 @@ class CityStats {
val amountOfEffects = (cityInfo.population.population / unique.params[1].toInt()).toFloat() val amountOfEffects = (cityInfo.population.population / unique.params[1].toInt()).toFloat()
stats.add(Stats.parse(unique.params[0]).times(amountOfEffects)) stats.add(Stats.parse(unique.params[0]).times(amountOfEffects))
} }
if (unique.text == "+1 gold and -1 unhappiness for every 2 citizens in capital" && cityInfo.isCapital()) if (unique.text == "+1 gold and -1 unhappiness for every 2 citizens in capital" && cityInfo.isCapital()) {
stats.gold += (cityInfo.population.population / 2).toFloat() stats.gold += (cityInfo.population.population / 2).toFloat()
stats.happiness += (cityInfo.population.population / 2).toFloat()
}
} }
return stats return stats

View File

@ -634,11 +634,7 @@ class MapUnit {
} }
fun interceptChance():Int{ fun interceptChance():Int{
val interceptUnique = getUniques() return getMatchingUniques("[100]% chance to intercept air attacks").sumBy { it.params[0].toInt() }
.firstOrNull { it.text.endsWith(CHANCE_TO_INTERCEPT_AIR_ATTACKS) }
if(interceptUnique==null) return 0
val percent = Regex("\\d+").find(interceptUnique.text)!!.value.toInt()
return percent
} }
fun isTransportTypeOf(mapUnit: MapUnit): Boolean { fun isTransportTypeOf(mapUnit: MapUnit): Boolean {