mirror of
https://github.com/yairm210/Unciv.git
synced 2025-01-07 14:02:48 +07:00
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:
parent
1f47fff05d
commit
5061b29197
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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'
|
||||
|
Loading…
Reference in New Issue
Block a user