269 lines
8.3 KiB
Haskell
269 lines
8.3 KiB
Haskell
--{-# LANGUAGE LambdaCase #-}
|
|
module Dodge.PlacementSpot (
|
|
atFstLnkOut,
|
|
atNthLnkOutShiftBy,
|
|
rpIsOnPath,
|
|
rpIsOffPath,
|
|
rpOffPathFromEdge,
|
|
rpOnPathFromEdge,
|
|
useUnusedLnk,
|
|
psRandRanges,
|
|
useRoomPosCond,
|
|
isUsedLnkUnplaced,
|
|
anyUnusedSpot,
|
|
unusedSpotAwayFromLink,
|
|
isUnusedLnk,
|
|
isInLnk,
|
|
isOutLnk,
|
|
unusedSpotNearInLink,
|
|
randDirPS,
|
|
unusedSpotAwayFromInLink,
|
|
useLnkRoomPos,
|
|
atFstLnkOutShiftInward,
|
|
atFstLnkOutShiftBy,
|
|
atNthLnkOutShiftInward,
|
|
unusedOffPathAwayFromLink,
|
|
setFallback,
|
|
twoRoomPoss,
|
|
isUnusedLnkType,
|
|
rprBoolShift,
|
|
rprShift,
|
|
rprBool,
|
|
shiftInBy,
|
|
resetPLUse,
|
|
psposAddLabel,
|
|
shiftByV2,
|
|
usedRoomLinkPoss,
|
|
usedRoomInLinkPoss,
|
|
atNthLinkOut,
|
|
) where
|
|
|
|
import Control.Lens
|
|
import Control.Monad.State
|
|
import Data.Bifunctor
|
|
import Data.Maybe
|
|
import qualified Data.Set as S
|
|
import Dodge.Data.GenWorld
|
|
import Geometry
|
|
import System.Random
|
|
|
|
setDirPS :: Float -> PlacementSpot -> PlacementSpot
|
|
setDirPS a ps = case ps of
|
|
PS p _ -> PS p a
|
|
PSNoShiftCont p _ -> PS p a
|
|
PSPos f rmeff fb -> PSPos (\rp r -> fmap (first (setDirPS a)) (f rp r)) rmeff fb
|
|
PSRoomRand i f -> PSRoomRand i (fmap (setDirPS a) f)
|
|
|
|
randDirPS :: RandomGen g => PlacementSpot -> State g PlacementSpot
|
|
randDirPS ps = do
|
|
a <- state $ randomR (0, pi * 2)
|
|
return $ setDirPS a ps
|
|
|
|
isUnusedLnk :: RoomPos -> Room -> Bool
|
|
isUnusedLnk rp _ = case _rpLinkStatus rp of
|
|
UnusedLink{} -> _rpPlacementUse rp == 0
|
|
_ -> False
|
|
|
|
anyUnusedSpot :: PlacementSpot
|
|
anyUnusedSpot = rprBool $ \rp _ -> _rpLinkStatus rp == NotLink && _rpPlacementUse rp == 0
|
|
|
|
psposAddLabel :: RoomPosType -> PlacementSpot -> PlacementSpot
|
|
psposAddLabel lab = psSelect %~ (\f rp r -> f rp r & _Just . _2 . rpType %~ S.insert lab)
|
|
|
|
rprBool :: (RoomPos -> Room -> Bool) -> PlacementSpot
|
|
rprBool t = PSPos (useRoomPosRoomCond t) (const id) Nothing
|
|
|
|
rpIsOnPath :: RoomPos -> Bool
|
|
rpIsOnPath = any f . _rpType
|
|
where
|
|
f RoomPosOnPath{} = True
|
|
f _ = False
|
|
|
|
rpIsOffPath :: RoomPos -> Bool
|
|
rpIsOffPath = any f . _rpType
|
|
where
|
|
f RoomPosOffPath{} = True
|
|
f _ = False
|
|
|
|
rpOffPathFromEdge :: PathFromEdge -> RoomPos -> Bool
|
|
rpOffPathFromEdge pe = any f . _rpType
|
|
where
|
|
f rt = maybe False (pe `elem`) (rt ^? offPathFromEdges)
|
|
|
|
-- test whether a roomPos is on the path with a given from edge value
|
|
rpOnPathFromEdge :: PathFromEdge -> RoomPos -> Bool
|
|
rpOnPathFromEdge pe = any f . _rpType
|
|
where
|
|
f rt = maybe False (pe `elem`) (rt ^? onPathFromEdges)
|
|
|
|
resetPLUse :: PlacementSpot -> PlacementSpot
|
|
resetPLUse (PSPos f g fallback) = PSPos f' g fallback
|
|
where
|
|
f' rp = fmap (second (rpPlacementUse .~ 0)) . f rp
|
|
resetPLUse _ = error "Tried to reset _rpPlacementUse of non PSPos placement"
|
|
|
|
rprShift ::
|
|
(RoomPos -> Room -> Maybe (Point2, Float)) ->
|
|
PlacementSpot
|
|
rprShift t = PSPos f (const id) Nothing
|
|
where
|
|
f rp r = case t rp r of
|
|
Just (p, a) -> Just (PS p a, rp & rpPlacementUse +~ 1)
|
|
Nothing -> Nothing
|
|
|
|
rprBoolShift ::
|
|
(RoomPos -> Room -> Bool) ->
|
|
((Point2, Float) -> (Point2, Float)) ->
|
|
PlacementSpot
|
|
rprBoolShift t shift = PSPos f (const id) Nothing
|
|
where
|
|
f rp r
|
|
| t rp r = Just (PS p a, rp & rpPlacementUse +~ 1)
|
|
| otherwise = Nothing
|
|
where
|
|
(p, a) = shift (_rpPos rp, _rpDir rp)
|
|
|
|
unusedSpotAwayFromLink :: Float -> PlacementSpot
|
|
unusedSpotAwayFromLink x = rprBool $ \rp r ->
|
|
_rpLinkStatus rp == NotLink
|
|
&& _rpPlacementUse rp == 0
|
|
&& all ((> x) . dist (_rpPos rp)) (usedRoomLinkPoss r)
|
|
|
|
setFallback :: Placement -> Placement -> Placement
|
|
setFallback fallback =
|
|
(plSpot . psFallback %~ maybe (Just fallback) Just)
|
|
. ( plIDCont %~ fmap (fmap (fmap $ setFallback fallback))
|
|
)
|
|
|
|
unusedOffPathAwayFromLink :: Float -> PlacementSpot
|
|
unusedOffPathAwayFromLink x = rprBool $ \rp r ->
|
|
_rpPlacementUse rp == 0
|
|
&& all ((> x) . dist (_rpPos rp)) (usedRoomLinkPoss r)
|
|
&& rpIsOffPath rp
|
|
|
|
unusedSpotAwayFromInLink :: Float -> PlacementSpot
|
|
unusedSpotAwayFromInLink x = rprBool $ \rp r ->
|
|
_rpLinkStatus rp == NotLink
|
|
&& _rpPlacementUse rp == 0
|
|
&& all ((> x) . dist (_rpPos rp)) (usedRoomInLinkPoss r)
|
|
|
|
--twoUnusedLinks :: (PlacementSpot -> PlacementSpot -> Placement) -> Placement
|
|
--twoUnusedLinks = twoRoomPoss isUnusedLnk isUnusedLnk
|
|
|
|
twoRoomPoss ::
|
|
(RoomPos -> Room -> Bool) ->
|
|
(RoomPos -> Room -> Bool) ->
|
|
(PlacementSpot -> PlacementSpot -> Placement) ->
|
|
Placement
|
|
twoRoomPoss cond1 cond2 f = Placement (rprBool cond1) PutNothing Nothing $
|
|
\_ pl1 -> Just $
|
|
Placement (rprBool cond2) PutNothing Nothing $
|
|
\_ pl2 -> Just $ f (_plSpot pl1) (_plSpot pl2)
|
|
|
|
--isUnusedLnk :: RoomPos -> Bool
|
|
--isUnusedLnk rp = case _rpLinkStatus rp of
|
|
-- UnusedLink {} -> _rpPlacementUse rp == 0
|
|
-- _ -> False
|
|
|
|
isInLnk :: RoomPos -> Bool
|
|
isInLnk rp = case _rpLinkStatus rp of
|
|
UsedInLink{} -> _rpPlacementUse rp == 0
|
|
_ -> False
|
|
|
|
isOutLnk :: RoomPos -> Bool
|
|
isOutLnk rp = case _rpLinkStatus rp of
|
|
UsedOutLink{} -> _rpPlacementUse rp == 0
|
|
_ -> False
|
|
|
|
useUnusedLnk :: PlacementSpot
|
|
useUnusedLnk = rprBool isUnusedLnk
|
|
|
|
isUsedLnkUnplaced :: RoomPos -> Bool
|
|
isUsedLnkUnplaced rp = case _rpLinkStatus rp of
|
|
UsedOutLink{} -> _rpPlacementUse rp == 0
|
|
UsedInLink{} -> _rpPlacementUse rp == 0
|
|
_ -> False
|
|
|
|
useRoomPosCond :: (RoomPos -> Room -> Bool) -> RoomPos -> Room -> Maybe (PlacementSpot, RoomPos)
|
|
useRoomPosCond f = useRoomPosRoomCond $ \rp r -> f rp r
|
|
|
|
useRoomPosRoomCond :: (RoomPos -> Room -> Bool) -> RoomPos -> Room -> Maybe (PlacementSpot, RoomPos)
|
|
useRoomPosRoomCond t rp r
|
|
| t rp r = Just (PS (_rpPos rp) (_rpDir rp), rp & rpPlacementUse +~ 1)
|
|
| otherwise = Nothing
|
|
|
|
isUnusedLnkType :: RoomLinkType -> RoomPos -> Room -> Bool
|
|
isUnusedLnkType rlt rp _ = case _rpLinkStatus rp of
|
|
UnusedLink{_rplsType = rlts} -> rlt `S.member` rlts && _rpPlacementUse rp == 0
|
|
_ -> False
|
|
|
|
unusedSpotNearInLink :: Float -> PlacementSpot
|
|
unusedSpotNearInLink x = rprBool $ \rp r ->
|
|
_rpLinkStatus rp == NotLink
|
|
&& _rpPlacementUse rp == 0
|
|
&& any ((< x) . dist (_rpPos rp)) (usedRoomInLinkPoss r)
|
|
|
|
usedRoomInLinkPoss :: Room -> [Point2]
|
|
usedRoomInLinkPoss r = mapMaybe f $ _rmPos r
|
|
where
|
|
f rp = case _rpLinkStatus rp of
|
|
UsedInLink{} -> Just $ _rpPos rp
|
|
_ -> Nothing
|
|
|
|
usedRoomLinkPoss :: Room -> [Point2]
|
|
usedRoomLinkPoss r = mapMaybe f $ _rmPos r
|
|
where
|
|
f rp = case _rpLinkStatus rp of
|
|
UsedInLink{} -> Just $ _rpPos rp
|
|
UsedOutLink{} -> Just $ _rpPos rp
|
|
_ -> Nothing
|
|
|
|
atFstLnkOut :: PlacementSpot
|
|
atFstLnkOut = atNthLinkOut 0
|
|
|
|
atNthLinkOut :: Int -> PlacementSpot
|
|
atNthLinkOut n = rprBool $ \rp _ -> rp ^? rpLinkStatus . rplsChildNum == Just n
|
|
|
|
atNthLnkOutShiftBy :: Int -> ((Point2, Float) -> (Point2, Float)) -> PlacementSpot
|
|
atNthLnkOutShiftBy n = rprBoolShift $
|
|
\rp _ -> rp ^? rpLinkStatus . rplsChildNum == Just n
|
|
|
|
--atNthLnkOutShiftBy n theshift = PSPos f (const id) Nothing
|
|
-- where
|
|
-- f rp _ = case _rpLinkStatus rp of
|
|
-- UsedOutLink {_rplsChildNum = i} | i == n
|
|
-- -> Just (PS p a, rp & rpPlacementUse +~ 1)
|
|
-- _ -> Nothing
|
|
-- where
|
|
-- (p,a) = theshift (_rpPos rp,_rpDir rp)
|
|
|
|
atFstLnkOutShiftBy :: ((Point2, Float) -> (Point2, Float)) -> PlacementSpot
|
|
atFstLnkOutShiftBy = atNthLnkOutShiftBy 0
|
|
|
|
atFstLnkOutShiftInward :: Float -> PlacementSpot
|
|
atFstLnkOutShiftInward = atNthLnkOutShiftInward 0
|
|
|
|
atNthLnkOutShiftInward :: Int -> Float -> PlacementSpot
|
|
atNthLnkOutShiftInward n x = atNthLnkOutShiftBy n $
|
|
\(p, a) -> (p +.+ rotateV a (V2 0 (negate x)), a)
|
|
|
|
shiftInBy :: Float -> (Point2, Float) -> (Point2, Float)
|
|
shiftInBy x (p, a) = (p +.+ rotateV a (V2 0 (negate x)), a)
|
|
|
|
shiftByV2 :: Point2 -> (Point2, Float) -> (Point2, Float)
|
|
shiftByV2 x (p, a) = (p +.+ rotateV a x, a)
|
|
|
|
-- this should probably check the placement use, but so should others: should
|
|
-- unify these
|
|
useLnkRoomPos :: RoomPos -> Room -> Maybe (PlacementSpot, RoomPos)
|
|
useLnkRoomPos rp _ = case _rpLinkStatus rp of
|
|
UnusedLink{} -> Just (PS (_rpPos rp) (_rpDir rp), rp & rpPlacementUse +~ 1)
|
|
_ -> Nothing
|
|
|
|
psRandRanges :: (Float, Float) -> (Float, Float) -> (Float, Float) -> State StdGen (Point2, Float)
|
|
psRandRanges xranges yranges aranges = do
|
|
x <- state $ randomR xranges
|
|
y <- state $ randomR yranges
|
|
a <- state $ randomR aranges
|
|
return (V2 x y, a)
|