mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-09 15:29:32 +07:00
Worker AI for mods, step 2 (#5998)
* Worker AI for mods, step 2 Support for removing terrain features, both when we need to get rid of them for a resource, and when they plain reduce the yield of a tile Note that the "Remove <improvement>" was implemented WAY before templating and uniques were a thing - the correct solution in these enlightened times would be to separate the improvement *name* from the *effect*, so we could have e.g. a "Deforestation" improvement which would contain botth ["Removes [Jungle]", "Removes [Forest]"] or whatnot. For now I Constant'D the "Remove " so we can at least follow where it's used. * Reverted some of the auto-formatting so the PR is cleaner * Caught 'nullify yields' unique for terrain removal
This commit is contained in:
@ -63,6 +63,7 @@ object Constants {
|
|||||||
|
|
||||||
const val rising = "Rising"
|
const val rising = "Rising"
|
||||||
const val lowering = "Lowering"
|
const val lowering = "Lowering"
|
||||||
|
const val remove = "Remove "
|
||||||
|
|
||||||
const val minimumMovementEpsilon = 0.05
|
const val minimumMovementEpsilon = 0.05
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,9 @@ import com.unciv.logic.map.BFS
|
|||||||
import com.unciv.logic.map.MapUnit
|
import com.unciv.logic.map.MapUnit
|
||||||
import com.unciv.logic.map.RoadStatus
|
import com.unciv.logic.map.RoadStatus
|
||||||
import com.unciv.logic.map.TileInfo
|
import com.unciv.logic.map.TileInfo
|
||||||
|
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
|
||||||
|
|
||||||
private object WorkerAutomationConst {
|
private object WorkerAutomationConst {
|
||||||
/** Controls detailed logging of decisions to the console -Turn off for release builds! */
|
/** Controls detailed logging of decisions to the console -Turn off for release builds! */
|
||||||
@ -329,14 +331,6 @@ class WorkerAutomation(
|
|||||||
* Determine the improvement appropriate to a given tile and worker
|
* Determine the improvement appropriate to a given tile and worker
|
||||||
*/
|
*/
|
||||||
private fun chooseImprovement(unit: MapUnit, tile: TileInfo): TileImprovement? {
|
private fun chooseImprovement(unit: MapUnit, tile: TileInfo): TileImprovement? {
|
||||||
val improvementStringForResource: String? = when {
|
|
||||||
tile.resource == null || !tile.hasViewableResource(civInfo) -> null
|
|
||||||
tile.terrainFeatures.contains(Constants.marsh) && !isImprovementOnFeatureAllowed(tile) -> "Remove Marsh"
|
|
||||||
tile.terrainFeatures.contains("Fallout") && !isImprovementOnFeatureAllowed(tile) -> "Remove Fallout" // for really mad modders
|
|
||||||
tile.terrainFeatures.contains(Constants.jungle) && !isImprovementOnFeatureAllowed(tile) -> "Remove Jungle"
|
|
||||||
tile.terrainFeatures.contains(Constants.forest) && !isImprovementOnFeatureAllowed(tile) -> "Remove Forest"
|
|
||||||
else -> tile.tileResource.improvement
|
|
||||||
}
|
|
||||||
|
|
||||||
// turnsToBuild is what defines them as buildable
|
// turnsToBuild is what defines them as buildable
|
||||||
val tileImprovements = ruleSet.tileImprovements.filter {
|
val tileImprovements = ruleSet.tileImprovements.filter {
|
||||||
@ -349,6 +343,19 @@ class WorkerAutomation(
|
|||||||
.filter { it.second > 0f }
|
.filter { it.second > 0f }
|
||||||
.maxByOrNull { it.second }?.first
|
.maxByOrNull { it.second }?.first
|
||||||
|
|
||||||
|
val lastTerrain = tile.getLastTerrain()
|
||||||
|
|
||||||
|
fun isUnbuildableAndRemovable(terrain: Terrain): Boolean = terrain.unbuildable
|
||||||
|
&& ruleSet.tileImprovements.containsKey(Constants.remove + terrain.name)
|
||||||
|
|
||||||
|
val improvementStringForResource: String? = when {
|
||||||
|
tile.resource == null || !tile.hasViewableResource(civInfo) -> null
|
||||||
|
tile.terrainFeatures.isNotEmpty()
|
||||||
|
&& isUnbuildableAndRemovable(lastTerrain)
|
||||||
|
&& !isResourceImprovementAllowedOnFeature(tile) -> Constants.remove + lastTerrain.name
|
||||||
|
else -> tile.tileResource.improvement
|
||||||
|
}
|
||||||
|
|
||||||
val improvementString = when {
|
val improvementString = when {
|
||||||
tile.improvementInProgress != null -> tile.improvementInProgress!!
|
tile.improvementInProgress != null -> tile.improvementInProgress!!
|
||||||
improvementStringForResource != null && tileImprovements.containsKey(improvementStringForResource) -> improvementStringForResource
|
improvementStringForResource != null && tileImprovements.containsKey(improvementStringForResource) -> improvementStringForResource
|
||||||
@ -357,14 +364,16 @@ class WorkerAutomation(
|
|||||||
|
|
||||||
// Defence is more important that civilian improvements
|
// Defence is more important that civilian improvements
|
||||||
// While AI sucks in strategical placement of forts, allow a human does it manually
|
// While AI sucks in strategical placement of forts, allow a human does it manually
|
||||||
!civInfo.isPlayerCivilization() && evaluateFortPlacement(tile, civInfo, false) -> Constants.fort
|
!civInfo.isPlayerCivilization() && evaluateFortPlacement(tile, civInfo,false) -> Constants.fort
|
||||||
// I think we can assume that the unique improvement is better
|
// I think we can assume that the unique improvement is better
|
||||||
uniqueImprovement != null && tile.canBuildImprovement(uniqueImprovement, civInfo)
|
uniqueImprovement != null && tile.canBuildImprovement(uniqueImprovement, civInfo)
|
||||||
&& unit.canBuildImprovement(uniqueImprovement, tile) ->
|
&& unit.canBuildImprovement(uniqueImprovement, tile) ->
|
||||||
uniqueImprovement.name
|
uniqueImprovement.name
|
||||||
|
|
||||||
tile.terrainFeatures.contains("Fallout") -> "Remove Fallout"
|
lastTerrain.let {
|
||||||
tile.terrainFeatures.contains(Constants.marsh) -> "Remove Marsh"
|
isUnbuildableAndRemovable(it) &&
|
||||||
|
(Automation.rankStatsValue(it, civInfo) < 0 || it.hasUnique(UniqueType.NullifyYields) )
|
||||||
|
} -> Constants.remove + lastTerrain.name
|
||||||
tile.terrainFeatures.contains(Constants.jungle) -> Constants.tradingPost
|
tile.terrainFeatures.contains(Constants.jungle) -> Constants.tradingPost
|
||||||
tile.terrainFeatures.contains("Oasis") -> return null
|
tile.terrainFeatures.contains("Oasis") -> return null
|
||||||
tile.terrainFeatures.contains(Constants.forest) && tileImprovements.containsKey("Lumber mill") -> "Lumber mill"
|
tile.terrainFeatures.contains(Constants.forest) && tileImprovements.containsKey("Lumber mill") -> "Lumber mill"
|
||||||
@ -372,10 +381,7 @@ class WorkerAutomation(
|
|||||||
tile.baseTerrain in listOf(Constants.grassland, Constants.desert, Constants.plains)
|
tile.baseTerrain in listOf(Constants.grassland, Constants.desert, Constants.plains)
|
||||||
&& tileImprovements.containsKey("Farm") -> "Farm"
|
&& tileImprovements.containsKey("Farm") -> "Farm"
|
||||||
tile.isAdjacentToFreshwater && tileImprovements.containsKey("Farm") -> "Farm"
|
tile.isAdjacentToFreshwater && tileImprovements.containsKey("Farm") -> "Farm"
|
||||||
tile.baseTerrain in listOf(Constants.tundra, Constants.snow) && tileImprovements.containsKey(Constants.tradingPost)
|
|
||||||
-> Constants.tradingPost
|
|
||||||
|
|
||||||
// This is the ONLY thing that will catch modded non-unique improvements
|
|
||||||
bestBuildableImprovement != null -> bestBuildableImprovement.name
|
bestBuildableImprovement != null -> bestBuildableImprovement.name
|
||||||
else -> return null
|
else -> return null
|
||||||
}
|
}
|
||||||
@ -387,7 +393,7 @@ class WorkerAutomation(
|
|||||||
*
|
*
|
||||||
* Assumes the caller ensured that terrainFeature and resource are both present!
|
* Assumes the caller ensured that terrainFeature and resource are both present!
|
||||||
*/
|
*/
|
||||||
private fun isImprovementOnFeatureAllowed(tile: TileInfo): Boolean {
|
private fun isResourceImprovementAllowedOnFeature(tile: TileInfo): Boolean {
|
||||||
val resourceImprovementName = tile.tileResource.improvement
|
val resourceImprovementName = tile.tileResource.improvement
|
||||||
?: return false
|
?: return false
|
||||||
val resourceImprovement = ruleSet.tileImprovements[resourceImprovementName]
|
val resourceImprovement = ruleSet.tileImprovements[resourceImprovementName]
|
||||||
|
@ -628,8 +628,8 @@ class MapUnit {
|
|||||||
UncivGame.Current.settings.addCompletedTutorialTask("Construct an improvement")
|
UncivGame.Current.settings.addCompletedTutorialTask("Construct an improvement")
|
||||||
|
|
||||||
when {
|
when {
|
||||||
tile.improvementInProgress!!.startsWith("Remove ") -> {
|
tile.improvementInProgress!!.startsWith(Constants.remove) -> {
|
||||||
val removedFeatureName = tile.improvementInProgress!!.removePrefix("Remove ")
|
val removedFeatureName = tile.improvementInProgress!!.removePrefix(Constants.remove)
|
||||||
val tileImprovement = tile.getTileImprovement()
|
val tileImprovement = tile.getTileImprovement()
|
||||||
if (tileImprovement != null
|
if (tileImprovement != null
|
||||||
&& tile.terrainFeatures.any {
|
&& tile.terrainFeatures.any {
|
||||||
|
@ -487,7 +487,7 @@ open class TileInfo {
|
|||||||
&& getTileImprovement().let { it != null && it.hasUnique("Irremovable") } -> false
|
&& getTileImprovement().let { it != null && it.hasUnique("Irremovable") } -> false
|
||||||
|
|
||||||
// Terrain blocks BUILDING improvements - removing things (such as fallout) is fine
|
// Terrain blocks BUILDING improvements - removing things (such as fallout) is fine
|
||||||
!improvement.name.startsWith("Remove ") &&
|
!improvement.name.startsWith(Constants.remove) &&
|
||||||
getAllTerrains().any { it.getMatchingUniques(UniqueType.RestrictedBuildableImprovements)
|
getAllTerrains().any { it.getMatchingUniques(UniqueType.RestrictedBuildableImprovements)
|
||||||
.any { unique -> !improvement.matchesFilter(unique.params[0]) } } -> false
|
.any { unique -> !improvement.matchesFilter(unique.params[0]) } } -> false
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ class MapEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(BaseScr
|
|||||||
}).row()
|
}).row()
|
||||||
|
|
||||||
for (improvement in ruleset.tileImprovements.values) {
|
for (improvement in ruleset.tileImprovements.values) {
|
||||||
if (improvement.name.startsWith("Remove")) continue
|
if (improvement.name.startsWith(Constants.remove)) continue
|
||||||
if (improvement.name == Constants.cancelImprovementOrder) continue
|
if (improvement.name == Constants.cancelImprovementOrder) continue
|
||||||
val improvementImage = getHex(ImageGetter.getImprovementIcon(improvement.name, 40f))
|
val improvementImage = getHex(ImageGetter.getImprovementIcon(improvement.name, 40f))
|
||||||
improvementImage.onClick {
|
improvementImage.onClick {
|
||||||
|
@ -84,7 +84,9 @@ class ImprovementPickerScreen(val tileInfo: TileInfo, unit: MapUnit, val onAccep
|
|||||||
val provideResource = tileInfo.hasViewableResource(currentPlayerCiv) && tileInfo.tileResource.improvement == improvement.name
|
val provideResource = tileInfo.hasViewableResource(currentPlayerCiv) && tileInfo.tileResource.improvement == improvement.name
|
||||||
if (provideResource) labelText += "\n" + "Provides [${tileInfo.resource}]".tr()
|
if (provideResource) labelText += "\n" + "Provides [${tileInfo.resource}]".tr()
|
||||||
val removeImprovement = (improvement.name != RoadStatus.Road.name
|
val removeImprovement = (improvement.name != RoadStatus.Road.name
|
||||||
&& improvement.name != RoadStatus.Railroad.name && !improvement.name.startsWith("Remove") && improvement.name != Constants.cancelImprovementOrder)
|
&& improvement.name != RoadStatus.Railroad.name
|
||||||
|
&& !improvement.name.startsWith(Constants.remove)
|
||||||
|
&& improvement.name != Constants.cancelImprovementOrder)
|
||||||
if (tileInfo.improvement != null && removeImprovement) labelText += "\n" + "Replaces [${tileInfo.improvement}]".tr()
|
if (tileInfo.improvement != null && removeImprovement) labelText += "\n" + "Replaces [${tileInfo.improvement}]".tr()
|
||||||
|
|
||||||
val pickNow = if (tileInfo.improvementInProgress != improvement.name)
|
val pickNow = if (tileInfo.improvementInProgress != improvement.name)
|
||||||
|
@ -261,7 +261,7 @@ object ImageGetter {
|
|||||||
|
|
||||||
|
|
||||||
fun getImprovementIcon(improvementName: String, size: Float = 20f): Actor {
|
fun getImprovementIcon(improvementName: String, size: Float = 20f): Actor {
|
||||||
if (improvementName.startsWith("Remove") || improvementName == Constants.cancelImprovementOrder)
|
if (improvementName.startsWith(Constants.remove) || improvementName == Constants.cancelImprovementOrder)
|
||||||
return Table().apply { add(getImage("OtherIcons/Stop")).size(size) }
|
return Table().apply { add(getImage("OtherIcons/Stop")).size(size) }
|
||||||
|
|
||||||
val iconGroup = getImage("ImprovementIcons/$improvementName").surroundWithCircle(size)
|
val iconGroup = getImage("ImprovementIcons/$improvementName").surroundWithCircle(size)
|
||||||
|
Reference in New Issue
Block a user