Permalink
Browse files

let monsters target heroes and prefer their targets

  • Loading branch information...
1 parent 3d69f3e commit b3b5fb2dc972b45bfae2478e1b3c654b674e9550 @Mikolaj Mikolaj committed Apr 7, 2011
Showing with 45 additions and 24 deletions.
  1. +9 −10 src/Movable.hs
  2. +36 −14 src/StrategyState.hs
View
@@ -11,15 +11,14 @@ import MovableKind
-- of properties form MovableKind, the intention is they may be modified
-- temporarily, but will return to the original value over time. E.g., HP.
data Movable = Movable
- { mkind :: !MovableKind,
- mhp :: !Int,
- mdir :: Maybe Dir, -- for monsters: the dir the monster last moved; TODO: use target for this, instead and use mdir to signal the monster wants to switch position with a hero (if the monster is smart/big enough)
- -- for heroes: the dir the hero is running
- mtarget :: Target,
- mloc :: !Loc,
- mitems :: [Item], -- inventory
- mletter :: !Char, -- next inventory letter
- mtime :: !Time } -- time of next action
+ { mkind :: !MovableKind, -- ^ kind of the movable; TODO: make this Int
+ mhp :: !Int, -- ^ current hit pints
+ mdir :: Maybe Dir, -- ^ the direction of running
+ mtarget :: Target, -- ^ the target for distance attacks and AI
+ mloc :: !Loc, -- ^ current location
+ mitems :: [Item], -- ^ inventory
+ mletter :: !Char, -- ^ next inventory letter
+ mtime :: !Time } -- ^ time of next action
deriving Show
instance Binary Movable where
@@ -46,7 +45,7 @@ instance Binary Movable where
data Actor = AHero Int -- ^ hero index (on the lheroes intmap)
| AMonster Int -- ^ monster index (on the lmonsters intmap)
- deriving (Show, Eq)
+ deriving (Show, Eq, Ord)
isAHero :: Actor -> Bool
isAHero (AHero _) = True
View
@@ -6,6 +6,7 @@ import Data.Set as S
import qualified Data.IntMap as IM
import Data.Maybe
import Control.Monad
+import Control.Monad.State hiding (State)
import Control.Exception (assert)
import Geometry
@@ -33,7 +34,8 @@ strategy actor
strategy
where
-- TODO: set monster targets and then prefer targets to other heroes
- Movable { mkind = mk, mloc = me, mdir = mdir } = getActor actor oldState
+ Movable { mkind = mk, mloc = me, mdir = mdir, mtarget = tgt } =
+ getActor actor oldState
delState = deleteActor actor oldState
-- If the player is a monster, monsters spot and attack him when adjacent.
ploc = if isAHero pl || creturnLn cursor /= ln
@@ -46,15 +48,30 @@ strategy actor
IM.assocs $ lheroes $ slevel delState
ms = L.map (\ (i, m) -> (AMonster i, mloc m)) $
IM.assocs $ lmonsters $ slevel delState
- foes = if L.null hs then ms else hs
- -- We assume monster sight is actually infravision, so light has no effect.
- foeVisible = L.filter (\ (a, l) ->
- actorReachesActor a actor l me per pl) foes
- foeDist = L.map (\ (_, l) -> (distance (me, l), l)) foeVisible
-- Below, "foe" is the hero (or a monster) at floc, attacked by the actor.
- floc = case foeVisible of
- [] -> Nothing
- _ -> Just $ snd $ L.minimum foeDist
+ (newTgt, floc) =
+ case tgt of
+ TEnemy a | focusedMonster ->
+ case findActorAnyLevel a delState of
+ Just (_, m) ->
+ let l = mloc m
+ in if actorReachesActor a actor l me per pl
+ then (tgt, Just l)
+ else closest -- TODO: got to the last know location
+ Nothing -> closest -- enemy dead
+ TLoc loc -> (tgt, Just loc) -- ignore everything and go to loc
+ _ -> closest
+ closest =
+ let foes = if L.null hs then ms else hs
+ -- We assume monster sight is infravision, so light has no effect.
+ foeVisible =
+ L.filter (\ (a, l) -> actorReachesActor a actor l me per pl) foes
+ foeDist = L.map (\ (a, l) -> (distance (me, l), l, a)) foeVisible
+ -- Below, "foe" is the hero (or a monster) at floc, attacked by the actor.
+ in case foeDist of
+ [] -> (tgt, Nothing)
+ _ -> let (_, l, a) = L.minimum foeDist
+ in (TEnemy a, Just $ l)
onlyFoe = onlyMoves (maybe (const False) (==) floc) me
towardsFoe = case floc of
Nothing -> const mzero
@@ -72,24 +89,24 @@ strategy actor
accessibleHere = accessible lmap me
onlySensible = onlyMoves (\ l -> accessibleHere l || openableHere l) me
greedyMonster = niq mk < 5
+ focusedMonster = niq mk > 10
pushyMonster = not $ nsight mk
smells =
L.map fst $
L.sortBy (\ (_, s1) (_, s2) -> compare s2 s1) $
L.filter (\ (_, s) -> s > 0) $
L.map (\ x -> (x, nsmap ! (me `shift` x) - time `max` 0)) moves
fromDir d = dirToAction actor `liftM` onlySensible d
+ fromFoe d = setTarget actor newTgt `liftM` fromDir d
strategy =
- fromDir moveAttack
+ fromDir (onlyTraitor moveFreely) -- traitor disguised; hard to target
+ .| fromFoe (onlyFoe moveFreely)
.| (greedyMonster && lootHere me) .=> actionPickup
- .| fromDir moveTowards
+ .| fromFoe moveTowards
.| lootHere me .=> actionPickup
.| fromDir moveAround
actionPickup = return $ actorPickupItem actor
- moveAttack =
- onlyTraitor moveFreely
- .| onlyFoe moveFreely
moveTowards =
(if pushyMonster then id else onlyUnoccupied) $
nsight mk .=> towardsFoe moveFreely
@@ -114,6 +131,11 @@ dirToAction actor dir =
-- if the following action aborts, we just advance the time and continue
moveOrAttack True True actor dir
+setTarget :: Actor -> Target -> Action () -> Action ()
+setTarget actor tgt action = do
+ modify (updateAnyActorBody actor (\ m -> m { mtarget = tgt }))
+ action
+
onlyMoves :: (Dir -> Bool) -> Loc -> Strategy Dir -> Strategy Dir
onlyMoves p l = only (\ x -> p (l `shift` x))

0 comments on commit b3b5fb2

Please sign in to comment.