-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Countable scopes #11389
Comments
I'm not sure what it is you're actually suggesting. |
I am suggesting you to add more countables. Many of them are scope-bound, so they would apply to specific scope.
For example: The population in a Game-wide scope is a world population In Civ-wide is a Civ population In City-wide is the population of a city Any questions? |
Yes, that's not an actual suggestion. That doesn't say what it would look like from a modders perspective at all. |
So in that case, it would look like this: <when number of [scopeFilter][countable] is greater than [scopeFilter][countable]> scopeFilter allowed values are:
And the gameWideScope (for all civilizations in game) Examples: <when number of [in all cities with a world wonder][number of cities] is greater than [0]> Returns true when a civilization has at least one city with world wonder <when number of [gameWideScope][population] is greater than [200]> Returns true when the global population is more than 200 <when number of [{gameWideScope} {Military}][Number of units] is greater than [100]> Returns true when the number of military units owned by all civilizations is more than 100 Now you probably know what I mean. If you have some suggestions, share them with me. It's just a concept for now. |
@yairm210 I hope I described my idea in a way detailed enough. What do you think about it? |
Index: core/src/com/unciv/models/ruleset/unique/Conditionals.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/core/src/com/unciv/models/ruleset/unique/Conditionals.kt b/core/src/com/unciv/models/ruleset/unique/Conditionals.kt
--- a/core/src/com/unciv/models/ruleset/unique/Conditionals.kt (revision 7dfa6682e08ebd353e45aa5b81888be776224737)
+++ b/core/src/com/unciv/models/ruleset/unique/Conditionals.kt (date 1712574009931)
@@ -99,28 +99,9 @@
return compare(statReserve, lowerLimit * gameSpeedModifier, upperLimit * gameSpeedModifier)
}
- fun getCountableAmount(countable: String): Float? {
- if (countable.toFloatOrNull() != null) return countable.toFloat()
-
- val relevantStat = Stat.safeValueOf(countable)
-
- if (relevantStat != null) {
- return if (relevantCity != null) {
- relevantCity!!.getStatReserve(relevantStat).toFloat()
- } else if (relevantStat in Stat.statsWithCivWideField && relevantCiv != null) {
- relevantCiv!!.getStatReserve(relevantStat).toFloat()
- } else {
- null
- }
- }
-
- if (gameInfo == null) return null
-
- if (countable == "year") return gameInfo!!.getYear(gameInfo!!.turns).toFloat()
- if (gameInfo!!.ruleset.tileResources.containsKey(countable))
- return getResourceAmount(countable).toFloat()
-
- return null
+ fun getCountableAmount(id: String): Float? {
+ val countable = Countables[id, gameInfo?.ruleset] ?: return null
+ return countable(gameInfo, relevantCiv, relevantCity)
}
fun compareCountables(
Index: core/src/com/unciv/models/ruleset/unique/UniqueParameterType.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueParameterType.kt b/core/src/com/unciv/models/ruleset/unique/UniqueParameterType.kt
--- a/core/src/com/unciv/models/ruleset/unique/UniqueParameterType.kt (revision 7dfa6682e08ebd353e45aa5b81888be776224737)
+++ b/core/src/com/unciv/models/ruleset/unique/UniqueParameterType.kt (date 1712574011246)
@@ -76,25 +76,17 @@
},
Countable("countable", "1000", "This indicate a number or a numeric variable") {
- // todo add more countables
- private val knownValues = setOf(
- "year"
- )
-
- override fun isKnownValue(parameterText: String, ruleset: Ruleset): Boolean {
- if (parameterText in knownValues) return true
- if (parameterText.toIntOrNull() != null) return true
- if (parameterText.toFloatOrNull() != null) return true
- if (Stat.isStat(parameterText)) return true
- if (parameterText in ruleset.tileResources) return true
- return false
- }
+ override fun isKnownValue(parameterText: String, ruleset: Ruleset) =
+ Countables[parameterText, ruleset] != null
override fun getErrorSeverity(
parameterText: String, ruleset: Ruleset): UniqueType.UniqueParameterErrorSeverity? {
return if (isKnownValue(parameterText, ruleset)) null
else UniqueType.UniqueParameterErrorSeverity.RulesetSpecific
}
+
+ override fun getTranslationWriterStringsForOutput() =
+ Countables.getTranslationWriterStringsForOutput()
},
// todo potentially remove if OneTimeRevealSpecificMapTiles changes
Index: core/src/com/unciv/models/ruleset/unique/Countables.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/core/src/com/unciv/models/ruleset/unique/Countables.kt b/core/src/com/unciv/models/ruleset/unique/Countables.kt
new file mode 100644
--- /dev/null (date 1712574009740)
+++ b/core/src/com/unciv/models/ruleset/unique/Countables.kt (date 1712574009740)
@@ -0,0 +1,93 @@
+package com.unciv.models.ruleset.unique
+
+import com.unciv.logic.GameInfo
+import com.unciv.logic.city.City
+import com.unciv.logic.civilization.Civilization
+import com.unciv.models.ruleset.Ruleset
+import com.unciv.models.ruleset.tile.TileResource
+import com.unciv.models.stats.Stat
+
+interface Countables {
+ val name: String
+ val id: String
+ operator fun invoke(gameInfo: GameInfo?, civ: Civilization?, city: City?): Float?
+
+ companion object {
+ operator fun get(id: String, ruleset: Ruleset?) =
+ GlobalCountables.idMap[id]
+ ?: CivCountables.idMap[id]
+ ?: CityCountables.idMap[id]
+ ?: Stat.safeValueOf(id)?.let { StatCountable(it) }
+ ?: ruleset?.tileResources?.get(id)?.let { ResourceCountable(it) }
+ ?: id.toFloatOrNull()?.let { LiteralCountable(it) }
+
+ fun getTranslationWriterStringsForOutput() =
+ GlobalCountables.idMap.keys +
+ CivCountables.idMap.keys +
+ CityCountables.idMap.keys
+ }
+}
+
+enum class GlobalCountables(override val id: String, val getValue: (GameInfo) -> Float?) : Countables {
+ Year("year", {
+ it.getYear(it.turns).toFloat()
+ })
+ ;
+
+ override fun invoke(gameInfo: GameInfo?, civ: Civilization?, city: City?) =
+ if (gameInfo == null) null else getValue(gameInfo)
+
+ companion object {
+ val idMap = values().associateBy { it.id }
+ }
+}
+
+enum class CivCountables(override val id: String, val getValue: (Civilization) -> Float?) : Countables {
+ Cities("cities", {
+ it.cities.size.toFloat()
+ })
+ ;
+ override fun invoke(gameInfo: GameInfo?, civ: Civilization?, city: City?) =
+ if (civ == null) null else getValue(civ)
+
+ companion object {
+ val idMap = GlobalCountables.values().associateBy { it.id }
+ }
+}
+
+enum class CityCountables(override val id: String, val getValue: (City) -> Float?) : Countables {
+ Citizens("citizens", {
+ it.population.population.toFloat()
+ })
+ ;
+ override fun invoke(gameInfo: GameInfo?, civ: Civilization?, city: City?) =
+ if (city == null) null else getValue(city)
+
+ companion object {
+ val idMap = GlobalCountables.values().associateBy { it.id }
+ }
+}
+
+class StatCountable(private val stat: Stat) : Countables {
+ override val name = stat.name
+ override val id = stat.name
+ override fun invoke(gameInfo: GameInfo?, civ: Civilization?, city: City?) =
+ city?.getStatReserve(stat)?.toFloat()
+ ?: civ?.takeIf { stat in Stat.statsWithCivWideField }?.getStatReserve(stat)?.toFloat()
+}
+
+class LiteralCountable(private val value: Float) : Countables {
+ override val name = ""
+ override val id = ""
+ override fun invoke(gameInfo: GameInfo?, civ: Civilization?, city: City?) = value
+}
+
+class ResourceCountable(private val tileResource: TileResource) : Countables {
+ override val name = tileResource.name
+ override val id = tileResource.name
+ override fun invoke(gameInfo: GameInfo?, civ: Civilization?, city: City?): Float {
+ if (city != null) return city.getAvailableResourceAmount(name).toFloat()
+ if (civ != null) return civ.getResourceAmount(name).toFloat()
+ return 0f
+ }
+}
Better read: branch on my fork |
@SomeTroglodyte I've got a two questions:
|
In that model there are no scope modifiers (it does -quoting-: "to have countable identifiers unqiuely bound to a scope type each, and use all other conditionals on the same Unique as filters")- each ICountable.id needs to uniquely identify scope. For simplicity, that was more of an experiment to see if such a class hierarchy model could work. And it can - one interface implemented both by enums and by directly-instantiated classes. |
@SomeTroglodyte You say that the countable identifiers should be bound to specific scope. But I am wondering how would we count things that met the additional filters. Example: Let's assume I need the count of owned units of a specific type, like number of Air units or a Wounded Land units (combined filters) What syntax would you propose to support filters? Let's ask @yairm210 for the advice. |
Not "should" per se. "Could" as in, might make for simpler and more maintainable code.
Very good! Someone needs to invest brainpower, and I'm feeling a little low on that resource.
With that experimental code, |
I'm doing a bump here, due to lack of activity. So, in that case, how do we define a variable scope? All of these examples do the same - return true when there is more than 25 cities on the entire map Solution 1 - Additional scope parameters <when [Game-Wide] [Number of Cities] is greater than [25]> Solution 2 - Scope-specific names <when [Number of All Cities] is greater than [25]> Solution 3 - Countable limiters and modifiers <when [Number of Cities] is greater than [25]> My thoughts: Solution 1, in my opinion is the best. The drawback of 4 instead of 2 parameters is not really an issue. Solution 2 requires making a huge amount of countable filter values (possibly even hundreds which is contradictory with modding philosophy) Solution 3 makes it difficult to distinguish between countable limiter/modifier and the next conditional (all conditionals must be true to make an unique active). There is also a problem regarding the scope of the second countable. If you want to opt for Solution 3, you will need to add some kind of countable limiter/modifier, denoted by different character (maybe @, pronounced as "at") We need to decide between these three solutions. Maybe we should make a poll? |
This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 15 days. |
This issue was closed because it has been stalled for 5 days with no activity. |
Before creating
Problem Description
@yairm210 I've recently introduced the countable comparison unique. However, for now it supports only a limited number of countables. There is a lot more of countables to implement. Many of proposed countables are heavily dependent on scopes, so they would apply either to:
Entire playthrough (Game-wide)
Civilization(s)
City/cities
Unit(s)
Tile(s)
Related Issue Links
#11308
Desired Solution
Here is the list of the proposed countables
Game-wide:
Current year
Current turn
Years since beginning
Number of all civilizations ever present
Number of current civilizations
Number of cities of all civilizations
Number of tiles (with tile filter)
Global population
Civ scope (supports Game-wide scope)
Number of cities (with civ filter)
Number of cities (with civ and city filter)
Total stats per turn (stat filter, optionally civ and city filter)
Total stockpiled stats (gold, science, culture, faith)
Total stats ever produced
Total resources currently stockpiled
Total resources ever stockpiled
Number of traded resources
Number of wars
Number of defensive pacts
Number of science agreements
Number of wonders built
Number of units
Civ population
City-wide (supports civ and game wide)
Number of buildings
Number of wonders
Stat production per turn
Worked tiles
City population
Turns until population growth/construction complete/border expansion
Unit-wide (supports previous scopes)
XP
Base strength
Max strength
HP
Number of promotions
Alternative Approaches
If you think there is a better way, share your thoughts with me.
Additional Context
No response
The text was updated successfully, but these errors were encountered: