194 lines
6.6 KiB
Haskell
194 lines
6.6 KiB
Haskell
module Dodge.Creature.State
|
|
( stateUpdate
|
|
, doDamage
|
|
) where
|
|
import Dodge.Data
|
|
import Dodge.Hammer
|
|
import Dodge.Reloading
|
|
|
|
import Dodge.Base
|
|
import Dodge.Creature.State.WalkCycle
|
|
--import Dodge.Creature.Test
|
|
--import Dodge.Base
|
|
import Dodge.SoundLogic
|
|
import Dodge.RandomHelp
|
|
import Dodge.WorldEvent
|
|
--import Dodge.WallCreatureCollisions
|
|
import Dodge.Creature.Action
|
|
--import Dodge.Hammer
|
|
import Geometry
|
|
import Picture
|
|
import qualified IntMapHelp as IM
|
|
--import StrictHelp
|
|
|
|
import qualified Data.IntSet as IS
|
|
--import Data.Maybe
|
|
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 qualified Data.Vector as V
|
|
--import qualified Data.Vector.Mutable as MV
|
|
|
|
foldCr :: [Creature -> World -> World]
|
|
-> Creature -> World -> World
|
|
foldCr xs cr w = foldr ($ cr) w xs
|
|
|
|
-- | this seems to work, but I am not sure about the ordering:
|
|
-- previously, the movement was updated before the ai in order to correctly set the oldpos.
|
|
-- This should be made more sensible: should the movement side effects apply to
|
|
-- the creature before or after it has moved?
|
|
-- at what point invSideEffects is applied wrt to when the creature moves
|
|
-- may effect whether the shield moves correctly
|
|
stateUpdate :: (Creature -> World -> World) -> Creature -> World -> World
|
|
stateUpdate f = foldCr
|
|
[ checkDeath
|
|
, doDamage
|
|
, invSideEff
|
|
, movementSideEff
|
|
, internalUpdate
|
|
, f
|
|
]
|
|
|
|
checkDeath :: Creature -> World -> World
|
|
checkDeath cr w
|
|
| _crHP cr > 0 = w
|
|
| otherwise = w
|
|
& creatures . at (_crID cr) .~ Nothing
|
|
& stopSoundFrom (CrWeaponSound (_crID cr) 0)
|
|
& over decorations addCorpse
|
|
& dropByState cr
|
|
where
|
|
addCorpse = IM.insertNewKey
|
|
$ uncurryV translate (_crOldPos cr)
|
|
$ rotate (_crDir cr)
|
|
(_crCorpse cr)
|
|
|
|
internalUpdate :: Creature -> World -> World
|
|
internalUpdate cr = creatures . ix (_crID cr) %~
|
|
( (crHammerPosition %~ moveHammerUp)
|
|
. stepReloading
|
|
. updateMovement
|
|
)
|
|
|
|
-- | Drop items according to the creature state.
|
|
-- TODO make sure this doesn't mess up any ItemPosition
|
|
dropByState :: Creature -> World -> World
|
|
dropByState cr w = foldr (copyInvItemToFloor cr) w $ 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
|
|
|
|
doDamage :: Creature -> World -> World
|
|
doDamage cr w = w
|
|
& creatures . ix (_crID cr) . crState . crDamage .~ []
|
|
& _crApplyDamage cr dams cr
|
|
where
|
|
dams = _crDamage $ _crState cr
|
|
|
|
movementSideEff :: Creature -> World -> World
|
|
movementSideEff cr w
|
|
| hasJetPack = case cr ^? crStance . carriage of
|
|
Just (Boosting v) -> w
|
|
& randGen .~ g
|
|
& makeFlamelet
|
|
(oldPos +.+ (_crRad cr + 3) *.* unitVectorAtAngle (_crDir cr + pi))
|
|
20
|
|
(momentum +.+ 1 *.* rotateV randDir (vInverse v))
|
|
Nothing
|
|
1
|
|
20
|
|
_ -> w
|
|
| otherwise = footstepSideEffect cr w
|
|
where
|
|
hasJetPack = any (\it -> it ^? itType == 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
|
|
|
|
heldItemUpdate :: Item -> Item
|
|
heldItemUpdate = invItemUpdate
|
|
-- . (itUse %~ useupdate)
|
|
-- where
|
|
-- useupdate = id
|
|
|
|
invItemUpdate :: Item -> Item
|
|
invItemUpdate = itUse %~ useupdate
|
|
where
|
|
useupdate = (useHammer . hammerPosition %~ moveHammerUp)
|
|
. (useDelay . warmTime %~ decreaseToZero)
|
|
. (useDelay . rateTime %~ decreaseToZero)
|
|
|
|
invSideEff :: Creature -> World -> World
|
|
invSideEff cr w = weaponReloadSounds cr
|
|
. flip (IS.foldr useeq) (_crInvEquipped cr)
|
|
. doHeldItemTargeting cr
|
|
$ IM.foldrWithKey f w (_crInv cr)
|
|
where
|
|
useeq i = _eqUse (_itUse $ _crInv cr IM.! i) cr i
|
|
f i it w' = case it ^? itEffect . itInvEffect of
|
|
Nothing -> w' & doitemupdate
|
|
Just g -> g (_itEffect it) cr i w' & doitemupdate
|
|
where
|
|
doitemupdate
|
|
| i == _crInvSel cr = itpointer %~ heldItemUpdate
|
|
| otherwise = itpointer %~ invItemUpdate
|
|
itpointer = creatures . ix (_crID cr) . crInv . ix i
|
|
|
|
doHeldItemTargeting :: Creature -> World -> World
|
|
doHeldItemTargeting cr w = case cr ^? crInv . ix (_crInvSel cr) . itTargeting of
|
|
Nothing -> w
|
|
Just NoTargeting -> w
|
|
Just t -> let (w',t') = _tgUpdate t (_crInv cr IM.! _crInvSel cr) cr w t
|
|
in w' & creatures . ix (_crID cr) . crInv . ix (_crInvSel cr) . itTargeting .~ t'
|
|
|
|
weaponReloadSounds :: Creature -> World -> World
|
|
weaponReloadSounds cr w = case cr ^? crInv . ix (_crInvSel cr) . itConsumption of
|
|
Just am@LoadableAmmo{} -> case _reloadType am of
|
|
PassiveReload stype |Just' (_reloadTime am) == _reloadState am
|
|
-> soundContinue (CrReloadSound 0) (_crPos cr) stype Nothing w
|
|
PassiveReload _ -> w
|
|
ActiveClear | _reloadState am == Just' 0 -> stopSoundFrom (CrReloadSound cid) w
|
|
ActiveClear | _reloadState am == Nothing' -> w
|
|
ActiveClear -> soundContinue (CrReloadSound cid) (_crPos cr) reloadS (Just 1) w
|
|
ActivePartial{} | _reloadState am == Just' 0 -> stopSoundFrom (CrReloadSound cid) w
|
|
ActivePartial{} | _reloadState am == Nothing' -> w
|
|
ActivePartial{} -> soundContinue (CrReloadSound cid) (_crPos cr) reloadS (Just 1) w
|
|
Just ChargeableAmmo {} -> w
|
|
Just NoConsumption {} -> w
|
|
Just ItemItselfConsumable {} -> w
|
|
Nothing -> 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
|