--------------------------------------------------------------------------------
-- |
-- 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 la formula «menu, poi fai questo, poi
-- ritorni, astrai questo pattern [menu]
-- todo timer in contrib o altro modulo?
-- todo controlla caratteri strani su windows, prova con morganw e ibispi
-- todo boxratio, 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]
-- todo (da sm) sound with sox
-- todo (da sm) add tick counter
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,
planePaper,
planeSize,
-- ** Draw
Draw,
(%), (&), (#),
subPlane,
mergePlanes,
cell, word, box,
Color(..), ColorIntensity(..),
color, bold, invert,
-- *** Text boxes
textBox, textBoxLiquid,
textBoxHyphen, textBoxHyphenLiquid,
Hyphenator,
-- | Eurocentric convenience reexports. Check
-- "Text.Hyphenation.Language" for more languages.
english_GB, english_US, esperanto,
french, german_1996, italian, spanish,
-- *** Declarative drawing
(|||), (===), (***), hcat, vcat,
-- * Testing
testGame,
setupGame,
recordGame,
readRecord,
narrateGame,
playGameS,
-- * Utility
Terminal.Game.displaySize,
errorPress,
ATGException(..)
-- * 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
import Text.LineBreak
-- $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). Throws 'CannotGetDisplaySize' on error.
displaySize :: IO (Width, Height)
displaySize = O.displaySizeErr