about summary refs log tree commit diff
path: root/src/Xanthous/AI/Gormlak.hs
blob: db504c1e7d3a9c09b4d09418b4070b5f1e9c170b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
{-# OPTIONS_GHC -fno-warn-orphans #-}
--------------------------------------------------------------------------------
module Xanthous.AI.Gormlak () where
--------------------------------------------------------------------------------
import           Xanthous.Prelude hiding (lines)
--------------------------------------------------------------------------------
import           Data.Coerce
import           Control.Monad.State
import           Control.Monad.Random
import           Data.Aeson (object)
import qualified Data.Aeson as A
--------------------------------------------------------------------------------
import           Xanthous.Data (Positioned(..), diffPositions, stepTowards, isUnit)
import           Xanthous.Data.EntityMap
import qualified Xanthous.Entities.Creature as Creature
import           Xanthous.Entities.Creature (Creature)
import           Xanthous.Entities.Character (Character)
import qualified Xanthous.Entities.Character as Character
import qualified Xanthous.Entities.RawTypes as Raw
import           Xanthous.Entities (Entity(..), Brain(..), brainVia)
import           Xanthous.Game.State (entities, GameState, entityIs)
import           Xanthous.Game.Lenses
                 ( Collision(..), collisionAt, character, characterPosition )
import           Xanthous.Data.EntityMap.Graphics (linesOfSight, canSee)
import           Xanthous.Random
import           Xanthous.Monad (say)
--------------------------------------------------------------------------------

stepGormlak
  :: (MonadState GameState m, MonadRandom m)
  => Positioned Creature
  -> m (Positioned Creature)
stepGormlak pe@(Positioned pos creature) = do
  newPos <- do
    canSeeCharacter <- uses entities $ canSee (entityIs @Character) pos vision
    if canSeeCharacter
      then do
        charPos <- use characterPosition
        if isUnit (pos `diffPositions` charPos)
          then attackCharacter $> pos
          else pure $ pos `stepTowards` charPos
    else do
      lines <- uses entities $ linesOfSight pos (Creature.visionRadius creature)
      line <- choose $ weightedBy length lines
      pure $ fromMaybe pos $ fmap fst . headMay =<< tailMay =<< line
  collisionAt newPos >>= \case
    Nothing -> pure $ Positioned newPos creature
    Just Stop -> pure pe
    Just Combat -> do
      ents <- use $ entities . atPosition newPos
      when (any (entityIs @Character) ents) attackCharacter
      pure pe

  where
    vision = Creature.visionRadius creature
    attackCharacter = do
      say ["combat", "creatureAttack"] $ object [ "creature" A..= creature ]
      character %= Character.damage 1

newtype GormlakBrain = GormlakBrain Creature

instance Brain GormlakBrain where
  step = fmap coerce . stepGormlak . coerce

--------------------------------------------------------------------------------

instance Brain Creature where step = brainVia GormlakBrain

instance Entity Creature where
  blocksVision _ = False
  description = view $ Creature.creatureType . Raw.description