Permalink
Browse files

don't target and fire at actors others can see/reach, but you can't

  • Loading branch information...
1 parent b39b854 commit d178c1d880525ed986789b8de71d2fd8b9dd0226 @Mikolaj Mikolaj committed Mar 22, 2011
Showing with 33 additions and 27 deletions.
  1. +18 −15 src/Actions.hs
  2. +3 −3 src/Command.hs
  3. +0 −1 src/Movable.hs
  4. +12 −5 src/Perception.hs
  5. +0 −3 src/StrategyState.hs
View
@@ -161,12 +161,12 @@ continueRun dir =
msg <- currentMessage
let lvl@(Level { lmap = lmap, lheroes = hs }) = slevel state
mslocs = S.fromList (L.map mloc (levelMonsterList state))
- t = lmap `at` loc -- tile at current location
monstersVisible = not (S.null (mslocs `S.intersection` ptvisible per))
newsReported = not (L.null msg)
- itemsHere = not (L.null (titems t))
- heroThere = L.elem (loc `shift` dir) (L.map mloc (IM.elems hs))
- dirOK = accessible lmap loc (loc `shift` dir)
+ t = lmap `at` loc -- tile at current location
+ itemsHere = not (L.null (titems t))
+ heroThere = L.elem (loc `shift` dir) (L.map mloc (IM.elems hs))
+ dirOK = accessible lmap loc (loc `shift` dir)
-- What happens next is mostly depending on the terrain we're currently on.
let exit (Stairs {}) = True
exit (Opening {}) = True
@@ -522,10 +522,9 @@ targetFloor = do
-- | Start the monster targeting mode. Cycle between monster targets.
-- TODO: also target a monster by moving the cursor, if in target monster mode.
-- TODO: sort monsters by distance to the player.
--- TODO: when each hero has his own perception, only target monsters
--- visible by the current player.
targetMonster :: Action ()
targetMonster = do
+ pl <- gets splayer
ms <- gets (lmonsters . slevel)
per <- currentPerception
target <- gets (mtarget . getPlayerBody)
@@ -536,7 +535,7 @@ targetMonster = do
_ -> -1 -- try to target first monster (e.g., number 0)
(lt, gt) = IM.split i ms
gtlt = IM.assocs gt ++ IM.assocs lt
- lf = L.filter (\ (_, m) -> S.member (mloc m) (ptvisible per)) gtlt
+ lf = L.filter (\ (_, m) -> actorSeesLoc pl (mloc m) per pl) gtlt
tgt = case lf of
[] -> target -- no monsters in sight, stick to last target
(ni, _) : _ -> TEnemy (AMonster ni) -- pick the next monster
@@ -653,28 +652,32 @@ fireItem = do
case targetToLoc state (ptvisible per) of
Nothing -> abortWith "target invalid"
Just loc ->
- case locToActor state loc of
- Just a -> actorDamageActor pl a 1 " with a dart"
- Nothing -> modify (updateLevel (scatterItems [fired] loc))
+ if actorReachesLoc pl loc per pl
+ then case locToActor state loc of
+ Just ta -> actorDamageActor pl ta 1 " with a dart"
+ Nothing -> modify (updateLevel (scatterItems [fired] loc))
+ else abortWith "target not reachable"
Nothing -> abortWith "nothing to fire"
playerAdvanceTime
applyItem :: Action ()
applyItem = do
+ pl <- gets splayer
state <- get
per <- currentPerception
pitems <- gets (mitems . getPlayerBody)
case findItem (\ i -> itype i == Wand) pitems of
Just (wand, _) -> do
let applied = wand { icount = 1 }
+ removeFromInventory applied
case targetToLoc state (ptvisible per) of
Nothing -> abortWith "target invalid"
Just loc ->
- case locToActor state loc of
- Just targetActor -> do
- removeFromInventory applied
- selectPlayer targetActor >> return ()
- Nothing -> abortWith "no living target to affect"
+ if actorReachesLoc pl loc per pl
+ then case locToActor state loc of
+ Just ta -> selectPlayer ta >> return ()
+ Nothing -> abortWith "no living target to affect"
+ else abortWith "target not reachable"
Nothing -> abortWith "nothing to apply"
playerAdvanceTime
View
@@ -21,10 +21,10 @@ searchCommand = Described "search for secret doors" (checkCursor search)
ascendCommand = Described "ascend a level" (lvlchange Up)
descendCommand = Described "descend a level" (lvlchange Down)
floorCommand = Described "target location" targetFloor
-monsterCommand = Described "target monster" targetMonster
+monsterCommand = Described "target monster" (checkCursor targetMonster)
drinkCommand = Described "quaff a potion" drinkPotion
-fireCommand = Described "fire an item" fireItem
-applyCommand = Described "aim a wand " applyItem -- TODO: change descriptions as soon as the command generalized and requires specifying an item
+fireCommand = Described "fire an item" (checkCursor fireItem)
+applyCommand = Described "aim a wand " (checkCursor applyItem) -- TODO: change descriptions as soon as the command generalized and requires specifying an item
waitCommand = Described "wait" playerAdvanceTime
saveCommand = Described "save and quit the game" saveGame
quitCommand = Described "quit without saving" quitGame
View
@@ -14,7 +14,6 @@ data Movable = Movable
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,
--- TODO: mper :: Maybe Perception -- see https://github.com/Mikolaj/LambdaHack/issues/issue/31
mloc :: !Loc,
mitems :: [Item], -- inventory
mletter :: !Char, -- next inventory letter
View
@@ -30,20 +30,27 @@ ptreachable = preachable . ptotal
ptvisible :: Perceptions -> S.Set Loc
ptvisible = pvisible . ptotal
-actorSeesLoc :: Actor -> Loc -> Perceptions -> Actor -> Bool
-actorSeesLoc actor loc per pl =
+actorPrLoc :: (Perception -> S.Set Loc) ->
+ Actor -> Loc -> Perceptions -> Actor -> Bool
+actorPrLoc projection actor loc per pl =
let tryHero = case actor of
AMonster _ -> Nothing
AHero i -> do
hper <- IM.lookup i (pheroes per)
- return $ loc `S.member` (pvisible hper)
+ return $ loc `S.member` (projection hper)
tryPl = do -- the case for a monster under player control
guard $ actor == pl
pper <- pplayer per
- return $ loc `S.member` pvisible pper
+ return $ loc `S.member` projection pper
tryAny = tryHero `mplus` tryPl
in fromMaybe False tryAny -- assume not visible, if no perception found
+actorSeesLoc :: Actor -> Loc -> Perceptions -> Actor -> Bool
+actorSeesLoc = actorPrLoc pvisible
+
+actorReachesLoc :: Actor -> Loc -> Perceptions -> Actor -> Bool
+actorReachesLoc = actorPrLoc preachable
+
-- Not quite correct if FOV not symmetric (Shadow).
actorSeesActor :: Actor -> Actor -> Loc -> Loc -> Perceptions -> Actor -> Bool
actorSeesActor actor1 actor2 loc1 loc2 per pl =
@@ -70,7 +77,7 @@ perception_ state@(State { slevel = Level { lmap = lmap, lheroes = hs },
"shadow" -> Shadow
_ -> error $ "perception_: unknown mode: " ++ show mode
- pers = IM.map (\ pl -> perception fovMode (mloc pl) lmap) hs
+ pers = IM.map (\ h -> perception fovMode (mloc h) lmap) hs
lpers = IM.elems pers
pper = Nothing -- TODO, and add it to ptotal, in case it's monster
reachable = S.unions (L.map preachable lpers)
View
@@ -48,9 +48,6 @@ strategy actor
ploc = case lmhVisible of
[] -> Nothing
_ -> Just $ snd $ L.minimum lmhDist
- -- TODO: currently even invisible heroes are targeted if _any_ hero
- -- is visible; each hero should carry his own perception to check
- -- if he's visible by a given monster
playerVisible = isJust ploc -- monster sees any hero
playerAdjacent = maybe False (adjacent me) ploc
towardsPlayer = maybe (0, 0) (\ ploc -> towards (me, ploc)) ploc

0 comments on commit d178c1d

Please sign in to comment.