mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-22 10:54:19 -04:00
Citadel improvements + improved AI for the forts (#2453)
* Allow building the citadels either next to or within friendly tiles only * Citadel acquire the tiles around it * AI uses the citadels to get the tiles back + improved AI for the forts
This commit is contained in:
parent
d4ef5cb637
commit
77a63ce365
@ -109,6 +109,7 @@ You fulfilled your promise to stop settling cities near us! =
|
||||
You refused to stop settling cities near us =
|
||||
Your arrogant demands are in bad taste =
|
||||
Your use of nuclear weapons is disgusting! =
|
||||
You have stolen our lands! =
|
||||
|
||||
Demands =
|
||||
Please don't settle new cities near us. =
|
||||
@ -240,6 +241,8 @@ Mongol Terror =
|
||||
|
||||
Units ignore terrain costs when moving into any tile with Hills. No maintenance costs for improvements in Hills; half cost elsewhere. =
|
||||
Great Andean Road =
|
||||
|
||||
+1 Movement to all embarked units, units pay only 1 movement point to embark and disembark. Melee units pay no movement cost to pillage. =
|
||||
Viking Fury =
|
||||
|
||||
# New game screen
|
||||
@ -484,6 +487,7 @@ Our proposed trade request is no longer relevant! =
|
||||
[defender] could not withdraw from a [attacker] - blocked. =
|
||||
[defender] withdrew from a [attacker] =
|
||||
[building] has provided [amount] Gold! =
|
||||
[civName] has stolen your territory! =
|
||||
|
||||
|
||||
# World Screen UI
|
||||
|
@ -1,9 +1,10 @@
|
||||
package com.unciv.logic.automation
|
||||
package com.unciv.logic.automation
|
||||
|
||||
import com.unciv.logic.battle.MapUnitCombatant
|
||||
import com.unciv.logic.civilization.CivilizationInfo
|
||||
import com.unciv.logic.civilization.GreatPersonManager
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomaticModifiers
|
||||
import com.unciv.logic.map.MapUnit
|
||||
import com.unciv.logic.map.TileInfo
|
||||
import com.unciv.models.ruleset.tile.ResourceType
|
||||
@ -59,9 +60,37 @@ object SpecificUnitAutomation {
|
||||
return
|
||||
}
|
||||
|
||||
// try to build a citadel
|
||||
if (WorkerAutomation(unit).evaluateFortPlacement(unit.currentTile, unit.civInfo))
|
||||
// try to revenge and capture their tiles
|
||||
val enemyCities = unit.civInfo.gameInfo.civilizations
|
||||
.filter { unit.civInfo.knows(it) &&
|
||||
unit.civInfo.getDiplomacyManager(it).hasModifier(DiplomaticModifiers.StealingTerritory) }
|
||||
.flatMap { it.cities }.asSequence()
|
||||
// find the suitable tiles (or their neigbours)
|
||||
val tileToSteal = enemyCities.flatMap { it.getTiles() }.flatMap { it.neighbors.asSequence() }
|
||||
.filter { it in unit.civInfo.viewableTiles // we can see them
|
||||
&& unit.movement.canReach(it) // we can reach it
|
||||
&& it.neighbors.any { tile -> tile.getOwner() == unit.civInfo} } // they are close to our borders
|
||||
.sortedBy {
|
||||
// get closest tiles
|
||||
val distance = it.aerialDistanceTo(unit.currentTile)
|
||||
// ...also get priorities to steal the most valuable for them
|
||||
val owner = it.getOwner()
|
||||
if (owner != null)
|
||||
distance - WorkerAutomation(unit).getPriority(it, owner)
|
||||
else distance }.firstOrNull()
|
||||
// if there is a good tile to steal - go there
|
||||
if (tileToSteal != null) {
|
||||
unit.movement.headTowards(tileToSteal)
|
||||
if (unit.currentMovement > 0 && unit.currentTile == tileToSteal)
|
||||
UnitActions.getBuildImprovementAction(unit)?.action?.invoke()
|
||||
return
|
||||
}
|
||||
|
||||
// try to build a citadel
|
||||
if (WorkerAutomation(unit).evaluateFortPlacement(unit.currentTile, unit.civInfo, true)) {
|
||||
UnitActions.getBuildImprovementAction(unit)?.action?.invoke()
|
||||
return
|
||||
}
|
||||
|
||||
//if no unit to follow, take refuge in city or build citadel there.
|
||||
val reachableTest : (TileInfo) -> Boolean = {it.civilianUnit == null &&
|
||||
@ -75,10 +104,12 @@ object SpecificUnitAutomation {
|
||||
// try to find a good place for citadel nearby
|
||||
val potentialTilesNearCity = cityToGarrison.getTilesInDistanceRange(3..4)
|
||||
val tileForCitadel = potentialTilesNearCity.firstOrNull { reachableTest(it) &&
|
||||
WorkerAutomation(unit).evaluateFortPlacement(it, unit.civInfo) }
|
||||
if (tileForCitadel != null)
|
||||
WorkerAutomation(unit).evaluateFortPlacement(it, unit.civInfo, true) }
|
||||
if (tileForCitadel != null) {
|
||||
unit.movement.headTowards(tileForCitadel)
|
||||
else
|
||||
if (unit.currentMovement > 0 && unit.currentTile == tileForCitadel)
|
||||
UnitActions.getBuildImprovementAction(unit)?.action?.invoke()
|
||||
} else
|
||||
unit.movement.headTowards(cityToGarrison)
|
||||
return
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ class WorkerAutomation(val unit: MapUnit) {
|
||||
return false // cou;dn't find anything to construct here
|
||||
}
|
||||
|
||||
private fun getPriority(tileInfo: TileInfo, civInfo: CivilizationInfo): Int {
|
||||
fun getPriority(tileInfo: TileInfo, civInfo: CivilizationInfo): Int {
|
||||
var priority = 0
|
||||
if (tileInfo.getOwner() == civInfo){
|
||||
priority += 2
|
||||
@ -195,7 +195,7 @@ class WorkerAutomation(val unit: MapUnit) {
|
||||
|
||||
// Defence is more important that civilian improvements
|
||||
// While AI sucks in strategical placement of forts, allow a human does it manually
|
||||
!civInfo.isPlayerCivilization() && evaluateFortPlacement(tile,civInfo) -> Constants.fort
|
||||
!civInfo.isPlayerCivilization() && evaluateFortPlacement(tile,civInfo,false) -> Constants.fort
|
||||
// I think we can assume that the unique improvement is better
|
||||
uniqueImprovement!=null && tile.canBuildImprovement(uniqueImprovement,civInfo) -> uniqueImprovement.name
|
||||
|
||||
@ -226,21 +226,21 @@ class WorkerAutomation(val unit: MapUnit) {
|
||||
|
||||
private fun isAcceptableTileForFort(tile: TileInfo, civInfo: CivilizationInfo): Boolean
|
||||
{
|
||||
// don't build fort in the city
|
||||
if (tile.isCityCenter()) return false
|
||||
// don't build fort if it is already here
|
||||
if (tile.improvement == Constants.fort) return false
|
||||
// don't build on resource tiles
|
||||
if (tile.hasViewableResource(civInfo)) return false
|
||||
// don't build on great improvements
|
||||
if (tile.containsGreatImprovement() || tile.containsUnfinishedGreatImprovement()) return false
|
||||
if (tile.isCityCenter() // don't build fort in the city
|
||||
|| !tile.isLand // don't build fort in the water
|
||||
|| tile.improvement == Constants.fort // don't build fort if it is already here
|
||||
|| tile.hasViewableResource(civInfo) // don't build on resource tiles
|
||||
|| tile.containsGreatImprovement() // don't build on great improvements (including citadel)
|
||||
|| tile.containsUnfinishedGreatImprovement()) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun evaluateFortPlacement(tile: TileInfo, civInfo: CivilizationInfo): Boolean {
|
||||
fun evaluateFortPlacement(tile: TileInfo, civInfo: CivilizationInfo, isCitadel: Boolean): Boolean {
|
||||
// build on our land only
|
||||
if ((tile.owningCity?.civInfo != civInfo) ||
|
||||
if ((tile.owningCity?.civInfo != civInfo &&
|
||||
// except citadel which can be built near-by
|
||||
(!isCitadel || tile.neighbors.all { it.getOwner() != civInfo })) ||
|
||||
!isAcceptableTileForFort(tile, civInfo)) return false
|
||||
|
||||
val isHills = tile.getBaseTerrain().name == Constants.hill
|
||||
@ -286,11 +286,14 @@ class WorkerAutomation(val unit: MapUnit) {
|
||||
val distanceToEnemy = tile.aerialDistanceTo(closestEnemyCity)
|
||||
|
||||
// find closest our city to defend from this enemy city
|
||||
val closestOurCity = tile.owningCity!!.getCenterTile()
|
||||
val closestOurCity = civInfo.cities.minBy { it.getCenterTile().aerialDistanceTo(tile) }!!.getCenterTile()
|
||||
val distanceToOurCity = tile.aerialDistanceTo(closestOurCity)
|
||||
|
||||
val distanceBetweenCities = closestEnemyCity.aerialDistanceTo(closestOurCity)
|
||||
|
||||
// let's build fort on the front line, not behind the city
|
||||
return distanceBetweenCities > distanceToEnemy
|
||||
// +2 is a acceptable deviation from the straight line between cities
|
||||
return distanceBetweenCities + 2 > distanceToEnemy + distanceToOurCity
|
||||
}
|
||||
|
||||
}
|
@ -49,6 +49,7 @@ enum class DiplomaticModifiers{
|
||||
BetrayedPromiseToNotSettleCitiesNearUs,
|
||||
UnacceptableDemands,
|
||||
UsedNuclearWeapons,
|
||||
StealingTerritory,
|
||||
|
||||
YearsOfPeace,
|
||||
SharedEnemy,
|
||||
|
@ -303,6 +303,7 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
|
||||
FulfilledPromiseToNotSettleCitiesNearUs -> "You fulfilled your promise to stop settling cities near us!"
|
||||
UnacceptableDemands -> "Your arrogant demands are in bad taste"
|
||||
UsedNuclearWeapons -> "Your use of nuclear weapons is disgusting!"
|
||||
StealingTerritory -> "You have stolen our lands!"
|
||||
}
|
||||
text = text.tr() + " "
|
||||
if (modifier.value > 0) text += "+"
|
||||
|
@ -7,6 +7,7 @@ import com.unciv.UniqueAbility
|
||||
import com.unciv.logic.automation.UnitAutomation
|
||||
import com.unciv.logic.automation.WorkerAutomation
|
||||
import com.unciv.logic.civilization.CivilizationInfo
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomaticModifiers
|
||||
import com.unciv.logic.map.MapUnit
|
||||
import com.unciv.logic.map.RoadStatus
|
||||
import com.unciv.logic.map.TileInfo
|
||||
@ -364,6 +365,8 @@ object UnitActions {
|
||||
unitTile.improvement = improvementName
|
||||
unitTile.improvementInProgress = null
|
||||
unitTile.turnsToImprovement = 0
|
||||
if (improvementName == Constants.citadel)
|
||||
takeOverTilesAround(unit)
|
||||
val city = unitTile.getCity()
|
||||
if (city != null) {
|
||||
city.cityStats.update()
|
||||
@ -373,11 +376,37 @@ object UnitActions {
|
||||
unit.destroy()
|
||||
}.takeIf { unit.currentMovement > 0f && !tile.isWater &&
|
||||
!tile.isCityCenter() && !tile.getLastTerrain().impassable &&
|
||||
tile.improvement != improvementName })
|
||||
tile.improvement != improvementName &&
|
||||
// citadel can be built only next to or within own borders
|
||||
(improvementName != Constants.citadel ||
|
||||
tile.neighbors.any { it.getOwner() == unit.civInfo })})
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun takeOverTilesAround(unit: MapUnit) {
|
||||
// one of the neighbour tile must belong to unit's civ, so nearestCity will be never `null`
|
||||
val nearestCity = unit.currentTile.neighbors.first { it.getOwner() == unit.civInfo }.getCity()
|
||||
// capture all tiles which do not belong to unit's civ and are not enemy cities
|
||||
// we use getTilesInDistance here, not neighbours to include the current tile as well
|
||||
val tilesToTakeOver = unit.currentTile.getTilesInDistance(1)
|
||||
.filter { !it.isCityCenter() && it.getOwner() != unit.civInfo }
|
||||
// make a set of civs to be notified (a set - in order to not repeat notification on each tile)
|
||||
val notifications = mutableSetOf<CivilizationInfo>()
|
||||
// take over the ownership
|
||||
for (tile in tilesToTakeOver) {
|
||||
val otherCiv = tile.getOwner()
|
||||
if (otherCiv != null) {
|
||||
// decrease relations for -10 pt/tile
|
||||
otherCiv.getDiplomacyManager(unit.civInfo).addModifier(DiplomaticModifiers.StealingTerritory, -10f)
|
||||
notifications.add(otherCiv)
|
||||
}
|
||||
nearestCity!!.expansion.takeOwnership(tile)
|
||||
}
|
||||
for (otherCiv in notifications)
|
||||
otherCiv.addNotification("${unit.civInfo} has stolen your territory!", unit.currentTile.position, Color.RED)
|
||||
}
|
||||
|
||||
private fun addGoldPerGreatPersonUsage(civInfo: CivilizationInfo) {
|
||||
val uniqueText = "Provides a sum of gold each time you spend a Great Person"
|
||||
val cityWithMausoleum = civInfo.cities.firstOrNull { it.containsBuildingUnique(uniqueText) }
|
||||
|
Loading…
x
Reference in New Issue
Block a user