chore: separated unit actions into several files

This commit is contained in:
Yair Morgenstern 2023-01-23 00:42:45 +02:00
parent 35399eb74c
commit 783a469da5
19 changed files with 487 additions and 427 deletions

View File

@ -1,16 +0,0 @@
java.lang.NullPointerException
at com.unciv.ui.worldscreen.AlertPopup.<init>(AlertPopup.kt:318)
at com.unciv.ui.worldscreen.WorldScreen.update(WorldScreen.kt:450)
at com.unciv.ui.worldscreen.WorldScreen.render(WorldScreen.kt:830)
at com.badlogic.gdx.Game.render(Game.java:48)
at com.unciv.UncivGame.access$render$s2211858(UncivGame.kt:50)
at com.unciv.UncivGame$wrappedCrashHandlingRender$1.invoke(UncivGame.kt:89)
at com.unciv.UncivGame$wrappedCrashHandlingRender$1.invoke(UncivGame.kt:89)
at com.unciv.ui.crashhandling.CrashHandlingExtensionsKt$wrapCrashHandling$1.invoke(CrashHandlingExtensions.kt:17)
at com.unciv.ui.crashhandling.CrashHandlingExtensionsKt$wrapCrashHandlingUnit$1.invoke(CrashHandlingExtensions.kt:33)
at com.unciv.ui.crashhandling.CrashHandlingExtensionsKt$wrapCrashHandlingUnit$1.invoke(CrashHandlingExtensions.kt:33)
at com.unciv.UncivGame.render(UncivGame.kt:392)
at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Window.update(Lwjgl3Window.java:387)
at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application.loop(Lwjgl3Application.java:192)
at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application.<init>(Lwjgl3Application.java:166)
at com.unciv.app.desktop.DesktopLauncher.main(DesktopLauncher.kt:87)

View File

@ -16,7 +16,8 @@ import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.models.ruleset.tile.TileResource import com.unciv.models.ruleset.tile.TileResource
import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.stats.Stat import com.unciv.models.stats.Stat
import com.unciv.ui.worldscreen.unit.UnitActions import com.unciv.ui.worldscreen.unit.actions.UnitActions
import com.unciv.ui.worldscreen.unit.actions.UnitActionsReligion
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
@ -557,7 +558,7 @@ object SpecificUnitAutomation {
return return
} }
UnitActions.getFoundReligionAction(unit)() UnitActionsReligion.getFoundReligionAction(unit)()
} }
fun enhanceReligion(unit: MapUnit) { fun enhanceReligion(unit: MapUnit) {
@ -569,12 +570,12 @@ object SpecificUnitAutomation {
if (!unit.getTile().isCityCenter()) if (!unit.getTile().isCityCenter())
return return
UnitActions.getEnhanceReligionAction(unit)() UnitActionsReligion.getEnhanceReligionAction(unit)()
} }
private fun doReligiousAction(unit: MapUnit, destination: Tile) { private fun doReligiousAction(unit: MapUnit, destination: Tile) {
val religiousActions = ArrayList<UnitAction>() val religiousActions = ArrayList<UnitAction>()
UnitActions.addActionsWithLimitedUses(unit, religiousActions, destination) UnitActionsReligion.addActionsWithLimitedUses(unit, religiousActions, destination)
if (religiousActions.firstOrNull()?.action == null) return if (religiousActions.firstOrNull()?.action == null) return
religiousActions.first().action!!.invoke() religiousActions.first().action!!.invoke()
} }

View File

@ -15,7 +15,9 @@ import com.unciv.logic.civilization.managers.ReligionState
import com.unciv.logic.map.mapunit.MapUnit import com.unciv.logic.map.mapunit.MapUnit
import com.unciv.logic.map.tile.Tile import com.unciv.logic.map.tile.Tile
import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.ui.worldscreen.unit.UnitActions import com.unciv.ui.worldscreen.unit.actions.UnitActions
import com.unciv.ui.worldscreen.unit.actions.UnitActionsPillage
import com.unciv.ui.worldscreen.unit.actions.UnitActionsUpgrade
object UnitAutomation { object UnitAutomation {
@ -124,7 +126,7 @@ object UnitAutomation {
if (!Automation.allowSpendingResource(unit.civInfo, upgradedUnit)) return false if (!Automation.allowSpendingResource(unit.civInfo, upgradedUnit)) return false
} }
val upgradeAction = UnitActions.getUpgradeAction(unit) val upgradeAction = UnitActionsUpgrade.getUpgradeAction(unit)
?: return false ?: return false
upgradeAction.action?.invoke() upgradeAction.action?.invoke()
@ -372,7 +374,7 @@ object UnitAutomation {
if (unit.getTile() != tileToPillage) if (unit.getTile() != tileToPillage)
unit.movement.moveToTile(tileToPillage) unit.movement.moveToTile(tileToPillage)
UnitActions.getPillageAction(unit)?.action?.invoke() UnitActionsPillage.getPillageAction(unit)?.action?.invoke()
return unit.currentMovement == 0f return unit.currentMovement == 0f
} }

View File

@ -18,7 +18,7 @@ import com.unciv.logic.map.tile.Tile
import com.unciv.models.ruleset.tile.Terrain import com.unciv.models.ruleset.tile.Terrain
import com.unciv.models.ruleset.tile.TileImprovement import com.unciv.models.ruleset.tile.TileImprovement
import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.ui.worldscreen.unit.UnitActions import com.unciv.ui.worldscreen.unit.actions.UnitActions
import com.unciv.utils.Log import com.unciv.utils.Log
import com.unciv.utils.debug import com.unciv.utils.debug

View File

@ -26,7 +26,7 @@ import com.unciv.ui.civilopedia.FormattedLine
import com.unciv.ui.utils.Fonts import com.unciv.ui.utils.Fonts
import com.unciv.ui.utils.extensions.withItem import com.unciv.ui.utils.extensions.withItem
import com.unciv.ui.utils.extensions.withoutItem import com.unciv.ui.utils.extensions.withoutItem
import com.unciv.ui.worldscreen.unit.UnitActions import com.unciv.ui.worldscreen.unit.actions.UnitActions
import kotlin.math.ceil import kotlin.math.ceil
import kotlin.math.roundToInt import kotlin.math.roundToInt

View File

@ -87,7 +87,8 @@ class TileMap : IsPartOfGameInfoSerialization {
val startingLocationsByNation = HashMap<String,HashSet<Tile>>() val startingLocationsByNation = HashMap<String,HashSet<Tile>>()
@Transient @Transient
val continentSizes = HashMap<Int, Int>() // Continent ID, Continent size /** Continent ID to Continent size */
val continentSizes = HashMap<Int, Int>()
//endregion //endregion
//region Constructors //region Constructors

View File

@ -1016,15 +1016,6 @@ class MapUnit : IsPartOfGameInfoSerialization {
} }
fun getPressureAddedFromSpread(): Int {
var pressureAdded = baseUnit.religiousStrength.toFloat()
for (unique in getMatchingUniques(UniqueType.SpreadReligionStrength, checkCivInfoUniques = true))
pressureAdded *= unique.params[0].toPercent()
return pressureAdded.toInt()
}
fun getActionString(action: String): String { fun getActionString(action: String): String {
val maxActionUses = maxAbilityUses[action] val maxActionUses = maxAbilityUses[action]
if (abilityUsesLeft[action] == null) return "0/0" // Something went wrong if (abilityUsesLeft[action] == null) return "0/0" // Something went wrong

View File

@ -16,7 +16,7 @@ import com.unciv.models.translations.tr
import com.unciv.ui.civilopedia.CivilopediaScreen.Companion.showReligionInCivilopedia import com.unciv.ui.civilopedia.CivilopediaScreen.Companion.showReligionInCivilopedia
import com.unciv.ui.civilopedia.FormattedLine import com.unciv.ui.civilopedia.FormattedLine
import com.unciv.ui.utils.extensions.toPercent import com.unciv.ui.utils.extensions.toPercent
import com.unciv.ui.worldscreen.unit.UnitActions import com.unciv.ui.worldscreen.unit.actions.UnitActions
import kotlin.math.roundToInt import kotlin.math.roundToInt
class TileImprovement : RulesetStatsObject() { class TileImprovement : RulesetStatsObject() {

View File

@ -20,7 +20,7 @@ import com.unciv.models.stats.Stats
import com.unciv.models.translations.fillPlaceholders import com.unciv.models.translations.fillPlaceholders
import com.unciv.models.translations.hasPlaceholderParameters import com.unciv.models.translations.hasPlaceholderParameters
import com.unciv.ui.utils.MayaCalendar import com.unciv.ui.utils.MayaCalendar
import com.unciv.ui.worldscreen.unit.UnitActions import com.unciv.ui.worldscreen.unit.actions.UnitActionsUpgrade
import kotlin.random.Random import kotlin.random.Random
// Buildings, techs, policies, ancient ruins and promotions can have 'triggered' effects // Buildings, techs, policies, ancient ruins and promotions can have 'triggered' effects
@ -377,10 +377,8 @@ object UniqueTriggerActivation {
|| unique.params[1].toIntOrNull() == null || unique.params[1].toIntOrNull() == null
) return false ) return false
val finalStatAmount = val finalStatAmount = tileBasedRandom.nextInt(unique.params[0].toInt(), unique.params[1].toInt()) *
(tileBasedRandom.nextInt(unique.params[0].toInt(), unique.params[1].toInt()) * civInfo.gameInfo.speed.statCostModifiers[stat]!!
civInfo.gameInfo.speed.statCostModifiers[stat]!!
).toFloat()
val stats = Stats().add(stat, finalStatAmount) val stats = Stats().add(stat, finalStatAmount)
civInfo.addStats(stats) civInfo.addStats(stats)
@ -592,7 +590,7 @@ object UniqueTriggerActivation {
return true return true
} }
UniqueType.OneTimeUnitUpgrade -> { UniqueType.OneTimeUnitUpgrade -> {
val upgradeAction = UnitActions.getFreeUpgradeAction(unit) val upgradeAction = UnitActionsUpgrade.getFreeUpgradeAction(unit)
?: return false ?: return false
upgradeAction.action!!() upgradeAction.action!!()
if (notification != null) if (notification != null)
@ -600,7 +598,7 @@ object UniqueTriggerActivation {
return true return true
} }
UniqueType.OneTimeUnitSpecialUpgrade -> { UniqueType.OneTimeUnitSpecialUpgrade -> {
val upgradeAction = UnitActions.getAncientRuinsUpgradeAction(unit) val upgradeAction = UnitActionsUpgrade.getAncientRuinsUpgradeAction(unit)
?: return false ?: return false
upgradeAction.action!!() upgradeAction.action!!()
if (notification != null) if (notification != null)

View File

@ -27,7 +27,7 @@ import com.unciv.ui.utils.extensions.darken
import com.unciv.ui.utils.extensions.onClick import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.surroundWithCircle import com.unciv.ui.utils.extensions.surroundWithCircle
import com.unciv.ui.utils.extensions.toLabel import com.unciv.ui.utils.extensions.toLabel
import com.unciv.ui.worldscreen.unit.UnitActions import com.unciv.ui.worldscreen.unit.actions.UnitActionsUpgrade
import kotlin.math.abs import kotlin.math.abs
/** /**
@ -230,7 +230,7 @@ class UnitOverviewTab(
// Upgrade column // Upgrade column
if (unit.upgrade.canUpgrade()) { if (unit.upgrade.canUpgrade()) {
val unitAction = UnitActions.getUpgradeAction(unit) val unitAction = UnitActionsUpgrade.getUpgradeAction(unit)
val enable = unitAction?.action != null val enable = unitAction?.action != null
val upgradeIcon = ImageGetter.getUnitIcon(unit.upgrade.getUnitToUpgradeTo().name, val upgradeIcon = ImageGetter.getUnitIcon(unit.upgrade.getUnitToUpgradeTo().name,
if (enable) Color.GREEN else Color.GREEN.darken(0.5f)) if (enable) Color.GREEN else Color.GREEN.darken(0.5f))

View File

@ -65,7 +65,7 @@ import com.unciv.ui.worldscreen.status.MultiplayerStatusButton
import com.unciv.ui.worldscreen.status.NextTurnAction import com.unciv.ui.worldscreen.status.NextTurnAction
import com.unciv.ui.worldscreen.status.NextTurnButton import com.unciv.ui.worldscreen.status.NextTurnButton
import com.unciv.ui.worldscreen.status.StatusButtons import com.unciv.ui.worldscreen.status.StatusButtons
import com.unciv.ui.worldscreen.unit.UnitActionsTable import com.unciv.ui.worldscreen.unit.actions.UnitActionsTable
import com.unciv.ui.worldscreen.unit.UnitTable import com.unciv.ui.worldscreen.unit.UnitTable
import com.unciv.utils.concurrency.Concurrency import com.unciv.utils.concurrency.Concurrency
import com.unciv.utils.concurrency.launchOnGLThread import com.unciv.utils.concurrency.launchOnGLThread

View File

@ -1,10 +1,9 @@
package com.unciv.ui.worldscreen.unit package com.unciv.ui.worldscreen.unit.actions
import com.unciv.Constants import com.unciv.Constants
import com.unciv.UncivGame import com.unciv.UncivGame
import com.unciv.logic.automation.unit.UnitAutomation import com.unciv.logic.automation.unit.UnitAutomation
import com.unciv.logic.automation.unit.WorkerAutomation import com.unciv.logic.automation.unit.WorkerAutomation
import com.unciv.logic.city.City
import com.unciv.logic.civilization.Civilization import com.unciv.logic.civilization.Civilization
import com.unciv.logic.civilization.NotificationCategory import com.unciv.logic.civilization.NotificationCategory
import com.unciv.logic.civilization.NotificationIcon import com.unciv.logic.civilization.NotificationIcon
@ -17,22 +16,17 @@ import com.unciv.models.Counter
import com.unciv.models.UncivSound import com.unciv.models.UncivSound
import com.unciv.models.UnitAction import com.unciv.models.UnitAction
import com.unciv.models.UnitActionType import com.unciv.models.UnitActionType
import com.unciv.models.ruleset.Building
import com.unciv.models.ruleset.unique.StateForConditionals import com.unciv.models.ruleset.unique.StateForConditionals
import com.unciv.models.ruleset.unique.UniqueTriggerActivation import com.unciv.models.ruleset.unique.UniqueTriggerActivation
import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.stats.Stat
import com.unciv.models.stats.Stats
import com.unciv.models.translations.tr import com.unciv.models.translations.tr
import com.unciv.ui.pickerscreens.ImprovementPickerScreen import com.unciv.ui.pickerscreens.ImprovementPickerScreen
import com.unciv.ui.pickerscreens.PromotionPickerScreen import com.unciv.ui.pickerscreens.PromotionPickerScreen
import com.unciv.ui.popup.ConfirmPopup import com.unciv.ui.popup.ConfirmPopup
import com.unciv.ui.popup.hasOpenPopups import com.unciv.ui.popup.hasOpenPopups
import com.unciv.ui.utils.Fonts import com.unciv.ui.utils.Fonts
import com.unciv.ui.utils.extensions.toPercent
import com.unciv.ui.worldscreen.WorldScreen import com.unciv.ui.worldscreen.WorldScreen
import kotlin.math.min import com.unciv.ui.worldscreen.unit.UnitTable
import kotlin.random.Random
object UnitActions { object UnitActions {
@ -57,9 +51,9 @@ object UnitActions {
addFortifyActions(actionList, unit, false) addFortifyActions(actionList, unit, false)
addPromoteAction(unit, actionList) addPromoteAction(unit, actionList)
addUnitUpgradeAction(unit, actionList) UnitActionsUpgrade.addUnitUpgradeAction(unit, actionList)
addTransformAction(unit, actionList) addTransformAction(unit, actionList)
addPillageAction(unit, actionList, worldScreen) UnitActionsPillage.addPillageAction(unit, actionList, worldScreen)
addParadropAction(unit, actionList) addParadropAction(unit, actionList)
addAirSweepAction(unit, actionList) addAirSweepAction(unit, actionList)
addSetupAction(unit, actionList) addSetupAction(unit, actionList)
@ -67,11 +61,11 @@ object UnitActions {
addBuildingImprovementsAction(unit, actionList, tile, worldScreen, unitTable) addBuildingImprovementsAction(unit, actionList, tile, worldScreen, unitTable)
addRepairAction(unit, actionList) addRepairAction(unit, actionList)
addCreateWaterImprovements(unit, actionList) addCreateWaterImprovements(unit, actionList)
addGreatPersonActions(unit, actionList, tile) UnitActionsGreatPerson.addGreatPersonActions(unit, actionList, tile)
addFoundReligionAction(unit, actionList) UnitActionsReligion.addFoundReligionAction(unit, actionList)
addEnhanceReligionAction(unit, actionList) UnitActionsReligion.addEnhanceReligionAction(unit, actionList)
actionList += getImprovementConstructionActions(unit, tile) actionList += getImprovementConstructionActions(unit, tile)
addActionsWithLimitedUses(unit, actionList, tile) UnitActionsReligion.addActionsWithLimitedUses(unit, actionList, tile)
addExplorationActions(unit, actionList) addExplorationActions(unit, actionList)
addAutomateBuildingImprovementsAction(unit, actionList) addAutomateBuildingImprovementsAction(unit, actionList)
addTriggerUniqueActions(unit, actionList) addTriggerUniqueActions(unit, actionList)
@ -289,96 +283,6 @@ object UnitActions {
) )
} }
private fun addPillageAction(unit: MapUnit, actionList: ArrayList<UnitAction>, worldScreen: WorldScreen) {
val pillageAction = getPillageAction(unit)
?: return
if (pillageAction.action == null)
actionList += UnitAction(UnitActionType.Pillage,
title = "${UnitActionType.Pillage} [${unit.currentTile.getImprovementToPillageName()!!}]",
action = null)
else actionList += UnitAction(type = UnitActionType.Pillage,
title = "${UnitActionType.Pillage} [${unit.currentTile.getImprovementToPillageName()!!}]") {
if (!worldScreen.hasOpenPopups()) {
val pillageText = "Are you sure you want to pillage this [${unit.currentTile.getImprovementToPillageName()!!}]?"
ConfirmPopup(
UncivGame.Current.worldScreen!!,
pillageText,
"Pillage",
true
) {
(pillageAction.action)()
worldScreen.shouldUpdate = true
}.open()
}
}
}
fun getPillageAction(unit: MapUnit): UnitAction? {
val tile = unit.currentTile
if (unit.isCivilian() || !tile.canPillageTile() || tile.getOwner() == unit.civInfo) return null
return UnitAction(UnitActionType.Pillage,
action = {
val pillagedImprovement = unit.currentTile.getImprovementToPillageName()!!
val pillageText = "An enemy [${unit.baseUnit.name}] has pillaged our [$pillagedImprovement]"
val icon = "ImprovementIcons/$pillagedImprovement"
tile.getOwner()?.addNotification(
pillageText,
tile.position,
NotificationCategory.War,
icon,
NotificationIcon.War,
unit.baseUnit.name
)
pillageLooting(tile, unit)
tile.setPillaged()
if (tile.resource != null) tile.getOwner()?.cache?.updateCivResources() // this might take away a resource
tile.getCity()?.updateCitizens = true
val freePillage = unit.hasUnique(UniqueType.NoMovementToPillage, checkCivInfoUniques = true)
if (!freePillage) unit.useMovementPoints(1f)
unit.healBy(25)
}.takeIf { unit.currentMovement > 0 && canPillage(unit, tile) })
}
private fun pillageLooting(tile: Tile, unit: MapUnit) {
// Stats objects for reporting pillage results in a notification
val pillageYield = Stats()
val globalPillageYield = Stats()
val toCityPillageYield = Stats()
val closestCity = unit.civInfo.cities.minByOrNull { it.getCenterTile().aerialDistanceTo(tile) }
val improvement = tile.getImprovementToPillage()!!
for (unique in improvement.getMatchingUniques(UniqueType.PillageYieldRandom)) {
for (stat in unique.stats) {
val looted = Random.nextInt((stat.value + 1).toInt()) + Random.nextInt((stat.value + 1).toInt())
pillageYield.add(stat.key, looted.toFloat())
}
}
for (unique in improvement.getMatchingUniques(UniqueType.PillageYieldFixed)) {
for (stat in unique.stats) {
pillageYield.add(stat.key, stat.value)
}
}
for (stat in pillageYield) {
if (stat.key in Stat.statsWithCivWideField) {
unit.civInfo.addStat(stat.key, stat.value.toInt())
globalPillageYield[stat.key] += stat.value
}
else if (closestCity != null) {
closestCity.addStat(stat.key, stat.value.toInt())
toCityPillageYield[stat.key] += stat.value
}
}
val lootNotificationText = if (!toCityPillageYield.isEmpty() && closestCity != null)
"We have looted [${toCityPillageYield.toStringWithoutIcons()}] from a [${improvement.name}] which has been sent to [${closestCity.name}]"
else "We have looted [${globalPillageYield.toStringWithoutIcons()}] from a [${improvement.name}]"
unit.civInfo.addNotification(lootNotificationText, tile.position, NotificationCategory.War, "ImprovementIcons/${improvement.name}", NotificationIcon.War)
}
private fun addExplorationActions(unit: MapUnit, actionList: ArrayList<UnitAction>) { private fun addExplorationActions(unit: MapUnit, actionList: ArrayList<UnitAction>) {
if (unit.baseUnit.movesLikeAirUnits()) return if (unit.baseUnit.movesLikeAirUnits()) return
@ -389,90 +293,6 @@ object UnitActions {
} }
} }
private fun addUnitUpgradeAction(
unit: MapUnit,
actionList: ArrayList<UnitAction>
) {
val upgradeAction = getUpgradeAction(unit)
if (upgradeAction != null) actionList += upgradeAction
}
/** Common implementation for [getUpgradeAction], [getFreeUpgradeAction] and [getAncientRuinsUpgradeAction] */
private fun getUpgradeAction(
unit: MapUnit,
isFree: Boolean,
isSpecial: Boolean
): UnitAction? {
if (unit.baseUnit().upgradesTo == null && unit.baseUnit().specialUpgradesTo == null) return null // can't upgrade to anything
val unitTile = unit.getTile()
val civInfo = unit.civInfo
if (!isFree && unitTile.getOwner() != civInfo) return null
val upgradesTo = unit.baseUnit().upgradesTo
val specialUpgradesTo = unit.baseUnit().specialUpgradesTo
val upgradedUnit = when {
isSpecial && specialUpgradesTo != null -> civInfo.getEquivalentUnit(specialUpgradesTo)
(isFree || isSpecial) && upgradesTo != null -> civInfo.getEquivalentUnit(upgradesTo) // Only get DIRECT upgrade
else -> unit.upgrade.getUnitToUpgradeTo() // Get EVENTUAL upgrade, all the way up the chain
}
if (!unit.upgrade.canUpgrade(unitToUpgradeTo = upgradedUnit, ignoreRequirements = isFree, ignoreResources = true))
return null
// Check _new_ resource requirements (display only - yes even for free or special upgrades)
// Using Counter to aggregate is a bit exaggerated, but - respect the mad modder.
val resourceRequirementsDelta = Counter<String>()
for ((resource, amount) in unit.baseUnit().getResourceRequirements())
resourceRequirementsDelta.add(resource, -amount)
for ((resource, amount) in upgradedUnit.getResourceRequirements())
resourceRequirementsDelta.add(resource, amount)
val newResourceRequirementsString = resourceRequirementsDelta.entries
.filter { it.value > 0 }
.joinToString { "${it.value} {${it.key}}".tr() }
val goldCostOfUpgrade = if (isFree) 0 else unit.upgrade.getCostOfUpgrade(upgradedUnit)
// No string for "FREE" variants, these are never shown to the user.
// The free actions are only triggered via OneTimeUnitUpgrade or OneTimeUnitSpecialUpgrade in UniqueTriggerActivation.
val title = if (newResourceRequirementsString.isEmpty())
"Upgrade to [${upgradedUnit.name}] ([$goldCostOfUpgrade] gold)"
else "Upgrade to [${upgradedUnit.name}]\n([$goldCostOfUpgrade] gold, [$newResourceRequirementsString])"
return UnitAction(UnitActionType.Upgrade,
title = title,
action = {
unit.destroy(destroyTransportedUnit = false)
val newUnit = civInfo.units.placeUnitNearTile(unitTile.position, upgradedUnit.name)
/** 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.name)!!
unit.copyStatisticsTo(resurrectedUnit)
} else { // Managed to upgrade
if (!isFree) civInfo.addGold(-goldCostOfUpgrade)
unit.copyStatisticsTo(newUnit)
newUnit.currentMovement = 0f
}
}.takeIf {
isFree || (
unit.civInfo.gold >= goldCostOfUpgrade
&& unit.currentMovement > 0
&& !unit.isEmbarked()
&& unit.upgrade.canUpgrade(unitToUpgradeTo = upgradedUnit)
)
}
)
}
fun getUpgradeAction(unit: MapUnit) =
getUpgradeAction(unit, isFree = false, isSpecial = false)
fun getFreeUpgradeAction(unit: MapUnit) =
getUpgradeAction(unit, isFree = true, isSpecial = false)
fun getAncientRuinsUpgradeAction(unit: MapUnit) =
getUpgradeAction(unit, isFree = true, isSpecial = true)
private fun addTransformAction( private fun addTransformAction(
unit: MapUnit, unit: MapUnit,
actionList: ArrayList<UnitAction> actionList: ArrayList<UnitAction>
@ -624,195 +444,6 @@ object UnitActions {
actionList += getAddInCapitalAction(unit, tile) actionList += getAddInCapitalAction(unit, tile)
} }
private fun addGreatPersonActions(unit: MapUnit, actionList: ArrayList<UnitAction>, tile: Tile) {
if (unit.currentMovement > 0) for (unique in unit.getUniques()) when (unique.type) {
UniqueType.CanHurryResearch -> {
actionList += UnitAction(UnitActionType.HurryResearch,
action = {
unit.civInfo.tech.addScience(unit.civInfo.tech.getScienceFromGreatScientist())
unit.consume()
}.takeIf { unit.civInfo.tech.currentTechnologyName() != null
&& !unit.civInfo.tech.currentTechnology()!!.hasUnique(UniqueType.CannotBeHurried) }
)
}
UniqueType.StartGoldenAge -> {
val turnsToGoldenAge = unique.params[0].toInt()
actionList += UnitAction(UnitActionType.StartGoldenAge,
action = {
unit.civInfo.goldenAges.enterGoldenAge(turnsToGoldenAge)
unit.consume()
}.takeIf { unit.currentTile.getOwner() != null && unit.currentTile.getOwner() == unit.civInfo }
)
}
UniqueType.CanSpeedupWonderConstruction -> {
val canHurryWonder =
if (!tile.isCityCenter()) false
else tile.getCity()!!.cityConstructions.isBuildingWonder()
&& tile.getCity()!!.cityConstructions.canBeHurried()
actionList += UnitAction(UnitActionType.HurryWonder,
action = {
tile.getCity()!!.cityConstructions.apply {
//http://civilization.wikia.com/wiki/Great_engineer_(Civ5)
addProductionPoints(((300 + 30 * tile.getCity()!!.population.population) * unit.civInfo.gameInfo.speed.productionCostModifier).toInt())
constructIfEnough()
}
unit.consume()
}.takeIf { canHurryWonder }
)
}
UniqueType.CanSpeedupConstruction -> {
if (!tile.isCityCenter()) {
actionList += UnitAction(UnitActionType.HurryBuilding, action = null)
continue
}
val cityConstructions = tile.getCity()!!.cityConstructions
val canHurryConstruction = cityConstructions.getCurrentConstruction() is Building
&& cityConstructions.canBeHurried()
//http://civilization.wikia.com/wiki/Great_engineer_(Civ5)
val productionPointsToAdd = min(
(300 + 30 * tile.getCity()!!.population.population) * unit.civInfo.gameInfo.speed.productionCostModifier,
cityConstructions.getRemainingWork(cityConstructions.currentConstructionFromQueue).toFloat() - 1
).toInt()
if (productionPointsToAdd <= 0) continue
actionList += UnitAction(UnitActionType.HurryBuilding,
title = "Hurry Construction (+[$productionPointsToAdd]⚙)",
action = {
cityConstructions.apply {
addProductionPoints(productionPointsToAdd)
constructIfEnough()
}
unit.consume()
}.takeIf { canHurryConstruction }
)
}
UniqueType.CanTradeWithCityStateForGoldAndInfluence -> {
val canConductTradeMission = tile.owningCity?.civInfo?.isCityState() == true
&& tile.owningCity?.civInfo?.isAtWarWith(unit.civInfo) == false
val influenceEarned = unique.params[0].toFloat()
actionList += UnitAction(UnitActionType.ConductTradeMission,
action = {
// http://civilization.wikia.com/wiki/Great_Merchant_(Civ5)
var goldEarned = (350 + 50 * unit.civInfo.getEraNumber()) * unit.civInfo.gameInfo.speed.goldCostModifier
for (goldUnique in unit.civInfo.getMatchingUniques(UniqueType.PercentGoldFromTradeMissions))
goldEarned *= goldUnique.params[0].toPercent()
unit.civInfo.addGold(goldEarned.toInt())
tile.owningCity!!.civInfo.getDiplomacyManager(unit.civInfo).addInfluence(influenceEarned)
unit.civInfo.addNotification("Your trade mission to [${tile.owningCity!!.civInfo}] has earned you [${goldEarned}] gold and [$influenceEarned] influence!",
NotificationCategory.General, tile.owningCity!!.civInfo.civName, NotificationIcon.Gold, NotificationIcon.Culture)
unit.consume()
}.takeIf { canConductTradeMission }
)
}
else -> {}
}
}
private fun addFoundReligionAction(unit: MapUnit, actionList: ArrayList<UnitAction>) {
if (!unit.hasUnique(UniqueType.MayFoundReligion)) return
if (!unit.civInfo.religionManager.mayFoundReligionAtAll(unit)) return
actionList += UnitAction(UnitActionType.FoundReligion,
action = getFoundReligionAction(unit).takeIf { unit.civInfo.religionManager.mayFoundReligionNow(unit) }
)
}
fun getFoundReligionAction(unit: MapUnit): () -> Unit {
return {
unit.civInfo.religionManager.foundReligion(unit)
unit.consume()
}
}
private fun addEnhanceReligionAction(unit: MapUnit, actionList: ArrayList<UnitAction>) {
if (!unit.hasUnique(UniqueType.MayEnhanceReligion)) return
if (!unit.civInfo.religionManager.mayEnhanceReligionAtAll(unit)) return
actionList += UnitAction(UnitActionType.EnhanceReligion,
title = "Enhance [${unit.civInfo.religionManager.religion!!.getReligionDisplayName()}]",
action = getEnhanceReligionAction(unit).takeIf { unit.civInfo.religionManager.mayEnhanceReligionNow(unit) }
)
}
fun getEnhanceReligionAction(unit: MapUnit): () -> Unit {
return {
unit.civInfo.religionManager.useProphetForEnhancingReligion(unit)
unit.consume()
}
}
fun addActionsWithLimitedUses(unit: MapUnit, actionList: ArrayList<UnitAction>, tile: Tile) {
val actionsToAdd = unit.religiousActionsUnitCanDo()
if (actionsToAdd.none()) return
if (unit.religion == null || unit.civInfo.gameInfo.religions[unit.religion]!!.isPantheon()) return
val city = tile.getCity() ?: return
for (action in actionsToAdd) {
if (!unit.abilityUsesLeft.containsKey(action)) continue
if (unit.abilityUsesLeft[action]!! <= 0) continue
when (action) {
Constants.spreadReligion -> addSpreadReligionActions(unit, actionList, city)
Constants.removeHeresy -> addRemoveHeresyActions(unit, actionList, city)
}
}
}
private fun useActionWithLimitedUses(unit: MapUnit, action: String) {
unit.abilityUsesLeft[action] = unit.abilityUsesLeft[action]!! - 1
if (unit.abilityUsesLeft[action]!! <= 0) {
unit.consume()
}
}
private fun addSpreadReligionActions(unit: MapUnit, actionList: ArrayList<UnitAction>, city: City) {
if (!unit.civInfo.religionManager.maySpreadReligionAtAll(unit)) return
actionList += UnitAction(UnitActionType.SpreadReligion,
title = "Spread [${unit.getReligionDisplayName()!!}]",
action = {
val followersOfOtherReligions = city.religion.getFollowersOfOtherReligionsThan(unit.religion!!)
for (unique in unit.getMatchingUniques(UniqueType.StatsWhenSpreading, checkCivInfoUniques = true)) {
unit.civInfo.addStat(Stat.valueOf(unique.params[1]), followersOfOtherReligions * unique.params[0].toInt())
}
city.religion.addPressure(unit.religion!!, unit.getPressureAddedFromSpread())
if (unit.hasUnique(UniqueType.RemoveOtherReligions))
city.religion.removeAllPressuresExceptFor(unit.religion!!)
unit.currentMovement = 0f
useActionWithLimitedUses(unit, Constants.spreadReligion)
}.takeIf { unit.currentMovement > 0 && unit.civInfo.religionManager.maySpreadReligionNow(unit) }
)
}
private fun addRemoveHeresyActions(unit: MapUnit, actionList: ArrayList<UnitAction>, city: City) {
if (!unit.civInfo.gameInfo.isReligionEnabled()) return
if (city.civInfo != unit.civInfo) return
// Only allow the action if the city actually has any foreign religion
// This will almost be always due to pressure from cities close-by
if (city.religion.getPressures().none { it.key != unit.religion!! }) return
actionList += UnitAction(UnitActionType.RemoveHeresy,
title = "Remove Heresy",
action = {
city.religion.removeAllPressuresExceptFor(unit.religion!!)
if (city.religion.religionThisIsTheHolyCityOf != null) {
val religion = unit.civInfo.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)
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)
city.religion.isBlockedHolyCity = false
}
}
unit.currentMovement = 0f
useActionWithLimitedUses(unit, Constants.removeHeresy)
}.takeIf { unit.currentMovement > 0f }
)
}
fun getImprovementConstructionActions(unit: MapUnit, tile: Tile): ArrayList<UnitAction> { fun getImprovementConstructionActions(unit: MapUnit, tile: Tile): ArrayList<UnitAction> {
val finalActions = ArrayList<UnitAction>() val finalActions = ArrayList<UnitAction>()
val uniquesToCheck = unit.getMatchingUniques(UniqueType.ConstructImprovementConsumingUnit) val uniquesToCheck = unit.getMatchingUniques(UniqueType.ConstructImprovementConsumingUnit)

View File

@ -0,0 +1,112 @@
package com.unciv.ui.worldscreen.unit.actions
import com.unciv.logic.civilization.NotificationCategory
import com.unciv.logic.civilization.NotificationIcon
import com.unciv.logic.map.mapunit.MapUnit
import com.unciv.logic.map.tile.Tile
import com.unciv.models.UnitAction
import com.unciv.models.UnitActionType
import com.unciv.models.ruleset.Building
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.ui.utils.extensions.toPercent
import kotlin.math.min
object UnitActionsGreatPerson {
internal fun addGreatPersonActions(unit: MapUnit, actionList: ArrayList<UnitAction>, tile: Tile) {
if (unit.currentMovement > 0) for (unique in unit.getUniques()) when (unique.type) {
UniqueType.CanHurryResearch -> {
actionList += UnitAction(
UnitActionType.HurryResearch,
action = {
unit.civInfo.tech.addScience(unit.civInfo.tech.getScienceFromGreatScientist())
unit.consume()
}.takeIf { unit.civInfo.tech.currentTechnologyName() != null
&& !unit.civInfo.tech.currentTechnology()!!.hasUnique(UniqueType.CannotBeHurried) }
)
}
UniqueType.StartGoldenAge -> {
val turnsToGoldenAge = unique.params[0].toInt()
actionList += UnitAction(
UnitActionType.StartGoldenAge,
action = {
unit.civInfo.goldenAges.enterGoldenAge(turnsToGoldenAge)
unit.consume()
}.takeIf { unit.currentTile.getOwner() != null && unit.currentTile.getOwner() == unit.civInfo }
)
}
UniqueType.CanSpeedupWonderConstruction -> {
val canHurryWonder =
if (!tile.isCityCenter()) false
else tile.getCity()!!.cityConstructions.isBuildingWonder()
&& tile.getCity()!!.cityConstructions.canBeHurried()
actionList += UnitAction(
UnitActionType.HurryWonder,
action = {
tile.getCity()!!.cityConstructions.apply {
//http://civilization.wikia.com/wiki/Great_engineer_(Civ5)
addProductionPoints(((300 + 30 * tile.getCity()!!.population.population) * unit.civInfo.gameInfo.speed.productionCostModifier).toInt())
constructIfEnough()
}
unit.consume()
}.takeIf { canHurryWonder }
)
}
UniqueType.CanSpeedupConstruction -> {
if (!tile.isCityCenter()) {
actionList += UnitAction(UnitActionType.HurryBuilding, action = null)
continue
}
val cityConstructions = tile.getCity()!!.cityConstructions
val canHurryConstruction = cityConstructions.getCurrentConstruction() is Building
&& cityConstructions.canBeHurried()
//http://civilization.wikia.com/wiki/Great_engineer_(Civ5)
val productionPointsToAdd = min(
(300 + 30 * tile.getCity()!!.population.population) * unit.civInfo.gameInfo.speed.productionCostModifier,
cityConstructions.getRemainingWork(cityConstructions.currentConstructionFromQueue).toFloat() - 1
).toInt()
if (productionPointsToAdd <= 0) continue
actionList += UnitAction(
UnitActionType.HurryBuilding,
title = "Hurry Construction (+[$productionPointsToAdd]⚙)",
action = {
cityConstructions.apply {
addProductionPoints(productionPointsToAdd)
constructIfEnough()
}
unit.consume()
}.takeIf { canHurryConstruction }
)
}
UniqueType.CanTradeWithCityStateForGoldAndInfluence -> {
val canConductTradeMission = tile.owningCity?.civInfo?.isCityState() == true
&& tile.owningCity?.civInfo?.isAtWarWith(unit.civInfo) == false
val influenceEarned = unique.params[0].toFloat()
actionList += UnitAction(
UnitActionType.ConductTradeMission,
action = {
// http://civilization.wikia.com/wiki/Great_Merchant_(Civ5)
var goldEarned = (350 + 50 * unit.civInfo.getEraNumber()) * unit.civInfo.gameInfo.speed.goldCostModifier
for (goldUnique in unit.civInfo.getMatchingUniques(UniqueType.PercentGoldFromTradeMissions))
goldEarned *= goldUnique.params[0].toPercent()
unit.civInfo.addGold(goldEarned.toInt())
tile.owningCity!!.civInfo.getDiplomacyManager(unit.civInfo).addInfluence(influenceEarned)
unit.civInfo.addNotification("Your trade mission to [${tile.owningCity!!.civInfo}] has earned you [${goldEarned}] gold and [$influenceEarned] influence!",
NotificationCategory.General, tile.owningCity!!.civInfo.civName, NotificationIcon.Gold, NotificationIcon.Culture)
unit.consume()
}.takeIf { canConductTradeMission }
)
}
else -> {}
}
}
}

View File

@ -0,0 +1,112 @@
package com.unciv.ui.worldscreen.unit.actions
import com.unciv.UncivGame
import com.unciv.logic.civilization.NotificationCategory
import com.unciv.logic.civilization.NotificationIcon
import com.unciv.logic.map.mapunit.MapUnit
import com.unciv.logic.map.tile.Tile
import com.unciv.models.UnitAction
import com.unciv.models.UnitActionType
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.stats.Stat
import com.unciv.models.stats.Stats
import com.unciv.ui.popup.ConfirmPopup
import com.unciv.ui.popup.hasOpenPopups
import com.unciv.ui.worldscreen.WorldScreen
import kotlin.random.Random
object UnitActionsPillage {
fun addPillageAction(unit: MapUnit, actionList: ArrayList<UnitAction>, worldScreen: WorldScreen) {
val pillageAction = getPillageAction(unit)
?: return
if (pillageAction.action == null)
actionList += UnitAction(
UnitActionType.Pillage,
title = "${UnitActionType.Pillage} [${unit.currentTile.getImprovementToPillageName()!!}]",
action = null)
else actionList += UnitAction(type = UnitActionType.Pillage,
title = "${UnitActionType.Pillage} [${unit.currentTile.getImprovementToPillageName()!!}]") {
if (!worldScreen.hasOpenPopups()) {
val pillageText = "Are you sure you want to pillage this [${unit.currentTile.getImprovementToPillageName()!!}]?"
ConfirmPopup(
UncivGame.Current.worldScreen!!,
pillageText,
"Pillage",
true
) {
(pillageAction.action)()
worldScreen.shouldUpdate = true
}.open()
}
}
}
internal fun getPillageAction(unit: MapUnit): UnitAction? {
val tile = unit.currentTile
if (unit.isCivilian() || !tile.canPillageTile() || tile.getOwner() == unit.civInfo) return null
return UnitAction(
UnitActionType.Pillage,
action = {
val pillagedImprovement = unit.currentTile.getImprovementToPillageName()!!
val pillageText = "An enemy [${unit.baseUnit.name}] has pillaged our [$pillagedImprovement]"
val icon = "ImprovementIcons/$pillagedImprovement"
tile.getOwner()?.addNotification(
pillageText,
tile.position,
NotificationCategory.War,
icon,
NotificationIcon.War,
unit.baseUnit.name
)
pillageLooting(tile, unit)
tile.setPillaged()
if (tile.resource != null) tile.getOwner()?.cache?.updateCivResources() // this might take away a resource
tile.getCity()?.updateCitizens = true
val freePillage = unit.hasUnique(UniqueType.NoMovementToPillage, checkCivInfoUniques = true)
if (!freePillage) unit.useMovementPoints(1f)
unit.healBy(25)
}.takeIf { unit.currentMovement > 0 && UnitActions.canPillage(unit, tile) })
}
private fun pillageLooting(tile: Tile, unit: MapUnit) {
// Stats objects for reporting pillage results in a notification
val pillageYield = Stats()
val globalPillageYield = Stats()
val toCityPillageYield = Stats()
val closestCity = unit.civInfo.cities.minByOrNull { it.getCenterTile().aerialDistanceTo(tile) }
val improvement = tile.getImprovementToPillage()!!
for (unique in improvement.getMatchingUniques(UniqueType.PillageYieldRandom)) {
for (stat in unique.stats) {
val looted = Random.nextInt((stat.value + 1).toInt()) + Random.nextInt((stat.value + 1).toInt())
pillageYield.add(stat.key, looted.toFloat())
}
}
for (unique in improvement.getMatchingUniques(UniqueType.PillageYieldFixed)) {
for (stat in unique.stats) {
pillageYield.add(stat.key, stat.value)
}
}
for (stat in pillageYield) {
if (stat.key in Stat.statsWithCivWideField) {
unit.civInfo.addStat(stat.key, stat.value.toInt())
globalPillageYield[stat.key] += stat.value
}
else if (closestCity != null) {
closestCity.addStat(stat.key, stat.value.toInt())
toCityPillageYield[stat.key] += stat.value
}
}
val lootNotificationText = if (!toCityPillageYield.isEmpty() && closestCity != null)
"We have looted [${toCityPillageYield.toStringWithoutIcons()}] from a [${improvement.name}] which has been sent to [${closestCity.name}]"
else "We have looted [${globalPillageYield.toStringWithoutIcons()}] from a [${improvement.name}]"
unit.civInfo.addNotification(lootNotificationText, tile.position, NotificationCategory.War, "ImprovementIcons/${improvement.name}", NotificationIcon.War)
}
}

View File

@ -0,0 +1,127 @@
package com.unciv.ui.worldscreen.unit.actions
import com.unciv.Constants
import com.unciv.logic.city.City
import com.unciv.logic.civilization.NotificationCategory
import com.unciv.logic.map.mapunit.MapUnit
import com.unciv.logic.map.tile.Tile
import com.unciv.models.UnitAction
import com.unciv.models.UnitActionType
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.stats.Stat
import com.unciv.ui.utils.extensions.toPercent
object UnitActionsReligion {
internal fun addFoundReligionAction(unit: MapUnit, actionList: ArrayList<UnitAction>) {
if (!unit.hasUnique(UniqueType.MayFoundReligion)) return
if (!unit.civInfo.religionManager.mayFoundReligionAtAll(unit)) return
actionList += UnitAction(
UnitActionType.FoundReligion,
action = getFoundReligionAction(unit).takeIf { unit.civInfo.religionManager.mayFoundReligionNow(unit) }
)
}
fun getFoundReligionAction(unit: MapUnit): () -> Unit {
return {
unit.civInfo.religionManager.foundReligion(unit)
unit.consume()
}
}
internal fun addEnhanceReligionAction(unit: MapUnit, actionList: ArrayList<UnitAction>) {
if (!unit.hasUnique(UniqueType.MayEnhanceReligion)) return
if (!unit.civInfo.religionManager.mayEnhanceReligionAtAll(unit)) return
actionList += UnitAction(
UnitActionType.EnhanceReligion,
title = "Enhance [${unit.civInfo.religionManager.religion!!.getReligionDisplayName()}]",
action = getEnhanceReligionAction(unit).takeIf { unit.civInfo.religionManager.mayEnhanceReligionNow(unit) }
)
}
fun getEnhanceReligionAction(unit: MapUnit): () -> Unit {
return {
unit.civInfo.religionManager.useProphetForEnhancingReligion(unit)
unit.consume()
}
}
fun addActionsWithLimitedUses(unit: MapUnit, actionList: ArrayList<UnitAction>, tile: Tile) {
val actionsToAdd = unit.religiousActionsUnitCanDo()
if (actionsToAdd.none()) return
if (unit.religion == null || unit.civInfo.gameInfo.religions[unit.religion]!!.isPantheon()) return
val city = tile.getCity() ?: return
for (action in actionsToAdd) {
if (!unit.abilityUsesLeft.containsKey(action)) continue
if (unit.abilityUsesLeft[action]!! <= 0) continue
when (action) {
Constants.spreadReligion -> addSpreadReligionActions(unit, actionList, city)
Constants.removeHeresy -> addRemoveHeresyActions(unit, actionList, city)
}
}
}
private fun useActionWithLimitedUses(unit: MapUnit, action: String) {
unit.abilityUsesLeft[action] = unit.abilityUsesLeft[action]!! - 1
if (unit.abilityUsesLeft[action]!! <= 0) {
unit.consume()
}
}
private fun getPressureAddedFromSpread(unit: MapUnit): Int {
var pressureAdded = unit.baseUnit.religiousStrength.toFloat()
for (unique in unit.getMatchingUniques(UniqueType.SpreadReligionStrength, checkCivInfoUniques = true))
pressureAdded *= unique.params[0].toPercent()
return pressureAdded.toInt()
}
private fun addSpreadReligionActions(unit: MapUnit, actionList: ArrayList<UnitAction>, city: City) {
if (!unit.civInfo.religionManager.maySpreadReligionAtAll(unit)) return
actionList += UnitAction(
UnitActionType.SpreadReligion,
title = "Spread [${unit.getReligionDisplayName()!!}]",
action = {
val followersOfOtherReligions = city.religion.getFollowersOfOtherReligionsThan(unit.religion!!)
for (unique in unit.getMatchingUniques(UniqueType.StatsWhenSpreading, checkCivInfoUniques = true)) {
unit.civInfo.addStat(Stat.valueOf(unique.params[1]), followersOfOtherReligions * unique.params[0].toInt())
}
city.religion.addPressure(unit.religion!!, getPressureAddedFromSpread(unit))
if (unit.hasUnique(UniqueType.RemoveOtherReligions))
city.religion.removeAllPressuresExceptFor(unit.religion!!)
unit.currentMovement = 0f
useActionWithLimitedUses(unit, Constants.spreadReligion)
}.takeIf { unit.currentMovement > 0 && unit.civInfo.religionManager.maySpreadReligionNow(unit) }
)
}
private fun addRemoveHeresyActions(unit: MapUnit, actionList: ArrayList<UnitAction>, city: City) {
if (!unit.civInfo.gameInfo.isReligionEnabled()) return
if (city.civInfo != unit.civInfo) return
// Only allow the action if the city actually has any foreign religion
// This will almost be always due to pressure from cities close-by
if (city.religion.getPressures().none { it.key != unit.religion!! }) return
actionList += UnitAction(
UnitActionType.RemoveHeresy,
title = "Remove Heresy",
action = {
city.religion.removeAllPressuresExceptFor(unit.religion!!)
if (city.religion.religionThisIsTheHolyCityOf != null) {
val religion = unit.civInfo.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)
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)
city.religion.isBlockedHolyCity = false
}
}
unit.currentMovement = 0f
useActionWithLimitedUses(unit, Constants.removeHeresy)
}.takeIf { unit.currentMovement > 0f }
)
}
}

View File

@ -1,4 +1,4 @@
package com.unciv.ui.worldscreen.unit package com.unciv.ui.worldscreen.unit.actions
import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.ui.Button import com.badlogic.gdx.scenes.scene2d.ui.Button
@ -21,7 +21,8 @@ class UnitActionsTable(val worldScreen: WorldScreen) : Table() {
clear() clear()
if (unit == null) return if (unit == null) return
if (!worldScreen.canChangeState) return // No actions when it's not your turn or spectator! if (!worldScreen.canChangeState) return // No actions when it's not your turn or spectator!
for (button in UnitActions.getUnitActions(unit, worldScreen).map { getUnitActionButton(unit, it) }) for (button in UnitActions.getUnitActions(unit, worldScreen)
.map { getUnitActionButton(unit, it) })
add(button).left().padBottom(2f).row() add(button).left().padBottom(2f).row()
pack() pack()
} }

View File

@ -0,0 +1,100 @@
package com.unciv.ui.worldscreen.unit.actions
import com.unciv.logic.map.mapunit.MapUnit
import com.unciv.models.Counter
import com.unciv.models.UnitAction
import com.unciv.models.UnitActionType
import com.unciv.models.translations.tr
object UnitActionsUpgrade{
internal fun addUnitUpgradeAction(
unit: MapUnit,
actionList: ArrayList<UnitAction>
) {
val upgradeAction = getUpgradeAction(unit)
if (upgradeAction != null) actionList += upgradeAction
}
/** Common implementation for [getUpgradeAction], [getFreeUpgradeAction] and [getAncientRuinsUpgradeAction] */
private fun getUpgradeAction(
unit: MapUnit,
isFree: Boolean,
isSpecial: Boolean
): UnitAction? {
if (unit.baseUnit().upgradesTo == null && unit.baseUnit().specialUpgradesTo == null) return null // can't upgrade to anything
val unitTile = unit.getTile()
val civInfo = unit.civInfo
if (!isFree && unitTile.getOwner() != civInfo) return null
val upgradesTo = unit.baseUnit().upgradesTo
val specialUpgradesTo = unit.baseUnit().specialUpgradesTo
val upgradedUnit = when {
isSpecial && specialUpgradesTo != null -> civInfo.getEquivalentUnit(specialUpgradesTo)
(isFree || isSpecial) && upgradesTo != null -> civInfo.getEquivalentUnit(upgradesTo) // Only get DIRECT upgrade
else -> unit.upgrade.getUnitToUpgradeTo() // Get EVENTUAL upgrade, all the way up the chain
}
if (!unit.upgrade.canUpgrade(unitToUpgradeTo = upgradedUnit, ignoreRequirements = isFree, ignoreResources = true))
return null
// Check _new_ resource requirements (display only - yes even for free or special upgrades)
// Using Counter to aggregate is a bit exaggerated, but - respect the mad modder.
val resourceRequirementsDelta = Counter<String>()
for ((resource, amount) in unit.baseUnit().getResourceRequirements())
resourceRequirementsDelta.add(resource, -amount)
for ((resource, amount) in upgradedUnit.getResourceRequirements())
resourceRequirementsDelta.add(resource, amount)
val newResourceRequirementsString = resourceRequirementsDelta.entries
.filter { it.value > 0 }
.joinToString { "${it.value} {${it.key}}".tr() }
val goldCostOfUpgrade = if (isFree) 0 else unit.upgrade.getCostOfUpgrade(upgradedUnit)
// No string for "FREE" variants, these are never shown to the user.
// The free actions are only triggered via OneTimeUnitUpgrade or OneTimeUnitSpecialUpgrade in UniqueTriggerActivation.
val title = if (newResourceRequirementsString.isEmpty())
"Upgrade to [${upgradedUnit.name}] ([$goldCostOfUpgrade] gold)"
else "Upgrade to [${upgradedUnit.name}]\n([$goldCostOfUpgrade] gold, [$newResourceRequirementsString])"
return UnitAction(
UnitActionType.Upgrade,
title = title,
action = {
unit.destroy(destroyTransportedUnit = false)
val newUnit = civInfo.units.placeUnitNearTile(unitTile.position, upgradedUnit.name)
/** 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.name)!!
unit.copyStatisticsTo(resurrectedUnit)
} else { // Managed to upgrade
if (!isFree) civInfo.addGold(-goldCostOfUpgrade)
unit.copyStatisticsTo(newUnit)
newUnit.currentMovement = 0f
}
}.takeIf {
isFree || (
unit.civInfo.gold >= goldCostOfUpgrade
&& unit.currentMovement > 0
&& !unit.isEmbarked()
&& unit.upgrade.canUpgrade(unitToUpgradeTo = upgradedUnit)
)
}
)
}
fun getUpgradeAction(unit: MapUnit) =
getUpgradeAction(unit, isFree = false, isSpecial = false)
fun getFreeUpgradeAction(unit: MapUnit) =
getUpgradeAction(unit, isFree = true, isSpecial = false)
fun getAncientRuinsUpgradeAction(unit: MapUnit) =
getUpgradeAction(unit, isFree = true, isSpecial = true)
}

View File

@ -7,7 +7,7 @@ import com.unciv.logic.map.tile.RoadStatus
import com.unciv.models.ruleset.BeliefType import com.unciv.models.ruleset.BeliefType
import com.unciv.models.stats.Stats import com.unciv.models.stats.Stats
import com.unciv.testing.GdxTestRunner import com.unciv.testing.GdxTestRunner
import com.unciv.ui.worldscreen.unit.UnitActions import com.unciv.ui.worldscreen.unit.actions.UnitActions
import org.junit.Assert import org.junit.Assert
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test

View File

@ -2,7 +2,7 @@ package com.unciv.uniques
import com.badlogic.gdx.math.Vector2 import com.badlogic.gdx.math.Vector2
import com.unciv.testing.GdxTestRunner import com.unciv.testing.GdxTestRunner
import com.unciv.ui.worldscreen.unit.UnitActions import com.unciv.ui.worldscreen.unit.actions.UnitActions
import org.junit.Assert.assertNotNull import org.junit.Assert.assertNotNull
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test