edge-0.9.1.0: Unit/Smart/Death.hs
{-|
Module : Unit.Smart.Death
Description : Death boss unit
Copyright : (c) Christopher Howard, 2016
License : GPL-3
Maintainer : ch.howard@zoho.com
-}
module Unit.Smart.Death ( Death(..)
, new
) where
import Prelude (Maybe(..), max, (-), (*), pi, (/), (+), (++), map, Bool(..), (.), fst, (>=), (>), (<), otherwise, abs, Double, (<=))
import Sound.ALUT ( Source )
import Data.WrapAround ( WP, WM, vectorRelation )
import Animation ( Audible(..), Animation(..), termSndSrc, handSndSrc )
import Math
import ResourceTracker
import Updating
import qualified Moving as M ( Moving(..), Locatable(..), Colliding(..), newVelocity, newLocation )
import Combat
import qualified Projectile.BulletSII as P.BulletSII ( speed, new )
import qualified Projectile.BulletMII as P.BulletMII ( new )
import AfterEffect ( AfterEffect(AfterEffect) )
import qualified AfterEffect.SimpleExplosion as SimpleExplosion
( new )
import Universe ( Arena(lance) )
import qualified Universe as U ( Arena(wrapMap) )
import Common
radialVelocity = pi
maxVelocityMag = 200
kamikazeDamage = 100
maxIntegrity = 12
accelerationRate = 200
adjAngleC = pi / 8
shotDelay_sniper = 3
shotDelay_spread = 2
collisionR = 60
data Death = Death { angle :: Angle -- radians
, velocity :: Velocity
, center :: WP
, idealTargetLocation :: Maybe WP
, wmap :: WM
, launchTube :: [Projectile]
, sinceLastShot_sniper :: Time
, sinceLastShot_spread :: Time
, integrity :: Double
, vision :: Maybe Arena
, rt :: RT
, queueShotSnd :: Bool
, shotSndSrc :: Maybe Source
}
instance Audible Death 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 a b c d = Death { center = c
, angle = d
, idealTargetLocation = Nothing
, velocity = (0, 0)
, wmap = b
, launchTube = []
, sinceLastShot_sniper = 0
, sinceLastShot_spread = 0
, integrity = maxIntegrity
, vision = Nothing
, rt = a
, queueShotSnd = False
, shotSndSrc = Nothing
}
instance Observant Death where
updateVision s a = s { vision = Just a }
updateAngle t s
= case vision s of
Nothing -> s
Just a -> case lance a of
Nothing -> s
Just l -> let b = angle s in
let e = if isNan b then 0.1 else b in
let m = vectorDirection
(vectorRelation
(wmap s)
(center s)
(M.center l)) in
let adj
| m - e > adjAngleC = radialVelocity * t
| m - e < (-1) * adjAngleC = (-radialVelocity) * t
| otherwise = 0 in
s { angle = angle s + adj }
updateVelocity t s =
s { velocity = b }
where c = M.newVelocity
(velocity s) accelerationRate (angle s) maxVelocityMag t
b = case vision s of
Nothing -> velocity s
Just a ->
case lance a of
Nothing -> velocity s
Just l -> let d = angle s in
let e = if isNan d then 0.1 else d in
let m = vectorDirection
(vectorRelation
(wmap s)
(center s)
(M.center l)) in
if abs (m - e) <= adjAngleC then c else velocity s
instance Animation Death where
image s _ = protectedGetImage (rt s) "death.bmp"
instance M.Locatable Death where
center = center
instance M.Moving Death where
velocity = velocity
instance M.Colliding Death where
collisionRadius _ = collisionR
instance InternallyUpdating Death 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 =
fst ((handleSpreadFiring . handleSniperFiring) (s, t))
handleSniperFiring (self, t) =
let sinceLastShot_sniper' = sinceLastShot_sniper self + t in
if sinceLastShot_sniper' >= shotDelay_sniper
then (self { sinceLastShot_sniper = 0.0
, launchTube = projectile : launchTube self
, queueShotSnd = True
}, t)
else (self { sinceLastShot_sniper = sinceLastShot_sniper' }, t)
where projectile = Projectile
(P.BulletSII.new
(wmap self)
pAngle
(center self)
(velocity self))
pSpeed = P.BulletSII.speed
pAngle = 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))
handleSpreadFiring (self, t) =
let sinceLastShot_spread' = sinceLastShot_spread self + t in
if sinceLastShot_spread' >= shotDelay_spread
then (self { sinceLastShot_spread = 0.0
, launchTube = projectiles ++ launchTube self
, queueShotSnd = True
}, t)
else (self { sinceLastShot_spread = sinceLastShot_spread' }, t)
where projectiles = map projectile [ x * pi / 8.0 - pi / 4.0 | x <- [0..7] ]
projectile x = Projectile
(P.BulletMII.new
(wmap self)
(pAngle + x)
(center self)
(velocity self))
pAngle = case vision self of
Nothing -> angle self
Just arena ->
case lance arena of
Nothing -> angle self
Just l -> vectorDirection
(vectorRelation
(U.wrapMap arena)
(center self)
(M.center l))
instance Launcher Death where
deployProjectiles s = (launchTube s, s { launchTube = [] })
instance Transient Death 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 Death where
inflictDamage s d = s { integrity = max 0 (integrity s - d) }
instance Damaging Death where
damageEnergy _ = kamikazeDamage