Files
loop/src/Dodge/Room/Link.hs
T

171 lines
5.9 KiB
Haskell

{- Concerns link pairs of rooms.
Link pairs determine where rooms can attach to each other; each pair consists
of a position and a rotation.
The last link in the list is considered the incoming link, the other links are
the outgoing links. -}
module Dodge.Room.Link
( shiftRoomToLink
--, shiftRoomShiftToLink
, shiftRoomShiftToLink'
, shiftRoomBy
, shiftLinkBy
, doRoomShift
, sortOutLinksOn
, filterSortOutLinksOn
, randomiseAllLinks
, filterLinks
, changeLinkTo
, changeLinkFrom
, randomiseOutLinks
-- , randomiseLinksBy
, invShiftLinkBy
, finalLinksUpdate
) where
import Dodge.Placement.PlaceSpot
import Dodge.LevelGen.Data
import Dodge.RandomHelp
import Geometry
import Data.Tile
import Dodge.RoomLink
import System.Random
import Control.Monad.State
import Control.Lens
import Data.List
{- Shuffle the initial links of a room randomly. -}
randomiseOutLinks :: RandomGen g => Room -> State g Room
randomiseOutLinks r = do
newLinks <- shuffle $ _rmOutLinks r
return $ r {_rmOutLinks = newLinks }
sortOutLinksOn :: Ord b => ((Point2,Float) -> b) -> Room -> Room
sortOutLinksOn f = overLnkType OutLink $ sortOn (f . lnkPosDir)
filterSortOutLinksOn :: Ord b => ((Point2,Float) -> Bool) -> ((Point2,Float) -> b) -> Room -> Room
filterSortOutLinksOn test f = overLnkType OutLink dosort
where
dosort [] = []
dosort xs = let (ys,zs) = partition (test . lnkPosDir) xs
in sortOn (f . lnkPosDir) ys ++ zs
{- Shuffle all links of a room randomly. -}
randomiseAllLinks :: RandomGen g => Room -> State g Room
randomiseAllLinks r = do
newLinks <- shuffle $ _rmOutLinks r ++ _rmInLinks r
return $ r {_rmOutLinks = tail newLinks
, _rmInLinks = [head newLinks]
}
--randomiseLinksBy
-- :: ( [(Point2,Float)] -> State g [(Point2,Float)] )
-- -> Room
-- -> State g Room
--randomiseLinksBy f r = do
-- newLinks <- f $ _rmOutLinks r ++ _rmInLinks r
-- return $ r {_rmOutLinks = init newLinks
-- , _rmInLinks = [last newLinks]
-- }
-- TODO rename to filterOutLinks
filterLinks :: RandomGen g => ((Point2,Float) -> Bool) -> Room -> State g Room
filterLinks cond r = do
newLinks <- shuffle $ filter (cond . lnkPosDir) $ _rmOutLinks r
return $ r {_rmOutLinks = newLinks}
{- | Swaps the first link in the list with one that satisfies a given property.
- Does not change the last link in the list -}
changeLinkFrom :: RandomGen g => ((Point2,Float) -> Bool) -> Room -> State g Room
changeLinkFrom cond r = do
let (possibleLnks,otherLnks) = partition (cond . lnkPosDir) $ _rmOutLinks r
newLnks <- shuffle possibleLnks
return $ r {_rmOutLinks = newLnks ++ otherLnks}
{- | Swaps the last link in the list with one that satisfies a given
- property (it might swap with itself). Unsafe.
- Be careful about calling this after changeLinkFrom. -}
changeLinkTo :: RandomGen g => ((Point2,Float) -> Bool) -> Room -> State g Room
changeLinkTo cond r = do
let alllinks = _rmOutLinks r ++ _rmInLinks r
l <- takeOne $ filter (cond . lnkPosDir) alllinks
let newLinks = delete l alllinks
return $ r { _rmOutLinks = newLinks
,_rmInLinks = [l]}
{- | Move a room so that the first link in '_rmInLinks' lines up to
an external point and direction.
This is intended to work when the external point is an outgoing link from another room.
-}
shiftRoomToLink :: (Point2,Float) -> Room -> Room
shiftRoomToLink l r
= shiftRoomBy l
. shiftRoomBy (V2 0 0 , pi-a)
$ shiftRoomBy (V2 0 0 -.- p , 0)
r
where
(p,a) = lnkPosDir $ head $ _rmInLinks r
doRoomShift :: Room -> Room
doRoomShift rm = shiftRoomBy (_rmShift rm) rm & rmShift .~ _rmShift rm
-- NOTE placements, when placed, will be shifted by the value _rmShift
shiftRoomBy :: (Point2,Float) -> Room -> Room
shiftRoomBy shift r = r
& rmPolys %~ fmap (map (shiftPointBy shift))
& rmOutLinks %~ fmap (shiftLinkBy shift)
& rmInLinks %~ fmap (shiftLinkBy shift)
& rmPath %~ map (shiftPathBy shift)
& rmBound %~ fmap (map (shiftPointBy shift))
& rmShift %~ shiftPosDirBy shift
& rmFloor %~ map
( (tilePoly %~ map (shiftPointBy shift))
. (tileZero %~ shiftPointBy shift )
. (tileX %~ shiftPointBy shift )
)
& rmViewpoints %~ map (shiftPointBy shift)
--shiftRoomShiftToLink :: (Point2,Float) -> Room -> Room
--shiftRoomShiftToLink l r
-- = shiftRoomShiftBy l
-- . shiftRoomShiftBy (V2 0 0 , pi-a)
-- $ shiftRoomShiftBy (V2 0 0 -.- p , 0)
-- r
-- where
-- (p,a) = head $ _rmInLinks r
shiftRoomShiftToLink' :: (Point2,Float) -> (Point2,Float) -> Room -> Room
shiftRoomShiftToLink' l inlink r
= shiftRoomShiftBy l
. shiftRoomShiftBy (V2 0 0 , pi-a)
$ shiftRoomShiftBy (V2 0 0 -.- p , 0)
r
where
(p,a) = inlink
-- NOTE placements, when placed, will be shifted by the value _rmShift
shiftRoomShiftBy :: (Point2,Float) -> Room -> Room
shiftRoomShiftBy shift r = r
& rmShift %~ shiftPosDirBy shift
shiftPosDirBy :: (Point2,Float) -> (Point2,Float) -> (Point2,Float)
shiftPosDirBy (pos,rot) (p,r) = (shiftPointBy (pos,rot) p, r + rot)
shiftLinkBy :: (Point2,Float) -> RoomLink -> RoomLink
shiftLinkBy (pos,rot) = overLnkPosDir f
where
f (p,r) = (shiftPointBy (pos,rot) p, r + rot)
invShiftLinkBy :: (Point2,Float) -> (Point2,Float) -> (Point2,Float)
invShiftLinkBy (pos,rot) (p,r) = (invShiftPointBy (pos,rot) p, r - rot)
shiftPathBy
:: (Point2,Float)
-> (Point2,Point2)
-> (Point2,Point2)
shiftPathBy s (p1,p2) = (shiftPointBy s p1, shiftPointBy s p2)
finalLinksUpdate :: Room -> Room
finalLinksUpdate rm = case _rmInLinks rm of
(_:_) -> rm
& rmInLinks %~ tail
& rmPos %~ ( (uncurry (UsedInLink 0) (lnkPosDir $ head inlnks) :)
. (map (uncurry UnusedLink . lnkPosDir) (outlnks ++ tail inlnks) ++) )
_ -> rm
where
inlnks = _rmInLinks rm
outlnks = _rmOutLinks rm