{- | Module testing for properties of creatures, whether they are reloading, etc. Each function takes a creature, and possibly other parameters, and returns a bool. Note that if there is a world parameter, the creature NEED NOT be the same as the creature with that id in the world, in fact a creature with that id need not exist. -} module Dodge.Creature.Test ( crIsAiming, -- crIsReloading, crIsArmouredFrom, oneH, twists, twoFlat, -- crWeaponReady, crInAimStance, crNearPoint, isAnimate, -- crCanShoot, crHasTargetLOS, crAwayFromPost, crHasTarget, crStratConMatches, crSafeDistFromTarg, hasAutoDoorBody, ) where import Linear import NewInt import qualified Data.IntMap.Strict as IM import Dodge.Creature.Radius import Dodge.Data.Equipment.Misc import Dodge.Data.AimStance import Control.Lens import Data.List (find) import Data.Maybe import Dodge.Base.Collide import Dodge.Data.World import Geometry --crIsReloading :: Creature -> Bool --crIsReloading cr = case cr ^? crManipulation . manObject . inInventory . iselAction of -- Just ReloadAction{} -> True -- _ -> False ---- Assumes the ammotype below the selected item is correct --crWeaponReady :: Creature -> Bool --crWeaponReady cr = fromMaybe False $ do -- i <- cr ^? crManipulation . manObject . inInventory . ispItem -- x <- cr ^? crInv . ix (i + 1) . itUse . amagLoadStatus . iaLoaded -- return (x > 0) crCanSeeCr :: Creature -> (World, Creature) -> Bool crCanSeeCr tcr (w, cr) = hasLOS (cr ^. crPos . _xy) (tcr ^. crPos . _xy) w --crCanSeeCrid :: Int -> (World, Creature) -> Bool --crCanSeeCrid tcid (w, cr) = fromMaybe False $ do -- tcr <- w ^? cWorld . lWorld . creatures . ix tcid -- return $ hasLOS (_crPos cr) (_crPos tcr) w crIsAiming :: Creature -> Bool crIsAiming cr = case _posture (_crStance cr) of Aiming {} -> True _ -> False crHasTarget :: Creature -> Bool crHasTarget cr = isJust $ cr ^? crIntention . targetCr . _Just crHasTargetLOS :: World -> Creature -> Bool crHasTargetLOS w cr = fromMaybe False $ do i <- cr ^. crIntention . targetCr tcr <- w ^? cWorld . lWorld . creatures . ix i return $ crCanSeeCr tcr (w, cr) crSafeDistFromTarg :: World -> Float -> Creature -> Bool crSafeDistFromTarg w d cr = fromMaybe True $ do i <- cr ^? crIntention . targetCr . _Just tcr <- w ^? cWorld . lWorld . creatures . ix i return $ dist (cr ^. crPos . _xy) (tcr ^. crPos . _xy) > d crStratConMatches :: Strategy -> Creature -> Bool crStratConMatches strat cr = strat == _apStrategy (_crActionPlan cr) -- this equality check might be slow... crAwayFromPost :: Creature -> Bool crAwayFromPost cr = case find sentinelGoal . _apGoal $ _crActionPlan cr of Just (SentinelAt p _) -> dist p (cr ^. crPos . _xy) > 15 _ -> False where sentinelGoal (SentinelAt _ _) = True sentinelGoal _ = False crInAimStance :: AimStance -> Creature -> Bool crInAimStance as cr = cr ^? crStance . posture . aimStance == Just as oneH :: Creature -> Bool oneH = crInAimStance OneHand twoFlat :: Creature -> Bool twoFlat = crInAimStance TwoHandFlat twists :: Creature -> Bool twists cr = crInAimStance TwoHandUnder cr || crInAimStance TwoHandOver cr -- the use of crOldPos is because the damage position is calculated on the -- previous frame -- Not sure if it is a good idea crIsArmouredFrom :: IM.IntMap Item -> Point2 -> Creature -> Bool crIsArmouredFrom m p cr = fromMaybe False $ do NInt itid <- cr ^? crEquipment . ix OnChest ittype <- m ^? ix itid . itType return $ EQUIP FRONTARMOUR == ittype && p /= ( cr ^. crOldPos . _xy) && angleVV (unitVectorAtAngle (_crDir cr + frontarmdirection)) (p -.- (cr ^. crOldPos . _xy)) < pi / 2 where -- even though angleVV can generate NaN, the comparison seems to deal with it frontarmdirection | crInAimStance OneHand cr = 0.5 | crInAimStance TwoHandUnder cr = negate 1 | crInAimStance TwoHandOver cr = negate 1 | otherwise = 0 --crOnSeg :: Point2 -> Point2 -> Creature -> Bool --crOnSeg p1 p2 cr = circOnSeg p1 p2 (_crPos cr) (_crRad cr) --crNearSeg :: Float -> Point2 -> Point2 -> Creature -> Bool --crNearSeg d p1 p2 cr = circOnSeg p1 p2 (_crPos cr) (_crRad cr + d) crNearPoint :: Float -> Point2 -> Creature -> Bool crNearPoint d p cr = dist (cr ^. crPos . _xy) p < d + crRad (cr ^. crType) isAnimate :: Creature -> Bool {-# INLINE isAnimate #-} isAnimate cr = case _crActionPlan cr of Inanimate -> False _ -> True hasAutoDoorBody :: Creature -> Bool hasAutoDoorBody cr = case cr ^. crHP of HP {} -> True CrIsCorpse {} -> True CrIsGibs -> False CrIsPitted -> False