{- | Effects of bullets upon impact with walls or creatures, and possibly force fields. -} module Dodge.Particle.Bullet.HitEffect where import Dodge.Data import Dodge.Data.DamageType import Dodge.Data.SoundOrigin --import Dodge.Base import Dodge.WorldEvent import Dodge.Particle.Bullet.Spawn import Dodge.WorldEvent.DamageBlock import Dodge.SoundLogic import Dodge.SoundLogic.LoadSound import Dodge.RandomHelp import Dodge.WorldEvent.Shockwave import Dodge.Creature.State.Data import Dodge.Creature.Property import Geometry import Geometry.Vector3D import Picture import System.Random import Control.Lens import Control.Monad.State --import Data.Maybe --import qualified Data.IntMap.Strict as IM -- -- | Basic bullet hit creature effect. bulHitCr :: Particle -> Point2 -> Creature -> World -> World bulHitCr bt p cr w | crIsArmouredFrom p cr = createSparkCol 8 colID p1 (argV (p1 -.- p) + d1) . addDamageArmoured $ w | otherwise = addDamage . makeHitSound . flashEff $ w where sp = head $ _btTrail' bt bulVel = _btVel' bt ep = sp +.+ bulVel mvDams = [ PushDam 1 $ 2 *.* bulVel ] addDamage = creatures . ix cid . crState . crDamage %~ ((Piercing 100 sp p ep : mvDams) ++ ) addDamageArmoured = creatures . ix cid . crState . crDamage %~ (mvDams ++) makeHitSound = soundMultiFrom [CrHitSound 0] p hit1S (Just 10) flashEff = over worldEvents (bloodFlashAt p . ) cid = _crID cr (d1,_) = randomR (-0.7,0.7) $ _randGen w colID = _btColor' bt p1 = p +.+ 2 *.* safeNormalizeV (p -.- _crPos cr) {- | Bounce off armoured creatures, otherwise do damage. -} bulBounceArmCr' :: Particle -> Point2 -> Creature -> World -> World bulBounceArmCr' bt p cr w | crIsArmouredFrom p cr = addBouncer . addDamageArmoured $ w | otherwise = addDamage . makeHitSound . flashEff $ w where sp = head $ _btTrail' bt bulVel = _btVel' bt ep = sp +.+ bulVel mvDams = [ PushDam 1 $ 2 *.* bulVel ] addDamage = creatures . ix cid . crState . crDamage %~ ((Piercing 100 sp p ep : mvDams) ++ ) addDamageArmoured = creatures . ix cid . crState . crDamage %~ (mvDams ++) makeHitSound = soundMultiFrom [CrHitSound 0] p hit1S (Just 10) flashEff = over worldEvents ((.) $ bloodFlashAt p) cid = _crID cr newDir = safeNormalizeV (p -.- _crPos cr) pOut = p +.+ 2 *.* newDir reflectVel = magV bulVel *.* newDir addBouncer = worldEvents %~ ( over particles (bouncer :) . ) bouncer = (aGenBulAt Nothing pOut reflectVel (_btHitEffect' bt) (_btWidth' bt) ) {_btTimer' = _btTimer' bt - 1} {- | Bullet pass through creatures. -} bulPenCr' :: Particle -> Point2 -> Creature -> World -> World bulPenCr' bt p cr w = over (creatures . ix cid . crState . crDamage) ([Piercing 50 sp p ep ,Blunt 50 sp p ep ,TorqueDam 1 d1 ,PushDam 1 $ 3 *.* (ep -.- sp) ] ++ ) $ soundMultiFrom [CrHitSound 0] ep hit1S (Just 10) $ over worldEvents (addPiercer . ) w where (d1,_) = randomR (-0.7,0.7) $ _randGen w cid = _crID cr sp = head $ _btTrail' bt ep = sp +.+ _btVel' bt addPiercer = over particles (piercer :) piercer = (aGenBulAt (Just cid) p (_btVel' bt) (_btHitEffect' bt) (_btWidth' bt) ) {_btTimer' = _btTimer' bt - 1} {- | Heavy bullet effects when hitting creature: piercing, blunt, twisting and pushback damage all applied. -} hvBulHitCr :: Particle -> Point2 -> Creature -> World -> World hvBulHitCr bt p cr w = over (creatures . ix cid . crState . crDamage) ([Piercing 200 sp p ep ,Blunt 100 sp p ep ,TorqueDam 1 d1 ,PushDam 1 $ 3 *.* (ep -.- sp) ] ++ ) $ soundMultiFrom [CrHitSound 0] ep hit1S (Just 10) w where (d1,_) = randomR (-0.7,0.7) $ _randGen w cid = _crID cr sp = head $ _btTrail' bt ep = sp +.+ _btVel' bt {- | Create a flamelet when hitting a creature. -} bulIncCr' :: Particle -> Point2 -> Creature -> World -> World bulIncCr' bt p cr w = over (creatures . ix cid . crState . crDamage) ( Piercing 60 sp p ep : ) . soundMultiFrom [CrHitSound 0] p hit1S (Just 10) $ incFlamelets w where cid = _crID cr sp = head $ _btTrail' bt ep = sp +.+ _btVel' bt v = evalState (randInCirc 1) $ _randGen w incFlamelets = over worldEvents $ (.) (makeFlameletTimed p 20 v Nothing 3 20) {- | Creates a shockwave when hitting a creature. -} bulConCr' :: Particle -> Point2 -> Creature -> World -> World bulConCr' bt p cr w = over (creatures . ix cid . crState . crDamage) ( Piercing 60 sp p ep : ) . soundMultiFrom [CrHitSound 0] p hit1S (Just 10) $ mkwave w where cid = _crID cr sp = head $ _btTrail' bt ep = sp +.+ _btVel' bt mkwave = over worldEvents $ (.) (makeShockwaveAt [] p 15 4 1 white) {- | Hitting wall effects: create a spark, damage blocks. -} bulHitWall :: Particle -> Point2 -> Wall -> World -> World bulHitWall bt p wl w = damageBlocksBy 5 wl . smokeCloudAt dustcol 20 200 1 (addZ 20 pOut) . createSparkCol 8 theCol pOut (reflectDir wl) $ set randGen g w where dustcol = _wlColor wl & _4 .~ 1 theCol = brightX 100 1.5 white sp = head $ _btTrail' bt pOut = p +.+ safeNormalizeV (sp -.- p) (a, g) = randomR (-0.2,0.2) $ _randGen w reflectDir wall = a + argV (reflectIn (uncurry (-.-) (_wlLine wall)) (p -.- sp) ) {- | Bounce off walls, do damage to blocks. -} bulBounceWall' :: Particle -> Point2 -> Wall -> World -> World bulBounceWall' bt p wl w = damageBlocksBy 5 wl $ over worldEvents addBouncer w where sp = head $ _btTrail' bt pOut = p +.+ safeNormalizeV (sp -.- p) bouncer = (aGenBulAt Nothing pOut reflectVel (_btHitEffect' bt) (_btWidth' bt) ) {_btTimer' = _btTimer' bt - 1} wallV = uncurry (-.-) (_wlLine wl) reflectVel = reflectIn wallV (_btVel' bt) addBouncer = ( over particles (bouncer : ) . ) -- the hack is to get around the fact that the particles list gets reset after -- all projectiles in it are checked, so we cannot add to it as we accumulate over -- this list {- | Create flamelet on wall. -} bulIncWall' :: Particle -> Point2 -- Impact point -> Wall -> World -> World bulIncWall' bt p wl w = damageBlocksBy 5 wl $ incFlamelets w where sp = head $ _btTrail' bt pOut = p +.+ safeNormalizeV (sp -.- p) wallV = uncurry (-.-) (_wlLine wl) reflectVel = safeNormalizeV $ reflectIn wallV (_btVel' bt) incFlamelets = over worldEvents $ (.) (makeFlameletTimed pOut 20 reflectVel Nothing 3 20) {- | Create a shockwave on wall-} bulConWall' :: Particle -> Point2 -- ^ Impact point -> Wall -> World -> World bulConWall' _ p wl = damageBlocksBy 1 wl . over worldEvents ( makeShockwaveAt [] p 15 4 1 white . ) hvBulHitWall' :: Particle -> Point2 -- ^ Impact point -> Wall -> World -> World hvBulHitWall' bt p x w = damageBlocksBy 5 x $ set randGen g $ foldr ($) w (sparks pOut sv) where sp = head $ _btTrail' bt pOut = p +.+ safeNormalizeV (sp -.- p) (a, g) = randomR (-0.2,0.2) $ _randGen w reflectDir wall = a + argV (reflectIn (uncurry (-.-) (_wlLine wall)) (p -.- sp) ) sv = unitVectorAtAngle $ reflectDir x cs' = take 10 $ randomRs (0,11) $ _randGen w cs = map (brightX 100 1.5 . numColor) cs' ds = randomRs (-0.7,0.7) $ _randGen w ts = randomRs (4,8) $ _randGen w sparks pos vel = zipWith3 (\t c d -> createSparkCol t c pos (argV vel + d)) ts cs ds bulHitFF' :: Particle -> Point2 -> ForceField -> World -> World bulHitFF' _ _ _ = id