aboutsummaryrefslogtreecommitdiff
path: root/src/Game/Entities/Shooter.hs
blob: 3a085e4a055c5b3f4d159ff38bb9b210c3887469 (plain)
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