packages feed

edge-0.9.1.0: Unit/Smart/Tank.hs

{-|
Module      : Unit.Smart.Tank
Description : Basic tank
Copyright   : (c) Christopher Howard, 2016
License     : GPL-3
Maintainer  : ch.howard@zoho.com
-}

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

import Prelude ((.), Maybe(..), max, (-), pi, Bool(..), (/), Double)
import Data.WrapAround ( WP, WM )
import Sound.ALUT ( Source )

import Animation
import Math
import ResourceTracker
import Updating
import qualified Moving as M ( Moving(..), Locatable(..), Colliding(..), newVelocity, newLocation )
import Combat
import qualified Projectile.BulletSI as P.BulletSI ( prj )
import AfterEffect ( AfterEffect(AfterEffect) )
import qualified AfterEffect.SimpleExplosion as SimpleExplosion ( new )
import Universe ( Arena )
import qualified Universe as U ()
import Common
import UnitUtil
import Unit

radialVelocity = pi/6
maxVelocityMag = 40
kamikazeDamage = 10
maxIntegrity = 3
accelerationRate = 30
collisionR = 20

data Tank = Tank { angle :: Angle -- radians
                 , velocity :: Velocity
                 , center :: WP
                 , wmap :: WM
                 , launchTube :: [Projectile]
                 , sinceLastShot :: Time
                 , integrity :: Double
                 , vision :: Maybe Arena
                 , rt :: ResourceTracker
                 , queueShotSnd :: Bool
                 , shotSndSrc :: Maybe Source
                 }

instance Audible Tank where

  processAudio s a = handSndSrc s
                       queueShotSnd
                       shotSndSrc
                       (\a -> a { queueShotSnd = False })
                       rt
                       "energy-shot-02.wav"
                       (\a b -> a { shotSndSrc = Just b })
                       a (wmap s) (M.center)

  terminateAudio s = termSndSrc s shotSndSrc

new :: ResourceTracker
        -> WM
        -> WP
        -> Angle
        -> Tank
new a b c d =
  Tank { center = c
        , angle = d
        , velocity = (0.0, 0.0)
        , wmap = b
        , launchTube = []
        , sinceLastShot = 0.0
        , integrity = maxIntegrity
        , vision = Nothing
        , rt = a
        , queueShotSnd = False
        , shotSndSrc = Nothing
        }

instance Observant Tank where

  updateVision s a = s { vision = Just a }

updateAngle t s = adjAngle s t vision (\x y -> x { angle = y }) angle (pi / 6) radialVelocity

updateVelocity t s = s { velocity = M.newVelocity
                                      (velocity s)
                                      accelerationRate
                                      (angle s)
                                      maxVelocityMag
                                      t                               
                       }

instance Animation Tank where
  image s _ = reorient (angle s) (protectedGetImage (rt s) "tank.bmp")

instance M.Locatable Tank where
  center = center

instance M.Moving Tank where
  velocity = velocity

instance M.Colliding Tank where
  collisionRadius _ = collisionR

instance InternallyUpdating Tank where

  preUpdate s t = (updateFiringInformation t
                  . updateVelocity t
                  . updateAngle t) s

  postUpdate s t =
    s { center = M.newLocation (wmap s) (center s) (velocity s) t }

updateFiringInformation t s = firing s sinceLastShot 1.5
                                (\x y -> x { sinceLastShot = y })
                                (\x y -> x { launchTube = y })
                                (\x y -> x { queueShotSnd = y })
                                [p] t launchTube
  where p = P.BulletSI.prj s wmap (firingAngle s vision angle)

instance Launcher Tank where

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

instance Transient Tank where

  expired' s = if moreThanZero (integrity s) then Nothing else Just [a]
    where a = AfterEffect
                (SimpleExplosion.new (rt s)(wmap s) (center s) (velocity s))

instance Damageable Tank where

  inflictDamage s d = s { integrity = max 0 (integrity s - d) }

instance Damaging Tank where

  damageEnergy s = kamikazeDamage