diff --git a/core/src/com/unciv/logic/city/CityConstructions.kt b/core/src/com/unciv/logic/city/CityConstructions.kt index 5736867c4f..37da95db85 100644 --- a/core/src/com/unciv/logic/city/CityConstructions.kt +++ b/core/src/com/unciv/logic/city/CityConstructions.kt @@ -29,6 +29,7 @@ import com.unciv.ui.screens.civilopediascreen.CivilopediaCategories import com.unciv.ui.screens.civilopediascreen.FormattedLine import com.unciv.ui.screens.worldscreen.unit.actions.UnitActions import kotlin.math.ceil +import kotlin.math.min import kotlin.math.roundToInt @@ -314,13 +315,17 @@ class CityConstructions : IsPartOfGameInfoSerialization { val productionCost = (construction as INonPerpetualConstruction).getProductionCost(city.civ) if (inProgressConstructions.containsKey(currentConstructionFromQueue) && inProgressConstructions[currentConstructionFromQueue]!! >= productionCost) { - productionOverflow = inProgressConstructions[currentConstructionFromQueue]!! - productionCost - // See the URL below for explanation for this cap - // https://forums.civfanatics.com/threads/hammer-overflow.419352/ - val maxOverflow = maxOf(productionCost, city.cityStats.currentCityStats.production.roundToInt()) - if (productionOverflow > maxOverflow) - productionOverflow = maxOverflow - constructionComplete(construction) + val potentialOverflow = inProgressConstructions[currentConstructionFromQueue]!! - productionCost + if (constructionComplete(construction)){ + // See the URL below for explanation for this cap + // https://forums.civfanatics.com/threads/hammer-overflow.419352/ + val maxOverflow = maxOf(productionCost, city.cityStats.currentCityStats.production.roundToInt()) + productionOverflow = min(maxOverflow, potentialOverflow) + } + else { + city.civ.addNotification("No space available to place [${construction.name}] near [${city.name}]", + city.location, NotificationCategory.Production, construction.name) + } } } } @@ -405,8 +410,11 @@ class CityConstructions : IsPartOfGameInfoSerialization { } } - private fun constructionComplete(construction: INonPerpetualConstruction) { - construction.postBuildEvent(this) + /** Returns false if we tried to construct a unit but it has nowhere to go */ + private fun constructionComplete(construction: INonPerpetualConstruction): Boolean { + val managedToConstruct = construction.postBuildEvent(this) + if (!managedToConstruct) return false + if (construction.name in inProgressConstructions) inProgressConstructions.remove(construction.name) if (construction.name == currentConstructionFromQueue) @@ -426,7 +434,8 @@ class CityConstructions : IsPartOfGameInfoSerialization { } } else { val icon = if (construction is Building) buildingIcon else construction.name // could be a unit, in which case take the unit name. - city.civ.addNotification("[${construction.name}] has been built in [" + city.name + "]", + city.civ.addNotification( + "[${construction.name}] has been built in [${city.name}]", city.location, NotificationCategory.Production, NotificationIcon.Construction, icon) } @@ -442,6 +451,7 @@ class CityConstructions : IsPartOfGameInfoSerialization { NotificationCategory.General, NotificationIcon.Construction, buildingIcon) } } + return true } fun addBuilding(buildingName: String) { diff --git a/core/src/com/unciv/models/ruleset/IConstruction.kt b/core/src/com/unciv/models/ruleset/IConstruction.kt index 25dd80040b..35cb9519c7 100644 --- a/core/src/com/unciv/models/ruleset/IConstruction.kt +++ b/core/src/com/unciv/models/ruleset/IConstruction.kt @@ -26,6 +26,8 @@ interface INonPerpetualConstruction : IConstruction, INamed, IHasUniques { fun getProductionCost(civInfo: Civilization): Int fun getStatBuyCost(city: City, stat: Stat): Int? fun getRejectionReasons(cityConstructions: CityConstructions): Sequence + + /** Returns whether was successful - can fail for units if we can't place them */ fun postBuildEvent(cityConstructions: CityConstructions, boughtWith: Stat? = null): Boolean // Yes I'm hilarious. /** Only checks if it has the unique to be bought with this stat, not whether it is purchasable at all */