parabox/app/Main.hs

120 lines
4.2 KiB
Haskell
Raw Normal View History

2022-12-05 08:13:26 -08:00
module Main (main) where
2022-11-30 13:38:12 -08:00
2022-12-02 21:33:44 -08:00
import Control.Exception ( bracket )
2022-11-30 13:38:12 -08:00
import Data.List.NonEmpty (NonEmpty(..))
import Data.List.NonEmpty qualified as NonEmpty
2022-12-07 10:11:06 -08:00
import Data.Char (toUpper)
import Data.List (intersperse)
2022-12-04 19:55:30 -08:00
import Data.Map (Map)
import Data.Map qualified as Map
2022-12-05 08:13:26 -08:00
import Graphics.Vty
import System.Environment ( getArgs )
2022-12-05 21:15:18 -08:00
import System.Directory ( listDirectory )
import System.FilePath ( (</>), takeBaseName )
2022-11-30 13:38:12 -08:00
2022-12-02 10:54:31 -08:00
import Model
2022-12-02 21:33:44 -08:00
import Rendering ( render )
2022-12-04 16:45:15 -08:00
import Parser (parse)
2022-12-07 10:11:06 -08:00
import BigFont
2022-11-30 16:44:30 -08:00
2022-12-03 11:50:06 -08:00
data Game = Game {
2022-12-04 19:55:30 -08:00
gameFlat :: Bool,
gameMode :: GameMode,
gameSelect :: Int
2022-12-03 11:50:06 -08:00
}
2022-11-30 13:38:12 -08:00
2022-12-04 19:55:30 -08:00
data GameMode
= MenuMode
| PlayMode (NonEmpty World)
2022-12-05 17:00:19 -08:00
getWorldList :: IO (Map String FilePath)
getWorldList =
do paths <- listDirectory "levels"
pure (Map.fromList [(takeBaseName path, "levels" </> path) | path <- paths])
2022-11-30 13:38:12 -08:00
main :: IO ()
main =
2022-12-02 20:53:45 -08:00
do args <- getArgs
2022-12-05 17:00:19 -08:00
worldList <- getWorldList
2022-12-04 19:55:30 -08:00
bracket (mkVty =<< userConfig) shutdown \vty ->
case args of
2022-12-05 17:00:19 -08:00
x:_ | Just path <- Map.lookup x worldList ->
do w <- parse <$> readFile path
loop vty Game {
gameMode = PlayMode (pure w),
gameFlat = True,
gameSelect = Map.findIndex x worldList
}
2022-12-04 19:55:30 -08:00
_ ->
loop vty Game {
gameMode = MenuMode,
gameFlat = True,
gameSelect = 0
}
2022-11-30 13:38:12 -08:00
2022-12-03 11:50:06 -08:00
loop :: Vty -> Game -> IO ()
loop vty game =
2022-12-04 19:55:30 -08:00
case gameMode game of
MenuMode ->
2022-12-05 17:00:19 -08:00
do worldList <- getWorldList
let (a,b) = Map.splitAt (gameSelect game) worldList
2022-12-04 19:55:30 -08:00
bnds <- displayBounds (outputIface vty)
update vty (picForImage (renderMenu bnds a b))
ev <- nextEvent vty
case ev of
EvKey key _modifier ->
case key of
KEsc -> pure ()
KUp | gameSelect game > 0 -> loop vty game{ gameSelect = gameSelect game - 1 }
KDown | gameSelect game + 1 < Map.size worldList -> loop vty game{ gameSelect = gameSelect game + 1 }
2022-12-05 17:00:19 -08:00
KEnter | Just (path,_) <- Map.minView b ->
do world <- parse <$> readFile path
loop vty game{ gameMode = PlayMode (pure world) }
2022-12-04 19:55:30 -08:00
_ -> loop vty game
_ -> loop vty game
PlayMode worlds ->
do let world = NonEmpty.head worlds
update vty (render (gameFlat game) (NonEmpty.head worlds))
ev <- nextEvent vty
case ev of
EvKey key _modifier ->
case key of
KUp -> loop vty game{ gameMode = PlayMode (NonEmpty.cons (move world (-1,0)) worlds) }
KDown -> loop vty game{ gameMode = PlayMode (NonEmpty.cons (move world (1,0) ) worlds) }
KLeft -> loop vty game{ gameMode = PlayMode (NonEmpty.cons (move world (0,-1)) worlds) }
KRight -> loop vty game{ gameMode = PlayMode (NonEmpty.cons (move world (0,1) ) worlds) }
KChar 'm' -> loop vty game { gameMode = MenuMode }
KChar 'r' -> loop vty game{ gameMode = PlayMode (pure (NonEmpty.last worlds)) }
KChar 'z'
| Just worlds' <- NonEmpty.nonEmpty (NonEmpty.tail worlds) ->
loop vty game{ gameMode = PlayMode worlds' }
KEsc -> pure ()
KChar 'f' -> loop vty game{ gameFlat = not (gameFlat game) }
_ -> loop vty game
2022-12-03 11:50:06 -08:00
_ -> loop vty game
2022-12-04 19:55:30 -08:00
2022-12-05 17:00:19 -08:00
renderMenu :: DisplayRegion -> Map String a -> Map String a -> Image
2022-12-04 19:55:30 -08:00
renderMenu (w,h) before after =
pad ((w - imageWidth menu) `div` 2) 0 0 0 menu
where
menu =
case Map.minViewWithKey after of
2022-12-07 10:11:06 -08:00
Nothing -> bigString defAttr "empty menu"
2022-12-04 19:55:30 -08:00
Just ((k,_),after') ->
2022-12-07 10:11:06 -08:00
let len1 = (h-1)`div`2 `div` 6 in
pad 0 (max 0 (6 * (len1 - Map.size before))) 0 0 $
vertCat $
intersperse (char defAttr ' ') $
[ bigString defAttr x
2022-12-04 19:55:30 -08:00
| x <- drop (Map.size before - len1) (Map.keys before)
2022-12-07 10:11:06 -08:00
] ++
[bigString (defAttr `withBackColor` cyan `withForeColor` white) k] ++
[ bigString defAttr x
2022-12-04 19:55:30 -08:00
| x <- drop (Map.size after' - h`div`2) (Map.keys after')
]
2022-12-07 10:11:06 -08:00
bigString :: Attr -> String -> Image
bigString a = vertCat . map (string a) . bigText . map toUpper