Files
loop/src/Dodge/Door.hs
T

111 lines
4.0 KiB
Haskell

{-# LANGUAGE LambdaCase #-}
module Dodge.Door (updateDoor) where
import Data.Foldable
import Data.Maybe
import qualified Data.Set as S
import Dodge.Data.World
import Dodge.Door.DoorLerp
import Dodge.ShiftPoint
import Dodge.SoundLogic
import Dodge.Wall.Move
import Dodge.WorldBool
import Dodge.Zoning.Base
import Dodge.Zoning.Pathing
import Geometry.Data
import LensHelp
import Linear
import Picture.Data
import Shape.Data
updateDoor :: Door -> World -> (S.Set Int2, World)
updateDoor dr w = case dr ^. drUpdate of
DoorLerp x -> doorLerp x dr w
DoorLerpWithTimer n x -> doorLerpWithTimer n x dr w
DoorDoNothing ->
( mempty
, foldl' (doDoorMount (doDoorLerp dr (dr ^. drLerp))) w (dr ^. drMounts)
)
-- could filter these HERE rather than later?
doDoorMount :: Point2A -> World -> MountedObject -> World
doDoorMount pa w = \case
MountedLight p r c ->
w & cWorld . lWorld . lights .:~ LSParam (p & _xy %~ shiftPointBy pa) r c
MountedSPic x ->
w & cWorld . lWorld . tempSPic
<>~ ( x & _1 . each . sfVs . each . _xy %~ shiftPointBy pa
& _2 . each . vxPos . _xy %~ shiftPointBy pa
)
-- do the mounts need to be done if there is no lerping?
doorLerp :: Float -> Door -> World -> (S.Set Int2, World)
doorLerp speed dr w = fromMaybe (mempty, domounts (dr ^. drLerp) $ setOldLerp w) $ do
x <- newlerp
let ps = wlposs x
ps' = wlposs (dr ^. drLerp)
is = foldMap (S.fromList . uncurry (zoneOfSeg peZoneSize)) (ps <> ps')
-- it seems possible that this will miss some paths: we don't add zones for the
-- old footprint. Seems unlikely, but a possible cause of pathfinding bugs
return
( is
, domounts x $
f x
& playSound x
& cWorld . lWorld . doors . ix drid . drLerp .~ x
& setOldLerp
)
where
setOldLerp = cWorld . lWorld . doors . ix drid . drOldLerp .~ (dr ^. drLerp)
domounts x w' = foldl' (doDoorMount (doDoorLerp dr x)) w' (dr ^. drMounts)
f = ifoldl' (flip . moveWallID) w . wlposs
wlposs x = (dr ^. drFootPrint) & each . each %~ shiftPointBy (doDoorLerp dr x)
clerp = dr ^. drLerp
newlerp
| toOpen && clerp < 1 = Just . min 1 $ clerp + speed
| clerp > 0 && not toOpen = Just . max 0 $ clerp - speed
| otherwise = Nothing
toOpen = doWdBl (_drTrigger dr) w
drid = _drID dr
playSound x
| _drPushedBy dr == PushesItself =
soundContinue (WallSound drid) (fst $ doDoorLerp dr x) slideDoorS (Just 1)
| otherwise = id
doorLerpWithTimer :: Int -> Float -> Door -> World -> (S.Set Int2, World)
doorLerpWithTimer n speed dr w = fromMaybe (mempty, domounts (dr ^. drLerp) w & uptimer) $ do
x <- newlerp
let ps = wlposs x
ps' = wlposs (dr ^. drLerp)
is = foldMap (S.fromList . uncurry (zoneOfSeg peZoneSize)) (ps <> ps')
-- it seems possible that this will miss some paths: we don't add zones for the
-- old footprint. Seems unlikely, but a possible cause of pathfinding bugs
return
( is
, domounts x $
f x
& playSound x
& cWorld . lWorld . doors . ix drid . drLerp .~ x
& uptimer
)
where
domounts x w' = foldl' (doDoorMount (doDoorLerp dr x)) w' (dr ^. drMounts)
f = ifoldl' (flip . moveWallID) w . wlposs
wlposs x = (dr ^. drFootPrint) & each . each %~ shiftPointBy (doDoorLerp dr x)
clerp = dr ^. drLerp
newlerp
| toOpen && clerp < 1 = Just . min 1 $ clerp + speed
| clerp > 0 && not toOpen = Just . max 0 $ clerp - speed
| otherwise = Nothing
uptimer = cWorld . lWorld . doors . ix drid . drUpdate . drLerpTimer %~ updatetimer
updatetimer
| doWdBl (_drTrigger dr) w = const 20
| otherwise = max 0 . subtract 1
toOpen = doWdBl (_drTrigger dr) w || n > 0
drid = _drID dr
playSound x
| _drPushedBy dr == PushesItself =
soundContinue (WallSound drid) (fst $ doDoorLerp dr x) slideDoorS (Just 1)
| otherwise = id