{-# LANGUAGE QuasiQuotes, ScopedTypeVariables, TupleSections, FlexibleContexts #-}
-- Repa
import Data.Array.Repa (Z (..), (:.) (..))
import qualified Data.Array.Repa as R
import qualified Data.Array.Repa.Repr.Vector as R
-- Gloss
import Graphics.Gloss
import Graphics.Gloss.Raster.Array
import Graphics.Gloss.Interface.Pure.Game
-- JuicyPixels-repa
import qualified Codec.Picture.Repa as J
-- base
import Control.Monad
import System.Random
import Data.Maybe
-- friends
import World
import Step
import Draw
import Paths_falling_turnip
import Data.Word
main :: IO ()
main = do
tooltips <- mapM loadTooltip tooltipFiles
playArrayIO
(InWindow "Falling Turnip" (winX * round factor, winY * round factor) (pos, pos))
(round factor, round factor)
frameRate
(World { array = R.computeS $ R.fromFunction (Z :. resY :. resX) bareWorld
, currentElem = nothing
, currGravityMask = margMaskEven
, nextGravityMask = margMaskOdd
, mouseDown = False
, mousePos = (0,0)
, mousePrevPos = (0,0)
, tooltipLeft = blankTooltip
, tooltipRight = blankTooltip
})
( return . render)
((return .) . handleInput)
(stepWorld tooltips)
where frameRate = 30
pos = 300
bareWorld = const nothing
loadTooltip :: (Element, FilePath) -> IO (Element, R.Array R.V R.DIM2 Color)
loadTooltip (e, p) = getDataFileName p >>= \p' -> liftM ((e,) . either (error) fromJuicy) $ J.readImageRGBA p'
where toF :: Word8 -> Float
toF x = fromIntegral x / 255
fromJuicy :: J.Collapsable a (Word8, Word8, Word8, Word8) => J.Img a -> R.Array R.V R.DIM2 Color
fromJuicy = (R.computeS . flip . R.map (\(a,b,c,d) -> makeColor (toF b) (toF c) (toF d) (toF a) ) . J.collapseColorChannel)
flip = R.backpermute (Z :. 15 :. 160) (\(Z:. y :. x) -> Z :. (14 - y) :. x )
handleInput :: Event -> World -> World
handleInput e w = handleInput' (w {mousePrevPos = mousePos w})
where handleInput' world = case e of
EventKey (MouseButton LeftButton) Down _ (x,y) -> world { mouseDown = True, mousePos = (x/factor, y/factor - palletteH) }
EventKey (MouseButton LeftButton) Up _ (x,y) -> world { mouseDown = False, mousePos = (x/factor, y/factor - palletteH) }
EventKey (Char 'e') Down _ _ -> world { currentElem = steam_water }
EventKey (Char 'f') Down _ _ -> world { currentElem = fire }
EventKey (Char 'o') Down _ _ -> world { currentElem = oil }
EventKey (Char 'w') Down _ _ -> world { currentElem = water }
EventKey (Char 'l') Down _ _ -> world { currentElem = salt_water }
EventKey (Char 's') Down _ _ -> world { currentElem = sand }
EventKey (Char 'n') Down _ _ -> world { currentElem = salt }
EventKey (Char 't') Down _ _ -> world { currentElem = stone }
EventKey (Char 'r') Down _ _ -> world { currentElem = torch }
EventKey (Char 'a') Down _ _ -> world { currentElem = wall }
EventKey (Char 'p') Down _ _ -> world { currentElem = plant }
EventKey (Char 'u') Down _ _ -> world { currentElem = spout }
EventKey (Char 'm') Down _ _ -> world { currentElem = metal }
EventMotion (x,y) -> world { mousePos = (x/factor, y/factor - palletteH) }
_ -> world
blankTooltip :: R.Array R.V R.DIM2 Color
blankTooltip = R.computeS $ R.fromFunction (Z :. 15 :. 160) (const black)
handleUI :: [(Element, R.Array R.V R.DIM2 Color)] -> GlossCoord -> World -> World
handleUI t p w = let tooltip = fromMaybe blankTooltip $ flip lookup t $ elemOf p
in if mouseDown w then
w {currentElem = elemOf p, tooltipLeft = tooltip
, tooltipRight = tooltip }
else w { tooltipRight = tooltip }
stepWorld :: [(Element, R.Array R.V R.DIM2 Color)] -> Float -> World -> IO World
stepWorld tooltips time world
= let curr = mousePos world
world' = if outOfWorld curr then handleUI tooltips curr world else world { tooltipRight = blankTooltip }
in do int <- randomRIO (0,100)
stepped <- if mouseDown world
then liftM (step int $ currGravityMask world')
$ drawLine (mousePrevPos world') curr
(currentElem world') (array world')
else return $ step int (currGravityMask world')
$ array world'
array' <- R.computeP stepped
return $ world' { array = array'
, currGravityMask = nextGravityMask world'
, nextGravityMask = currGravityMask world' }