Files
loop/src/Dodge/Creature/State.hs
T
2021-10-31 19:46:32 +00:00

168 lines
5.5 KiB
Haskell

module Dodge.Creature.State
( stateUpdate
, doDamage
) where
import Dodge.Data
import Dodge.Data.DamageType
import Dodge.Data.SoundOrigin
import Dodge.Item.Data
import Dodge.Creature.State.Data
import Dodge.Creature.State.WalkCycle
import Dodge.Creature.Stance.Data
--import Dodge.Creature.Test
--import Dodge.Base
import Dodge.SoundLogic
import Dodge.SoundLogic.LoadSound
import Dodge.RandomHelp
import Dodge.WorldEvent
--import Dodge.WallCreatureCollisions
import Dodge.Creature.Action
import Geometry
import Picture
import qualified IntMapHelp as IM
--import StrictHelp
import Data.Function
import Control.Lens
--import Control.Applicative
import Control.Monad.State
--import Control.Monad
--import qualified SDL
--import qualified SDL.Mixer as Mix
import System.Random
--import qualified Data.Set as S
--import qualified Data.Map as M
import Data.Monoid
import qualified Data.Vector as V
import qualified Data.Vector.Mutable as MV
--dummyUpdate :: CRUpdate
--dummyUpdate cr _ = (Endo id, Just cr)
-- | The movement is updated before the ai in order to correctly set the oldpos.
stateUpdate :: CRUpdate -> CRUpdate
stateUpdate u cr w = case u (updateMovement cr) w of
(f, maybeCr) ->
( Endo $ invSideEff cr . movementSideEff cr . deathEff . appEndo f
, fmap (stepReloading . stepItemUseCooldown . doDamage . crAutoReload) $ crOrCorpse =<< maybeCr
)
where
crOrCorpse cr'
| cr' ^. crHP > 0 = Just cr'
| otherwise = Nothing
deathEff
| cr ^.crHP > 0 = id
| otherwise = stopSoundFrom (CrWeaponSound (_crID cr) 0)
. over decorations addCorpse
. dropByState cr
addCorpse = IM.insertNewKey
$ uncurryV translate (_crOldPos cr)
$ rotate (_crDir cr)
(_crCorpse cr)
-- | Drop items according to the creature state.
dropByState :: Creature -> World -> World
dropByState cr w = foldr (copyItemToFloor cr) w is
where
is :: [Int]
is = case cr ^. crState . crDropsOnDeath of
DropAll -> IM.keys $ _crInv cr
DropSpecific xs -> xs
DropAmount n -> take n $ evalState (shuffle $ IM.keys $ _crInv cr) (_randGen w)
setOldPos :: Creature -> Creature
setOldPos cr = cr
& crOldPos .~ _crPos cr
& crOldDir .~ _crDir cr
--meleeCooldown :: CRUpdate -> CRUpdate
--meleeCooldown u cr = u $ cr & crMeleeCooldown . _Just %~ (max 0 . (\x -> x - 1))
doDamage :: Creature -> Creature
doDamage cr = set (crState . crDamage) []
. over (crState . crPastDamage) (advancePastDamages dams)
$ snd $ _crApplyDamage cr dams cr
where
dams = _crDamage $ _crState cr
advancePastDamages :: [DamageType] -> V.Vector [DamageType] -> V.Vector [DamageType]
advancePastDamages newDs v = f $ V.backpermute v bpVector
where
f = V.modify $ \v' -> MV.write v' 0 newDs
bpVector :: V.Vector Int
bpVector = V.fromList $ 0 : [0 .. 18]
movementSideEff :: Creature -> World -> World
movementSideEff cr w
| hasJetPack = case cr ^? crStance . carriage of
Just (Boosting v)
-> makeFlameletTimed
(oldPos +.+ (_crRad cr + 3) *.* unitVectorAtAngle (_crDir cr + pi))
20
(momentum +.+ 1 *.* rotateV randDir (vInverse v))
Nothing
1
20
$ set randGen g w
_ -> w
| otherwise = footstepSideEffect cr w
where
hasJetPack = any (\it -> it ^? itIdentity == Just JetPack) $ _crInv cr
oldPos = _crOldPos cr
momentum' = 0.97 *.* (_crPos cr -.- _crOldPos cr)
momentum'' | magV momentum' > 3 = 3 *.* normalizeV momentum'
| otherwise = momentum'
momentum = momentum'' +.+ 0.01 *.* unitVectorAtAngle randAng
(randDir,g) = randomR (-0.5,0.5) $ _randGen w
(randAng,_) = randomR (0,2*pi) $ _randGen w
invSideEff :: Creature -> World -> World
invSideEff cr w = weaponReloadSounds cr $ IM.foldrWithKey f w (_crInv cr)
where
f i it w' = case it ^? itEffect . itInvEffect of
Nothing -> w'
Just g -> g (_itEffect it) cr i w'
weaponReloadSounds :: Creature -> World -> World
weaponReloadSounds cr w = case _crInv cr IM.!? _crInvSel cr of
Just Weapon{_wpReloadType = PassiveReload stype,_wpReloadTime=rt,_wpReloadState=rs}
| rt == rs -> soundContinue (CrReloadSound 0) (_crPos cr) stype Nothing w
| otherwise -> w
Just Weapon{_wpReloadState = 0} -> w
Just Weapon{_wpReloadState = 1} -> stopSoundFrom (CrReloadSound cid) w
Just Weapon{} -> soundContinue (CrReloadSound cid) (_crPos cr) reloadS (Just 1) w
_ -> w
where
cid = _crID cr
updateMovement :: Creature -> Creature
updateMovement cr
| isFrictionless cr = over crPos (+.+ momentum) $ setOldPos cr
| otherwise = updateWalkCycle $ setOldPos cr
where
momentum' = 0.98 *.* (_crPos cr -.- _crOldPos cr)
momentum'' | magV momentum' > 1 = 1 *.* normalizeV momentum'
| otherwise = momentum'
momentum = momentum''
isFrictionless :: Creature -> Bool
isFrictionless cr = case cr ^? crStance . carriage of
Just (Boosting _) -> True
Just Floating -> True
_ -> False
stepItemUseCooldown :: Creature -> Creature
stepItemUseCooldown cr = cr & crInv . ix iSel %~
(itUseTime %~ decreaseToZero) . (wpCurWarmUp %~ decreaseToZero)
where
iSel = _crInvSel cr
stepReloading :: Creature -> Creature
stepReloading cr = over (crInv . ix iSel . wpReloadState) decreaseToZero cr
where
iSel = _crInvSel cr
decreaseToZero :: Int -> Int
decreaseToZero x = max 0 (x - 1)