{-# LANGUAGE LambdaCase #-} module Dodge.EnergyBall ( updateEnergyBall, makeFlamelet, makeMovingEB, ) where import Data.Maybe import Dodge.Base.Collide import Dodge.Damage import Dodge.Data.World import Dodge.SoundLogic import Dodge.Spark import Geometry import LensHelp import Linear.V3 import Picture import RandomHelp makeFlamelet :: Point3 -> Point3 -> Float -> Int -> World -> World makeFlamelet p v s t = cWorld . lWorld . energyBalls .:~ EnergyBall { _ebVel = v , _ebPos = p , _ebTimer = t , _ebType = FlameletBall s } updateEnergyBall :: World -> EnergyBall -> (World, Maybe EnergyBall) updateEnergyBall w eb | _ebTimer eb <= 0 = (w, Nothing) | otherwise = ( ebEffect eb . ebFlicker eb $ ebDamage (eb ^. ebPos) (_ebType eb) w , Just $ eb & ebTimer -~ 1 & ebPos . _xy .~ bp & ebVel . _xy .~ drag * bv ) where drag = case eb ^. ebType of ExplosiveBall -> 0.9 _ -> 0.85 p = (eb ^. ebPos + eb ^. ebVel) ^. _xy (bp, bv) = fromMaybe (p, eb ^. ebVel . _xy) $ bouncePoint (const True) 0 (eb ^. ebPos . _xy) p w ebEffect :: EnergyBall -> World -> World ebEffect eb = case _ebType eb of ElectricalBall i -> soundContinue (EBSound i) (eb ^. ebPos . _xy) elecCrackleS (Just 2) . randSparkExtraVel (eb ^. ebVel . _xy) ElectricSpark (state (randomR (3, 6))) (state (randomR (0, 2 * pi))) (eb ^. ebPos . _xy) IncendiaryBall{} | _ebTimer eb == 20 -> soundStart (EBSound (-1)) (eb ^. ebPos . _xy) fireFadeS Nothing _ -> id makeMovingEB :: Point2 -> EnergyBallType -> Point2 -> World -> World makeMovingEB v ebt p = cWorld . lWorld . energyBalls .:~ EnergyBall { _ebVel = v `v2z` 0 , _ebPos = p `v2z` 20 , _ebTimer = 20 , _ebType = ebt } ebFlicker :: EnergyBall -> World -> World ebFlicker pt | _ebTimer pt `mod` 7 == 0 = cWorld . lWorld . lights .:~ LSParam (pt ^. ebPos) 70 (0.5 * xyzV4 (ebColor pt)) | otherwise = id ebColor :: EnergyBall -> Color ebColor eb = case eb ^. ebType of IncendiaryBall{} -> red FlameletBall{} -> red ElectricalBall{} -> cyan ExplosiveBall -> white FlashBall -> white ebDamage :: Point3 -> EnergyBallType -> World -> World ebDamage sp dt | z > 0 && z < 25 = damageInCircle (const $ ebtToDamage (sp ^. _xy) dt) (sp ^. _xy) r | otherwise = id where z = sp ^. _z r = fromMaybe 5 $ dt ^? fbSize ebtToDamage :: Point2 -> EnergyBallType -> Damage ebtToDamage p = \case FlameletBall{} -> Flaming 1 IncendiaryBall{} -> Flaming 10 ElectricalBall{} -> Electrical 10 ExplosiveBall -> Explosive 10 p FlashBall -> Flashing 10 p