Don't walk gormlaks into walls

Because of the way lines are drawn, a specific configuration of
positioning for gormlaks would have them decide they desperately wanted
to walk *inside* a wall, which they would then both fail to do but also
always collide with whenever they tried to go anywhere else.
This commit is contained in:
Griffin Smith 2019-10-15 22:54:31 -04:00
parent 8a4220df83
commit 4882350f5d
3 changed files with 31 additions and 12 deletions

View file

@ -27,7 +27,9 @@ import qualified Xanthous.Entities.RawTypes as Raw
import Xanthous.Entities (Entity(..), Brain(..), brainVia) import Xanthous.Entities (Entity(..), Brain(..), brainVia)
import Xanthous.Game.State (entities, GameState, entityIs) import Xanthous.Game.State (entities, GameState, entityIs)
import Xanthous.Game.Lenses import Xanthous.Game.Lenses
( Collision(..), collisionAt, character, characterPosition ) ( Collision(..), entityCollision, collisionAt
, character, characterPosition
)
import Xanthous.Data.EntityMap.Graphics (linesOfSight, canSee) import Xanthous.Data.EntityMap.Graphics (linesOfSight, canSee)
import Xanthous.Random import Xanthous.Random
import Xanthous.Monad (say) import Xanthous.Monad (say)
@ -72,9 +74,13 @@ stepGormlak ticks pe@(Positioned pos creature) = do
then attackCharacter $> pos' then attackCharacter $> pos'
else pure $ pos' `stepTowards` charPos else pure $ pos' `stepTowards` charPos
else do else do
lines <- uses entities $ linesOfSight pos' (Creature.visionRadius creature') lines <- map (takeWhile (isNothing . entityCollision . map snd . snd)
-- the first item on these lines is always the creature itself
. fromMaybe mempty . tailMay)
. linesOfSight pos' (Creature.visionRadius creature')
<$> use entities
line <- choose $ weightedBy length lines line <- choose $ weightedBy length lines
pure $ fromMaybe pos' $ fmap fst . headMay =<< tailMay =<< line pure $ fromMaybe pos' $ fmap fst . headMay =<< line
vision = Creature.visionRadius creature vision = Creature.visionRadius creature
attackCharacter = do attackCharacter = do

View file

@ -10,6 +10,7 @@ module Xanthous.Game.Lenses
-- * Collisions -- * Collisions
, Collision(..) , Collision(..)
, entityCollision
, collisionAt , collisionAt
) where ) where
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -93,13 +94,21 @@ data Collision
deriving stock (Show, Eq, Ord, Generic) deriving stock (Show, Eq, Ord, Generic)
deriving anyclass (NFData) deriving anyclass (NFData)
collisionAt :: MonadState GameState m => Position -> m (Maybe Collision) entityCollision
collisionAt pos = do :: ( MonoFoldable (f SomeEntity)
ents <- use $ entities . EntityMap.atPosition pos , Foldable f
pure $ , Element (f SomeEntity) ~ SomeEntity
if | null ents -> Nothing , AsEmpty (f SomeEntity)
| any (entityIs @Creature) ents -> pure Combat )
| all (entityIs @Item) ents -> Nothing => f SomeEntity
-> Maybe Collision
entityCollision Empty = Nothing
entityCollision ents
| any (entityIs @Creature) ents = pure Combat
| all (entityIs @Item) ents = Nothing
| doors@(_ : _) <- ents ^.. folded . _SomeEntity @Door | doors@(_ : _) <- ents ^.. folded . _SomeEntity @Door
, all (view open) doors -> Nothing , all (view open) doors = Nothing
| otherwise -> pure Stop | otherwise = pure Stop
collisionAt :: MonadState GameState m => Position -> m (Maybe Collision)
collisionAt pos = uses (entities . EntityMap.atPosition pos) entityCollision

View file

@ -21,4 +21,8 @@ test = testGroup "Xanthous.Util"
forAll (shuffle xs) $ \shuffledXs -> forAll (shuffle xs) $ \shuffledXs ->
smallestNotIn xs === smallestNotIn shuffledXs smallestNotIn xs === smallestNotIn shuffledXs
] ]
, testGroup "takeWhileInclusive"
[ testProperty "takeWhileInclusive (const True) ≡ id"
$ \(xs :: [Int]) -> takeWhileInclusive (const True) xs === xs
]
] ]