nyx-game-0.1.0.0: app/VN.hs
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE OverloadedStrings #-}
module VN where
import SDL.Vect (V4(..))
import qualified SDL
import qualified SDL.Mixer as Mix
import qualified SDL.Font as SDLF
import qualified Play.Engine.MySDL.MySDL as MySDL
import Data.Maybe
import Control.Monad.Except
import Control.Lens
import System.Random
import Play.Engine
import qualified Play.Engine.Load as Load
import qualified Control.Monad.State as SM
import qualified Data.Map as M
import qualified Script
import qualified Play.Engine.Sprite as Spr
data State
= State
{ _bg :: Spr.Sprite
, _resources :: MySDL.Resources
, _script :: Script.Script
, _camera :: Int
, _isPause :: !Bool
, _pauseChanged :: !Bool
, _isMute :: !Bool
, _hudFont :: SDLF.Font
, _exit :: !Bool
}
makeFieldsNoPrefix ''State
wantedAssets :: [(String, MySDL.ResourceType FilePath)]
wantedAssets =
[ ("bg", MySDL.Texture "VNBG.png")
, ("unispace", MySDL.Font "unispace/unispace.ttf")
]
make :: Int -> Script.ScriptData -> Scene
make t sd = Load.mkState t (wantedAssets ++ Script.assets sd) (mkState $ Script.script sd)
mkState
:: (MySDL.Resources -> Script.Script)
-> MySDL.Resources -> Result Scene
mkState scrpt rs = do
state <- initState (scrpt rs) rs
pure $ mkScene
state
update
render
initState :: Script.Script -> MySDL.Resources -> Result State
initState scrpt rs = do
case (,) <$> M.lookup "bg" (MySDL.textures rs) <*> M.lookup "unispace" (MySDL.fonts rs) of
Nothing ->
throwError ["Texture not found: bg ot unispace"]
Just (bgt, font) -> do
pure $ State
{ _bg =
fromJust
$ Spr.make
$ Spr.MakeArgs
{ mkActionmap = ["normal"]
, mkAction = "normal"
, mkTexture = bgt
, mkSize = Point 800 1000
, mkMaxPos = 8
, mkSpeed = 8
}
, _resources = rs
, _script = scrpt
, _camera = 0
, _isPause = False
, _pauseChanged = False
, _isMute = False
, _hudFont = font
, _exit = False
}
update :: Input -> State -> Result (StackCommand, State)
update input st = do
_wSize <- _windowSize <$> SM.get
ismute <- _muteMusic <$> SM.get
let
state = set isMute ismute st
(acts, script') <- Script.update input Nothing mempty (state ^. script)
let
newState =
state'
& set script script'
& over camera
(\c ->
if
| c <= 0 && Script.shake acts -> 60
| c <= 0 -> 0
| otherwise -> c - 1
)
where
state' =
if Script.stopTheWorld acts
then
state
else
state
& over bg
( case Script.changeSprite acts of
Nothing -> Spr.update Nothing False
Just sp -> const sp
)
if
| keyReleased KeyP input && state ^. isPause -> do
pure (None, set pauseChanged True $ set isPause False state)
| keyReleased KeyP input && not (state ^. isPause) -> do
pure (None, set pauseChanged True $ set isPause True state)
| state ^. isPause -> do
pure (None, state)
| keyReleased KeyQuit input -> do
pure (None, set exit True state)
| state ^. exit -> do
pure (Done, state)
| otherwise ->
pure (Script.command acts, newState)
render :: SDL.Renderer -> State -> IO ()
render renderer state = do
cam' <- Point <$> randomRIO (-1, 1) <*> randomRIO (-1, 1) :: IO FPoint
let cam = addPoint $ fmap (floor . (*) (fromIntegral $ state ^. camera `div` 3)) cam'
Spr.render renderer cam (Point 0 0) (state ^. bg . size) 255 (state ^. bg)
when (state ^. isMute) $
renderText renderer (state ^. hudFont) (Point 40 30) "MUTED"
Script.render renderer cam (state ^. script)
renderText renderer (state ^. hudFont) (Point 900 30) "MUTED"
when (state ^. isPause) $ do
let rect = toRect (cam $ Point 342 375) (Point 85 35)
SDL.rendererDrawColor renderer SDL.$= V4 40 0 30 180
SDL.fillRect renderer (Just rect)
renderText renderer (state ^. hudFont) (Point 352 380) "PAUSE"
when (state ^. pauseChanged) $
if (state ^. isPause)
then
Mix.pauseMusic
else
Mix.resumeMusic
when (state ^. exit) $
Mix.haltMusic