{-# LANGUAGE TupleSections #-}
module Game.LambdaHack.Client.AI.PickTargetM
( refreshTarget
#ifdef EXPOSE_INTERNAL
, computeTarget
#endif
) where
import Prelude ()
import Game.LambdaHack.Core.Prelude
import qualified Data.EnumMap.Strict as EM
import qualified Data.EnumSet as ES
import Game.LambdaHack.Client.AI.ConditionM
import Game.LambdaHack.Client.Bfs
import Game.LambdaHack.Client.BfsM
import Game.LambdaHack.Client.CommonM
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.Item
import Game.LambdaHack.Common.Kind
import Game.LambdaHack.Common.Level
import Game.LambdaHack.Common.MonadStateRead
import Game.LambdaHack.Common.Point
import qualified Game.LambdaHack.Common.PointArray as PointArray
import Game.LambdaHack.Common.State
import qualified Game.LambdaHack.Common.Tile as Tile
import Game.LambdaHack.Common.Time
import Game.LambdaHack.Common.Types
import Game.LambdaHack.Common.Vector
import qualified Game.LambdaHack.Content.CaveKind as CK
import Game.LambdaHack.Content.FactionKind
import Game.LambdaHack.Content.RuleKind
import Game.LambdaHack.Content.TileKind (isUknownSpace)
import Game.LambdaHack.Core.Frequency
import Game.LambdaHack.Core.Random
import qualified Game.LambdaHack.Definition.Ability as Ability
refreshTarget :: MonadClient m
=> [(ActorId, Actor)] -> [(ActorId, Actor)] -> (ActorId, Actor)
-> m (Maybe TgtAndPath)
refreshTarget :: forall (m :: * -> *).
MonadClient m =>
[(ActorId, Actor)]
-> [(ActorId, Actor)] -> (ActorId, Actor) -> m (Maybe TgtAndPath)
refreshTarget [(ActorId, Actor)]
foeAssocs [(ActorId, Actor)]
friendAssocs (ActorId
aid, Actor
body) = do
side <- (StateClient -> FactionId) -> m FactionId
forall a. (StateClient -> a) -> m a
forall (m :: * -> *) a.
MonadClientRead m =>
(StateClient -> a) -> m a
getsClient StateClient -> FactionId
sside
let !_A = Bool -> () -> ()
forall a. (?callStack::CallStack) => Bool -> a -> a
assert (Actor -> FactionId
bfid Actor
body FactionId -> FactionId -> Bool
forall a. Eq a => a -> a -> Bool
== FactionId
side
Bool -> (String, (ActorId, Actor, FactionId)) -> Bool
forall v. Show v => Bool -> v -> Bool
`blame` String
"AI tries to move an enemy actor"
String
-> (ActorId, Actor, FactionId)
-> (String, (ActorId, Actor, FactionId))
forall v. String -> v -> (String, v)
`swith` (ActorId
aid, Actor
body, FactionId
side)) ()
let !_A = Bool -> () -> ()
forall a. (?callStack::CallStack) => Bool -> a -> a
assert (Bool -> Bool
not (Actor -> Bool
bproj Actor
body)
Bool -> (String, (ActorId, Actor, FactionId)) -> Bool
forall v. Show v => Bool -> v -> Bool
`blame` String
"AI gets to manually move its projectiles"
String
-> (ActorId, Actor, FactionId)
-> (String, (ActorId, Actor, FactionId))
forall v. String -> v -> (String, v)
`swith` (ActorId
aid, Actor
body, FactionId
side)) ()
mtarget <- computeTarget foeAssocs friendAssocs aid
case mtarget of
Maybe TgtAndPath
Nothing -> do
(StateClient -> StateClient) -> m ()
forall (m :: * -> *).
MonadClient m =>
(StateClient -> StateClient) -> m ()
modifyClient ((StateClient -> StateClient) -> m ())
-> (StateClient -> StateClient) -> m ()
forall a b. (a -> b) -> a -> b
$ \StateClient
cli -> StateClient
cli {stargetD = EM.delete aid (stargetD cli)}
Maybe TgtAndPath -> m (Maybe TgtAndPath)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe TgtAndPath
forall a. Maybe a
Nothing
Just TgtAndPath
tgtMPath -> do
(StateClient -> StateClient) -> m ()
forall (m :: * -> *).
MonadClient m =>
(StateClient -> StateClient) -> m ()
modifyClient ((StateClient -> StateClient) -> m ())
-> (StateClient -> StateClient) -> m ()
forall a b. (a -> b) -> a -> b
$ \StateClient
cli ->
StateClient
cli {stargetD = EM.insert aid tgtMPath (stargetD cli)}
Maybe TgtAndPath -> m (Maybe TgtAndPath)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe TgtAndPath
mtarget
computeTarget :: forall m. MonadClient m
=> [(ActorId, Actor)] -> [(ActorId, Actor)] -> ActorId
-> m (Maybe TgtAndPath)
computeTarget :: forall (m :: * -> *).
MonadClient m =>
[(ActorId, Actor)]
-> [(ActorId, Actor)] -> ActorId -> m (Maybe TgtAndPath)
computeTarget [(ActorId, Actor)]
foeAssocs [(ActorId, Actor)]
friendAssocs ActorId
aid = do
cops@COps{cocave, corule=RuleContent{rWidthMax, rHeightMax, rnearby}, coTileSpeedup}
<- (State -> COps) -> m COps
forall a. (State -> a) -> m a
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState State -> COps
scops
b <- getsState $ getActorBody aid
mleader <- getsClient sleader
salter <- getsClient salter
actorMaxSkills <- getsState sactorMaxSkills
condInMelee <- condInMeleeM $ blid b
let lalter = AlterLid
salter AlterLid -> LevelId -> Array Word8
forall k a. Enum k => EnumMap k a -> k -> a
EM.! Actor -> LevelId
blid Actor
b
actorMaxSk = ActorMaxSkills
actorMaxSkills ActorMaxSkills -> ActorId -> Skills
forall k a. Enum k => EnumMap k a -> k -> a
EM.! ActorId
aid
alterSkill = Skill -> Skills -> Int
Ability.getSk Skill
Ability.SkAlter Skills
actorMaxSk
lvl <- getLevel $ blid b
localTime <- getsState $ getLocalTime (blid b)
let stepAccesible :: [Point] -> Bool
stepAccesible (Point
q : [Point]
_) =
Int
alterSkill Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8 -> Int
forall a. Enum a => a -> Int
fromEnum (Array Word8
lalter Array Word8 -> Point -> Word8
forall c. UnboxRepClass c => Array c -> Point -> c
PointArray.! Point
q)
stepAccesible [] = Bool
False
mtgtMPath <- getsClient $ EM.lookup aid . stargetD
oldTgtUpdatedPath <- case mtgtMPath of
Just TgtAndPath{Target
tapTgt :: Target
tapTgt :: TgtAndPath -> Target
tapTgt,tapPath :: TgtAndPath -> Maybe AndPath
tapPath=Maybe AndPath
Nothing} ->
TgtAndPath -> Maybe TgtAndPath
forall a. a -> Maybe a
Just (TgtAndPath -> Maybe TgtAndPath)
-> m TgtAndPath -> m (Maybe TgtAndPath)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ActorId -> Target -> m TgtAndPath
forall (m :: * -> *).
MonadClient m =>
ActorId -> Target -> m TgtAndPath
createPath ActorId
aid Target
tapTgt
Just tap :: TgtAndPath
tap@TgtAndPath{Target
tapTgt :: TgtAndPath -> Target
tapTgt :: Target
tapTgt,tapPath :: TgtAndPath -> Maybe AndPath
tapPath=Just AndPath{Int
[Point]
Point
pathSource :: Point
pathList :: [Point]
pathGoal :: Point
pathLen :: Int
pathLen :: AndPath -> Int
pathGoal :: AndPath -> Point
pathList :: AndPath -> [Point]
pathSource :: AndPath -> Point
..}} -> do
mvalidPos <- (State -> Maybe Point) -> m (Maybe Point)
forall a. (State -> a) -> m a
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Maybe Point) -> m (Maybe Point))
-> (State -> Maybe Point) -> m (Maybe Point)
forall a b. (a -> b) -> a -> b
$ Maybe ActorId -> LevelId -> Maybe Target -> State -> Maybe Point
aidTgtToPos (ActorId -> Maybe ActorId
forall a. a -> Maybe a
Just ActorId
aid) (Actor -> LevelId
blid Actor
b) (Target -> Maybe Target
forall a. a -> Maybe a
Just Target
tapTgt)
return $!
if | isNothing mvalidPos -> Nothing
| bpos b == pathGoal ->
mtgtMPath
| pathSource == bpos b ->
if stepAccesible pathList then mtgtMPath else Nothing
| otherwise -> case break (== bpos b) pathList of
([Point]
crossed, Point
_ : [Point]
rest) ->
if [Point] -> Bool
forall a. [a] -> Bool
null [Point]
rest
then Maybe TgtAndPath
forall a. Maybe a
Nothing
else let newPath :: AndPath
newPath =
AndPath{ pathSource :: Point
pathSource = Actor -> Point
bpos Actor
b
, pathList :: [Point]
pathList = [Point]
rest
, Point
pathGoal :: Point
pathGoal :: Point
pathGoal
, pathLen :: Int
pathLen = Int
pathLen Int -> Int -> Int
forall a. Num a => a -> a -> a
- [Point] -> Int
forall a. [a] -> Int
length [Point]
crossed Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1 }
in if [Point] -> Bool
stepAccesible [Point]
rest
then TgtAndPath -> Maybe TgtAndPath
forall a. a -> Maybe a
Just TgtAndPath
tap{tapPath=Just newPath}
else Maybe TgtAndPath
forall a. Maybe a
Nothing
([Point]
_, []) -> Maybe TgtAndPath
forall a. Maybe a
Nothing
Maybe TgtAndPath
Nothing -> Maybe TgtAndPath -> m (Maybe TgtAndPath)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe TgtAndPath
forall a. Maybe a
Nothing
factionD <- getsState sfactionD
seps <- getsClient seps
let fact = FactionDict
factionD FactionDict -> FactionId -> Faction
forall k a. Enum k => EnumMap k a -> k -> a
EM.! Actor -> FactionId
bfid Actor
b
slackDoctrine = Faction -> Doctrine
gdoctrine Faction
fact
Doctrine -> [Doctrine] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [ Doctrine
Ability.TMeleeAndRanged, Doctrine
Ability.TMeleeAdjacent
, Doctrine
Ability.TBlock, Doctrine
Ability.TRoam, Doctrine
Ability.TPatrol ]
canMove = Skill -> Skills -> Int
Ability.getSk Skill
Ability.SkMove Skills
actorMaxSk Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0
canReach = Bool
canMove
Bool -> Bool -> Bool
|| Skill -> Skills -> Int
Ability.getSk Skill
Ability.SkDisplace Skills
actorMaxSk Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0
Bool -> Bool -> Bool
|| Skill -> Skills -> Int
Ability.getSk Skill
Ability.SkProject Skills
actorMaxSk Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0
canAlter = Skill -> Skills -> Int
Ability.getSk Skill
Ability.SkAlter Skills
actorMaxSk
Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= if Bool
slackDoctrine then Int
2 else Int
4
canMoveItem = Skill -> Skills -> Int
Ability.getSk Skill
Ability.SkMoveItem Skills
actorMaxSk Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0
calmE = Actor -> Skills -> Bool
calmEnough Actor
b Skills
actorMaxSk
heavilyDistressed =
ResDelta -> Bool
deltasSerious (Actor -> ResDelta
bcalmDelta Actor
b)
actorMinSk <- getsState $ actorCurrentSkills Nothing aid
condCanProject <-
condCanProjectM (Ability.getSk Ability.SkProject actorMaxSk) aid
fleeD <- getsClient sfleeD
let condCanMelee = ActorMaxSkills -> ActorId -> Actor -> Bool
actorCanMelee ActorMaxSkills
actorMaxSkills ActorId
aid Actor
b
condHpTooLow = Actor -> Skills -> Bool
hpTooLow Actor
b Skills
actorMaxSk
mfled = ActorId
aid ActorId -> EnumMap ActorId (Point, Time) -> Maybe (Point, Time)
forall k a. Enum k => k -> EnumMap k a -> Maybe a
`EM.lookup` EnumMap ActorId (Point, Time)
fleeD
recentlyFled =
Bool -> ((Point, Time) -> Bool) -> Maybe (Point, Time) -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False (\(Point
_, Time
time) -> Time -> Time -> Bool
timeRecent5 Time
localTime Time
time) Maybe (Point, Time)
mfled
recentlyFled20 =
Bool -> ((Point, Time) -> Bool) -> Maybe (Point, Time) -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False (\(Point
_, Time
time) -> Time -> Time -> Bool
timeRecent5 Time
localTime Time
time) Maybe (Point, Time)
mfled
actorTurn = Speed -> Delta Time
ticksPerMeter (Speed -> Delta Time) -> Speed -> Delta Time
forall a b. (a -> b) -> a -> b
$ Skills -> Speed
gearSpeed Skills
actorMaxSk
let canEscape = FactionKind -> Bool
fcanEscape (Faction -> FactionKind
gkind Faction
fact)
canSmell = Skill -> Skills -> Int
Ability.getSk Skill
Ability.SkSmell Skills
actorMaxSk Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0
meleeNearby | Bool
canEscape = Int
rnearby Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
2
| Bool
otherwise = Int
rnearby
rangedNearby = Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
meleeNearby
worthTargeting ActorId
aidE Actor
body =
let attacksFriends :: Bool
attacksFriends =
((ActorId, Actor) -> Bool) -> [(ActorId, Actor)] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Point -> Point -> Bool
adjacent (Actor -> Point
bpos Actor
body) (Point -> Bool)
-> ((ActorId, Actor) -> Point) -> (ActorId, Actor) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Actor -> Point
bpos (Actor -> Point)
-> ((ActorId, Actor) -> Actor) -> (ActorId, Actor) -> Point
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ActorId, Actor) -> Actor
forall a b. (a, b) -> b
snd) [(ActorId, Actor)]
friendAssocs
Bool -> Bool -> Bool
&& ActorMaxSkills -> ActorId -> Actor -> Bool
actorCanMeleeToHarm ActorMaxSkills
actorMaxSkills ActorId
aidE Actor
body
in Bool
attacksFriends
Bool -> Bool -> Bool
|| Actor -> Int
bweapBenign Actor
body Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0
Bool -> Bool -> Bool
|| ActorMaxSkills -> ActorId -> Actor -> Bool
actorWorthChasing ActorMaxSkills
actorMaxSkills ActorId
aidE Actor
body
targetableMelee Actor
body =
let attacksFriends :: Bool
attacksFriends =
((ActorId, Actor) -> Bool) -> [(ActorId, Actor)] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Point -> Point -> Bool
adjacent (Actor -> Point
bpos Actor
body) (Point -> Bool)
-> ((ActorId, Actor) -> Point) -> (ActorId, Actor) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Actor -> Point
bpos (Actor -> Point)
-> ((ActorId, Actor) -> Actor) -> (ActorId, Actor) -> Point
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ActorId, Actor) -> Actor
forall a b. (a, b) -> b
snd) [(ActorId, Actor)]
friendAssocs
n :: Int
n | Skill -> Skills -> Int
Ability.getSk Skill
Ability.SkAggression Skills
actorMaxSk Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
2
= Int
rangedNearby
| Bool
condInMelee = if Bool
attacksFriends then Int
8 else Int
4
| Bool
otherwise = Int
meleeNearby
in Bool
canMove
Bool -> Bool -> Bool
&& Bool
condCanMelee
Bool -> Bool -> Bool
&& Point -> Point -> Int
chessDist (Actor -> Point
bpos Actor
body) (Actor -> Point
bpos Actor
b) Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
n
targetableRanged Actor
body =
(Bool -> Bool
not Bool
condInMelee Bool -> Bool -> Bool
|| Skill -> Skills -> Int
Ability.getSk Skill
Ability.SkAggression Skills
actorMaxSk Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
2)
Bool -> Bool -> Bool
&& Point -> Point -> Int
chessDist (Actor -> Point
bpos Actor
body) (Actor -> Point
bpos Actor
b) Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
rangedNearby
Bool -> Bool -> Bool
&& Bool
condCanProject
Bool -> Bool -> Bool
&& (Bool
canMove Bool -> Bool -> Bool
|| Actor -> Bool
targetableLine Actor
body)
targetableLine Actor
body = Maybe Int -> Bool
forall a. Maybe a -> Bool
isJust (Maybe Int -> Bool) -> Maybe Int -> Bool
forall a b. (a -> b) -> a -> b
$ Bool -> Actor -> Point -> Int -> COps -> Level -> Maybe Int
makeLine Bool
False Actor
b (Actor -> Point
bpos Actor
body) Int
seps COps
cops Level
lvl
targetableEnemy (ActorId
aidE, Actor
body) = ActorId -> Actor -> Bool
worthTargeting ActorId
aidE Actor
body
Bool -> Bool -> Bool
&& (Point -> Point -> Bool
adjacent (Actor -> Point
bpos Actor
body) (Actor -> Point
bpos Actor
b)
Bool -> Bool -> Bool
|| Actor -> Bool
targetableMelee Actor
body
Bool -> Bool -> Bool
|| Actor -> Bool
targetableRanged Actor
body)
targetableFoes = ((ActorId, Actor) -> Bool)
-> [(ActorId, Actor)] -> [(ActorId, Actor)]
forall a. (a -> Bool) -> [a] -> [a]
filter (ActorId, Actor) -> Bool
targetableEnemy [(ActorId, Actor)]
foeAssocs
canMeleeEnemy (ActorId
aidE, Actor
body) = ActorMaxSkills -> ActorId -> Actor -> Bool
actorCanMeleeToHarm ActorMaxSkills
actorMaxSkills ActorId
aidE Actor
body
nearbyFoes = if Bool
recentlyFled Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
condInMelee
then ((ActorId, Actor) -> Bool)
-> [(ActorId, Actor)] -> [(ActorId, Actor)]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool)
-> ((ActorId, Actor) -> Bool) -> (ActorId, Actor) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ActorId, Actor) -> Bool
canMeleeEnemy) [(ActorId, Actor)]
targetableFoes
else [(ActorId, Actor)]
targetableFoes
discoBenefit <- getsClient sdiscoBenefit
getKind <- getsState $ flip getIidKind
getArItem <- getsState $ flip aspectRecordFromIid
cstashes <- if canMove
&& (calmE || null nearbyFoes)
&& not heavilyDistressed
&& gunderAI fact
then closestStashes aid
else return []
let desirableIid (ItemId
iid, (Int
k, ItemTimers
_)) =
let Benefit{Double
benPickup :: Double
benPickup :: Benefit -> Double
benPickup} = DiscoveryBenefit
discoBenefit DiscoveryBenefit -> ItemId -> Benefit
forall k a. Enum k => EnumMap k a -> k -> a
EM.! ItemId
iid
in COps -> Bool -> Double -> AspectRecord -> ItemKind -> Int -> Bool
desirableItem COps
cops Bool
canEscape Double
benPickup
(ItemId -> AspectRecord
getArItem ItemId
iid) (ItemId -> ItemKind
getKind ItemId
iid) Int
k
desirableBagFloor ItemBag
bag = ((ItemId, (Int, ItemTimers)) -> Bool)
-> [(ItemId, (Int, ItemTimers))] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (ItemId, (Int, ItemTimers)) -> Bool
desirableIid ([(ItemId, (Int, ItemTimers))] -> Bool)
-> [(ItemId, (Int, ItemTimers))] -> Bool
forall a b. (a -> b) -> a -> b
$ ItemBag -> [(ItemId, (Int, ItemTimers))]
forall k a. Enum k => EnumMap k a -> [(k, a)]
EM.assocs ItemBag
bag
desirableFloor (Int
_, (Point
_, ItemBag
bag)) = ItemBag -> Bool
desirableBagFloor ItemBag
bag
focused = Skills -> Speed
gearSpeed Skills
actorMaxSk Speed -> Speed -> Bool
forall a. Ord a => a -> a -> Bool
< Speed
speedWalk Bool -> Bool -> Bool
|| Bool
condHpTooLow
couldMoveLastTurn =
let actorSk :: Skills
actorSk = if Maybe ActorId
mleader Maybe ActorId -> Maybe ActorId -> Bool
forall a. Eq a => a -> a -> Bool
== ActorId -> Maybe ActorId
forall a. a -> Maybe a
Just ActorId
aid then Skills
actorMaxSk else Skills
actorMinSk
in Skill -> Skills -> Int
Ability.getSk Skill
Ability.SkMove Skills
actorSk Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0
isStuck = Actor -> Bool
actorWaits Actor
b Bool -> Bool -> Bool
&& Bool
couldMoveLastTurn
setPath :: Target -> m (Maybe TgtAndPath)
setPath Target
tgt = do
let take6 :: TgtAndPath -> TgtAndPath
take6 tap :: TgtAndPath
tap@TgtAndPath{tapTgt :: TgtAndPath -> Target
tapTgt=TEnemy{}} = TgtAndPath
tap
take6 TgtAndPath{tapPath :: TgtAndPath -> Maybe AndPath
tapPath=Just AndPath{Int
[Point]
Point
pathLen :: AndPath -> Int
pathGoal :: AndPath -> Point
pathList :: AndPath -> [Point]
pathSource :: AndPath -> Point
pathSource :: Point
pathList :: [Point]
pathGoal :: Point
pathLen :: Int
..}} =
let path6 :: [Point]
path6 = Int -> [Point] -> [Point]
forall a. Int -> [a] -> [a]
take Int
6 [Point]
pathList
vOld :: Vector
vOld = if Actor -> Point
bpos Actor
b Point -> Point -> Bool
forall a. Eq a => a -> a -> Bool
/= Point
pathGoal
then Point -> Point -> Vector
towards (Actor -> Point
bpos Actor
b) Point
pathGoal
else Int -> Int -> Vector
Vector Int
0 Int
0
tapTgt :: Target
tapTgt = Vector -> Target
TVector Vector
vOld
tapPath :: Maybe AndPath
tapPath = AndPath -> Maybe AndPath
forall a. a -> Maybe a
Just AndPath{pathList :: [Point]
pathList=[Point]
path6, Int
Point
pathLen :: Int
pathGoal :: Point
pathSource :: Point
pathSource :: Point
pathGoal :: Point
pathLen :: Int
..}
in TgtAndPath{Maybe AndPath
Target
tapTgt :: Target
tapPath :: Maybe AndPath
tapTgt :: Target
tapPath :: Maybe AndPath
..}
take6 TgtAndPath
tap = TgtAndPath
tap
tgtpath <- ActorId -> Target -> m TgtAndPath
forall (m :: * -> *).
MonadClient m =>
ActorId -> Target -> m TgtAndPath
createPath ActorId
aid Target
tgt
return $ Just $ if slackDoctrine then take6 tgtpath else tgtpath
pickNewTarget = Maybe ActorId -> m (Maybe TgtAndPath)
pickNewTargetIgnore Maybe ActorId
forall a. Maybe a
Nothing
pickNewTargetIgnore :: Maybe ActorId -> m (Maybe TgtAndPath)
pickNewTargetIgnore Maybe ActorId
maidToIgnore =
case [(Int, (FactionId, Point))]
cstashes of
(Int
_, (FactionId
fid2, Point
pos2)) : [(Int, (FactionId, Point))]
_ -> Target -> m (Maybe TgtAndPath)
setPath (Target -> m (Maybe TgtAndPath)) -> Target -> m (Maybe TgtAndPath)
forall a b. (a -> b) -> a -> b
$ TGoal -> LevelId -> Point -> Target
TPoint (FactionId -> TGoal
TStash FactionId
fid2) (Actor -> LevelId
blid Actor
b) Point
pos2
[] -> do
let f :: ActorId -> [(ActorId, Actor)]
f ActorId
aidToIgnore = ((ActorId, Actor) -> Bool)
-> [(ActorId, Actor)] -> [(ActorId, Actor)]
forall a. (a -> Bool) -> [a] -> [a]
filter ((ActorId -> ActorId -> Bool
forall a. Eq a => a -> a -> Bool
/= ActorId
aidToIgnore) (ActorId -> Bool)
-> ((ActorId, Actor) -> ActorId) -> (ActorId, Actor) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ActorId, Actor) -> ActorId
forall a b. (a, b) -> a
fst) [(ActorId, Actor)]
nearbyFoes
notIgnoredFoes :: [(ActorId, Actor)]
notIgnoredFoes = [(ActorId, Actor)]
-> (ActorId -> [(ActorId, Actor)])
-> Maybe ActorId
-> [(ActorId, Actor)]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [(ActorId, Actor)]
nearbyFoes ActorId -> [(ActorId, Actor)]
f Maybe ActorId
maidToIgnore
cfoes <- [(ActorId, Actor)] -> ActorId -> m [(Int, (ActorId, Actor))]
forall (m :: * -> *).
MonadClient m =>
[(ActorId, Actor)] -> ActorId -> m [(Int, (ActorId, Actor))]
closestFoes [(ActorId, Actor)]
notIgnoredFoes ActorId
aid
case cfoes of
(Int
_, (ActorId
aid2, Actor
_)) : [(Int, (ActorId, Actor))]
_ -> Target -> m (Maybe TgtAndPath)
setPath (Target -> m (Maybe TgtAndPath)) -> Target -> m (Maybe TgtAndPath)
forall a b. (a -> b) -> a -> b
$ ActorId -> Target
TEnemy ActorId
aid2
[] | Bool
condInMelee -> Maybe TgtAndPath -> m (Maybe TgtAndPath)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe TgtAndPath
forall a. Maybe a
Nothing
[] -> do
mhideout <- if Bool
recentlyFled20
then ActorId -> m (Maybe (Point, Int))
forall (m :: * -> *).
MonadClient m =>
ActorId -> m (Maybe (Point, Int))
closestHideout ActorId
aid
else Maybe (Point, Int) -> m (Maybe (Point, Int))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (Point, Int)
forall a. Maybe a
Nothing
case (mhideout, mfled) of
(Just (Point
p, Int
dist), Just (Point
_, Time
time))
| Time -> Time -> Delta Time
timeDeltaToFrom Time
localTime Time
time
Delta Time -> Delta Time -> Bool
forall a. Ord a => a -> a -> Bool
<= Delta Time -> Int -> Delta Time
timeDeltaScale Delta Time
actorTurn (Int
20 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
dist) ->
Target -> m (Maybe TgtAndPath)
setPath (Target -> m (Maybe TgtAndPath)) -> Target -> m (Maybe TgtAndPath)
forall a b. (a -> b) -> a -> b
$ TGoal -> LevelId -> Point -> Target
TPoint TGoal
THideout (Actor -> LevelId
blid Actor
b) Point
p
(Maybe (Point, Int), Maybe (Point, Time))
_ -> do
citemsRaw <- if Bool
canMoveItem Bool -> Bool -> Bool
&& Bool
canMove
then ActorId -> m [(Int, (Point, ItemBag))]
forall (m :: * -> *).
MonadClient m =>
ActorId -> m [(Int, (Point, ItemBag))]
closestItems ActorId
aid
else [(Int, (Point, ItemBag))] -> m [(Int, (Point, ItemBag))]
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return []
let citems = Text -> [(Int, (Point, ItemBag))] -> Frequency (Point, ItemBag)
forall a. Text -> [(Int, a)] -> Frequency a
toFreq Text
"closestItems"
([(Int, (Point, ItemBag))] -> Frequency (Point, ItemBag))
-> [(Int, (Point, ItemBag))] -> Frequency (Point, ItemBag)
forall a b. (a -> b) -> a -> b
$ ((Int, (Point, ItemBag)) -> Bool)
-> [(Int, (Point, ItemBag))] -> [(Int, (Point, ItemBag))]
forall a. (a -> Bool) -> [a] -> [a]
filter (Int, (Point, ItemBag)) -> Bool
desirableFloor [(Int, (Point, ItemBag))]
citemsRaw
if nullFreq citems then do
smpos <- if canSmell
then closestSmell aid
else return []
case smpos of
[] -> do
ctriggersRaw <- FleeViaStairsOrEscape
-> ActorId -> m [(Int, (Point, (Point, ItemBag)))]
forall (m :: * -> *).
MonadClient m =>
FleeViaStairsOrEscape
-> ActorId -> m [(Int, (Point, (Point, ItemBag)))]
closestTriggers FleeViaStairsOrEscape
ViaAnything ActorId
aid
let ctriggers = Text
-> [(Int, (Point, (Point, ItemBag)))]
-> Frequency (Point, (Point, ItemBag))
forall a. Text -> [(Int, a)] -> Frequency a
toFreq Text
"ctriggers" [(Int, (Point, (Point, ItemBag)))]
ctriggersRaw
if nullFreq ctriggers then do
let oldpos = Point -> Maybe Point -> Point
forall a. a -> Maybe a -> a
fromMaybe (Actor -> Point
bpos Actor
b) (Actor -> Maybe Point
boldpos Actor
b)
vOld = Actor -> Point
bpos Actor
b Point -> Point -> Vector
`vectorToFrom` Point
oldpos
pNew = Int -> Int -> Point -> Vector -> Point
shiftBounded Int
rWidthMax Int
rHeightMax (Actor -> Point
bpos Actor
b) Vector
vOld
if slackDoctrine && not isStuck && calmE && not focused
&& isUnit vOld && bpos b /= pNew
then do
let vFreq = Text -> [(Int, Vector)] -> Frequency Vector
forall a. Text -> [(Int, a)] -> Frequency a
toFreq Text
"vFreq"
([(Int, Vector)] -> Frequency Vector)
-> [(Int, Vector)] -> Frequency Vector
forall a b. (a -> b) -> a -> b
$ (Int
20, Vector
vOld) (Int, Vector) -> [(Int, Vector)] -> [(Int, Vector)]
forall a. a -> [a] -> [a]
: (Vector -> (Int, Vector)) -> [Vector] -> [(Int, Vector)]
forall a b. (a -> b) -> [a] -> [b]
map (Int
1,) [Vector]
moves
v <- rndToAction $ frequency vFreq
let pathSource = Actor -> Point
bpos Actor
b
traSlack7 = Int -> Int -> Point -> [Vector] -> [Point]
trajectoryToPathBounded
Int
rWidthMax Int
rHeightMax Point
pathSource
(Int -> Vector -> [Vector]
forall a. Int -> a -> [a]
replicate Int
7 Vector
v)
pathList = ([Point] -> Point) -> [[Point]] -> [Point]
forall a b. (a -> b) -> [a] -> [b]
map [Point] -> Point
forall a. (?callStack::CallStack) => [a] -> a
head ([[Point]] -> [Point]) -> [[Point]] -> [Point]
forall a b. (a -> b) -> a -> b
$ [Point] -> [[Point]]
forall a. Eq a => [a] -> [[a]]
group [Point]
traSlack7
pathGoal = [Point] -> Point
forall a. (?callStack::CallStack) => [a] -> a
last [Point]
pathList
pathLen = [Point] -> Int
forall a. [a] -> Int
length [Point]
pathList
tapTgt = Vector -> Target
TVector Vector
v
tapPath = AndPath -> Maybe AndPath
forall a. a -> Maybe a
Just AndPath{Int
[Point]
Point
pathLen :: Int
pathGoal :: Point
pathList :: [Point]
pathSource :: Point
pathSource :: Point
pathList :: [Point]
pathGoal :: Point
pathLen :: Int
..}
return $ Just TgtAndPath {..}
else do
upos <- if canMove
then closestUnknown aid
else return Nothing
case upos of
Maybe Point
Nothing -> do
Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
canMove Bool -> Bool -> Bool
&& Bool
canAlter) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$
(StateClient -> StateClient) -> m ()
forall (m :: * -> *).
MonadClient m =>
(StateClient -> StateClient) -> m ()
modifyClient ((StateClient -> StateClient) -> m ())
-> (StateClient -> StateClient) -> m ()
forall a b. (a -> b) -> a -> b
$ \StateClient
cli -> StateClient
cli {sexplored =
ES.insert (blid b) (sexplored cli)}
ctriggersRaw2 <- FleeViaStairsOrEscape
-> ActorId -> m [(Int, (Point, (Point, ItemBag)))]
forall (m :: * -> *).
MonadClient m =>
FleeViaStairsOrEscape
-> ActorId -> m [(Int, (Point, (Point, ItemBag)))]
closestTriggers FleeViaStairsOrEscape
ViaExit ActorId
aid
let ctriggers2 = Text
-> [(Int, (Point, (Point, ItemBag)))]
-> Frequency (Point, (Point, ItemBag))
forall a. Text -> [(Int, a)] -> Frequency a
toFreq Text
"ctriggers2" [(Int, (Point, (Point, ItemBag)))]
ctriggersRaw2
if nullFreq ctriggers2 then do
let toKill = ActorMaxSkills -> ActorId -> Actor -> Bool
actorWorthKilling ActorMaxSkills
actorMaxSkills
worthyFoes = ((ActorId, Actor) -> Bool)
-> [(ActorId, Actor)] -> [(ActorId, Actor)]
forall a. (a -> Bool) -> [a] -> [a]
filter ((ActorId -> Actor -> Bool) -> (ActorId, Actor) -> Bool
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry ActorId -> Actor -> Bool
toKill)
[(ActorId, Actor)]
foeAssocs
afoes <- closestFoes worthyFoes aid
case afoes of
(Int
_, (ActorId
aid2, Actor
_)) : [(Int, (ActorId, Actor))]
_ ->
Target -> m (Maybe TgtAndPath)
setPath (Target -> m (Maybe TgtAndPath)) -> Target -> m (Maybe TgtAndPath)
forall a b. (a -> b) -> a -> b
$ ActorId -> Target
TEnemy ActorId
aid2
[] -> do
furthest <- ActorId -> m Point
forall (m :: * -> *). MonadClient m => ActorId -> m Point
furthestKnown ActorId
aid
setPath $ TPoint TKnown (blid b) furthest
else do
(p, (p0, bag)) <-
rndToAction $ frequency ctriggers2
setPath $ TPoint (TEmbed bag p0) (blid b) p
Just Point
p -> Target -> m (Maybe TgtAndPath)
setPath (Target -> m (Maybe TgtAndPath)) -> Target -> m (Maybe TgtAndPath)
forall a b. (a -> b) -> a -> b
$ TGoal -> LevelId -> Point -> Target
TPoint TGoal
TUnknown (Actor -> LevelId
blid Actor
b) Point
p
else do
(p, (p0, bag)) <- rndToAction $ frequency ctriggers
setPath $ TPoint (TEmbed bag p0) (blid b) p
(Int
_, (Point
p, Time
_)) : [(Int, (Point, Time))]
_ -> Target -> m (Maybe TgtAndPath)
setPath (Target -> m (Maybe TgtAndPath)) -> Target -> m (Maybe TgtAndPath)
forall a b. (a -> b) -> a -> b
$ TGoal -> LevelId -> Point -> Target
TPoint TGoal
TSmell (Actor -> LevelId
blid Actor
b) Point
p
else do
(p, bag) <- rndToAction $ frequency citems
setPath $ TPoint (TItem bag) (blid b) p
tellOthersNothingHere = do
let f :: TgtAndPath -> Bool
f TgtAndPath{Target
tapTgt :: TgtAndPath -> Target
tapTgt :: Target
tapTgt} = case Target
tapTgt of
TPoint TGoal
_ LevelId
lid Point
p -> Point
p Point -> Point -> Bool
forall a. Eq a => a -> a -> Bool
/= Actor -> Point
bpos Actor
b Bool -> Bool -> Bool
|| LevelId
lid LevelId -> LevelId -> Bool
forall a. Eq a => a -> a -> Bool
/= Actor -> LevelId
blid Actor
b
Target
_ -> Bool
True
(StateClient -> StateClient) -> m ()
forall (m :: * -> *).
MonadClient m =>
(StateClient -> StateClient) -> m ()
modifyClient ((StateClient -> StateClient) -> m ())
-> (StateClient -> StateClient) -> m ()
forall a b. (a -> b) -> a -> b
$ \StateClient
cli -> StateClient
cli {stargetD = EM.filter f (stargetD cli)}
m (Maybe TgtAndPath)
pickNewTarget
updateTgt :: TgtAndPath -> m (Maybe TgtAndPath)
updateTgt TgtAndPath{tapPath :: TgtAndPath -> Maybe AndPath
tapPath=Maybe AndPath
Nothing} = m (Maybe TgtAndPath)
pickNewTarget
updateTgt tap :: TgtAndPath
tap@TgtAndPath{tapPath :: TgtAndPath -> Maybe AndPath
tapPath=Just AndPath{Int
[Point]
Point
pathLen :: AndPath -> Int
pathGoal :: AndPath -> Point
pathList :: AndPath -> [Point]
pathSource :: AndPath -> Point
pathSource :: Point
pathList :: [Point]
pathGoal :: Point
pathLen :: Int
..},Target
tapTgt :: TgtAndPath -> Target
tapTgt :: Target
tapTgt} = case Target
tapTgt of
TEnemy ActorId
a -> do
body <- (State -> Actor) -> m Actor
forall a. (State -> a) -> m a
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Actor
getActorBody ActorId
a
if (condInMelee
|| bweapon body <= 0
|| not focused && not (null nearbyFoes))
&& a `notElem` map fst nearbyFoes
|| blid body /= blid b
|| actorDying body
|| not (worthTargeting a body)
|| recentlyFled
then
pickNewTarget
else do
mpath <- getCachePath aid $ bpos body
case mpath of
Maybe AndPath
Nothing -> Maybe ActorId -> m (Maybe TgtAndPath)
pickNewTargetIgnore (ActorId -> Maybe ActorId
forall a. a -> Maybe a
Just ActorId
a)
Just AndPath{pathList :: AndPath -> [Point]
pathList=[]} -> m (Maybe TgtAndPath)
pickNewTarget
Just AndPath{pathList :: AndPath -> [Point]
pathList= Point
q : [Point]
_} ->
if Bool -> Bool
not Bool
condInMelee
Bool -> Bool -> Bool
|| Point
q Point -> Point -> Bool
forall a. Eq a => a -> a -> Bool
== Actor -> Point
bpos Actor
body
Bool -> Bool -> Bool
|| Bool -> Bool
not (Point -> Level -> Bool
occupiedBigLvl Point
q Level
lvl)
Bool -> Bool -> Bool
&& Bool -> Bool
not (Point -> Level -> Bool
occupiedProjLvl Point
q Level
lvl)
then Maybe TgtAndPath -> m (Maybe TgtAndPath)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe TgtAndPath -> m (Maybe TgtAndPath))
-> Maybe TgtAndPath -> m (Maybe TgtAndPath)
forall a b. (a -> b) -> a -> b
$ TgtAndPath -> Maybe TgtAndPath
forall a. a -> Maybe a
Just TgtAndPath
tap{tapPath=mpath}
else Maybe ActorId -> m (Maybe TgtAndPath)
pickNewTargetIgnore (ActorId -> Maybe ActorId
forall a. a -> Maybe a
Just ActorId
a)
TPoint TGoal
_ LevelId
lid Point
_ | LevelId
lid LevelId -> LevelId -> Bool
forall a. Eq a => a -> a -> Bool
/= Actor -> LevelId
blid Actor
b -> m (Maybe TgtAndPath)
pickNewTarget
TPoint TGoal
tgoal LevelId
lid Point
pos -> case TGoal
tgoal of
TStash FactionId
fid2 -> do
oursExploring <- (State -> [(ActorId, Actor)]) -> m [(ActorId, Actor)]
forall a. (State -> a) -> m a
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> [(ActorId, Actor)]) -> m [(ActorId, Actor)])
-> (State -> [(ActorId, Actor)]) -> m [(ActorId, Actor)]
forall a b. (a -> b) -> a -> b
$ FactionId -> State -> [(ActorId, Actor)]
oursExploringAssocs (Actor -> FactionId
bfid Actor
b)
let oursExploringLid =
((ActorId, Actor) -> Bool)
-> [(ActorId, Actor)] -> [(ActorId, Actor)]
forall a. (a -> Bool) -> [a] -> [a]
filter (\(ActorId
_, Actor
body) -> Actor -> LevelId
blid Actor
body LevelId -> LevelId -> Bool
forall a. Eq a => a -> a -> Bool
== LevelId
lid) [(ActorId, Actor)]
oursExploring
spawnFreqs = CaveKind -> Freqs ItemKind
CK.cactorFreq (CaveKind -> Freqs ItemKind) -> CaveKind -> Freqs ItemKind
forall a b. (a -> b) -> a -> b
$ ContentData CaveKind -> ContentId CaveKind -> CaveKind
forall a. ContentData a -> ContentId a -> a
okind ContentData CaveKind
cocave (ContentId CaveKind -> CaveKind) -> ContentId CaveKind -> CaveKind
forall a b. (a -> b) -> a -> b
$ Level -> ContentId CaveKind
lkind Level
lvl
hasGroup GroupName ItemKind
grp = Int -> Maybe Int -> Int
forall a. a -> Maybe a -> a
fromMaybe Int
0 (GroupName ItemKind -> Freqs ItemKind -> Maybe Int
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup GroupName ItemKind
grp Freqs ItemKind
spawnFreqs) Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0
lvlSpawnsUs = ((GroupName ItemKind, Int) -> Bool) -> Freqs ItemKind -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (GroupName ItemKind -> Bool
hasGroup (GroupName ItemKind -> Bool)
-> ((GroupName ItemKind, Int) -> GroupName ItemKind)
-> (GroupName ItemKind, Int)
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (GroupName ItemKind, Int) -> GroupName ItemKind
forall a b. (a, b) -> a
fst) (Freqs ItemKind -> Bool) -> Freqs ItemKind -> Bool
forall a b. (a -> b) -> a -> b
$ ((GroupName ItemKind, Int) -> Bool)
-> Freqs ItemKind -> Freqs ItemKind
forall a. (a -> Bool) -> [a] -> [a]
filter ((Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0) (Int -> Bool)
-> ((GroupName ItemKind, Int) -> Int)
-> (GroupName ItemKind, Int)
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (GroupName ItemKind, Int) -> Int
forall a b. (a, b) -> b
snd)
(Freqs ItemKind -> Freqs ItemKind)
-> Freqs ItemKind -> Freqs ItemKind
forall a b. (a -> b) -> a -> b
$ FactionKind -> Freqs ItemKind
fgroups (Faction -> FactionKind
gkind Faction
fact)
if (calmE || null nearbyFoes)
&& not heavilyDistressed
&& gstash (factionD EM.! fid2) == Just (lid, pos)
&& (fid2 == bfid b
&& (pos == bpos b
&& (null nearbyFoes
|| length oursExploringLid > 1)
|| isNothing (posToBigLvl pos lvl))
&& (length oursExploring > 1
|| lvlSpawnsUs)
|| isFoe (bfid b) fact fid2)
then return $ Just tap
else pickNewTarget
TGoal
_ | Bool
condInMelee Bool -> Bool -> Bool
|| Bool -> Bool
not ([(Int, (FactionId, Point))] -> Bool
forall a. [a] -> Bool
null [(Int, (FactionId, Point))]
cstashes) -> m (Maybe TgtAndPath)
pickNewTarget
TEnemyPos ActorId
_
| Actor -> Point
bpos Actor
b Point -> Point -> Bool
forall a. Eq a => a -> a -> Bool
== Point
pos -> m (Maybe TgtAndPath)
tellOthersNothingHere
| Bool
recentlyFled -> m (Maybe TgtAndPath)
pickNewTarget
| Bool -> Bool
not (Bool
couldMoveLastTurn Bool -> Bool -> Bool
|| [(ActorId, Actor)] -> Bool
forall a. [a] -> Bool
null [(ActorId, Actor)]
nearbyFoes) -> m (Maybe TgtAndPath)
pickNewTarget
| Bool
otherwise -> do
let remainingDist :: Int
remainingDist = Point -> Point -> Int
chessDist (Actor -> Point
bpos Actor
b) Point
pos
if ((ActorId, Actor) -> Bool) -> [(ActorId, Actor)] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\(ActorId
_, Actor
b3) -> Point -> Point -> Int
chessDist (Actor -> Point
bpos Actor
b) (Actor -> Point
bpos Actor
b3) Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
remainingDist)
[(ActorId, Actor)]
nearbyFoes
then m (Maybe TgtAndPath)
pickNewTarget
else Maybe TgtAndPath -> m (Maybe TgtAndPath)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe TgtAndPath -> m (Maybe TgtAndPath))
-> Maybe TgtAndPath -> m (Maybe TgtAndPath)
forall a b. (a -> b) -> a -> b
$ TgtAndPath -> Maybe TgtAndPath
forall a. a -> Maybe a
Just TgtAndPath
tap
TGoal
THideout ->
if Bool -> Bool
not Bool
recentlyFled20
then m (Maybe TgtAndPath)
pickNewTarget
else Maybe TgtAndPath -> m (Maybe TgtAndPath)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe TgtAndPath -> m (Maybe TgtAndPath))
-> Maybe TgtAndPath -> m (Maybe TgtAndPath)
forall a b. (a -> b) -> a -> b
$ TgtAndPath -> Maybe TgtAndPath
forall a. a -> Maybe a
Just TgtAndPath
tap
TGoal
_ | Bool -> Bool
not ([(ActorId, Actor)] -> Bool
forall a. [a] -> Bool
null [(ActorId, Actor)]
nearbyFoes) -> m (Maybe TgtAndPath)
pickNewTarget
TEmbed ItemBag
bag Point
p -> Bool -> m (Maybe TgtAndPath) -> m (Maybe TgtAndPath)
forall a. (?callStack::CallStack) => Bool -> a -> a
assert (Point -> Point -> Bool
adjacent Point
pos Point
p) (m (Maybe TgtAndPath) -> m (Maybe TgtAndPath))
-> m (Maybe TgtAndPath) -> m (Maybe TgtAndPath)
forall a b. (a -> b) -> a -> b
$ do
bag2 <- (State -> ItemBag) -> m ItemBag
forall a. (State -> a) -> m a
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> ItemBag) -> m ItemBag)
-> (State -> ItemBag) -> m ItemBag
forall a b. (a -> b) -> a -> b
$ LevelId -> Point -> State -> ItemBag
getEmbedBag LevelId
lid Point
p
if | bag /= bag2 -> pickNewTarget
| adjacent (bpos b) p ->
setPath $ TPoint TKnown lid (bpos b)
| otherwise -> return $ Just tap
TItem ItemBag
bag -> do
bag2 <- (State -> ItemBag) -> m ItemBag
forall a. (State -> a) -> m a
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> ItemBag) -> m ItemBag)
-> (State -> ItemBag) -> m ItemBag
forall a b. (a -> b) -> a -> b
$ LevelId -> Point -> State -> ItemBag
getFloorBag LevelId
lid Point
pos
if | bag /= bag2 -> pickNewTarget
| bpos b == pos ->
setPath $ TPoint TKnown lid (bpos b)
| otherwise -> return $ Just tap
TGoal
TSmell ->
if Bool -> Bool
not Bool
canSmell
Bool -> Bool -> Bool
|| let sml :: Time
sml = Time -> Point -> EnumMap Point Time -> Time
forall k a. Enum k => a -> k -> EnumMap k a -> a
EM.findWithDefault Time
timeZero Point
pos (Level -> EnumMap Point Time
lsmell Level
lvl)
in Time
sml Time -> Time -> Bool
forall a. Ord a => a -> a -> Bool
<= Level -> Time
ltime Level
lvl
then m (Maybe TgtAndPath)
pickNewTarget
else Maybe TgtAndPath -> m (Maybe TgtAndPath)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe TgtAndPath -> m (Maybe TgtAndPath))
-> Maybe TgtAndPath -> m (Maybe TgtAndPath)
forall a b. (a -> b) -> a -> b
$ TgtAndPath -> Maybe TgtAndPath
forall a. a -> Maybe a
Just TgtAndPath
tap
TGoal
TBlock -> do
let t :: ContentId TileKind
t = Level
lvl Level -> Point -> ContentId TileKind
`at` Point
pos
if Bool
isStuck
Bool -> Bool -> Bool
|| Int
alterSkill Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Word8 -> Int
forall a. Enum a => a -> Int
fromEnum (Array Word8
lalter Array Word8 -> Point -> Word8
forall c. UnboxRepClass c => Array c -> Point -> c
PointArray.! Point
pos)
Bool -> Bool -> Bool
|| TileSpeedup -> ContentId TileKind -> Bool
Tile.isWalkable TileSpeedup
coTileSpeedup ContentId TileKind
t
then m (Maybe TgtAndPath)
pickNewTarget
else Maybe TgtAndPath -> m (Maybe TgtAndPath)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe TgtAndPath -> m (Maybe TgtAndPath))
-> Maybe TgtAndPath -> m (Maybe TgtAndPath)
forall a b. (a -> b) -> a -> b
$ TgtAndPath -> Maybe TgtAndPath
forall a. a -> Maybe a
Just TgtAndPath
tap
TGoal
TUnknown ->
let t :: ContentId TileKind
t = Level
lvl Level -> Point -> ContentId TileKind
`at` Point
pos
in if Level -> Int
lexpl Level
lvl Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Level -> Int
lseen Level
lvl
Bool -> Bool -> Bool
|| Bool -> Bool
not (ContentId TileKind -> Bool
isUknownSpace ContentId TileKind
t)
then m (Maybe TgtAndPath)
pickNewTarget
else Maybe TgtAndPath -> m (Maybe TgtAndPath)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe TgtAndPath -> m (Maybe TgtAndPath))
-> Maybe TgtAndPath -> m (Maybe TgtAndPath)
forall a b. (a -> b) -> a -> b
$ TgtAndPath -> Maybe TgtAndPath
forall a. a -> Maybe a
Just TgtAndPath
tap
TGoal
TKnown ->
if Actor -> Point
bpos Actor
b Point -> Point -> Bool
forall a. Eq a => a -> a -> Bool
== Point
pos
Bool -> Bool -> Bool
|| Bool
isStuck
Bool -> Bool -> Bool
|| Int
alterSkill Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Word8 -> Int
forall a. Enum a => a -> Int
fromEnum (Array Word8
lalter Array Word8 -> Point -> Word8
forall c. UnboxRepClass c => Array c -> Point -> c
PointArray.! Point
pos)
then m (Maybe TgtAndPath)
pickNewTarget
else Maybe TgtAndPath -> m (Maybe TgtAndPath)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe TgtAndPath -> m (Maybe TgtAndPath))
-> Maybe TgtAndPath -> m (Maybe TgtAndPath)
forall a b. (a -> b) -> a -> b
$ TgtAndPath -> Maybe TgtAndPath
forall a. a -> Maybe a
Just TgtAndPath
tap
Target
_ | Bool
condInMelee Bool -> Bool -> Bool
|| Bool -> Bool
not ([(ActorId, Actor)] -> Bool
forall a. [a] -> Bool
null [(ActorId, Actor)]
nearbyFoes Bool -> Bool -> Bool
&& [(Int, (FactionId, Point))] -> Bool
forall a. [a] -> Bool
null [(Int, (FactionId, Point))]
cstashes) ->
m (Maybe TgtAndPath)
pickNewTarget
TNonEnemy ActorId
_ | Maybe ActorId
mleader Maybe ActorId -> Maybe ActorId -> Bool
forall a. Eq a => a -> a -> Bool
== ActorId -> Maybe ActorId
forall a. a -> Maybe a
Just ActorId
aid ->
m (Maybe TgtAndPath)
pickNewTarget
TNonEnemy ActorId
a -> do
body <- (State -> Actor) -> m Actor
forall a. (State -> a) -> m a
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Actor
getActorBody ActorId
a
if blid body /= blid b
then pickNewTarget
else do
mpath <- getCachePath aid $ bpos body
case mpath of
Maybe AndPath
Nothing -> m (Maybe TgtAndPath)
pickNewTarget
Just AndPath{pathList :: AndPath -> [Point]
pathList=[]} -> m (Maybe TgtAndPath)
pickNewTarget
Maybe AndPath
_ -> Maybe TgtAndPath -> m (Maybe TgtAndPath)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe TgtAndPath -> m (Maybe TgtAndPath))
-> Maybe TgtAndPath -> m (Maybe TgtAndPath)
forall a b. (a -> b) -> a -> b
$ TgtAndPath -> Maybe TgtAndPath
forall a. a -> Maybe a
Just TgtAndPath
tap{tapPath=mpath}
TVector{} -> if Actor -> Point
bpos Actor
b Point -> Point -> Bool
forall a. Eq a => a -> a -> Bool
/= Point
pathGoal
then Maybe TgtAndPath -> m (Maybe TgtAndPath)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe TgtAndPath -> m (Maybe TgtAndPath))
-> Maybe TgtAndPath -> m (Maybe TgtAndPath)
forall a b. (a -> b) -> a -> b
$ TgtAndPath -> Maybe TgtAndPath
forall a. a -> Maybe a
Just TgtAndPath
tap
else m (Maybe TgtAndPath)
pickNewTarget
if canReach
then maybe pickNewTarget updateTgt oldTgtUpdatedPath
else return Nothing