packages feed

edge-0.8.2: Projectile/Cannon.hs

module Projectile.Cannon ( Cannon(..)
                            , 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
import GHC.Float
import Common

velocityC = 500.0
rangeC = 800.0

integrityMax = 60.0

punch = 4.0

radiusC = 12.0

data Cannon =
  Cannon { velocity :: Velocity
         , center :: WrapPoint
         , rangeLeft :: Double
         , wrapMap :: WrapMap
         , idealNewCenter :: Maybe WrapPoint
         , integrity :: Double
         , clock :: Time
         }

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

instance Animation Cannon where

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

instance M.Colliding Cannon where

  collisionRadius self = radiusC

instance M.Moving Cannon where

  velocity self = Projectile.Cannon.velocity self

instance M.Locatable Cannon where

  center self = Projectile.Cannon.center self

instance SimpleTransient Cannon where

  expired self = rangeLeft self <= 0.0 || integrity self <= 0.0

instance InternallyUpdating Cannon 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 -> Cannon -> Cannon
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 Cannon where

  damageEnergy self = punch

instance Transient Cannon where

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

instance Damageable Cannon where

  inflictDamage self d = self { integrity = integrity self - d }