module AppData where #include "Utils.cpp" import qualified Graphics.UI.GLFW as GLFW import qualified Data.IORef as R import qualified Data.List as L import Data.Maybe (fromMaybe) import qualified Control.Monad.State as ST import qualified Gamgine.Utils as GU import qualified GameData.Data as GD import qualified GameData.Level as LV import qualified GameData.Entity as E import qualified Defaults as DF import qualified Gamgine.State.RenderState as RS import qualified Gamgine.State.State as S import qualified Gamgine.State.StateTree as SS import Gamgine.State.StateTree (enterWhen, leaveWhen, adjacents, StateTree(..), StateTransition(..)) import Gamgine.State.StateTreeZipper as SZ import qualified Gamgine.State.KeyInfo as KI import qualified Gamgine.State.MouseInfo as MI import qualified Gamgine.State.InputInfo as II import Gamgine.State.InputInfo (Modifier(..), InputState(..)) import qualified States.GameRunning as GR import qualified States.EditModeRunning as EM import qualified States.MovingEntity as ME import qualified States.CreatingPlatform as CP import qualified States.ResizingPlatform as RP import qualified States.DefiningAnimation as DA import qualified States.IntroRunning as IR IMPORT_LENS_AS_LE data AppData = AppData { window :: GLFW.Window, windowSize :: (Int, Int), frustumSize :: (Double, Double), orthoScale :: Double, renderRessources :: RS.Ressources, levelsLoadedFrom :: FilePath, saveLevelsTo :: FilePath, appMode :: AppMode, gameData :: GD.Data, stateTree :: SZ.Zipper GD.Data } LENS(window) LENS(windowSize) LENS(frustumSize) LENS(orthoScale) LENS(renderRessources) LENS(levelsLoadedFrom) LENS(saveLevelsTo) LENS(appMode) LENS(gameData) LENS(stateTree) newAppData :: GLFW.Window -> GD.Data -> FilePath -> FilePath -> AppMode -> AppData newAppData win gameData levelsLoadedFrom saveLevelsTo appMode = AppData { window = win, windowSize = (0,0), frustumSize = (0,0), orthoScale = DF.orthoScale, renderRessources = RS.emptyRessources, levelsLoadedFrom = levelsLoadedFrom, saveLevelsTo = saveLevelsTo, appMode = appMode, gameData = gameData, stateTree = SZ.zipper $ if appMode == EditMode then SS.root EM.mkEditModeRunningState [Branch {state = ME.mkMovingEntityState, enterWhen = ByMouseWithMod GLFW.MouseButton'1 Pressed Ctrl, leaveWhen = ByMouse GLFW.MouseButton'1 Released, adjacents = []}, Branch {state = RP.mkResizingPlatformState, enterWhen = ByMouseWithMod GLFW.MouseButton'1 Pressed Shift, leaveWhen = ByMouse GLFW.MouseButton'1 Released, adjacents = []}, Branch {state = CP.mkCreatingPlatformState, enterWhen = ByMouse GLFW.MouseButton'1 Pressed, leaveWhen = ByMouse GLFW.MouseButton'1 Released, adjacents = []}, Branch {state = DA.mkDefiningAnimationState, enterWhen = ByKey (GLFW.Key'U) Pressed, leaveWhen = ByKey (GLFW.Key'U) Pressed, adjacents = []}] else SS.root IR.mkIntroRunningState [Branch {state = GR.mkGameRunningState, enterWhen = ByKey (GLFW.Key'Space) Pressed, leaveWhen = NoTransition, adjacents = []}] } data AppMode = GameMode | EditMode deriving Eq type AppDataRef = R.IORef AppData type AppST = ST.StateT AppDataRef IO runAppST :: AppST a -> AppDataRef -> IO (a, AppDataRef) runAppST = ST.runStateT update :: AppData -> AppData update app = applyToState f app where f = S.update $ LE.getL currentStateL app render :: Double -> AppData -> IO AppData render nextFrameFraction app = applyToStateIO f app where f = (S.render $ LE.getL currentStateL app) rstate rstate = RS.RenderState nextFrameFraction (renderRessources app) (frustumSize app) handleKeyEvent :: KI.KeyInfo -> AppData -> AppData handleKeyEvent ki app = let (gdata', stree') = SZ.handleKeyEvent ki (gameData app) (stateTree app) in app {gameData = gdata', stateTree = stree'} handleMouseEvent :: MI.MouseInfo -> AppData -> AppData handleMouseEvent mi app = let (gdata', stree') = SZ.handleMouseEvent mi (gameData app) (stateTree app) in app {gameData = gdata', stateTree = stree'} handleMouseMoved :: II.MousePos -> AppData -> AppData handleMouseMoved mp app = applyToState f app where f = (S.mouseMoved $ LE.getL currentStateL app) mp applyToState :: (GD.Data -> (GD.Data, S.State GD.Data)) -> AppData -> AppData applyToState f app = LE.setL currentStateL state' $ app {gameData = gdata'} where (gdata', state') = f $ gameData app applyToStateIO :: (GD.Data -> IO (GD.Data, S.State GD.Data)) -> AppData -> IO AppData applyToStateIO f app = do (gdata', state') <- f $ gameData app return (LE.setL currentStateL state' $ app {gameData = gdata'}) currentStateL = LE.lens getCurrentState setCurrentState where getCurrentState = state . SZ.current . stateTree where state (SS.Branch s _ _ _) = s setCurrentState state = LE.modL stateTreeL $ SZ.replace state currentLevelL = GD.currentLevelL . gameDataL activeLayerL = LV.activeLayerL . currentLevelL inactiveLayers = LV.inactiveLayers . LE.getL currentLevelL