diff --git a/android/assets/jsons/Buildings.json b/android/assets/jsons/Buildings.json index b00c046f52..c706017764 100644 --- a/android/assets/jsons/Buildings.json +++ b/android/assets/jsons/Buildings.json @@ -69,6 +69,13 @@ hurryCostModifier:25, requiredTech:"Trapping" }, + { + name:"Walls", + cityStrength:5, + cityHealth:50, + hurryCostModifier:25, + requiredTech:"Masonry" + }, { name:"The Pyramids", baseDescription: "Worker construction increased 25%, provides 2 free workers", @@ -243,6 +250,14 @@ requiredBuildingInAllCities:"University", requiredTech:"Education" }, + { + name:"Castle", + cityStrength:7, + cityHealth:25, + hurryCostModifier:25, + requiredBuilding:"Walls", + requiredTech:"Chivalry" + }, { name:"Angkor Wat", baseDescription: "Cost of acquiring new tiles reduced by 25%", diff --git a/core/src/com/unciv/logic/battle/BattleDamage.kt b/core/src/com/unciv/logic/battle/BattleDamage.kt index a567093527..19c5daceaa 100644 --- a/core/src/com/unciv/logic/battle/BattleDamage.kt +++ b/core/src/com/unciv/logic/battle/BattleDamage.kt @@ -76,33 +76,32 @@ class BattleDamage{ return modifiers } - fun getDefenceModifiers(attacker: ICombatant, defender: ICombatant): HashMap { + fun getDefenceModifiers(attacker: ICombatant, defender: MapUnitCombatant): HashMap { val modifiers = getGeneralModifiers(defender, attacker) - if (!(defender is MapUnitCombatant && defender.unit.hasUnique("No defensive terrain bonus"))) { + if (!(defender.unit.hasUnique("No defensive terrain bonus"))) { val tileDefenceBonus = defender.getTile().getDefensiveBonus() if (tileDefenceBonus > 0) modifiers["Terrain"] = tileDefenceBonus } - if(defender is MapUnitCombatant) { - val defenderTile = defender.getTile() - val isDefenderInRoughTerrain = defenderTile.baseTerrain=="Hill" || defenderTile.terrainFeature == "Forest" || defenderTile.terrainFeature == "Jungle" - for (BDM in getBattleDamageModifiersOfUnit(defender.unit)) { - val text = BDM.getText() - if (BDM.vs == "units in open terrain" && !isDefenderInRoughTerrain) { - if(modifiers.containsKey(text)) - modifiers[text] =modifiers[text]!! + BDM.modificationAmount - else modifiers[text] = BDM.modificationAmount - } - if (BDM.vs == "units in rough terrain" && isDefenderInRoughTerrain) { - if (modifiers.containsKey(text)) - modifiers[text] = modifiers[text]!! + BDM.modificationAmount - else modifiers[text] = BDM.modificationAmount - } + val defenderTile = defender.getTile() + val isDefenderInRoughTerrain = defenderTile.baseTerrain == "Hill" || defenderTile.terrainFeature == "Forest" || defenderTile.terrainFeature == "Jungle" + for (BDM in getBattleDamageModifiersOfUnit(defender.unit)) { + val text = BDM.getText() + if (BDM.vs == "units in open terrain" && !isDefenderInRoughTerrain) { + if (modifiers.containsKey(text)) + modifiers[text] = modifiers[text]!! + BDM.modificationAmount + else modifiers[text] = BDM.modificationAmount + } + if (BDM.vs == "units in rough terrain" && isDefenderInRoughTerrain) { + if (modifiers.containsKey(text)) + modifiers[text] = modifiers[text]!! + BDM.modificationAmount + else modifiers[text] = BDM.modificationAmount } } - if(defender is MapUnitCombatant && defender.unit.isFortified()) - modifiers["Fortification"]=0.2f*defender.unit.getFortificationTurns() + + if (defender.unit.isFortified()) + modifiers["Fortification"] = 0.2f * defender.unit.getFortificationTurns() return modifiers } @@ -133,7 +132,8 @@ class BattleDamage{ * Includes defence modifiers */ fun getDefendingStrength(attacker: ICombatant, defender: ICombatant): Float { - val defenceModifier = modifiersToMultiplicationBonus(getDefenceModifiers(attacker,defender)) + var defenceModifier = 1f + if(defender is MapUnitCombatant) defenceModifier = modifiersToMultiplicationBonus(getDefenceModifiers(attacker,defender)) return defender.getDefendingStrength(attacker) * defenceModifier } diff --git a/core/src/com/unciv/logic/battle/CityCombatant.kt b/core/src/com/unciv/logic/battle/CityCombatant.kt index 52e0074ca3..22974ebdcd 100644 --- a/core/src/com/unciv/logic/battle/CityCombatant.kt +++ b/core/src/com/unciv/logic/battle/CityCombatant.kt @@ -3,8 +3,8 @@ package com.unciv.logic.battle import com.unciv.logic.city.CityInfo import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.map.TileInfo -import com.unciv.models.gamebasics.unit.UnitType import com.unciv.models.gamebasics.GameBasics +import com.unciv.models.gamebasics.unit.UnitType class CityCombatant(val city: CityInfo) : ICombatant { override fun getHealth(): Int = city.health @@ -25,24 +25,29 @@ class CityCombatant(val city: CityInfo) : ICombatant { return getCityStrength() } - private fun - getCityStrength(): Int { - val baseStrength = 10 + private fun getCityStrength(): Int { // Civ fanatics forum, from a modder who went through the original code + var strength = 8f + if(city.isCapital()) strength+=2.5f + strength += (city.population.population/5) * 2 // Each 5 pop gives 2 defence + val cityTile = city.getCenterTile() + if(cityTile.baseTerrain=="Hill") strength+=5 // as tech progresses so does city strength val techsPercentKnown: Float = city.civInfo.tech.techsResearched.count().toFloat() / GameBasics.Technologies.count() - val strengthFromTechs = Math.pow(techsPercentKnown*3.0,2.0) *5 + strength += Math.pow(techsPercentKnown*5.5, 2.8).toFloat() // The way all of this adds up... - // 25% of the way through the game provides an extra 3.12 - // 50% of the way through the game provides an extra 12.50 - // 75% of the way through the game provides an extra 28.12 + // 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 - // 10% bonus foreach pop - val strengthWithPop = (baseStrength + strengthFromTechs) * (1 + 0.1*city.population.population) + // Garrisoned unit gives up to 20% of strength to city, health-dependant + if(cityTile.militaryUnit!=null) + strength += cityTile.militaryUnit!!.getBaseUnit().strength * cityTile.militaryUnit!!.health/100f - return strengthWithPop.toInt() + strength += city.cityConstructions.getBuiltBuildings().sumBy{ it.cityStrength } + + return strength.toInt() } override fun toString(): String {return city.name} // for debug diff --git a/core/src/com/unciv/logic/city/CityInfo.kt b/core/src/com/unciv/logic/city/CityInfo.kt index cf6d5f49f7..68b7f7ff35 100644 --- a/core/src/com/unciv/logic/city/CityInfo.kt +++ b/core/src/com/unciv/logic/city/CityInfo.kt @@ -142,15 +142,14 @@ class CityInfo { } } - val maxHealth =getMaxHealth() - health = min(health+maxHealth/10, maxHealth) + health = min(health+20, getMaxHealth()) population.unassignExtraPopulation() } fun isCapital() = cityConstructions.isBuilt("Palace") internal fun getMaxHealth(): Int { - return 200 // add more later when walls citadel etc. + return 200 + cityConstructions.getBuiltBuildings().sumBy { it.cityHealth } } override fun toString(): String {return name} // for debug diff --git a/core/src/com/unciv/models/gamebasics/Building.kt b/core/src/com/unciv/models/gamebasics/Building.kt index eb3e94fdb0..53ba9649e7 100644 --- a/core/src/com/unciv/models/gamebasics/Building.kt +++ b/core/src/com/unciv/models/gamebasics/Building.kt @@ -28,6 +28,8 @@ class Building : NamedStats(), IConstruction{ /** City can only be built if one of these resources is nearby - it must be improved! */ var requiredNearbyImprovedResources: List? = null var cannotBeBuiltWith: String? = null + var cityStrength=0 + var cityHealth=0 // Uniques var providesFreeBuilding: String? = null @@ -52,6 +54,8 @@ class Building : NamedStats(), IConstruction{ infoList += resourceBonusStats.toString() +" from "+improvedResources.joinToString() } if(unique!=null) infoList += unique!! + if(cityStrength!=0) infoList+="city strength +"+cityStrength + if(cityHealth!=0) infoList+="city health +"+cityHealth return infoList.joinToString() } @@ -123,6 +127,9 @@ class Building : NamedStats(), IConstruction{ val resources = GameBasics.TileResources.values.filter { name == it.building }.joinToString { it.name } stringBuilder.appendln("$resources provide $resourceBonusStats") } + + if(cityStrength!=0) stringBuilder.appendln("City strength +"+cityStrength) + if(cityHealth!=0) stringBuilder.appendln("City health +"+cityHealth) if (maintenance != 0) stringBuilder.appendln("Maintenance cost: $maintenance "+"Gold".tr()) return stringBuilder.toString().trim() diff --git a/core/src/com/unciv/ui/worldscreen/bottombar/BattleTable.kt b/core/src/com/unciv/ui/worldscreen/bottombar/BattleTable.kt index 7b417a7772..ca55dbf398 100644 --- a/core/src/com/unciv/ui/worldscreen/bottombar/BattleTable.kt +++ b/core/src/com/unciv/ui/worldscreen/bottombar/BattleTable.kt @@ -68,7 +68,9 @@ class BattleTable(val worldScreen: WorldScreen): Table() { row().pad(5f) val attackerModifiers = BattleDamage().getAttackModifiers(attacker,defender) .map { it.key+": "+(if(it.value>0)"+" else "")+(it.value*100).toInt()+"%" } - val defenderModifiers = BattleDamage().getDefenceModifiers(attacker, defender).map { it.key+": "+(if(it.value>0)"+" else "")+(it.value*100).toInt()+"%" } + val defenderModifiers = if (defender is MapUnitCombatant) + BattleDamage().getDefenceModifiers(attacker, defender).map { it.key+": "+(if(it.value>0)"+" else "")+(it.value*100).toInt()+"%" } + else listOf() for(i in 0..max(attackerModifiers.size,defenderModifiers.size)){ if (attackerModifiers.size > i) add(attackerModifiers[i]).actor.setFont(14) else add()