Add airlocks

This commit is contained in:
2021-05-02 21:09:25 +02:00
parent 9cdd3a9629
commit f336d7e3f6
27 changed files with 522 additions and 219 deletions
-1
View File
@@ -46,7 +46,6 @@ dependencies:
- aeson - aeson
- directory - directory
- QuickCheck - QuickCheck
- utility-ht
library: library:
source-dirs: src source-dirs: src
+1 -1
View File
@@ -735,7 +735,7 @@ nearestCrInFront p dir x w
{- | Test whether a creature is in a polygon. {- | Test whether a creature is in a polygon.
-} -}
crInPolygon :: Creature -> [Point2] -> Bool crInPolygon :: Creature -> [Point2] -> Bool
crInPolygon cr xs = errorPointInPolygon 3 (_crPos cr) xs crInPolygon cr = errorPointInPolygon 3 (_crPos cr)
{- | Transform coordinates from world position to normalised screen coordinates. {- | Transform coordinates from world position to normalised screen coordinates.
-} -}
+5 -3
View File
@@ -67,10 +67,12 @@ explosiveBarrel :: Creature
explosiveBarrel = defaultInanimate explosiveBarrel = defaultInanimate
{ _crUpdate = updateExpBarrel { _crUpdate = updateExpBarrel
, _crHP = 400 , _crHP = 400
, _crPict = \ _ -> onLayer CrLayer $ pictures [ color orange $ circleSolid 10 , _crPict = \ _ -> onLayer CrLayer $ pictures
, color red $ circleSolid 8 [ color red $ circleSolid 8
, color orange $ circleSolid 10
] ]
, _crState = defaultState {_goals = [[Wait]] , _crState = defaultState
{_goals = [[Wait]]
,_faction = ChaseCritters ,_faction = ChaseCritters
,_crSpState = Barrel [] ,_crSpState = Barrel []
} }
+7 -4
View File
@@ -46,9 +46,11 @@ stateUpdate u w (f,g) cr =
$ crOrCorpse =<< maybeCr $ crOrCorpse =<< maybeCr
) )
where where
crOrCorpse cr | cr ^. crHP > 0 = Just cr crOrCorpse cr
| cr ^. crHP > 0 = Just cr
| otherwise = Nothing | otherwise = Nothing
deathEff | cr ^.crHP > 0 = id deathEff
| cr ^.crHP > 0 = id
| otherwise = stopSoundFrom (CrWeaponSound (_crID cr)) | otherwise = stopSoundFrom (CrWeaponSound (_crID cr))
. over decorations addCorpse . over decorations addCorpse
. dropByState cr . dropByState cr
@@ -57,7 +59,7 @@ stateUpdate u w (f,g) cr =
$ rotate (_crDir cr) $ rotate (_crDir cr)
(_crCorpse cr) (_crCorpse cr)
-- | Drop items accoring to the creature state. -- | Drop items according to the creature state.
dropByState :: Creature -> World -> World dropByState :: Creature -> World -> World
dropByState cr w = foldr (copyItemToFloor cr) w is dropByState cr w = foldr (copyItemToFloor cr) w is
where where
@@ -81,7 +83,8 @@ crFriction cr vel = (0,0)
doDamage :: Creature -> Creature doDamage :: Creature -> Creature
doDamage cr = set (crState . crDamage) [] $ over (crState . crPastDamage) (+ hpLost) doDamage cr = set (crState . crDamage) [] $ over (crState . crPastDamage) (+ hpLost)
damagedCr damagedCr
where dams = _crDamage $ _crState cr where
dams = _crDamage $ _crState cr
startHP = _crHP cr startHP = _crHP cr
damagedCr = snd $ (_crApplyDamage cr) dams cr damagedCr = snd $ (_crApplyDamage cr) dams cr
afterHP = _crHP damagedCr afterHP = _crHP damagedCr
-2
View File
@@ -16,8 +16,6 @@ import qualified Data.Set as S
import qualified Data.IntMap.Strict as IM import qualified Data.IntMap.Strict as IM
import System.Random import System.Random
yourControl :: World -> (World -> World,StdGen) -> Creature -> ((World -> World,StdGen), Maybe Creature) yourControl :: World -> (World -> World,StdGen) -> Creature -> ((World -> World,StdGen), Maybe Creature)
yourControl w (f,g) cr = ( (updateUsingInput . f, g) yourControl w (f,g) cr = ( (updateUsingInput . f, g)
, Just . crAutoReload . mouseActionsCr (_mouseButtons w) $ wasdWithAiming w speed strafeSpeed 0 cr , Just . crAutoReload . mouseActionsCr (_mouseButtons w) $ wasdWithAiming w speed strafeSpeed 0 cr
+5 -5
View File
@@ -26,10 +26,12 @@ import Dodge.Data.DamageType
import Dodge.Config.Data import Dodge.Config.Data
import Dodge.Config.KeyConfig import Dodge.Config.KeyConfig
import Dodge.Item.Attachment.Data import Dodge.Item.Attachment.Data
import Dodge.World.Trigger.Data
import Preload.Data import Preload.Data
import Picture.Data import Picture.Data
import Geometry.Data import Geometry.Data
import Sound.Data import Sound.Data
import qualified DoubleStack as DS
import Control.Lens import Control.Lens
import Control.Monad.State import Control.Monad.State
@@ -162,10 +164,6 @@ data WorldState
| CrNumAlive Int | CrNumAlive Int
deriving (Eq,Ord) deriving (Eq,Ord)
data WorldTrigger
= ResetLevel Int
deriving (Eq,Ord)
data Button = Button data Button = Button
{ _btPict :: Picture { _btPict :: Picture
, _btPos :: Point2 , _btPos :: Point2
@@ -434,12 +432,14 @@ data Wall
, _wlIsSeeThrough :: Bool , _wlIsSeeThrough :: Bool
} }
| Door | Door
{ _wlLine :: [Point2] , _wlID :: Int { _wlLine :: [Point2]
, _wlID :: Int
, _doorMech :: World -> World , _doorMech :: World -> World
, _wlColor :: Color , _wlColor :: Color
, _wlSeen :: Bool , _wlSeen :: Bool
, _wlIsSeeThrough :: Bool , _wlIsSeeThrough :: Bool
, _doorPathable :: Bool , _doorPathable :: Bool
, _drPositions :: DS.DS [Point2]
} }
| Block | Block
{ _wlLine :: [Point2] { _wlLine :: [Point2]
+1 -1
View File
@@ -616,7 +616,7 @@ data PSType = PutCrit Creature
| PutAutoDoor Point2 Point2 | PutAutoDoor Point2 Point2
| PutBlock [Int] Color [Point2] | PutBlock [Int] Color [Point2]
| PutLineBlock Wall Float Float Point2 Point2 | PutLineBlock Wall Float Float Point2 Point2
| PutTriggerDoor Color (World -> Bool) Point2 Point2 | PutDoubleDoor Color (World -> Bool) Point2 Point2
| PutBtDoor Color Point2 Float Point2 Point2 | PutBtDoor Color Point2 Float Point2 Point2
| PutSwitchDoor Color Point2 Float Point2 Point2 | PutSwitchDoor Color Point2 Float Point2 Point2
| RandPS (State StdGen PSType) | RandPS (State StdGen PSType)
+3
View File
@@ -16,6 +16,7 @@ import Dodge.Config.Data
import Dodge.Config.KeyConfig import Dodge.Config.KeyConfig
import Geometry import Geometry
import Picture import Picture
import qualified DoubleStack as DS
import Control.Lens import Control.Lens
import System.Random import System.Random
@@ -44,6 +45,7 @@ defaultAutoDoor = Door
, _wlSeen = False , _wlSeen = False
, _wlIsSeeThrough = False , _wlIsSeeThrough = False
, _doorPathable = True , _doorPathable = True
, _drPositions = DS.singleton [(0,0),(50,0)]
} }
{- {-
Non-pathable door. Non-pathable door.
@@ -56,6 +58,7 @@ defaultDoor = Door
, _wlSeen = False , _wlSeen = False
, _wlIsSeeThrough = False , _wlIsSeeThrough = False
, _doorPathable = False , _doorPathable = False
, _drPositions = DS.singleton [(0,0),(50,0)]
} }
defaultCreature :: Creature defaultCreature :: Creature
defaultCreature = Creature defaultCreature = Creature
+8 -2
View File
@@ -12,6 +12,7 @@ import Dodge.Room.Link
import Dodge.Room.Door import Dodge.Room.Door
import Dodge.Room.Branch import Dodge.Room.Branch
import Dodge.Room.Boss import Dodge.Room.Boss
import Dodge.Room.Airlock
import Dodge.Base import Dodge.Base
import Dodge.Layout import Dodge.Layout
import Dodge.Layout.Tree.Polymorphic import Dodge.Layout.Tree.Polymorphic
@@ -41,8 +42,12 @@ roomTreex = do
let t' = padCorridors struct let t' = padCorridors struct
t = treeFromTrunk t = treeFromTrunk
[[StartRoom] [[StartRoom]
,[Corridor]
,[SpecificRoom $ (pure . pure . Right) $ airlockCrystal 20]
,[Corridor]
,[DoorAno] ,[DoorAno]
,[SpecificRoom $ fmap (pure . Right) $ randomiseAllLinks =<< centerVaultRoom 1 200 200 50] ,[SpecificRoom $ fmap (pure . Right)
$ randomiseLinksBy shuffleTail =<< centerVaultRoom 1 200 200 50]
,[SpecificRoom blockedCorridor] ,[SpecificRoom blockedCorridor]
,[OrAno [[DoorAno] ,[OrAno [[DoorAno]
,[Corridor] ,[Corridor]
@@ -52,7 +57,8 @@ roomTreex = do
,[Corridor] ,[Corridor]
,[SpecificRoom $ fmap (pure . Right) testRoom] ,[SpecificRoom $ fmap (pure . Right) testRoom]
,[Corridor] ,[Corridor]
,[OrAno [[SpecificRoom $ branchRectWith $ fmap (pure . Left) armouredChasers] ,[OrAno
[[SpecificRoom $ branchRectWith $ fmap (pure . Left) armouredChasers]
,[BossAno $ addArmour launcherCrit & crHP +~ 800 ,[BossAno $ addArmour launcherCrit & crHP +~ 800
& crState . crDropsOnDeath .~ DropSpecific [0] ] & crState . crDropsOnDeath .~ DropSpecific [0] ]
] ]
+2 -1
View File
@@ -15,6 +15,7 @@ import Dodge.Room.Boss
import Dodge.Room.Treasure import Dodge.Room.Treasure
import Dodge.Room.Link import Dodge.Room.Link
import Dodge.Room.Data import Dodge.Room.Data
import Dodge.Room.Airlock
import Dodge.Room import Dodge.Room
import Dodge.Room.Teleport import Dodge.Room.Teleport
@@ -71,7 +72,7 @@ annoToRoomTree [OrAno as] = do
annoToRoomTree a annoToRoomTree a
annoToRoomTree [Corridor] = pure . Right <$> randomiseOutLinks corridor annoToRoomTree [Corridor] = pure . Right <$> randomiseOutLinks corridor
annoToRoomTree [DoorAno] = roomThenCorridor door annoToRoomTree [DoorAno] = roomThenCorridor door
annoToRoomTree [DoorNumAno i,AirlockAno] = roomThenCorridor (airlock i) annoToRoomTree [DoorNumAno i,AirlockAno] = airlock i >>= roomThenCorridor
annoToRoomTree [FirstWeapon] = do annoToRoomTree [FirstWeapon] = do
branchWP <- branchRectWith weaponRoom branchWP <- branchRectWith weaponRoom
blockedC <- longBlockedCorridor blockedC <- longBlockedCorridor
+9 -3
View File
@@ -61,10 +61,16 @@ placeSpot ps w = case ps of
-> placePressPlate pp p rot w -> placePressPlate pp p rot w
PS {_psType = RandPS rgen} PS {_psType = RandPS rgen}
-> placeSpot (set psType evaluatedType ps) (set randGen g w) -> placeSpot (set psType evaluatedType ps) (set randGen g w)
where (evaluatedType, g) = runState rgen (_randGen w) where
(evaluatedType, g) = runState rgen (_randGen w)
PS {_psPos = p, _psRot = rot, _psType = PutTriggerDoor col f a b} PS {_psPos = p, _psRot = rot, _psType = PutDoor col f pss}
-> addTriggerDoor col f (shiftPointBy (p,rot) a) (shiftPointBy (p,rot) b) w -> putDoor col f (map (mapBoth $ shiftPointBy (p,rot)) pss) w
where
mapBoth fn (x,y) = (fn x, fn y)
PS {_psPos = p, _psRot = rot, _psType = PutDoubleDoor col f a b}
-> putDoubleDoor col f (shiftPointBy (p,rot) a) (shiftPointBy (p,rot) b) w
PS {_psPos = p, _psRot = rot, _psType = PutAutoDoor a b} PS {_psPos = p, _psRot = rot, _psType = PutAutoDoor a b}
-> addAutoDoor (shiftPointBy (p,rot) a) (shiftPointBy (p,rot) b) w -> addAutoDoor (shiftPointBy (p,rot) a) (shiftPointBy (p,rot) b) w
+2
View File
@@ -10,6 +10,7 @@ import Dodge.SoundLogic
import Dodge.Creature.Property import Dodge.Creature.Property
import Geometry import Geometry
import Picture import Picture
import qualified DoubleStack as DS
import Data.List import Data.List
import Data.Maybe import Data.Maybe
@@ -85,6 +86,7 @@ autoDoorPane (trigx,trigy) n closedPos openPos = Door
, _wlSeen = False , _wlSeen = False
, _wlIsSeeThrough = False , _wlIsSeeThrough = False
, _doorPathable = True , _doorPathable = True
, _drPositions = DS.singleton closedPos
} }
where where
a = closedPos !! 0 a = closedPos !! 0
+2 -1
View File
@@ -17,7 +17,8 @@ data PSType = PutCrit Creature
| PutAutoDoor Point2 Point2 | PutAutoDoor Point2 Point2
| PutBlock [Int] Color [Point2] | PutBlock [Int] Color [Point2]
| PutLineBlock Wall Float Float Point2 Point2 | PutLineBlock Wall Float Float Point2 Point2
| PutTriggerDoor Color (World -> Bool) Point2 Point2 | PutDoubleDoor Color (World -> Bool) Point2 Point2
| PutDoor Color (World -> Bool) [(Point2,Point2)]
| PutBtDoor Color Point2 Float Point2 Point2 | PutBtDoor Color Point2 Float Point2 Point2
| PutSwitchDoor Color Point2 Float Point2 Point2 | PutSwitchDoor Color Point2 Float Point2 Point2
| RandPS (State StdGen PSType) | RandPS (State StdGen PSType)
+88 -15
View File
@@ -6,17 +6,15 @@ import Dodge.Base
import Dodge.SoundLogic import Dodge.SoundLogic
import Dodge.LevelGen.Switch import Dodge.LevelGen.Switch
import Dodge.LevelGen.Pathing import Dodge.LevelGen.Pathing
import Picture import Picture
import Geometry import Geometry
import qualified DoubleStack as DS
import Data.List import Data.List
import Data.Maybe import Data.Maybe
import qualified Data.IntMap.Strict as IM import qualified Data.IntMap.Strict as IM
import Control.Lens import Control.Lens
import Control.DeepSeq (deepseq) import Control.DeepSeq (deepseq)
import Data.Graph.Inductive hiding ((&)) import Data.Graph.Inductive hiding ((&))
import Data.Graph.Inductive.NodeMap import Data.Graph.Inductive.NodeMap
@@ -26,7 +24,7 @@ addButtonDoor c btp btr a b w = over buttons (IM.insert bid bt)
$ set pathPoints (foldr insertPoint IM.empty (labNodes newGraph)) $ set pathPoints (foldr insertPoint IM.empty (labNodes newGraph))
$ set pathGraph newGraph $ set pathGraph newGraph
$ set pathGraph' newGraphPairs $ set pathGraph' newGraphPairs
$ addTriggerDoor c cond a b w $ putDoubleDoor c cond a b w
where where
bid = newKey $ _buttons w bid = newKey $ _buttons w
cond w = BtNoLabel == _btState (_buttons w IM.! bid) cond w = BtNoLabel == _btState (_buttons w IM.! bid)
@@ -44,7 +42,7 @@ addSwitchDoor c btp btr a b w = over buttons (IM.insert bid bt)
$ set pathPoints (foldr insertPoint IM.empty (labNodes newGraph)) $ set pathPoints (foldr insertPoint IM.empty (labNodes newGraph))
$ set pathGraph newGraph $ set pathGraph newGraph
$ set pathGraph' newGraphPairs $ set pathGraph' newGraphPairs
$ addTriggerDoor c cond a b w $ putDoubleDoor c cond a b w
where where
bid = newKey $ _buttons w bid = newKey $ _buttons w
cond w = BtOn == _btState (_buttons w IM.! bid) cond w = BtOn == _btState (_buttons w IM.! bid)
@@ -59,17 +57,48 @@ addSwitchDoor c btp btr a b w = over buttons (IM.insert bid bt)
closeDoor w' = over pathGraph' (\\ removedPairs) closeDoor w' = over pathGraph' (\\ removedPairs)
. over pathGraph (flip run_ $ delMapEdgesM removedPairs) $ w' . over pathGraph (flip run_ $ delMapEdgesM removedPairs) $ w'
addTriggerDoor :: Color -> (World -> Bool) -> Point2 -> Point2 -> World -> World
addTriggerDoor c cond a b = over walls (triggerDoor c cond a b)
triggerDoor :: Color -> (World -> Bool) -> Point2 -> Point2 -> IM.IntMap Wall -> IM.IntMap Wall putDoor
triggerDoor c cond a b wls = IM.union wls $ IM.fromList $ zip is $ mkTriggerDoor c cond a b is :: Color
-> (World -> Bool)
-> [(Point2,Point2)] -- ^ Door positions, closed to open.
-- Bumped out up and down by 9, not widened
-> World
-> World
putDoor c cond pss = over walls triggerDoor
where where
i = newKey wls triggerDoor wls = IM.union wls $ IM.fromList $ zip is $ mkTriggerDoor c cond pss is
is = [i..] where
is = [newKey wls..]
mkTriggerDoor :: Color -> (World -> Bool) -> Point2 -> Point2 -> [Int] -> [Wall] putDoubleDoor :: Color -> (World -> Bool) -> Point2 -> Point2 -> World -> World
mkTriggerDoor c cond pl pr xs = addSound $ zipWith3 (triggerDoorPane c cond) putDoubleDoor c cond a b = over walls triggerDoubleDoor
where
triggerDoubleDoor wls = IM.union wls $ IM.fromList $ zip is $ mkTriggerDoubleDoor c cond a b is
where
is = [newKey wls..]
mkTriggerDoor
:: Color
-> (World -> Bool) -- ^ Opening condition
-> [(Point2,Point2)] -- ^ List of wall position pairs, closed to open
-> [Int] -- ^ Wall ids
-> [Wall]
mkTriggerDoor c cond ppairs is = zipWith (triggerDoorPane c cond) is $
transpose $ map toPanePoints ppairs
toPanePoints :: (Point2,Point2) -> [[Point2]]
toPanePoints (x,y) =
[ [y +.+ perp, y -.- perp]
, [y -.- perp, x -.- perp]
, [x -.- perp, x +.+ perp]
, [x +.+ perp, y +.+ perp]
]
where
perp = 9 *.* errorNormalizeV 49 ( vNormal (x -.- y))
mkTriggerDoubleDoor :: Color -> (World -> Bool) -> Point2 -> Point2 -> [Int] -> [Wall]
mkTriggerDoubleDoor c cond pl pr xs = addSound $ zipWith3 (triggerDoorPaneLinear c cond)
xs xs
(leftDoor ++ rightDoor) (leftDoor ++ rightDoor)
(map shiftLeft leftDoor ++ map shiftRight rightDoor) (map shiftLeft leftDoor ++ map shiftRight rightDoor)
@@ -106,8 +135,14 @@ mkTriggerDoor c cond pl pr xs = addSound $ zipWith3 (triggerDoorPane c cond)
where where
wp = _wlLine (_walls w IM.! head xs) !! 1 wp = _wlLine (_walls w IM.! head xs) !! 1
triggerDoorPane :: Color -> (World -> Bool) -> Int -> [Point2] -> [Point2] -> Wall triggerDoorPaneLinear
triggerDoorPane c cond n closedPos openPos = Door :: Color
-> (World -> Bool) -- ^ Opening condition
-> Int -- ^ Wall id
-> [Point2] -- ^ Closed position
-> [Point2] -- ^ Open position
-> Wall
triggerDoorPaneLinear c cond n closedPos openPos = Door
{ _wlLine = closedPos { _wlLine = closedPos
, _wlID = n , _wlID = n
, _doorMech = dm , _doorMech = dm
@@ -115,6 +150,7 @@ triggerDoorPane c cond n closedPos openPos = Door
, _wlSeen = False , _wlSeen = False
, _wlIsSeeThrough = False , _wlIsSeeThrough = False
, _doorPathable = False , _doorPathable = False
, _drPositions = DS.singleton closedPos
} }
where where
a = closedPos !! 0 a = closedPos !! 0
@@ -135,3 +171,40 @@ triggerDoorPane c cond n closedPos openPos = Door
= over wallsZone $ adjustIMZone openDoor x y n = over wallsZone $ adjustIMZone openDoor x y n
changeZonedWall' (!x,!y) changeZonedWall' (!x,!y)
= over wallsZone $ adjustIMZone closeDoor x y n = over wallsZone $ adjustIMZone closeDoor x y n
{- |
Zoning might be an issue here.
It is necessary in the current version, but I am not sure of its behaviour. -}
triggerDoorPane
:: Color
-> (World -> Bool) -- ^ Opening condition
-> Int -- ^ Wall id
-> [[Point2]] -- ^ List of positions: closed to open
-> Wall
triggerDoorPane c cond n poss = Door
{ _wlLine = head poss
, _wlID = n
, _doorMech = dm
, _wlColor = c
, _wlSeen = False
, _wlIsSeeThrough = False
, _doorPathable = False
, _drPositions = DS.fromListL poss
}
where
dm w | cond w = flip (foldr changeZonedWall) allZoneps
$ over walls (IM.adjust openDoor n) w -- . wlLine . ix 0) (mvPointToward a')
| otherwise = flip (foldr changeZonedWall') allZoneps
$ over walls (IM.adjust closeDoor n) w -- . wlLine . ix 0) (mvPointToward a)
openDoor = updatePos . (drPositions %~ DS.pushL)
closeDoor = updatePos . (drPositions %~ DS.pushR)
updatePos :: Wall -> Wall
updatePos d = d & wlLine %~ maybe id const (DS.head <$> (d ^? drPositions))
changeZonedWall (!x,!y)
= over wallsZone $ adjustIMZone openDoor x y n
changeZonedWall' (!x,!y)
= over wallsZone $ adjustIMZone closeDoor x y n
allZoneps = nub $ concatMap zoneps poss
zoneps [a,b]
| dist a b <= 2 * zoneSize = [zoneOfPoint $ pHalf a b]
| otherwise = map zoneOfPoint $ divideLine (2*zoneSize) a b
+5 -1
View File
@@ -41,7 +41,7 @@ takeN :: RandomGen g => Int -> [a] -> State g [a]
takeN 0 xs = return [] takeN 0 xs = return []
takeN i xs = fmap fst $ takeNMore i ([],xs) takeN i xs = fmap fst $ takeNMore i ([],xs)
-- to randomly shuffle a list -- | Randomly shuffle a list.
shuffle :: RandomGen g => [a] -> State g [a] shuffle :: RandomGen g => [a] -> State g [a]
shuffle xs = do shuffle xs = do
let l = length xs let l = length xs
@@ -51,6 +51,10 @@ shuffle xs = do
let (_,zs) = mapAccumR f xs rands let (_,zs) = mapAccumR f xs rands
return zs return zs
-- | Randomly shuffle the tail of a list, not safe.
shuffleTail :: RandomGen g => [a] -> State g [a]
shuffleTail (x:xs) = (x :) <$> shuffle xs
randomSelectionFromList :: RandomGen g => Float -> [a] -> State g [a] randomSelectionFromList :: RandomGen g => Float -> [a] -> State g [a]
randomSelectionFromList p = filterM $ const $ randProb p randomSelectionFromList p = filterM $ const $ randProb p
+6 -13
View File
@@ -51,53 +51,43 @@ doDrawing pdata w = do
viewFroms@(viewFromx,viewFromy) = _cameraViewFrom w viewFroms@(viewFromx,viewFromy) = _cameraViewFrom w
pic = worldPictures w pic = worldPictures w
wallPoints = map fst wallPointsCol wallPoints = map fst wallPointsCol
-- set the coordinate uniforms ready for drawing elements with using world coordinates -- set the coordinate uniforms ready for drawing elements with using world coordinates
setCommonUniforms pdata rot zoom trans wins setCommonUniforms pdata rot zoom trans wins
depthFunc $= Just Less depthFunc $= Just Less
pmat <- (newMatrix RowMajor $ perspectiveMatrix rot zoom trans wins viewFroms) pmat <- (newMatrix RowMajor $ perspectiveMatrix rot zoom trans wins viewFroms)
:: IO (GLmatrix GLfloat) :: IO (GLmatrix GLfloat)
-- draw the lightmap. Probably changes the bound framebufferObject -- draw the lightmap. Probably changes the bound framebufferObject
createLightMap pdata (w ^. config . shadow_resolution) wallPoints lightPoints viewFroms pmat createLightMap pdata (w ^. config . shadow_resolution) wallPoints lightPoints viewFroms pmat
-- draw the background. Assumes that depth testing is not enabled or that -- draw the background. Assumes that depth testing is not enabled or that
-- the depth buffer is ready to be drawn on -- the depth buffer is ready to be drawn on
blendFuncSeparate $= ((SrcAlphaSaturate, OneMinusSrcAlpha), (Zero,One)) blendFuncSeparate $= ((SrcAlphaSaturate, OneMinusSrcAlpha), (Zero,One))
renderBackground pdata rot zoom trans wins renderBackground pdata rot zoom trans wins
-- draw the walls -- draw the walls
depthFunc $= Just Less depthFunc $= Just Less
if w ^. config . wall_textured if w ^. config . wall_textured
then renderTextureWalls pdata wallPointsCol pmat then renderTextureWalls pdata wallPointsCol pmat
else renderBlankWalls pdata wallPointsCol pmat else renderBlankWalls pdata wallPointsCol pmat
-- I believe a more apt name would be setCeilingDepth: stops drawing of objects -- I believe a more apt name would be setCeilingDepth: stops drawing of objects
-- at points that are behind the extension of walls to the screen edge -- at points that are behind the extension of walls to the screen edge
setWallDepth pdata wallPoints (viewFromx,viewFromy) pmat setWallDepth pdata wallPoints (viewFromx,viewFromy) pmat
-- draw the first layer of pictures -- draw the first layer of pictures
-- these will probably all be opaque -- these will probably all be opaque
renderFoldable pdata $ picToLTree (Just 0) pic renderFoldable pdata $ picToLTree (Just 0) pic
-- reset blend so that light map doesn't apply -- reset blend so that light map doesn't apply
-- useful for drawing vivid projectiles -- useful for drawing vivid projectiles
blendFuncSeparate $= ((SrcAlpha,OneMinusSrcAlpha) , (Zero,One)) blendFuncSeparate $= ((SrcAlpha,OneMinusSrcAlpha) , (Zero,One))
depthFunc $= Just Lequal depthFunc $= Just Lequal
renderFoldable pdata $ picToLTree (Just 1) pic renderFoldable pdata $ picToLTree (Just 1) pic
-- reset blend so that light map applies again -- reset blend so that light map applies again
-- allows us to be certain these elements are drawn on top of those before, -- allows us to be certain these elements are drawn on top of those before,
-- in case we want transparency effects -- in case we want transparency effects
blendFuncSeparate $= ((SrcAlphaSaturate, OneMinusSrcAlpha), (Zero,One)) blendFuncSeparate $= ((SrcAlphaSaturate, OneMinusSrcAlpha), (Zero,One))
renderFoldable pdata $ picToLTree (Just 2) pic renderFoldable pdata $ picToLTree (Just 2) pic
depthMask $= Disabled depthMask $= Disabled
-- render transparent walls -- render transparent walls
-- the ordering between these and transparent clouds perhaps presents a challenge -- the ordering between these and transparent clouds perhaps presents a challenge
renderBlankWalls pdata windowPoints pmat renderBlankWalls pdata windowPoints pmat
depthMask $= Enabled depthMask $= Enabled
-- draw the fbo to the screen -- draw the fbo to the screen
-- allows for post-processing -- allows for post-processing
-- first, bind the screen fbo -- first, bind the screen fbo
@@ -108,20 +98,23 @@ doDrawing pdata w = do
textureBinding Texture2D $= Just (snd $ _fbo2 pdata) textureBinding Texture2D $= Just (snd $ _fbo2 pdata)
-- textureFilter Texture2D $= ((Linear',Just Linear') , Linear') -- textureFilter Texture2D $= ((Linear',Just Linear') , Linear')
-- generateMipmap' Texture2D -- generateMipmap' Texture2D
if _crHP (you w) > 0
then do
bindShaderBuffers [_fullscreenShader pdata] [4] bindShaderBuffers [_fullscreenShader pdata] [4]
drawShader (_fullscreenShader pdata) 4 drawShader (_fullscreenShader pdata) 4
else do
bindShaderBuffers [_grayscaleShader pdata] [4]
drawShader (_grayscaleShader pdata) 4
blend $= Enabled blend $= Enabled
-- reset the coordinate uniforms for pictures that are drawn wrt to window -- reset the coordinate uniforms for pictures that are drawn wrt to window
-- coordinates -- coordinates
resetShaderUniforms (map extractProgAndUnis $ _pictureShaders pdata) resetShaderUniforms (map extractProgAndUnis $ _pictureShaders pdata)
blendFunc $= (SrcAlpha,OneMinusSrcAlpha) blendFunc $= (SrcAlpha,OneMinusSrcAlpha)
renderFoldable pdata (picToLTree Nothing $ fixedCoordPictures w) renderFoldable pdata (picToLTree Nothing $ fixedCoordPictures w)
eTicks <- SDL.ticks eTicks <- SDL.ticks
return (eTicks - sTicks) return (eTicks - sTicks)
---------------------- --------------------------------------------------------------------------------
renderBlankWalls renderBlankWalls
:: RenderData :: RenderData
+3 -48
View File
@@ -27,6 +27,7 @@ import Dodge.Room.Corridor
import Dodge.Room.Link import Dodge.Room.Link
import Dodge.Room.Branch import Dodge.Room.Branch
import Dodge.Room.Door import Dodge.Room.Door
import Dodge.Room.Airlock
import Geometry import Geometry
import Picture import Picture
@@ -47,53 +48,6 @@ import Data.Graph.Inductive.NodeMap
import qualified Data.Map as M import qualified Data.Map as M
import qualified Data.IntMap.Strict as IM import qualified Data.IntMap.Strict as IM
airlockOneWay :: Int -> Room
airlockOneWay n = Room
{ _rmPolys = [rectNSWE 90 0 0 40]
, _rmLinks = lnks
, _rmPath = []
, _rmPS = [PS (0,15) 0 $ PutTriggerDoor col (not . cond) (0,0) (0,40)
,PS (0,75) 0 $ PutTriggerDoor col (cond) (0,0) (0,40)
,PS (35,45) (pi/2) $ PutButton $ makeButton col (over worldState
(M.insert (DoorNumOpen n) True))
]
--, _rmBound = rectNSWE 90 30 (-30) 30
, _rmBound = rectNSWE 75 15 0 40
}
where lnks = [((0,85),0)
,((0, 5),pi)
]
cond w = or $ M.lookup (DoorNumOpen n) (_worldState w)
col = dim $ dim $ bright red
airlock
:: Int -- ^ Door id
-> Room
airlock n = Room
{ _rmPolys =
[ rectNSWE 100 0 0 40
, rectNSWE 65 35 (-40) 20
]
, _rmLinks = lnks
, _rmPath = [((20,85),(20,45))
,((20,45),(20, 5))
]
, _rmPS =
[PS (0,20) 0 $ PutTriggerDoor col (not . cond) (1,0) (39,0)
,PS (0,80) 0 $ PutTriggerDoor col (cond) (1,0) (39,0)
,PS (35,50) (pi/2) $ PutButton $ makeSwitch col
(over worldState (M.insert (DoorNumOpen n) True))
(over worldState (M.insert (DoorNumOpen n) False))
,PS (-25, 50) 0 putLamp
]
, _rmBound = rectNSWE 75 15 0 40
}
where
lnks = [((20,85),0)
,((20, 5),pi)
]
cond w = or $ M.lookup (DoorNumOpen n) (_worldState w)
col = dim $ dim $ bright red
roomC :: Float -> Float -> Room roomC :: Float -> Float -> Room
roomC x y = Room roomC x y = Room
@@ -633,4 +587,5 @@ spawnerRoom = do
] ]
let f ((lx,_),_) = lx < x/2-5 let f ((lx,_),_) = lx < x/2-5
roomWithSpawner <- (fmap connectRoom . randomiseOutLinks) =<< filterLinks f (set rmPS plmnts $ roomRect x y 2 2) roomWithSpawner <- (fmap connectRoom . randomiseOutLinks) =<< filterLinks f (set rmPS plmnts $ roomRect x y 2 2)
return $ treeFromTrunk [Left (airlock 0)] roomWithSpawner aRoom <- airlock 0
return $ treeFromTrunk [Left aRoom] roomWithSpawner
+157
View File
@@ -0,0 +1,157 @@
{-# LANGUAGE TupleSections #-}
{-
Rooms that contain two doors and a switch alternating both. -}
module Dodge.Room.Airlock
where
import Dodge.Room.Data
import Dodge.Room.Placement
import Dodge.Data
import Dodge.LevelGen.Data
import Dodge.LevelGen.Switch
import Dodge.RandomHelp
import Geometry
import Picture
import qualified Data.Map as M
import System.Random
import Control.Monad.State
import Control.Lens
airlockOneWay :: Int -> Room
airlockOneWay n = Room
{ _rmPolys = [rectNSWE 90 0 0 40]
, _rmLinks = lnks
, _rmPath = []
, _rmPS = [PS (0,15) 0 $ PutDoubleDoor col (not . cond) (0,0) (0,40)
,PS (0,75) 0 $ PutDoubleDoor col (cond) (0,0) (0,40)
,PS (35,45) (pi/2) $ PutButton $ makeButton col (over worldState
(M.insert (DoorNumOpen n) True))
]
--, _rmBound = rectNSWE 90 30 (-30) 30
, _rmBound = rectNSWE 75 15 0 40
}
where lnks = [((0,85),0)
,((0, 5),pi)
]
cond w = or $ M.lookup (DoorNumOpen n) (_worldState w)
col = dim $ dim $ bright red
{- |
A passage with a switch that opens forward access while closing backwards access. -}
airlock
:: RandomGen g
=> Int -- ^ Door id
-> State g Room
airlock n = takeOne [airlock0 n,airlock90 n,airlockCrystal n]
{- |
Straight airlock -}
airlock0
:: Int -- ^ Door id
-> Room
airlock0 n = Room
{ _rmPolys =
[ rectNSWE 100 0 0 40
, rectNSWE 65 35 (-40) 20
]
, _rmLinks = lnks
, _rmPath = [((20,95),(20,45))
,((20,45),(20, 5))
]
, _rmPS =
[PS (0,20) 0 $ PutDoubleDoor col (not . cond) (1,0) (39,0)
,PS (0,80) 0 $ PutDoubleDoor col (cond) (1,0) (39,0)
,PS (35,50) (pi/2) $ PutButton $ makeSwitch col
(over worldState (M.insert (DoorNumOpen n) True))
(over worldState (M.insert (DoorNumOpen n) False))
,PS (-25, 50) 0 putLamp
]
, _rmBound = rectNSWE 75 15 0 40
}
where
lnks = [((20,95),0)
,((20, 5),pi)
]
cond w = or $ M.lookup (DoorNumOpen n) (_worldState w)
col = dim $ dim $ bright red
airlock90
:: Int -- ^ Door id
-> Room
airlock90 n = Room
{ _rmPolys =
[ rectNSWE 100 10 10 100
, rectNSWE 20 0 20 60
, rectNSWE 20 60 20 0
, [ (10,100)
, (100,150)
, (150,100)
, (100,10)
]
]
, _rmLinks =
[((0,40),pi/2)
,((40, 0),pi)
]
, _rmPath =
[((0,40),(40,0))
,((40,0),(0,40))
]
, _rmPS =
[PS (5,5) 0 $ PutDoor col (not . cond) pss
,PS (120,120) (3* pi/4) $ PutButton $ makeSwitch col
(over worldState (M.insert (DoorNumOpen n) True))
(over worldState (M.insert (DoorNumOpen n) False))
,PS (60, 60) 0 putLamp
]
, _rmBound =
[ (10,10)
, (10,100)
, (100,150)
, (150,100)
, (100,10)
]
}
where
cond w = or $ M.lookup (DoorNumOpen n) (_worldState w)
col = dim $ dim $ bright red
pss = ((0,0) ,) <$> arcStepwise 3 (negate $ pi/2) (0,0) (0,55)
airlockCrystal
:: Int -- ^ Door id
-> Room
airlockCrystal n = Room
{ _rmPolys =
[ rectNSWE 140 0 0 40
, orderPolygon
[(39,20)
,(150,60)
,(150,80)
,(39,120)
]
]
, _rmLinks =
[((20,130),0)
,((20, 0),pi)
]
, _rmPath =
[
]
, _rmPS =
[PS (0,0) 0 $ PutDoor col (not . cond) pss
,PS (145,70) (pi/2) $ PutButton $ makeSwitch col
(over worldState (M.insert (DoorNumOpen n) True))
(over worldState (M.insert (DoorNumOpen n) False))
,crystalLine (0,70) (40,70)
,PS (20, 40) 0 putLamp
,PS (20, 100) 0 putLamp
]
, _rmBound =
[ ]
}
where
cond w = or $ M.lookup (DoorNumOpen n) (_worldState w)
col = dim $ dim $ bright red
pss :: [(Point2,Point2)]
pss = reverse $ fmap ( (\x -> ((50,x),(50,x+50)) ) . fromIntegral)
[20,22..70]
+2
View File
@@ -22,3 +22,5 @@ door = Room
where lnks = [((20,35),0) where lnks = [((20,35),0)
,((20, 5),pi) ,((20, 5),pi)
] ]
+9
View File
@@ -30,6 +30,15 @@ randomiseAllLinks r = do
newLinks <- shuffle $ _rmLinks r newLinks <- shuffle $ _rmLinks r
return $ r {_rmLinks = newLinks} return $ r {_rmLinks = newLinks}
randomiseLinksBy
:: RandomGen g
=> ( [(Point2,Float)] -> State g [(Point2,Float)] )
-> Room
-> State g Room
randomiseLinksBy f r = do
newLinks <- f $ _rmLinks r
return $ r {_rmLinks = newLinks}
filterLinks :: RandomGen g => ((Point2,Float) -> Bool) -> Room -> State g Room filterLinks :: RandomGen g => ((Point2,Float) -> Bool) -> Room -> State g Room
filterLinks cond r = do filterLinks cond r = do
newLinks <- shuffle $ filter cond $ init $ _rmLinks r newLinks <- shuffle $ filter cond $ init $ _rmLinks r
+5 -1
View File
@@ -260,6 +260,10 @@ centerVaultRoom n w h d = do
,PS (w-5,5-h) 0 putLamp ,PS (w-5,5-h) 0 putLamp
,PS (5-w,h-5) 0 putLamp ,PS (5-w,h-5) 0 putLamp
,PS (5-w,5-h) 0 putLamp ,PS (5-w,5-h) 0 putLamp
,PS (0,h-5) 0 $ PutCrit explosiveBarrel
,PS (5,h-5) 0 $ PutCrit explosiveBarrel
,PS (0,h) 0 $ PutCrit explosiveBarrel
,PS (-4,h-5) 0 $ PutCrit explosiveBarrel
,PS (0,0) 0 $ PutCrit (cr & crState . crDropsOnDeath .~ DropAll) ,PS (0,0) 0 $ PutCrit (cr & crState . crDropsOnDeath .~ DropAll)
] ]
++ concat (zipWith (\i r -> map (shiftPSBy ((0,0),r)) $ theDoor i) ++ concat (zipWith (\i r -> map (shiftPSBy ((0,0),r)) $ theDoor i)
@@ -269,7 +273,7 @@ centerVaultRoom n w h d = do
where where
col = dim $ dim $ bright red col = dim $ dim $ bright red
theDoor i = theDoor i =
[ PS (0,d-10) 0 $ PutTriggerDoor col (cond i) (-19,0) (19,0) [ PS (0,d-10) 0 $ PutDoubleDoor col (cond i) (-19,0) (19,0)
, PS (35,d+4) 0 $ PutButton $ makeSwitch col , PS (35,d+4) 0 $ PutButton $ makeSwitch col
(over worldState (M.insert (DoorNumOpen i) True)) (over worldState (M.insert (DoorNumOpen i) True))
(over worldState (M.insert (DoorNumOpen i) False)) (over worldState (M.insert (DoorNumOpen i) False))
+1
View File
@@ -4,6 +4,7 @@ Specification of rooms that teleport (between levels).
module Dodge.Room.Teleport module Dodge.Room.Teleport
where where
import Dodge.Data import Dodge.Data
import Dodge.World.Trigger.Data
import Dodge.Base import Dodge.Base
import Dodge.Room.Data import Dodge.Room.Data
import Dodge.Room.Procedural import Dodge.Room.Procedural
+50 -40
View File
@@ -7,6 +7,7 @@ module Dodge.Update
) where ) where
import Dodge.Data import Dodge.Data
import Dodge.Data.Menu import Dodge.Data.Menu
import Dodge.World.Trigger.Data
import Dodge.Config.Data import Dodge.Config.Data
import Dodge.Data.Menu import Dodge.Data.Menu
import Dodge.Base import Dodge.Base
@@ -35,26 +36,19 @@ pushSideEffects :: World -> World
pushSideEffects w = w pushSideEffects w = w
& sideEffects .~ [] & sideEffects .~ []
& doneSideEffects .~ _sideEffects w & doneSideEffects .~ _sideEffects w
{- |
{- | The update step. The update step.
If '_menuLayers' is not empty, or the saving screen, this is the identity. For most menus the only way to change the world is using event handling. -}
In such menus, the only way to change the world is using event handling.
-}
update' :: World -> World update' :: World -> World
update' w = case _menuLayers w of update' w = case _menuLayers w of
(WaitMessage _ : ls) -> w & menuLayers .~ ls (WaitMessage _ : ls) -> w & menuLayers .~ ls
(_ : _) -> w (GameOverMenu : _) -> updateParticles
[] -> let w1 = updateParticles
. updateProjectiles . updateProjectiles
. updateLightSources . updateLightSources
. zoneClouds $ updateClouds
. updateClouds w
. updateCreatures (_ : _) -> w
. updateBlocks -- . zoning [] -> checkEndGame
. updateSeenWalls
. updateSoundQueue
$ updateCloseObjects w
in checkEndGame
. updateTriggers . updateTriggers
. ppEvents . ppEvents
. updateCamera . updateCamera
@@ -63,7 +57,17 @@ update' w = case _menuLayers w of
. zoneCreatures . zoneCreatures
. updateWalls . updateWalls
. set worldEvents id . set worldEvents id
$ _worldEvents w1 w1 . doubleArgumentFor _worldEvents
. updateParticles
. updateProjectiles
. updateLightSources
. zoneClouds
. updateClouds
. updateCreatures
. updateBlocks
. updateSeenWalls
. updateSoundQueue
$ updateCloseObjects w
where where
zoneCreatures = set creaturesZone (IM.foldr creatureInZone IM.empty (_creatures w)) zoneCreatures = set creaturesZone (IM.foldr creatureInZone IM.empty (_creatures w))
creatureInZone cr = insertIMInZone x y cid cr creatureInZone cr = insertIMInZone x y cid cr
@@ -73,17 +77,18 @@ update' w = case _menuLayers w of
cloudInZone cr = insertIMInZone x y cid cr cloudInZone cr = insertIMInZone x y cid cr
where (x,y) = zoneOfPoint $ _clPos cr where (x,y) = zoneOfPoint $ _clPos cr
cid = _clID cr cid = _clID cr
doubleArgumentFor f x = f x x
updateTriggers :: World -> World updateTriggers :: World -> World
updateTriggers w updateTriggers w
| ResetLevel 1 `S.member` _worldTriggers w | ResetLevel 1 `S.member` _worldTriggers w = generateFromList levx $ initialWorld
= generateFromList levx
$ initialWorld
& randGen .~ _randGen w & randGen .~ _randGen w
& config .~ _config w & config .~ _config w
& menuLayers .~ [] & menuLayers .~ []
& creatures . ix 0 . crPos .~ (0,0) & creatures . ix 0 .~ cr
| otherwise = w | otherwise = w
where
cr = _creatures w IM.! 0 & crPos .~ (0,0)
updateSoundQueue = set soundQueue [] . set sounds M.empty updateSoundQueue = set soundQueue [] . set sounds M.empty
@@ -93,10 +98,8 @@ updateLightSources w = set tempLightSources (catMaybes tlss) w'
(w',tlss) = mapAccumR (\a b -> _tlsUpdate b a b) w $ _tempLightSources w (w',tlss) = mapAccumR (\a b -> _tlsUpdate b a b) w $ _tempLightSources w
updateProjectiles w = IM.foldr' _pjUpdate w $ _projectiles w updateProjectiles w = IM.foldr' _pjUpdate w $ _projectiles w
{- {-
Apply internal particle updates, delete 'Nothing's. Apply internal particle updates, delete 'Nothing's. -}
-}
updateParticles :: World -> World updateParticles :: World -> World
updateParticles w = set particles (catMaybes ps) w' updateParticles w = set particles (catMaybes ps) w'
where where
@@ -105,12 +108,11 @@ updateParticles w = set particles (catMaybes ps) w'
updateCreatures :: World -> World updateCreatures :: World -> World
updateCreatures w = f $ set randGen newG $ set creatures (IM.mapMaybe id crs) w updateCreatures w = f $ set randGen newG $ set creatures (IM.mapMaybe id crs) w
where where
((f,newG),crs) = IM.mapAccum (\g' cr -> _crUpdate cr w g' cr) (id,_randGen w) ((f,newG),crs) =
$ _creatures w IM.mapAccum (\g' cr -> _crUpdate cr w g' cr) (id,_randGen w) $ _creatures w
{- | {- |
Apply door mechanisms. Apply door mechanisms. -}
-}
updateWalls :: World -> World updateWalls :: World -> World
updateWalls w = IM.foldr (maybe id id . (^? doorMech)) w (_walls w) updateWalls w = IM.foldr (maybe id id . (^? doorMech)) w (_walls w)
@@ -127,29 +129,34 @@ updateSeenWalls w = foldr markSeen w wallsToUpdate
setTestStringIO :: IO World -> IO World setTestStringIO :: IO World -> IO World
setTestStringIO = fmap (\ w -> set testString (show $ s w) w) setTestStringIO = fmap (\ w -> set testString (show $ s w) w)
where s w = (-.-) <$> (w ^? creatures . ix 0 . crPos) <*> (w ^? creatures . ix 0 . crOldPos) where
s w = (-.-) <$> (w ^? creatures . ix 0 . crPos) <*> (w ^? creatures . ix 0 . crOldPos)
checkEndGame :: World -> World checkEndGame :: World -> World
checkEndGame w | _crHP (you w) < 1 = haltSound $ w {_menuLayers = [GameOverMenu]} checkEndGame w
| _crHP (you w) < 1 = haltSound $ w {_menuLayers = [GameOverMenu]}
| otherwise = w | otherwise = w
updateClouds :: World -> World updateClouds :: World -> World
updateClouds w = IM.foldr' updateCloud w $ _clouds w updateClouds w = IM.foldr' updateCloud w $ _clouds w
updateCloud :: Cloud -> World -> World updateCloud :: Cloud -> World -> World
updateCloud c w | _clTimer c < 1 = w & clouds %~ IM.delete (_clID c) updateCloud c w
| _clTimer c < 1 = w & clouds %~ IM.delete (_clID c)
| otherwise = moveCloud c w | otherwise = moveCloud c w
moveCloud :: Cloud -> World -> World moveCloud :: Cloud -> World -> World
moveCloud c w = _clEffect c c . theUpdate $ w moveCloud c w = _clEffect c c . theUpdate $ w
where newVel = 0.95 *.* springVels where
newVel = 0.95 *.* springVels
springVels = IM.foldr' (clClSpringVel c w) (_clVel c) (cloudsNearPoint oldPos w) springVels = IM.foldr' (clClSpringVel c w) (_clVel c) (cloudsNearPoint oldPos w)
oldPos = _clPos c oldPos = _clPos c
newPos = oldPos +.+ newVel newPos = oldPos +.+ newVel
hitWl = collideCircWalls' oldPos newPos 5 $ wallsNearPoint newPos w hitWl = collideCircWalls' oldPos newPos 5 $ wallsNearPoint newPos w
finalPos = fromMaybe newPos (fmap fst hitWl) finalPos = fromMaybe newPos (fmap fst hitWl)
finalVel = fromMaybe newVel (fmap snd hitWl) finalVel = fromMaybe newVel (fmap snd hitWl)
theUpdate w' = w' & clouds . ix (_clID c) . clTimer %~ (\t -> t - 1) theUpdate w' = w'
& clouds . ix (_clID c) . clTimer %~ (\t -> t - 1)
& clouds . ix (_clID c) . clVel .~ finalVel & clouds . ix (_clID c) . clVel .~ finalVel
& clouds . ix (_clID c) . clPos .~ finalPos & clouds . ix (_clID c) . clPos .~ finalPos
@@ -158,7 +165,8 @@ clClSpringVel a w b v
| ida == idb = v | ida == idb = v
| dist pa pb < radDist = v +.+ 0.1 *.* (safeNormalizeV (pa -.- pb)) | dist pa pb < radDist = v +.+ 0.1 *.* (safeNormalizeV (pa -.- pb))
| otherwise = v | otherwise = v
where ida = _clID a where
ida = _clID a
idb = _clID b idb = _clID b
pa = _clPos a pa = _clPos a
pb = _clPos b pb = _clPos b
@@ -169,7 +177,8 @@ simpleCrSprings w = IM.foldr' crSpring w $ _creatures w
crSpring :: Creature -> World -> World crSpring :: Creature -> World -> World
crSpring c w = IM.foldr' (crCrSpring c) w $ cs crSpring c w = IM.foldr' (crCrSpring c) w $ cs
where cs = creaturesNearPoint (_crPos c) w where
cs = creaturesNearPoint (_crPos c) w
crCrSpring :: Creature -> Creature -> World -> World crCrSpring :: Creature -> Creature -> World -> World
crCrSpring c1 c2 w crCrSpring c1 c2 w
@@ -178,7 +187,8 @@ crCrSpring c1 c2 w
| diff < comRad = over (creatures . ix id1 . crPos) (+.+ overlap1) | diff < comRad = over (creatures . ix id1 . crPos) (+.+ overlap1)
$ over (creatures . ix id2 . crPos) (-.- overlap2) w $ over (creatures . ix id2 . crPos) (-.- overlap2) w
| otherwise = w | otherwise = w
where id1 = _crID c1 where
id1 = _crID c1
id2 = _crID c2 id2 = _crID c2
vec = _crPos c1 -.- _crPos c2 vec = _crPos c1 -.- _crPos c2
diff = magV $ vec diff = magV $ vec
@@ -186,10 +196,8 @@ crCrSpring c1 c2 w
overlap1 = ((comRad - diff) * _crMass c2 * 0.5 / massT) *.* errorNormalizeV 55 vec overlap1 = ((comRad - diff) * _crMass c2 * 0.5 / massT) *.* errorNormalizeV 55 vec
overlap2 = ((comRad - diff) * _crMass c1 * 0.5 / massT) *.* errorNormalizeV 56 vec overlap2 = ((comRad - diff) * _crMass c1 * 0.5 / massT) *.* errorNormalizeV 56 vec
massT = _crMass c1 + _crMass c2 massT = _crMass c1 + _crMass c2
{- {-
Finds the IDs of visible walls from a point to another point. Finds the IDs of visible walls from a point to another point. -}
-}
visibleWalls :: Point2 -> Point2 -> IM.IntMap Wall -> [Int] visibleWalls :: Point2 -> Point2 -> IM.IntMap Wall -> [Int]
visibleWalls p1 p2 ws visibleWalls p1 p2 ws
= map fst = map fst
@@ -201,8 +209,10 @@ visibleWalls p1 p2 ws
$ IM.toList ws $ IM.toList ws
where where
f (i,wl) = (intersectSegSeg' (_wlLine wl !! 0) (_wlLine wl !! 1) p1 p2, (i,wl)) f (i,wl) = (intersectSegSeg' (_wlLine wl !! 0) (_wlLine wl !! 1) p1 p2, (i,wl))
takeUntil h xs = let (ys,zs) = span h xs takeUntil h xs =
let (ys,zs) = span h xs
in ys ++ tf zs in ys ++ tf zs
where tf (x:_) = [x] where
tf (x:_) = [x]
tf _ = [] tf _ = []
+6
View File
@@ -0,0 +1,6 @@
{- |
Placeholder... not sure of its purpose, but might deal with pure world change functions.
The world datatype itself is very intertwined with the creature, weapon, etc datatypes.
-}
module Dodge.World
where
+12
View File
@@ -0,0 +1,12 @@
{- |
World triggers are intended to help me handle global events,
such as new levels, game overs, etc, that disrupt the typical flow of the game.
They should probably be used sparingly.
-}
module Dodge.World.Trigger.Data
where
data WorldTrigger
= ResetLevel Int
| GameOver
deriving (Eq,Ord)
+33
View File
@@ -0,0 +1,33 @@
module DoubleStack
where
newtype DS a = DS (a,[a],[a])
deriving (Eq, Ord, Read, Show)
{- |
Unsafe. -}
fromListL :: [a] -> DS a
fromListL (x:xs) = DS (x,xs,[])
singleton :: a -> DS a
singleton x = DS (x,[],[])
head (DS (x,_,_)) = x
left (DS (_,l,_)) = l
right (DS (_,_,r)) = r
pushL :: DS a -> DS a
pushL (DS (x,xs,(y:ys))) = DS (y,(x:xs),ys)
pushL ds = ds
pushR :: DS a -> DS a
pushR (DS (y,(x:xs),ys)) = DS (x,xs,(y:ys))
pushR ds = ds
cycleL :: DS a -> Maybe (DS a)
cycleL (DS (x,xs,(y:ys))) = Just $ DS (y,(x:xs),ys)
cycleL _ = Nothing
cycleR :: DS a -> Maybe (DS a)
cycleR (DS (y,(x:xs),ys)) = Just $ DS (x,xs,(y:ys))
cycleR _ = Nothing
+23
View File
@@ -461,6 +461,29 @@ divideCircle x cen rad = map (cen +.+) $ nRaysRad n rad
where where
n = ceiling $ rad * 2 * pi / x n = ceiling $ rad * 2 * pi / x
arcStepwise
:: Float -- ^ Maximum distance between points
-> Float -- ^ Angle to travel
-> Point2 -- ^ Center
-> Point2 -- ^ Start vector from center
-> [Point2]
arcStepwise ssize a c v
| a < 0 = reverse $ arcStepwisePositive ssize (negate a) c (rotateV a v)
| otherwise = arcStepwisePositive ssize a c v
arcStepwisePositive
:: Float -- ^ Maximum distance between points
-> Float -- ^ Angle to travel, assumed to be positive
-> Point2 -- ^ Center
-> Point2 -- ^ Start vector from center
-> [Point2]
arcStepwisePositive ssize a cen v = ((cen +.+) . (\rot -> rotateV rot v) ) <$> rots
where
rots :: [Float]
rots = map ((a*) . (/ fromIntegral n ) . fromIntegral) [0 .. n]
n :: Int
n = ceiling (a * magV v / ssize)
--nPointsOnCirc :: Int -> Float -> [Point2] --nPointsOnCirc :: Int -> Float -> [Point2]
--nPointsOnCirc n rad = take n $ iterate (rotateV (2*pi/fromIntegral n)) (rad,0) --nPointsOnCirc n rad = take n $ iterate (rotateV (2*pi/fromIntegral n)) (rad,0)