Skip to content
This repository was archived by the owner on Sep 16, 2025. It is now read-only.

Commit 9165fa5

Browse files
committed
Adds a link bacl to campaign trackers
If the player comes from the Gloomhaven Storyline app then there is now a menu item to get back to it. Otherwise the app acts exactly as it did before
1 parent 39ab1c1 commit 9165fa5

File tree

3 files changed

+91
-14
lines changed

3 files changed

+91
-14
lines changed

VirtualGloomhavenBoard/Elm/src/AppStorage.elm

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
port module AppStorage exposing (AppModeType(..), AppOverrides, Config, GameModeType(..), MoveablePiece, MoveablePieceType(..), decodeMoveablePiece, empty, emptyOverrides, encodeMoveablePiece, loadFromStorage, loadOverrides, saveToStorage)
1+
port module AppStorage exposing (AppModeType(..), AppOverrides, CampaignTrackerUrl(..), Config, GameModeType(..), MoveablePiece, MoveablePieceType(..), decodeMoveablePiece, empty, emptyOverrides, encodeMoveablePiece, loadFromStorage, loadOverrides, saveToStorage)
22

33
import BoardOverlay exposing (BoardOverlay)
44
import Character exposing (CharacterClass, stringToCharacter)
55
import Game exposing (GameState, Piece)
66
import GameSync exposing (decodeGameState, decodePiece, encodeGameState, encodeOverlay, encodePiece)
77
import Html exposing (s)
8-
import Json.Decode as Decode exposing (Decoder, andThen, decodeValue, fail, field, map2, map4, map5, map6, maybe, string, succeed)
8+
import Json.Decode as Decode exposing (Decoder, andThen, decodeValue, fail, field, map2, map4, map5, map6, map7, maybe, string, succeed)
99
import Json.Encode as Encode exposing (object, string)
1010
import List exposing (filterMap)
1111
import SharedSync exposing (decodeBoardOverlay)
@@ -26,6 +26,7 @@ type alias Config =
2626
, roomCode : Maybe String
2727
, showRoomCode : Bool
2828
, boardOnly : Bool
29+
, campaignTracker : Maybe CampaignTrackerUrl
2930
}
3031

3132

@@ -36,9 +37,14 @@ type alias AppOverrides =
3637
, lockScenario : Bool
3738
, lockPlayers : Bool
3839
, lockRoomCode : Bool
40+
, campaignTracker : Maybe CampaignTrackerUrl
3941
}
4042

4143

44+
type CampaignTrackerUrl
45+
= CampaignTrackerUrl String String
46+
47+
4248
type GameModeType
4349
= MovePiece
4450
| KillPiece
@@ -70,7 +76,7 @@ type MoveablePieceType
7076

7177
emptyConfig : Config
7278
emptyConfig =
73-
Config Game MovePiece Nothing True False
79+
Config Game MovePiece Nothing True False Nothing
7480

7581

7682
empty : ( GameState, Config )
@@ -80,7 +86,7 @@ empty =
8086

8187
emptyOverrides : AppOverrides
8288
emptyOverrides =
83-
AppOverrides Nothing Nothing Nothing False False False
89+
AppOverrides Nothing Nothing Nothing False False False Nothing
8490

8591

8692
saveToStorage : GameState -> Config -> Cmd msg
@@ -131,6 +137,14 @@ encodeConfig config =
131137
)
132138
, ( "showRoomCode", Encode.bool config.showRoomCode )
133139
, ( "boardOnly", Encode.bool config.boardOnly )
140+
, ( "campaignTracker"
141+
, case config.campaignTracker of
142+
Just t ->
143+
Encode.object (encodeCampaignTrackerUrl t)
144+
145+
Nothing ->
146+
Encode.null
147+
)
134148
]
135149

136150

@@ -184,7 +198,7 @@ storedDataDecoder =
184198

185199
appOverridesDecoder : Decoder AppOverrides
186200
appOverridesDecoder =
187-
map6 AppOverrides
201+
map7 AppOverrides
188202
(field "initScenario" (maybe Decode.int))
189203
(field "initPlayers"
190204
(maybe (Decode.list Decode.string)
@@ -199,16 +213,18 @@ appOverridesDecoder =
199213
(field "lockScenario" Decode.bool)
200214
(field "lockPlayers" Decode.bool)
201215
(field "lockRoomCode" Decode.bool)
216+
(field "campaignTracker" (maybe decodeCampaignTrackerUrl))
202217

203218

204219
decodeConfig : Decoder Config
205220
decodeConfig =
206-
map5 Config
221+
map6 Config
207222
(field "appMode" (Decode.string |> Decode.andThen decodeAppMode))
208223
(field "gameMode" (Decode.string |> Decode.andThen decodeGameMode))
209224
(field "roomCode" (Decode.nullable Decode.string))
210225
(field "showRoomCode" Decode.bool)
211226
(maybe (field "boardOnly" Decode.bool) |> andThen (\b -> succeed (Maybe.withDefault False b)))
227+
(maybe (field "campaignTracker" decodeCampaignTrackerUrl))
212228

213229

214230
decodeAppMode : String -> Decoder AppModeType
@@ -310,6 +326,16 @@ decodeCoords =
310326
)
311327

312328

329+
decodeCampaignTrackerUrl : Decoder CampaignTrackerUrl
330+
decodeCampaignTrackerUrl =
331+
field "name" Decode.string
332+
|> andThen
333+
(\name ->
334+
field "url" Decode.string
335+
|> andThen (\url -> Decode.succeed (CampaignTrackerUrl name url))
336+
)
337+
338+
313339
encodeMoveablePiece : MoveablePiece -> Encode.Value
314340
encodeMoveablePiece piece =
315341
Encode.object
@@ -378,3 +404,10 @@ encodeCoords ( x, y ) =
378404
[ ( "x", Encode.int x )
379405
, ( "y", Encode.int y )
380406
]
407+
408+
409+
encodeCampaignTrackerUrl : CampaignTrackerUrl -> List ( String, Encode.Value )
410+
encodeCampaignTrackerUrl tracker =
411+
case tracker of
412+
CampaignTrackerUrl name url ->
413+
[ ( "name", Encode.string name ), ( "url", Encode.string url ) ]

VirtualGloomhavenBoard/Elm/src/Main.elm

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
port module Main exposing (main)
22

3-
import AppStorage exposing (AppModeType(..), Config, GameModeType(..), MoveablePiece, MoveablePieceType(..), decodeMoveablePiece, emptyOverrides, encodeMoveablePiece, loadFromStorage, loadOverrides, saveToStorage)
3+
import AppStorage exposing (AppModeType(..), CampaignTrackerUrl(..), Config, GameModeType(..), MoveablePiece, MoveablePieceType(..), decodeMoveablePiece, emptyOverrides, encodeMoveablePiece, loadFromStorage, loadOverrides, saveToStorage)
44
import Array exposing (Array, fromList, length, toIndexedList, toList)
55
import Bitwise
66
import BoardMapTile exposing (MapTileRef(..), refToString)
@@ -230,6 +230,13 @@ init ( oldState, maybeOverrides, seed ) =
230230

231231
Nothing ->
232232
c.roomCode
233+
, campaignTracker =
234+
case overrides.campaignTracker of
235+
Just t ->
236+
Just t
237+
238+
Nothing ->
239+
c.campaignTracker
233240
}
234241
)
235242

@@ -1056,14 +1063,15 @@ view model =
10561063
, id "content"
10571064
, Touch.onCancel (\_ -> TouchCanceled)
10581065
]
1059-
([ lazy7
1066+
([ lazy8
10601067
getHeaderHtml
10611068
model.game.scenario.id
10621069
model.game.scenario.title
10631070
model.config.roomCode
10641071
model.config.showRoomCode
10651072
model.lockScenario
10661073
model.lockPlayers
1074+
model.config.campaignTracker
10671075
model.menuOpen
10681076
, div [ class "main" ]
10691077
[ div
@@ -1204,8 +1212,8 @@ subscriptions _ =
12041212
]
12051213

12061214

1207-
getHeaderHtml : Int -> String -> Maybe String -> Bool -> Bool -> Bool -> Bool -> Html.Html Msg
1208-
getHeaderHtml scenarioId scenarioTitle roomCode showRoomCode lockScenario lockPlayers menuOpen =
1215+
getHeaderHtml : Int -> String -> Maybe String -> Bool -> Bool -> Bool -> Maybe CampaignTrackerUrl -> Bool -> Html.Html Msg
1216+
getHeaderHtml scenarioId scenarioTitle roomCode showRoomCode lockScenario lockPlayers campaignTracker menuOpen =
12091217
div
12101218
[ class "header" ]
12111219
[ div
@@ -1231,7 +1239,17 @@ getHeaderHtml scenarioId scenarioTitle roomCode showRoomCode lockScenario lockPl
12311239
"false"
12321240
)
12331241
]
1234-
[ lazy3 getMenuHtml lockScenario lockPlayers menuOpen ]
1242+
[ let
1243+
( campaignTrackerName, campaignTrackerUrl ) =
1244+
case campaignTracker of
1245+
Just (CampaignTrackerUrl name url) ->
1246+
( Just name, Just url )
1247+
1248+
Nothing ->
1249+
( Nothing, Nothing )
1250+
in
1251+
lazy6 getMenuHtml lockScenario lockPlayers scenarioId campaignTrackerName campaignTrackerUrl menuOpen
1252+
]
12351253
, header [ attribute "aria-label" "Scenario" ]
12361254
(if scenarioId /= 0 then
12371255
[ span [ class "number" ] [ text (String.fromInt scenarioId) ]
@@ -1481,8 +1499,8 @@ getNewPieceHtml gameMode currentDraggable hasDiviner bearSummoned nextSummonsId
14811499
|> Dom.render
14821500

14831501

1484-
getMenuHtml : Bool -> Bool -> Bool -> Html.Html Msg
1485-
getMenuHtml lockScenario lockPlayers menuOpen =
1502+
getMenuHtml : Bool -> Bool -> Int -> Maybe String -> Maybe String -> Bool -> Html.Html Msg
1503+
getMenuHtml lockScenario lockPlayers scenarioId campaignTrackerName campaignTrackerUrl menuOpen =
14861504
Dom.element "nav"
14871505
|> Dom.addAttribute
14881506
(attribute
@@ -1544,7 +1562,24 @@ getMenuHtml lockScenario lockPlayers menuOpen =
15441562
|> Dom.addClass "section-end"
15451563
|> Dom.appendText "Settings"
15461564
|> shortcutHtml [ "", "s" ]
1547-
, Dom.element "li"
1565+
]
1566+
++ (case ( campaignTrackerName, campaignTrackerUrl ) of
1567+
( Just name, Just url ) ->
1568+
[ Dom.element "li"
1569+
|> Dom.addAttribute (attribute "role" "menuitem")
1570+
|> Dom.addAttribute (tabindex 0)
1571+
|> Dom.appendChild
1572+
(Dom.element "a"
1573+
|> Dom.addAttribute (href (String.replace "{scenarioId}" (String.fromInt scenarioId) url))
1574+
|> Dom.addAttribute (target "_new")
1575+
|> Dom.appendText name
1576+
)
1577+
]
1578+
1579+
_ ->
1580+
[]
1581+
)
1582+
++ [ Dom.element "li"
15481583
|> Dom.addAttribute (attribute "role" "menuitem")
15491584
|> Dom.addAttribute (tabindex 0)
15501585
|> Dom.appendChild

VirtualGloomhavenBoard/wwwroot/js/app.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,15 @@
185185
o.initRoomCodeSeed = seed;
186186
}
187187

188+
if (document.referrer !== "") {
189+
if (document.referrer.includes("gloomhaven-storyline.com")) {
190+
o.campaignTracker = {
191+
name: "Gloomhaven Storyline",
192+
url: "https://gloomhaven-storyline.com/#/story/{scenarioId}"
193+
}
194+
}
195+
}
196+
188197
return o;
189198
}
190199

0 commit comments

Comments
 (0)