diff --git a/changelog.md b/changelog.md index 8bb2120ffb..911b5940f0 100644 --- a/changelog.md +++ b/changelog.md @@ -11,8 +11,6 @@ Mods: Added lake-land edge tiles - by legacymtgsalvationuser69544 -Move Capital building function from city to civ - By SeventhM - ## 4.14.10 Fixed Flood Plains generation diff --git a/core/src/com/unciv/logic/map/mapunit/MapUnit.kt b/core/src/com/unciv/logic/map/mapunit/MapUnit.kt index fd2771d775..dbf8d6dbce 100644 --- a/core/src/com/unciv/logic/map/mapunit/MapUnit.kt +++ b/core/src/com/unciv/logic/map/mapunit/MapUnit.kt @@ -109,7 +109,13 @@ class MapUnit : IsPartOfGameInfoSerialization { } } + @Deprecated("As of 4.14.12 - use statusMap instead (for lookup performance)") + /** This is still the source of truth, currently replicating all statuses to use both the map and the list + so that ongoing games retain their statuses until we're ready to switch over */ var statuses = ArrayList() + /** New status container - should NOT serve as source of truth since MP games going + * back and forth between older versions will lose this data! */ + var statusMap = HashMap() //endregion //region Transient fields @@ -217,7 +223,8 @@ class MapUnit : IsPartOfGameInfoSerialization { toReturn.religion = religion toReturn.religiousStrengthLost = religiousStrengthLost toReturn.movementMemories = movementMemories.copy() - toReturn.statuses = ArrayList(statuses) + toReturn.statuses = ArrayList(statuses) + toReturn.statusMap = HashMap(statusMap) toReturn.mostRecentMoveType = mostRecentMoveType toReturn.attacksSinceTurnStart = ArrayList(attacksSinceTurnStart.map { Vector2(it) }) return toReturn @@ -583,6 +590,9 @@ class MapUnit : IsPartOfGameInfoSerialization { if (civ.matchesFilter(filter, cache.state, false)) return true if (nonUnitUniquesMap.hasUnique(filter, cache.state)) if (promotions.promotions.contains(filter)) return true + // Badly optimized, but it's rare that statuses is even non-empty + // Statuses really should be converted to a hashmap + if (getStatus(name) != null) return true return false } } @@ -648,7 +658,11 @@ class MapUnit : IsPartOfGameInfoSerialization { promotions.setTransients(this) baseUnit = ruleset.units[name] ?: throw java.lang.Exception("Unit $name is not found!") - for (status in statuses) status.setTransients(this) + + for (status in statuses){ + status.setTransients(this) + statusMap[status.name] = status + } updateUniques() if (action == UnitActionType.Automate.value){ @@ -1033,8 +1047,11 @@ class MapUnit : IsPartOfGameInfoSerialization { } } + fun getStatus(name:String): UnitStatus? = statuses.firstOrNull { it.name == name } + fun hasStatus(name:String): Boolean = getStatus(name) != null + fun setStatus(name:String, turns:Int){ - val existingStatus = statuses.firstOrNull { it.name == name } + val existingStatus = getStatus(name) if (existingStatus != null){ if (turns > existingStatus.turnsLeft) existingStatus.turnsLeft = turns return @@ -1045,6 +1062,7 @@ class MapUnit : IsPartOfGameInfoSerialization { status.turnsLeft = turns status.setTransients(this) statuses.add(status) + statusMap[status.name] = status updateUniques() for (unique in getTriggeredUniques(UniqueType.TriggerUponStatusGain){ it.params[0] == name }) @@ -1053,6 +1071,7 @@ class MapUnit : IsPartOfGameInfoSerialization { fun removeStatus(name:String){ val wereRemoved = statuses.removeAll { it.name == name } + statusMap.remove(name) if (!wereRemoved) return updateUniques() diff --git a/core/src/com/unciv/models/ruleset/unique/Conditionals.kt b/core/src/com/unciv/models/ruleset/unique/Conditionals.kt index 29ad2a716d..d86284e263 100644 --- a/core/src/com/unciv/models/ruleset/unique/Conditionals.kt +++ b/core/src/com/unciv/models/ruleset/unique/Conditionals.kt @@ -213,10 +213,10 @@ object Conditionals { state.relevantUnit?.matchesFilter(conditional.params[0]) == true UniqueType.ConditionalUnitWithPromotion -> state.relevantUnit != null && (state.relevantUnit!!.promotions.promotions.contains(conditional.params[0]) - || state.relevantUnit!!.statuses.any { it.name == conditional.params[0] } ) + || state.relevantUnit!!.hasStatus(conditional.params[0]) ) UniqueType.ConditionalUnitWithoutPromotion -> state.relevantUnit != null && !(state.relevantUnit!!.promotions.promotions.contains(conditional.params[0]) - || state.relevantUnit!!.statuses.any { it.name == conditional.params[0] } ) + || state.relevantUnit!!.hasStatus(conditional.params[0]) ) UniqueType.ConditionalAttacking -> state.combatAction == CombatAction.Attack UniqueType.ConditionalDefending -> state.combatAction == CombatAction.Defend UniqueType.ConditionalAboveHP -> state.relevantUnit != null && state.relevantUnit!!.health > conditional.params[0].toInt() diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt b/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt index 06a616b431..b45bbf66bc 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt @@ -982,7 +982,7 @@ object UniqueTriggerActivation { } UniqueType.OneTimeUnitLoseStatus -> { if (unit == null) return null - if (unit.statuses.none { it.name == unique.params[1] }) return null + if (!unit.hasStatus(unique.params[1])) return null return { unit.removeStatus(unique.params[1]) true diff --git a/core/src/com/unciv/ui/screens/worldscreen/unit/actions/UnitActionModifiers.kt b/core/src/com/unciv/ui/screens/worldscreen/unit/actions/UnitActionModifiers.kt index 7587f0450d..af51f39e83 100644 --- a/core/src/com/unciv/ui/screens/worldscreen/unit/actions/UnitActionModifiers.kt +++ b/core/src/com/unciv/ui/screens/worldscreen/unit/actions/UnitActionModifiers.kt @@ -121,7 +121,7 @@ object UnitActionModifiers { UniqueType.UnitActionRemovingPromotion -> { val promotionName = conditional.params[0] // if has a status, remove that instead - the promotion is 'safe' - if (unit.statuses.any { it.name == promotionName }) { + if (unit.hasStatus(promotionName)) { unit.removeStatus(promotionName) } else { // check for real promotion unit.promotions.removePromotion(promotionName)