mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-09 07:18:57 +07:00
Fix exploit allowing promotion with 0 movement (#9055)
* Close exploit allowing promotion with 0 movement * PromotionPickerScreen linting
This commit is contained in:
@ -62,7 +62,7 @@ class PromotionNode(val promotion: Promotion) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class CustomComparator(
|
class CustomComparator(
|
||||||
val baseNode: PromotionNode
|
private val baseNode: PromotionNode
|
||||||
) : Comparator<PromotionNode> {
|
) : Comparator<PromotionNode> {
|
||||||
override fun compare(a: PromotionNode, b: PromotionNode): Int {
|
override fun compare(a: PromotionNode, b: PromotionNode): Int {
|
||||||
val baseName = baseNode.baseName
|
val baseName = baseNode.baseName
|
||||||
@ -78,15 +78,15 @@ class PromotionNode(val promotion: Promotion) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class PromotionButton(
|
private class PromotionButton(
|
||||||
val node: PromotionNode,
|
val node: PromotionNode,
|
||||||
val isPickable: Boolean = true,
|
val isPickable: Boolean = true,
|
||||||
val isPromoted: Boolean = false
|
val isPromoted: Boolean = false
|
||||||
|
|
||||||
) : BorderedTable(
|
) : BorderedTable(
|
||||||
path="PromotionScreen/PromotionButton",
|
path="PromotionScreen/PromotionButton",
|
||||||
defaultBgShape = BaseScreen.skinStrings.roundedEdgeRectangleMidShape,
|
defaultBgShape = BaseScreen.skinStrings.roundedEdgeRectangleMidShape,
|
||||||
defaultBgBorder = BaseScreen.skinStrings.roundedEdgeRectangleMidBorderShape) {
|
defaultBgBorder = BaseScreen.skinStrings.roundedEdgeRectangleMidBorderShape
|
||||||
|
) {
|
||||||
|
|
||||||
var isSelected = false
|
var isSelected = false
|
||||||
val label = node.promotion.name.toLabel().apply {
|
val label = node.promotion.name.toLabel().apply {
|
||||||
@ -144,28 +144,25 @@ class PromotionPickerScreen(val unit: MapUnit) : PickerScreen(), RecreateOnResiz
|
|||||||
private var selectedPromotion: PromotionButton? = null
|
private var selectedPromotion: PromotionButton? = null
|
||||||
private var lines = ArrayList<Image>()
|
private var lines = ArrayList<Image>()
|
||||||
|
|
||||||
private fun acceptPromotion(node: PromotionNode?) {
|
// [acceptPromotion] will [recreate] the screen, so these are constant for this picker's lifetime
|
||||||
// if user managed to click disabled button, still do nothing
|
private val canChangeState = GUI.isAllowedChangeState()
|
||||||
if (node == null) return
|
private val canBePromoted = unit.promotions.canBePromoted()
|
||||||
|
private val canPromoteNow = canChangeState && canBePromoted &&
|
||||||
unit.promotions.addPromotion(node.promotion.name)
|
unit.currentMovement > 0 && unit.attacksThisTurn == 0
|
||||||
game.replaceCurrentScreen(recreate())
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
setDefaultCloseAction()
|
setDefaultCloseAction()
|
||||||
|
|
||||||
|
if (canPromoteNow) {
|
||||||
rightSideButton.setText("Pick promotion".tr())
|
rightSideButton.setText("Pick promotion".tr())
|
||||||
rightSideButton.onClick(UncivSound.Promote) {
|
rightSideButton.onClick(UncivSound.Promote) {
|
||||||
if (selectedPromotion?.isPickable == true)
|
if (selectedPromotion?.isPickable == true)
|
||||||
acceptPromotion(selectedPromotion?.node)
|
acceptPromotion(selectedPromotion?.node)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
rightSideButton.isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
val canBePromoted = unit.promotions.canBePromoted()
|
|
||||||
val canChangeState = GUI.isAllowedChangeState()
|
|
||||||
val canPromoteNow = canBePromoted && canChangeState
|
|
||||||
&& unit.currentMovement > 0 && unit.attacksThisTurn == 0
|
|
||||||
rightSideButton.isEnabled = canPromoteNow
|
|
||||||
descriptionLabel.setText(updateDescriptionLabel())
|
descriptionLabel.setText(updateDescriptionLabel())
|
||||||
|
|
||||||
val availablePromotionsGroup = Table()
|
val availablePromotionsGroup = Table()
|
||||||
@ -197,14 +194,19 @@ class PromotionPickerScreen(val unit: MapUnit) : PickerScreen(), RecreateOnResiz
|
|||||||
displayTutorial(TutorialTrigger.Experience)
|
displayTutorial(TutorialTrigger.Experience)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun acceptPromotion(node: PromotionNode?) {
|
||||||
|
// if user managed to click disabled button, still do nothing
|
||||||
|
if (node == null) return
|
||||||
|
|
||||||
|
unit.promotions.addPromotion(node.promotion.name)
|
||||||
|
game.replaceCurrentScreen(recreate())
|
||||||
|
}
|
||||||
|
|
||||||
private fun fillTable(promotions: Collection<Promotion>) {
|
private fun fillTable(promotions: Collection<Promotion>) {
|
||||||
val map = LinkedHashMap<String, PromotionNode>()
|
val map = LinkedHashMap<String, PromotionNode>()
|
||||||
|
|
||||||
val availablePromotions = unit.promotions.getAvailablePromotions()
|
val availablePromotions = unit.promotions.getAvailablePromotions()
|
||||||
|
|
||||||
val canBePromoted = unit.promotions.canBePromoted()
|
|
||||||
val canChangeState = GUI.isAllowedChangeState()
|
|
||||||
|
|
||||||
// Create nodes
|
// Create nodes
|
||||||
// Pass 1 - create nodes for all promotions
|
// Pass 1 - create nodes for all promotions
|
||||||
for (promotion in promotions)
|
for (promotion in promotions)
|
||||||
@ -248,10 +250,8 @@ class PromotionPickerScreen(val unit: MapUnit) : PickerScreen(), RecreateOnResiz
|
|||||||
// Choose best predecessor - the one with less depth
|
// Choose best predecessor - the one with less depth
|
||||||
var best: PromotionNode? = null
|
var best: PromotionNode? = null
|
||||||
for (predecessor in node.predecessors) {
|
for (predecessor in node.predecessors) {
|
||||||
if (best == null)
|
if (best == null || predecessor.maxDepth < best.maxDepth)
|
||||||
best = predecessor
|
best = predecessor
|
||||||
else
|
|
||||||
best = if (predecessor.maxDepth < best.maxDepth) predecessor else best
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove everything else, leave only best
|
// Remove everything else, leave only best
|
||||||
@ -300,7 +300,7 @@ class PromotionPickerScreen(val unit: MapUnit) : PickerScreen(), RecreateOnResiz
|
|||||||
val cell = cellMatrix[row][col]
|
val cell = cellMatrix[row][col]
|
||||||
val isPromotionAvailable = node.promotion in availablePromotions
|
val isPromotionAvailable = node.promotion in availablePromotions
|
||||||
val hasPromotion = unit.promotions.promotions.contains(name)
|
val hasPromotion = unit.promotions.promotions.contains(name)
|
||||||
val isPickable = canBePromoted && isPromotionAvailable && !hasPromotion && canChangeState
|
val isPickable = canPromoteNow && isPromotionAvailable && !hasPromotion
|
||||||
val button = getButton(promotions, node, isPickable, hasPromotion)
|
val button = getButton(promotions, node, isPickable, hasPromotion)
|
||||||
promotionToButton[name] = button
|
promotionToButton[name] = button
|
||||||
cell.setActor(button)
|
cell.setActor(button)
|
||||||
|
Reference in New Issue
Block a user