mirror of
https://github.com/yairm210/Unciv.git
synced 2025-02-03 12:54:43 +07:00
reorg: Separated UnitActions into 3 files:
- UnitActionsFromUniques - UnitActionModifiers - UnitActions retains actions relevant to all units
This commit is contained in:
parent
6ffe13e780
commit
d1b2d652e3
@ -18,6 +18,7 @@ import com.unciv.models.ruleset.unique.LocalUniqueCache
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.models.stats.Stat
|
||||
import com.unciv.ui.screens.worldscreen.unit.actions.UnitActions
|
||||
import com.unciv.ui.screens.worldscreen.unit.actions.UnitActionsFromUniques
|
||||
import com.unciv.ui.screens.worldscreen.unit.actions.UnitActionsReligion
|
||||
|
||||
object SpecificUnitAutomation {
|
||||
@ -58,13 +59,13 @@ object SpecificUnitAutomation {
|
||||
if (tileToSteal != null) {
|
||||
unit.movement.headTowards(tileToSteal)
|
||||
if (unit.currentMovement > 0 && unit.currentTile == tileToSteal)
|
||||
UnitActions.getImprovementConstructionActions(unit, unit.currentTile).firstOrNull()?.action?.invoke()
|
||||
UnitActionsFromUniques.getImprovementConstructionActions(unit, unit.currentTile).firstOrNull()?.action?.invoke()
|
||||
return true
|
||||
}
|
||||
|
||||
// try to build a citadel for defensive purposes
|
||||
if (unit.civ.getWorkerAutomation().evaluateFortPlacement(unit.currentTile, true)) {
|
||||
UnitActions.getImprovementConstructionActions(unit, unit.currentTile).firstOrNull()?.action?.invoke()
|
||||
UnitActionsFromUniques.getImprovementConstructionActions(unit, unit.currentTile).firstOrNull()?.action?.invoke()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@ -98,13 +99,13 @@ object SpecificUnitAutomation {
|
||||
}
|
||||
unit.movement.headTowards(tileForCitadel)
|
||||
if (unit.currentMovement > 0 && unit.currentTile == tileForCitadel)
|
||||
UnitActions.getImprovementConstructionActions(unit, unit.currentTile)
|
||||
UnitActionsFromUniques.getImprovementConstructionActions(unit, unit.currentTile)
|
||||
.firstOrNull()?.action?.invoke()
|
||||
}
|
||||
|
||||
fun automateSettlerActions(unit: MapUnit, tilesWhereWeWillBeCaptured: Set<Tile>) {
|
||||
if (unit.civ.gameInfo.turns == 0) { // Special case, we want AI to settle in place on turn 1.
|
||||
val foundCityAction = UnitActions.getFoundCityAction(unit, unit.getTile())
|
||||
val foundCityAction = UnitActionsFromUniques.getFoundCityAction(unit, unit.getTile())
|
||||
// Depending on era and difficulty we might start with more than one settler. In that case settle the one with the best location
|
||||
val otherSettlers = unit.civ.units.getCivUnits().filter { it.currentMovement > 0 && it.baseUnit == unit.baseUnit }
|
||||
if (foundCityAction?.action != null &&
|
||||
@ -146,7 +147,7 @@ object SpecificUnitAutomation {
|
||||
return
|
||||
}
|
||||
|
||||
val foundCityAction = UnitActions.getFoundCityAction(unit, bestCityLocation)
|
||||
val foundCityAction = UnitActionsFromUniques.getFoundCityAction(unit, bestCityLocation)
|
||||
if (foundCityAction?.action == null) { // this means either currentMove == 0 or city within 3 tiles
|
||||
if (unit.currentMovement > 0) // therefore, city within 3 tiles
|
||||
throw Exception("City within distance")
|
||||
@ -215,9 +216,10 @@ object SpecificUnitAutomation {
|
||||
unit.movement.headTowards(chosenTile)
|
||||
if (unit.currentTile == chosenTile) {
|
||||
if (unit.currentTile.isPillaged())
|
||||
UnitActions.getRepairAction(unit).invoke()
|
||||
UnitActions.getUnitActions(unit).firstOrNull { it.type == UnitActionType.Repair }
|
||||
?.action?.invoke()
|
||||
else
|
||||
UnitActions.getImprovementConstructionActions(unit, unit.currentTile)
|
||||
UnitActionsFromUniques.getImprovementConstructionActions(unit, unit.currentTile)
|
||||
.firstOrNull()?.action?.invoke()
|
||||
return true
|
||||
}
|
||||
@ -320,8 +322,7 @@ object SpecificUnitAutomation {
|
||||
if (unit.movement.canReach(capitalTile))
|
||||
unit.movement.headTowards(capitalTile)
|
||||
if (unit.getTile() == capitalTile) {
|
||||
UnitActions.getAddInCapitalAction(unit, capitalTile).action!!()
|
||||
return
|
||||
UnitActionsFromUniques.getAddInCapitalAction(unit, capitalTile).action?.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -462,7 +462,7 @@ object UnitAutomation {
|
||||
val unitDistanceToTiles = unit.movement.getDistanceToTiles()
|
||||
val tilesThatCanWalkToAndThenPillage = unitDistanceToTiles
|
||||
.filter { it.value.totalDistance < unit.currentMovement }.keys
|
||||
.filter { unit.movement.canMoveTo(it) && UnitActions.canPillage(unit, it)
|
||||
.filter { unit.movement.canMoveTo(it) && UnitActionsPillage.canPillage(unit, it)
|
||||
&& (it.canPillageTileImprovement()
|
||||
|| (it.canPillageRoad() && it.getRoadOwner() != null && unit.civ.isAtWarWith(it.getRoadOwner()!!)))}
|
||||
|
||||
|
@ -19,7 +19,7 @@ import com.unciv.models.ruleset.tile.Terrain
|
||||
import com.unciv.models.ruleset.tile.TileImprovement
|
||||
import com.unciv.models.ruleset.unique.LocalUniqueCache
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.ui.screens.worldscreen.unit.actions.UnitActions
|
||||
import com.unciv.ui.screens.worldscreen.unit.actions.UnitActionsFromUniques
|
||||
import com.unciv.utils.Log
|
||||
import com.unciv.utils.debug
|
||||
|
||||
@ -141,7 +141,7 @@ class WorkerAutomation(
|
||||
if (unit.currentMovement > 0 && reachedTile == tileToWork) {
|
||||
if (reachedTile.isPillaged()) {
|
||||
debug("WorkerAutomation: ${unit.label()} -> repairs $reachedTile")
|
||||
UnitActions.getRepairAction(unit).invoke()
|
||||
UnitActionsFromUniques.getRepairAction(unit)?.action?.invoke()
|
||||
return
|
||||
}
|
||||
if (reachedTile.improvementInProgress == null && reachedTile.isLand
|
||||
@ -158,7 +158,7 @@ class WorkerAutomation(
|
||||
|
||||
if (currentTile.isPillaged()) {
|
||||
debug("WorkerAutomation: ${unit.label()} -> repairs $currentTile")
|
||||
UnitActions.getRepairAction(unit).invoke()
|
||||
UnitActionsFromUniques.getRepairAction(unit)?.action?.invoke()
|
||||
return
|
||||
}
|
||||
|
||||
@ -587,7 +587,7 @@ class WorkerAutomation(
|
||||
// all conditionals succeed with a current StateForConditionals(civ, unit)
|
||||
// todo: Not necessarily the optimal flow: Be optimistic and head towards,
|
||||
// then when arrived and the conditionals say "no" do something else instead?
|
||||
val action = UnitActions.getWaterImprovementAction(unit)
|
||||
val action = UnitActionsFromUniques.getWaterImprovementAction(unit)
|
||||
?: return false
|
||||
|
||||
// If action.action is null that means only transient reasons prevent the improvement -
|
||||
|
@ -5,10 +5,10 @@ import com.unciv.logic.civilization.Civilization
|
||||
import com.unciv.logic.civilization.LocationAction
|
||||
import com.unciv.logic.civilization.NotificationCategory
|
||||
import com.unciv.logic.civilization.NotificationIcon
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomaticModifiers
|
||||
import com.unciv.models.ruleset.tile.TileImprovement
|
||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.ui.screens.worldscreen.unit.actions.UnitActions
|
||||
|
||||
|
||||
enum class ImprovementBuildingProblem {
|
||||
@ -203,7 +203,7 @@ class TileInfoImprovementFunctions(val tile: Tile) {
|
||||
if (civToActivateBroaderEffects != null && improvementObject != null
|
||||
&& improvementObject.hasUnique(UniqueType.TakesOverAdjacentTiles)
|
||||
)
|
||||
UnitActions.takeOverTilesAround(civToActivateBroaderEffects, tile)
|
||||
takeOverTilesAround(civToActivateBroaderEffects, tile)
|
||||
|
||||
val city = tile.owningCity
|
||||
if (city != null) {
|
||||
@ -261,6 +261,51 @@ class TileInfoImprovementFunctions(val tile: Tile) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun takeOverTilesAround(civ: Civilization, tile: Tile) {
|
||||
// This method should only be called for a citadel - therefore one of the neighbour tile
|
||||
// must belong to unit's civ, so minByOrNull in the nearestCity formula should be never `null`.
|
||||
// That is, unless a mod does not specify the proper unique - then fallbackNearestCity will take over.
|
||||
|
||||
fun priority(tile: Tile): Int { // helper calculates priority (lower is better): distance plus razing malus
|
||||
val city = tile.getCity()!! // !! assertion is guaranteed by the outer filter selector.
|
||||
return city.getCenterTile().aerialDistanceTo(tile) +
|
||||
(if (city.isBeingRazed) 5 else 0)
|
||||
}
|
||||
fun fallbackNearestCity(civ: Civilization, tile: Tile) =
|
||||
civ.cities.minByOrNull {
|
||||
it.getCenterTile().aerialDistanceTo(tile) +
|
||||
(if (it.isBeingRazed) 5 else 0)
|
||||
}!!
|
||||
|
||||
// In the rare case more than one city owns tiles neighboring the citadel
|
||||
// this will prioritize the nearest one not being razed
|
||||
val nearestCity = tile.neighbors
|
||||
.filter { it.getOwner() == civ }
|
||||
.minByOrNull { priority(it) }?.getCity()
|
||||
?: fallbackNearestCity(civ, tile)
|
||||
|
||||
// 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 = tile.getTilesInDistance(1)
|
||||
.filter { !it.isCityCenter() && it.getOwner() != civ }
|
||||
|
||||
val civsToNotify = mutableSetOf<Civilization>()
|
||||
for (tileToTakeOver in tilesToTakeOver) {
|
||||
val otherCiv = tileToTakeOver.getOwner()
|
||||
if (otherCiv != null) {
|
||||
// decrease relations for -10 pt/tile
|
||||
if (!otherCiv.knows(civ)) otherCiv.diplomacyFunctions.makeCivilizationsMeet(civ)
|
||||
otherCiv.getDiplomacyManager(civ).addModifier(DiplomaticModifiers.StealingTerritory, -10f)
|
||||
civsToNotify.add(otherCiv)
|
||||
}
|
||||
nearestCity.expansion.takeOwnership(tileToTakeOver)
|
||||
}
|
||||
|
||||
for (otherCiv in civsToNotify)
|
||||
otherCiv.addNotification("Your territory has been stolen by [$civ]!",
|
||||
tile.position, NotificationCategory.Cities, civ.civName, NotificationIcon.War)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Marks tile as target tile for a building with a [UniqueType.CreatesOneImprovement] unique */
|
||||
|
@ -0,0 +1,84 @@
|
||||
package com.unciv.ui.screens.worldscreen.unit.actions
|
||||
|
||||
import com.unciv.logic.map.mapunit.MapUnit
|
||||
import com.unciv.models.ruleset.unique.Unique
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.models.translations.removeConditionals
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.components.Fonts
|
||||
|
||||
object UnitActionModifiers {
|
||||
|
||||
private fun getMovementPointsToUse(actionUnique: Unique): Int {
|
||||
val movementCost = actionUnique.conditionals
|
||||
.filter { it.type == UniqueType.UnitActionMovementCost }
|
||||
.minOfOrNull { it.params[0].toInt() }
|
||||
if (movementCost != null) return movementCost
|
||||
return 1
|
||||
}
|
||||
|
||||
fun activateSideEffects(unit: MapUnit, actionUnique: Unique){
|
||||
val movementCost = getMovementPointsToUse(actionUnique)
|
||||
unit.useMovementPoints(movementCost.toFloat())
|
||||
|
||||
for (conditional in actionUnique.conditionals){
|
||||
when (conditional.type){
|
||||
UniqueType.UnitActionConsumeUnit -> unit.consume()
|
||||
UniqueType.UnitActionLimitedTimes, UniqueType.UnitActionOnce -> {
|
||||
if (usagesLeft(unit, actionUnique) == 1
|
||||
&& actionUnique.conditionals.any { it.type== UniqueType.UnitActionAfterWhichConsumed }) {
|
||||
unit.consume()
|
||||
continue
|
||||
}
|
||||
val usagesSoFar = unit.abilityToTimesUsed[actionUnique.placeholderText] ?: 0
|
||||
unit.abilityToTimesUsed[actionUnique.placeholderText] = usagesSoFar + 1
|
||||
}
|
||||
else -> continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns 'null' if usages are not limited */
|
||||
fun usagesLeft(unit: MapUnit, actionUnique: Unique): Int?{
|
||||
val usagesTotal = getMaxUsages(unit, actionUnique) ?: return null
|
||||
val usagesSoFar = unit.abilityToTimesUsed[actionUnique.placeholderText] ?: 0
|
||||
return usagesTotal - usagesSoFar
|
||||
}
|
||||
|
||||
private fun getMaxUsages(unit: MapUnit, actionUnique: Unique): Int? {
|
||||
val extraTimes = unit.getMatchingUniques(actionUnique.type!!)
|
||||
.filter { it.text.removeConditionals() == actionUnique.text.removeConditionals() }
|
||||
.flatMap { unique -> unique.conditionals.filter { it.type == UniqueType.UnitActionExtraLimitedTimes } }
|
||||
.sumOf { it.params[0].toInt() }
|
||||
|
||||
val times = actionUnique.conditionals
|
||||
.filter { it.type == UniqueType.UnitActionLimitedTimes }
|
||||
.maxOfOrNull { it.params[0].toInt() }
|
||||
if (times != null) return times + extraTimes
|
||||
if (actionUnique.conditionals.any { it.type == UniqueType.UnitActionOnce }) return 1 + extraTimes
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun actionTextWithSideEffects(originalText: String, actionUnique: Unique, unit: MapUnit): String {
|
||||
val sideEffectString = getSideEffectString(unit, actionUnique)
|
||||
if (sideEffectString == "") return originalText
|
||||
else return "{$originalText} $sideEffectString"
|
||||
}
|
||||
|
||||
private fun getSideEffectString(unit: MapUnit, actionUnique: Unique): String {
|
||||
val effects = ArrayList<String>()
|
||||
|
||||
val maxUsages = getMaxUsages(unit, actionUnique)
|
||||
if (maxUsages!=null) effects += "${usagesLeft(unit, actionUnique)}/$maxUsages"
|
||||
|
||||
if (actionUnique.conditionals.any { it.type == UniqueType.UnitActionConsumeUnit }
|
||||
|| actionUnique.conditionals.any { it.type == UniqueType.UnitActionAfterWhichConsumed } && usagesLeft(unit, actionUnique) == 1
|
||||
) effects += Fonts.death.toString()
|
||||
else effects += getMovementPointsToUse(actionUnique).toString() + Fonts.movement
|
||||
|
||||
|
||||
return if (effects.isEmpty()) ""
|
||||
else "(${effects.joinToString { it.tr() }})"
|
||||
}
|
||||
}
|
@ -1,33 +1,17 @@
|
||||
package com.unciv.ui.screens.worldscreen.unit.actions
|
||||
|
||||
import com.unciv.Constants
|
||||
import com.unciv.GUI
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.automation.unit.UnitAutomation
|
||||
import com.unciv.logic.civilization.Civilization
|
||||
import com.unciv.logic.civilization.NotificationCategory
|
||||
import com.unciv.logic.civilization.NotificationIcon
|
||||
import com.unciv.logic.civilization.PlayerType
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomaticModifiers
|
||||
import com.unciv.logic.map.mapunit.MapUnit
|
||||
import com.unciv.logic.map.tile.Tile
|
||||
import com.unciv.models.Counter
|
||||
import com.unciv.models.UncivSound
|
||||
import com.unciv.models.UnitAction
|
||||
import com.unciv.models.UnitActionType
|
||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||
import com.unciv.models.ruleset.unique.Unique
|
||||
import com.unciv.models.ruleset.unique.UniqueTarget
|
||||
import com.unciv.models.ruleset.unique.UniqueTriggerActivation
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.models.translations.fillPlaceholders
|
||||
import com.unciv.models.translations.removeConditionals
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.components.Fonts
|
||||
import com.unciv.ui.popups.ConfirmPopup
|
||||
import com.unciv.ui.popups.hasOpenPopups
|
||||
import com.unciv.ui.screens.pickerscreens.ImprovementPickerScreen
|
||||
import com.unciv.ui.screens.pickerscreens.PromotionPickerScreen
|
||||
|
||||
object UnitActions {
|
||||
@ -42,24 +26,25 @@ object UnitActions {
|
||||
val actionList = ArrayList<UnitAction>()
|
||||
|
||||
// Determined by unit uniques
|
||||
addTransformActions(unit, actionList)
|
||||
addParadropAction(unit, actionList)
|
||||
addAirSweepAction(unit, actionList)
|
||||
addSetupAction(unit, actionList)
|
||||
addFoundCityAction(unit, actionList, tile)
|
||||
addBuildingImprovementsAction(unit, actionList, tile)
|
||||
addRepairAction(unit, actionList)
|
||||
addCreateWaterImprovements(unit, actionList)
|
||||
UnitActionsFromUniques.addTransformActions(unit, actionList)
|
||||
UnitActionsFromUniques.addParadropAction(unit, actionList)
|
||||
UnitActionsFromUniques.addAirSweepAction(unit, actionList)
|
||||
UnitActionsFromUniques.addSetupAction(unit, actionList)
|
||||
UnitActionsFromUniques.addFoundCityAction(unit, actionList, tile)
|
||||
UnitActionsFromUniques.addBuildingImprovementsAction(unit, actionList, tile)
|
||||
UnitActionsFromUniques.addRepairAction(unit, actionList)
|
||||
UnitActionsFromUniques.addCreateWaterImprovements(unit, actionList)
|
||||
UnitActionsGreatPerson.addGreatPersonActions(unit, actionList, tile)
|
||||
UnitActionsReligion.addFoundReligionAction(unit, actionList)
|
||||
UnitActionsReligion.addEnhanceReligionAction(unit, actionList)
|
||||
actionList += getImprovementConstructionActions(unit, tile)
|
||||
actionList += UnitActionsFromUniques.getImprovementConstructionActions(unit, tile)
|
||||
UnitActionsReligion.addActionsWithLimitedUses(unit, actionList, tile)
|
||||
|
||||
addAutomateAction(unit, actionList, true)
|
||||
addTriggerUniqueActions(unit, actionList)
|
||||
addAddInCapitalAction(unit, actionList, tile)
|
||||
UnitActionsFromUniques.addTriggerUniqueActions(unit, actionList)
|
||||
UnitActionsFromUniques.addAddInCapitalAction(unit, actionList, tile)
|
||||
|
||||
// General actions
|
||||
addAutomateAction(unit, actionList, true)
|
||||
if (unit.isMoving()) {
|
||||
actionList += UnitAction(UnitActionType.StopMovement) { unit.action = null }
|
||||
}
|
||||
@ -149,108 +134,6 @@ object UnitActions {
|
||||
}.takeIf { unit.currentMovement > 0 })
|
||||
}
|
||||
|
||||
private fun addCreateWaterImprovements(unit: MapUnit, actionList: ArrayList<UnitAction>) {
|
||||
val waterImprovementAction = getWaterImprovementAction(unit)
|
||||
if (waterImprovementAction != null) actionList += waterImprovementAction
|
||||
}
|
||||
|
||||
fun getWaterImprovementAction(unit: MapUnit): UnitAction? {
|
||||
val tile = unit.currentTile
|
||||
if (!tile.isWater || !unit.hasUnique(UniqueType.CreateWaterImprovements) || tile.resource == null) return null
|
||||
|
||||
val improvementName = tile.tileResource.getImprovingImprovement(tile, unit.civ) ?: return null
|
||||
val improvement = tile.ruleset.tileImprovements[improvementName] ?: return null
|
||||
if (!tile.improvementFunctions.canBuildImprovement(improvement, unit.civ)) return null
|
||||
|
||||
return UnitAction(UnitActionType.Create, "Create [$improvementName]",
|
||||
action = {
|
||||
tile.changeImprovement(improvementName, unit.civ)
|
||||
unit.destroy() // Modders may wish for a nondestructive way, but that should be another Unique
|
||||
}.takeIf { unit.currentMovement > 0 })
|
||||
}
|
||||
|
||||
|
||||
private fun addFoundCityAction(unit: MapUnit, actionList: ArrayList<UnitAction>, tile: Tile) {
|
||||
val getFoundCityAction = getFoundCityAction(unit, tile)
|
||||
if (getFoundCityAction != null) actionList += getFoundCityAction
|
||||
}
|
||||
|
||||
/** Produce a [UnitAction] for founding a city.
|
||||
* @param unit The unit to do the founding.
|
||||
* @param tile The tile to found a city on.
|
||||
* @return null if impossible (the unit lacks the ability to found),
|
||||
* or else a [UnitAction] 'defining' the founding.
|
||||
* The [action][UnitAction.action] field will be null if the action cannot be done here and now
|
||||
* (no movement left, too close to another city).
|
||||
*/
|
||||
fun getFoundCityAction(unit: MapUnit, tile: Tile): UnitAction? {
|
||||
val unique = unit.getMatchingUniques(UniqueType.FoundCity)
|
||||
.filter { unique -> unique.conditionals.none { it.type == UniqueType.UnitActionExtraLimitedTimes } }
|
||||
.firstOrNull()
|
||||
if (unique == null || tile.isWater || tile.isImpassible()) return null
|
||||
// Spain should still be able to build Conquistadors in a one city challenge - but can't settle them
|
||||
if (unit.civ.isOneCityChallenger() && unit.civ.hasEverOwnedOriginalCapital) return null
|
||||
if (usagesLeft(unit, unique)==0) return null
|
||||
|
||||
if (unit.currentMovement <= 0 || !tile.canBeSettled())
|
||||
return UnitAction(UnitActionType.FoundCity, action = null)
|
||||
|
||||
val hasActionModifiers = unique.conditionals.any { it.type?.targetTypes?.contains(UniqueTarget.UnitActionModifier) == true }
|
||||
val foundAction = {
|
||||
if (unit.civ.playerType != PlayerType.AI)
|
||||
UncivGame.Current.settings.addCompletedTutorialTask("Found city")
|
||||
unit.civ.addCity(tile.position)
|
||||
if (tile.ruleset.tileImprovements.containsKey(Constants.cityCenter))
|
||||
tile.changeImprovement(Constants.cityCenter)
|
||||
tile.removeRoad()
|
||||
|
||||
if (hasActionModifiers) activateSideEffects(unit, unique)
|
||||
else unit.destroy()
|
||||
GUI.setUpdateWorldOnNextRender() // Set manually, since this could be triggered from the ConfirmPopup and not from the UnitActionsTable
|
||||
}
|
||||
|
||||
if (unit.civ.playerType == PlayerType.AI)
|
||||
return UnitAction(UnitActionType.FoundCity, action = foundAction)
|
||||
|
||||
return UnitAction(
|
||||
type = UnitActionType.FoundCity,
|
||||
title =
|
||||
if (hasActionModifiers) actionTextWithSideEffects(UnitActionType.FoundCity.value, unique, unit)
|
||||
else UnitActionType.FoundCity.value,
|
||||
uncivSound = UncivSound.Chimes,
|
||||
action = {
|
||||
// check if we would be breaking a promise
|
||||
val leaders = testPromiseNotToSettle(unit.civ, tile)
|
||||
if (leaders == null)
|
||||
foundAction()
|
||||
else {
|
||||
// ask if we would be breaking a promise
|
||||
val text = "Do you want to break your promise to [$leaders]?"
|
||||
ConfirmPopup(GUI.getWorldScreen(), text, "Break promise", action = foundAction).open(force = true)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a civ founding a city on a certain tile would break a promise.
|
||||
* @param civInfo The civilization trying to found a city
|
||||
* @param tile The tile where the new city would go
|
||||
* @return null if no promises broken, else a String listing the leader(s) we would p* off.
|
||||
*/
|
||||
private fun testPromiseNotToSettle(civInfo: Civilization, tile: Tile): String? {
|
||||
val brokenPromises = HashSet<String>()
|
||||
for (otherCiv in civInfo.getKnownCivs().filter { it.isMajorCiv() && !civInfo.isAtWarWith(it) }) {
|
||||
val diplomacyManager = otherCiv.getDiplomacyManager(civInfo)
|
||||
if (diplomacyManager.hasFlag(DiplomacyFlags.AgreedToNotSettleNearUs)) {
|
||||
val citiesWithin6Tiles = otherCiv.cities
|
||||
.filter { it.getCenterTile().aerialDistanceTo(tile) <= 6 }
|
||||
.filter { otherCiv.hasExplored(it.getCenterTile()) }
|
||||
if (citiesWithin6Tiles.isNotEmpty()) brokenPromises += otherCiv.getLeaderDisplayName()
|
||||
}
|
||||
}
|
||||
return if(brokenPromises.isEmpty()) null else brokenPromises.joinToString(", ")
|
||||
}
|
||||
|
||||
private fun addPromoteAction(unit: MapUnit, actionList: ArrayList<UnitAction>) {
|
||||
if (unit.isCivilian() || !unit.promotions.canBePromoted()) return
|
||||
@ -261,50 +144,6 @@ object UnitActions {
|
||||
}.takeIf { unit.currentMovement > 0 && unit.attacksThisTurn == 0 })
|
||||
}
|
||||
|
||||
private fun addSetupAction(unit: MapUnit, actionList: ArrayList<UnitAction>) {
|
||||
if (!unit.hasUnique(UniqueType.MustSetUp) || unit.isEmbarked()) return
|
||||
val isSetUp = unit.isSetUpForSiege()
|
||||
actionList += UnitAction(UnitActionType.SetUp,
|
||||
isCurrentAction = isSetUp,
|
||||
action = {
|
||||
unit.action = UnitActionType.SetUp.value
|
||||
unit.useMovementPoints(1f)
|
||||
}.takeIf { unit.currentMovement > 0 && !isSetUp })
|
||||
}
|
||||
|
||||
private fun addParadropAction(unit: MapUnit, actionList: ArrayList<UnitAction>) {
|
||||
val paradropUniques =
|
||||
unit.getMatchingUniques(UniqueType.MayParadrop)
|
||||
if (!paradropUniques.any() || unit.isEmbarked()) return
|
||||
unit.cache.paradropRange = paradropUniques.maxOfOrNull { it.params[0] }!!.toInt()
|
||||
actionList += UnitAction(UnitActionType.Paradrop,
|
||||
isCurrentAction = unit.isPreparingParadrop(),
|
||||
action = {
|
||||
if (unit.isPreparingParadrop()) unit.action = null
|
||||
else unit.action = UnitActionType.Paradrop.value
|
||||
}.takeIf {
|
||||
!unit.hasUnitMovedThisTurn() &&
|
||||
unit.currentTile.isFriendlyTerritory(unit.civ) &&
|
||||
!unit.isEmbarked()
|
||||
})
|
||||
}
|
||||
|
||||
private fun addAirSweepAction(unit: MapUnit, actionList: ArrayList<UnitAction>) {
|
||||
val airsweepUniques =
|
||||
unit.getMatchingUniques(UniqueType.CanAirsweep)
|
||||
if (!airsweepUniques.any()) return
|
||||
actionList += UnitAction(UnitActionType.AirSweep,
|
||||
isCurrentAction = unit.isPreparingAirSweep(),
|
||||
action = {
|
||||
if (unit.isPreparingAirSweep()) unit.action = null
|
||||
else unit.action = UnitActionType.AirSweep.value
|
||||
}.takeIf {
|
||||
unit.canAttack()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
private fun addExplorationActions(unit: MapUnit, actionList: ArrayList<UnitAction>) {
|
||||
if (unit.baseUnit.movesLikeAirUnits()) return
|
||||
if (unit.isExploring()) return
|
||||
@ -314,252 +153,6 @@ object UnitActions {
|
||||
}
|
||||
}
|
||||
|
||||
private fun addTransformActions(
|
||||
unit: MapUnit,
|
||||
actionList: ArrayList<UnitAction>
|
||||
) {
|
||||
val upgradeAction = getTransformActions(unit)
|
||||
actionList += upgradeAction
|
||||
}
|
||||
|
||||
/** */
|
||||
private fun getTransformActions(
|
||||
unit: MapUnit
|
||||
): ArrayList<UnitAction> {
|
||||
val unitTile = unit.getTile()
|
||||
val civInfo = unit.civ
|
||||
val stateForConditionals = StateForConditionals(unit = unit, civInfo = civInfo, tile = unitTile)
|
||||
val transformList = ArrayList<UnitAction>()
|
||||
for (unique in unit.baseUnit().getMatchingUniques(UniqueType.CanTransform, stateForConditionals)) {
|
||||
val unitToTransformTo = civInfo.getEquivalentUnit(unique.params[0])
|
||||
|
||||
if (unitToTransformTo.getMatchingUniques(UniqueType.OnlyAvailableWhen, StateForConditionals.IgnoreConditionals)
|
||||
.any { !it.conditionalsApply(stateForConditionals) })
|
||||
continue
|
||||
|
||||
// Check _new_ resource requirements
|
||||
// Using Counter to aggregate is a bit exaggerated, but - respect the mad modder.
|
||||
val resourceRequirementsDelta = Counter<String>()
|
||||
for ((resource, amount) in unit.baseUnit().getResourceRequirementsPerTurn())
|
||||
resourceRequirementsDelta.add(resource, -amount)
|
||||
for ((resource, amount) in unitToTransformTo.getResourceRequirementsPerTurn())
|
||||
resourceRequirementsDelta.add(resource, amount)
|
||||
val newResourceRequirementsString = resourceRequirementsDelta.entries
|
||||
.filter { it.value > 0 }
|
||||
.joinToString { "${it.value} {${it.key}}".tr() }
|
||||
|
||||
val title = if (newResourceRequirementsString.isEmpty())
|
||||
"Transform to [${unitToTransformTo.name}]"
|
||||
else "Transform to [${unitToTransformTo.name}]\n([$newResourceRequirementsString])"
|
||||
|
||||
transformList.add(UnitAction(UnitActionType.Transform,
|
||||
title = title,
|
||||
action = {
|
||||
unit.destroy()
|
||||
val newUnit = civInfo.units.placeUnitNearTile(unitTile.position, unitToTransformTo)
|
||||
|
||||
/** We were UNABLE to place the new unit, which means that the unit failed to upgrade!
|
||||
* The only known cause of this currently is "land units upgrading to water units" which fail to be placed.
|
||||
*/
|
||||
if (newUnit == null) {
|
||||
val resurrectedUnit = civInfo.units.placeUnitNearTile(unitTile.position, unit.baseUnit)!!
|
||||
unit.copyStatisticsTo(resurrectedUnit)
|
||||
} else { // Managed to upgrade
|
||||
unit.copyStatisticsTo(newUnit)
|
||||
newUnit.currentMovement = 0f
|
||||
}
|
||||
}.takeIf {
|
||||
unit.currentMovement > 0 && !unit.isEmbarked()
|
||||
}
|
||||
) )
|
||||
}
|
||||
return transformList
|
||||
}
|
||||
|
||||
private fun addBuildingImprovementsAction(
|
||||
unit: MapUnit,
|
||||
actionList: ArrayList<UnitAction>,
|
||||
tile: Tile) {
|
||||
if (!unit.cache.hasUniqueToBuildImprovements) return
|
||||
|
||||
val couldConstruct = unit.currentMovement > 0
|
||||
&& !tile.isCityCenter()
|
||||
&& unit.civ.gameInfo.ruleset.tileImprovements.values.any {
|
||||
ImprovementPickerScreen.canReport(tile.improvementFunctions.getImprovementBuildingProblems(it, unit.civ).toSet())
|
||||
&& unit.canBuildImprovement(it)
|
||||
}
|
||||
|
||||
actionList += UnitAction(UnitActionType.ConstructImprovement,
|
||||
isCurrentAction = unit.currentTile.hasImprovementInProgress(),
|
||||
action = {
|
||||
GUI.pushScreen(ImprovementPickerScreen(tile, unit) {
|
||||
if (GUI.getSettings().autoUnitCycle)
|
||||
GUI.getWorldScreen().switchToNextUnit()
|
||||
})
|
||||
}.takeIf { couldConstruct }
|
||||
)
|
||||
}
|
||||
|
||||
private fun getRepairTurns(unit: MapUnit): Int {
|
||||
val tile = unit.currentTile
|
||||
if (!tile.isPillaged()) return 0
|
||||
if (tile.improvementInProgress == Constants.repair) return tile.turnsToImprovement
|
||||
var repairTurns = tile.ruleset.tileImprovements[Constants.repair]!!.getTurnsToBuild(unit.civ, unit)
|
||||
|
||||
val pillagedImprovement = tile.getImprovementToRepair()!!
|
||||
val turnsToBuild = pillagedImprovement.getTurnsToBuild(unit.civ, unit)
|
||||
// cap repair to number of turns to build original improvement
|
||||
if (turnsToBuild < repairTurns) repairTurns = turnsToBuild
|
||||
return repairTurns
|
||||
}
|
||||
|
||||
private fun addRepairAction(unit: MapUnit, actionList: ArrayList<UnitAction>) {
|
||||
if (!unit.currentTile.ruleset.tileImprovements.containsKey(Constants.repair)) return
|
||||
if (!unit.cache.hasUniqueToBuildImprovements) return
|
||||
if (unit.isEmbarked()) return
|
||||
val tile = unit.getTile()
|
||||
if (tile.isCityCenter()) return
|
||||
if (!tile.isPillaged()) return
|
||||
|
||||
val couldConstruct = unit.currentMovement > 0
|
||||
&& !tile.isCityCenter() && tile.improvementInProgress != Constants.repair
|
||||
|
||||
val turnsToBuild = getRepairTurns(unit)
|
||||
|
||||
actionList += UnitAction(UnitActionType.Repair,
|
||||
title = "${UnitActionType.Repair} [${unit.currentTile.getImprovementToRepair()!!.name}] - [${turnsToBuild}${Fonts.turn}]",
|
||||
action = getRepairAction(unit).takeIf { couldConstruct }
|
||||
)
|
||||
}
|
||||
|
||||
fun getRepairAction(unit: MapUnit): () -> Unit {
|
||||
return {
|
||||
val tile = unit.currentTile
|
||||
tile.turnsToImprovement = getRepairTurns(unit)
|
||||
tile.improvementInProgress = Constants.repair
|
||||
}
|
||||
}
|
||||
|
||||
private fun addAutomateAction(unit: MapUnit, actionList: ArrayList<UnitAction>, showingAdditionalActions:Boolean) {
|
||||
|
||||
// If either of these are true it goes in primary actions, else in additional actions
|
||||
if ((unit.hasUnique(UniqueType.AutomationPrimaryAction) || unit.cache.hasUniqueToBuildImprovements) != showingAdditionalActions)
|
||||
return
|
||||
|
||||
if (unit.isAutomated()) return
|
||||
|
||||
actionList += UnitAction(UnitActionType.Automate,
|
||||
isCurrentAction = unit.isAutomated(),
|
||||
action = {
|
||||
unit.action = UnitActionType.Automate.value
|
||||
UnitAutomation.automateUnitMoves(unit)
|
||||
}.takeIf { unit.currentMovement > 0 }
|
||||
)
|
||||
}
|
||||
|
||||
fun getAddInCapitalAction(unit: MapUnit, tile: Tile): UnitAction {
|
||||
return UnitAction(UnitActionType.AddInCapital,
|
||||
title = "Add to [${unit.getMatchingUniques(UniqueType.AddInCapital).first().params[0]}]",
|
||||
action = {
|
||||
unit.civ.victoryManager.currentsSpaceshipParts.add(unit.name, 1)
|
||||
unit.destroy()
|
||||
}.takeIf { tile.isCityCenter() && tile.getCity()!!.isCapital() && tile.getCity()!!.civ == unit.civ }
|
||||
)
|
||||
}
|
||||
|
||||
private fun addAddInCapitalAction(unit: MapUnit, actionList: ArrayList<UnitAction>, tile: Tile) {
|
||||
if (!unit.hasUnique(UniqueType.AddInCapital)) return
|
||||
|
||||
actionList += getAddInCapitalAction(unit, tile)
|
||||
}
|
||||
|
||||
fun getImprovementConstructionActions(unit: MapUnit, tile: Tile): ArrayList<UnitAction> {
|
||||
val finalActions = ArrayList<UnitAction>()
|
||||
val uniquesToCheck = unit.getMatchingUniques(UniqueType.ConstructImprovementInstantly)
|
||||
val civResources = unit.civ.getCivResourcesByName()
|
||||
|
||||
for (unique in uniquesToCheck) {
|
||||
// Skip actions with a "[amount] extra times" conditional - these are treated in addTriggerUniqueActions instead
|
||||
if (unique.conditionals.any { it.type == UniqueType.UnitActionExtraLimitedTimes }) continue
|
||||
|
||||
val improvementName = unique.params[0]
|
||||
val improvement = tile.ruleset.tileImprovements[improvementName]
|
||||
?: continue
|
||||
if (usagesLeft(unit, unique) == 0) continue
|
||||
|
||||
val resourcesAvailable = improvement.uniqueObjects.none {
|
||||
improvementUnique ->
|
||||
improvementUnique.isOfType(UniqueType.ConsumesResources) &&
|
||||
(civResources[improvementUnique.params[1]] ?: 0) < improvementUnique.params[0].toInt()
|
||||
}
|
||||
|
||||
finalActions += UnitAction(UnitActionType.Create,
|
||||
title = actionTextWithSideEffects("Create [$improvementName]", unique, unit),
|
||||
action = {
|
||||
val unitTile = unit.getTile()
|
||||
unitTile.changeImprovement(improvementName, unit.civ)
|
||||
|
||||
// without this the world screen won't show the improvement because it isn't the 'last seen improvement'
|
||||
unit.civ.cache.updateViewableTiles()
|
||||
|
||||
activateSideEffects(unit, unique)
|
||||
}.takeIf {
|
||||
resourcesAvailable
|
||||
&& unit.currentMovement > 0f
|
||||
&& tile.improvementFunctions.canBuildImprovement(improvement, unit.civ)
|
||||
// Next test is to prevent interfering with UniqueType.CreatesOneImprovement -
|
||||
// not pretty, but users *can* remove the building from the city queue an thus clear this:
|
||||
&& !tile.isMarkedForCreatesOneImprovement()
|
||||
&& !tile.isImpassible() // Not 100% sure that this check is necessary...
|
||||
})
|
||||
}
|
||||
return finalActions
|
||||
}
|
||||
|
||||
fun takeOverTilesAround(civ: Civilization, tile: Tile) {
|
||||
// This method should only be called for a citadel - therefore one of the neighbour tile
|
||||
// must belong to unit's civ, so minByOrNull in the nearestCity formula should be never `null`.
|
||||
// That is, unless a mod does not specify the proper unique - then fallbackNearestCity will take over.
|
||||
|
||||
fun priority(tile: Tile): Int { // helper calculates priority (lower is better): distance plus razing malus
|
||||
val city = tile.getCity()!! // !! assertion is guaranteed by the outer filter selector.
|
||||
return city.getCenterTile().aerialDistanceTo(tile) +
|
||||
(if (city.isBeingRazed) 5 else 0)
|
||||
}
|
||||
fun fallbackNearestCity(civ: Civilization, tile: Tile) =
|
||||
civ.cities.minByOrNull {
|
||||
it.getCenterTile().aerialDistanceTo(tile) +
|
||||
(if (it.isBeingRazed) 5 else 0)
|
||||
}!!
|
||||
|
||||
// In the rare case more than one city owns tiles neighboring the citadel
|
||||
// this will prioritize the nearest one not being razed
|
||||
val nearestCity = tile.neighbors
|
||||
.filter { it.getOwner() == civ }
|
||||
.minByOrNull { priority(it) }?.getCity()
|
||||
?: fallbackNearestCity(civ, tile)
|
||||
|
||||
// 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 = tile.getTilesInDistance(1)
|
||||
.filter { !it.isCityCenter() && it.getOwner() != civ }
|
||||
|
||||
val civsToNotify = mutableSetOf<Civilization>()
|
||||
for (tileToTakeOver in tilesToTakeOver) {
|
||||
val otherCiv = tileToTakeOver.getOwner()
|
||||
if (otherCiv != null) {
|
||||
// decrease relations for -10 pt/tile
|
||||
if (!otherCiv.knows(civ)) otherCiv.diplomacyFunctions.makeCivilizationsMeet(civ)
|
||||
otherCiv.getDiplomacyManager(civ).addModifier(DiplomaticModifiers.StealingTerritory, -10f)
|
||||
civsToNotify.add(otherCiv)
|
||||
}
|
||||
nearestCity.expansion.takeOwnership(tileToTakeOver)
|
||||
}
|
||||
|
||||
for (otherCiv in civsToNotify)
|
||||
otherCiv.addNotification("Your territory has been stolen by [$civ]!",
|
||||
tile.position, NotificationCategory.Cities, civ.civName, NotificationIcon.War)
|
||||
}
|
||||
|
||||
private fun addFortifyActions(actionList: ArrayList<UnitAction>, unit: MapUnit, showingAdditionalActions: Boolean) {
|
||||
if (unit.isFortified() && !showingAdditionalActions) {
|
||||
@ -607,14 +200,6 @@ object UnitActions {
|
||||
}
|
||||
}
|
||||
|
||||
fun canPillage(unit: MapUnit, tile: Tile): Boolean {
|
||||
if (unit.isTransported) return false
|
||||
if (!tile.canPillageTile()) return false
|
||||
val tileOwner = tile.getOwner()
|
||||
// Can't pillage friendly tiles, just like you can't attack them - it's an 'act of war' thing
|
||||
return tileOwner == null || unit.civ.isAtWarWith(tileOwner)
|
||||
}
|
||||
|
||||
private fun addGiftAction(unit: MapUnit, actionList: ArrayList<UnitAction>, tile: Tile) {
|
||||
val getGiftAction = getGiftAction(unit, tile)
|
||||
if (getGiftAction != null) actionList += getGiftAction
|
||||
@ -666,28 +251,21 @@ object UnitActions {
|
||||
return UnitAction(UnitActionType.GiftUnit, action = giftAction)
|
||||
}
|
||||
|
||||
private fun addTriggerUniqueActions(unit: MapUnit, actionList: ArrayList<UnitAction>){
|
||||
for (unique in unit.getUniques()) {
|
||||
// not a unit action
|
||||
if (unique.conditionals.none { it.type?.targetTypes?.contains(UniqueTarget.UnitActionModifier) == true }) continue
|
||||
// extends an existing unit action
|
||||
if (unique.conditionals.any { it.type == UniqueType.UnitActionExtraLimitedTimes }) continue
|
||||
if (!unique.isTriggerable) continue
|
||||
if (usagesLeft(unit, unique)==0) continue
|
||||
private fun addAutomateAction(unit: MapUnit, actionList: ArrayList<UnitAction>, showingAdditionalActions:Boolean) {
|
||||
|
||||
val baseTitle = if (unique.isOfType(UniqueType.OneTimeEnterGoldenAgeTurns))
|
||||
unique.placeholderText.fillPlaceholders(
|
||||
unit.civ.goldenAges.calculateGoldenAgeLength(
|
||||
unique.params[0].toInt()).toString())
|
||||
else unique.text.removeConditionals()
|
||||
val title = actionTextWithSideEffects(baseTitle, unique, unit)
|
||||
// If either of these are true it goes in primary actions, else in additional actions
|
||||
if ((unit.hasUnique(UniqueType.AutomationPrimaryAction) || unit.cache.hasUniqueToBuildImprovements) != showingAdditionalActions)
|
||||
return
|
||||
|
||||
val unitAction = UnitAction(type = UnitActionType.TriggerUnique, title){
|
||||
UniqueTriggerActivation.triggerUnitwideUnique(unique, unit)
|
||||
activateSideEffects(unit, unique)
|
||||
}
|
||||
actionList += unitAction
|
||||
}
|
||||
if (unit.isAutomated()) return
|
||||
|
||||
actionList += UnitAction(UnitActionType.Automate,
|
||||
isCurrentAction = unit.isAutomated(),
|
||||
action = {
|
||||
unit.action = UnitActionType.Automate.value
|
||||
UnitAutomation.automateUnitMoves(unit)
|
||||
}.takeIf { unit.currentMovement > 0 }
|
||||
)
|
||||
}
|
||||
|
||||
private fun addWaitAction(unit: MapUnit, actionList: ArrayList<UnitAction>) {
|
||||
@ -710,77 +288,5 @@ object UnitActions {
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun getMovementPointsToUse(actionUnique: Unique): Int {
|
||||
val movementCost = actionUnique.conditionals
|
||||
.filter { it.type == UniqueType.UnitActionMovementCost }
|
||||
.minOfOrNull { it.params[0].toInt() }
|
||||
if (movementCost != null) return movementCost
|
||||
return 1
|
||||
}
|
||||
|
||||
fun activateSideEffects(unit: MapUnit, actionUnique: Unique){
|
||||
val movementCost = getMovementPointsToUse(actionUnique)
|
||||
unit.useMovementPoints(movementCost.toFloat())
|
||||
|
||||
for (conditional in actionUnique.conditionals){
|
||||
when (conditional.type){
|
||||
UniqueType.UnitActionConsumeUnit -> unit.consume()
|
||||
UniqueType.UnitActionLimitedTimes, UniqueType.UnitActionOnce -> {
|
||||
if (usagesLeft(unit, actionUnique) == 1
|
||||
&& actionUnique.conditionals.any { it.type==UniqueType.UnitActionAfterWhichConsumed }) {
|
||||
unit.consume()
|
||||
continue
|
||||
}
|
||||
val usagesSoFar = unit.abilityToTimesUsed[actionUnique.placeholderText] ?: 0
|
||||
unit.abilityToTimesUsed[actionUnique.placeholderText] = usagesSoFar + 1
|
||||
}
|
||||
else -> continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns 'null' if usages are not limited */
|
||||
fun usagesLeft(unit:MapUnit, actionUnique: Unique): Int?{
|
||||
val usagesTotal = getMaxUsages(unit, actionUnique) ?: return null
|
||||
val usagesSoFar = unit.abilityToTimesUsed[actionUnique.placeholderText] ?: 0
|
||||
return usagesTotal - usagesSoFar
|
||||
}
|
||||
|
||||
fun getMaxUsages(unit: MapUnit, actionUnique: Unique): Int? {
|
||||
val extraTimes = unit.getMatchingUniques(actionUnique.type!!)
|
||||
.filter { it.text.removeConditionals() == actionUnique.text.removeConditionals() }
|
||||
.flatMap { unique -> unique.conditionals.filter { it.type == UniqueType.UnitActionExtraLimitedTimes } }
|
||||
.sumOf { it.params[0].toInt() }
|
||||
|
||||
val times = actionUnique.conditionals
|
||||
.filter { it.type == UniqueType.UnitActionLimitedTimes }
|
||||
.maxOfOrNull { it.params[0].toInt() }
|
||||
if (times != null) return times + extraTimes
|
||||
if (actionUnique.conditionals.any { it.type == UniqueType.UnitActionOnce }) return 1 + extraTimes
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun actionTextWithSideEffects(originalText: String, actionUnique: Unique, unit: MapUnit): String {
|
||||
val sideEffectString = getSideEffectString(unit, actionUnique)
|
||||
if (sideEffectString == "") return originalText
|
||||
else return "{$originalText} $sideEffectString"
|
||||
}
|
||||
|
||||
fun getSideEffectString(unit:MapUnit, actionUnique: Unique): String {
|
||||
val effects = ArrayList<String>()
|
||||
|
||||
val maxUsages = getMaxUsages(unit, actionUnique)
|
||||
if (maxUsages!=null) effects += "${usagesLeft(unit, actionUnique)}/$maxUsages"
|
||||
|
||||
if (actionUnique.conditionals.any { it.type == UniqueType.UnitActionConsumeUnit }
|
||||
|| actionUnique.conditionals.any { it.type == UniqueType.UnitActionAfterWhichConsumed } && usagesLeft(unit, actionUnique) == 1
|
||||
) effects += Fonts.death.toString()
|
||||
else effects += getMovementPointsToUse(actionUnique).toString() + Fonts.movement
|
||||
|
||||
|
||||
return if (effects.isEmpty()) ""
|
||||
else "(${effects.joinToString { it.tr() }})"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,414 @@
|
||||
package com.unciv.ui.screens.worldscreen.unit.actions
|
||||
|
||||
import com.unciv.Constants
|
||||
import com.unciv.GUI
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.civilization.Civilization
|
||||
import com.unciv.logic.civilization.PlayerType
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
|
||||
import com.unciv.logic.map.mapunit.MapUnit
|
||||
import com.unciv.logic.map.tile.Tile
|
||||
import com.unciv.models.Counter
|
||||
import com.unciv.models.UncivSound
|
||||
import com.unciv.models.UnitAction
|
||||
import com.unciv.models.UnitActionType
|
||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||
import com.unciv.models.ruleset.unique.UniqueTarget
|
||||
import com.unciv.models.ruleset.unique.UniqueTriggerActivation
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.models.translations.fillPlaceholders
|
||||
import com.unciv.models.translations.removeConditionals
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.components.Fonts
|
||||
import com.unciv.ui.popups.ConfirmPopup
|
||||
import com.unciv.ui.screens.pickerscreens.ImprovementPickerScreen
|
||||
|
||||
object UnitActionsFromUniques {
|
||||
|
||||
fun addCreateWaterImprovements(unit: MapUnit, actionList: ArrayList<UnitAction>) {
|
||||
val waterImprovementAction = getWaterImprovementAction(unit)
|
||||
if (waterImprovementAction != null) actionList += waterImprovementAction
|
||||
}
|
||||
|
||||
fun getWaterImprovementAction(unit: MapUnit): UnitAction? {
|
||||
val tile = unit.currentTile
|
||||
if (!tile.isWater || !unit.hasUnique(UniqueType.CreateWaterImprovements) || tile.resource == null) return null
|
||||
|
||||
val improvementName = tile.tileResource.getImprovingImprovement(tile, unit.civ) ?: return null
|
||||
val improvement = tile.ruleset.tileImprovements[improvementName] ?: return null
|
||||
if (!tile.improvementFunctions.canBuildImprovement(improvement, unit.civ)) return null
|
||||
|
||||
return UnitAction(UnitActionType.Create, "Create [$improvementName]",
|
||||
action = {
|
||||
tile.changeImprovement(improvementName, unit.civ)
|
||||
unit.destroy() // Modders may wish for a nondestructive way, but that should be another Unique
|
||||
}.takeIf { unit.currentMovement > 0 })
|
||||
}
|
||||
|
||||
|
||||
fun addFoundCityAction(unit: MapUnit, actionList: ArrayList<UnitAction>, tile: Tile) {
|
||||
val getFoundCityAction = getFoundCityAction(unit, tile)
|
||||
if (getFoundCityAction != null) actionList += getFoundCityAction
|
||||
}
|
||||
|
||||
/** Produce a [UnitAction] for founding a city.
|
||||
* @param unit The unit to do the founding.
|
||||
* @param tile The tile to found a city on.
|
||||
* @return null if impossible (the unit lacks the ability to found),
|
||||
* or else a [UnitAction] 'defining' the founding.
|
||||
* The [action][UnitAction.action] field will be null if the action cannot be done here and now
|
||||
* (no movement left, too close to another city).
|
||||
*/
|
||||
fun getFoundCityAction(unit: MapUnit, tile: Tile): UnitAction? {
|
||||
val unique = unit.getMatchingUniques(UniqueType.FoundCity)
|
||||
.filter { unique -> unique.conditionals.none { it.type == UniqueType.UnitActionExtraLimitedTimes } }
|
||||
.firstOrNull()
|
||||
if (unique == null || tile.isWater || tile.isImpassible()) return null
|
||||
// Spain should still be able to build Conquistadors in a one city challenge - but can't settle them
|
||||
if (unit.civ.isOneCityChallenger() && unit.civ.hasEverOwnedOriginalCapital) return null
|
||||
if (UnitActionModifiers.usagesLeft(unit, unique) ==0) return null
|
||||
|
||||
if (unit.currentMovement <= 0 || !tile.canBeSettled())
|
||||
return UnitAction(UnitActionType.FoundCity, action = null)
|
||||
|
||||
val hasActionModifiers = unique.conditionals.any { it.type?.targetTypes?.contains(
|
||||
UniqueTarget.UnitActionModifier
|
||||
) == true }
|
||||
val foundAction = {
|
||||
if (unit.civ.playerType != PlayerType.AI)
|
||||
UncivGame.Current.settings.addCompletedTutorialTask("Found city")
|
||||
unit.civ.addCity(tile.position)
|
||||
if (tile.ruleset.tileImprovements.containsKey(Constants.cityCenter))
|
||||
tile.changeImprovement(Constants.cityCenter)
|
||||
tile.removeRoad()
|
||||
|
||||
if (hasActionModifiers) UnitActionModifiers.activateSideEffects(unit, unique)
|
||||
else unit.destroy()
|
||||
GUI.setUpdateWorldOnNextRender() // Set manually, since this could be triggered from the ConfirmPopup and not from the UnitActionsTable
|
||||
}
|
||||
|
||||
if (unit.civ.playerType == PlayerType.AI)
|
||||
return UnitAction(UnitActionType.FoundCity, action = foundAction)
|
||||
|
||||
return UnitAction(
|
||||
type = UnitActionType.FoundCity,
|
||||
title =
|
||||
if (hasActionModifiers) UnitActionModifiers.actionTextWithSideEffects(
|
||||
UnitActionType.FoundCity.value,
|
||||
unique,
|
||||
unit
|
||||
)
|
||||
else UnitActionType.FoundCity.value,
|
||||
uncivSound = UncivSound.Chimes,
|
||||
action = {
|
||||
// check if we would be breaking a promise
|
||||
val leaders = testPromiseNotToSettle(unit.civ, tile)
|
||||
if (leaders == null)
|
||||
foundAction()
|
||||
else {
|
||||
// ask if we would be breaking a promise
|
||||
val text = "Do you want to break your promise to [$leaders]?"
|
||||
ConfirmPopup(
|
||||
GUI.getWorldScreen(),
|
||||
text,
|
||||
"Break promise",
|
||||
action = foundAction
|
||||
).open(force = true)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a civ founding a city on a certain tile would break a promise.
|
||||
* @param civInfo The civilization trying to found a city
|
||||
* @param tile The tile where the new city would go
|
||||
* @return null if no promises broken, else a String listing the leader(s) we would p* off.
|
||||
*/
|
||||
private fun testPromiseNotToSettle(civInfo: Civilization, tile: Tile): String? {
|
||||
val brokenPromises = HashSet<String>()
|
||||
for (otherCiv in civInfo.getKnownCivs().filter { it.isMajorCiv() && !civInfo.isAtWarWith(it) }) {
|
||||
val diplomacyManager = otherCiv.getDiplomacyManager(civInfo)
|
||||
if (diplomacyManager.hasFlag(DiplomacyFlags.AgreedToNotSettleNearUs)) {
|
||||
val citiesWithin6Tiles = otherCiv.cities
|
||||
.filter { it.getCenterTile().aerialDistanceTo(tile) <= 6 }
|
||||
.filter { otherCiv.hasExplored(it.getCenterTile()) }
|
||||
if (citiesWithin6Tiles.isNotEmpty()) brokenPromises += otherCiv.getLeaderDisplayName()
|
||||
}
|
||||
}
|
||||
return if(brokenPromises.isEmpty()) null else brokenPromises.joinToString(", ")
|
||||
}
|
||||
|
||||
fun addSetupAction(unit: MapUnit, actionList: ArrayList<UnitAction>) {
|
||||
if (!unit.hasUnique(UniqueType.MustSetUp) || unit.isEmbarked()) return
|
||||
val isSetUp = unit.isSetUpForSiege()
|
||||
actionList += UnitAction(UnitActionType.SetUp,
|
||||
isCurrentAction = isSetUp,
|
||||
action = {
|
||||
unit.action = UnitActionType.SetUp.value
|
||||
unit.useMovementPoints(1f)
|
||||
}.takeIf { unit.currentMovement > 0 && !isSetUp })
|
||||
}
|
||||
|
||||
fun addParadropAction(unit: MapUnit, actionList: ArrayList<UnitAction>) {
|
||||
val paradropUniques =
|
||||
unit.getMatchingUniques(UniqueType.MayParadrop)
|
||||
if (!paradropUniques.any() || unit.isEmbarked()) return
|
||||
unit.cache.paradropRange = paradropUniques.maxOfOrNull { it.params[0] }!!.toInt()
|
||||
actionList += UnitAction(UnitActionType.Paradrop,
|
||||
isCurrentAction = unit.isPreparingParadrop(),
|
||||
action = {
|
||||
if (unit.isPreparingParadrop()) unit.action = null
|
||||
else unit.action = UnitActionType.Paradrop.value
|
||||
}.takeIf {
|
||||
!unit.hasUnitMovedThisTurn() &&
|
||||
unit.currentTile.isFriendlyTerritory(unit.civ) &&
|
||||
!unit.isEmbarked()
|
||||
})
|
||||
}
|
||||
|
||||
fun addAirSweepAction(unit: MapUnit, actionList: ArrayList<UnitAction>) {
|
||||
val airsweepUniques =
|
||||
unit.getMatchingUniques(UniqueType.CanAirsweep)
|
||||
if (!airsweepUniques.any()) return
|
||||
actionList += UnitAction(UnitActionType.AirSweep,
|
||||
isCurrentAction = unit.isPreparingAirSweep(),
|
||||
action = {
|
||||
if (unit.isPreparingAirSweep()) unit.action = null
|
||||
else unit.action = UnitActionType.AirSweep.value
|
||||
}.takeIf {
|
||||
unit.canAttack()
|
||||
}
|
||||
)
|
||||
}
|
||||
fun addTriggerUniqueActions(unit: MapUnit, actionList: ArrayList<UnitAction>){
|
||||
for (unique in unit.getUniques()) {
|
||||
// not a unit action
|
||||
if (unique.conditionals.none { it.type?.targetTypes?.contains(UniqueTarget.UnitActionModifier) == true }) continue
|
||||
// extends an existing unit action
|
||||
if (unique.conditionals.any { it.type == UniqueType.UnitActionExtraLimitedTimes }) continue
|
||||
if (!unique.isTriggerable) continue
|
||||
if (UnitActionModifiers.usagesLeft(unit, unique) ==0) continue
|
||||
|
||||
val baseTitle = if (unique.isOfType(UniqueType.OneTimeEnterGoldenAgeTurns))
|
||||
unique.placeholderText.fillPlaceholders(
|
||||
unit.civ.goldenAges.calculateGoldenAgeLength(
|
||||
unique.params[0].toInt()).toString())
|
||||
else unique.text.removeConditionals()
|
||||
val title = UnitActionModifiers.actionTextWithSideEffects(baseTitle, unique, unit)
|
||||
|
||||
val unitAction = UnitAction(type = UnitActionType.TriggerUnique, title) {
|
||||
UniqueTriggerActivation.triggerUnitwideUnique(unique, unit)
|
||||
UnitActionModifiers.activateSideEffects(unit, unique)
|
||||
}
|
||||
actionList += unitAction
|
||||
}
|
||||
}
|
||||
|
||||
fun getAddInCapitalAction(unit: MapUnit, tile: Tile): UnitAction {
|
||||
return UnitAction(UnitActionType.AddInCapital,
|
||||
title = "Add to [${
|
||||
unit.getMatchingUniques(UniqueType.AddInCapital).first().params[0]
|
||||
}]",
|
||||
action = {
|
||||
unit.civ.victoryManager.currentsSpaceshipParts.add(unit.name, 1)
|
||||
unit.destroy()
|
||||
}.takeIf {
|
||||
tile.isCityCenter() && tile.getCity()!!
|
||||
.isCapital() && tile.getCity()!!.civ == unit.civ
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun addAddInCapitalAction(unit: MapUnit, actionList: ArrayList<UnitAction>, tile: Tile) {
|
||||
if (!unit.hasUnique(UniqueType.AddInCapital)) return
|
||||
actionList += getAddInCapitalAction(unit, tile)
|
||||
}
|
||||
|
||||
fun getImprovementConstructionActions(unit: MapUnit, tile: Tile): ArrayList<UnitAction> {
|
||||
val finalActions = ArrayList<UnitAction>()
|
||||
val uniquesToCheck = unit.getMatchingUniques(UniqueType.ConstructImprovementInstantly)
|
||||
val civResources = unit.civ.getCivResourcesByName()
|
||||
|
||||
for (unique in uniquesToCheck) {
|
||||
// Skip actions with a "[amount] extra times" conditional - these are treated in addTriggerUniqueActions instead
|
||||
if (unique.conditionals.any { it.type == UniqueType.UnitActionExtraLimitedTimes }) continue
|
||||
|
||||
val improvementName = unique.params[0]
|
||||
val improvement = tile.ruleset.tileImprovements[improvementName]
|
||||
?: continue
|
||||
if (UnitActionModifiers.usagesLeft(unit, unique) == 0) continue
|
||||
|
||||
val resourcesAvailable = improvement.uniqueObjects.none {
|
||||
improvementUnique ->
|
||||
improvementUnique.isOfType(UniqueType.ConsumesResources) &&
|
||||
(civResources[improvementUnique.params[1]] ?: 0) < improvementUnique.params[0].toInt()
|
||||
}
|
||||
|
||||
finalActions += UnitAction(UnitActionType.Create,
|
||||
title = UnitActionModifiers.actionTextWithSideEffects(
|
||||
"Create [$improvementName]",
|
||||
unique,
|
||||
unit
|
||||
),
|
||||
action = {
|
||||
val unitTile = unit.getTile()
|
||||
unitTile.changeImprovement(improvementName, unit.civ)
|
||||
|
||||
// without this the world screen won't show the improvement because it isn't the 'last seen improvement'
|
||||
unit.civ.cache.updateViewableTiles()
|
||||
|
||||
UnitActionModifiers.activateSideEffects(unit, unique)
|
||||
}.takeIf {
|
||||
resourcesAvailable
|
||||
&& unit.currentMovement > 0f
|
||||
&& tile.improvementFunctions.canBuildImprovement(improvement, unit.civ)
|
||||
// Next test is to prevent interfering with UniqueType.CreatesOneImprovement -
|
||||
// not pretty, but users *can* remove the building from the city queue an thus clear this:
|
||||
&& !tile.isMarkedForCreatesOneImprovement()
|
||||
&& !tile.isImpassible() // Not 100% sure that this check is necessary...
|
||||
})
|
||||
}
|
||||
return finalActions
|
||||
}
|
||||
|
||||
fun addTransformActions(
|
||||
unit: MapUnit,
|
||||
actionList: ArrayList<UnitAction>
|
||||
) {
|
||||
val upgradeAction = getTransformActions(unit)
|
||||
actionList += upgradeAction
|
||||
}
|
||||
|
||||
private fun getTransformActions(
|
||||
unit: MapUnit
|
||||
): ArrayList<UnitAction> {
|
||||
val unitTile = unit.getTile()
|
||||
val civInfo = unit.civ
|
||||
val stateForConditionals =
|
||||
StateForConditionals(unit = unit, civInfo = civInfo, tile = unitTile)
|
||||
val transformList = ArrayList<UnitAction>()
|
||||
for (unique in unit.baseUnit().getMatchingUniques(UniqueType.CanTransform, stateForConditionals)) {
|
||||
val unitToTransformTo = civInfo.getEquivalentUnit(unique.params[0])
|
||||
|
||||
if (unitToTransformTo.getMatchingUniques(
|
||||
UniqueType.OnlyAvailableWhen,
|
||||
StateForConditionals.IgnoreConditionals
|
||||
)
|
||||
.any { !it.conditionalsApply(stateForConditionals) })
|
||||
continue
|
||||
|
||||
// Check _new_ resource requirements
|
||||
// Using Counter to aggregate is a bit exaggerated, but - respect the mad modder.
|
||||
val resourceRequirementsDelta = Counter<String>()
|
||||
for ((resource, amount) in unit.baseUnit().getResourceRequirementsPerTurn())
|
||||
resourceRequirementsDelta.add(resource, -amount)
|
||||
for ((resource, amount) in unitToTransformTo.getResourceRequirementsPerTurn())
|
||||
resourceRequirementsDelta.add(resource, amount)
|
||||
val newResourceRequirementsString = resourceRequirementsDelta.entries
|
||||
.filter { it.value > 0 }
|
||||
.joinToString { "${it.value} {${it.key}}".tr() }
|
||||
|
||||
val title = if (newResourceRequirementsString.isEmpty())
|
||||
"Transform to [${unitToTransformTo.name}]"
|
||||
else "Transform to [${unitToTransformTo.name}]\n([$newResourceRequirementsString])"
|
||||
|
||||
transformList.add(UnitAction(UnitActionType.Transform,
|
||||
title = title,
|
||||
action = {
|
||||
unit.destroy()
|
||||
val newUnit =
|
||||
civInfo.units.placeUnitNearTile(unitTile.position, unitToTransformTo)
|
||||
|
||||
/** We were UNABLE to place the new unit, which means that the unit failed to upgrade!
|
||||
* The only known cause of this currently is "land units upgrading to water units" which fail to be placed.
|
||||
*/
|
||||
|
||||
/** We were UNABLE to place the new unit, which means that the unit failed to upgrade!
|
||||
* The only known cause of this currently is "land units upgrading to water units" which fail to be placed.
|
||||
*/
|
||||
if (newUnit == null) {
|
||||
val resurrectedUnit =
|
||||
civInfo.units.placeUnitNearTile(unitTile.position, unit.baseUnit)!!
|
||||
unit.copyStatisticsTo(resurrectedUnit)
|
||||
} else { // Managed to upgrade
|
||||
unit.copyStatisticsTo(newUnit)
|
||||
newUnit.currentMovement = 0f
|
||||
}
|
||||
}.takeIf {
|
||||
unit.currentMovement > 0 && !unit.isEmbarked()
|
||||
}
|
||||
))
|
||||
}
|
||||
return transformList
|
||||
}
|
||||
|
||||
fun addBuildingImprovementsAction(
|
||||
unit: MapUnit,
|
||||
actionList: ArrayList<UnitAction>,
|
||||
tile: Tile
|
||||
) {
|
||||
if (!unit.cache.hasUniqueToBuildImprovements) return
|
||||
|
||||
val couldConstruct = unit.currentMovement > 0
|
||||
&& !tile.isCityCenter()
|
||||
&& unit.civ.gameInfo.ruleset.tileImprovements.values.any {
|
||||
ImprovementPickerScreen.canReport(
|
||||
tile.improvementFunctions.getImprovementBuildingProblems(
|
||||
it,
|
||||
unit.civ
|
||||
).toSet()
|
||||
)
|
||||
&& unit.canBuildImprovement(it)
|
||||
}
|
||||
|
||||
actionList += UnitAction(UnitActionType.ConstructImprovement,
|
||||
isCurrentAction = unit.currentTile.hasImprovementInProgress(),
|
||||
action = {
|
||||
GUI.pushScreen(ImprovementPickerScreen(tile, unit) {
|
||||
if (GUI.getSettings().autoUnitCycle)
|
||||
GUI.getWorldScreen().switchToNextUnit()
|
||||
})
|
||||
}.takeIf { couldConstruct }
|
||||
)
|
||||
}
|
||||
|
||||
private fun getRepairTurns(unit: MapUnit): Int {
|
||||
val tile = unit.currentTile
|
||||
if (!tile.isPillaged()) return 0
|
||||
if (tile.improvementInProgress == Constants.repair) return tile.turnsToImprovement
|
||||
var repairTurns = tile.ruleset.tileImprovements[Constants.repair]!!.getTurnsToBuild(unit.civ, unit)
|
||||
|
||||
val pillagedImprovement = tile.getImprovementToRepair()!!
|
||||
val turnsToBuild = pillagedImprovement.getTurnsToBuild(unit.civ, unit)
|
||||
// cap repair to number of turns to build original improvement
|
||||
if (turnsToBuild < repairTurns) repairTurns = turnsToBuild
|
||||
return repairTurns
|
||||
}
|
||||
|
||||
fun addRepairAction(unit: MapUnit, actionList: ArrayList<UnitAction>){
|
||||
val repairAction = getRepairAction(unit)
|
||||
if (repairAction != null) actionList.add(repairAction)
|
||||
}
|
||||
fun getRepairAction(unit: MapUnit) : UnitAction? {
|
||||
if (!unit.currentTile.ruleset.tileImprovements.containsKey(Constants.repair)) return null
|
||||
if (!unit.cache.hasUniqueToBuildImprovements) return null
|
||||
if (unit.isEmbarked()) return null
|
||||
val tile = unit.getTile()
|
||||
if (tile.isCityCenter()) return null
|
||||
if (!tile.isPillaged()) return null
|
||||
|
||||
val couldConstruct = unit.currentMovement > 0
|
||||
&& !tile.isCityCenter() && tile.improvementInProgress != Constants.repair
|
||||
|
||||
val turnsToBuild = getRepairTurns(unit)
|
||||
|
||||
return UnitAction(UnitActionType.Repair,
|
||||
title = "${UnitActionType.Repair} [${unit.currentTile.getImprovementToRepair()!!.name}] - [${turnsToBuild}${Fonts.turn}]",
|
||||
action = {
|
||||
tile.turnsToImprovement = getRepairTurns(unit)
|
||||
tile.improvementInProgress = Constants.repair
|
||||
}.takeIf { couldConstruct }
|
||||
)
|
||||
}
|
||||
}
|
@ -67,7 +67,7 @@ object UnitActionsPillage {
|
||||
|
||||
if (pillagingImprovement) // only Improvements heal HP
|
||||
unit.healBy(25)
|
||||
}.takeIf { unit.currentMovement > 0 && UnitActions.canPillage(unit, tile) }
|
||||
}.takeIf { unit.currentMovement > 0 && canPillage(unit, tile) }
|
||||
)
|
||||
}
|
||||
|
||||
@ -114,4 +114,12 @@ object UnitActionsPillage {
|
||||
toCityPillageYield.notify(" which has been sent to [${closestCity?.name}]")
|
||||
globalPillageYield.notify("")
|
||||
}
|
||||
|
||||
fun canPillage(unit: MapUnit, tile: Tile): Boolean {
|
||||
if (unit.isTransported) return false
|
||||
if (!tile.canPillageTile()) return false
|
||||
val tileOwner = tile.getOwner()
|
||||
// Can't pillage friendly tiles, just like you can't attack them - it's an 'act of war' thing
|
||||
return tileOwner == null || unit.civ.isAtWarWith(tileOwner)
|
||||
}
|
||||
}
|
||||
|
@ -106,12 +106,12 @@ object UnitActionsReligion {
|
||||
action = {
|
||||
city.religion.removeAllPressuresExceptFor(unit.religion!!)
|
||||
if (city.religion.religionThisIsTheHolyCityOf != null) {
|
||||
val religion = unit.civ.gameInfo.religions[city.religion.religionThisIsTheHolyCityOf]!!
|
||||
val holyCityReligion = unit.civ.gameInfo.religions[city.religion.religionThisIsTheHolyCityOf]!!
|
||||
if (city.religion.religionThisIsTheHolyCityOf != unit.religion && !city.religion.isBlockedHolyCity) {
|
||||
religion.getFounder().addNotification("An [${unit.baseUnit.name}] has removed your religion [${religion.getReligionDisplayName()}] from its Holy City [${city.name}]!", NotificationCategory.Religion)
|
||||
holyCityReligion.getFounder().addNotification("An [${unit.baseUnit.name}] has removed your religion [${holyCityReligion.getReligionDisplayName()}] from its Holy City [${city.name}]!", NotificationCategory.Religion)
|
||||
city.religion.isBlockedHolyCity = true
|
||||
} else if (city.religion.religionThisIsTheHolyCityOf == unit.religion && city.religion.isBlockedHolyCity) {
|
||||
religion.getFounder().addNotification("An [${unit.baseUnit.name}] has restored [${city.name}] as the Holy City of your religion [${religion.getReligionDisplayName()}]!", NotificationCategory.Religion)
|
||||
holyCityReligion.getFounder().addNotification("An [${unit.baseUnit.name}] has restored [${city.name}] as the Holy City of your religion [${holyCityReligion.getReligionDisplayName()}]!", NotificationCategory.Religion)
|
||||
city.religion.isBlockedHolyCity = false
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import com.unciv.testing.GdxTestRunner
|
||||
import com.unciv.testing.TestGame
|
||||
import com.unciv.ui.screens.pickerscreens.PromotionTree
|
||||
import com.unciv.ui.screens.worldscreen.unit.actions.UnitActions
|
||||
import com.unciv.ui.screens.worldscreen.unit.actions.UnitActions.getImprovementConstructionActions
|
||||
import com.unciv.ui.screens.worldscreen.unit.actions.UnitActionsFromUniques
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
@ -66,7 +66,7 @@ class UnitUniquesTests {
|
||||
val unit = game.addUnit("Great Engineer", civ, unitTile)
|
||||
unit.currentMovement = unit.baseUnit.movement.toFloat() // Required!
|
||||
val actionsWithoutIron = try {
|
||||
getImprovementConstructionActions(unit, unitTile)
|
||||
UnitActionsFromUniques.getImprovementConstructionActions(unit, unitTile)
|
||||
} catch (ex: Throwable) {
|
||||
// Give that IndexOutOfBoundsException a nicer name
|
||||
Assert.fail("getImprovementConstructionActions throws Exception ${ex.javaClass.simpleName}")
|
||||
@ -88,7 +88,7 @@ class UnitUniquesTests {
|
||||
Assert.assertTrue("Test preparation failed to add Iron to Civ resources", ironAvailable >= 3)
|
||||
|
||||
// See if that same Engineer could create a Manufactory NOW
|
||||
val actionsWithIron = getImprovementConstructionActions(unit, unitTile)
|
||||
val actionsWithIron = UnitActionsFromUniques.getImprovementConstructionActions(unit, unitTile)
|
||||
.filter { it.action != null }
|
||||
Assert.assertFalse("Great Engineer SHOULD be able to create a Manufactory modded to require Iron once Iron is available",
|
||||
actionsWithIron.isEmpty())
|
||||
@ -152,7 +152,7 @@ class UnitUniquesTests {
|
||||
// add unit
|
||||
val centerTile = game.tileMap[0,0]
|
||||
val unit = game.addUnit("Scout", civ, centerTile)
|
||||
var tree = PromotionTree(unit)
|
||||
val tree = PromotionTree(unit)
|
||||
Assert.assertFalse("We shouldn't be able to get the promotion without XP",
|
||||
tree.canBuyUpTo(promotionTestBranchB))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user