module Dodge.Humanoid where 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 . humanoidAI of ChaseAI -> humanoidAIList [ const doStrategyActions , performActions , const overrideMeleeCloseTarget , setViewPos , setMvPos , chaseCritMv , chaseCritPerceptionUpdate [0] , targetYouWhenCognizant , const searchIfDamaged , const (crMeleeCooldown %~ max 0 . subtract 1) , const (crVocalization . vcCoolDown %~ max 0 . subtract 1) ] cr 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 YourAI -> crUpdate yourControl 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 = crUpdate . 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 = _crPos cr ycr = w ^?! cWorld . lWorld . creatures . ix 0 ypos = _crPos ycr 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 = _crPos cr tpos = _crPos tcr 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]