packages feed

edge-0.8.8: Projectile/Interceptor.hs

module Projectile.Interceptor ( Interceptor(..)
                              , new
                              , speed
                              ) 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
import GHC.Float
import Common
import Trigonometry ( doubleRem
                    , radToDeg
                    )
import Data.Maybe
import ResourceTracker

velocityC = 900.0
rangeC = 1200.0

integrityMax = 60.0

punch = 4.0

radiusC = 12.0

speed = velocityC

data Interceptor =
  Interceptor { velocity :: Velocity
         , center :: WrapPoint
         , rangeLeft :: Double
         , wrapMap :: WrapMap
         , idealNewCenter :: Maybe WrapPoint
         , impacted :: Bool
         , clock :: Time
         , angle :: Angle
         , resourceTracker :: ResourceTracker
         }

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

instance Animation Interceptor where

  image self t = Rotate a cpic

    where rt = resourceTracker self
          defImage x = fromMaybe
                         (Color white
                           (Circle r))
                         (getImage rt x)
          p1 = defImage "interceptor-1.bmp"
          p2 = defImage "interceptor-2.bmp"
          p3 = defImage "interceptor-3.bmp"
          rem = clock self `doubleRem` 0.3
          cpic = if rem > 0.2
                   then p3
                   else if rem > 0.1
                          then p2
                          else p1
          a = radToDeg (double2Float (angle self)) * (-1) - 90
          r = double2Float radiusC
             
instance M.Colliding Interceptor where

  collisionRadius self = radiusC

instance M.Moving Interceptor where

  velocity self = Projectile.Interceptor.velocity self

instance M.Locatable Interceptor where

  center self = Projectile.Interceptor.center self

instance SimpleTransient Interceptor where

  expired self = impacted self || rangeLeft self <= 0.0

instance InternallyUpdating Interceptor 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 :: Time -> Interceptor -> Interceptor
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 Interceptor where

  damageEnergy self = punch

instance Transient Interceptor where

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

instance Damageable Interceptor where

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