Refactored all lobby sub-scenes to modify the lobby via message rather than directly - simpler code and a single modification point.
This commit is contained in:
@@ -181,6 +181,23 @@ back : String -> Player.Secret -> Request Never Game.LobbyAndHand
|
||||
back = commandRequest "back" [] []
|
||||
|
||||
|
||||
{-| Errors specific to redrawing.
|
||||
* `NotEnoughPoints` - The player does not have enough points to redraw.
|
||||
-}
|
||||
type RedrawError
|
||||
= NotEnoughPoints
|
||||
|
||||
{-| Make a request to redraw the players hand, losing a point.
|
||||
-}
|
||||
redraw : String -> Player.Secret -> Request RedrawError Game.LobbyAndHand
|
||||
redraw =
|
||||
commandRequest
|
||||
"redraw"
|
||||
[]
|
||||
[ ((400, "not-enough-points-to-redraw"), Decode.succeed NotEnoughPoints)
|
||||
]
|
||||
|
||||
|
||||
{- Private -}
|
||||
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import MassiveDecks.API as API
|
||||
import MassiveDecks.API.Request as Request
|
||||
import MassiveDecks.Components.Input as Input
|
||||
import MassiveDecks.Components.Errors as Errors
|
||||
import MassiveDecks.Models.Game as Game
|
||||
import MassiveDecks.Scenes.Lobby.Models as Lobby
|
||||
import MassiveDecks.Scenes.Config.Messages exposing (ConsumerMessage(..), Message(..), InputId(..), Deck(..))
|
||||
import MassiveDecks.Scenes.Config.Models exposing (Model)
|
||||
@@ -41,90 +40,58 @@ view lobbyModel = UI.view lobbyModel |> Html.map LocalMessage
|
||||
|
||||
{-| Handles messages and alters the model as appropriate.
|
||||
-}
|
||||
update : Message -> Lobby.Model -> (Lobby.Model, Cmd ConsumerMessage)
|
||||
update : Message -> Lobby.Model -> (Model, Cmd ConsumerMessage)
|
||||
update message lobbyModel =
|
||||
let
|
||||
gameCode = lobbyModel.lobbyAndHand.lobby.gameCode
|
||||
gameCode = lobbyModel.lobby.gameCode
|
||||
secret = lobbyModel.secret
|
||||
model = lobbyModel.config
|
||||
in
|
||||
case message of
|
||||
ConfigureDecks (Request rawDeckId) ->
|
||||
let
|
||||
deckId = String.toUpper rawDeckId
|
||||
in
|
||||
lobbyModel
|
||||
|> updateConfig (\model -> ({ model | loadingDecks = model.loadingDecks ++ [ deckId ] }, Cmd.none))
|
||||
:> cmd (Request.send (API.addDeck gameCode secret deckId)
|
||||
(addDeckErrorHandler deckId)
|
||||
ErrorMessage
|
||||
((Add deckId) >> ConfigureDecks >> LocalMessage))
|
||||
:> clearDeckIdError
|
||||
{ model | loadingDecks = model.loadingDecks ++ [ deckId ] } !
|
||||
[ Request.send (API.addDeck gameCode secret deckId) (addDeckErrorHandler deckId) ErrorMessage ((Add deckId) >> ConfigureDecks >> LocalMessage)
|
||||
, inputClearErrorCmd DeckId
|
||||
]
|
||||
|
||||
ConfigureDecks (Add deckId lobbyAndHand) ->
|
||||
lobbyModel
|
||||
|> updateLobbyAndHand lobbyAndHand
|
||||
:> removeDeckLoadingSpinner deckId
|
||||
(removeDeckLoadingSpinner deckId model, Util.cmd (LobbyUpdate lobbyAndHand))
|
||||
|
||||
ConfigureDecks (Fail deckId errorMessage) ->
|
||||
lobbyModel
|
||||
|> deckIdError errorMessage
|
||||
:> removeDeckLoadingSpinner deckId
|
||||
(removeDeckLoadingSpinner deckId model, inputSetErrorCmd DeckId errorMessage)
|
||||
|
||||
InputMessage message ->
|
||||
lobbyModel
|
||||
|> updateDeckIdInput (Input.update message lobbyModel.config.deckIdInput)
|
||||
let
|
||||
(deckIdInput, msg) = Input.update message lobbyModel.config.deckIdInput
|
||||
in
|
||||
({ model | deckIdInput = deckIdInput }, Cmd.map LocalMessage msg)
|
||||
|
||||
AddAi ->
|
||||
lobbyModel
|
||||
|> cmd (Request.send' (API.newAi gameCode) ErrorMessage (\_ -> LocalMessage NoOp))
|
||||
(model, Request.send' (API.newAi gameCode) ErrorMessage (\_ -> LocalMessage NoOp))
|
||||
|
||||
StartGame ->
|
||||
lobbyModel
|
||||
|> cmd (Request.send (API.newGame gameCode secret) newGameErrorHandler ErrorMessage (GameStarted >> LocalMessage))
|
||||
(model, Request.send (API.newGame gameCode secret) newGameErrorHandler ErrorMessage (GameStarted >> LocalMessage))
|
||||
|
||||
GameStarted lobbyAndHand ->
|
||||
lobbyModel
|
||||
|> updateLobbyAndHand lobbyAndHand
|
||||
(model, Util.cmd (LobbyUpdate lobbyAndHand))
|
||||
|
||||
NoOp ->
|
||||
(lobbyModel, Cmd.none)
|
||||
(model, Cmd.none)
|
||||
|
||||
|
||||
type alias Update = Lobby.Model -> (Lobby.Model, Cmd ConsumerMessage)
|
||||
inputClearErrorCmd : InputId -> Cmd ConsumerMessage
|
||||
inputClearErrorCmd inputId = (inputId, Nothing |> Input.Error) |> InputMessage |> LocalMessage |> Util.cmd
|
||||
|
||||
|
||||
clearDeckIdError : Update
|
||||
clearDeckIdError lobbyModel = (lobbyModel, (DeckId, Nothing |> Input.Error) |> InputMessage |> LocalMessage |> Util.cmd)
|
||||
inputSetErrorCmd : InputId -> String -> Cmd ConsumerMessage
|
||||
inputSetErrorCmd inputId error = (inputId, Just error |> Input.Error) |> InputMessage |> LocalMessage |> Util.cmd
|
||||
|
||||
|
||||
deckIdError : String -> Update
|
||||
deckIdError error lobbyModel = (lobbyModel, (DeckId, Just error |> Input.Error) |> InputMessage |> LocalMessage |> Util.cmd)
|
||||
|
||||
|
||||
cmd : Cmd ConsumerMessage -> Update
|
||||
cmd command lobbyModel = (lobbyModel, command)
|
||||
|
||||
|
||||
updateLobbyAndHand : Game.LobbyAndHand -> Update
|
||||
updateLobbyAndHand lobbyAndHand lobbyModel = ({ lobbyModel | lobbyAndHand = lobbyAndHand }, Cmd.none)
|
||||
|
||||
|
||||
updateConfig : (Model -> (Model, Cmd ConsumerMessage)) -> Update
|
||||
updateConfig update lobbyModel =
|
||||
let
|
||||
result = update lobbyModel.config
|
||||
in
|
||||
({ lobbyModel | config = fst result }, snd result)
|
||||
|
||||
|
||||
removeDeckLoadingSpinner : String -> Update
|
||||
removeDeckLoadingSpinner deckId =
|
||||
updateConfig (\model -> ({ model | loadingDecks = List.filter ((/=) deckId) model.loadingDecks }, Cmd.none))
|
||||
|
||||
|
||||
updateDeckIdInput : (Input.Model InputId Message, Cmd Message) -> Update
|
||||
updateDeckIdInput update lobbyModel =
|
||||
updateConfig (\model -> ({ model | deckIdInput = fst update }, snd update |> Cmd.map LocalMessage)) lobbyModel
|
||||
removeDeckLoadingSpinner : String -> Model -> Model
|
||||
removeDeckLoadingSpinner deckId model = { model | loadingDecks = List.filter ((/=) deckId) model.loadingDecks }
|
||||
|
||||
|
||||
addDeckErrorHandler : String -> API.AddDeckError -> ConsumerMessage
|
||||
|
||||
@@ -8,7 +8,8 @@ import MassiveDecks.Models.Game as Game
|
||||
{-| This type is used for all sending of messages, allowing us to send messages handled outside this scene.
|
||||
-}
|
||||
type ConsumerMessage
|
||||
= ErrorMessage Errors.Message
|
||||
= LobbyUpdate Game.LobbyAndHand
|
||||
| ErrorMessage Errors.Message
|
||||
| LocalMessage Message
|
||||
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ view : Lobby.Model -> Html Message
|
||||
view lobbyModel =
|
||||
let
|
||||
model = lobbyModel.config
|
||||
lobby = lobbyModel.lobbyAndHand.lobby
|
||||
lobby = lobbyModel.lobby
|
||||
decks = lobby.config.decks
|
||||
enoughPlayers = ((List.length lobby.players) > 1)
|
||||
enoughCards = not (List.isEmpty decks)
|
||||
|
||||
@@ -32,7 +32,8 @@ import MassiveDecks.Util as Util
|
||||
-}
|
||||
init : Init -> Game.LobbyAndHand -> Player.Secret -> (Model, Cmd ConsumerMessage)
|
||||
init init lobbyAndHand secret =
|
||||
( { lobbyAndHand = lobbyAndHand
|
||||
( { lobby = lobbyAndHand.lobby
|
||||
, hand = lobbyAndHand.hand
|
||||
, config = Config.init
|
||||
, playing = Playing.init init
|
||||
, secret = secret
|
||||
@@ -54,11 +55,11 @@ sendSecretToWebSocket url gameCode secret = WebSocket.send (webSocketUrl url gam
|
||||
subscriptions : Model -> Sub ConsumerMessage
|
||||
subscriptions model =
|
||||
let
|
||||
delegated = case model.lobbyAndHand.lobby.round of
|
||||
delegated = case model.lobby.round of
|
||||
Nothing -> Config.subscriptions model.config |> Sub.map ConfigMessage
|
||||
Just round -> Sub.none
|
||||
|
||||
websocket = WebSocket.listen (webSocketUrl model.init.url model.lobbyAndHand.lobby.gameCode) webSocketResponseDecoder
|
||||
websocket = WebSocket.listen (webSocketUrl model.init.url model.lobby.gameCode) webSocketResponseDecoder
|
||||
in
|
||||
Sub.batch [ delegated |> Sub.map LocalMessage
|
||||
, websocket |> Sub.map LocalMessage
|
||||
@@ -116,28 +117,31 @@ update message model =
|
||||
Config.ErrorMessage errorMessage ->
|
||||
(model, ErrorMessage errorMessage |> Util.cmd)
|
||||
|
||||
Config.LobbyUpdate lobbyAndHand ->
|
||||
model |> updateLobbyAndHand lobbyAndHand
|
||||
|
||||
Config.LocalMessage localMessage ->
|
||||
let
|
||||
(newModel, cmd) = Config.update localMessage model
|
||||
(config, cmd) = Config.update localMessage model
|
||||
in
|
||||
(newModel, Cmd.map (LocalMessage << ConfigMessage) cmd)
|
||||
({ model | config = config }, Cmd.map (LocalMessage << ConfigMessage) cmd)
|
||||
|
||||
PlayingMessage playingMessage ->
|
||||
case playingMessage of
|
||||
Playing.ErrorMessage errorMessage ->
|
||||
(model, ErrorMessage errorMessage |> Util.cmd)
|
||||
|
||||
Playing.LobbyUpdate lobbyAndHand ->
|
||||
model |> updateLobbyAndHand lobbyAndHand
|
||||
|
||||
Playing.LocalMessage localMessage ->
|
||||
let
|
||||
(newModel, cmd) = Playing.update localMessage model
|
||||
(playing, cmd) = Playing.update localMessage model
|
||||
in
|
||||
(newModel, Cmd.map (LocalMessage << PlayingMessage) cmd)
|
||||
({ model | playing = playing }, Cmd.map (LocalMessage << PlayingMessage) cmd)
|
||||
|
||||
LobbyUpdated lobby ->
|
||||
let
|
||||
lobbyAndHand = model.lobbyAndHand
|
||||
in
|
||||
({ model | lobbyAndHand = { lobbyAndHand | lobby = lobby } }, Cmd.none)
|
||||
model |> updateLobbyAndHand { lobby = lobby, hand = model.hand }
|
||||
|
||||
DismissNotification notification ->
|
||||
let
|
||||
@@ -151,7 +155,7 @@ update message model =
|
||||
|
||||
GameEvent event ->
|
||||
let
|
||||
players = model.lobbyAndHand.lobby.players
|
||||
players = model.lobby.players
|
||||
in
|
||||
case event of
|
||||
Event.RoundEnd call czar responses playedByAndWinner ->
|
||||
@@ -180,6 +184,18 @@ update message model =
|
||||
(model, Cmd.none)
|
||||
|
||||
|
||||
type alias Update = Model -> (Model, Cmd ConsumerMessage)
|
||||
|
||||
|
||||
updateLobbyAndHand : Game.LobbyAndHand -> Update
|
||||
updateLobbyAndHand lobbyAndHand model =
|
||||
let
|
||||
events = Event.events model.lobby lobbyAndHand.lobby |> List.map (GameEvent >> LocalMessage >> Util.cmd)
|
||||
in
|
||||
{ model | lobby = lobbyAndHand.lobby
|
||||
, hand = lobbyAndHand.hand} ! events
|
||||
|
||||
|
||||
{-| Handles a change to the displayed notification.
|
||||
-}
|
||||
notificationChange : Model -> Maybe Notification -> (Model, Cmd ConsumerMessage)
|
||||
|
||||
@@ -3,6 +3,7 @@ module MassiveDecks.Scenes.Lobby.Models exposing (Model)
|
||||
import MassiveDecks.Models exposing (Init)
|
||||
import MassiveDecks.Models.Game as Game
|
||||
import MassiveDecks.Models.Player as Player
|
||||
import MassiveDecks.Models.Card as Card
|
||||
import MassiveDecks.Models.Notification as Notification exposing (Notification)
|
||||
import MassiveDecks.Scenes.Config.Models as Config
|
||||
import MassiveDecks.Scenes.Playing.Models as Playing
|
||||
@@ -11,7 +12,8 @@ import MassiveDecks.Scenes.Playing.Models as Playing
|
||||
{-| The state of the lobby.
|
||||
-}
|
||||
type alias Model =
|
||||
{ lobbyAndHand : Game.LobbyAndHand
|
||||
{ lobby : Game.Lobby
|
||||
, hand : Card.Hand
|
||||
, config : Config.Model
|
||||
, playing : Playing.Model
|
||||
, secret : Player.Secret
|
||||
|
||||
@@ -19,7 +19,7 @@ import MassiveDecks.Util as Util
|
||||
view : Model -> Html ConsumerMessage
|
||||
view model =
|
||||
let
|
||||
lobby = model.lobbyAndHand.lobby
|
||||
lobby = model.lobby
|
||||
url = model.init.url
|
||||
gameCode = lobby.gameCode
|
||||
players = lobby.players
|
||||
|
||||
@@ -59,11 +59,11 @@ view model =
|
||||
|
||||
{-| Handles messages and alters the model as appropriate.
|
||||
-}
|
||||
update : Message -> Lobby.Model -> (Lobby.Model, Cmd ConsumerMessage)
|
||||
update : Message -> Lobby.Model -> (Model, Cmd ConsumerMessage)
|
||||
update message lobbyModel =
|
||||
let
|
||||
model = lobbyModel.playing
|
||||
lobby = lobbyModel.lobbyAndHand.lobby
|
||||
lobby = lobbyModel.lobby
|
||||
secret = lobbyModel.secret
|
||||
gameCode = lobby.gameCode
|
||||
in
|
||||
@@ -78,62 +78,61 @@ update message lobbyModel =
|
||||
) lobby.round)
|
||||
in
|
||||
if playing && canPlay then
|
||||
lobbyModel |> updateModel (\model -> { model | picked = model.picked ++ [ cardId ] })
|
||||
({ model | picked = model.picked ++ [ cardId ] }, Cmd.none)
|
||||
else
|
||||
(lobbyModel, Cmd.none)
|
||||
(model, Cmd.none)
|
||||
|
||||
Withdraw cardId ->
|
||||
lobbyModel |> updateModel (\model -> { model | picked = List.filter ((/=) cardId) model.picked })
|
||||
({ model | picked = List.filter ((/=) cardId) model.picked }, Cmd.none)
|
||||
|
||||
Play ->
|
||||
lobbyModel
|
||||
|> updateModel (\model -> { model | picked = [] })
|
||||
:> cmd (Request.send (API.play gameCode secret model.picked) playErrorHandler ErrorMessage (UpdateLobbyAndHand >> LocalMessage))
|
||||
( { model | picked = [] }
|
||||
, Request.send (API.play gameCode secret model.picked) playErrorHandler ErrorMessage (UpdateLobbyAndHand >> LocalMessage)
|
||||
)
|
||||
|
||||
Consider potentialWinnerIndex ->
|
||||
lobbyModel |> updateModel (\model -> { model | considering = Just potentialWinnerIndex })
|
||||
( { model | considering = Just potentialWinnerIndex }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
Choose winnerIndex ->
|
||||
lobbyModel
|
||||
|> updateModel (\model -> { model | considering = Nothing })
|
||||
:> cmd (Request.send (API.choose gameCode secret winnerIndex) chooseErrorHandler ErrorMessage (UpdateLobbyAndHand >> LocalMessage))
|
||||
( { model | considering = Nothing }
|
||||
, Request.send (API.choose gameCode secret winnerIndex) chooseErrorHandler ErrorMessage (UpdateLobbyAndHand >> LocalMessage)
|
||||
)
|
||||
|
||||
NextRound ->
|
||||
lobbyModel |> updateModel (\model -> { model | considering = Nothing
|
||||
, finishedRound = Nothing
|
||||
})
|
||||
( { model | considering = Nothing
|
||||
, finishedRound = Nothing
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
CheckForPlayedCardsToAnimate ->
|
||||
lobbyModel
|
||||
|> cmd (if List.isEmpty model.shownPlayed.toAnimate then Cmd.none else Util.cmd (LocalMessage AnimatePlayedCards))
|
||||
( model
|
||||
, if List.isEmpty model.shownPlayed.toAnimate then Cmd.none else Util.cmd (LocalMessage AnimatePlayedCards)
|
||||
)
|
||||
|
||||
AnimatePlayedCards ->
|
||||
let
|
||||
(shownPlayed, seed) = updatePositioning model.shownPlayed model.seed
|
||||
in
|
||||
lobbyModel |> updateModel (\model -> { model | seed = seed
|
||||
, shownPlayed = shownPlayed
|
||||
})
|
||||
( { model | seed = seed
|
||||
, shownPlayed = shownPlayed
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
Skip playerIds ->
|
||||
lobbyModel |> cmd (Request.send (API.skip gameCode secret playerIds) skipErrorHandler ErrorMessage (UpdateLobbyAndHand >> LocalMessage))
|
||||
(model, Request.send (API.skip gameCode secret playerIds) skipErrorHandler ErrorMessage (UpdateLobbyAndHand >> LocalMessage))
|
||||
|
||||
Back ->
|
||||
lobbyModel |> cmd (Request.send' (API.back gameCode secret) ErrorMessage (UpdateLobbyAndHand >> LocalMessage))
|
||||
(model, Request.send' (API.back gameCode secret) ErrorMessage (UpdateLobbyAndHand >> LocalMessage))
|
||||
|
||||
UpdateLobbyAndHand lobbyAndHand ->
|
||||
lobbyModel |> updateLobbyAndHand lobbyAndHand
|
||||
|
||||
|
||||
type alias Update = Lobby.Model -> (Lobby.Model, Cmd ConsumerMessage)
|
||||
|
||||
|
||||
updateModel : (Model -> Model) -> Update
|
||||
updateModel update lobbyModel = ({ lobbyModel | playing = update lobbyModel.playing }, Cmd.none)
|
||||
|
||||
|
||||
cmd : Cmd ConsumerMessage -> Update
|
||||
cmd command lobbyModel = (lobbyModel, command)
|
||||
type alias Update = Lobby.Model -> (Model, Cmd ConsumerMessage)
|
||||
|
||||
|
||||
updateLobbyAndHand : Game.LobbyAndHand -> Update
|
||||
@@ -160,9 +159,7 @@ updateLobbyAndHand lobbyAndHand lobbyModel =
|
||||
newModel = { model | shownPlayed = newShownPlayed
|
||||
, seed = seed}
|
||||
in
|
||||
({ lobbyModel | lobbyAndHand = lobbyAndHand
|
||||
, playing = newModel
|
||||
}, Cmd.none)
|
||||
(newModel, Util.cmd (LobbyUpdate lobbyAndHand))
|
||||
|
||||
|
||||
chooseErrorHandler : API.ChooseError -> ConsumerMessage
|
||||
|
||||
@@ -8,7 +8,8 @@ import MassiveDecks.Models.Game as Game
|
||||
{-| This type is used for all sending of messages, allowing us to send messages handled outside this scene.
|
||||
-}
|
||||
type ConsumerMessage
|
||||
= ErrorMessage Errors.Message
|
||||
= LobbyUpdate Game.LobbyAndHand
|
||||
| ErrorMessage Errors.Message
|
||||
| LocalMessage Message
|
||||
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ view : Lobby.Model -> (List (Html Message), List (Html Message))
|
||||
view lobbyModel =
|
||||
let
|
||||
model = lobbyModel.playing
|
||||
lobby = lobbyModel.lobbyAndHand.lobby
|
||||
lobby = lobbyModel.lobby
|
||||
in
|
||||
case model.finishedRound of
|
||||
Just round ->
|
||||
@@ -35,8 +35,8 @@ view lobbyModel =
|
||||
roundContents : Lobby.Model -> Game.Round -> List (Html Message)
|
||||
roundContents lobbyModel round =
|
||||
let
|
||||
lobby = lobbyModel.lobbyAndHand.lobby
|
||||
hand = lobbyModel.lobbyAndHand.hand.hand
|
||||
lobby = lobbyModel.lobby
|
||||
hand = lobbyModel.hand.hand
|
||||
model = lobbyModel.playing
|
||||
pickedWithIndex = Util.getAllWithIndex hand model.picked
|
||||
picked = List.map snd pickedWithIndex
|
||||
|
||||
Reference in New Issue
Block a user