{- 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