From 56f4d2d57b37bf05a5bd99ed1751f0b678809938 Mon Sep 17 00:00:00 2001 From: Duan Tao Date: Wed, 25 Sep 2019 11:08:26 +0800 Subject: [PATCH 1/6] Annexed city from puppet status should not be in resistance. --- core/src/com/unciv/ui/cityscreen/CityScreen.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/src/com/unciv/ui/cityscreen/CityScreen.kt b/core/src/com/unciv/ui/cityscreen/CityScreen.kt index 99de1b85..135e2277 100644 --- a/core/src/com/unciv/ui/cityscreen/CityScreen.kt +++ b/core/src/com/unciv/ui/cityscreen/CityScreen.kt @@ -168,9 +168,13 @@ class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() { val annexCityButton = TextButton("Annex city".tr(), skin) annexCityButton.labelCell.pad(10f) annexCityButton.onClick { + if(!city.civInfo.policies.isAdopted("Police State")) { + city.expansion.cultureStored = 0 + city.expansion.reset() + } + city.isPuppet=false city.isBeingRazed=false - city.resistanceCounter = city.population.population update() } razeCityButtonHolder.add(annexCityButton).colspan(cityPickerTable.columns) From e511385d12a86858b2f179191dabf729fad6b62f Mon Sep 17 00:00:00 2001 From: Duan Tao Date: Wed, 25 Sep 2019 12:22:37 +0800 Subject: [PATCH 2/6] Fix a bug that causes exception when selecting special construction. --- core/src/com/unciv/logic/city/CityConstructions.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/src/com/unciv/logic/city/CityConstructions.kt b/core/src/com/unciv/logic/city/CityConstructions.kt index e10d33d0..1010e4ae 100644 --- a/core/src/com/unciv/logic/city/CityConstructions.kt +++ b/core/src/com/unciv/logic/city/CityConstructions.kt @@ -115,8 +115,11 @@ class CityConstructions { else return 0 } - fun getRemainingWork(constructionName: String) = - getConstruction(constructionName).getProductionCost(cityInfo.civInfo) - getWorkDone(constructionName) + fun getRemainingWork(constructionName: String): Int { + val constr = getConstruction(constructionName) + if (constr is SpecialConstruction) return 0 + return constr.getProductionCost(cityInfo.civInfo) - getWorkDone(constructionName) + } fun turnsToConstruction(constructionName: String): Int { val workLeft = getRemainingWork(constructionName) From 4ca32a052326d4d0c7c61c870cdb16b0042fd83f Mon Sep 17 00:00:00 2001 From: Duan Tao Date: Wed, 25 Sep 2019 18:57:47 +0800 Subject: [PATCH 3/6] Fix a code style bug that caused exception mentioned in last commit. --- core/src/com/unciv/logic/city/CityConstructions.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/com/unciv/logic/city/CityConstructions.kt b/core/src/com/unciv/logic/city/CityConstructions.kt index 1010e4ae..5fcf4467 100644 --- a/core/src/com/unciv/logic/city/CityConstructions.kt +++ b/core/src/com/unciv/logic/city/CityConstructions.kt @@ -61,9 +61,10 @@ class CityConstructions { val currentConstructionSnapshot = currentConstruction // See below var result = currentConstructionSnapshot.tr() if (currentConstructionSnapshot!="" - && SpecialConstruction.getSpecialConstructions().none { it.name==currentConstructionSnapshot }) + && SpecialConstruction.getSpecialConstructions().none { it.name==currentConstructionSnapshot }) { result += ("\r\nCost " + getConstruction(currentConstruction).getProductionCost(cityInfo.civInfo).toString()).tr() - result += "\r\n" + turnsToConstruction(currentConstructionSnapshot ) + " {turns}".tr() + result += "\r\n" + turnsToConstruction(currentConstructionSnapshot) + " {turns}".tr() + } return result } From fc5c7235c5c019e20183eae21791c31f823dbd56 Mon Sep 17 00:00:00 2001 From: Duan Tao Date: Wed, 25 Sep 2019 23:27:55 +0800 Subject: [PATCH 4/6] Minor code reorg. Adjust tech trade value with game speed. --- core/src/com/unciv/logic/city/CityInfo.kt | 9 ++++----- core/src/com/unciv/logic/trade/TradeEvaluation.kt | 4 +++- core/src/com/unciv/ui/cityscreen/CityScreen.kt | 8 +------- core/src/com/unciv/ui/worldscreen/AlertPopup.kt | 6 ++++-- 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/core/src/com/unciv/logic/city/CityInfo.kt b/core/src/com/unciv/logic/city/CityInfo.kt index e3973308..1ce46fa3 100644 --- a/core/src/com/unciv/logic/city/CityInfo.kt +++ b/core/src/com/unciv/logic/city/CityInfo.kt @@ -271,10 +271,8 @@ class CityInfo { getCenterTile().improvement="City ruins" } - fun annexCity(conqueringCiv: CivilizationInfo) { - puppetCity(conqueringCiv) - - if(!conqueringCiv.policies.isAdopted("Police State")) { + fun annexCity() { + if(!civInfo.policies.isAdopted("Police State")) { expansion.cultureStored = 0 expansion.reset() } @@ -327,7 +325,8 @@ class CityInfo { /* Liberating is returning a city to its founder - makes you LOSE warmongering points **/ fun liberateCity(conqueringCiv: CivilizationInfo) { if (foundingCiv == "") { // this should never happen but just in case... - annexCity(conqueringCiv) + puppetCity(conqueringCiv) + annexCity() return } diff --git a/core/src/com/unciv/logic/trade/TradeEvaluation.kt b/core/src/com/unciv/logic/trade/TradeEvaluation.kt index f9b7aaff..1a6d5598 100644 --- a/core/src/com/unciv/logic/trade/TradeEvaluation.kt +++ b/core/src/com/unciv/logic/trade/TradeEvaluation.kt @@ -117,7 +117,9 @@ class TradeEvaluation{ return 50 * amountToBuyInOffer } - TradeType.Technology -> return sqrt(GameBasics.Technologies[offer.name]!!.cost.toDouble()).toInt()*20 + TradeType.Technology -> + return (sqrt(GameBasics.Technologies[offer.name]!!.cost.toDouble()) + * civInfo.gameInfo.gameParameters.gameSpeed.getModifier()).toInt()*20 TradeType.Introduction -> return 250 TradeType.WarDeclaration -> { val nameOfCivToDeclareWarOn = offer.name.removePrefix("Declare war on ") diff --git a/core/src/com/unciv/ui/cityscreen/CityScreen.kt b/core/src/com/unciv/ui/cityscreen/CityScreen.kt index 135e2277..c9ab3118 100644 --- a/core/src/com/unciv/ui/cityscreen/CityScreen.kt +++ b/core/src/com/unciv/ui/cityscreen/CityScreen.kt @@ -168,13 +168,7 @@ class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() { val annexCityButton = TextButton("Annex city".tr(), skin) annexCityButton.labelCell.pad(10f) annexCityButton.onClick { - if(!city.civInfo.policies.isAdopted("Police State")) { - city.expansion.cultureStored = 0 - city.expansion.reset() - } - - city.isPuppet=false - city.isBeingRazed=false + city.annexCity() update() } razeCityButtonHolder.add(annexCityButton).colspan(cityPickerTable.columns) diff --git a/core/src/com/unciv/ui/worldscreen/AlertPopup.kt b/core/src/com/unciv/ui/worldscreen/AlertPopup.kt index feb9099c..8460ef58 100644 --- a/core/src/com/unciv/ui/worldscreen/AlertPopup.kt +++ b/core/src/com/unciv/ui/worldscreen/AlertPopup.kt @@ -72,7 +72,8 @@ class AlertPopup(val worldScreen: WorldScreen, val popupAlert: PopupAlert): Popu }).row() } add(TextButton("Annex".tr(), skin).onClick { - city.annexCity(conqueringCiv) + city.puppetCity(conqueringCiv) + city.annexCity() worldScreen.shouldUpdate=true close() }).row() @@ -82,7 +83,8 @@ class AlertPopup(val worldScreen: WorldScreen, val popupAlert: PopupAlert): Popu close() }).row() add(TextButton("Raze".tr(), skin).onClick { - city.annexCity(conqueringCiv) + city.puppetCity(conqueringCiv) + city.annexCity() city.isBeingRazed = true worldScreen.shouldUpdate=true close() From f714dd197c884836b03af564256c03adaa26126f Mon Sep 17 00:00:00 2001 From: Duan Tao Date: Wed, 25 Sep 2019 23:32:18 +0800 Subject: [PATCH 5/6] AI bonus starting units should not provide city-states settlers. --- core/src/com/unciv/logic/GameStarter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/com/unciv/logic/GameStarter.kt b/core/src/com/unciv/logic/GameStarter.kt index 88cd0c09..9f906728 100644 --- a/core/src/com/unciv/logic/GameStarter.kt +++ b/core/src/com/unciv/logic/GameStarter.kt @@ -77,7 +77,7 @@ class GameStarter{ civ.placeUnitNearTile(startingLocation.position, "Warrior") civ.placeUnitNearTile(startingLocation.position, "Scout") - if (!civ.isPlayerCivilization()) { + if (!civ.isPlayerCivilization() && civ.isMajorCiv()) { for (unit in gameInfo.getDifficulty().aiFreeUnits) { civ.placeUnitNearTile(startingLocation.position, unit) } From 98f780be93538cab44b085e9f7bf8a5afdc2331e Mon Sep 17 00:00:00 2001 From: Yair Morgenstern Date: Wed, 25 Sep 2019 22:26:07 +0300 Subject: [PATCH 6/6] Attacking unit now enters enemy city before you decide what to do with it - #1123 --- android/build.gradle | 2 +- core/src/com/unciv/logic/battle/Battle.kt | 88 +++++++++++-------- core/src/com/unciv/logic/city/CityInfo.kt | 2 + .../unciv/logic/map/UnitMovementAlgorithms.kt | 4 +- 4 files changed, 58 insertions(+), 38 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 832f4358..31a2514f 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -22,7 +22,7 @@ android { minSdkVersion 14 targetSdkVersion 29 versionCode 301 - versionName "3.1.0" + versionName "3.1.0-patch1" } // Had to add this crap for Travis to build, it wanted to sign the app diff --git a/core/src/com/unciv/logic/battle/Battle.kt b/core/src/com/unciv/logic/battle/Battle.kt index 55f032a9..2809b04d 100644 --- a/core/src/com/unciv/logic/battle/Battle.kt +++ b/core/src/com/unciv/logic/battle/Battle.kt @@ -67,6 +67,37 @@ class Battle(val gameInfo:GameInfo) { private fun postBattleAction(attacker: ICombatant, defender: ICombatant, attackedTile:TileInfo) { + postBattleNotifications(attacker, defender, attackedTile) + + tryHealAfterAttacking(attacker, defender) + + postBattleNationUniques(defender, attackedTile, attacker) + + // This needs to come BEFORE the move-to-tile, because if we haven't conquered it we can't move there =) + if (defender.isDefeated() && defender is CityCombatant && attacker.isMelee()) + conquerCity(defender.city, attacker) + + // we're a melee unit and we destroyed\captured an enemy unit + postBattleMoveToAttackedTile(attacker, defender, attackedTile) + + reduceAttackerMovementPointsAndAttacks(attacker, defender) + + postBattleAddXp(attacker, defender) + + // Add culture when defeating a barbarian when Honor policy is adopted (can be either attacker or defender!) + tryGetCultureFromHonor(attacker, defender) + tryGetCultureFromHonor(defender, attacker) + + if (defender.isDefeated() && defender is MapUnitCombatant && !defender.getUnitType().isCivilian() + && attacker.getCivInfo().policies.isAdopted("Honor Complete")) + attacker.getCivInfo().gold += defender.unit.baseUnit.getProductionCost(attacker.getCivInfo()) / 10 + + if (attacker is MapUnitCombatant && attacker.unit.action != null + && attacker.unit.action!!.startsWith("moveTo")) + attacker.unit.action = null + } + + private fun postBattleNotifications(attacker: ICombatant, defender: ICombatant, attackedTile: TileInfo) { if (attacker.getCivInfo() != defender.getCivInfo()) { // If what happened was that a civilian unit was captures, that's dealt with in the CaptureCilvilianUnit function val whatHappenedString = if (attacker !is CityCombatant && attacker.isDefeated()) " {was destroyed while attacking}" @@ -80,8 +111,9 @@ class Battle(val gameInfo:GameInfo) { val notificationString = attackerString + whatHappenedString + defenderString defender.getCivInfo().addNotification(notificationString, attackedTile.position, Color.RED) } + } - // Units that heal when killing + private fun tryHealAfterAttacking(attacker: ICombatant, defender: ICombatant) { if (defender.isDefeated() && defender is MapUnitCombatant && attacker is MapUnitCombatant) { @@ -93,8 +125,9 @@ class Battle(val gameInfo:GameInfo) { attacker.unit.healBy(amountToHeal) } } + } - + private fun postBattleNationUniques(defender: ICombatant, attackedTile: TileInfo, attacker: ICombatant) { // German unique - needs to be checked before we try to move to the enemy tile, since the encampment disappears after we move in if (defender.isDefeated() && defender.getCivInfo().isBarbarian() && attackedTile.improvement == Constants.barbarianEncampment @@ -111,9 +144,10 @@ class Battle(val gameInfo:GameInfo) { && Random().nextDouble() > 0.33) { attacker.getCivInfo().placeUnitNearTile(attackedTile.position, defender.getName()) } + } - // we're a melee unit and we destroyed\captured an enemy unit - else if (attacker.isMelee() + private fun postBattleMoveToAttackedTile(attacker: ICombatant, defender: ICombatant, attackedTile: TileInfo) { + if (attacker.isMelee() && (defender.isDefeated() || defender.getCivInfo() == attacker.getCivInfo()) // This is so that if we attack e.g. a barbarian in enemy territory that we can't enter, we won't enter it && (attacker as MapUnitCombatant).unit.movement.canMoveTo(attackedTile)) { @@ -122,8 +156,22 @@ class Battle(val gameInfo:GameInfo) { captureCivilianUnit(attacker, MapUnitCombatant(attackedTile.civilianUnit!!)) attacker.unit.movement.moveToTile(attackedTile) } + } + private fun postBattleAddXp(attacker: ICombatant, defender: ICombatant) { + if (attacker.isMelee()) { + if (!defender.getUnitType().isCivilian()) // unit was not captured but actually attacked + { + addXp(attacker, 5, defender) + addXp(defender, 4, attacker) + } + } else { // ranged attack + addXp(attacker, 2, defender) + addXp(defender, 2, attacker) + } + } + private fun reduceAttackerMovementPointsAndAttacks(attacker: ICombatant, defender: ICombatant) { if (attacker is MapUnitCombatant) { val unit = attacker.unit if (unit.hasUnique("Can move after attacking") @@ -140,37 +188,6 @@ class Battle(val gameInfo:GameInfo) { } else if (attacker is CityCombatant) { attacker.city.attackedThisTurn = true } - - - if (defender.isDefeated() - && defender is CityCombatant - && attacker.isMelee()) - conquerCity(defender.city, attacker) - - - if (attacker.isMelee()) { - if (!defender.getUnitType().isCivilian()) // unit was not captured but actually attacked - { - addXp(attacker, 5, defender) - addXp(defender, 4, attacker) - } - } else { // ranged attack - addXp(attacker, 2, defender) - addXp(defender, 2, attacker) - } - - - // Add culture when defeating a barbarian when Honor policy is adopted (can be either attacker or defender!) - tryGetCultureFromHonor(attacker, defender) - tryGetCultureFromHonor(defender, attacker) - - if (defender.isDefeated() && defender is MapUnitCombatant && !defender.getUnitType().isCivilian() - && attacker.getCivInfo().policies.isAdopted("Honor Complete")) - attacker.getCivInfo().gold += defender.unit.baseUnit.getProductionCost(attacker.getCivInfo()) / 10 - - if (attacker is MapUnitCombatant && attacker.unit.action != null - && attacker.unit.action!!.startsWith("moveTo")) - attacker.unit.action = null } private fun tryGetCultureFromHonor(civUnit:ICombatant, barbarianUnit:ICombatant){ @@ -209,6 +226,7 @@ class Battle(val gameInfo:GameInfo) { if(civilianUnit!=null) captureCivilianUnit(attacker, MapUnitCombatant(civilianUnit!!)) for(airUnit in airUnits.toList()) airUnit.destroy() } + city.hasJustBeenConquered = true if (attacker.getCivInfo().isPlayerCivilization()) attackerCiv.popupAlerts.add(PopupAlert(AlertType.CityConquered, city.name)) diff --git a/core/src/com/unciv/logic/city/CityInfo.kt b/core/src/com/unciv/logic/city/CityInfo.kt index 1ce46fa3..144632c8 100644 --- a/core/src/com/unciv/logic/city/CityInfo.kt +++ b/core/src/com/unciv/logic/city/CityInfo.kt @@ -26,6 +26,7 @@ class CityInfo { @Transient val range = 2 @Transient lateinit var tileMap: TileMap @Transient lateinit var tilesInRange:HashSet + @Transient var hasJustBeenConquered = false // this is so that military units can enter the city, even before we decide what to do with it var location: Vector2 = Vector2.Zero var name: String = "" @@ -366,6 +367,7 @@ class CityInfo { civInfo.cities = civInfo.cities.toMutableList().apply { remove(this@CityInfo) } newCivInfo.cities = newCivInfo.cities.toMutableList().apply { add(this@CityInfo) } civInfo = newCivInfo + hasJustBeenConquered=false // now that the tiles have changed, we need to reassign population workedTiles.filterNot { tiles.contains(it) } diff --git a/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt b/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt index c0571212..ccad22d5 100644 --- a/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt +++ b/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt @@ -228,7 +228,7 @@ class UnitMovementAlgorithms(val unit:MapUnit) { if (!distanceToTiles.containsKey(destination)) throw YouCantGetThereFromHereException("$unit can't get from ${unit.currentTile.position} to ${destination.position}.") - if(destination.isCityCenter() && destination.getOwner()!=unit.civInfo) + if(destination.isCityCenter() && destination.getOwner()!=unit.civInfo && !destination.getCity()!!.hasJustBeenConquered) throw Exception("This is an enemy city, you can't go here!") unit.currentMovement -= distanceToTiles[destination]!!.totalDistance @@ -290,7 +290,7 @@ class UnitMovementAlgorithms(val unit:MapUnit) { val tileOwner = tile.getOwner() if(tileOwner!=null && tileOwner.civName!=unit.owner) { - if (tile.isCityCenter()) return false + if (tile.isCityCenter() && !tile.getCity()!!.hasJustBeenConquered) return false if (!unit.civInfo.canEnterTiles(tileOwner) && !(unit.civInfo.isPlayerCivilization() && tileOwner.isCityState())) return false // AIs won't enter city-state's border.