module Dodge.Humanoid where import Linear import Data.Maybe import Dodge.Creature.Action import Dodge.Creature import Dodge.Data.CreatureEffect import Dodge.Data.World import Geometry import LensHelp import RandomHelp updateHumanoid :: Creature -> World -> World updateHumanoid cr = case cr ^?! crType of ChaseCrit {} -> humanoidAIList [ const doStrategyActions , performActions , overrideMeleeCloseTarget , setViewPos , setMvPos , chaseCritMv , chaseCritPerceptionUpdate [0] , targetYouWhenCognizant , const searchIfDamaged , const (crType . meleeCooldown %~ max 0 . subtract 1) , const (crVocalization . vcCoolDown %~ max 0 . subtract 1) ] cr _ -> id -- SpreadGunAI -> -- defaultImpulsive -- [ performActions -- , watchUpdateStrat -- [ -- ( crHasTargetLOS -- , \_ _ -> -- StrategyActions -- (ShootAt 0) -- [ DoActionIf (WdCrNegate $ WdCrBlfromCrBl CrIsAiming) drawWeapon -- , DoActionThen -- (DoActionWhile WdCrLOSTarget $ ArbitraryAction ChooseMovementSpreadGun) -- (DoImpulses [ChangeStrategy WatchAndWait]) -- ] -- ) -- , (const crAwayFromPost, const goToPostStrat) -- ] -- , perceptionUpdate [0] -- , const doStrategyActions -- , targetYouWhenCognizant -- , const $ -- overrideInternal -- (\cr' -> crHasTarget cr' && crStratConMatches (GetTo (V2 0 0)) cr') -- (\cr' -> cr' & crActionPlan . apStrategy .~ WatchAndWait) -- ] -- cr -- PistolAI -> -- defaultImpulsive -- [ performActions -- , watchUpdateStrat -- [ -- ( crHasTargetLOS -- , \w cr' -> -- StrategyActions -- (ShootAt 0) -- [DoActionIf (WdCrNegate $ WdCrBlfromCrBl CrIsAiming) drawWeapon, chooseMovementPistol cr' w] -- ) -- , (const crAwayFromPost, const goToPostStrat) -- ] -- , perceptionUpdate [0] -- , const doStrategyActions -- , targetYouWhenCognizant -- , const $ -- overrideInternal -- (\cr' -> crHasTarget cr' && crStratConMatches (GetTo (V2 0 0)) cr') -- (crActionPlan . apStrategy .~ WatchAndWait) -- ] -- cr -- LtAutoAI -> -- defaultImpulsive -- [ performActions -- , watchUpdateStrat -- [ -- ( crHasTargetLOS -- , \_ _ -> -- StrategyActions -- (ShootAt 0) -- [ DoActionIf (WdCrNegate $ WdCrBlfromCrBl CrIsAiming) drawWeapon -- , DoActionThen -- (DoActionWhile WdCrLOSTarget $ ArbitraryAction ChooseMovementLtAuto) -- (DoImpulses [ChangeStrategy WatchAndWait]) -- ] -- ) -- , (const crAwayFromPost, const goToPostStrat) -- ] -- , perceptionUpdate [0] -- , const doStrategyActions -- , targetYouWhenCognizant -- , const $ -- overrideInternal -- (\cr' -> crHasTarget cr' && crStratConMatches (GetTo (V2 0 0)) cr') -- (crActionPlan . apStrategy .~ WatchAndWait) -- ] -- cr -- LauncherAI -> -- defaultImpulsive -- [ performActions -- , watchUpdateStrat -- [ (crHasTargetLOS, \_ _ -> StrategyActions (ShootAt 0) [retreatFireLauncher]) -- , (const crAwayFromPost, const goToPostStrat) -- ] -- , perceptionUpdate [0] -- , const doStrategyActions -- , targetYouWhenCognizant -- , const $ -- overrideInternal -- (\cr' -> crHasTarget cr' && crStratConMatches (GetTo (V2 0 0)) cr') -- (crActionPlan . apStrategy .~ WatchAndWait) -- ] -- cr -- SwarmAI -> -- defaultImpulsive -- [ flockToPointUsing' (encircleDistP 100) (meleeHeadingMove 0.1 0.1 (pi / 4) 3.9) -- , const (crMeleeCooldown %~ max 0 . subtract 1) -- , perceptionUpdate [0] -- , const doStrategyActions -- , targetYouWhenCognizant -- ] -- cr -- AutoAI -> defaultImpulsive [sentinelAI] cr -- FlockArmourChaseAI -> -- defaultImpulsive -- [ watchUpdateStrat [] -- , const doStrategyActions -- , performActions -- , targetYouWhenCognizant -- , setTargetMv (\_ -> _targetCr . _crIntention) -- , flockACC -- , perceptionUpdate [0] -- , goToTarget -- , const overrideMeleeCloseTarget -- , const (crMeleeCooldown %~ max 0 . subtract 1) -- ] -- cr -- MiniGunAI -> defaultImpulsive [sentinelFireType (const shootTillEmpty)] cr -- LongAI -> defaultImpulsive [sentinelFireType $ const shootTillEmpty] cr -- MultGunAI -> -- defaultImpulsive -- [ sentinelExtraWatchUpdate -- [ ---- ( const $ not . crWeaponReady ---- , \_ _ -> StrategyActions Reload reloadActions ---- ) ---- , -- ( const $ not . crSafeDistFromTarg 150 -- , \_ _ -> -- StrategyActions -- Flee -- [ WdCrNegate (WdCrSafeDistFromTarget 150) `DoActionWhile` UseSelf CrFleeFromTarget -- (fleeFrom cr') -- `DoActionThen` DoImpulses [ChangeStrategy WatchAndWait] -- ] -- ) -- , -- ( crHasTargetLOS -- , \_ _ -> -- StrategyActions -- (ShootAt 0) -- [drawwp `DoActionThen` shootFirstMiss `DoActionThen` DoImpulses [ChangeStrategy WatchAndWait]] -- ) -- ] -- ] -- cr -- InanimateAI -> id -- where -- drawwp = DoActionIfElse NoAction (WdCrBlfromCrBl CrIsAiming) (DoActionThen drawWeapon (WaitThen 50 NoAction)) -- reloadActions = -- [ holsterWeapon -- --, WaitThen 1 $ DoActionWhileInterrupt NoAction (WdCrBlfromCrBl CrIsReloading) (DoImpulses [ChangeStrategy WatchAndWait]) -- , WaitThen 1 $ (DoImpulses [ChangeStrategy WatchAndWait]) -- ] humanoidAIList :: [World -> Creature -> Creature] -> Creature -> World -> World humanoidAIList = impulsiveAIBefore . chainCreatureUpdates ---- bit of a hack to get new random generators after each creature's update --defaultImpulsive :: -- [World -> Creature -> Creature] -> -- Creature -> -- World -> -- World --defaultImpulsive -- = fmap (fmap updateRandGen) . crUpdate . impulsiveAIBefore . chainCreatureUpdates -- where -- updateRandGen w = -- let (_, g) = randomR (0, 1 :: Int) (_randGen w) -- in w & randGen .~ g chooseMovementPistol :: Creature -> World -> Action chooseMovementPistol cr w = chooseMovementPistol' cr w `DoActionThen` DoImpulses [ChangeStrategy WatchAndWait] chooseMovementPistol' :: Creature -> World -> Action chooseMovementPistol' cr w = takeOneWeighted [chargeProb, retreatProb, strafeProb, strafeProb] [ chargeActions , retreatActionsPistol ycr cr , strafeLeftActions , strafeRightActions ] & evalState $ g where g = _randGen w cpos = cr ^. crPos . _xy ycr = w ^?! cWorld . lWorld . creatures . ix 0 ypos = ycr ^. crPos . _xy chargeProb | dist cpos ypos > 300 = 5 | dist cpos ypos > 150 = 1 | otherwise = 0 strafeProb | dist cpos ypos > 150 = 1 | otherwise = 0 retreatProb | dist cpos ypos < 200 = 1 :: Float | otherwise = 0 chargeActions = [TurnToward ypos 0.1] `DoImpulsesAlongside` 3 `DoReplicate` ImpulsesList (replicate 9 [Move (V2 3 0)] ++ [[Move (V2 3 0), UseItem]]) strafeLeftActions = DoImpulses [TurnToward yposr (2 * pi)] `DoActionThen` 3 `DoReplicate` ImpulsesList (replicate 9 [Move (V2 0 3)] ++ [[Move (V2 0 3), UseItem]]) strafeRightActions = DoImpulses [TurnToward yposl (2 * pi)] `DoActionThen` 3 `DoReplicate` ImpulsesList (replicate 9 [Move (V2 0 (-3))] ++ [[Move (V2 0 (-3)), UseItem]]) yposl = ypos -.- 100 *.* vNormal (normalizeV $ ypos -.- cpos) yposr = ypos +.+ 100 *.* vNormal (normalizeV $ ypos -.- cpos) retreatActionsPistol :: Creature -> Creature -> Action retreatActionsPistol tcr cr = [TurnToward retreatOffset 0.2] `DoImpulsesAlongside` 3 `DoReplicate` ImpulsesList (replicate 9 [Move (V2 (-3) 0)] ++ [[UseItem]]) where cpos = cr ^. crPos . _xy tpos = tcr ^. crPos . _xy retreatOffset = let a | dist cpos tpos < 50 = 0 | isLeftOfA (_crDir cr) (argV $ tpos -.- cpos) = -0.7 | otherwise = 0.7 in fromMaybe tpos $ intersectLineLine cpos (cpos +.+ rotateV a (tpos -.- cpos)) tpos (tpos +.+ vNormal (cpos -.- tpos)) retreatFireLauncher :: Action retreatFireLauncher = ImpulsesList ([UseItem] : replicate 20 [Turn 0.16]) `DoActionThen` holsterWeapon `DoActionThen` ImpulsesList (replicate 30 [MoveForward 3]) `DoActionThen` drawWeapon `DoActionThen` ImpulsesList ([UseItem] : replicate 20 [Turn $ negate 0.16]) `DoActionThen` holsterWeapon `DoActionThen` ImpulsesList (replicate 15 [MoveForward 3]) `DoActionThen` drawWeapon `DoActionThen` ImpulsesList ( replicate 100 [ UseItem , ImpulseUseTarget (TurnTowardCr (pi / 16)) ] ) `DoActionThen` 20 `WaitThen` holsterWeapon `DoActionThen` ImpulsesList (replicate 15 [MoveForward 3]) `DoActionThen` DoImpulses [ChangeStrategy WatchAndWait]