{-# LANGUAGE TupleSections #-} {- | Find which objects lie upon a line. -} module Dodge.WorldEvent.ThingsHit ( thingsHit, thingHit, thingHitFilt, thingsHitExceptCr, crsHitRadial, wlsHitRadial, crHit, ) where import Dodge.Creature.Radius import Control.Monad import Control.Lens import Data.Bifunctor import qualified Data.IntSet as IS import Data.List (sortOn) import Data.Maybe import Dodge.Base import Dodge.Data.World import Dodge.Zoning.Creature import Dodge.Zoning.Wall import Geometry import qualified ListHelp as List {- List those objects that appear on a line. -} thingsHit :: Point2 -> Point2 -> World -> [(Point2, Either Creature Wall)] thingsHit sp ep w = List.mergeOn (dist sp . fst) (map (second Left) (crsHit sp ep w)) (map (second Right) (wlsHit sp ep w)) crsHit :: Point2 -> Point2 -> World -> [(Point2, Creature)] crsHit sp ep w | sp == ep = mempty | otherwise = sortOn (dist sp . fst) . overlapSegCrs sp ep . mapMaybe (\cid -> w ^? cWorld . lWorld . creatures . ix cid) . IS.toList . crixsNearSeg sp ep $ w thingHitFilt :: (Creature -> Bool) -> (Wall -> Bool) -> Point2 -> Point2 -> World -> Maybe (Point2, Either Creature Wall) thingHitFilt fcr fwl sp ep = List.find (f . snd) . thingsHit sp ep where f (Left cr) = fcr cr f (Right wl) = fwl wl thingHit :: Point2 -> Point2 -> World -> Maybe (Point2, Either Creature Wall) thingHit sp ep = listToMaybe . thingsHit sp ep crHit :: Point2 -> Point2 -> World -> Maybe (Point2,Creature) --crHit sp ep = listToMaybe . sortOn (dist sp . fst) . crsHit sp ep crHit sp ep = listToMaybe . crsHit sp ep {- List objects that appear on a line. Can filter out a creature. -} thingsHitExceptCr :: -- | A possible creature ID Maybe Int -> -- | Line start point Point2 -> -- | Line end point Point2 -> World -> [(Point2, Either Creature Wall)] thingsHitExceptCr Nothing sp ep = thingsHit sp ep thingsHitExceptCr (Just cid) sp ep = filter t . thingsHit sp ep where t = (Just cid /=) . (^? _2 . _Left . crID) wlsHit :: Point2 -> Point2 -> World -> [(Point2, Wall)] wlsHit sp ep | sp == ep = const mempty | otherwise = sortOn (dist sp . fst) . overlapSegWalls sp ep . wlsNearSeg sp ep wlsHitRadial :: Point2 -> Float -> World -> [(Point2, Wall)] wlsHitRadial p r = mapMaybe f . wlsNearCirc p r where f wl = uncurry (intersectSegSeg p (p - r *.* v)) (_wlLine wl) <&> (,wl) where v = normalizeV . vNormal . uncurry (-) $ _wlLine wl crsHitRadial :: Point2 -> Float -> World -> [(Point2, Creature)] crsHitRadial p r = mapMaybe f . crsNearCirc p r where f cr = do let cp = _crPos cr guard $ dist p cp < r + crRad (_crType cr) return (cp + (1 + crRad (_crType cr)) *.* (cp - p), cr)