--------------------------------------------------------------------------------
-- |
-- Module      :  Terminal.Game
-- Copyright   :  © 2017-2019 Francesco Ariis
-- License     :  GPLv3 (see LICENSE file)
--
-- Maintainer  :  Francesco Ariis <fa-ml@ariis.it>
-- Stability   :  provisional
-- Portability :  portable
--
-- Machinery and utilities for 2D terminal games.
--
-- New? Start from 'Game'.
--
--------------------------------------------------------------------------------

-- Basic col-on-black ASCII terminal, operations.
-- Only module to be imported.

-- todo a-t-g senza timer
-- todo test that handlers are closed in case of errr [test]
-- todo invert # invert (doppio) si elimina? [test] [design]
-- todo schermo piccolo, si centra verticalmente? [test]
-- todo metti in a-t-g [design] la formula «menu, poi fai questo, poi
--      ritorni, astrai questo pattern

-- todo timer in contrib o altro modulo?
-- todo qptain e jimreed, implement normal movement
-- todo [design] javascript backend
-- todo controlla caratteri strani su windows, prova con morganw e ibispi
-- todo boxratio, blitcenter e blit top left etc in ansi-terminal-game? [u:2]
-- todo autoresize terminal (or get-term-size?)
-- todo ranSelect :: [a] -> m a in a-t-g [design]
-- todo random shuffle in atg?
-- todo (da sm) sm any plans to expose more of these bits in a future
--      release, making ansi-terminal-game more of a full game engine ?
--      [suggestion]
-- todo (da sm) music [suggestion]
-- todo (da sm) I'm also wondering if I can adjust the frame rate during
--      play, to speed things up
-- todo (da sm) hot reload for game (see IHP web app) [suggestion]


module Terminal.Game ( -- * Running
                       FPS,
                       Event(..),
                       Game(..),
                       playGame,

                       -- * Game logic
                       -- | Some convenient function dealing with
                       -- Timers ('Timed') and 'Animation's.
                       --
                       -- Usage of these is not mandatory: 'Game' is
                       -- parametrised over any state @s@, you are free
                       -- to implement game logic as you prefer.

                       -- ** Timers/Animation

                       -- *** Timers
                       Timed,
                       creaTimer, creaBoolTimer,
                       creaTimerLoop, creaBoolTimerLoop,

                       -- *** Animations
                       Animation,
                       creaAnimation,
                       creaLoopAnimation,
                       creaStaticAnimation,

                       -- *** T/A interface
                       tick, ticks, reset, lapse,
                       fetchFrame, isExpired, getFrames,

                       -- ** Random numbers
                       StdGen,
                       getStdGen, mkStdGen,
                       getRandom, getRandomList,
                       Random,

                       -- * Drawing
                       -- | To get to the gist of drawing, check the
                       -- documentation for '%'.
                       --
                       -- Blitting on screen is double-buffered and diff'd
                       -- (at each frame, only cells with changed character
                       -- will be redrawn).

                       -- ** Plane
                       Plane,
                       Coords,
                       Row, Column,
                       Width, Height,
                       blankPlane,
                       stringPlane,
                       stringPlaneTrans,
                       makeTransparent,
                       makeOpaque,
                       paperPlane,
                       planeSize,

                       -- ** Draw
                       Draw,
                       (%), (&), (#),
                       subPlane,
                       mergePlanes,
                       cell, word, box, textBox, textBoxLiquid,
                       Color(..), ColorIntensity(..),
                       color, bold, invert,

                       -- *** Declarative drawing
                       (|||), (===), (***), hcat, vcat,

                       -- * Testing
                       testGame,
                       setupGame,
                       recordGame,
                       readRecord,
                       narrateGame,
                       playGameS,

                       -- * Utility
                       Terminal.Game.displaySize,
                       errorPress

                       -- * Cross platform
                       -- $threaded
                     )
    where

import System.Console.ANSI
import Terminal.Game.Animation
import Terminal.Game.Draw
import Terminal.Game.Layer.Imperative
import Terminal.Game.Layer.Object as O
import Terminal.Game.Plane
import Terminal.Game.Random

-- $threaded
-- Good practices for cross-compatibility:
--
-- * choose game dimensions of no more than __24 rows__ and __80 columns__.
--   This ensures compatibility with the trickiest terminals (i.e. Win32
--   console);
--
-- * use __ASCII characters__ only. Again this is for Win32 console
--   compatibility, until
--   [this GHC bug](https://gitlab.haskell.org/ghc/ghc/issues/7593) gets
--   fixed;
--
-- * employ colour sparingly: as some users will play your game in a
--   light-background terminal and some in a dark one, choose only colours
--   that go well with either (blue, red, etc.);
--
-- * some terminals/multiplexers (i.e. tmux) do not make a distinction
--   between vivid/dull; do not base your game mechanics on that
--   difference.

-- | /Usable/ terminal display size (on Win32 console the last line is
-- set aside for input).
displaySize :: IO (Width, Height)
displaySize :: IO (Width, Width)
displaySize = IO (Width, Width)
forall (m :: * -> *). MonadDisplay m => m (Width, Width)
O.displaySize