module Game.Entities.Slime (mkSlime) where import Data.Bits (Bits (..)) import Data.IORef import Game.Entities.Common import Game.Entities.Const import Game.Entities.Types import qualified Game.Sprites as S mkSlime :: S.SpriteSheet -> Int -> Int -> IORef Entity -> IsBlocked -> IO () -> IO Entity mkSlime sprites x y playerRef isBlocked hitPlayer' = do s <- S.get sprites "slime" pure Entity { typ = TypeEnemy, x = x, y = y, delay = frameDelay, frame = 0, jumping = False, gravity = gravityOff, dir = DirRight, sprite = s, update = updateSlime (collision playerRef 16) isBlocked hitPlayer', destroy = False, spawns = [] } updateSlime :: Collision -> IsBlocked -> IO () -> Entity -> IO Entity updateSlime touchedPlayer isBlocked hitPlayer' e = do touched <- touchedPlayer e let updated = updateSlimeFrame if touched then fmap (const e) hitPlayer' else pure $ updateMovement updated where updateMovement :: Entity -> Entity updateMovement ent | testBit ent.delay 1 = ent | ent.dir == DirLeft && (isBlocked (ent.x - 1) (ent.y + 15) || isBlocked (ent.x - 1) (ent.y + 10) || not (isBlocked (ent.x - 1) (ent.y + 16))) = ent {dir = DirRight} | ent.dir == DirLeft = ent {x = ent.x - 1} | ent.dir == DirRight && (isBlocked (ent.x + 16) (ent.y + 15) || isBlocked (ent.x + 16) (ent.y + 10) || not (isBlocked (ent.x + 16) (ent.y + 16))) = ent {dir = DirLeft} | ent.dir == DirRight = ent {x = ent.x + 1} | otherwise = ent updateSlimeFrame :: Entity updateSlimeFrame | e.delay > 0 = e {delay = e.delay - 1} | e.frame + 1 < frameLimit e = e {delay = frameDelay + 2, frame = e.frame + 1} | otherwise = e {delay = frameDelay + 2, frame = 0}