packages feed

edge-0.8.16: Projectile/Pellet.hs

module Projectile.Pellet ( Pellet(..)
                         , new
                         , range
                         ) 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 Common

velocityC = 600.0
rangeC = 300.0
punch = 0.3

range = rangeC

data Pellet =
  Pellet { velocity :: Velocity
         , center :: WrapPoint
         , rangeLeft :: Double
         , wrapMap :: WrapMap
         , idealNewCenter :: Maybe WrapPoint
         , impacted :: Bool
         }

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

instance Animation Pellet where

  image self t = Color (makeColor8 172 172 172 255) (Circle 1.0)

instance M.Colliding Pellet where

  collisionRadius b = 1.0

instance M.Moving Pellet where

  velocity b = Projectile.Pellet.velocity b

instance M.Locatable Pellet where

  center b = Projectile.Pellet.center b

instance SimpleTransient Pellet where

  expired b = rangeLeft b <= 0.0

instance InternallyUpdating Pellet where

  preUpdate self t = updateIdealTargetCenter t self

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

updateIdealTargetCenter :: Time -> Pellet -> Pellet
updateIdealTargetCenter t self =
  let newLoc = M.newLocation (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 Pellet where

  damageEnergy b = punch

instance Transient Pellet where

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

instance Damageable Pellet where

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