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
|
module Game.Entities.Runner (mkRunner) where
import Data.Bits (Bits (..))
import Game.Entities.Common
import Game.Entities.Const
import Game.Entities.Types
import Game.Sprites qualified as S
import System.Random (randomRIO)
mkRunner :: S.SpriteSheet -> Int -> Int -> Dir -> Collision -> IsBlocked -> IsBlocked -> IO Entity
mkRunner sprites x y d playerCollision isBlocked isBlockedDeadly = do
s <- S.get sprites "runner"
pure
Entity
{ typ = TypeEnemy,
x = x,
y = y,
delay = frameDelay,
frame = 0,
set = toSpriteSet d,
jumping = False,
gravity = gravityOff,
dir = d,
sprite = s,
update = updateRunner playerCollision isBlocked isBlockedDeadly,
destroy = False,
actions = [],
dat = RunnerData 0
}
updateRunner :: Collision -> IsBlocked -> IsBlocked -> Entity -> IO Entity
updateRunner touchedPlayer isBlocked isBlockedDeadly e = do
touched <- touchedPlayer e
if touched
then pure e {actions = [ActionHitPlayer]}
else do
let gravityUpdated = updateGravity isBlocked e
if gravityUpdated.gravity /= gravityOff then pure gravityUpdated else updateMovement $ updateFrame True gravityUpdated
where
updateMovement :: Entity -> IO Entity
updateMovement ent
| testBit ent.delay 1 = pure ent
| ent.dir == DirLeft
&& ( isBlocked (ent.x - 1) (ent.y + 17)
|| isBlocked (ent.x - 1) (ent.y + 17)
|| checkDeadlyFloor (ent.x - 1) (ent.y + 24)
) =
tryJumpingOrTurn ent
| ent.dir == DirLeft = pure ent {x = ent.x - 1}
| ent.dir == DirRight
&& ( isBlocked (ent.x + 16) (ent.y + 17)
|| isBlocked (ent.x + 16) (ent.y + 17)
|| checkDeadlyFloor (ent.x + 16) (ent.y + 24)
) =
tryJumpingOrTurn ent
| ent.dir == DirRight = pure ent {x = ent.x + 1}
| otherwise = pure ent
checkDeadlyFloor :: Int -> Int -> Bool
checkDeadlyFloor x y
| isBlockedDeadly x y = True
| isBlocked x y = False
| otherwise = checkDeadlyFloor x (y + 8)
randomWallCount :: [Int]
randomWallCount = [0, 0, 0, 2, 2, 3]
tryJumpingOrTurn :: Entity -> IO Entity
tryJumpingOrTurn ent
| ent.dat.wallCount > 2
&& not (isBlocked (ent.x + 8) (ent.y + 24 + 8))
&& not (checkDeadlyFloor (ent.x + 8) (ent.y + 24 + 8)) = do
r <- randomRIO (0, length randomWallCount - 1) :: IO Int
pure
ent
{ dir = turn ent.dir,
set = toSpriteSet $ turn ent.dir,
y = e.y + 1,
gravity = gravityDown,
frame = jumpFrame,
dat = RunnerData $ randomWallCount !! r
}
| ent.dat.wallCount > 1 && not (isBlocked (ent.x + 8) (ent.y - 1)) && isBlocked (ent.x + 8) ent.y = do
r <- randomRIO (0, length randomWallCount - 1) :: IO Int
pure
ent
{ dir = turn ent.dir,
set = toSpriteSet $ turn ent.dir,
gravity = gravityUp,
frame = jumpFrame,
actions = [ActionAddEffect ent.x (ent.y + 8) "dust"],
dat = RunnerData $ randomWallCount !! r
}
| otherwise =
pure
ent
{ dir = turn ent.dir,
set = toSpriteSet $ turn ent.dir,
dat = RunnerData (ent.dat.wallCount + 1)
}
|