diff --git a/android/Images.Construction/UnitActionIcons/Transform.png b/android/Images.Construction/UnitActionIcons/Transform.png new file mode 100644 index 0000000000..c9ddb30ed8 Binary files /dev/null and b/android/Images.Construction/UnitActionIcons/Transform.png differ diff --git a/android/assets/jsons/translations/template.properties b/android/assets/jsons/translations/template.properties index 5a9852c545..b9648bd81c 100644 --- a/android/assets/jsons/translations/template.properties +++ b/android/assets/jsons/translations/template.properties @@ -946,6 +946,8 @@ Add in capital = Add to [comment] = Upgrade to [unitType] ([goldCost] gold) = Upgrade to [unitType]\n([goldCost] gold, [resources]) = +Transform to [unitType] = +Transform to [unitType]\n([resources]) = Found city = Promote = Health = @@ -1330,6 +1332,7 @@ Can upgrade from [unit] = Can upgrade from: = Upgrades to [upgradedUnit] = Obsolete with [obsoleteTech] = +Can Transform to [upgradedUnit] = Occurs on [listOfTerrains] = Occurs on: = Placed on [terrainType] = diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index e830ffa28d..97e1c5079d 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -1235,7 +1235,7 @@ class CivilizationInfo : IsPartOfGameInfoSerialization { Stat.Culture -> policies.storedCulture Stat.Science -> { if (tech.currentTechnology() == null) 0 - else tech.remainingScienceToTech(tech.currentTechnology()!!.name) + else tech.researchOfTech(tech.currentTechnology()!!.name) } Stat.Gold -> gold Stat.Faith -> religionManager.storedFaith diff --git a/core/src/com/unciv/models/UnitAction.kt b/core/src/com/unciv/models/UnitAction.kt index 279d3a2614..0757535588 100644 --- a/core/src/com/unciv/models/UnitAction.kt +++ b/core/src/com/unciv/models/UnitAction.kt @@ -83,6 +83,8 @@ enum class UnitActionType( { ImageGetter.getUnitActionPortrait("Promote") }, 'o', false, UncivSound.Promote), Upgrade("Upgrade", { ImageGetter.getUnitActionPortrait("Upgrade") }, 'u', UncivSound.Upgrade), + Transform("Transform", + { ImageGetter.getUnitActionPortrait("Transform") }, 'k', UncivSound.Upgrade), Pillage("Pillage", { ImageGetter.getUnitActionPortrait("Pillage") }, 'p', false), Paradrop("Paradrop", diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt index 10d1dff0ea..424a0cc983 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt @@ -480,7 +480,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags: CanHurryResearch("Can hurry technology research", UniqueTarget.Unit), CanTradeWithCityStateForGoldAndInfluence("Can undertake a trade mission with City-State, giving a large sum of gold and [amount] Influence", UniqueTarget.Unit), - + CanTransform("Can transform to [unit]", UniqueTarget.Unit), //endregion diff --git a/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt b/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt index a025277c9f..f2c8204875 100644 --- a/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt +++ b/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt @@ -18,6 +18,7 @@ import com.unciv.models.UncivSound import com.unciv.models.UnitAction import com.unciv.models.UnitActionType import com.unciv.models.ruleset.Building +import com.unciv.models.ruleset.unique.StateForConditionals import com.unciv.models.ruleset.unique.UniqueTriggerActivation import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.stats.Stat @@ -57,6 +58,7 @@ object UnitActions { addPromoteAction(unit, actionList) addUnitUpgradeAction(unit, actionList) + addTransformAction(unit, actionList) addPillageAction(unit, actionList, worldScreen) addParadropAction(unit, actionList) addAirSweepAction(unit, actionList) @@ -472,6 +474,70 @@ object UnitActions { fun getAncientRuinsUpgradeAction(unit: MapUnit) = getUpgradeAction(unit, isFree = true, isSpecial = true) + private fun addTransformAction( + unit: MapUnit, + actionList: ArrayList, + maxSteps: Int = Int.MAX_VALUE + ) { + val upgradeAction = getTransformAction(unit) + if (upgradeAction != null) actionList += upgradeAction + } + + /** */ + private fun getTransformAction( + unit: MapUnit + ): ArrayList? { + if (!unit.baseUnit().hasUnique(UniqueType.CanTransform)) return null // can't upgrade to anything + val unitTile = unit.getTile() + val civInfo = unit.civInfo + val transformList = ArrayList() + for (unique in unit.baseUnit().getMatchingUniques(UniqueType.CanTransform, + StateForConditionals(unit = unit, civInfo = civInfo, tile = unitTile))) { + val upgradedUnit = civInfo.getEquivalentUnit(unique.params[0]) + // don't show if haven't researched/is obsolete + if (!unit.canUpgrade(unitToUpgradeTo = upgradedUnit)) continue + + // Check _new_ resource requirements + // Using Counter to aggregate is a bit exaggerated, but - respect the mad modder. + val resourceRequirementsDelta = Counter() + 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 title = if (newResourceRequirementsString.isEmpty()) + "Transform to [${upgradedUnit.name}]" + else "Transform to [${upgradedUnit.name}]\n([$newResourceRequirementsString])" + + transformList.add(UnitAction(UnitActionType.Transform, + title = title, + action = { + unit.destroy() + val newUnit = civInfo.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.placeUnitNearTile(unitTile.position, unit.name)!! + unit.copyStatisticsTo(resurrectedUnit) + } else { // Managed to upgrade + unit.copyStatisticsTo(newUnit) + newUnit.currentMovement = 0f + } + }.takeIf { + unit.currentMovement > 0 + && !unit.isEmbarked() + && unit.canUpgrade(unitToUpgradeTo = upgradedUnit) + } + ) ) + } + return transformList + } + private fun addBuildingImprovementsAction(unit: MapUnit, actionList: ArrayList, tile: TileInfo, worldScreen: WorldScreen, unitTable: UnitTable) { if (!unit.hasUniqueToBuildImprovements) return if (unit.isEmbarked()) return diff --git a/docs/Credits.md b/docs/Credits.md index f4e1e599c3..a76d1e2b23 100644 --- a/docs/Credits.md +++ b/docs/Credits.md @@ -768,6 +768,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https: - [Trade](https://www.flaticon.com/free-icon/trade_4257019) created by Smashicons for Conduct Trade Mission - [Nothing](https://www.flaticon.com/free-icon/nothing_5084125) created by Freepik for Nothing construction process - Icon for Unique created by [vegeta1k95](https://github.com/vegeta1k95) +- [Transform] created by letstalkaboutdune ### Main menu