{-# OPTIONS_GHC -Wno-unused-imports #-} module Dodge.Projectile.Update where import Control.Lens import qualified Data.Map.Strict as M import Data.Maybe import Dodge.Base import Dodge.Data.World import Dodge.Default.Weapon import Dodge.EnergyBall import Dodge.Item.Location import Dodge.Item.Weapon.Launcher import Dodge.Item.Weapon.Remote import Dodge.Item.Weapon.Shell import Dodge.Item.Weapon.TriggerType import Dodge.Movement.Turn import Dodge.Payload import Dodge.Reloading.Action import Dodge.SoundLogic import Dodge.SoundLogic.LoadSound import Dodge.WorldEvent.Cloud import Geometry import qualified IntMapHelp as IM import RandomHelp import qualified SDL updateProjectile :: Proj -> World -> World updateProjectile pj = case pj of Shell{} -> upsProjectile pj shellCollisionCheck :: (Proj -> World -> World) -> Proj -> World -> World shellCollisionCheck doExplode pj w | time > 330 && circOnSomeWall oldPos 4 w = doExplode pj w | time <= 330 && anythingHitCirc 2 oldPos newPos w = doExplode pj w | time <= 0 = doExplode pj w | otherwise = w where time = _prjTimer pj oldPos = _prjPos pj vel = _prjVel pj newPos = oldPos +.+ vel remoteShellCollisionCheck :: Proj -> World -> World remoteShellCollisionCheck = shellCollisionCheck $ \pj -> explodeRemoteRocket (fromJust (_prjMITID pj)) (_prjID pj) plainShellCollisionCheck :: Proj -> World -> World plainShellCollisionCheck = shellCollisionCheck $ \pj -> usePayload (_prjPayload pj) (_prjPos pj) . stopSoundFrom (ShellSound (_prjID pj)) . (cWorld . lWorld . projectiles %~ IM.delete (_prjID pj)) upsProjectile :: Proj -> World -> World upsProjectile pj w' = foldr (`upProjectile` pj) w' (_prjUpdates pj) upProjectile :: ProjectileUpdate -> Proj -> World -> World upProjectile pu pj = case pu of PJRemoteShellCollisionCheck -> remoteShellCollisionCheck pj PJShellCollisionCheck -> plainShellCollisionCheck pj PJDecTimMvVel -> decTimMvVel pj PJThrust st et | act st et -> doThrust pj | otherwise -> id PJSpin t cid spinamount | ain t -> trySpinByCID cid spinamount pj | otherwise -> id PJTrack st et itid | act st et -> pjTrack itid pj | otherwise -> id PJReduceSpin x -> reduceSpinBy x pj PJRemoteDirection st et cid itid | act st et -> setRemoteDir cid itid pj | otherwise -> id PJSetScope itid -> setRemoteScope itid (_prjPos pj) PJRetireRemote itid 0 pjid -> retireRemoteProj itid pjid PJRetireRemote _ _ pjid -> cWorld . lWorld . projectiles . ix pjid . prjUpdates . ix 0 . pjuTimer -~ 1 where time = _prjTimer pj act st et = time <= st && time >= et ain t = time == t retireRemoteProj :: Int -> Int -> World -> World retireRemoteProj itid pjid w = w & pointerToItemLocation (w ^?! cWorld . lWorld . itemLocations . ix itid) %~ ( (itScope . scopePos .~ V2 0 0) . (itUse . heldUse .~ HeldFireRemoteShell) ) & cWorld . lWorld . props %~ IM.delete pjid setRemoteDir :: Int -> Int -> Proj -> World -> World setRemoteDir cid itid pj w = w & cWorld . lWorld . projectiles . ix (_prjID pj) . prjAcc .~ turntonewdir where turntonewdir = magV (_prjAcc pj) *.* unitVectorAtAngle newdir --i = _prjID pj newdir | SDL.ButtonRight `M.member` _mouseButtons w && w ^? cWorld . lWorld . creatures . ix cid . crInvSel . iselPos == w ^? cWorld . lWorld . itemLocations . ix itid . ipInvID = (w ^. cWorld . lWorld . camPos . camRot) + argV (_mousePos w) | otherwise = _prjDir pj doThrust :: Proj -> World -> World doThrust pj w = w & randGen .~ g & cWorld . lWorld . projectiles . ix i . prjVel %~ (\v -> accel +.+ frict *.* v) & soundContinue (ShellSound i) newPos missileLaunchS (Just 1) & makeFlamelet (oldPos -.- vel) 0 (vel +.+ rotateV (pi + sparkD) accel) 3 10 & shellTrailCloud (addZ 20 (oldPos +.+ r1 +.+ 30 *.* normalizeV (oldPos -.- newPos))) where accel = _prjAcc pj i = _prjID pj oldPos = _prjPos pj vel = _prjVel pj newPos = oldPos +.+ vel (frict, g) = randomR (0.6, 0.9) $ _randGen w (sparkD, _) = randomR (-0.2, 0.2) $ _randGen w r1 = randInCirc 10 & evalState $ _randGen w trySpinByCID :: -- | creature id Int -> -- | Spin amount Int -> Proj -> World -> World trySpinByCID cid i pj w = w & cWorld . lWorld . projectiles . ix pjid . prjSpin .~ newSpin where pjid = _prjID pj dir = argV $ _prjVel pj newSpin = case w ^? cWorld . lWorld . creatures . ix cid of Just cr -> negate $ min 0.2 $ max (-0.2) $ normalizeAnglePi (dir - _crDir cr) / spinFactor _ -> 0 spinFactor = 5 * (6 - fromIntegral i) pjTrack :: Int -> Proj -> World -> World pjTrack itid pj w = rotateToTarget pj w where rotateToTarget _ = fromMaybe id $ do tpos <- w ^? itPoint . itTargeting . tgPos . _Just return $ cWorld . lWorld . projectiles . ix (_prjID pj) . prjSpin .~ turnToAmount 0.15 (_prjPos pj) tpos (argV $ _prjAcc pj) itPoint = pointerToItemLocation $ w ^?! cWorld . lWorld . itemLocations . ix itid reduceSpinBy :: Float -> Proj -> World -> World reduceSpinBy x pj = cWorld . lWorld . projectiles . ix (_prjID pj) . prjSpin *~ x