168 lines
5.5 KiB
Haskell
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)
|
|
|