Files
loop/src/Dodge/Projectile/Update.hs
T
2022-08-22 11:23:19 +01:00

154 lines
5.2 KiB
Haskell

{-# 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 . 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 . 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 (_itemLocations (_cWorld w) IM.! itid)
%~ ( (itScope . scopePos .~ V2 0 0)
. (itUse . heldUse .~ HeldFireRemoteShell)
)
& cWorld . props %~ IM.delete pjid
setRemoteDir :: Int -> Int -> Proj -> World -> World
setRemoteDir cid itid pj w = w & cWorld . 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 . creatures . ix cid . crInvSel . iselPos
== w ^? cWorld . itemLocations . ix itid . ipInvID
= (w ^. cWorld . cwCam . cwcRot) + argV (_mousePos w)
| otherwise = _prjDir pj
doThrust :: Proj -> World -> World
doThrust pj w =
w
& randGen .~ g
& cWorld . 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 . projectiles . ix pjid . prjSpin .~ newSpin
where
pjid = _prjID pj
dir = argV $ _prjVel pj
newSpin = case w ^? cWorld . 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 . projectiles . ix (_prjID pj) . prjSpin
.~ turnToAmount
0.15
(_prjPos pj)
tpos
(argV $ _prjAcc pj)
itPoint = pointerToItemLocation $ _itemLocations (_cWorld w) IM.! itid
reduceSpinBy :: Float -> Proj -> World -> World
reduceSpinBy x pj = cWorld . projectiles . ix (_prjID pj) . prjSpin *~ x