module Game.Entities.Slime (mkSlime) where import Data.Bits (Bits (..)) import Game.Entities.Common import Game.Entities.Const import Game.Entities.Types import qualified Game.Sprites as S mkSlime :: S.SpriteSheet -> Int -> Int -> Dir -> Collision -> IsBlocked -> IO Entity mkSlime sprites x y d playerCollision isBlocked = do s <- S.get sprites "slime" pure Entity { typ = TypeEnemy, x = x, y = y, delay = frameDelay, frame = 0, set = 0, jumping = False, gravity = gravityOff, dir = d, sprite = s, update = updateSlime playerCollision isBlocked, destroy = False, actions = [] } updateSlime :: Collision -> IsBlocked -> Entity -> IO Entity updateSlime touchedPlayer isBlocked e = do touched <- touchedPlayer e let updated = updateSlimeFrame pure $ if touched then updated {actions = [ActionHitPlayer]} else 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}