Notification for "Policy branch unlocked" clickable (#10655)

* Ruleset-validate some Unique amounts to be positive

* Add TechAction for tech gained from Ruins

* Allow PolicyPickerScreen to highlight a Policy

* Add the 'PolicyAction' NotificationAction

* Use the new PolicyAction
This commit is contained in:
SomeTroglodyte 2023-12-03 21:12:26 +01:00 committed by GitHub
parent 1f47fff05d
commit 5061b29197
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 198 additions and 153 deletions

View File

@ -12,6 +12,7 @@ import com.unciv.ui.screens.civilopediascreen.CivilopediaScreen
import com.unciv.ui.screens.diplomacyscreen.DiplomacyScreen
import com.unciv.ui.screens.overviewscreen.EmpireOverviewCategories
import com.unciv.ui.screens.overviewscreen.EmpireOverviewScreen
import com.unciv.ui.screens.pickerscreens.PolicyPickerScreen
import com.unciv.ui.screens.pickerscreens.PromotionPickerScreen
import com.unciv.ui.screens.pickerscreens.TechPickerScreen
import com.unciv.ui.screens.worldscreen.WorldScreen
@ -146,6 +147,15 @@ class OverviewAction(
}
}
/** Open policy picker, optionally preselecting [select] (how or if at all that works for branches is [PolicyPickerScreen]'s business) */
class PolicyAction(
private val select: String? = null
) : NotificationAction {
override fun execute(worldScreen: WorldScreen) {
worldScreen.game.pushScreen(PolicyPickerScreen(worldScreen.selectedCiv, worldScreen.canChangeState, select))
}
}
@Suppress("PrivatePropertyName") // These names *must* match their class name, see below
internal class NotificationActionsDeserializer {
/* This exists as trick to leverage readFields for Json deserialization.
@ -167,12 +177,13 @@ internal class NotificationActionsDeserializer {
private val CivilopediaAction: CivilopediaAction? = null
private val PromoteUnitAction: PromoteUnitAction? = null
private val OverviewAction: OverviewAction? = null
private val PolicyAction: PolicyAction? = null
fun read(json: Json, jsonData: JsonValue): List<NotificationAction> {
json.readFields(this, jsonData)
return listOfNotNull(
LocationAction, TechAction, CityAction, DiplomacyAction, MayaLongCountAction,
MapUnitAction, CivilopediaAction, PromoteUnitAction, OverviewAction
MapUnitAction, CivilopediaAction, PromoteUnitAction, OverviewAction, PolicyAction
)
}
}

View File

@ -203,6 +203,7 @@ class PolicyManager : IsPartOfGameInfoSerialization {
triggerGlobalAlerts(policy, unique.params[0])
}
//todo Can this be mapped downstream to a PolicyAction:NotificationAction?
val triggerNotificationText = "due to adopting [${policy.name}]"
for (unique in policy.uniqueObjects)
if (!unique.hasTriggerConditional())

View File

@ -10,6 +10,7 @@ import com.unciv.logic.civilization.MayaLongCountAction
import com.unciv.logic.civilization.NotificationCategory
import com.unciv.logic.civilization.NotificationIcon
import com.unciv.logic.civilization.PlayerType
import com.unciv.logic.civilization.PolicyAction
import com.unciv.logic.civilization.PopupAlert
import com.unciv.logic.civilization.TechAction
import com.unciv.logic.map.MapSize
@ -417,6 +418,7 @@ class TechManager : IsPartOfGameInfoSerialization {
if (!civInfo.isSpectator())
civInfo.addNotification(
"[${policyBranch.name}] policy branch unlocked!",
PolicyAction(policyBranch.name),
NotificationCategory.General,
NotificationIcon.Culture
)

View File

@ -49,6 +49,16 @@ enum class UniqueParameterType(
}
},
PositiveNumber("positiveAmount", "3", "This indicates a positive whole number, larger than zero, a '+' sign is optional") {
override fun getErrorSeverity(parameterText: String, ruleset: Ruleset):
UniqueType.UniqueParameterErrorSeverity? {
val amount = parameterText.toIntOrNull()
?: return UniqueType.UniqueParameterErrorSeverity.RulesetInvariant
if (amount <= 0) return UniqueType.UniqueParameterErrorSeverity.RulesetInvariant
return null
}
},
Fraction("fraction", docExample = "0.5", "Indicates a fractional number, which can be negative") {
override fun getErrorSeverity(parameterText: String, ruleset: Ruleset): UniqueType.UniqueParameterErrorSeverity? {
return if (parameterText.toFloatOrNull () == null) UniqueType.UniqueParameterErrorSeverity.RulesetInvariant

View File

@ -9,8 +9,11 @@ import com.unciv.logic.civilization.Civilization
import com.unciv.logic.civilization.LocationAction
import com.unciv.logic.civilization.MapUnitAction
import com.unciv.logic.civilization.MayaLongCountAction
import com.unciv.logic.civilization.NotificationAction
import com.unciv.logic.civilization.NotificationCategory
import com.unciv.logic.civilization.NotificationIcon
import com.unciv.logic.civilization.PolicyAction
import com.unciv.logic.civilization.TechAction
import com.unciv.logic.civilization.managers.ReligionState
import com.unciv.logic.map.mapunit.MapUnit
import com.unciv.logic.map.tile.Tile
@ -20,8 +23,8 @@ import com.unciv.models.stats.Stat
import com.unciv.models.stats.Stats
import com.unciv.models.translations.fillPlaceholders
import com.unciv.models.translations.hasPlaceholderParameters
import com.unciv.ui.components.extensions.addToMapOfSets
import com.unciv.ui.components.MayaCalendar
import com.unciv.ui.components.extensions.addToMapOfSets
import com.unciv.ui.screens.worldscreen.unit.actions.UnitActionsUpgrade
import kotlin.math.roundToInt
import kotlin.random.Random
@ -189,7 +192,7 @@ object UniqueTriggerActivation {
"You gain the [$policyName] Policy")
?: return true
civInfo.addNotification(notificationText, NotificationCategory.General, NotificationIcon.Culture)
civInfo.addNotification(notificationText, PolicyAction(policyName), NotificationCategory.General, NotificationIcon.Culture)
return true
}
UniqueType.OneTimeEnterGoldenAge, UniqueType.OneTimeEnterGoldenAgeTurns -> {
@ -311,7 +314,11 @@ object UniqueTriggerActivation {
notification.fillPlaceholders(*(techsToResearch.map { it.name }
.toTypedArray()))
else notification
civInfo.addNotification(notificationText, LocationAction(tile?.position),
// Notification click for first tech only, supporting multiple adds little value.
// Relies on RulesetValidator catching <= 0!
val notificationActions: Sequence<NotificationAction> =
LocationAction(tile?.position) + TechAction(techsToResearch.first().name)
civInfo.addNotification(notificationText, notificationActions,
NotificationCategory.General, NotificationIcon.Science)
}
@ -326,7 +333,7 @@ object UniqueTriggerActivation {
"You have discovered the secrets of [$techName]")
?: return true
civInfo.addNotification(notificationText, NotificationCategory.General, NotificationIcon.Science)
civInfo.addNotification(notificationText, TechAction(techName), NotificationCategory.General, NotificationIcon.Science)
return true
}

View File

@ -696,26 +696,26 @@ enum class UniqueType(
OneTimeFreeUnit("Free [unit] appears", UniqueTarget.Triggerable), // used in Policies, Buildings
OneTimeAmountFreeUnits("[amount] free [unit] units appear", UniqueTarget.Triggerable), // used in Buildings
OneTimeAmountFreeUnits("[positiveAmount] free [unit] units appear", UniqueTarget.Triggerable), // used in Buildings
OneTimeFreeUnitRuins("Free [unit] found in the ruins", UniqueTarget.Ruins), // Differs from "Free [] appears" in that it spawns near the ruins instead of in a city
OneTimeFreePolicy("Free Social Policy", UniqueTarget.Triggerable), // used in Buildings
OneTimeAmountFreePolicies("[amount] Free Social Policies", UniqueTarget.Triggerable), // Not used in Vanilla
OneTimeAmountFreePolicies("[positiveAmount] Free Social Policies", UniqueTarget.Triggerable), // Not used in Vanilla
OneTimeEnterGoldenAge("Empire enters golden age", UniqueTarget.Triggerable), // used in Policies, Buildings
OneTimeEnterGoldenAgeTurns("Empire enters a [amount]-turn Golden Age", UniqueTarget.Triggerable),
OneTimeEnterGoldenAgeTurns("Empire enters a [positiveAmount]-turn Golden Age", UniqueTarget.Triggerable),
OneTimeFreeGreatPerson("Free Great Person", UniqueTarget.Triggerable), // used in Policies, Buildings
OneTimeGainPopulation("[amount] population [cityFilter]", UniqueTarget.Triggerable), // used in CN tower
OneTimeGainPopulationRandomCity("[amount] population in a random city", UniqueTarget.Triggerable),
OneTimeDiscoverTech("Discover [tech]", UniqueTarget.Triggerable),
OneTimeAdoptPolicy("Adopt [policy]", UniqueTarget.Triggerable),
OneTimeFreeTech("Free Technology", UniqueTarget.Triggerable), // used in Buildings
OneTimeAmountFreeTechs("[amount] Free Technologies", UniqueTarget.Triggerable), // used in Policy
OneTimeFreeTechRuins("[amount] free random researchable Tech(s) from the [era]", UniqueTarget.Triggerable),
OneTimeAmountFreeTechs("[positiveAmount] Free Technologies", UniqueTarget.Triggerable), // used in Policy
OneTimeFreeTechRuins("[positiveAmount] free random researchable Tech(s) from the [era]", UniqueTarget.Triggerable),
OneTimeRevealEntireMap("Reveals the entire map", UniqueTarget.Triggerable), // used in tech
OneTimeFreeBelief("Gain a free [beliefType] belief", UniqueTarget.Triggerable),
OneTimeTriggerVoting("Triggers voting for the Diplomatic Victory", UniqueTarget.Triggerable), // used in Building
OneTimeConsumeResources("Instantly consumes [amount] [stockpiledResource]", UniqueTarget.Triggerable),
OneTimeProvideResources("Instantly provides [amount] [stockpiledResource]", UniqueTarget.Triggerable),
OneTimeConsumeResources("Instantly consumes [positiveAmount] [stockpiledResource]", UniqueTarget.Triggerable),
OneTimeProvideResources("Instantly provides [positiveAmount] [stockpiledResource]", UniqueTarget.Triggerable),
OneTimeGainStat("Gain [amount] [stat]", UniqueTarget.Triggerable),
OneTimeGainStatSpeed("Gain [amount] [stat] (modified by game speed)", UniqueTarget.Triggerable),
@ -724,8 +724,8 @@ enum class UniqueType(
OneTimeGainProphet("Gain enough Faith for [amount]% of a Great Prophet", UniqueTarget.Triggerable),
// todo: The "up to [All]" used in vanilla json is not nice to read. Split?
// Or just reword it without the 'up to', so it reads "Reveal [amount/'all'] [tileFilter] tiles within [amount] tiles"
OneTimeRevealSpecificMapTiles("Reveal up to [amount/'all'] [tileFilter] within a [amount] tile radius", UniqueTarget.Triggerable),
OneTimeRevealCrudeMap("From a randomly chosen tile [amount] tiles away from the ruins, reveal tiles up to [amount] tiles away with [amount]% chance", UniqueTarget.Ruins),
OneTimeRevealSpecificMapTiles("Reveal up to [positiveAmount/'all'] [tileFilter] within a [amount] tile radius", UniqueTarget.Triggerable),
OneTimeRevealCrudeMap("From a randomly chosen tile [positiveAmount] tiles away from the ruins, reveal tiles up to [positiveAmount] tiles away with [positiveAmount]% chance", UniqueTarget.Ruins),
OneTimeGlobalAlert("Triggers the following global alert: [comment]", UniqueTarget.Triggerable), // used in Policy
OneTimeGlobalSpiesWhenEnteringEra("Every major Civilization gains a spy once a civilization enters this era", UniqueTarget.Era),
@ -738,8 +738,8 @@ enum class UniqueType(
FreePromotion("This Promotion is free", UniqueTarget.Promotion),
UnitsGainPromotion("[mapUnitFilter] units gain the [promotion] promotion", UniqueTarget.Triggerable), // Not used in Vanilla
FreeStatBuildings("Provides the cheapest [stat] building in your first [amount] cities for free", UniqueTarget.Triggerable), // used in Policy
FreeSpecificBuildings("Provides a [buildingName] in your first [amount] cities for free", UniqueTarget.Triggerable), // used in Policy
FreeStatBuildings("Provides the cheapest [stat] building in your first [positiveAmount] cities for free", UniqueTarget.Triggerable), // used in Policy
FreeSpecificBuildings("Provides a [buildingName] in your first [positiveAmount] cities for free", UniqueTarget.Triggerable), // used in Policy
//endregion

View File

@ -53,7 +53,7 @@ private object PolicyColors {
val branchAdopted = colorFromRGB(100, 90, 10).darken(0.5f)
}
fun Policy.isPickable(viewingCiv: Civilization, canChangeState: Boolean) : Boolean {
private fun Policy.isPickable(viewingCiv: Civilization, canChangeState: Boolean) : Boolean {
if (!viewingCiv.isCurrentPlayer()
|| !canChangeState
|| viewingCiv.isDefeated()
@ -66,7 +66,7 @@ fun Policy.isPickable(viewingCiv: Civilization, canChangeState: Boolean) : Boole
return true
}
class PolicyButton(viewingCiv: Civilization, canChangeState: Boolean, val policy: Policy, size: Float = 30f) : BorderedTable(
private class PolicyButton(viewingCiv: Civilization, canChangeState: Boolean, val policy: Policy, size: Float = 30f) : BorderedTable(
path = "PolicyScreen/PolicyButton",
defaultBgBorder = BaseScreen.skinStrings.roundedEdgeRectangleSmallShape,
defaultBgShape = BaseScreen.skinStrings.roundedEdgeRectangleSmallShape,
@ -131,7 +131,11 @@ class PolicyButton(viewingCiv: Civilization, canChangeState: Boolean, val policy
}
class PolicyPickerScreen(val viewingCiv: Civilization, val canChangeState: Boolean)
class PolicyPickerScreen(
val viewingCiv: Civilization,
val canChangeState: Boolean,
select: String? = null
)
: PickerScreen(), RecreateOnResize {
object Sizes {
@ -142,10 +146,12 @@ class PolicyPickerScreen(val viewingCiv: Civilization, val canChangeState: Boole
const val iconSize = 50f
}
private var policyNameToButton = HashMap<String, PolicyButton>()
private val policyNameToButton = HashMap<String, PolicyButton>()
private var selectedPolicyButton: PolicyButton? = null
init {
val branchToGroup = HashMap<String, BranchGroup>()
val policies = viewingCiv.policies
displayTutorial(TutorialTrigger.CultureAndPolicies)
@ -204,8 +210,9 @@ class PolicyPickerScreen(val viewingCiv: Civilization, val canChangeState: Boole
wrapper.add().expand()
} else {
val branch = branches.values.elementAt(r)
val branchGroup = getBranchGroup(branch)
val branchGroup = BranchGroup(branch)
wrapper.add(branchGroup).growY().growX()
branchToGroup[branch.name] = branchGroup
}
}
topTable.add(wrapper).pad(5f,10f)
@ -222,6 +229,11 @@ class PolicyPickerScreen(val viewingCiv: Civilization, val canChangeState: Boole
scrollPane.scrollX = hScroll
}
scrollPane.updateVisualScroll()
when(select) {
in branches -> branchToGroup[select]?.toggle()
in policyNameToButton -> policyNameToButton[select]!!.also { pickPolicy(it) }
}
}
private fun pickPolicy(button: PolicyButton) {
@ -252,133 +264,136 @@ class PolicyPickerScreen(val viewingCiv: Civilization, val canChangeState: Boole
* @param branch the policy branch to display
* @return a [Table], with outer padding _zero_
*/
private fun getBranchGroup(branch: PolicyBranch): Group {
private inner class BranchGroup(branch: PolicyBranch) : BorderedTable(path = "PolicyScreen/PolicyBranchBackground") {
private val header = getBranchHeader(branch)
private val group = Group()
private val groupCell: Cell<Group>
private val topBtn = getTopButton(branch)
private val topBtnCell: Cell<Table>
private val labelTable = Table()
// Calculate preferred size
val maxCol = max(5, branch.policies.maxOf { it.column })
val maxRow = branch.policies.maxOf { it.row }
init {
// Calculate preferred size
val maxCol = max(5, branch.policies.maxOf { it.column })
val maxRow = branch.policies.maxOf { it.row }
val prefWidth = Sizes.paddingHorizontal *2 + Sizes.iconSize *maxCol - (Sizes.iconSize - Sizes.paddingBetweenHor)*(maxCol-1)/2
val prefHeight = Sizes.paddingVertical *2 + Sizes.iconSize *maxRow + Sizes.paddingBetweenVer *(maxRow - 1)
val prefWidth = Sizes.paddingHorizontal * 2 + Sizes.iconSize * maxCol - (Sizes.iconSize - Sizes.paddingBetweenHor) * (maxCol - 1) / 2
val prefHeight = Sizes.paddingVertical * 2 + Sizes.iconSize * maxRow + Sizes.paddingBetweenVer * (maxRow - 1)
// Main table
val colorBg = if (viewingCiv.policies.isAdopted(branch.name)) PolicyColors.branchAdopted else PolicyColors.branchNotAdopted
val branchGroup = BorderedTable(path="PolicyScreen/PolicyBranchBackground")
.apply { bgColor = colorBg }
// Main table
bgColor = if (viewingCiv.policies.isAdopted(branch.name)) PolicyColors.branchAdopted else PolicyColors.branchNotAdopted
// Header
val header = getBranchHeader(branch)
branchGroup.add(header).growX().row()
// Header
add(header).growX().row()
// Description
val onAdoption = branch.getDescription()
val onCompletion = branch.policies.last().getDescription()
var text = ""
if (viewingCiv.gameInfo.ruleset.eras[branch.era]!!.eraNumber > viewingCiv.getEraNumber())
text += "{Unlocked at} {${branch.era}}" + "\n\n"
text += "{On adoption}:" + "\n\n" + onAdoption + "\n\n" +
// Description
val onAdoption = branch.getDescription()
val onCompletion = branch.policies.last().getDescription()
var text = ""
if (viewingCiv.gameInfo.ruleset.eras[branch.era]!!.eraNumber > viewingCiv.getEraNumber())
text += "{Unlocked at} {${branch.era}}" + "\n\n"
text += "{On adoption}:" + "\n\n" + onAdoption + "\n\n" +
"{On completion}:" + "\n\n" + onCompletion
val labelTable = Table()
val label = text.toLabel(fontSize = 13)
label.setFillParent(false)
label.setAlignment(Align.topLeft)
label.wrap = true
labelTable.add(label).pad(7f, 20f, 10f, 20f).grow().row()
val label = text.toLabel(fontSize = 13)
label.setFillParent(false)
label.setAlignment(Align.topLeft)
label.wrap = true
labelTable.add(label).pad(7f,20f, 10f, 20f).grow().row()
val conditionals = LinkedHashMap<UniqueType, ArrayList<String>>()
val conditionals = LinkedHashMap<UniqueType, ArrayList<String>>()
branch.uniqueMap[UniqueType.OnlyAvailableWhen.text]?.forEach {
unique ->
unique.conditionals.forEach {
if (it.type != null) {
if (conditionals[it.type] == null)
conditionals[it.type] = ArrayList()
conditionals[it.type]!!.add(it.params.toString().tr())
branch.uniqueMap[UniqueType.OnlyAvailableWhen.text]?.forEach { unique ->
unique.conditionals.forEach {
if (it.type != null) {
if (conditionals[it.type] == null)
conditionals[it.type] = ArrayList()
conditionals[it.type]!!.add(it.params.toString().tr())
}
}
}
}
if (conditionals.isNotEmpty()) {
var warning = UniqueType.OnlyAvailableWhen.text.tr() + ":\n"
for ((k, v) in conditionals) {
warning += "" + k.text.fillPlaceholders(v.joinToString()).tr() + "\n"
}
val warningLabel = ColorMarkupLabel(warning, Color.RED, fontSize = 13)
warningLabel.setAlignment(Align.topLeft)
warningLabel.wrap = true
labelTable.add(warningLabel).pad(0f, 20f, 17f, 20f).grow()
}
// Top button
val topBtn = getTopButton(branch)
val topBtnCell = branchGroup.add(topBtn).growX().pad(10f, 10f, 0f, 10f)
topBtnCell.row()
// Main grid
val group = Group()
group.width = prefWidth
group.height = prefHeight
// Calculate grid points coordinates
val startX = Sizes.paddingHorizontal
val endX = prefWidth - Sizes.paddingHorizontal - Sizes.iconSize
val deltaX = (endX - startX)/(maxCol - 1)
val startY = prefHeight - Sizes.paddingVertical - Sizes.iconSize
val endY = Sizes.paddingVertical
val deltaY = (startY - endY)/(maxRow - 1)
val coords = Array(maxRow+1) { Array(maxCol+1) {Pair(0f,0f)}}
var row = 1
var col: Int
var posX: Float
var posY = startY
while (row <= maxRow) {
col = 1
posX = startX
while (col <= maxCol) {
coords[row][col] = Pair(posX, posY)
col += 1
posX += deltaX
if (conditionals.isNotEmpty()) {
var warning = UniqueType.OnlyAvailableWhen.text.tr() + ":\n"
for ((k, v) in conditionals) {
warning += "" + k.text.fillPlaceholders(v.joinToString()).tr() + "\n"
}
val warningLabel = ColorMarkupLabel(warning, Color.RED, fontSize = 13)
warningLabel.setAlignment(Align.topLeft)
warningLabel.wrap = true
labelTable.add(warningLabel).pad(0f, 20f, 17f, 20f).grow()
}
row += 1
posY -= deltaY
// Top button
topBtnCell = add(topBtn).growX().pad(10f, 10f, 0f, 10f)
row()
// Main grid
group.width = prefWidth
group.height = prefHeight
// Calculate grid points coordinates
val startX = Sizes.paddingHorizontal
val endX = prefWidth - Sizes.paddingHorizontal - Sizes.iconSize
val deltaX = (endX - startX) / (maxCol - 1)
val startY = prefHeight - Sizes.paddingVertical - Sizes.iconSize
val endY = Sizes.paddingVertical
val deltaY = (startY - endY) / (maxRow - 1)
val coords = Array(maxRow + 1) { Array(maxCol + 1) { Pair(0f, 0f) } }
var row = 1
var col: Int
var posX: Float
var posY = startY
while (row <= maxRow) {
col = 1
posX = startX
while (col <= maxCol) {
coords[row][col] = Pair(posX, posY)
col += 1
posX += deltaX
}
row += 1
posY -= deltaY
}
// Create policy buttons at calculated coordinates
for (policy in branch.policies) {
if (policy.policyBranchType == PolicyBranchType.BranchComplete)
continue
val button = getPolicyButton(policy, size = Sizes.iconSize)
group.addActor(button)
val policyX = coords[policy.row][policy.column].first
val policyY = coords[policy.row][policy.column].second
button.x = policyX
button.y = policyY
policyNameToButton[policy.name] = button
}
// Draw connecting lines
drawLines(branch)
groupCell = add(group).minWidth(prefWidth).expandY().top()
row()
// Setup header clicks
header.onClick(::toggle)
// Ensure dimensions are calculated
pack()
}
// Create policy buttons at calculated coordinates
for (policy in branch.policies) {
if (policy.policyBranchType == PolicyBranchType.BranchComplete)
continue
val button = getPolicyButton(policy, size = Sizes.iconSize)
group.addActor(button)
val policyX = coords[policy.row][policy.column].first
val policyY = coords[policy.row][policy.column].second
button.x = policyX
button.y = policyY
policyNameToButton[policy.name] = button
}
// Draw connecting lines
drawLines(branch)
val groupCell = branchGroup.add(group).minWidth(prefWidth).expandY().top()
branchGroup.row()
// Setup header clicks
header.onClick {
fun toggle() {
val newActor = if (groupCell.actor == group) labelTable else group
val rotate = if (groupCell.actor == group) -90f else 90f
@ -390,18 +405,16 @@ class PolicyPickerScreen(val viewingCiv: Civilization, val canChangeState: Boole
groupCell.clearActor()
groupCell.setActor(newActor)
((header.cells[0].actor as Table).cells[0] as Cell<Actor>).clearActor()
((header.cells[0].actor as Table).cells[0] as Cell<Actor>).setActor(ImageGetter.
getImage("OtherIcons/BackArrow").apply { rotation = rotate}.toGroup(10f))
//todo resolve kludge by making BranchHeader a proper class
((header.cells[0].actor as Table).cells[0] as Cell<Actor>)
.clearActor()
.setActor(
ImageGetter.getImage("OtherIcons/BackArrow").apply { rotation = rotate }.toGroup(10f)
)
}
// Ensure dimensions are calculated
branchGroup.pack()
return branchGroup
}
private fun drawLines(branch: PolicyBranch) {
for (policy in branch.policies) {
@ -659,7 +672,7 @@ class PolicyPickerScreen(val viewingCiv: Civilization, val canChangeState: Boole
}
override fun recreate(): BaseScreen {
val newScreen = PolicyPickerScreen(viewingCiv, canChangeState)
val newScreen = PolicyPickerScreen(viewingCiv, canChangeState, selectedPolicyButton?.policy?.name)
newScreen.scrollPane.scrollPercentX = scrollPane.scrollPercentX
newScreen.scrollPane.scrollPercentY = scrollPane.scrollPercentY
newScreen.scrollPane.updateVisualScroll()

View File

@ -28,7 +28,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Applicable to: Triggerable
??? example "[amount] free [unit] units appear"
??? example "[positiveAmount] free [unit] units appear"
Example: "[3] free [Musketman] units appear"
Applicable to: Triggerable
@ -36,7 +36,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
??? example "Free Social Policy"
Applicable to: Triggerable
??? example "[amount] Free Social Policies"
??? example "[positiveAmount] Free Social Policies"
Example: "[3] Free Social Policies"
Applicable to: Triggerable
@ -44,7 +44,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
??? example "Empire enters golden age"
Applicable to: Triggerable
??? example "Empire enters a [amount]-turn Golden Age"
??? example "Empire enters a [positiveAmount]-turn Golden Age"
Example: "Empire enters a [3]-turn Golden Age"
Applicable to: Triggerable
@ -75,12 +75,12 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
??? example "Free Technology"
Applicable to: Triggerable
??? example "[amount] Free Technologies"
??? example "[positiveAmount] Free Technologies"
Example: "[3] Free Technologies"
Applicable to: Triggerable
??? example "[amount] free random researchable Tech(s) from the [era]"
??? example "[positiveAmount] free random researchable Tech(s) from the [era]"
Example: "[3] free random researchable Tech(s) from the [Ancient era]"
Applicable to: Triggerable
@ -96,12 +96,12 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
??? example "Triggers voting for the Diplomatic Victory"
Applicable to: Triggerable
??? example "Instantly consumes [amount] [stockpiledResource]"
??? example "Instantly consumes [positiveAmount] [stockpiledResource]"
Example: "Instantly consumes [3] [StockpiledResource]"
Applicable to: Triggerable
??? example "Instantly provides [amount] [stockpiledResource]"
??? example "Instantly provides [positiveAmount] [stockpiledResource]"
Example: "Instantly provides [3] [StockpiledResource]"
Applicable to: Triggerable
@ -129,7 +129,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Applicable to: Triggerable
??? example "Reveal up to [amount/'all'] [tileFilter] within a [amount] tile radius"
??? example "Reveal up to [positiveAmount/'all'] [tileFilter] within a [amount] tile radius"
Example: "Reveal up to [3] [Farm] within a [3] tile radius"
Applicable to: Triggerable
@ -144,12 +144,12 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Applicable to: Triggerable
??? example "Provides the cheapest [stat] building in your first [amount] cities for free"
??? example "Provides the cheapest [stat] building in your first [positiveAmount] cities for free"
Example: "Provides the cheapest [Culture] building in your first [3] cities for free"
Applicable to: Triggerable
??? example "Provides a [buildingName] in your first [amount] cities for free"
??? example "Provides a [buildingName] in your first [positiveAmount] cities for free"
Example: "Provides a [Library] in your first [3] cities for free"
Applicable to: Triggerable
@ -1750,7 +1750,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Applicable to: Ruins
??? example "From a randomly chosen tile [amount] tiles away from the ruins, reveal tiles up to [amount] tiles away with [amount]% chance"
??? example "From a randomly chosen tile [positiveAmount] tiles away from the ruins, reveal tiles up to [positiveAmount] tiles away with [positiveAmount]% chance"
Example: "From a randomly chosen tile [3] tiles away from the ruins, reveal tiles up to [3] tiles away with [3]% chance"
Applicable to: Ruins
@ -2207,6 +2207,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
*[improvementName]: The name of any improvement.
*[modFilter]: A Mod name, case-sensitive _or_ a simple wildcard filter beginning and ending in an Asterisk, case-insensitive.
*[policy]: The name of any policy.
*[positiveAmount]: This indicates a positive whole number, larger than zero, a '+' sign is optional.
*[promotion]: The name of any promotion.
*[relativeAmount]: This indicates a number, usually with a + or - sign, such as `+25` (this kind of parameter is often followed by '%' which is nevertheless not part of the value).
*[resource]: The name of any resource.
@ -2216,4 +2217,4 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
*[stockpiledResource]: The name of any stockpiled.
*[tech]: The name of any tech.
*[tileFilter]: Anything that can be used either in an improvementFilter or in a terrainFilter can be used here, plus 'unimproved'
*[victoryType]: The name of any victory type: 'Neutral', 'Cultural', 'Diplomatic', 'Domination', 'Scientific', 'Time'
*[victoryType]: The name of any victory type: 'Neutral', 'Cultural', 'Diplomatic', 'Domination', 'Scientific', 'Time'