haxparse-0.3.0.0: src/HaxParse/Output/Plain.hs
{-# OPTIONS_GHC -fno-warn-unused-do-bind #-}
module HaxParse.Output.Plain (
render
) where
import Control.Monad.Reader
import Data.ByteString.Lazy.UTF8 (toString)
import qualified Data.IntMap as I
import HaxParse.AST
import HaxParse.Options hiding (showRoom)
import qualified HaxParse.Options as O
import Prelude hiding (Left, Right)
import System.IO
import Text.Printf
type RenderState = ReaderT (Opts, I.IntMap Player) IO
render :: Opts -> Replay -> IO ()
render o re = do
hSetEncoding stdout utf8
printf "HBRP version %d.\n" (version re)
let fullSec = fromIntegral (frameCount re) / 60 :: Double
minutes = floor (fullSec / 60) :: Integer
seconds = fullSec - fromIntegral (minutes * 60)
printf "Length: %d frames (%d:%.3f).\n" (frameCount re) minutes seconds
printf "First frame: %d.\n" (firstFrame re)
when (O.showRoom o) $ showRoom $ room re
printf "The game is %sin progress.\n" $ if inProgress re then "" :: String
else "not "
when (showDiscs o) $ if null $ discs re
then putStrLn "Discs: none."
else putStrLn "Discs:" >> mapM_ showDisc (discs re)
when (showPlayers o) $ do putStrLn "Players:"
mapM_ showPlayer . I.toList $ players re
when (showEvents o) $ do putStrLn "Events:"
let filteredEvents = if null (eventTypes o)
then events re
else filter (\ev -> any ($ ev) (eventTypes o)) (events re)
forM_ filteredEvents $ \f -> runReaderT (showAction f) (o, players re)
showRoom :: Room -> IO ()
showRoom r = do
printf "Room name: %s.\n" (toString $ roomName r)
printf "The room is %slocked.\n" $ if locked r then "" :: String else "not "
printf "Score limit: %d.\nTime limit: %d min.\n" (scoreLimit r) (timeLimit r)
printf "Rules? %d.\n" (rules r)
printf "The kickoff has %sbeen taken%s.\n"
(if kickoffTaken r then "" :: String else "not ")
(if kickoffTaken r then " by " ++ show (kickoffSide r) else "")
uncurry (printf "The ball is at (%.3f,%.3f).\n") (ballCoords r)
printf "Score: Red %d - %d Blue.\n" (redScore r) (blueScore r)
printf "Current timer: %.3f%s.\n"
(timer r)
(if pauseTimer r > 0 then printf " (unpaused in %d sec)" (pauseTimer r)
else "" :: String)
showStadium $ stadium r
showStadium :: Stadium -> IO ()
showStadium s = printf "Current stadium: %s.\n" (show s)
showDisc :: Disc -> IO ()
showDisc = undefined
showPlayer :: (I.Key, Player) -> IO ()
showPlayer (k, p) = do
printf "#%d %s%s\n" k (toString $ name p) (if admin p then " (admin)" :: String else "")
unless (initial p) $ printf " This player joined the room during the replay.\n"
printf " Team: %s\n" (show $ team p)
printf " Number: %d\n" (number p)
printf " Avatar: %s\n" (toString $ avatar p)
printf " Input: %d\n" (input p)
printf " Banned: %s\n" (show $ autoKick p)
printf " Desynced: %s\n" (show $ desync p)
printf " Country: %s\n" (toString $ country p)
printf " Handicap: %d\n" (handicap p)
printf " Disc ID: %s\n" (if pDiscId p + 1 == 0 then "(none)" else show (pDiscId p))
showAction :: Action -> RenderState ()
showAction (Action p fc ev) = do
(o,ps) <- ask
e <- showEv ev (ps I.! p)
let prelude = case timeFormat o of
Frame -> printf "frame %05d" fc
Second -> printf "(%02d:%06.3f)" minutes seconds
Both -> printf "frame %05d (%02d:%06.3f)" fc minutes seconds
sec :: Double
sec = fromIntegral fc / 60
minutes :: Integer
minutes = floor (sec / 60)
seconds :: Double
seconds = sec - (fromIntegral minutes * 60)
liftIO $ printf "%s: %s\n" (prelude :: String) e
showEv :: Event -> Player -> RenderState String
showEv (PingBroadcast ps) _ = return $ printf "ping update: %s" $ show ps
showEv (Chat bs) p = return $ printf "%s: \"%s\"" (toString $ name p) (toString bs)
showEv StartMatch p = return $ printf "%s starts match" (toString $ name p)
showEv (DiscMove ds) p = return $ printf "%s %s" (toString $ name p) (showMoves ds)
showEv (NewPlayer _ n _ c) _ = return $ printf "new player joins: %s (from %s)" (toString n) (toString c)
showEv (ChangeAvatar s) p = return $ printf "%s changes avatar to \"%s\"" (toString $ name p) (toString s)
showEv (Departure d k b r) p = do ps <- asks snd
let n = toString . name $ ps I.! fromIntegral d
if b
then return $ printf "%s bans %s (%s)" n (toString $ name p) (maybe "no reason" toString r)
else if k
then return $ printf "%s kicks %s (%s)" n (toString $ name p) (maybe "no reason" toString r)
else return $ printf "%s leaves" n
showEv StopMatch p = return $ printf "%s stops match" (toString $ name p)
showEv (TeamChange m t) p = do ps <- asks snd
let n = toString . name $ ps I.! fromIntegral m
return $ printf "%s moves %s to %s" (toString $ name p) n (show t)
showEv x _ = error $ show x
showMoves :: Move -> String
showMoves Kick = "kicks"
showMoves Nop = "stops moving"
showMoves (Move ms) = printf "moves %s" $ join (map showDir ms)
showMoves (MoveKick ms) = printf "moves %s and kicks" $ join (map showDir ms)
showDir :: Direction -> String
showDir Left = "←"
showDir Up = "↑"
showDir Right = "→"
showDir Down = "↓"