Files
loop/src/Dodge/WorldEvent/ThingsHit.hs
T
2025-06-20 23:11:40 +01:00

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)