{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Terminal.Game.Layer.Object.IO where
import Terminal.Game.Layer.Object.Interface
import Terminal.Game.Plane
import Terminal.Game.Utils
import qualified Control.Concurrent as CC
import qualified Control.Monad as CM
import qualified Control.Monad.Catch as MC
import qualified Control.Monad.Trans as T
import qualified Data.List.Split as LS
import qualified System.Clock as SC
import qualified System.Console.ANSI as CA
import qualified System.Console.Terminal.Size as TS
import qualified System.IO as SI
instance {-# OVERLAPS #-} (Monad m, T.MonadIO m) => MonadInput m where
startEvents :: TPS -> m InputHandle
startEvents TPS
tps = IO InputHandle -> m InputHandle
forall (m :: * -> *) a. MonadIO m => IO a -> m a
T.liftIO (IO InputHandle -> m InputHandle)
-> IO InputHandle -> m InputHandle
forall a b. (a -> b) -> a -> b
$ Maybe (MVar [Event]) -> TPS -> IO InputHandle
startIOInput Maybe (MVar [Event])
forall a. Maybe a
Nothing TPS
tps
pollEvents :: MVar [Event] -> m [Event]
pollEvents MVar [Event]
ve = IO [Event] -> m [Event]
forall (m :: * -> *) a. MonadIO m => IO a -> m a
T.liftIO (IO [Event] -> m [Event]) -> IO [Event] -> m [Event]
forall a b. (a -> b) -> a -> b
$ MVar [Event] -> [Event] -> IO [Event]
forall a. MVar a -> a -> IO a
CC.swapMVar MVar [Event]
ve []
stopEvents :: [ThreadId] -> m ()
stopEvents [ThreadId]
ts = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
T.liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ [ThreadId] -> IO ()
stopEventsIO [ThreadId]
ts
startIOInput :: Maybe (CC.MVar [Event]) -> TPS -> IO InputHandle
startIOInput :: Maybe (MVar [Event]) -> TPS -> IO InputHandle
startIOInput Maybe (MVar [Event])
mr TPS
tps =
Handle -> BufferMode -> IO ()
SI.hSetBuffering Handle
SI.stdin BufferMode
SI.NoBuffering IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
Handle -> BufferMode -> IO ()
SI.hSetBuffering Handle
SI.stdout BufferMode
SI.NoBuffering IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
Handle -> Bool -> IO ()
SI.hSetEcho Handle
SI.stdin Bool
False IO () -> IO (MVar [Event]) -> IO (MVar [Event])
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
[Event] -> IO (MVar [Event])
forall a. a -> IO (MVar a)
CC.newMVar [] IO (MVar [Event])
-> (MVar [Event] -> IO InputHandle) -> IO InputHandle
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \MVar [Event]
ve ->
TPS -> IO TPS
getTimeTick TPS
tps IO TPS -> (TPS -> IO InputHandle) -> IO InputHandle
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \TPS
it ->
IO () -> IO ThreadId
CC.forkIO (Maybe (MVar [Event]) -> MVar [Event] -> TPS -> TPS -> IO ()
addTick Maybe (MVar [Event])
mr MVar [Event]
ve TPS
tps TPS
it) IO ThreadId -> (ThreadId -> IO InputHandle) -> IO InputHandle
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \ThreadId
te ->
IO () -> IO ThreadId
CC.forkIO (Maybe (MVar [Event]) -> MVar [Event] -> IO ()
addKeypress Maybe (MVar [Event])
mr MVar [Event]
ve) IO ThreadId -> (ThreadId -> IO InputHandle) -> IO InputHandle
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \ThreadId
tk ->
InputHandle -> IO InputHandle
forall (m :: * -> *) a. Monad m => a -> m a
return (MVar [Event] -> [ThreadId] -> InputHandle
InputHandle MVar [Event]
ve [ThreadId
te, ThreadId
tk])
type Elapsed = Integer
getTimeTick :: TPS -> IO Elapsed
getTimeTick :: TPS -> IO TPS
getTimeTick TPS
tps =
IO TPS
forall (m :: * -> *). MonadTimer m => m TPS
getTime IO TPS -> (TPS -> IO TPS) -> IO TPS
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \TPS
tm ->
let ns :: TPS
ns = TPS
10 TPS -> TPS -> TPS
forall a b. (Num a, Integral b) => a -> b -> a
^ (TPS
9 :: Integer)
t1 :: TPS
t1 = TPS -> TPS -> TPS
forall a. Integral a => a -> a -> a
quot TPS
ns TPS
tps in
TPS -> IO TPS
forall (m :: * -> *) a. Monad m => a -> m a
return (TPS -> TPS -> TPS
forall a. Integral a => a -> a -> a
quot TPS
tm TPS
t1)
addTick :: Maybe (CC.MVar [Event]) -> CC.MVar [Event] ->
TPS -> Elapsed -> IO ()
addTick :: Maybe (MVar [Event]) -> MVar [Event] -> TPS -> TPS -> IO ()
addTick Maybe (MVar [Event])
mr MVar [Event]
ve TPS
tps TPS
el =
TPS -> IO TPS
getTimeTick TPS
tps IO TPS -> (TPS -> IO ()) -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \TPS
t ->
Int -> IO () -> IO ()
forall (m :: * -> *) a. Applicative m => Int -> m a -> m ()
CM.replicateM_ (TPS -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (TPS -> Int) -> TPS -> Int
forall a b. (a -> b) -> a -> b
$ TPS
tTPS -> TPS -> TPS
forall a. Num a => a -> a -> a
-TPS
el)
(Maybe (MVar [Event]) -> MVar [Event] -> Event -> IO ()
addEvent Maybe (MVar [Event])
mr MVar [Event]
ve Event
Tick) IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
TPS -> IO ()
forall (m :: * -> *). MonadTimer m => TPS -> m ()
sleepABit TPS
tps IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
Maybe (MVar [Event]) -> MVar [Event] -> TPS -> TPS -> IO ()
addTick Maybe (MVar [Event])
mr MVar [Event]
ve TPS
tps TPS
t
addKeypress :: Maybe (CC.MVar [Event]) -> CC.MVar [Event] -> IO ()
addKeypress :: Maybe (MVar [Event]) -> MVar [Event] -> IO ()
addKeypress Maybe (MVar [Event])
mr MVar [Event]
ve =
IO Char
inputCharTerminal IO Char -> (Char -> IO ()) -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Char
c ->
Maybe (MVar [Event]) -> MVar [Event] -> Event -> IO ()
addEvent Maybe (MVar [Event])
mr MVar [Event]
ve (Char -> Event
KeyPress Char
c) IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
Maybe (MVar [Event]) -> MVar [Event] -> IO ()
addKeypress Maybe (MVar [Event])
mr MVar [Event]
ve
addEvent :: Maybe (CC.MVar [Event]) -> CC.MVar [Event] -> Event -> IO ()
addEvent :: Maybe (MVar [Event]) -> MVar [Event] -> Event -> IO ()
addEvent Maybe (MVar [Event])
mr MVar [Event]
ve Event
e | (Just MVar [Event]
d) <- Maybe (MVar [Event])
mr = MVar [Event] -> IO ()
vf MVar [Event]
d IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> MVar [Event] -> IO ()
vf MVar [Event]
ve
| Bool
otherwise = MVar [Event] -> IO ()
vf MVar [Event]
ve
where
vf :: MVar [Event] -> IO ()
vf MVar [Event]
d = MVar [Event] -> ([Event] -> IO [Event]) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
CC.modifyMVar_ MVar [Event]
d ([Event] -> IO [Event]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Event] -> IO [Event])
-> ([Event] -> [Event]) -> [Event] -> IO [Event]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Event] -> [Event] -> [Event]
forall a. [a] -> [a] -> [a]
++[Event
e]))
stopEventsIO :: [CC.ThreadId] -> IO ()
stopEventsIO :: [ThreadId] -> IO ()
stopEventsIO [ThreadId]
ts = (ThreadId -> IO ()) -> [ThreadId] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ ThreadId -> IO ()
CC.killThread [ThreadId]
ts
instance {-# OVERLAPS #-} (Monad m, T.MonadIO m) => MonadTimer m where
getTime :: m TPS
getTime = IO TPS -> m TPS
forall (m :: * -> *) a. MonadIO m => IO a -> m a
T.liftIO (IO TPS -> m TPS) -> IO TPS -> m TPS
forall a b. (a -> b) -> a -> b
$ TimeSpec -> TPS
SC.toNanoSecs (TimeSpec -> TPS) -> IO TimeSpec -> IO TPS
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Clock -> IO TimeSpec
SC.getTime Clock
SC.Monotonic
sleepABit :: TPS -> m ()
sleepABit TPS
tps = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
T.liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$
Int -> IO ()
CC.threadDelay (TPS -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (TPS -> Int) -> TPS -> Int
forall a b. (a -> b) -> a -> b
$ TPS -> TPS -> TPS
forall a. Integral a => a -> a -> a
quot TPS
oneTickSec (TPS
tpsTPS -> TPS -> TPS
forall a. Num a => a -> a -> a
*TPS
10))
instance {-# OVERLAPS #-}
(Monad m, T.MonadIO m, MC.MonadMask m, MC.MonadThrow m) =>
MonadException m where
cleanUpErr :: m a -> m b -> m a
cleanUpErr m a
m m b
c = m a -> m b -> m a
forall (m :: * -> *) a b. MonadMask m => m a -> m b -> m a
MC.finally m a
m m b
c
throwExc :: ATGException -> m a
throwExc ATGException
t = ATGException -> m a
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
MC.throwM ATGException
t
instance {-# OVERLAPS #-} (Monad m, T.MonadIO m) =>
MonadLogic m where
checkQuit :: (s -> Bool) -> s -> m Bool
checkQuit s -> Bool
fb s
s = Bool -> m Bool
forall (m :: * -> *) a. Monad m => a -> m a
return (s -> Bool
fb s
s)
instance {-# OVERLAPS #-} (Monad m, T.MonadIO m) => MonadDisplay m where
setupDisplay :: m ()
setupDisplay = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
T.liftIO IO ()
initPart
clearDisplay :: m ()
clearDisplay = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
T.liftIO IO ()
clearScreen
displaySize :: m (Maybe Dimensions)
displaySize = IO (Maybe Dimensions) -> m (Maybe Dimensions)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
T.liftIO IO (Maybe Dimensions)
displaySizeIO
blitPlane :: Maybe Plane -> Plane -> m ()
blitPlane Maybe Plane
mp Plane
p = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
T.liftIO (Maybe Plane -> Plane -> IO ()
blitPlaneIO Maybe Plane
mp Plane
p)
shutdownDisplay :: m ()
shutdownDisplay = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
T.liftIO IO ()
cleanAndExit
displaySizeIO :: IO (Maybe Dimensions)
displaySizeIO :: IO (Maybe Dimensions)
displaySizeIO =
IO (Maybe (Window Int))
forall n. Integral n => IO (Maybe (Window n))
TS.size IO (Maybe (Window Int))
-> (Maybe (Window Int) -> IO (Maybe Dimensions))
-> IO (Maybe Dimensions)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Maybe (Window Int)
ts ->
IO Bool
isWin32Console IO Bool -> (Bool -> IO (Maybe Dimensions)) -> IO (Maybe Dimensions)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Bool
bw ->
Maybe Dimensions -> IO (Maybe Dimensions)
forall (m :: * -> *) a. Monad m => a -> m a
return ((Window Int -> Dimensions)
-> Maybe (Window Int) -> Maybe Dimensions
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Bool -> Window Int -> Dimensions
f Bool
bw) Maybe (Window Int)
ts)
where
f :: Bool -> TS.Window Int -> Dimensions
f :: Bool -> Window Int -> Dimensions
f Bool
wbw (TS.Window Int
h Int
w) =
let h' :: Int
h' | Bool
wbw = Int
h Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
| Bool
otherwise = Int
h
in (Int
w, Int
h')
blitPlaneIO :: Maybe Plane -> Plane -> IO ()
blitPlaneIO :: Maybe Plane -> Plane -> IO ()
blitPlaneIO Maybe Plane
mpo Plane
pn =
let
(Int
pw, Int
ph) = Plane -> Dimensions
planeSize Plane
pn
bp :: Plane
bp = Int -> Int -> Plane
blankPlane Int
pw Int
ph
po :: Plane
po = Plane -> Plane -> Dimensions -> Plane
pastePlane (Plane -> (Plane -> Plane) -> Maybe Plane -> Plane
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Plane
bp Plane -> Plane
forall a. a -> a
id Maybe Plane
mpo) Plane
bp (Int
1, Int
1)
in
let pn' :: Plane
pn' = Plane -> Plane -> Dimensions -> Plane
pastePlane Plane
pn Plane
bp (Int
1, Int
1)
in
[SGR] -> IO ()
CA.setSGR [SGR
CA.Reset] IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
Plane -> Plane -> IO ()
blitMap Plane
po Plane
pn'
initPart :: IO ()
initPart :: IO ()
initPart =
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
CM.unless Bool
CC.rtsSupportsBoundThreads
([Char] -> IO ()
forall a. HasCallStack => [Char] -> a
error [Char]
errMes) IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
IO ()
CA.hideCursor IO () -> IO TextEncoding -> IO TextEncoding
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
[Char] -> IO TextEncoding
SI.mkTextEncoding [Char]
"UTF-8//TRANSLIT" IO TextEncoding -> (TextEncoding -> IO ()) -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \TextEncoding
te ->
Handle -> TextEncoding -> IO ()
SI.hSetEncoding Handle
SI.stdout TextEncoding
te IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
IO ()
clearScreen
where
errMes :: [Char]
errMes = [[Char]] -> [Char]
unlines
[[Char]
"\nError: you *must* compile this program with -threaded!",
[Char]
"Just add",
[Char]
"",
[Char]
" ghc-options: -threaded",
[Char]
"",
[Char]
"in your .cabal file (executable section) and you will be fine!"]
clearScreen :: IO ()
clearScreen :: IO ()
clearScreen = Int -> Int -> IO ()
CA.setCursorPosition Int
0 Int
0 IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
[SGR] -> IO ()
CA.setSGR [SGR
CA.Reset] IO () -> IO Dimensions -> IO Dimensions
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
IO Dimensions
forall (m :: * -> *).
(MonadDisplay m, MonadException m) =>
m Dimensions
displaySizeErr IO Dimensions -> (Dimensions -> IO ()) -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \(Int
w, Int
h) ->
Int -> IO () -> IO ()
forall (m :: * -> *) a. Applicative m => Int -> m a -> m ()
CM.replicateM_ (Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ Int
wInt -> Int -> Int
forall a. Num a => a -> a -> a
*Int
h) (Char -> IO ()
putChar Char
' ')
cleanAndExit :: IO ()
cleanAndExit :: IO ()
cleanAndExit = [SGR] -> IO ()
CA.setSGR [SGR
CA.Reset] IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
IO ()
CA.clearScreen IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
Int -> Int -> IO ()
CA.setCursorPosition Int
0 Int
0 IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
IO ()
CA.showCursor
blitMap :: Plane -> Plane -> IO ()
blitMap :: Plane -> Plane -> IO ()
blitMap Plane
po Plane
pn =
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
CM.when (Plane -> Dimensions
planeSize Plane
po Dimensions -> Dimensions -> Bool
forall a. Eq a => a -> a -> Bool
/= Plane -> Dimensions
planeSize Plane
pn)
([Char] -> IO ()
forall a. HasCallStack => [Char] -> a
error [Char]
"blitMap: different plane sizes") IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
Int -> Int -> IO ()
CA.setCursorPosition Int
0 Int
0 IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
Dimensions -> [[Cell]] -> [[Cell]] -> IO ()
blitToTerminal (Int
0, Int
0) (Plane -> [[Cell]]
orderedCells Plane
po) (Plane -> [[Cell]]
orderedCells Plane
pn)
orderedCells :: Plane -> [[Cell]]
orderedCells :: Plane -> [[Cell]]
orderedCells Plane
p = Int -> [Cell] -> [[Cell]]
forall e. Int -> [e] -> [[e]]
LS.chunksOf (Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
w) [Cell]
cells
where
cells :: [Cell]
cells = ((Dimensions, Cell) -> Cell) -> [(Dimensions, Cell)] -> [Cell]
forall a b. (a -> b) -> [a] -> [b]
map (Dimensions, Cell) -> Cell
forall a b. (a, b) -> b
snd ([(Dimensions, Cell)] -> [Cell]) -> [(Dimensions, Cell)] -> [Cell]
forall a b. (a -> b) -> a -> b
$ Plane -> [(Dimensions, Cell)]
assocsPlane Plane
p
(Int
w, Int
_) = Plane -> Dimensions
planeSize Plane
p
blitToTerminal :: Coords -> [[Cell]] -> [[Cell]] -> IO ()
blitToTerminal :: Dimensions -> [[Cell]] -> [[Cell]] -> IO ()
blitToTerminal (Int
rr, Int
rc) [[Cell]]
ocs [[Cell]]
ncs = (Int -> [(Cell, Cell)] -> IO Int)
-> Int -> [[(Cell, Cell)]] -> IO ()
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m ()
CM.foldM_ Int -> [(Cell, Cell)] -> IO Int
blitLine Int
rr [[(Cell, Cell)]]
oldNew
where
oldNew :: [[(Cell, Cell)]]
oldNew :: [[(Cell, Cell)]]
oldNew = ([Cell] -> [Cell] -> [(Cell, Cell)])
-> [[Cell]] -> [[Cell]] -> [[(Cell, Cell)]]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith [Cell] -> [Cell] -> [(Cell, Cell)]
forall a b. [a] -> [b] -> [(a, b)]
zip [[Cell]]
ocs [[Cell]]
ncs
blitLine :: Row -> [(Cell, Cell)] -> IO Row
blitLine :: Int -> [(Cell, Cell)] -> IO Int
blitLine Int
pr [(Cell, Cell)]
ccs =
(Int -> (Cell, Cell) -> IO Int) -> Int -> [(Cell, Cell)] -> IO ()
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m ()
CM.foldM_ Int -> (Cell, Cell) -> IO Int
blitCell Int
0 [(Cell, Cell)]
ccs IO () -> IO Int -> IO Int
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
let wr :: Int
wr = Int
pr Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 in
Int -> Int -> IO ()
CA.setCursorPosition (Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
wr)
(Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
rc) IO () -> IO Int -> IO Int
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
Int -> IO Int
forall (m :: * -> *) a. Monad m => a -> m a
return Int
wr
blitCell :: Int -> (Cell, Cell) -> IO Int
blitCell :: Int -> (Cell, Cell) -> IO Int
blitCell Int
k (Cell
clo, Cell
cln)
| Cell
cln Cell -> Cell -> Bool
forall a. Eq a => a -> a -> Bool
== Cell
clo = Int -> IO Int
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
kInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)
| Bool
otherwise = Int -> IO Int
moveIf Int
k IO Int -> (Int -> IO Int) -> IO Int
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Int
k' ->
Cell -> IO ()
putCellStyle Cell
cln IO () -> IO Int -> IO Int
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
Int -> IO Int
forall (m :: * -> *) a. Monad m => a -> m a
return Int
k'
moveIf :: Int -> IO Int
moveIf :: Int -> IO Int
moveIf Int
k | Int
k Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = Int -> IO Int
forall (m :: * -> *) a. Monad m => a -> m a
return Int
k
| Bool
otherwise = Int -> IO ()
CA.cursorForward Int
k IO () -> IO Int -> IO Int
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
Int -> IO Int
forall (m :: * -> *) a. Monad m => a -> m a
return Int
0
putCellStyle :: Cell -> IO ()
putCellStyle :: Cell -> IO ()
putCellStyle Cell
c = [SGR] -> IO ()
CA.setSGR ([SGR
CA.Reset] [SGR] -> [SGR] -> [SGR]
forall a. [a] -> [a] -> [a]
++ [SGR]
sgrb [SGR] -> [SGR] -> [SGR]
forall a. [a] -> [a] -> [a]
++ [SGR]
sgrr [SGR] -> [SGR] -> [SGR]
forall a. [a] -> [a] -> [a]
++ [SGR]
sgrc) IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
Char -> IO ()
putChar (Cell -> Char
cellChar Cell
c)
where
sgrb :: [SGR]
sgrb | Cell -> Bool
isBold Cell
c = [ConsoleIntensity -> SGR
CA.SetConsoleIntensity ConsoleIntensity
CA.BoldIntensity]
| Bool
otherwise = []
sgrr :: [SGR]
sgrr | Cell -> Bool
isReversed Cell
c = [Bool -> SGR
CA.SetSwapForegroundBackground Bool
True]
| Bool
otherwise = []
sgrc :: [SGR]
sgrc | Just (Color
k, ColorIntensity
i) <- Cell -> Maybe (Color, ColorIntensity)
cellColor Cell
c = [ConsoleLayer -> ColorIntensity -> Color -> SGR
CA.SetColor ConsoleLayer
CA.Foreground ColorIntensity
i Color
k]
| Bool
otherwise = []
oneTickSec :: Integer
oneTickSec :: TPS
oneTickSec = TPS
10 TPS -> TPS -> TPS
forall a b. (Num a, Integral b) => a -> b -> a
^ (TPS
6 :: Integer)