mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-08 11:43:21 -04:00
Much more accurate improvement stat effects
This commit is contained in:
parent
60ea752c1f
commit
0561a7951c
@ -783,8 +783,6 @@ class CityConstructions : IsPartOfGameInfoSerialization {
|
||||
/**todo unify with [UnitActions.getImprovementConstructionActions] and [UnitTurnManager.workOnImprovement] - this won't allow e.g. a building to place a road */
|
||||
tileForImprovement.changeImprovement(improvement.name)
|
||||
city.civ.lastSeenImprovement[tileForImprovement.position] = improvement.name
|
||||
city.cityStats.update()
|
||||
city.civ.cache.updateCivResources()
|
||||
// If bought the worldscreen will not have been marked to update, and the new improvement won't show until later...
|
||||
GUI.setUpdateWorldOnNextRender()
|
||||
}
|
||||
|
@ -1,11 +1,9 @@
|
||||
package com.unciv.logic.map.mapunit
|
||||
|
||||
import com.unciv.Constants
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.civilization.LocationAction
|
||||
import com.unciv.logic.civilization.NotificationCategory
|
||||
import com.unciv.logic.civilization.NotificationIcon
|
||||
import com.unciv.logic.map.tile.RoadStatus
|
||||
import com.unciv.models.ruleset.unique.UniqueTriggerActivation
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
|
||||
@ -179,60 +177,12 @@ class UnitTurnManager(val unit: MapUnit) {
|
||||
UncivGame.Current.settings.addCompletedTutorialTask("Construct an improvement")
|
||||
|
||||
val improvementInProgress = tile.improvementInProgress ?: return
|
||||
when {
|
||||
improvementInProgress.startsWith(Constants.remove) -> {
|
||||
val removedFeatureName = improvementInProgress.removePrefix(Constants.remove)
|
||||
val tileImprovement = tile.getTileImprovement()
|
||||
if (tileImprovement != null
|
||||
&& tile.terrainFeatures.any {
|
||||
tileImprovement.terrainsCanBeBuiltOn.contains(it) && it == removedFeatureName
|
||||
}
|
||||
&& !tileImprovement.terrainsCanBeBuiltOn.contains(tile.baseTerrain)
|
||||
) {
|
||||
// We removed a terrain (e.g. Forest) and the improvement (e.g. Lumber mill) requires it!
|
||||
tile.removeImprovement()
|
||||
if (tile.resource != null) unit.civ.cache.updateCivResources() // unlikely, but maybe a mod makes a resource improvement dependent on a terrain feature
|
||||
}
|
||||
if (RoadStatus.values().any { improvementInProgress == it.removeAction }) {
|
||||
tile.removeRoad()
|
||||
} else {
|
||||
val removedFeatureObject = tile.ruleset.terrains[removedFeatureName]
|
||||
if (removedFeatureObject != null && removedFeatureObject.hasUnique(UniqueType.ProductionBonusWhenRemoved)) {
|
||||
tryProvideProductionToClosestCity(removedFeatureName)
|
||||
}
|
||||
tile.removeTerrainFeature(removedFeatureName)
|
||||
}
|
||||
}
|
||||
improvementInProgress == RoadStatus.Road.name -> tile.addRoad(RoadStatus.Road, unit.civ)
|
||||
improvementInProgress == RoadStatus.Railroad.name -> tile.addRoad(RoadStatus.Railroad, unit.civ)
|
||||
improvementInProgress == Constants.repair -> tile.setRepaired()
|
||||
else -> {
|
||||
tile.changeImprovement(improvementInProgress, unit.civ)
|
||||
}
|
||||
}
|
||||
tile.changeImprovement(improvementInProgress, unit.civ)
|
||||
|
||||
tile.improvementInProgress = null
|
||||
tile.getCity()?.updateCitizens = true
|
||||
}
|
||||
|
||||
|
||||
private fun tryProvideProductionToClosestCity(removedTerrainFeature: String) {
|
||||
val tile = unit.getTile()
|
||||
val closestCity = unit.civ.cities.minByOrNull { it.getCenterTile().aerialDistanceTo(tile) }
|
||||
@Suppress("FoldInitializerAndIfToElvis")
|
||||
if (closestCity == null) return
|
||||
val distance = closestCity.getCenterTile().aerialDistanceTo(tile)
|
||||
var productionPointsToAdd = if (distance == 1) 20 else 20 - (distance - 2) * 5
|
||||
if (tile.owningCity == null || tile.owningCity!!.civ != unit.civ) productionPointsToAdd =
|
||||
productionPointsToAdd * 2 / 3
|
||||
if (productionPointsToAdd > 0) {
|
||||
closestCity.cityConstructions.addProductionPoints(productionPointsToAdd)
|
||||
val locations = LocationAction(tile.position, closestCity.location)
|
||||
unit.civ.addNotification(
|
||||
"Clearing a [$removedTerrainFeature] has created [$productionPointsToAdd] Production for [${closestCity.name}]",
|
||||
locations, NotificationCategory.Production, NotificationIcon.Construction
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -316,14 +316,14 @@ open class Tile : IsPartOfGameInfoSerialization {
|
||||
improvementFunctions.changeImprovement(improvementStr, civToHandleCompletion)
|
||||
|
||||
// function handling when adding a road to the tile
|
||||
fun addRoad(roadType: RoadStatus, unitCivInfo: Civilization) {
|
||||
fun addRoad(roadType: RoadStatus, creatingCivInfo: Civilization?) {
|
||||
roadStatus = roadType
|
||||
roadIsPillaged = false
|
||||
if (getOwner() == null) {
|
||||
roadOwner = unitCivInfo.civName // neutral tile, use building unit
|
||||
unitCivInfo.neutralRoads.add(this.position)
|
||||
} else {
|
||||
if (getOwner() != null) {
|
||||
roadOwner = getOwner()!!.civName
|
||||
} else if (creatingCivInfo != null) {
|
||||
roadOwner = creatingCivInfo.civName // neutral tile, use building unit
|
||||
creatingCivInfo.neutralRoads.add(this.position)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,9 @@ package com.unciv.logic.map.tile
|
||||
|
||||
import com.unciv.Constants
|
||||
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.models.ruleset.tile.TileImprovement
|
||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
@ -164,11 +167,26 @@ class TileInfoImprovementFunctions(val tile: Tile) {
|
||||
}
|
||||
|
||||
|
||||
fun changeImprovement(improvementStr: String?, civToHandleCompletion:Civilization? = null) {
|
||||
tile.improvementIsPillaged = false
|
||||
tile.improvement = improvementStr
|
||||
fun changeImprovement(improvementName: String?,
|
||||
/** For road assignment and taking over tiles - DO NOT pass when simulating improvement effects! */
|
||||
civToActivateBroaderEffects:Civilization? = null) {
|
||||
val improvementObject = tile.ruleset.tileImprovements[improvementName]
|
||||
|
||||
when {
|
||||
improvementName?.startsWith(Constants.remove) == true -> {
|
||||
adtivateRemovalImprovement(improvementName, civToActivateBroaderEffects)
|
||||
}
|
||||
improvementName == RoadStatus.Road.name -> tile.addRoad(RoadStatus.Road, civToActivateBroaderEffects)
|
||||
improvementName == RoadStatus.Railroad.name -> tile.addRoad(RoadStatus.Railroad, civToActivateBroaderEffects)
|
||||
improvementName == Constants.repair -> tile.setRepaired()
|
||||
else -> {
|
||||
tile.improvementIsPillaged = false
|
||||
tile.improvement = improvementName
|
||||
|
||||
removeCreatesOneImprovementMarker()
|
||||
}
|
||||
}
|
||||
|
||||
val improvementObject = tile.getTileImprovement()
|
||||
if (improvementObject != null && improvementObject.hasUnique(UniqueType.RemovesFeaturesIfBuilt)) {
|
||||
// Remove terrainFeatures that a Worker can remove
|
||||
// and that aren't explicitly allowed under the improvement
|
||||
@ -182,14 +200,62 @@ class TileInfoImprovementFunctions(val tile: Tile) {
|
||||
tile.setTerrainFeatures(tile.terrainFeatures.filterNot { it in removableTerrainFeatures })
|
||||
}
|
||||
|
||||
if (civToHandleCompletion != null && improvementObject != null
|
||||
if (civToActivateBroaderEffects != null && improvementObject != null
|
||||
&& improvementObject.hasUnique(UniqueType.TakesOverAdjacentTiles)
|
||||
)
|
||||
UnitActions.takeOverTilesAround(civToHandleCompletion, tile)
|
||||
UnitActions.takeOverTilesAround(civToActivateBroaderEffects, tile)
|
||||
|
||||
if (tile.owningCity != null) {
|
||||
tile.owningCity!!.civ.cache.updateCivResources()
|
||||
tile.owningCity!!.reassignPopulationDeferred()
|
||||
val city = tile.owningCity
|
||||
if (city != null) {
|
||||
city.cityStats.update()
|
||||
city.civ.cache.updateCivResources()
|
||||
city.reassignPopulationDeferred()
|
||||
}
|
||||
}
|
||||
|
||||
private fun adtivateRemovalImprovement(
|
||||
improvementName: String,
|
||||
civToActivateBroaderEffects: Civilization?
|
||||
) {
|
||||
val removedFeatureName = improvementName.removePrefix(Constants.remove)
|
||||
val currentTileImprovement = tile.getTileImprovement()
|
||||
// We removed a terrain (e.g. Forest) and the improvement (e.g. Lumber mill) requires it!
|
||||
if (currentTileImprovement != null
|
||||
&& tile.terrainFeatures.any {
|
||||
currentTileImprovement.terrainsCanBeBuiltOn.contains(it) && it == removedFeatureName
|
||||
}
|
||||
&& !currentTileImprovement.terrainsCanBeBuiltOn.contains(tile.baseTerrain)
|
||||
) tile.removeImprovement()
|
||||
|
||||
if (RoadStatus.values().any { improvementName == it.removeAction }) {
|
||||
tile.removeRoad()
|
||||
} else {
|
||||
val removedFeatureObject = tile.ruleset.terrains[removedFeatureName]
|
||||
if (removedFeatureObject != null
|
||||
&& civToActivateBroaderEffects != null
|
||||
&& removedFeatureObject.hasUnique(UniqueType.ProductionBonusWhenRemoved)
|
||||
)
|
||||
tryProvideProductionToClosestCity(removedFeatureName, civToActivateBroaderEffects)
|
||||
|
||||
tile.removeTerrainFeature(removedFeatureName)
|
||||
}
|
||||
}
|
||||
|
||||
private fun tryProvideProductionToClosestCity(removedTerrainFeature: String, civ:Civilization) {
|
||||
val closestCity = civ.cities.minByOrNull { it.getCenterTile().aerialDistanceTo(tile) }
|
||||
@Suppress("FoldInitializerAndIfToElvis")
|
||||
if (closestCity == null) return
|
||||
val distance = closestCity.getCenterTile().aerialDistanceTo(tile)
|
||||
var productionPointsToAdd = if (distance == 1) 20 else 20 - (distance - 2) * 5
|
||||
if (tile.owningCity == null || tile.owningCity!!.civ != civ) productionPointsToAdd =
|
||||
productionPointsToAdd * 2 / 3
|
||||
if (productionPointsToAdd > 0) {
|
||||
closestCity.cityConstructions.addProductionPoints(productionPointsToAdd)
|
||||
val locations = LocationAction(tile.position, closestCity.location)
|
||||
civ.addNotification(
|
||||
"Clearing a [$removedTerrainFeature] has created [$productionPointsToAdd] Production for [${closestCity.name}]",
|
||||
locations, NotificationCategory.Production, NotificationIcon.Construction
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -206,9 +206,7 @@ class TileStatFunctions(val tile: Tile) {
|
||||
val tileClone = tile.clone()
|
||||
tileClone.setTerrainTransients()
|
||||
|
||||
if (improvement.name.startsWith(Constants.remove))
|
||||
tileClone.removeTerrainFeature(improvement.name.removePrefix(Constants.remove))
|
||||
else tileClone.changeImprovement(improvement.name)
|
||||
tileClone.changeImprovement(improvement.name)
|
||||
val futureStats = tileClone.stats.getTileStats(city, observingCiv, cityUniqueCache)
|
||||
|
||||
return futureStats.minus(currentStats)
|
||||
|
@ -491,9 +491,7 @@ object UnitActions {
|
||||
title = actionTextWithSideEffects("Create [$improvementName]", unique, unit),
|
||||
action = {
|
||||
val unitTile = unit.getTile()
|
||||
unitTile.improvementFunctions.removeCreatesOneImprovementMarker()
|
||||
unitTile.changeImprovement(improvementName, unit.civ)
|
||||
unitTile.stopWorkingOnImprovement()
|
||||
|
||||
// without this the world screen won't show the improvement because it isn't the 'last seen improvement'
|
||||
unit.civ.cache.updateViewableTiles()
|
||||
|
@ -3,9 +3,11 @@ package com.unciv.logic.map
|
||||
|
||||
import com.unciv.logic.city.City
|
||||
import com.unciv.logic.civilization.Civilization
|
||||
import com.unciv.logic.map.tile.RoadStatus
|
||||
import com.unciv.models.ruleset.tile.TerrainType
|
||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.models.stats.Stats
|
||||
import com.unciv.testing.GdxTestRunner
|
||||
import com.unciv.uniques.TestGame
|
||||
import org.junit.Assert
|
||||
@ -172,4 +174,63 @@ class TileImprovementConstructionTests {
|
||||
Assert.assertFalse(improvement.name, canBeBuilt)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun buildingRoadBuildsARoad(){
|
||||
val tile = tileMap[1,1]
|
||||
tile.improvementFunctions.changeImprovement("Road")
|
||||
assert(tile.roadStatus == RoadStatus.Road)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun removingRoadRemovesRoad(){
|
||||
val tile = tileMap[1,1]
|
||||
tile.roadStatus = RoadStatus.Road
|
||||
tile.improvementFunctions.changeImprovement("Remove Road")
|
||||
assert(tile.roadStatus == RoadStatus.None)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun removingForestRemovesForestAndLumbermill(){
|
||||
val tile = tileMap[1,1]
|
||||
tile.addTerrainFeature("Forest")
|
||||
tile.improvementFunctions.changeImprovement("Lumber mill")
|
||||
assert(tile.getTileImprovement()!!.name == "Lumber mill")
|
||||
tile.improvementFunctions.changeImprovement("Remove Forest")
|
||||
assert(tile.terrainFeatures.isEmpty())
|
||||
assert(tile.improvement == null) // Lumber mill can ONLY be on Forest, and is therefore removed
|
||||
}
|
||||
|
||||
@Test
|
||||
fun removingForestRemovesForestButNotCamp(){
|
||||
val tile = tileMap[1,1]
|
||||
tile.addTerrainFeature("Forest")
|
||||
tile.resource = "Deer"
|
||||
tile.baseTerrain = "Plains"
|
||||
tile.improvementFunctions.changeImprovement("Camp")
|
||||
assert(tile.getTileImprovement()!!.name == "Camp")
|
||||
tile.improvementFunctions.changeImprovement("Remove Forest")
|
||||
assert(tile.terrainFeatures.isEmpty())
|
||||
assert(tile.improvement == "Camp") // Camp can be both on Forest AND on Plains, so not removed
|
||||
}
|
||||
|
||||
@Test
|
||||
fun statsDiffFromRemovingForestTakesRemovedLumberMillIntoAccount(){
|
||||
val tile = tileMap[1,1]
|
||||
tile.baseTerrain = "Grassland"
|
||||
tile.addTerrainFeature("Forest")
|
||||
|
||||
val lumberMill = testGame.ruleset.tileImprovements["Lumber mill"]!!
|
||||
tile.improvementFunctions.changeImprovement(lumberMill.name)
|
||||
assert(tile.getTileImprovement() == lumberMill)
|
||||
|
||||
// 1f 1p from forest, 2p from lumber mill since all techs are researched
|
||||
val tileStats = tile.stats.getTileStats(civInfo)
|
||||
assert(tileStats.equals(Stats(production = 3f, food = 1f)))
|
||||
|
||||
val statsDiff = tile.stats.getStatDiffForImprovement(testGame.ruleset.tileImprovements["Remove Forest"]!!, civInfo, null)
|
||||
|
||||
// We'll be reverting back to grassland stats - 2f only
|
||||
assert(statsDiff.equals(Stats(food = +1f, production = -3f)))
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user