diff --git a/Projectile/SWForward.hs b/Projectile/SWForward.hs
--- a/Projectile/SWForward.hs
+++ b/Projectile/SWForward.hs
@@ -78,7 +78,7 @@
                     Just x -> x in
     self { center = center'
          , idealNewCenter = Nothing
-         , radius = (radius self) + radiusGrowth * t
+         , radius = min 128.0 ((radius self) + radiusGrowth * t)
          }
 
 updateIdealTargetCenter :: Time -> SWForward -> SWForward
diff --git a/Projectile/SWSide.hs b/Projectile/SWSide.hs
--- a/Projectile/SWSide.hs
+++ b/Projectile/SWSide.hs
@@ -78,7 +78,7 @@
                     Just x -> x in
     self { center = center'
          , idealNewCenter = Nothing
-         , radius = (radius self) + radiusGrowth * t
+         , radius = min 128.0 ((radius self) + radiusGrowth * t)
          }
 
 updateIdealTargetCenter :: Time -> SWSide -> SWSide
diff --git a/Resources.hs b/Resources.hs
--- a/Resources.hs
+++ b/Resources.hs
@@ -17,6 +17,7 @@
 import qualified Unit.Smart.ATank as ATank
 import qualified Unit.Smart.STank as STank
 import qualified Unit.Smart.Death as Death
+import qualified Unit.Smart.Master as Master
 import qualified Unit.Smart.Ninja as Ninja
 import qualified Unit.Smart.Saucer as Saucer
 import qualified Unit.Smart.Sniper as Sniper
@@ -44,6 +45,8 @@
                                  , "item-sigma.bmp"
                                  , "lance.bmp"
                                  , "lance-thrusting.bmp"
+                                 , "master.bmp"
+                                 , "master-cloaking.bmp"
                                  , "mine.bmp"
                                  , "mine-explosion.bmp"
                                  , "mine-lit.bmp"
@@ -476,6 +479,62 @@
                                       , (-1700.0, 1100.0)
                                       ]
                 }
+              ,
+              -- 12
+              a { smartUnits = masterGen rt wmap
+                                 [ ((-600, 600.0), 0.0, 10.0)
+                                 , ((800, 600.0), 0.0, 16.0)
+                                 , ((-800, 1000.0), 0.0, 13.0)
+                                 , ((1200, 1000.0), 0.0, 18.0)
+                                 , ((1400, 1300.0), 0.0, 10.0)
+                                 , ((-300, 900.0), 0.0, 20.0)
+                                 , ((700, -900.0), 0.0, 12.0)
+                                 , ((-1499, -1499.0), 0.0, 10.0)
+                                 ]
+                , asteroids = asteroidGen rt wmap
+                                [ ((1000,  600), (100, -140))
+                                , ((-850,  1100), (100, -140))
+                                , ((200,  -900), (100, -140))
+                                ] ++
+                              bigAsteroidGen rt wmap
+                                [ ((-600,  1300), (100, -140))
+                                , ((1400,  -1000), (100, -140))
+                                ]
+                }
+              ,
+              -- 13
+              a { smartUnits = sTankGen rt wmap
+                                 [ ((0, -500.0), pi / 2)
+                                 , ((-200, -700.0), pi / 2)
+                                 , ((200, -700.0), pi / 2)
+                                 , ((-400, -900.0), pi / 2)
+                                 -- , ((0, -900.0), pi / 2)
+                                 , ((400, -900.0), pi / 2)
+                                 , ((-600, -1100.0), pi / 2)
+                                 -- , ((-200, -1100.0), pi / 2)
+                                 -- , ((200, -1100.0), pi / 2)
+                                 , ((600, -1100.0), pi / 2)
+                                 , ((-800, -1300.0), pi / 2)
+                                 , ((800, -1300.0), pi / 2)
+                                 ]
+                               -- sniperGen rt wmap
+                               --   [ ((-600.0, 1000.0), 0.0)
+                               --   , ((600.0, 1000.0), 0.0)
+                               --   ]
+                , simpleUnits = turretGen rt wmap
+                                  [ ((0.0, 1000.0), 0.0, pi / 2)
+                                  , ((-600.0, 1000.0), 0.0, - pi / 2)
+                                  , ((600.0, 1000.0), 0.0, - pi / 2)
+                                  ]
+                , asteroids = asteroidGen rt wmap
+                                [ ((1000,  600), (40, -40))
+                                , ((200,  -900), (-10, 30))
+                                ] ++
+                              bigAsteroidGen rt wmap
+                                [ ((-600,  1300), (60, -30))
+                                , ((1400,  -1000), (-20, 70))
+                                ]
+                }
               ]
      let addItems a = do (it1, it2) <- randomItemPair
                          x1 <- randomRIO (0, 2999)
@@ -542,4 +601,7 @@
 
 ninjaGen rt wmap =
   map (\(x, y) -> SmartUnit (Ninja.new rt wmap (wrappoint wmap x) y))
+
+masterGen rt wmap =
+  map (\(x, y, z) -> SmartUnit (Master.new rt wmap (wrappoint wmap x) y z))
 
diff --git a/Unit/Smart/Master.hs b/Unit/Smart/Master.hs
new file mode 100644
--- /dev/null
+++ b/Unit/Smart/Master.hs
@@ -0,0 +1,282 @@
+module Unit.Smart.Master ( Master(..)
+                        , new
+                        ) where
+
+import Data.WrapAround
+import Animation
+import Graphics.Gloss.Data.Picture
+import Graphics.Gloss.Data.Color
+import GHC.Float
+import Trigonometry
+import ResourceTracker
+import Updating
+import qualified Moving as M
+import Combat
+import qualified Projectile.Blade as P.Blade
+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/2 -- radians per second
+
+maxVelocityMag = 400.0
+
+kamikazeDamage = 8.0
+
+maxIntegrity = 3
+
+accelerationRate = 250.0
+
+adjAngle = pi / 8
+
+shotDelay = 4.0
+
+data Master = Master { angle :: Angle -- radians
+                     , velocity :: Velocity
+                     , center :: WrapPoint
+                     , idealTargetLocation :: Maybe WrapPoint
+                     , wrapMap :: WrapMap
+                     , launchTube :: [Projectile]
+                     , sinceLastShot :: Time
+                     , integrity :: Double
+                     , vision :: Maybe Arena
+                     , resourceTracker :: ResourceTracker
+                     , cloakClock :: Time
+                     , cloakPeriod :: Time
+
+                     -- Sound
+                     , queueShotSound :: Bool
+                     , shotSoundSource :: Maybe Source
+                     }
+
+instance Audible Master 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
+        -> WrapMap
+        -> WrapPoint
+        -> Angle
+        -> Time
+        -> Master
+new rt wmap center' angle' cloakPeriod' =
+  Master { center = center'
+        , angle = angle'
+        , idealTargetLocation = Nothing
+        , velocity = (0.0, 0.0)
+        , wrapMap = wmap
+        , launchTube = []
+        , sinceLastShot = 0.0
+        , integrity = maxIntegrity
+        , vision = Nothing
+        , resourceTracker = rt
+        , queueShotSound = False
+        , shotSoundSource = Nothing
+        , cloakClock = 0.0
+        , cloakPeriod = cloakPeriod'
+        }
+
+instance Observant Master where
+
+  updateVision self arena = self { vision = Just arena }
+
+updateCloakingData t self
+  = self { cloakClock = let a = cloakClock self + t in
+                        if a >= cloakPeriod self then 0.0 else a
+         }
+
+updateAngle t self
+ = case vision self of
+     Nothing -> self
+     Just a -> case lance a of
+                Nothing -> self
+                Just l -> let sDir = angle self in
+                          let sDir' = if sDir == 0.0 / 0.0
+                                        then 0.1
+                                        else sDir in
+                          let tDir = vectorDirection
+                                       (vectorRelation
+                                         (wrapMap self)
+                                         (center self)
+                                         (M.center l)) in
+                          let adj
+                                | tDir - sDir' > adjAngle = radialVelocity * t
+                                | tDir - sDir' < (-1) * adjAngle = (-radialVelocity) * t
+                                | otherwise = 0.0 in
+                          self { angle = angle self + adj }
+
+updateVelocity :: Time -> Master -> Master
+updateVelocity t self =
+  let thrustingVelocity = M.calcNewVelocity
+                              (velocity self)
+                              accelerationRate
+                              (angle self)
+                              maxVelocityMag
+                              t in
+  let velocity' = case vision self of
+                    Nothing -> velocity self
+                    Just a ->
+                      case lance a of
+                        Nothing -> velocity self
+                        Just l -> let sDir = angle self in
+                                  let sDir' = if sDir == 0.0 / 0.0
+                                                then 0.1
+                                                else sDir in
+                                  let tDir = vectorDirection
+                                               (vectorRelation
+                                                 (wrapMap self)
+                                                 (center self)
+                                                 (M.center l)) in
+                                  if abs (tDir - sDir') <= adjAngle
+                                    then thrustingVelocity
+                                    else velocity self in
+  self { velocity = velocity' }
+
+instance Animation Master where
+  image self _ = Rotate (radToDeg
+                          (double2Float
+                            (angle self)) * (-1) - 90)
+                              currentPic
+    where defaultPic = fromMaybe
+                 (Scale 0.20 0.20
+                    (Color white
+                    (Text "Error! Missing image!")))
+                  (getImage rt "master.bmp")
+          cloakingPic = fromMaybe Blank (getImage rt "master-cloaking.bmp")
+          rt = resourceTracker self
+          t = cloakClock self
+          p = cloakPeriod self
+          currentPic = if t < 0.3
+                         then cloakingPic
+                         else if t < p * 0.5 - 0.3
+                                then defaultPic
+                                else if t < p * 0.5
+                                        then cloakingPic
+                                        else Blank
+
+instance M.Locatable Master where
+  center = center
+
+instance M.Moving Master where
+  velocity = velocity
+
+instance M.Colliding Master where
+  collisionRadius _ = 40.0
+
+instance InternallyUpdating Master where
+
+  preUpdate self t = (updateFiringInformation t
+                        . updateIdealTargetLocation t
+                        . updateVelocity t
+                        . updateAngle t
+                        . updateCloakingData t) self
+
+  postUpdate self t =
+    let center' = fromMaybe (center self) (idealTargetLocation self) in
+    self { center = center'
+         , idealTargetLocation = Nothing
+         }
+
+updateFiringInformation t self =
+  let cloaked = cloakClock self >= cloakPeriod self * 0.5 in
+  let sinceLastShot' = sinceLastShot self + t in
+    if sinceLastShot' >= shotDelay
+      then self { sinceLastShot = 0.0
+                , launchTube = if cloaked
+                                 then launchTube self
+                                 else projectile : launchTube self
+                , queueShotSound = if cloaked then False else True
+                }
+      else self { sinceLastShot = sinceLastShot' }
+  where projectile = Projectile
+                       (P.Blade.new
+                         (wrapMap self)
+                         (resourceTracker self)
+                         pAngle
+                         (center self)
+                         (velocity self))
+        pSpeed = P.Blade.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))
+
+updateIdealTargetLocation :: Time -> Master -> Master
+updateIdealTargetLocation t self =
+  self { idealTargetLocation = Just (M.idealNewLocation (wrapMap self)
+                                                        (center self)
+                                                        (velocity self)
+                                                        t)
+        }
+
+instance Launcher Master where
+
+  deployProjectiles self = (launchTube self, self { launchTube = [] })
+
+instance Transient Master where
+
+  expired' self = if integrity self > 0.0
+                    then Nothing
+                    else Just [aeffect]
+    where aeffect = AfterEffect (SimpleExplosion.new (resourceTracker self)
+                                                     (wrapMap self)
+                                                     (center self)
+                                                     (velocity self))
+
+instance Damageable Master where
+
+  inflictDamage self d = 
+    let cloaked = cloakClock self >= cloakPeriod self * 0.5 in
+    if cloaked 
+      then self
+      else self { integrity = max 0.0 (integrity self - d) }
+
+instance Damaging Master where
+
+  damageEnergy self = 
+    let cloaked = cloakClock self >= cloakPeriod self * 0.5 in
+    if cloaked then 0.0 else kamikazeDamage
diff --git a/edge.cabal b/edge.cabal
--- a/edge.cabal
+++ b/edge.cabal
@@ -7,7 +7,7 @@
 -- The package version. See the Haskell package versioning policy
 -- (http://www.haskell.org/haskellwiki/Package_versioning_policy) for
 -- standards guiding when and how versions should be incremented.
-Version:             0.8.12.1
+Version:             0.8.14
 
 -- A short (one-line) description of the package.
 Synopsis:            Top view space combat arcade game
@@ -110,6 +110,7 @@
                      , Unit.Smart.ATank
                      , Unit.Smart.STank
                      , Unit.Smart.Death
+                     , Unit.Smart.Master
                      , Unit.Smart.Ninja
                      , Unit.Smart.Saucer
                      , Unit.Smart.Sniper
diff --git a/image/master-cloaking.bmp b/image/master-cloaking.bmp
new file mode 100644
Binary files /dev/null and b/image/master-cloaking.bmp differ
diff --git a/image/master.bmp b/image/master.bmp
new file mode 100644
Binary files /dev/null and b/image/master.bmp differ
