summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjoffrey-bion <joffrey.bion@gmail.com>2020-11-27 01:00:04 +0100
committerjoffrey-bion <joffrey.bion@gmail.com>2020-11-28 02:26:32 +0100
commit132fcc3222245f02e5425617a15c90752b26b218 (patch)
tree64d40d9418cc4140ee4f28ef8a4760962f731f29
parentAdd blueprintjs Dialog component (diff)
downloadseven-wonders-132fcc3222245f02e5425617a15c90752b26b218.tar.gz
seven-wonders-132fcc3222245f02e5425617a15c90752b26b218.tar.bz2
seven-wonders-132fcc3222245f02e5425617a15c90752b26b218.zip
Add dialog to choose who to buy resources from
Resolves: https://github.com/joffrey-bion/seven-wonders/issues/50
-rw-r--r--sw-bot/src/main/kotlin/org/luxons/sevenwonders/bot/SevenWondersBot.kt4
-rw-r--r--sw-ui/src/main/kotlin/com/palantir/blueprintjs/blueprintjsHelpers.kt3
-rw-r--r--sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/GameScene.kt43
-rw-r--r--sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/GameStyles.kt12
-rw-r--r--sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/Hand.kt42
-rw-r--r--sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/ProductionBar.kt35
-rw-r--r--sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/Tokens.kt50
-rw-r--r--sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/TransactionsSelector.kt193
-rw-r--r--sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Actions.kt4
-rw-r--r--sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Reducers.kt12
10 files changed, 305 insertions, 93 deletions
diff --git a/sw-bot/src/main/kotlin/org/luxons/sevenwonders/bot/SevenWondersBot.kt b/sw-bot/src/main/kotlin/org/luxons/sevenwonders/bot/SevenWondersBot.kt
index 8ceae2c2..e3d54314 100644
--- a/sw-bot/src/main/kotlin/org/luxons/sevenwonders/bot/SevenWondersBot.kt
+++ b/sw-bot/src/main/kotlin/org/luxons/sevenwonders/bot/SevenWondersBot.kt
@@ -73,7 +73,9 @@ private fun createPlayCardMove(turnInfo: PlayerTurnInfo): PlayerMove {
val transactions = wonderBuildability.cheapestTransactions.random()
return PlayerMove(MoveType.UPGRADE_WONDER, hand.random().name, transactions)
}
- val playableCard = hand.filter { it.playability.isPlayable }.randomOrNull()
+ val playableCard = hand
+ .filter { it.playability.isPlayable }
+ .randomOrNull()
return if (playableCard != null) {
PlayerMove(MoveType.PLAY, playableCard.name, playableCard.playability.cheapestTransactions.random())
} else {
diff --git a/sw-ui/src/main/kotlin/com/palantir/blueprintjs/blueprintjsHelpers.kt b/sw-ui/src/main/kotlin/com/palantir/blueprintjs/blueprintjsHelpers.kt
index b74e984d..0bd126fd 100644
--- a/sw-ui/src/main/kotlin/com/palantir/blueprintjs/blueprintjsHelpers.kt
+++ b/sw-ui/src/main/kotlin/com/palantir/blueprintjs/blueprintjsHelpers.kt
@@ -1,13 +1,12 @@
package com.palantir.blueprintjs
-import kotlinext.js.js
import org.w3c.dom.events.Event
import org.w3c.dom.events.MouseEvent
import react.RBuilder
import react.RHandler
import react.ReactElement
import react.buildElement
-import react.dom.*
+import react.dom.h2
typealias IconName = String
diff --git a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/GameScene.kt b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/GameScene.kt
index fbd6d8c5..bab6fe81 100644
--- a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/GameScene.kt
+++ b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/GameScene.kt
@@ -1,38 +1,18 @@
package org.luxons.sevenwonders.ui.components.game
-import com.palantir.blueprintjs.Elevation
-import com.palantir.blueprintjs.Intent
-import com.palantir.blueprintjs.bpButton
-import com.palantir.blueprintjs.bpButtonGroup
-import com.palantir.blueprintjs.bpCallout
-import com.palantir.blueprintjs.bpCard
-import com.palantir.blueprintjs.bpNonIdealState
-import com.palantir.blueprintjs.bpOverlay
+import com.palantir.blueprintjs.*
import kotlinx.css.*
-import kotlinx.css.properties.*
+import kotlinx.css.properties.transform
+import kotlinx.css.properties.translate
import kotlinx.html.DIV
-import org.luxons.sevenwonders.model.Action
-import org.luxons.sevenwonders.model.PlayerMove
-import org.luxons.sevenwonders.model.PlayerTurnInfo
+import org.luxons.sevenwonders.model.*
import org.luxons.sevenwonders.model.api.PlayerDTO
import org.luxons.sevenwonders.model.boards.Board
import org.luxons.sevenwonders.model.boards.RelativeBoardPosition
import org.luxons.sevenwonders.model.cards.HandCard
-import org.luxons.sevenwonders.model.getBoard
-import org.luxons.sevenwonders.model.getOwnBoard
import org.luxons.sevenwonders.ui.components.GlobalStyles
-import org.luxons.sevenwonders.ui.redux.GameState
-import org.luxons.sevenwonders.ui.redux.RequestLeaveGame
-import org.luxons.sevenwonders.ui.redux.RequestPrepareMove
-import org.luxons.sevenwonders.ui.redux.RequestSayReady
-import org.luxons.sevenwonders.ui.redux.RequestUnprepareMove
-import org.luxons.sevenwonders.ui.redux.connectStateAndDispatch
-import react.RBuilder
-import react.RClass
-import react.RComponent
-import react.RProps
-import react.RState
-import react.ReactElement
+import org.luxons.sevenwonders.ui.redux.*
+import react.*
import styled.StyledDOMBuilder
import styled.css
import styled.getClassName
@@ -50,6 +30,8 @@ interface GameSceneDispatchProps : RProps {
var sayReady: () -> Unit
var prepareMove: (move: PlayerMove) -> Unit
var unprepareMove: () -> Unit
+ var startTransactionsSelection: (TransactionSelectorState) -> Unit
+ var cancelTransactionsSelection: () -> Unit
var leaveGame: () -> Unit
}
@@ -92,9 +74,14 @@ private class GameScene(props: GameSceneProps) : RComponent<GameSceneProps, RSta
height = 100.pct
}
}
+ transactionsSelectorDialog(
+ state = props.gameState?.transactionSelector,
+ prepareMove = props.prepareMove,
+ cancelTransactionSelection = props.cancelTransactionsSelection,
+ )
boardSummaries(leftBoard, rightBoard, topBoards)
handRotationIndicator(turnInfo.table.handRotationDirection)
- handCards(turnInfo, props.preparedMove, props.prepareMove)
+ handCards(turnInfo, props.preparedMove, props.prepareMove, props.startTransactionsSelection)
val card = props.preparedCard
val move = props.preparedMove
if (card != null && move != null) {
@@ -235,6 +222,8 @@ private val gameScene: RClass<GameSceneProps> =
mapDispatchToProps = { dispatch, _ ->
prepareMove = { move -> dispatch(RequestPrepareMove(move)) }
unprepareMove = { dispatch(RequestUnprepareMove()) }
+ startTransactionsSelection = { selector -> dispatch(StartTransactionSelection(selector)) }
+ cancelTransactionsSelection = { dispatch(CancelTransactionSelection) }
sayReady = { dispatch(RequestSayReady()) }
leaveGame = { dispatch(RequestLeaveGame()) }
},
diff --git a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/GameStyles.kt b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/GameStyles.kt
index b2e12dab..e69bc671 100644
--- a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/GameStyles.kt
+++ b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/GameStyles.kt
@@ -6,8 +6,10 @@ import styled.StyleSheet
object GameStyles : StyleSheet("GameStyles", isStatic = true) {
+ private val sandColor = Color.paleGoldenrod.withAlpha(0.7)
+
val fullBoardPreviewPopover by css {
- val bgColor = Color.paleGoldenrod.withAlpha(0.7)
+ val bgColor = sandColor
backgroundColor = bgColor
borderRadius = 0.5.rem
padding(all = 0.5.rem)
@@ -35,6 +37,14 @@ object GameStyles : StyleSheet("GameStyles", isStatic = true) {
filter = "brightness(60%) grayscale(50%)"
}
+ val transactionsSelector by css {
+ backgroundColor = sandColor
+
+ children(".bp3-dialog-header") {
+ background = "none" // overrides default white background
+ }
+ }
+
val discardMoveText by css {
display = Display.flex
alignItems = Align.center
diff --git a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/Hand.kt b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/Hand.kt
index c8fb8d61..373ad0f1 100644
--- a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/Hand.kt
+++ b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/Hand.kt
@@ -1,28 +1,16 @@
package org.luxons.sevenwonders.ui.components.game
-import com.palantir.blueprintjs.IButtonGroupProps
-import com.palantir.blueprintjs.IButtonProps
-import com.palantir.blueprintjs.IconName
-import com.palantir.blueprintjs.Intent
-import com.palantir.blueprintjs.bpButton
-import com.palantir.blueprintjs.bpButtonGroup
-import com.palantir.blueprintjs.bpIcon
+import com.palantir.blueprintjs.*
import kotlinx.css.*
import kotlinx.css.properties.*
import kotlinx.html.DIV
-import org.luxons.sevenwonders.model.Action
-import org.luxons.sevenwonders.model.MoveType
-import org.luxons.sevenwonders.model.PlayerMove
-import org.luxons.sevenwonders.model.PlayerTurnInfo
+import org.luxons.sevenwonders.model.*
import org.luxons.sevenwonders.model.cards.CardPlayability
import org.luxons.sevenwonders.model.cards.HandCard
-import org.luxons.sevenwonders.model.getOwnBoard
+import org.luxons.sevenwonders.model.resources.PricedResourceTransactions
import org.luxons.sevenwonders.model.wonders.WonderBuildability
-import react.RBuilder
-import react.RComponent
-import react.RElementBuilder
-import react.RProps
-import react.RState
+import org.luxons.sevenwonders.ui.redux.TransactionSelectorState
+import react.*
import styled.StyledDOMBuilder
import styled.css
import styled.styledDiv
@@ -43,6 +31,7 @@ interface HandProps : RProps {
var turnInfo: PlayerTurnInfo
var preparedMove: PlayerMove?
var prepareMove: (PlayerMove) -> Unit
+ var startTransactionsSelection: (TransactionSelectorState) -> Unit
}
class HandComponent(props: HandProps) : RComponent<HandProps, RState>(props) {
@@ -131,10 +120,7 @@ class HandComponent(props: HandProps) : RComponent<HandProps, RState>(props) {
large = true,
intent = Intent.SUCCESS,
disabled = !card.playability.isPlayable,
- onClick = {
- val transactions = card.playability.cheapestTransactions.first()
- props.prepareMove(PlayerMove(handAction.moveType, card.name, transactions))
- },
+ onClick = { prepareMove(handAction.moveType, card, card.playability.cheapestTransactions) },
) {
bpIcon(handAction.icon)
if (card.playability.isPlayable && !card.playability.isFree) {
@@ -150,10 +136,7 @@ class HandComponent(props: HandProps) : RComponent<HandProps, RState>(props) {
large = true,
intent = Intent.PRIMARY,
disabled = !wonderBuildability.isBuildable,
- onClick = {
- val transactions = wonderBuildability.cheapestTransactions.first()
- props.prepareMove(PlayerMove(MoveType.UPGRADE_WONDER, card.name, transactions))
- },
+ onClick = { prepareMove(MoveType.UPGRADE_WONDER, card, wonderBuildability.cheapestTransactions) },
) {
bpIcon("key-shift")
if (wonderBuildability.isBuildable && !wonderBuildability.isFree) {
@@ -162,6 +145,13 @@ class HandComponent(props: HandProps) : RComponent<HandProps, RState>(props) {
}
}
+ private fun prepareMove(moveType: MoveType, card: HandCard, transactions: Set<PricedResourceTransactions>) {
+ when (transactions.size) {
+ 1 -> props.prepareMove(PlayerMove(moveType, card.name, transactions.first()))
+ else -> props.startTransactionsSelection(TransactionSelectorState(moveType, card, transactions))
+ }
+ }
+
private fun RElementBuilder<IButtonGroupProps>.discardButton(card: HandCard) {
bpButton(
title = "DISCARD (+3 coins)", // TODO remove hardcoded value
@@ -266,12 +256,14 @@ fun RBuilder.handCards(
turnInfo: PlayerTurnInfo,
preparedMove: PlayerMove?,
prepareMove: (PlayerMove) -> Unit,
+ startTransactionsSelection: (TransactionSelectorState) -> Unit,
) {
child(HandComponent::class) {
attrs {
this.turnInfo = turnInfo
this.preparedMove = preparedMove
this.prepareMove = prepareMove
+ this.startTransactionsSelection = startTransactionsSelection
}
}
}
diff --git a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/ProductionBar.kt b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/ProductionBar.kt
index 507883e7..c3cd9911 100644
--- a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/ProductionBar.kt
+++ b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/ProductionBar.kt
@@ -1,35 +1,14 @@
package org.luxons.sevenwonders.ui.components.game
-import kotlinx.css.Align
-import kotlinx.css.BorderStyle
-import kotlinx.css.CSSBuilder
-import kotlinx.css.Color
-import kotlinx.css.Display
-import kotlinx.css.Position
-import kotlinx.css.VerticalAlign
-import kotlinx.css.alignItems
-import kotlinx.css.background
-import kotlinx.css.bottom
-import kotlinx.css.color
-import kotlinx.css.display
-import kotlinx.css.fontSize
-import kotlinx.css.height
-import kotlinx.css.margin
-import kotlinx.css.marginLeft
-import kotlinx.css.position
-import kotlinx.css.properties.*
-import kotlinx.css.px
-import kotlinx.css.rem
-import kotlinx.css.verticalAlign
-import kotlinx.css.vw
-import kotlinx.css.width
-import kotlinx.css.zIndex
+import kotlinx.css.*
+import kotlinx.css.properties.borderTop
+import kotlinx.css.properties.boxShadow
import kotlinx.html.DIV
import org.luxons.sevenwonders.model.boards.Production
import org.luxons.sevenwonders.model.resources.CountedResource
import org.luxons.sevenwonders.model.resources.ResourceType
import react.RBuilder
-import react.dom.*
+import react.dom.key
import styled.StyledDOMBuilder
import styled.css
import styled.styledDiv
@@ -53,7 +32,7 @@ private fun RBuilder.fixedResources(resources: List<CountedResource>) {
display = Display.flex
}
resources.forEach {
- tokenWithCount(tokenName = getResourceTokenName(it.type), count = it.count, imgSize = 3.rem) {
+ resourceWithCount(resourceType = it.type, count = it.count, imgSize = 3.rem) {
attrs { key = it.type.toString() }
css { marginLeft = 1.rem }
}
@@ -84,7 +63,7 @@ private fun RBuilder.resourceChoice(types: Set<ResourceType>, block: StyledDOMBu
}
block()
for ((i, t) in types.withIndex()) {
- tokenImage(tokenName = getResourceTokenName(t), size = 3.rem) {
+ resourceImage(resourceType = t, size = 3.rem) {
attrs { this.key = t.toString() }
}
if (i < types.indices.last) {
@@ -97,8 +76,6 @@ private fun RBuilder.resourceChoice(types: Set<ResourceType>, block: StyledDOMBu
}
}
-private fun getResourceTokenName(resourceType: ResourceType) = "resources/${resourceType.toString().toLowerCase()}"
-
private fun CSSBuilder.productionBarStyle() {
alignItems = Align.center
background = "linear-gradient(#eaeaea, #888 7%)"
diff --git a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/Tokens.kt b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/Tokens.kt
index 74dc232e..846a9f07 100644
--- a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/Tokens.kt
+++ b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/Tokens.kt
@@ -4,13 +4,14 @@ import kotlinx.css.*
import kotlinx.html.DIV
import kotlinx.html.IMG
import kotlinx.html.title
+import org.luxons.sevenwonders.model.resources.ResourceType
import org.luxons.sevenwonders.ui.components.GlobalStyles
import react.RBuilder
-import styled.StyledDOMBuilder
-import styled.css
-import styled.styledDiv
-import styled.styledImg
-import styled.styledSpan
+import styled.*
+
+private fun getResourceTokenName(resourceType: ResourceType) = "resources/${resourceType.toString().toLowerCase()}"
+
+private fun getTokenImagePath(tokenName: String) = "/images/tokens/$tokenName.png"
enum class TokenCountPosition {
LEFT,
@@ -36,6 +37,37 @@ fun RBuilder.goldIndicator(
)
}
+fun RBuilder.resourceWithCount(
+ resourceType: ResourceType,
+ count: Int,
+ title: String = resourceType.toString(),
+ imgSize: LinearDimension? = null,
+ countPosition: TokenCountPosition = TokenCountPosition.RIGHT,
+ brightText: Boolean = false,
+ customCountStyle: CSSBuilder.() -> Unit = {},
+ block: StyledDOMBuilder<DIV>.() -> Unit = {},
+) {
+ tokenWithCount(
+ tokenName = getResourceTokenName(resourceType),
+ count = count,
+ title = title,
+ imgSize = imgSize,
+ countPosition = countPosition,
+ brightText = brightText,
+ customCountStyle = customCountStyle,
+ block = block
+ )
+}
+
+fun RBuilder.resourceImage(
+ resourceType: ResourceType,
+ title: String = resourceType.toString(),
+ size: LinearDimension?,
+ block: StyledDOMBuilder<IMG>.() -> Unit = {},
+) {
+ tokenImage(getResourceTokenName(resourceType), title, size, block)
+}
+
fun RBuilder.tokenWithCount(
tokenName: String,
count: Int,
@@ -72,7 +104,11 @@ fun RBuilder.tokenWithCount(
}
TokenCountPosition.OVER -> {
styledDiv {
- css { position = Position.relative }
+ css {
+ position = Position.relative
+ // if container becomes large, this one stays small so that children stay on top of each other
+ width = LinearDimension.fitContent
+ }
tokenImage(tokenName, title = title, size = imgSize)
styledSpan {
css {
@@ -109,8 +145,6 @@ fun RBuilder.tokenImage(
}
}
-private fun getTokenImagePath(tokenName: String) = "/images/tokens/$tokenName.png"
-
private fun CSSBuilder.tokenCountStyle(
size: LinearDimension,
brightText: Boolean,
diff --git a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/TransactionsSelector.kt b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/TransactionsSelector.kt
new file mode 100644
index 00000000..e8b6cf8c
--- /dev/null
+++ b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/components/game/TransactionsSelector.kt
@@ -0,0 +1,193 @@
+package org.luxons.sevenwonders.ui.components.game
+
+import com.palantir.blueprintjs.*
+import kotlinx.css.*
+import kotlinx.html.DIV
+import kotlinx.html.TD
+import kotlinx.html.classes
+import kotlinx.html.js.onClickFunction
+import org.luxons.sevenwonders.model.PlayerMove
+import org.luxons.sevenwonders.model.resources.CountedResource
+import org.luxons.sevenwonders.model.resources.Provider
+import org.luxons.sevenwonders.model.resources.ResourceType
+import org.luxons.sevenwonders.ui.redux.TransactionSelectorState
+import react.RBuilder
+import react.dom.div
+import react.dom.p
+import react.dom.tbody
+import styled.*
+
+fun RBuilder.transactionsSelectorDialog(
+ state: TransactionSelectorState?,
+ prepareMove: (PlayerMove) -> Unit,
+ cancelTransactionSelection: () -> Unit,
+) {
+ bpDialog(
+ isOpen = state != null,
+ title = "Time to foot the bill!",
+ canEscapeKeyClose = true,
+ canOutsideClickClose = true,
+ isCloseButtonShown = true,
+ onClose = cancelTransactionSelection,
+ ) {
+ attrs {
+ className = GameStyles.getClassName { it::transactionsSelector }
+ }
+ div {
+ attrs {
+ classes += Classes.DIALOG_BODY
+ }
+ p {
+ +"You don't have enough resources to perform this move, but you can buy them from neighbours. "
+ +"Please pick an option:"
+ }
+ if (state != null) { // should always be true when the dialog is rendered
+ styledDiv {
+ css {
+ margin(all = LinearDimension.auto)
+ display = Display.flex
+ alignItems = Align.center
+ }
+ bpIcon("user", size = 50)
+ styledDiv {
+ css {
+ grow(Grow.GROW)
+ margin(horizontal = 0.5.rem)
+ }
+ optionsTable(state, prepareMove)
+ }
+ bpIcon("user", size = 50)
+ }
+ }
+ }
+ }
+}
+
+private fun RBuilder.optionsTable(
+ state: TransactionSelectorState,
+ prepareMove: (PlayerMove) -> Unit,
+) {
+ bpHtmlTable(interactive = true) {
+ tbody {
+ state.transactionsOptions.forEach { transactions ->
+ styledTr {
+ css {
+ cursor = Cursor.pointer
+ alignItems = Align.center
+ }
+ attrs {
+ onClickFunction = { prepareMove(PlayerMove(state.moveType, state.card.name, transactions)) }
+ }
+ // there should be at most one of each
+ val left = transactions.firstOrNull { it.provider == Provider.LEFT_PLAYER }
+ val right = transactions.firstOrNull { it.provider == Provider.RIGHT_PLAYER }
+ styledTd {
+ transactionCellCss()
+ if (left != null) {
+ styledDiv {
+ transactionCellInnerCss()
+ bpIcon(name = left.provider.arrowIcon(), size = Icon.SIZE_LARGE)
+ goldIndicator(left.totalPrice, imgSize = 2.rem)
+ }
+ }
+ }
+ styledTd {
+ transactionCellCss()
+ if (left != null) {
+ styledDiv {
+ transactionCellInnerCss()
+ resourceList(left.resources)
+ }
+ }
+ }
+ styledTd {
+ transactionCellCss()
+ css {
+ // make this cell fill the space
+ width = 100.pct
+ }
+// goldIndicator(-transactions.sumBy { it.totalPrice }) {
+// css {
+// width = LinearDimension.fitContent
+// margin(horizontal = LinearDimension.auto)
+// }
+// }
+ }
+ styledTd {
+ transactionCellCss()
+ if (right != null) {
+ styledDiv {
+ transactionCellInnerCss()
+ resourceList(right.resources)
+ }
+ }
+ }
+ styledTd {
+ transactionCellCss()
+ if (right != null) {
+ styledDiv {
+ transactionCellInnerCss()
+ goldIndicator(right.totalPrice, imgSize = 2.rem)
+ bpIcon(name = right.provider.arrowIcon(), size = Icon.SIZE_LARGE)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+private fun StyledDOMBuilder<TD>.transactionCellCss() {
+ // we need inline styles to win over blueprintjs's styles (which are more specific than .class)
+ inlineStyles {
+ verticalAlign = VerticalAlign.middle
+ }
+}
+
+private fun StyledDOMBuilder<DIV>.transactionCellInnerCss() {
+ css {
+ display = Display.flex
+ flexDirection = FlexDirection.row
+ alignItems = Align.center
+ }
+}
+
+private fun Provider.arrowIcon() = when (this) {
+ Provider.LEFT_PLAYER -> "caret-left"
+ Provider.RIGHT_PLAYER -> "caret-right"
+}
+
+private fun RBuilder.resourceList(resources: List<CountedResource>) {
+ // The biggest card is the Palace and requires 7 resources (1 of each).
+ // We always have at least 1 resource on our wonder, so we'll never need to buy more than 6.
+ // Therefore, 3 by row seems decent.
+ val rows = resources.toRepeatedTypesList().chunked(3)
+ styledDiv {
+ css {
+ display = Display.flex
+ flexDirection = FlexDirection.column
+ alignItems = Align.center
+ grow(Grow.GROW)
+ }
+ rows.forEach { row ->
+ styledDiv {
+ resourceRowCss()
+ row.forEach {
+ resourceImage(it, size = 1.5.rem)
+ }
+ }
+ }
+ }
+}
+
+private fun StyledDOMBuilder<DIV>.resourceRowCss() {
+ css {
+ display = Display.flex
+ flexDirection = FlexDirection.row
+ alignItems = Align.center
+ margin(horizontal = LinearDimension.auto)
+ }
+}
+
+private fun List<CountedResource>.toRepeatedTypesList(): List<ResourceType> = flatMap { cr -> List(cr.count) { cr.type } }
diff --git a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Actions.kt b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Actions.kt
index bacf6795..951f4f2a 100644
--- a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Actions.kt
+++ b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Actions.kt
@@ -19,6 +19,10 @@ data class EnterGameAction(val lobby: LobbyDTO, val turnInfo: PlayerTurnInfo) :
data class TurnInfoEvent(val turnInfo: PlayerTurnInfo) : RAction
+data class StartTransactionSelection(val transactionSelector: TransactionSelectorState) : RAction
+
+object CancelTransactionSelection : RAction
+
data class PreparedMoveEvent(val move: PlayerMove) : RAction
data class PreparedCardEvent(val card: PreparedCard) : RAction
diff --git a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Reducers.kt b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Reducers.kt
index 97d00ab7..ef1f0362 100644
--- a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Reducers.kt
+++ b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Reducers.kt
@@ -1,5 +1,6 @@
package org.luxons.sevenwonders.ui.redux
+import org.luxons.sevenwonders.model.MoveType
import org.luxons.sevenwonders.model.PlayerMove
import org.luxons.sevenwonders.model.PlayerTurnInfo
import org.luxons.sevenwonders.model.api.ConnectedPlayer
@@ -8,6 +9,7 @@ import org.luxons.sevenwonders.model.api.PlayerDTO
import org.luxons.sevenwonders.model.api.State
import org.luxons.sevenwonders.model.cards.CardBack
import org.luxons.sevenwonders.model.cards.HandCard
+import org.luxons.sevenwonders.model.resources.PricedResourceTransactions
import redux.RAction
data class SwState(
@@ -29,11 +31,18 @@ data class GameState(
val turnInfo: PlayerTurnInfo?,
val preparedCardsByUsername: Map<String, CardBack?> = emptyMap(),
val currentPreparedMove: PlayerMove? = null,
+ val transactionSelector: TransactionSelectorState? = null,
) {
val currentPreparedCard: HandCard?
get() = turnInfo?.hand?.firstOrNull { it.name == currentPreparedMove?.cardName }
}
+data class TransactionSelectorState(
+ val moveType: MoveType,
+ val card: HandCard,
+ val transactionsOptions: Set<PricedResourceTransactions>,
+)
+
fun rootReducer(state: SwState, action: RAction): SwState = state.copy(
gamesById = gamesReducer(state.gamesById, action),
connectedPlayer = currentPlayerReducer(state.connectedPlayer, action),
@@ -81,5 +90,8 @@ private fun gameStateReducer(gameState: GameState?, action: RAction): GameState?
turnInfo = action.turnInfo,
currentPreparedMove = null,
)
+ is StartTransactionSelection -> gameState?.copy(transactionSelector = action.transactionSelector)
+ is CancelTransactionSelection -> gameState?.copy(transactionSelector = null)
+ is RequestPrepareMove -> gameState?.copy(transactionSelector = null)
else -> gameState
}
bgstack15