packages feed

edge-0.8: Projectile/BulletMI.hs

module Projectile.BulletMI ( BulletMI(..)
                            , new
                            ) where

import Combat
import Animation
import Updating
import Graphics.Gloss.Data.Picture
import Graphics.Gloss.Data.Color
import Data.WrapAround
import qualified Moving as M

velocityC = 400.0
rangeC = 500.0

data BulletMI =
  BulletMI { velocity :: (Double, Double)
            , center :: WrapPoint
            , rangeLeft :: Double
            , wrapMap :: WrapMap
            , idealNewCenter :: Maybe WrapPoint
            , impacted :: Bool
            , clock :: Double
            }

-- angle is radians
new :: WrapMap -> Double -> WrapPoint -> (Double, Double) -> BulletMI
new wmap angle center' (vpx, vpy) =
  let x = cos angle * velocityC in
  let y = sin angle * velocityC in
  BulletMI { velocity = (x + vpx, y + vpy)
            , center = center'
            , rangeLeft = rangeC
            , wrapMap = wmap
            , idealNewCenter = Nothing
            , impacted = False
            , clock = 0.0
            }

instance Animation BulletMI where

  image self t = let r = fromInteger (ceiling (clock self)) - clock self in
                           Color (c r)
                                   (Rotate 45.0
                                      (Circle 4.0))
    where c x | x < 0.10 = red
              | x < 0.20 = yellow
              | x < 0.30 = red
              | x < 0.40 = yellow
              | x < 0.50 = red
              | x < 0.60 = yellow
              | x < 0.70 = red
              | x < 0.80 = yellow
              | x < 0.90 = red
              | otherwise = yellow

instance M.Colliding BulletMI where

  collisionRadius b = 2.0

instance M.Moving BulletMI where

  velocity b = Projectile.BulletMI.velocity b

instance M.Locatable BulletMI where

  center b = Projectile.BulletMI.center b

instance SimpleTransient BulletMI where

  expired b = rangeLeft b <= 0.0

instance InternallyUpdating BulletMI where

  preUpdate self t = let s' = updateIdealTargetCenter t self in
                     s' { clock = clock self + t }

  postUpdate self t =
    let center' = case idealNewCenter self of
                    Nothing -> center self
                    Just x -> x in
    self { center = center'
         , idealNewCenter = Nothing
         }

updateIdealTargetCenter :: Double -> BulletMI -> BulletMI
updateIdealTargetCenter t self =
  let newLoc = M.idealNewLocation (wrapMap self)
                                  (center self)
                                  (velocity self)
                                   t in
  self { idealNewCenter = Just (newLoc)
       , rangeLeft = max 0.0 $ rangeLeft self - distance (wrapMap self)
                                                         (center self)
                                                         (newLoc)
       }

instance Damaging BulletMI where

  damageEnergy b = 2.0

instance Transient BulletMI where

  expired' self = if impacted self || rangeLeft self <= 0.0
                     then Just []
                     else Nothing

instance Damageable BulletMI where

  inflictDamage self d = if d > 0 then self { impacted = True }
                                  else self