module Game.LambdaHack.Common.Time
( Time, timeZero, timeClip, timeTurn, timeEpsilon
, absoluteTimeAdd, absoluteTimeNegate, timeFit, timeFitUp
, Delta(..), timeShift, timeDeltaToFrom, timeDeltaReverse, timeDeltaScale
, timeDeltaToDigit, ticksPerMeter
, Speed, toSpeed, fromSpeed, speedZero, speedNormal
, speedScale, speedAdd, speedNegate
, speedFromWeight, rangeFromSpeed, rangeFromSpeedAndLinger
) where
import Data.Binary
import qualified Data.Char as Char
import Data.Int (Int64)
import Game.LambdaHack.Common.Misc
newtype Time = Time Int64
deriving (Show, Eq, Ord, Enum, Bounded, Binary)
newtype Delta a = Delta a
deriving (Show, Eq, Ord, Enum, Bounded, Binary, Functor)
timeZero :: Time
timeZero = Time 0
_timeTick :: Time
_timeTick = Time 1
timeEpsilon :: Time
timeEpsilon = _timeTick
timeClip :: Time
timeClip = Time 100000
timeTurn :: Time
timeTurn = Time 500000
turnsInSecond :: Int64
turnsInSecond = 2
_ticksInSecond :: Int64
_ticksInSecond =
let Time ticksInTurn = timeTurn
in ticksInTurn * turnsInSecond
absoluteTimeAdd :: Time -> Time -> Time
absoluteTimeAdd (Time t1) (Time t2) = Time (t1 + t2)
timeShift :: Time -> Delta Time -> Time
timeShift (Time t1) (Delta (Time t2)) = Time (t1 + t2)
timeFit :: Time -> Time -> Int
timeFit (Time t1) (Time t2) = fromIntegral $ t1 `div` t2
timeFitUp :: Time -> Time -> Int
timeFitUp (Time t1) (Time t2) = fromIntegral $ t1 `divUp` t2
timeDeltaReverse :: Delta Time -> Delta Time
timeDeltaReverse (Delta (Time t)) = Delta (Time (t))
absoluteTimeNegate :: Time -> Time
absoluteTimeNegate (Time t) = Time (t)
timeDeltaToFrom :: Time -> Time -> Delta Time
timeDeltaToFrom (Time t1) (Time t2) = Delta $ Time (t1 t2)
timeDeltaScale :: Delta Time -> Int -> Delta Time
timeDeltaScale (Delta (Time t)) s = Delta (Time (t * fromIntegral s))
timeDeltaToDigit :: Delta Time -> Delta Time -> Char
timeDeltaToDigit (Delta (Time maxT)) (Delta (Time t)) =
let k = 10 * t `div` maxT
digit | k > 9 = '*'
| k < 0 = '-'
| otherwise = Char.intToDigit $ fromIntegral k
in digit
newtype Speed = Speed Int64
deriving (Eq, Ord, Binary)
instance Show Speed where
show s = show $ fromSpeed s
sInMs :: Int64
sInMs = 1000000
toSpeed :: Int -> Speed
toSpeed s = Speed $ fromIntegral s * sInMs `div` 10
fromSpeed :: Speed -> Int
fromSpeed (Speed s) = fromIntegral $ s * 10 `div` sInMs
speedZero :: Speed
speedZero = Speed 0
speedNormal :: Speed
speedNormal = Speed $ 2 * sInMs
speedScale :: Rational -> Speed -> Speed
speedScale s (Speed v) = Speed (round $ fromIntegral v * s)
speedAdd :: Speed -> Speed -> Speed
speedAdd (Speed s1) (Speed s2) = Speed (s1 + s2)
speedNegate :: Speed -> Speed
speedNegate (Speed n) = Speed (n)
ticksPerMeter :: Speed -> Delta Time
ticksPerMeter (Speed v) = Delta $ Time $ _ticksInSecond * sInMs `divUp` max 1 v
speedFromWeight :: Int -> Int -> Speed
speedFromWeight weight velocityPercent =
let w = fromIntegral weight
vp = fromIntegral velocityPercent
mpMs | w <= 500 = sInMs * 16
| w > 500 && w <= 2000 = sInMs * 16 * 1500 `div` (w + 1000)
| w < 16000 = sInMs * (18000 w) `div` 1000
| w < 200000 = sInMs
| otherwise = 0
v = mpMs * vp `div` 100
multiple2M = sInMs * if v > 2 * sInMs
then 2 * (v `div` (2 * sInMs))
else v `div` sInMs
minimumSpeed = if mpMs == 0 then 0 else sInMs
in Speed $ max minimumSpeed multiple2M
rangeFromSpeed :: Speed -> Int
rangeFromSpeed (Speed v) = fromIntegral $ v `div` sInMs
rangeFromSpeedAndLinger :: Speed -> Int -> Int
rangeFromSpeedAndLinger speed linger =
let range = rangeFromSpeed speed
in linger * range `div` 100