about summary refs log tree commit diff
path: root/src/Xanthous/Entities/Creature.hs
blob: 6ea6f93e425479317d318a9eeb378f59e1e96483 (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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
--------------------------------------------------------------------------------
module Xanthous.Entities.Creature
  ( -- * Creature
    Creature(..)
    -- ** Lenses
  , creatureType
  , hitpoints
  , hippocampus

    -- ** Creature functions
  , newWithType
  , damage
  , isDead
  , visionRadius

    -- * Hippocampus
  , Hippocampus(..)
    -- ** Lenses
  , destination
    -- ** Destination
  , Destination(..)
  , destinationFromPos
    -- *** Lenses
  , destinationPosition
  , destinationProgress
  ) where
--------------------------------------------------------------------------------
import           Xanthous.Prelude
--------------------------------------------------------------------------------
import           Test.QuickCheck
import           Test.QuickCheck.Arbitrary.Generic
import           Data.Aeson.Generic.DerivingVia
import           Data.Aeson (ToJSON, FromJSON)
--------------------------------------------------------------------------------
import           Xanthous.Entities.RawTypes hiding (Creature, description)
import           Xanthous.Entities (Draw(..), DrawRawChar(..))
import           Xanthous.Data
--------------------------------------------------------------------------------

data Destination = Destination
  { _destinationPosition :: !Position
    -- | The progress towards the destination, tracked as an offset from the
    -- creature's original position.
    --
    -- When this value reaches >= 1, the creature has reached their destination
  , _destinationProgress :: !Tiles
  }
  deriving stock (Eq, Show, Generic)
  deriving anyclass (NFData, CoArbitrary, Function)
  deriving (ToJSON, FromJSON)
       via WithOptions '[ FieldLabelModifier '[Drop 1] ]
                       Destination
instance Arbitrary Destination where arbitrary = genericArbitrary
makeLenses ''Destination

destinationFromPos :: Position -> Destination
destinationFromPos _destinationPosition =
  let _destinationProgress = 0
  in Destination{..}

data Hippocampus = Hippocampus
  { _destination :: !(Maybe Destination)
  }
  deriving stock (Eq, Show, Generic)
  deriving anyclass (NFData, CoArbitrary, Function)
  deriving (ToJSON, FromJSON)
       via WithOptions '[ FieldLabelModifier '[Drop 1] ]
                       Hippocampus
instance Arbitrary Hippocampus where arbitrary = genericArbitrary
makeLenses ''Hippocampus

initialHippocampus :: Hippocampus
initialHippocampus = Hippocampus Nothing

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

data Creature = Creature
  { _creatureType :: !CreatureType
  , _hitpoints    :: !Word
  , _hippocampus  :: !Hippocampus
  }
  deriving stock (Eq, Show, Generic)
  deriving anyclass (NFData, CoArbitrary, Function)
  deriving Draw via DrawRawChar "_creatureType" Creature
  deriving (ToJSON, FromJSON)
       via WithOptions '[ FieldLabelModifier '[Drop 1] ]
                       Creature
instance Arbitrary Creature where arbitrary = genericArbitrary
makeLenses ''Creature


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

newWithType :: CreatureType -> Creature
newWithType _creatureType =
  let _hitpoints = _creatureType ^. maxHitpoints
      _hippocampus = initialHippocampus
  in Creature {..}

damage :: Word -> Creature -> Creature
damage amount = hitpoints %~ \hp ->
  if hp <= amount
  then 0
  else hp - amount

isDead :: Creature -> Bool
isDead = views hitpoints (== 0)

visionRadius :: Creature -> Word
visionRadius = const 50 -- TODO

{-# ANN module ("Hlint: ignore Use newtype instead of data" :: String) #-}