Resolved #3476 - captured civilian units can no longer move on the same turn

This commit is contained in:
Yair Morgenstern
2020-12-29 19:57:28 +02:00
parent 03ddd3c410
commit 2ff345b6a6

View File

@ -21,7 +21,7 @@ import kotlin.math.max
*/
object Battle {
fun moveAndAttack(attacker: ICombatant, attackableTile: AttackableTile){
fun moveAndAttack(attacker: ICombatant, attackableTile: AttackableTile) {
if (attacker is MapUnitCombatant) {
attacker.unit.movement.moveToTile(attackableTile.tileToAttackFrom)
if (attacker.unit.hasUnique("Must set up to ranged attack") && attacker.unit.action != Constants.unitActionSetUp) {
@ -38,18 +38,18 @@ object Battle {
fun attack(attacker: ICombatant, defender: ICombatant) {
if (UncivGame.Current.alertBattle) {
println(attacker.getCivInfo().civName+" "+attacker.getName()+" attacked "+
defender.getCivInfo().civName+" "+defender.getName())
println(attacker.getCivInfo().civName + " " + attacker.getName() + " attacked " +
defender.getCivInfo().civName + " " + defender.getName())
}
val attackedTile = defender.getTile()
if(attacker is MapUnitCombatant && attacker.getUnitType().isAirUnit()) {
if (attacker is MapUnitCombatant && attacker.getUnitType().isAirUnit()) {
tryInterceptAirAttack(attacker, defender)
if (attacker.isDefeated()) return
}
// 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.getMatchingUniques("May withdraw before melee ([]%)").firstOrNull()
if (withdraw != null && doWithdrawFromMeleeAbility(attacker, defender, withdraw)) return
}
@ -71,7 +71,7 @@ object Battle {
reduceAttackerMovementPointsAndAttacks(attacker, defender)
if(!isAlreadyDefeatedCity) postBattleAddXp(attacker, defender)
if (!isAlreadyDefeatedCity) postBattleAddXp(attacker, defender)
// Add culture when defeating a barbarian when Honor policy is adopted, gold from enemy killed when honor is complete
// or any enemy military unit with Sacrificial captives unique (can be either attacker or defender!)
@ -91,7 +91,7 @@ object Battle {
}
}
private fun tryEarnFromKilling(civUnit:ICombatant, defeatedUnit:MapUnitCombatant){
private fun tryEarnFromKilling(civUnit: ICombatant, defeatedUnit: MapUnitCombatant) {
val unitStr = max(defeatedUnit.unit.baseUnit.strength, defeatedUnit.unit.baseUnit.rangedStrength)
val unitCost = defeatedUnit.unit.baseUnit.cost
val bonusUniquePlaceholderText = "Earn []% of [] opponent's [] as [] for kills"
@ -132,7 +132,7 @@ object Battle {
var damageToAttacker = BattleDamage.calculateDamageToAttacker(attacker, attacker.getTile(), defender)
if (defender.getUnitType().isCivilian() && attacker.isMelee()) {
captureCivilianUnit(attacker, defender)
captureCivilianUnit(attacker, defender as MapUnitCombatant)
} else if (attacker.isRanged()) {
defender.takeDamage(damageToDefender) // straight up
} else {
@ -251,22 +251,22 @@ object Battle {
}
// XP!
private fun addXp(thisCombatant:ICombatant, amount:Int, otherCombatant:ICombatant){
if(thisCombatant !is MapUnitCombatant) return
if(thisCombatant.unit.promotions.totalXpProduced() >= thisCombatant.unit.civInfo.gameInfo.ruleSet.modOptions.maxXPfromBarbarians
private fun addXp(thisCombatant: ICombatant, amount: Int, otherCombatant: ICombatant) {
if (thisCombatant !is MapUnitCombatant) return
if (thisCombatant.unit.promotions.totalXpProduced() >= thisCombatant.unit.civInfo.gameInfo.ruleSet.modOptions.maxXPfromBarbarians
&& otherCombatant.getCivInfo().isBarbarian())
return
var XPModifier = 1f
if (thisCombatant.getCivInfo().hasUnique("Military units gain 50% more Experience from combat")) XPModifier += 0.5f
for (unique in thisCombatant.unit.getMatchingUniques("[]% Bonus XP gain"))
XPModifier += unique.params[0].toFloat() / 100
XPModifier += unique.params[0].toFloat() / 100
val XPGained = (amount * XPModifier).toInt()
thisCombatant.unit.promotions.XP += XPGained
if(thisCombatant.getCivInfo().isMajorCiv()) {
if (thisCombatant.getCivInfo().isMajorCiv()) {
var greatGeneralPointsModifier = 1f
val unitUniques = thisCombatant.unit.getMatchingUniques("[] is earned []% faster")
val civUniques = thisCombatant.getCivInfo().getMatchingUniques("[] is earned []% faster")
@ -311,17 +311,17 @@ object Battle {
}
}
fun getMapCombatantOfTile(tile:TileInfo): ICombatant? {
fun getMapCombatantOfTile(tile: TileInfo): ICombatant? {
if (tile.isCityCenter()) return CityCombatant(tile.getCity()!!)
if (tile.militaryUnit != null) return MapUnitCombatant(tile.militaryUnit!!)
if (tile.civilianUnit != null) return MapUnitCombatant(tile.civilianUnit!!)
return null
}
private fun captureCivilianUnit(attacker: ICombatant, defender: ICombatant){
private fun captureCivilianUnit(attacker: ICombatant, defender: MapUnitCombatant) {
// barbarians don't capture civilians
if(attacker.getCivInfo().isBarbarian()
||(defender as MapUnitCombatant).unit.hasUnique("Uncapturable")){
if (attacker.getCivInfo().isBarbarian()
|| (defender as MapUnitCombatant).unit.hasUnique("Uncapturable")) {
defender.takeDamage(100)
return
}
@ -330,25 +330,25 @@ object Battle {
val defenderCiv = defender.getCivInfo()
val capturedUnit = defender.unit
capturedUnit.civInfo.addNotification("An enemy ["+attacker.getName()+"] has captured our ["+defender.getName()+"]",
capturedUnit.civInfo.addNotification("An enemy [" + attacker.getName() + "] has captured our [" + defender.getName() + "]",
defender.getTile().position, Color.RED)
// Apparently in Civ V, captured settlers are converted to workers.
if(capturedUnit.name==Constants.settler) {
if (capturedUnit.name == Constants.settler) {
val tile = capturedUnit.getTile()
capturedUnit.destroy()
attacker.getCivInfo().placeUnitNearTile(tile.position, Constants.worker)
}
else {
} else {
capturedUnit.civInfo.removeUnit(capturedUnit)
capturedUnit.assignOwner(attacker.getCivInfo())
capturedUnit.currentMovement = 0f
}
destroyIfDefeated(defenderCiv, attacker.getCivInfo())
capturedUnit.updateVisibleTiles()
}
fun destroyIfDefeated(attackedCiv:CivilizationInfo, attacker: CivilizationInfo){
fun destroyIfDefeated(attackedCiv: CivilizationInfo, attacker: CivilizationInfo) {
if (attackedCiv.isDefeated()) {
attackedCiv.destroy()
attacker.popupAlerts.add(PopupAlert(AlertType.Defeated, attackedCiv.civName))
@ -366,11 +366,11 @@ object Battle {
if (city.population.population <= 5 && !city.isOriginalCapital) {
city.destroyCity()
} else {
city.population.population = max(city.population.population-5, 1)
city.population.population = max(city.population.population - 5, 1)
city.population.unassignExtraPopulation()
continue
}
destroyIfDefeated(city.civInfo,attackingCiv)
destroyIfDefeated(city.civInfo, attackingCiv)
}
fun declareWar(civSuffered: CivilizationInfo) {
@ -381,7 +381,7 @@ object Battle {
}
}
for(unit in tile.getUnits()){
for (unit in tile.getUnits()) {
unit.destroy()
postBattleNotifications(attacker, MapUnitCombatant(unit), unit.currentTile)
declareWar(unit.civInfo)
@ -399,16 +399,16 @@ object Battle {
if (tile.isLand && !tile.isImpassible()) tile.terrainFeature = "Fallout"
}
for(civ in attacker.getCivInfo().getKnownCivs()){
for (civ in attacker.getCivInfo().getKnownCivs()) {
civ.getDiplomacyManager(attackingCiv)
.setModifier(DiplomaticModifiers.UsedNuclearWeapons,-50f)
.setModifier(DiplomaticModifiers.UsedNuclearWeapons, -50f)
}
// Instead of postBattleAction() just destroy the missile, all other functions are not relevant
(attacker as MapUnitCombatant).unit.destroy()
}
private fun tryInterceptAirAttack(attacker:MapUnitCombatant, defender: ICombatant) {
private fun tryInterceptAirAttack(attacker: MapUnitCombatant, defender: ICombatant) {
val attackedTile = defender.getTile()
for (interceptor in defender.getCivInfo().getCivUnits().filter { it.canIntercept(attackedTile) }) {
if (Random().nextFloat() > 100f / interceptor.interceptChance()) continue
@ -426,17 +426,17 @@ object Battle {
if (attacker.isDefeated()) {
attacker.getCivInfo()
.addNotification("Our [$attackerName] was destroyed by an intercepting [$interceptorName]",
Color.RED)
Color.RED)
defender.getCivInfo()
.addNotification("Our [$interceptorName] intercepted and destroyed an enemy [$attackerName]",
interceptor.currentTile.position, Color.RED)
interceptor.currentTile.position, Color.RED)
} else {
attacker.getCivInfo()
.addNotification("Our [$attackerName] was attacked by an intercepting [$interceptorName]",
Color.RED)
Color.RED)
defender.getCivInfo()
.addNotification("Our [$interceptorName] intercepted and attacked an enemy [$attackerName]",
interceptor.currentTile.position, Color.RED)
interceptor.currentTile.position, Color.RED)
}
return
}
@ -460,8 +460,8 @@ object Battle {
val defendBaseUnit = defender.unit.baseUnit
val baseChance = withdrawUnique.params[0].toFloat()
val percentChance = (baseChance
* defendBaseUnit.strength / attackBaseUnit.strength
* defendBaseUnit.movement / attackBaseUnit.movement).toInt()
* defendBaseUnit.strength / attackBaseUnit.strength
* defendBaseUnit.movement / attackBaseUnit.movement).toInt()
// Roll the dice - note the effect of the surroundings, namely how much room there is to evade to,
// isn't yet factored in. But it should, and that's factored in by allowing the dice to choose
// any geometrically fitting tile first and *then* fail when checking the tile for viability.
@ -494,11 +494,11 @@ object Battle {
defender.unit.removeFromTile()
defender.unit.putInTile(toTile)
// and count 1 attack for attacker but leave it in place
reduceAttackerMovementPointsAndAttacks(attacker,defender)
reduceAttackerMovementPointsAndAttacks(attacker, defender)
val notificationString = "[" + defendBaseUnit.name + "] withdrew from a [" + attackBaseUnit.name + "]"
defender.getCivInfo().addNotification(notificationString, toTile.position, Color.GREEN)
attacker.getCivInfo().addNotification(notificationString, toTile.position, Color.RED)
return true
}
}
}