106 lines
2.9 KiB
Haskell
106 lines
2.9 KiB
Haskell
{-# 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)
|