Files
loop/src/Dodge/Creature/ReaderUpdate.hs
T
2022-06-28 12:26:37 +01:00

175 lines
6.1 KiB
Haskell

{- | Functions updating a creature in a Reader World environment -}
module Dodge.Creature.ReaderUpdate
( doStrategyActions
, setTargetMv
, targetYouWhenCognizant
, overrideMeleeCloseTarget
, watchUpdateStrat
, reloadOverride
, overrideInternal
, turnIfDamaged
, goToTarget
, flockACC
, chaseCritMv
, setMvPos
, setViewPos
) where
import Dodge.Data
import Dodge.Creature.Test
import Dodge.Creature.Volition
import Dodge.Base
import Dodge.Zone
import Geometry
import qualified Data.IntMap.Strict as IM
import Control.Lens
import Control.Applicative
import Data.Maybe
import Data.Bifunctor
--import StreamingHelp
import qualified Streaming.Prelude as S
overrideMeleeCloseTarget :: Creature -> Creature
overrideMeleeCloseTarget cr = maybe cr (tryMeleeAttack cr) (_targetCr $ _crIntention cr)
tryMeleeAttack :: Creature -> Creature -> Creature
tryMeleeAttack cr tcr
| _crMeleeCooldown cr == 0
&& dist (_crPos tcr) cpos < _crRad cr + _crRad tcr + 5
&& abs (_crDir cr - argV (_crPos tcr -.- cpos)) < pi/4
= cr & crActionPlan . crImpulse .~ [Melee $ _crID tcr]
| otherwise = cr
where
cpos = _crPos cr
setMvPos :: World -> Creature -> Creature
setMvPos w cr = cr & crIntention . mvToPoint .~ mpos
where
int = _crIntention cr
mtpos = do
tpos <- _crPos <$> _targetCr int
if hasLOS (_crPos cr) tpos w
then Just tpos
else Nothing
mpos = mtpos
<|> _mvToPoint int
-- <|> listToMaybe (_soundsToInvestigate $ _crMemory cr)
setViewPos :: Creature -> Creature
setViewPos cr = cr & crIntention . viewPoint %~ (<|> mpos)
where
mpos = listToMaybe (_soundsToInvestigate $ _crMemory cr)
setTargetMv :: (World -> Creature -> Maybe Creature) -- ^ Function for determining target
-> World -> Creature -> Creature
setTargetMv targFunc w cr = maybe
cr
(\ctarg -> cr & crIntention . mvToPoint ?~ _crPos ctarg)
(targFunc w cr)
-- ugly
flockACC :: World -> Creature -> Creature
flockACC w cr = case cr ^? crIntention . targetCr . _Just of
Nothing -> cr
Just tcr ->
let tpos = _crPos tcr
cpos = _crPos cr
isFarACC cr' = _crGroup cr' == _crGroup cr
&& _crID cr' /= _crID cr
&& dist (_crPos cr') tpos > dist cpos tpos
macr = minStreamOn (dist cpos . _crPos) . S.filter isFarACC $ crsInsideCirc cpos 50 w
in case macr of
Nothing -> cr
Just acr ->
let r = _crRad acr + _crRad cr + 10
horDir = normalizeV (vNormal (cpos -.- tpos))
horShift = if isLHS tpos cpos (_crPos acr)
then r *.* horDir
else negate r *.* horDir
in cr & crIntention . mvToPoint ?~ tpos +.+ horShift
chaseCritMv :: World -> Creature -> Creature
chaseCritMv w cr = case _crStrategy (_crActionPlan cr) of
StrategyActions _ _ -> cr
WarningCry -> cr
_ -> case cr ^? crIntention . mvToPoint . _Just of
Just p -> cr & crActionPlan . crAction .~ [PathTo p]
_ -> viewTarget w cr
goToTarget :: World -> Creature -> Creature
goToTarget w cr =
case cr ^? crIntention . mvToPoint . _Just of
Just p -> cr & crActionPlan . crAction .~ [PathTo p]
_ -> viewTarget w cr
viewTarget :: World -> Creature -> Creature
viewTarget w cr = do
case cr ^? crIntention . viewPoint . _Just of
Just p | hasLOSIndirect p (_crPos cr) w -> cr'
& crActionPlan . crAction %~ replaceNullWith (TurnToA p)
& crIntention . viewPoint .~ Nothing
| otherwise -> cr' & crActionPlan . crAction %~ replaceNullWith (PathTo p)
Nothing -> cr-- & crPerception . crAwakeLevel .~ Lethargic
where
cr' = cr & crPerception . cpVigilance .~ Vigilant
replaceNullWith :: a -> [a] -> [a]
replaceNullWith x [] = [x]
replaceNullWith _ xs = xs
doStrategyActions :: Creature -> Creature
doStrategyActions cr = case cr ^? crActionPlan . crStrategy of
Just (StrategyActions strat acs) -> cr & crActionPlan . crAction .~ acs
& crActionPlan . crStrategy .~ strat
_ -> cr
reloadOverride :: Creature -> Creature
reloadOverride cr
| cr ^? crInv . ix (crSel cr) . itConsumption . laLoaded == Just 0
&& cr ^. crStance . posture == Aiming
= cr & crActionPlan . crStrategy .~ StrategyActions Reload reloadActions
| otherwise = cr
where
reloadActions =
[ holsterWeapon
, 1 `WaitThen`
DoActionWhileInterrupt NoAction (const crIsReloading)
(DoImpulses [ChangeStrategy WatchAndWait])
]
overrideInternal :: (Creature -> Bool) -> (Creature -> Creature) -> Creature -> Creature
overrideInternal test update cr
| test cr = update cr
| otherwise = cr
watchUpdateStrat
:: [ (World -> Creature -> Bool, World -> Creature -> Strategy) ]
-> World
-> Creature
-> Creature
watchUpdateStrat fs w cr = case cr ^? crActionPlan . crStrategy of
Just WatchAndWait -> cr
& crActionPlan . crStrategy .~ listGuard (map (first uncurry) fs, \_ _ -> WatchAndWait) (w, cr) w cr
_ -> cr
listGuard :: ([(a -> Bool, b)] , b) -> a -> b
listGuard ( (test,y):ps, z ) x
| test x = y
| otherwise = listGuard (ps, z) x
listGuard (_,z) _ = z
targetYouWhenCognizant :: World -> Creature -> Creature
targetYouWhenCognizant w cr = case cr ^? crPerception . cpAwareness . ix 0 of
-- so this caused a space leak: be careful with ?~
-- consider changing targeted creature to be just an index
Just (Cognizant _) -> _creatures w IM.! 0 `seq` cr & crIntention . targetCr ?~ _creatures w IM.! 0
_ -> cr & crIntention . targetCr .~ Nothing
turnIfDamaged :: Creature -> Creature
turnIfDamaged cr
| _crPastDamage cr > 0 = case _crStrategy (_crActionPlan cr) of
WatchAndWait -> cr & crPerception . cpVigilance .~ Vigilant
& crActionPlan . crStrategy .~ StrategyActions LookAround [TurnToA (_crPos cr -.- unitVectorAtAngle (_crDir cr))]
_ -> cr
| otherwise = cr