immutaball-core-0.1.0.4.1: Immutaball/Share/Level/Attributes.hs
{-# OPTIONS_GHC -fno-warn-tabs #-} -- Support tab indentation better, for a better default of no warning if tabs are used: https://dmitryfrank.com/articles/indent_with_tabs_align_with_spaces .
-- Enable warnings:
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}
-- Game.hs.
{-# LANGUAGE Haskell2010 #-}
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
module Immutaball.Share.Level.Attributes
(
SolAttributes(..), saAttributes, saMessage, saSong, saShot, saGoal,
saTime, saTimeHs, saFastUnlockHs, saCoinHs, saVersionStr,
saVersionNum, saAuthor, saBonus,
mkSolAttributes
) where
import Prelude ()
import Immutaball.Prelude
import Data.Maybe
import Data.Function hiding (id, (.))
import Data.Word
import Foreign.C.Types
import Control.Lens
import Data.Array.IArray
import qualified Data.Map as M
import Immutaball.Share.Level.Base
import Immutaball.Share.Utils
data SolAttributes = SolAttributes {
-- | Level attributes.
_saAttributes :: M.Map String String,
-- | Level message.
_saMessage :: String,
-- | Level song / track.
_saSong :: String,
-- | Screenshot of the level.
_saShot :: String,
-- | Coins needed to unlock the goal.
_saGoal :: Integer,
-- | Time available in this level.
_saTime :: Integer,
-- | Hard, easy, medium. Best times.
_saTimeHs :: (Integer, Integer, Integer),
-- | Hard, easy, medium. Fast unlock (best times after unlocking goal).
_saFastUnlockHs :: (Integer, Integer, Integer),
-- | Hard, easy, medium. Most coins.
_saCoinHs :: (Integer, Integer, Integer),
_saVersionStr :: String,
_saVersionNum :: Integer,
_saAuthor :: String,
-- | Is this a bonus level?
_saBonus :: Bool
}
deriving (Eq, Ord, Show)
makeLenses ''SolAttributes
mkSolAttributes :: Sol -> SolAttributes
mkSolAttributes sol = fix $ \sa -> SolAttributes {
_saAttributes = M.fromList $ do
d <- elems (sol^.solDv)
(ki, vi) <- return (d^.dictAi, d^.dictAj)
let k = (\f -> fix f 0 "") $ \me idx reversed_ ->
let (cc :: CChar) = (sol^.solAv)!(ki+idx) in
let (cb :: Word8) = fromIntegral cc in
let (c :: Char) = asciiChar8 cb in
if' (cc == 0) (reverse reversed_) $
me (idx+1) (c:reversed_)
let v = (\f -> fix f 0 "") $ \me idx reversed_ ->
let (cc :: CChar) = (sol^.solAv)!(vi+idx) in
let (cb :: Word8) = fromIntegral cc in
let (c :: Char) = asciiChar8 cb in
if' (cc == 0) (reverse reversed_) $
me (idx+1) (c:reversed_)
let r = (k, v)
return r,
_saMessage = M.lookup "message" (sa^.saAttributes) & fromMaybe "",
_saSong = M.lookup "song" (sa^.saAttributes) & fromMaybe "",
_saShot = M.lookup "shot" (sa^.saAttributes) & fromMaybe "",
_saGoal = M.lookup "goal" (sa^.saAttributes) >>= parseInteger & fromMaybe 0,
_saTime = M.lookup "time" (sa^.saAttributes) >>= parseInteger & fromMaybe 0,
_saTimeHs =
let (hard, afterHard) = M.lookup "time_hs" (sa^.saAttributes) >>= parseIntegerMore & fromMaybe (sa^.saTime, "") in
let (medium, afterMedium) = parseIntegerMore afterHard & fromMaybe (sa^.saTime, "") in
let (easy, _afterEasy) = parseIntegerMore afterMedium & fromMaybe (sa^.saTime, "") in
(hard, medium, easy),
_saFastUnlockHs =
let (hard, afterHard) = M.lookup "goal_hs" (sa^.saAttributes) >>= parseIntegerMore & fromMaybe (sa^.saTime, "") in
let (medium, afterMedium) = parseIntegerMore afterHard & fromMaybe (sa^.saTime, "") in
let (easy, _afterEasy) = parseIntegerMore afterMedium & fromMaybe (sa^.saTime, "") in
(hard, medium, easy),
_saCoinHs =
let (hard, afterHard) = M.lookup "coin_hs" (sa^.saAttributes) >>= parseIntegerMore & fromMaybe (sa^.saGoal, "") in
let (medium, afterMedium) = parseIntegerMore afterHard & fromMaybe (sa^.saGoal, "") in
let (easy, _afterEasy) = parseIntegerMore afterMedium & fromMaybe (sa^.saGoal, "") in
(hard, medium, easy),
_saVersionStr = M.lookup "version" (sa^.saAttributes) & fromMaybe "",
_saVersionNum = let (versionNum, _afterVersionNum) = parseIntegerMore (sa^.saVersionStr) & fromMaybe (0, "") in versionNum,
_saAuthor = M.lookup "author" (sa^.saAttributes) & fromMaybe "",
_saBonus = (M.lookup "bonus" (sa^.saAttributes) >>= parseInteger & fromMaybe 0) /= 0
}
where
asciiChar8 :: Word8 -> Char
asciiChar8 = toEnum . fromEnum
parseInteger :: String -> Maybe Integer
parseInteger str = case (reads str :: [(Integer, String)]) of
([(val, "")]) -> Just val
_ -> Nothing
parseIntegerMore :: String -> Maybe (Integer, String)
parseIntegerMore str = case (reads str :: [(Integer, String)]) of
([(val, rest)]) -> Just (val, rest)
_ -> Nothing