Merge branch 'master' of ssh://git.xkjq.uk:30001/justin/loop
This commit is contained in:
+14
-7
@@ -19,7 +19,8 @@ import Picture.Render
|
|||||||
import Picture.Preload
|
import Picture.Preload
|
||||||
import Sound
|
import Sound
|
||||||
import Preload
|
import Preload
|
||||||
import Sound.Preload
|
import Sound.Data
|
||||||
|
import Music
|
||||||
|
|
||||||
import Control.Concurrent
|
import Control.Concurrent
|
||||||
import Control.Lens
|
import Control.Lens
|
||||||
@@ -27,22 +28,28 @@ import Foreign (Word32)
|
|||||||
|
|
||||||
import Control.Monad (when,void)
|
import Control.Monad (when,void)
|
||||||
|
|
||||||
import System.Random
|
|
||||||
|
|
||||||
import System.Random
|
|
||||||
|
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
import Graphics.Rendering.OpenGL hiding (color, rotate, scale,
|
import Graphics.Rendering.OpenGL hiding (color, rotate, scale,
|
||||||
translate)
|
translate)
|
||||||
|
import qualified Data.Map as M
|
||||||
|
import qualified Data.IntMap as IM
|
||||||
import qualified SDL
|
import qualified SDL
|
||||||
import qualified SDL.Mixer as Mix
|
import qualified SDL.Mixer as Mix
|
||||||
|
|
||||||
doPreload' :: IO (PreloadData a)
|
doPreload' :: IO (PreloadData a)
|
||||||
doPreload' = do
|
doPreload' = do
|
||||||
lChunks <- loadSounds
|
lChunks <- loadSounds
|
||||||
|
lMusic <- loadMusic
|
||||||
let sData = SoundData {_loadedChunks = lChunks, _playingSounds = M.empty}
|
let sData = SoundData {_loadedChunks = lChunks, _playingSounds = M.empty}
|
||||||
|
mData = MusicData {_loadedMusic = lMusic}
|
||||||
|
Mix.playMusic Mix.Forever (lMusic IM.! 0)
|
||||||
rData <- preloadRender
|
rData <- preloadRender
|
||||||
return $ PreloadData rData sData 0
|
return $ PreloadData
|
||||||
|
{ _renderData = rData
|
||||||
|
, _soundData = sData
|
||||||
|
, _musicData = mData
|
||||||
|
, _frameTimer = 0
|
||||||
|
}
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
@@ -56,7 +63,7 @@ main = do
|
|||||||
( \preData w -> do
|
( \preData w -> do
|
||||||
startTicks <- SDL.ticks
|
startTicks <- SDL.ticks
|
||||||
void $ doDrawing (_renderData preData) w
|
void $ doDrawing (_renderData preData) w
|
||||||
playSoundQueue (_loadedChunks $ _soundData preData) (_soundQueue w)
|
playPositionalSoundQueue (_loadedChunks $ _soundData preData) (_soundQueue w)
|
||||||
newPlayingSounds <- playAndUpdate (_soundData preData) (_sounds w)
|
newPlayingSounds <- playAndUpdate (_soundData preData) (_sounds w)
|
||||||
|
|
||||||
endTicks <- SDL.ticks
|
endTicks <- SDL.ticks
|
||||||
|
|||||||
Binary file not shown.
@@ -35,8 +35,11 @@ updateLamp :: Int -> CRUpdate
|
|||||||
updateLamp i = unrandUpdate handleLS internalUpdate
|
updateLamp i = unrandUpdate handleLS internalUpdate
|
||||||
where
|
where
|
||||||
handleLS cr w
|
handleLS cr w
|
||||||
| _crHP cr < 0 = explosionFlashAt (_crPos cr) $ mkSoundBreakGlass w & lightSources %~ IM.delete i
|
| _crHP cr < 0 = explosionFlashAt cPos
|
||||||
| otherwise = w & lightSources . ix i . lsPos .~ _crPos cr
|
$ mkSoundBreakGlass cPos w & lightSources %~ IM.delete i
|
||||||
|
| otherwise = w & lightSources . ix i . lsPos .~ cPos
|
||||||
|
where
|
||||||
|
cPos = _crPos cr
|
||||||
internalUpdate cr
|
internalUpdate cr
|
||||||
| _crHP cr < 0 = Nothing
|
| _crHP cr < 0 = Nothing
|
||||||
| otherwise = Just $ doDamage cr
|
| otherwise = Just $ doDamage cr
|
||||||
|
|||||||
+4
-2
@@ -10,7 +10,7 @@ module Dodge.Data
|
|||||||
where
|
where
|
||||||
import Picture.Data
|
import Picture.Data
|
||||||
import Geometry.Data
|
import Geometry.Data
|
||||||
import Sound.Preload
|
import Sound.Data
|
||||||
import Control.Lens
|
import Control.Lens
|
||||||
import Control.Monad.State
|
import Control.Monad.State
|
||||||
import System.Random
|
import System.Random
|
||||||
@@ -25,6 +25,8 @@ import Codec.Picture (Image,PixelRGBA8)
|
|||||||
import qualified Data.DList as DL
|
import qualified Data.DList as DL
|
||||||
import Dodge.LoadConfig
|
import Dodge.LoadConfig
|
||||||
|
|
||||||
|
import Data.Int (Int16)
|
||||||
|
|
||||||
data World = World
|
data World = World
|
||||||
{ _keys :: !(S.Set Scancode)
|
{ _keys :: !(S.Set Scancode)
|
||||||
, _mouseButtons :: !(S.Set MouseButton)
|
, _mouseButtons :: !(S.Set MouseButton)
|
||||||
@@ -50,7 +52,7 @@ data World = World
|
|||||||
, _worldEvents :: !(World -> World)
|
, _worldEvents :: !(World -> World)
|
||||||
, _pressPlates :: IM.IntMap PressPlate
|
, _pressPlates :: IM.IntMap PressPlate
|
||||||
, _buttons :: IM.IntMap Button
|
, _buttons :: IM.IntMap Button
|
||||||
, _soundQueue :: [Int]
|
, _soundQueue :: [(Int,Int16)]
|
||||||
, _sounds :: M.Map SoundOrigin Sound
|
, _sounds :: M.Map SoundOrigin Sound
|
||||||
, _decorations :: IM.IntMap Picture
|
, _decorations :: IM.IntMap Picture
|
||||||
, _corpses :: IM.IntMap (IM.IntMap [Corpse])
|
, _corpses :: IM.IntMap (IM.IntMap [Corpse])
|
||||||
|
|||||||
@@ -810,7 +810,7 @@ moveShell time i cid rot accel w
|
|||||||
$ set (projectiles . ix i . pjUpdate)
|
$ set (projectiles . ix i . pjUpdate)
|
||||||
(moveShell (time-1) i cid rot (rotateV rot accel))
|
(moveShell (time-1) i cid rot (rotateV rot accel))
|
||||||
$ over (projectiles . ix i . pjVel) (\v -> accel +.+ frict *.* v)
|
$ over (projectiles . ix i . pjVel) (\v -> accel +.+ frict *.* v)
|
||||||
$ soundFrom (ShellSound i) (fromIntegral smokeTrailSound) (1) 250
|
$ soundFromPos (ShellSound i) newPos (fromIntegral smokeTrailSound) (1) 250
|
||||||
$ makeFlameletTimed oldPos
|
$ makeFlameletTimed oldPos
|
||||||
(0.5 *.* rotateV (pi+sparkD) accel) Nothing 3 10
|
(0.5 *.* rotateV (pi+sparkD) accel) Nothing 3 10
|
||||||
$ smokeGen
|
$ smokeGen
|
||||||
@@ -879,8 +879,7 @@ tractorBeamAt colID i pos dir = Projectile
|
|||||||
|
|
||||||
aGasCloud :: Int -> World -> World
|
aGasCloud :: Int -> World -> World
|
||||||
aGasCloud cid w
|
aGasCloud cid w
|
||||||
= -- soundFrom Flame fireSound 2 500
|
= insertCloud $ set randGen g $
|
||||||
insertCloud $ set randGen g $
|
|
||||||
w
|
w
|
||||||
where
|
where
|
||||||
(a,g) = randomR (-0.1,0.1) (_randGen w)
|
(a,g) = randomR (-0.1,0.1) (_randGen w)
|
||||||
@@ -896,7 +895,6 @@ aGasCloud cid w
|
|||||||
aFlame :: Float -> Int -> World -> World
|
aFlame :: Float -> Int -> World -> World
|
||||||
aFlame a cid w
|
aFlame a cid w
|
||||||
= shakeCr cid 2
|
= shakeCr cid 2
|
||||||
-- $ soundFrom Flame fireSound 2 500
|
|
||||||
$ insertFlame $ resetAngle $ set randGen g $
|
$ insertFlame $ resetAngle $ set randGen g $
|
||||||
w
|
w
|
||||||
where
|
where
|
||||||
@@ -1381,7 +1379,7 @@ moveRemoteShell time i cid itid dir w
|
|||||||
$ set (projectiles . ix i . pjUpdate)
|
$ set (projectiles . ix i . pjUpdate)
|
||||||
(moveRemoteShell (time-1) i cid itid newdir)
|
(moveRemoteShell (time-1) i cid itid newdir)
|
||||||
$ over (projectiles . ix i . pjVel) (\v -> accel +.+ frict *.* v)
|
$ over (projectiles . ix i . pjVel) (\v -> accel +.+ frict *.* v)
|
||||||
$ soundFrom (ShellSound i) (fromIntegral smokeTrailSound) (1) 250
|
$ soundFromPos (ShellSound i) newPos (fromIntegral smokeTrailSound) (1) 250
|
||||||
$ smokeGen
|
$ smokeGen
|
||||||
$ makeFlameletTimed oldPos
|
$ makeFlameletTimed oldPos
|
||||||
(0.5 *.* rotateV (pi+sparkD) accel) Nothing 3 10
|
(0.5 *.* rotateV (pi+sparkD) accel) Nothing 3 10
|
||||||
|
|||||||
@@ -43,9 +43,9 @@ withWarmUp t f cid w
|
|||||||
| fState == 0 = set (pointerToItem . wpFire) (withWarmUp 100 f)
|
| fState == 0 = set (pointerToItem . wpFire) (withWarmUp 100 f)
|
||||||
$ set (pointerToItem . wpFireState) 2
|
$ set (pointerToItem . wpFireState) 2
|
||||||
w
|
w
|
||||||
| t > 1 = set (pointerToItem . wpFire) (withWarmUp (t-1) f)
|
| t > 2 = set (pointerToItem . wpFire) (withWarmUp (t-1) f)
|
||||||
$ set (pointerToItem . wpFireState) 2
|
$ set (pointerToItem . wpFireState) 2
|
||||||
$ soundFrom (CrWeaponSound cid) 26 1 0
|
$ soundFrom (CrWeaponSound cid) 26 2 0
|
||||||
w
|
w
|
||||||
| t > 0 = set (pointerToItem . wpFire) (withWarmUp (t-1) f)
|
| t > 0 = set (pointerToItem . wpFire) (withWarmUp (t-1) f)
|
||||||
$ set (pointerToItem . wpFireState) 2
|
$ set (pointerToItem . wpFireState) 2
|
||||||
@@ -56,7 +56,8 @@ withWarmUp t f cid w
|
|||||||
$ f cid
|
$ f cid
|
||||||
$ soundFrom (CrWeaponSound cid) 28 2 0
|
$ soundFrom (CrWeaponSound cid) 28 2 0
|
||||||
w
|
w
|
||||||
where cr = _creatures w IM.! cid
|
where
|
||||||
|
cr = _creatures w IM.! cid
|
||||||
itRef = _crInvSel cr
|
itRef = _crInvSel cr
|
||||||
item = _crInv cr IM.! itRef
|
item = _crInv cr IM.! itRef
|
||||||
pointerToItem = creatures . ix cid . crInv . ix itRef
|
pointerToItem = creatures . ix cid . crInv . ix itRef
|
||||||
@@ -65,7 +66,9 @@ withWarmUp t f cid w
|
|||||||
reloadCondition = _wpLoadedAmmo item == 0
|
reloadCondition = _wpLoadedAmmo item == 0
|
||||||
|
|
||||||
withSound :: Int -> (Int -> World -> World) -> Int -> World -> World
|
withSound :: Int -> (Int -> World -> World) -> Int -> World -> World
|
||||||
withSound soundid f cid = soundOnce soundid . f cid
|
withSound soundid f cid w = (soundOncePos soundid p . f cid) w
|
||||||
|
where
|
||||||
|
p = _crPos (_creatures w IM.! cid)
|
||||||
|
|
||||||
withRecoil :: Float -> (Int -> World -> World) -> Int -> World -> World
|
withRecoil :: Float -> (Int -> World -> World) -> Int -> World -> World
|
||||||
withRecoil recoilAmount eff cid w = eff cid . over (creatures . ix cid) pushback $ w
|
withRecoil recoilAmount eff cid w = eff cid . over (creatures . ix cid) pushback $ w
|
||||||
|
|||||||
@@ -42,11 +42,10 @@ killBlock bl w = f bl .
|
|||||||
where
|
where
|
||||||
f bl@(Block {_blDegrades = (x:xs)}) = degradeBlock bl . hitSound bl
|
f bl@(Block {_blDegrades = (x:xs)}) = degradeBlock bl . hitSound bl
|
||||||
f bl = hitSound' bl
|
f bl = hitSound' bl
|
||||||
hitSound bl | _wlIsSeeThrough bl = mkSoundBreakGlass
|
pos = _wlLine bl !! 0
|
||||||
-- hitSound bl | _wlIsSeeThrough bl = soundMultiFrom sos (soundid+8) 25 0
|
hitSound bl | _wlIsSeeThrough bl = mkSoundBreakGlass pos
|
||||||
| otherwise = soundMultiFrom sos soundid 25 0
|
| otherwise = soundMultiFrom sos soundid 25 0
|
||||||
hitSound' bl | _wlIsSeeThrough bl = mkSoundSplinterGlass
|
hitSound' bl | _wlIsSeeThrough bl = mkSoundSplinterGlass pos
|
||||||
-- hitSound' bl | _wlIsSeeThrough bl = soundMultiFrom sos (soundid+4) 25 0
|
|
||||||
| otherwise = soundMultiFrom sos soundid 25 0
|
| otherwise = soundMultiFrom sos soundid 25 0
|
||||||
sos = [BlockDegradeSound 0,BlockDegradeSound 1]
|
sos = [BlockDegradeSound 0,BlockDegradeSound 1]
|
||||||
(soundid,_) = randomR (29,32) $ _randGen w
|
(soundid,_) = randomR (29,32) $ _randGen w
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import qualified SDL.Mixer as Mix
|
|||||||
-- }}}
|
-- }}}
|
||||||
loadSounds :: IO (IM.IntMap Mix.Chunk)
|
loadSounds :: IO (IM.IntMap Mix.Chunk)
|
||||||
loadSounds = do
|
loadSounds = do
|
||||||
Mix.openAudio Mix.defaultAudio 256
|
Mix.openAudio Mix.defaultAudio 128
|
||||||
pFireSound <- Mix.load "./data/sound/tap3.wav"
|
pFireSound <- Mix.load "./data/sound/tap3.wav"
|
||||||
click <- Mix.load "./data/sound/click1.wav"
|
click <- Mix.load "./data/sound/click1.wav"
|
||||||
reloadSound' <- Mix.load "./data/sound/reload1.wav"
|
reloadSound' <- Mix.load "./data/sound/reload1.wav"
|
||||||
@@ -57,8 +57,8 @@ loadSounds = do
|
|||||||
glass3' <- Mix.load "./data/sound/Small-Piece-Of-Glass-Shattering-A3.wav"
|
glass3' <- Mix.load "./data/sound/Small-Piece-Of-Glass-Shattering-A3.wav"
|
||||||
glass4' <- Mix.load "./data/sound/Small-Piece-Of-Glass-Shattering-A4.wav"
|
glass4' <- Mix.load "./data/sound/Small-Piece-Of-Glass-Shattering-A4.wav"
|
||||||
foamSpray' <- Mix.load "./data/sound/foamSprayLoop.wav"
|
foamSpray' <- Mix.load "./data/sound/foamSprayLoop.wav"
|
||||||
return $ IM.fromList $ zip [0..]
|
return $ IM.fromList $ zip [0..] $
|
||||||
$ [ pFireSound
|
[ pFireSound
|
||||||
, click
|
, click
|
||||||
, reloadSound'
|
, reloadSound'
|
||||||
, tone440
|
, tone440
|
||||||
@@ -102,7 +102,9 @@ loadSounds = do
|
|||||||
, foamSpray'
|
, foamSpray'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
loadMusic :: IO (IM.IntMap Mix.Music)
|
||||||
soundOnce :: Int -> World -> World
|
loadMusic = do
|
||||||
soundOnce i = over soundQueue ((:) i)
|
undercity <- Mix.load "./data/music/undercity.mid"
|
||||||
|
return $ IM.fromList $ zip [0..] $
|
||||||
|
[ undercity
|
||||||
|
]
|
||||||
|
|||||||
+129
-10
@@ -1,35 +1,144 @@
|
|||||||
module Dodge.SoundLogic where
|
{-|
|
||||||
|
Module : Dodge.SoundLogic
|
||||||
|
Description : Messages to "Sound" backend
|
||||||
|
|
||||||
|
This module allows us to talk to the "Sound" module.
|
||||||
|
-}
|
||||||
|
module Dodge.SoundLogic (
|
||||||
|
-- * Manipulation of individual sounds
|
||||||
|
soundOnce
|
||||||
|
, soundOncePos
|
||||||
|
, soundOnceOrigin
|
||||||
|
, soundFromPos
|
||||||
|
, soundFrom
|
||||||
|
, soundMultiFrom
|
||||||
|
, stopSoundFrom
|
||||||
|
|
||||||
|
-- * Manipulation of all sounds
|
||||||
|
, haltSound
|
||||||
|
, resumeSound
|
||||||
|
, pauseSound
|
||||||
|
|
||||||
|
-- * Synonyms for sound identifiers
|
||||||
|
, clickSound
|
||||||
|
, reloadSound
|
||||||
|
, pickUpSound
|
||||||
|
, putDownSound
|
||||||
|
, fireSound
|
||||||
|
, grenadeBang
|
||||||
|
, tapQuiet
|
||||||
|
, twoStepSound
|
||||||
|
, healSound
|
||||||
|
, doorSound
|
||||||
|
, twoStepSlowSound
|
||||||
|
, knifeSound
|
||||||
|
, buzzSound
|
||||||
|
, hitSound
|
||||||
|
, autoGunSound
|
||||||
|
, shotgunSound
|
||||||
|
, teleSound
|
||||||
|
, longGunSound
|
||||||
|
, launcherSound
|
||||||
|
, smokeTrailSound
|
||||||
|
, foot1Sound
|
||||||
|
, foot2Sound
|
||||||
|
) where
|
||||||
import Dodge.Data
|
import Dodge.Data
|
||||||
import Sound.Preload (SoundStatus (..))
|
import Sound.Data (SoundStatus (..))
|
||||||
|
import Geometry.Vector
|
||||||
|
import Geometry (dist)
|
||||||
|
|
||||||
import Control.Lens
|
import Control.Lens
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
|
import Data.Int (Int16)
|
||||||
|
|
||||||
|
{-| Placeholder...-}
|
||||||
haltSound :: World -> World
|
haltSound :: World -> World
|
||||||
haltSound w = w
|
haltSound w = w
|
||||||
|
|
||||||
|
{-| Placeholder...-}
|
||||||
pauseSound :: World -> World
|
pauseSound :: World -> World
|
||||||
pauseSound w = w
|
pauseSound w = w
|
||||||
|
|
||||||
|
{-| Placeholder...-}
|
||||||
resumeSound :: World -> World
|
resumeSound :: World -> World
|
||||||
resumeSound w = w
|
resumeSound w = w
|
||||||
|
|
||||||
|
{-| Add a sound to the queue for playback.
|
||||||
|
Consider replacing with 'soundOncePos'.
|
||||||
|
-}
|
||||||
soundOnce :: Int -> World -> World
|
soundOnce :: Int -> World -> World
|
||||||
soundOnce i = over soundQueue ((:) i)
|
soundOnce i = over soundQueue ((:) (i,0))
|
||||||
|
|
||||||
soundOnceOrigin :: Int -> SoundOrigin -> World -> World
|
{-| Play a sound with a given position in the world.
|
||||||
soundOnceOrigin sType so = over sounds (M.insertWith (flip const) so sound)
|
Uses the angle between the given position and '_cameraViewFrom', taking into account '_cameraRot'.
|
||||||
|
-}
|
||||||
|
soundOncePos :: Int -> Point2 -> World -> World
|
||||||
|
soundOncePos i pos w = over soundQueue ((:) (i,a)) w
|
||||||
where
|
where
|
||||||
sound = Sound
|
a = soundAngle pos w
|
||||||
|
|
||||||
|
{-| Play a sound once, with a given origin.
|
||||||
|
For each origin only one sound will play at a time.
|
||||||
|
-}
|
||||||
|
soundOnceOrigin
|
||||||
|
:: Int -- ^ ID of the sound to be played
|
||||||
|
-> SoundOrigin -- ^ The \"creator\" of the sound
|
||||||
|
-> Point2 -- ^ The position of the sound in the world
|
||||||
|
-> World -> World
|
||||||
|
soundOnceOrigin sType so p w = over sounds (M.insertWith (flip const) so theSound) w
|
||||||
|
where
|
||||||
|
theSound = Sound
|
||||||
{ _soundChunkID = sType
|
{ _soundChunkID = sType
|
||||||
, _soundTime = Nothing
|
, _soundTime = Nothing
|
||||||
, _soundFadeTime = 0
|
, _soundFadeTime = 0
|
||||||
, _soundStatus = ToStart
|
, _soundStatus = ToStart
|
||||||
, _soundChannel = Nothing
|
, _soundChannel = Nothing
|
||||||
, _soundPos = Nothing
|
, _soundPos = Just (a,0)
|
||||||
}
|
}
|
||||||
|
a = soundAngle p w
|
||||||
|
|
||||||
soundFrom :: SoundOrigin -> Int -> Int -> Int -> World -> World
|
soundFromPos
|
||||||
|
:: SoundOrigin -- ^ \"Creator\" of sound
|
||||||
|
-> Point2 -- ^ Position of sound
|
||||||
|
-> Int -- ^ ID of sound to be played
|
||||||
|
-> Int -- ^ Frames to play sound for
|
||||||
|
-> Int -- ^ Time sound fades out after playing for the given number of frames (ms)
|
||||||
|
-> World -> World
|
||||||
|
soundFromPos so pos sType time fadeTime w = over sounds (M.insertWith f so sound) w
|
||||||
|
where
|
||||||
|
sound = Sound
|
||||||
|
{ _soundChunkID = sType
|
||||||
|
, _soundTime = Just time
|
||||||
|
, _soundStatus = ToStart
|
||||||
|
, _soundFadeTime = fadeTime
|
||||||
|
, _soundChannel = Nothing
|
||||||
|
, _soundPos = Just (a,0)
|
||||||
|
}
|
||||||
|
f _ s = s {_soundTime = Just time, _soundFadeTime = fadeTime}
|
||||||
|
a = soundAngle pos w
|
||||||
|
|
||||||
|
{-| Calculates the angle of a sound with reference to '_cameraViewFrom'.
|
||||||
|
Within 10 units considers the sound to be directly in front.
|
||||||
|
-}
|
||||||
|
soundAngle :: Point2 -> World -> Int16
|
||||||
|
{-# INLINE soundAngle #-}
|
||||||
|
soundAngle p w
|
||||||
|
| dist p earPos < 10 = 0
|
||||||
|
| otherwise = round
|
||||||
|
. radToDeg
|
||||||
|
. normalizeAngle
|
||||||
|
. (+ pi)
|
||||||
|
$ argV (vNormal (p -.- earPos)) - _cameraRot w
|
||||||
|
where
|
||||||
|
earPos = _cameraViewFrom w
|
||||||
|
|
||||||
|
soundFrom
|
||||||
|
:: SoundOrigin
|
||||||
|
-> Int -- ^ Sound ID
|
||||||
|
-> Int -- ^ Frames to play
|
||||||
|
-> Int -- ^ Fade out time (ms)
|
||||||
|
-> World -> World
|
||||||
soundFrom so sType time fadeTime w = over sounds (M.insertWith f so sound) w
|
soundFrom so sType time fadeTime w = over sounds (M.insertWith f so sound) w
|
||||||
where
|
where
|
||||||
sound = Sound
|
sound = Sound
|
||||||
@@ -42,7 +151,16 @@ soundFrom so sType time fadeTime w = over sounds (M.insertWith f so sound) w
|
|||||||
}
|
}
|
||||||
f _ s = s {_soundTime = Just time, _soundFadeTime = fadeTime}
|
f _ s = s {_soundTime = Just time, _soundFadeTime = fadeTime}
|
||||||
|
|
||||||
soundMultiFrom :: [SoundOrigin] -> Int -> Int -> Int -> World -> World
|
{-| Uses the first free origin from a list.
|
||||||
|
Does nothing if all origins are already creating sounds.
|
||||||
|
TODO: add positional information.
|
||||||
|
-}
|
||||||
|
soundMultiFrom
|
||||||
|
:: [SoundOrigin]
|
||||||
|
-> Int -- ^ Sound ID
|
||||||
|
-> Int -- ^ Frames to play for
|
||||||
|
-> Int -- ^ Fade out time (ms)
|
||||||
|
-> World -> World
|
||||||
soundMultiFrom [] _ _ _ w = w
|
soundMultiFrom [] _ _ _ w = w
|
||||||
soundMultiFrom (so:sos) sType time fadeTime w
|
soundMultiFrom (so:sos) sType time fadeTime w
|
||||||
| so `M.member` _sounds w = soundMultiFrom sos sType time fadeTime w
|
| so `M.member` _sounds w = soundMultiFrom sos sType time fadeTime w
|
||||||
@@ -57,7 +175,8 @@ soundMultiFrom (so:sos) sType time fadeTime w
|
|||||||
, _soundPos = Nothing
|
, _soundPos = Nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{- | Sets '_soundTime' to 0.
|
||||||
|
-}
|
||||||
stopSoundFrom :: SoundOrigin -> World -> World
|
stopSoundFrom :: SoundOrigin -> World -> World
|
||||||
stopSoundFrom so = over (sounds . ix so . soundTime) (fmap $ min 0)
|
stopSoundFrom so = over (sounds . ix so . soundTime) (fmap $ min 0)
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import Control.Lens
|
|||||||
|
|
||||||
-- The following should be improved.... I've made a first pass
|
-- The following should be improved.... I've made a first pass
|
||||||
makePoisonExplosionAt :: Point2 -> World -> World
|
makePoisonExplosionAt :: Point2 -> World -> World
|
||||||
makePoisonExplosionAt p w = soundOnce grenadeBang $ foldr (makeGasCloud p) w vels
|
makePoisonExplosionAt p w = soundOncePos grenadeBang p $ foldr (makeGasCloud p) w vels
|
||||||
where
|
where
|
||||||
vels = evalState (sequence ( replicate 25 (randInCirc 2) )) (_randGen w)
|
vels = evalState (sequence ( replicate 25 (randInCirc 2) )) (_randGen w)
|
||||||
-- just change the number after replicate to get more or less clouds
|
-- just change the number after replicate to get more or less clouds
|
||||||
@@ -29,12 +29,12 @@ makePoisonExplosionAt p w = soundOnce grenadeBang $ foldr (makeGasCloud p) w vel
|
|||||||
-- currently the clouds push away from each other rather hard if they are close
|
-- currently the clouds push away from each other rather hard if they are close
|
||||||
|
|
||||||
makeTeslaExplosionAt :: Point2 -> World -> World
|
makeTeslaExplosionAt :: Point2 -> World -> World
|
||||||
makeTeslaExplosionAt pos w = soundOnce grenadeBang $ foldr ($) w listOfFunctions -- a bit shorter
|
makeTeslaExplosionAt pos w = soundOncePos grenadeBang pos $ foldr ($) w listOfFunctions -- a bit shorter
|
||||||
where
|
where
|
||||||
-- rad or 360? Radians (hopefully) everywhere
|
-- rad or 360? Radians (hopefully) everywhere
|
||||||
xs = randomRs (0, 2*pi) $ _randGen w
|
xs = randomRs (0, 2*pi) $ _randGen w
|
||||||
p = newProjectileKey w
|
j = newProjectileKey w
|
||||||
pks = [p..]
|
pks = [j..]
|
||||||
listOfFunctions = map
|
listOfFunctions = map
|
||||||
(\i -> over projectiles (IM.insert (pks!!i) (makeTeslaArcAt (pks!!i) pos (xs!!i))))
|
(\i -> over projectiles (IM.insert (pks!!i) (makeTeslaArcAt (pks!!i) pos (xs!!i))))
|
||||||
[1 .. 29]
|
[1 .. 29]
|
||||||
@@ -43,7 +43,7 @@ makeTeslaExplosionAt pos w = soundOnce grenadeBang $ foldr ($) w listOfFunctions
|
|||||||
-- times
|
-- times
|
||||||
-- the new flames are directly added to the list of particles
|
-- the new flames are directly added to the list of particles
|
||||||
makeFlameExplosionAt :: Point2 -> World -> World
|
makeFlameExplosionAt :: Point2 -> World -> World
|
||||||
makeFlameExplosionAt p w = soundOnce grenadeBang $ over particles' (newFlames ++ ) w
|
makeFlameExplosionAt p w = soundOncePos grenadeBang p $ over particles' (newFlames ++ ) w
|
||||||
where
|
where
|
||||||
newFlames = zipWith makeFlameWithVelAndTime velocities timers
|
newFlames = zipWith makeFlameWithVelAndTime velocities timers
|
||||||
makeFlameWithVelAndTime vel time = aFlameParticle time p vel Nothing
|
makeFlameWithVelAndTime vel time = aFlameParticle time p vel Nothing
|
||||||
@@ -54,7 +54,7 @@ makeFlameExplosionAt p w = soundOnce grenadeBang $ over particles' (newFlames ++
|
|||||||
|
|
||||||
|
|
||||||
makeExplosionAt :: Point2 -> World -> World
|
makeExplosionAt :: Point2 -> World -> World
|
||||||
makeExplosionAt p w = soundOnce grenadeBang
|
makeExplosionAt p w = soundOncePos grenadeBang p
|
||||||
. addFlames
|
. addFlames
|
||||||
. explosionFlashAt p
|
. explosionFlashAt p
|
||||||
$ makeShockwaveAt [] p 50 10 1 white
|
$ makeShockwaveAt [] p 50 10 1 white
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
module Dodge.WorldEvent.Sound
|
module Dodge.WorldEvent.Sound
|
||||||
where
|
where
|
||||||
import Dodge.Data
|
import Dodge.Data
|
||||||
|
import Geometry.Data (Point2)
|
||||||
|
|
||||||
import Dodge.SoundLogic
|
import Dodge.SoundLogic
|
||||||
import System.Random
|
import System.Random
|
||||||
|
|
||||||
import Control.Lens
|
import Control.Lens
|
||||||
|
|
||||||
mkSoundBreakGlass :: World -> World
|
mkSoundBreakGlass :: Point2 -> World -> World
|
||||||
mkSoundBreakGlass w = soundOnceOrigin soundid (GlassBreakSound 0) $ set randGen g w
|
mkSoundBreakGlass p w = soundOnceOrigin soundid (GlassBreakSound 0) p $ set randGen g w
|
||||||
where
|
where
|
||||||
(soundid,g) = _randGen w & randomR (37,40)
|
(soundid,g) = _randGen w & randomR (37,40)
|
||||||
|
|
||||||
mkSoundSplinterGlass :: World -> World
|
mkSoundSplinterGlass :: Point2 -> World -> World
|
||||||
mkSoundSplinterGlass w = soundOnceOrigin soundid (GlassBreakSound 1) $ set randGen g w
|
mkSoundSplinterGlass p w = soundOnceOrigin soundid (GlassBreakSound 1) p $ set randGen g w
|
||||||
where
|
where
|
||||||
(soundid,g) = _randGen w & randomR (33,36)
|
(soundid,g) = _randGen w & randomR (33,36)
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
module Music
|
||||||
|
where
|
||||||
|
import qualified SDL.Mixer as Mix
|
||||||
|
import qualified Data.IntMap as IM
|
||||||
|
|
||||||
|
data MusicData = MusicData
|
||||||
|
{ _loadedMusic :: IM.IntMap Mix.Music
|
||||||
|
}
|
||||||
+1
-6
@@ -8,16 +8,11 @@ import Preload.Data
|
|||||||
import Preload.Update
|
import Preload.Update
|
||||||
|
|
||||||
import Picture.Preload
|
import Picture.Preload
|
||||||
import Sound.Preload
|
import Sound.Data
|
||||||
import Control.Lens
|
import Control.Lens
|
||||||
|
|
||||||
import GHC.Word (Word32)
|
import GHC.Word (Word32)
|
||||||
|
|
||||||
--doPreload :: IO (PreloadData a)
|
|
||||||
--doPreload = do
|
|
||||||
-- sData <- preloadSound
|
|
||||||
-- rData <- preloadRender
|
|
||||||
-- return $ PreloadData rData sData 0
|
|
||||||
|
|
||||||
cleanUpPreload :: PreloadData a -> IO ()
|
cleanUpPreload :: PreloadData a -> IO ()
|
||||||
cleanUpPreload pd = do
|
cleanUpPreload pd = do
|
||||||
|
|||||||
+3
-1
@@ -5,11 +5,13 @@ import Control.Lens
|
|||||||
import GHC.Word (Word32)
|
import GHC.Word (Word32)
|
||||||
|
|
||||||
import Picture.Preload
|
import Picture.Preload
|
||||||
import Sound.Preload
|
import Sound.Data
|
||||||
|
import Music
|
||||||
|
|
||||||
data PreloadData a = PreloadData
|
data PreloadData a = PreloadData
|
||||||
{ _renderData :: RenderData
|
{ _renderData :: RenderData
|
||||||
, _soundData :: SoundData a
|
, _soundData :: SoundData a
|
||||||
|
, _musicData :: MusicData
|
||||||
, _frameTimer :: Word32
|
, _frameTimer :: Word32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+31
-10
@@ -11,10 +11,11 @@ Uses SDL.Mixer.
|
|||||||
module Sound (
|
module Sound (
|
||||||
-- * Simple (One-Shot) Playback
|
-- * Simple (One-Shot) Playback
|
||||||
playSoundQueue
|
playSoundQueue
|
||||||
|
, playPositionalSoundQueue
|
||||||
-- * Complex Playback
|
-- * Complex Playback
|
||||||
, playAndUpdate
|
, playAndUpdate
|
||||||
) where
|
) where
|
||||||
import Sound.Preload
|
import Sound.Data
|
||||||
|
|
||||||
import qualified SDL.Mixer as Mix
|
import qualified SDL.Mixer as Mix
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
@@ -24,6 +25,7 @@ import Control.Monad
|
|||||||
import Control.Monad.Trans
|
import Control.Monad.Trans
|
||||||
import Control.Monad.Trans.Maybe
|
import Control.Monad.Trans.Maybe
|
||||||
import Control.Lens
|
import Control.Lens
|
||||||
|
import Data.Int (Int16)
|
||||||
{- | Start playing new sounds and update sound specifications.
|
{- | Start playing new sounds and update sound specifications.
|
||||||
A Map of new sound specifications is merged with a Map of already playing sounds,
|
A Map of new sound specifications is merged with a Map of already playing sounds,
|
||||||
then sounds in the merged Map are updated.
|
then sounds in the merged Map are updated.
|
||||||
@@ -63,7 +65,9 @@ updateSounds sd ss = do
|
|||||||
|
|
||||||
updateSound :: IM.IntMap Mix.Chunk -> Sound -> MaybeT IO Sound
|
updateSound :: IM.IntMap Mix.Chunk -> Sound -> MaybeT IO Sound
|
||||||
updateSound sd s =
|
updateSound sd s =
|
||||||
initialisePlaying sd s >>= liftIO . decrementTimer >>= cleanupHalted
|
initialisePlaying sd s
|
||||||
|
>>= liftIO . (decrementTimer >=> applyPosition)
|
||||||
|
>>= cleanupHalted
|
||||||
|
|
||||||
initialisePlaying :: IM.IntMap Mix.Chunk -> Sound -> MaybeT IO Sound
|
initialisePlaying :: IM.IntMap Mix.Chunk -> Sound -> MaybeT IO Sound
|
||||||
initialisePlaying sd s = case _soundStatus s of
|
initialisePlaying sd s = case _soundStatus s of
|
||||||
@@ -98,6 +102,12 @@ decrementTimer s = case _soundTime s of
|
|||||||
& soundStatus .~ FadingOut)
|
& soundStatus .~ FadingOut)
|
||||||
Nothing -> return s
|
Nothing -> return s
|
||||||
|
|
||||||
|
applyPosition :: Sound -> IO Sound
|
||||||
|
applyPosition s = case _soundPos s of
|
||||||
|
Nothing -> return s
|
||||||
|
Just (a,d) -> Mix.effectPosition (fromJust $ _soundChannel s) a d
|
||||||
|
>> return (s & soundPos .~ Nothing)
|
||||||
|
|
||||||
fadeOutMaybe :: Maybe Mix.Channel -> Int -> IO ()
|
fadeOutMaybe :: Maybe Mix.Channel -> Int -> IO ()
|
||||||
fadeOutMaybe (Just x) fadeT = Mix.fadeOut (fromIntegral fadeT + 1) x
|
fadeOutMaybe (Just x) fadeT = Mix.fadeOut (fromIntegral fadeT + 1) x
|
||||||
fadeOutMaybe _ _ = return ()
|
fadeOutMaybe _ _ = return ()
|
||||||
@@ -112,18 +122,29 @@ cleanupHalted s = do
|
|||||||
|
|
||||||
-----------------------------------------------------------------
|
-----------------------------------------------------------------
|
||||||
{- | Play sounds from a list of indices.
|
{- | Play sounds from a list of indices.
|
||||||
Each sound starts playing (and will not repeat) if there is a free channel.
|
For each index, the corresponding sound starts playing if there is a free channel.
|
||||||
Use this if you don't care about timing, overlapping, fading, or sound positions.
|
Use this if you don't care about timing, overlapping, fading, or sound positions.
|
||||||
-}
|
-}
|
||||||
playSoundQueue :: IM.IntMap Mix.Chunk -> [Int] -> IO ()
|
playSoundQueue :: IM.IntMap Mix.Chunk -> [Int] -> IO ()
|
||||||
playSoundQueue chunkMap ns = forM_ ns $ \n -> playIfFree (chunkMap IM.! n) Mix.Once
|
playSoundQueue chunkMap ns = forM_ ns $ \n -> runMaybeT $ playIfFree (chunkMap IM.! n) Mix.Once
|
||||||
{- | Given a chunk, attempt to play this on a free channel a given number of
|
{- | Given a chunk, attempt to play this on a free channel a given number of
|
||||||
times. Returns 'Just' the channel if succeeds.
|
times. Returns 'Just' the channel if succeeds.
|
||||||
-}
|
-}
|
||||||
playIfFree :: Mix.Chunk -> Mix.Times -> IO (Maybe Mix.Channel)
|
|
||||||
playIfFree c times = do
|
|
||||||
mayChan <- Mix.getAvailable Mix.DefaultGroup
|
|
||||||
case mayChan of
|
|
||||||
Nothing -> return Nothing
|
|
||||||
Just i -> Just <$> Mix.playOn i times c
|
|
||||||
|
|
||||||
|
playIfFree :: Mix.Chunk -> Mix.Times -> MaybeT IO Mix.Channel
|
||||||
|
playIfFree c times = do
|
||||||
|
i <- MaybeT $ Mix.getAvailable Mix.DefaultGroup
|
||||||
|
liftIO $ Mix.playOn i times c
|
||||||
|
|
||||||
|
-----------------------------------------------------------------
|
||||||
|
{- | Play sounds from a list of index/position pairs.
|
||||||
|
As for 'playSoundQueue', but with positional information in the form of an Int16.
|
||||||
|
-}
|
||||||
|
playPositionalSoundQueue :: IM.IntMap Mix.Chunk -> [(Int,Int16)] -> IO ()
|
||||||
|
playPositionalSoundQueue chunkMap ns = forM_ ns $ \(n,a) ->
|
||||||
|
runMaybeT $ playIfFree (chunkMap IM.! n) Mix.Once >>= setChannelPos a
|
||||||
|
|
||||||
|
setChannelPos :: Int16 -> Mix.Channel -> MaybeT IO Mix.Channel
|
||||||
|
setChannelPos a i = do
|
||||||
|
liftIO $ Mix.effectPosition i a 0
|
||||||
|
return i
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
{-# LANGUAGE TemplateHaskell #-}
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
module Sound.Preload
|
module Sound.Data
|
||||||
where
|
where
|
||||||
import qualified SDL.Mixer as Mix
|
import qualified SDL.Mixer as Mix
|
||||||
import qualified Data.IntMap as IM
|
import qualified Data.IntMap as IM
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
import Control.Lens
|
import Control.Lens
|
||||||
import Geometry
|
import Geometry
|
||||||
|
import Data.Word (Word8)
|
||||||
|
import Data.Int (Int16)
|
||||||
|
|
||||||
data SoundStatus
|
data SoundStatus
|
||||||
= Playing
|
= Playing
|
||||||
@@ -22,7 +24,7 @@ data Sound = Sound
|
|||||||
, _soundFadeTime :: Int
|
, _soundFadeTime :: Int
|
||||||
, _soundStatus :: SoundStatus
|
, _soundStatus :: SoundStatus
|
||||||
, _soundChannel :: Maybe Mix.Channel
|
, _soundChannel :: Maybe Mix.Channel
|
||||||
, _soundPos :: Maybe Point2
|
, _soundPos :: Maybe (Int16,Word8)
|
||||||
, _soundChunkID :: Int
|
, _soundChunkID :: Int
|
||||||
}
|
}
|
||||||
deriving (Eq,Ord,Show)
|
deriving (Eq,Ord,Show)
|
||||||
Reference in New Issue
Block a user