{-# LANGUAGE GADTs #-}
module Game.LambdaHack.Client.AI
( queryAI
#ifdef EXPOSE_INTERNAL
, pickAI, pickAction, udpdateCondInMelee, condInMeleeM
#endif
) where
import Prelude ()
import Game.LambdaHack.Common.Prelude
import qualified Data.EnumMap.Strict as EM
import Game.LambdaHack.Client.AI.HandleAbilityM
import Game.LambdaHack.Client.AI.PickActorM
import Game.LambdaHack.Client.AI.Strategy
import Game.LambdaHack.Client.MonadClient
import Game.LambdaHack.Client.State
import Game.LambdaHack.Common.Actor
import Game.LambdaHack.Common.ActorState
import Game.LambdaHack.Common.Faction
import Game.LambdaHack.Common.Frequency
import Game.LambdaHack.Common.MonadStateRead
import Game.LambdaHack.Common.Point
import Game.LambdaHack.Common.Random
import Game.LambdaHack.Common.Request
import Game.LambdaHack.Common.State
queryAI :: MonadClient m => ActorId -> m RequestAI
queryAI aid = do
side <- getsClient sside
mleader <- getsState $ _gleader . (EM.! side) . sfactionD
mleaderCli <- getsClient _sleader
unless (Just aid == mleader || mleader == mleaderCli) $
modifyClient $ \cli -> cli {_sleader = mleader}
udpdateCondInMelee aid
(aidToMove, treq) <- pickAI Nothing aid
(aidToMove2, treq2) <-
case treq of
RequestAnyAbility ReqWait | mleader == Just aid -> do
modifyClient $ \cli -> cli {_sleader = mleader}
pickAI (Just (aidToMove, treq)) aid
_ -> return (aidToMove, treq)
return ( ReqAITimed treq2
, if aidToMove2 /= aid then Just aidToMove2 else Nothing )
pickAI :: MonadClient m
=> Maybe (ActorId, RequestAnyAbility) -> ActorId
-> m (ActorId, RequestAnyAbility)
{-# INLINE pickAI #-}
pickAI maid aid = do
mleader <- getsClient _sleader
aidToMove <-
if mleader == Just aid
then pickActorToMove (fst <$> maid)
else do
useTactics aid
return aid
treq <- case maid of
Just (aidOld, treqOld) | aidToMove == aidOld ->
return treqOld
_ -> pickAction aidToMove (isJust maid)
return (aidToMove, treq)
pickAction :: MonadClient m => ActorId -> Bool -> m RequestAnyAbility
{-# INLINE pickAction #-}
pickAction aid retry = do
side <- getsClient sside
body <- getsState $ getActorBody aid
let !_A = assert (bfid body == side
`blame` "AI tries to move enemy actor"
`swith` (aid, bfid body, side)) ()
let !_A = assert (isNothing (btrajectory body)
`blame` "AI gets to manually move its projectiles"
`swith` (aid, bfid body, side)) ()
stratAction <- actionStrategy aid retry
let bestAction = bestVariant stratAction
!_A = assert (not (nullFreq bestAction)
`blame` "no AI action for actor"
`swith` (stratAction, aid, body)) ()
rndToAction $ frequency bestAction
udpdateCondInMelee :: MonadClient m => ActorId -> m ()
udpdateCondInMelee aid = do
b <- getsState $ getActorBody aid
condInMelee <- getsClient $ (EM.! blid b) . scondInMelee
case condInMelee of
Just{} -> return ()
Nothing -> do
newCond <- condInMeleeM b
modifyClient $ \cli ->
cli {scondInMelee =
EM.adjust (const $ Just newCond) (blid b) (scondInMelee cli)}
condInMeleeM :: MonadClient m => Actor -> m Bool
condInMeleeM bodyOur = do
fact <- getsState $ (EM.! bfid bodyOur) . sfactionD
let f !b = blid b == blid bodyOur && isAtWar fact (bfid b) && bhp b > 0
allFoes <- getsState $ filter f . EM.elems . sactorD
getsState $ any (\body ->
bfid bodyOur == bfid body
&& blid bodyOur == blid body
&& not (bproj body)
&& bhp body > 0
&& any (\b -> adjacent (bpos b) (bpos body)) allFoes) . sactorD