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
|
module Game.Entities.Shooter (mkShooter) where
import Data.Bits (Bits (..))
import Game.Entities.Common
import Game.Entities.Const
import Game.Entities.Types
import Game.Sprites qualified as S
blasterCoolDown :: Int
blasterCoolDown = 128
mkShooter :: S.SpriteSheet -> Int -> Int -> Dir -> Collision -> Collision -> IsBlocked -> Collision -> IO Entity
mkShooter sprites x y d playerCollision playerInLine isBlocked playerVsBlast = do
s <- S.get sprites "shooter"
pure
Entity
{ typ = TypeEnemy,
x = x,
y = y,
delay = frameDelay,
frame = 0,
set = toSpriteSet d,
jumping = False,
gravity = gravityOff,
dir = d,
sprite = s,
update = updateShooter playerCollision playerInLine isBlocked playerVsBlast,
destroy = False,
actions = [],
dat = ShooterData 0
}
updateShooter :: Collision -> Collision -> IsBlocked -> Collision -> Entity -> IO Entity
updateShooter touchedPlayer playerInLine isBlocked playerVsBlast e = do
touched <- touchedPlayer e
line <- playerInLine e
pure $ update touched line (updateFrame True (updateCoolDown e))
where
update :: Bool -> Bool -> Entity -> Entity
update wasTouched wasInLine ent
| wasInLine && ent.dat.coolDown == 0 =
ent
{ dat = ShooterData blasterCoolDown,
actions = [ActionAddBlast blastX (ent.y + 8) ent.dir playerVsBlast isBlocked],
frame = 1,
delay = frameDelay * 2
}
| wasTouched = ent {actions = [ActionHitPlayer]}
| testBit ent.delay 1 = ent
| ent.dir == DirLeft
&& (isBlocked (ent.x - 1) (ent.y + 17) || isBlocked (ent.x - 1) (ent.y + 17) || not (isBlocked (ent.x - 1) (ent.y + 24))) =
ent {dir = DirRight, set = toSpriteSet DirRight}
| ent.dir == DirLeft = ent {x = ent.x - 1}
| ent.dir == DirRight
&& (isBlocked (ent.x + 16) (ent.y + 17) || isBlocked (ent.x + 16) (ent.y + 17) || not (isBlocked (ent.x + 16) (ent.y + 24))) =
ent {dir = DirLeft, set = toSpriteSet DirLeft}
| ent.dir == DirRight = ent {x = ent.x + 1}
| otherwise = ent
updateCoolDown :: Entity -> Entity
updateCoolDown ent
| ent.dat.coolDown > 0 = ent {dat = ShooterData (ent.dat.coolDown - 1)}
| otherwise = ent
blastX = case e.dir of
DirLeft -> e.x - 16
DirRight -> e.x + 16
|