packages feed

edge-0.8.18: Unit/Smart/Zeus.hs

module Unit.Smart.Zeus ( Zeus(..)
                       , new
                       ) where

import Data.WrapAround
import Animation
import Graphics.Gloss.Data.Picture
import Graphics.Gloss.Data.Color
import GHC.Float
import Math
import ResourceTracker
import Updating
import qualified Moving as M
import Combat
import qualified Projectile.Interceptor as P.Interceptor
import AfterEffect
import qualified AfterEffect.SimpleExplosion as SimpleExplosion
import Data.Maybe
import Universe hiding (wrapMap, resourceTracker)
import qualified Universe as U
import Sound.ALUT
import Common

radialVelocity = pi -- radians per second

kamikazeDamage = 8.0

maxIntegrity = 2

shotDelay = 6.0

collisionRadiusC = 23.0

data Zeus = Zeus { angle :: Angle -- radians
                         , center :: WP
                         , wrapMap :: WM
                         , launchTube :: [Projectile]
                         , sinceLastShot :: Time
                         , integrity :: Double
                         , vision :: Maybe Arena
                         , resourceTracker :: ResourceTracker
                         , shotDelayShift :: Time
        
                         -- Sound
                         , queueShotSound :: Bool
                         , shotSoundSource :: Maybe Source
                         }

instance Audible Zeus where

  processAudio self lcenter =
    do self' <- if isNothing (shotSoundSource self)
                  then initializeShotSoundSource self
                  else return self
       if not (queueShotSound self)
               then return self'
               else do let (x, y) = vectorRelation
                                      (wrapMap self)
                                      (lcenter)
                                      (center self)
                       let s = fromJust $ shotSoundSource self
                       sourcePosition s $= (Vertex3 (double2Float x)
                                                    (double2Float (-y))
                                                    0)
                       play [s]
                       return self' { queueShotSound = False }

  terminateAudio self =
    if isNothing (shotSoundSource self)
      then return self
      else do stop [fromJust (shotSoundSource self)]
              return self

initializeShotSoundSource self =
  do [source] <- genObjectNames 1
     buffer source $= getSound (resourceTracker self) "energy-shot-02.wav"
     sourceRelative source $= Listener
     referenceDistance source $= audioReferenceDistance
     rolloffFactor source $= audioRolloffFactor
     return self { shotSoundSource = Just source }

new :: ResourceTracker
        -> WM
        -> WP
        -> Angle
        -> Time
        -> Zeus
new rt wmap center' angle' shotDelayShift' =
  Zeus { center = center'
         , angle = angle'
         , wrapMap = wmap
         , launchTube = []
         , sinceLastShot = 0.0
         , integrity = maxIntegrity
         , vision = Nothing
         , resourceTracker = rt
         , shotDelayShift = shotDelayShift'

         , queueShotSound = False
         , shotSoundSource = Nothing
         }

instance Observant Zeus where

  updateVision self arena = self { vision = Just arena }

updateAngle t self =
  self { angle = case vision self of
                   Nothing -> angle self
                   Just arena ->
                     case lance arena of
                       Nothing -> angle self
                       Just l -> targetingA
                                   pSpeed
                                   (vectorRelation
                                     (U.wrapMap arena)
                                     (center self)
                                     (M.center l))
                                   (subV
                                     (M.velocity l)
                                     (M.velocity self))
       }
  where pSpeed = P.Interceptor.speed

instance Animation Zeus where
  image self _ = Pictures [ bpic, tpic' ]
    where bpic = fromMaybe
                  (Scale 0.20 0.20
                     (Color white
                     (Text "Error! Missing image!")))
                  (getImage rt "zeus-base.bmp")
          tpic = fromMaybe
                  (Scale 0.20 0.20
                     (Color white
                     (Text "Error! Missing image!")))
                  (getImage rt "zeus-cannon.bmp")
          tpic' = Rotate (double2Float
                          (radToDeg
                            (angle self)) * (-1) - 90) tpic
          rt = resourceTracker self

instance M.Locatable Zeus where
  center = center

instance M.Moving Zeus where
  velocity self = (0, 0)

instance M.Colliding Zeus where
  collisionRadius _ = collisionRadiusC

instance InternallyUpdating Zeus where

  preUpdate self t = (updateFiringInformation t
                      . updateAngle t) self

  postUpdate self t = self

updateFiringInformation t self =
  let sinceLastShot' = sinceLastShot self + t in
    if sinceLastShot' >= shotDelay + shotDelayShift self
      then self { sinceLastShot = 0.0
                , launchTube = launchTube self ++ [projectile]
                , queueShotSound = True
                }
      else self { sinceLastShot = sinceLastShot' }
  where projectile = Projectile ( P.Interceptor.new
                                (wrapMap self)
                                (resourceTracker self)
                                (angle self)
                                (center self)
                                (M.velocity self) )

instance Launcher Zeus where

  deployProjectiles self = (launchTube self, self { launchTube = [] })

instance Transient Zeus where

  expired' self = if integrity self > 0.0
                    then Nothing
                    else Just [aeffect]
    where aeffect = AfterEffect (SimpleExplosion.new (resourceTracker self)
                                                     (wrapMap self)
                                                     (center self)
                                                     (M.velocity self))

instance Damageable Zeus where

  inflictDamage self d = self { integrity = max 0.0 (integrity self - d) }

instance Damaging Zeus where

  damageEnergy self = kamikazeDamage