packages feed

nyx-game-0.1.0.0: app/Enemy/Fast.hs

{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses  #-}
{-# LANGUAGE DuplicateRecordFields  #-}
{-# LANGUAGE FlexibleInstances  #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE OverloadedStrings  #-}

module Enemy.Fast where

import qualified SDL
import qualified Play.Engine.MySDL.MySDL as MySDL
import qualified Data.Map as M
import Control.Monad.Except
import Control.Lens

import Play.Engine

import Bullet
import Enemy
import qualified Attack as A
import qualified Attack.SpiralAttack as SA
import qualified Play.Engine.Movement as MV
import qualified Play.Engine.Sprite as Spr
import Data.Maybe (fromJust)


wantedAssets :: [(String, MySDL.ResourceType FilePath)]
wantedAssets =
  [ ("bullet", MySDL.Texture "bullet.png")
  , ("astral-sprite", MySDL.Texture "astral-sprite.png")
  , ("astral", MySDL.Texture "astral.png")
  ]

make :: IPoint -> M.Map String SDL.Texture -> Result Enemy
make posi ts = do
  let textName = "bullet"
  case (,,) <$> M.lookup textName ts <*> M.lookup "astral" ts <*> M.lookup "astral-sprite" ts of
    Nothing ->
      throwError ["Texture not found: astral or " ++ textName ++ " in " ++ show (M.keys ts)]
    Just (bt, et, spr) -> do
      let
        sz = Point 100 100
      pure . mkEnemy $
        MakeEnemy
          { mkePos = posi
          , mkeSize = sz
          , mkeMov = crossMovement (Right ())
          , mkeHealth = 300
          , mkeDirChanger = changeDirection
          , mkeAtk = attackPattern1 bt
          , mkeAtkChanger = \enemy atkId ->
              if
                | enemy ^. health < 200 && atkId < 1 -> pure $ attackPattern2 bt
                | enemy ^. health < 100 && atkId < 2 -> pure $ attackPattern3 bt
                | otherwise -> Nothing

          , mkeSprite =
            fromJust
              $ Spr.make
              $ Spr.MakeArgs
              { mkActionmap = ["normal"]
              , mkAction = "normal"
              , mkTexture = spr
              , mkSize = sz
              , mkMaxPos = 4
              , mkSpeed = 5
              }
          , mkeHitbox = Hitbox
            { _alignment = Point 30 6
            , _size = sz
              & over x (\n -> n - 60)
              & over y (\n -> n - 12)
            }
          , mkeDeathTime = 150
          , mkeDeathParts = Point 4 3
          , mkeDeathTexture = et
          }

crossMovement :: Either () () -> MV.Movement
crossMovement dir = MV.make $ MV.defArgs
  { MV.maxspeed = Point 1.8 1
  , MV.accel = Point (mul 0.4) 0.2
  }
  where
    mul = case dir of
      Left () -> (*) (-1)
      Right () -> (*) 1

attackPattern1 :: SDL.Texture -> A.Attack
attackPattern1 = SA.make 5 0 (1, 9) $ MV.fastGradualStart (Point 3.2 3.2)

attackPattern2 :: SDL.Texture -> A.Attack
attackPattern2 = SA.make 3 0 (1, 7) $ MV.fastGradualStart (Point 3.2 3.2)

attackPattern3 :: SDL.Texture -> A.Attack
attackPattern3 = SA.make 5 0 (3, 7) $ MV.gradualSlowdown (Point 12 14)


changeDirection :: Size -> Enemy -> FPoint
changeDirection wsize enemy
  | enemy ^. direction . x == 0
  , enemy ^. direction . y == 0
  = Point 0 1

  | enemy ^. pos . y >= 0
  , enemy ^. direction . y == 1
  , enemy ^. direction . x == 0
  = Point 1 1

  | enemy ^. pos . y <= 0
  = enemy ^. direction

  | otherwise
  = enemy ^. direction
    & set x
      (if
         | enemy ^. pos . x > (wsize ^. x * 2) `div` 3 -> -1
         | enemy ^. pos . x <= wsize ^. x `div` 3 -> 1
         | otherwise -> enemy ^. direction . x
      )
    & set y
      (if
         | enemy ^. pos . y > 250 -> -1
         | enemy ^. pos . y <= 50 -> 1
         | otherwise -> enemy ^. direction . y
      )