Files
loop/vim
T

735 lines
23 KiB
Plaintext

{-# LANGUAGE TupleSections #-}
{- |
Weapon effects when pulling the trigger.
-}
module Dodge.Item.Weapon.TriggerType (
useAmmoAmount,
useAllAmmo,
useAmmoUpTo,
lockInvFor,
withMuzFlareI,
withMuzPos,
withMuzPosShift,
crAtMuzPos,
withOldDir,
trigDoAlso,
trigDoAlso',
withTempLight,
withItem,
withItemUpdate,
withItemUpdate',
ammoUseCheck,
rateIncAB,
torqueBefore,
torqueBeforeAtLeast,
withTorqueAfter,
torqueSideEffect,
withRandomItemParams,
withRandomItemUpdate,
withSoundStart,
withSoundItemChoiceStart,
withSoundContinue,
withSoundForI,
withSoundForVol,
withSmoke,
withThickSmokeI,
withThinSmokeI,
withPositionOffset,
withPositionWallCheck,
withPosDirWallCheck,
withRandomOffset,
withRandomDirI,
withRecoil,
afterRecoil,
withSidePushAfterI,
withSidePushI,
withWarmUp,
spreadNumI,
spreadLoaded,
repeatOnFrames,
sideEffectOnFrame,
duplicateItem,
duplicateLoadedBarrels,
duplicateLoaded,
duplicateOffsets,
duplicateOffsetsV2,
duplicateOffsetsFocus,
hammerCheckI,
hammerCheckL,
shootL,
useTimeCheck,
ammoCheckI,
applyInaccuracy,
modClock,
ammoHammerCheck,
) where
import Data.Foldable
import Data.Maybe
import Dodge.Base
import Dodge.Creature.HandPos
import Dodge.Creature.Test
import Dodge.Data.World
import Dodge.Inventory.Lock
import Dodge.LightSource
import Dodge.Reloading
import Dodge.SoundLogic
import Dodge.WorldEvent
import Geometry
import LensHelp
import RandomHelp
import Sound.Data
type ChainEffect =
(Item -> Creature -> World -> World) ->
Item ->
Creature ->
World ->
World
lockInvFor :: Int -> ChainEffect
lockInvFor i f it cr =
f it cr . (cWorld . lWorld . delayedEvents .:~ (i, UnlockInv (_crID cr)))
. lockInv (_crID cr)
trigDoAlso' ::
(Item -> Item) ->
(Creature -> Creature) ->
(Item -> Creature -> World -> World) ->
ChainEffect
trigDoAlso' fit fcr f g itm cr = g itm cr . f (fit itm) (fcr cr)
-- Note that this uses the "base" creature and item values
trigDoAlso ::
(Item -> Creature -> World -> World) ->
ChainEffect
trigDoAlso afterEff eff item cr = afterEff item cr . eff item cr
withSmoke :: Int -> Point4 -> Float -> Int -> Float -> ChainEffect
withSmoke num col rad t alt eff item cr w =
eff item cr $
foldl' (flip $ smokeCloudAt col rad t alt . (+.+.+ pos) . (* 8)) w ps
where
dir = _crDir cr
pos = addZ 0 $ _crPos cr +.+ (_crRad cr + 15) *.* unitVectorAtAngle dir
ps = replicateM num randOnUnitSphere & evalState $ _randGen w
withThinSmokeI :: ChainEffect
withThinSmokeI eff item cr w =
eff item cr $
foldl' (flip $ makeThinSmokeAt . (+.+.+ pos) . (* 8)) w ps
where
dir = _crDir cr
pos = addZ 0 $ _crPos cr +.+ (_crRad cr + 0.5) *.* unitVectorAtAngle dir
ps = replicateM 5 randOnUnitSphere & evalState $ _randGen w
withThickSmokeI :: ChainEffect
withThickSmokeI eff item cr w =
eff item cr $
foldl' (flip $ makeThickSmokeAt . (+.+.+ pos) . (* 8)) w ps
where
dir = _crDir cr
pos = addZ 0 $ _crPos cr +.+ (_crRad cr + 15) *.* unitVectorAtAngle dir
ps = replicateM 20 randOnUnitSphere & evalState $ _randGen w
-- TODO create a trigger that does different things on first and continued
-- fire.
ammoCheckI :: ChainEffect
ammoCheckI eff itm cr w
| _laLoaded ic <= 0 || not (_laPrimed ic) = w
| otherwise = eff itm cr $ w & cWorld . lWorld . creatures . ix (_crID cr) %~ crCancelReloading
where
ic = _heldConsumption $ _itUse itm
-- combined ammo and hammer check: want to be able to auto-reload even if the
-- hammer is down?
ammoHammerCheck :: ChainEffect
ammoHammerCheck eff it cr w
| _laLoaded ic <= 0 || not (_laPrimed ic) = w -- fromMaybe w (startReloadingWeapon cr w)
| otherwise = case it ^? itUse . heldHammer of
Just HammerUp -> eff it cr $ w & cWorld . lWorld . creatures . ix (_crID cr) %~ crCancelReloading
_ -> w
where
ic = _heldConsumption $ _itUse it
itUseCharge :: Int -> Item -> Item
itUseCharge x = itUse . leftConsumption . arLoaded %~ (max 0 . subtract x)
itUseAmmo :: Int -> Item -> Item
itUseAmmo x = itUse . heldConsumption . laLoaded %~ (max 0 . subtract x)
{- | Fires at an increasing rate.
Has different effect after first fire.
Applies ammo check and use cooldown check.
-}
rateIncAB ::
-- | Extra effect on first fire
ChainEffect ->
-- | Extra effect on continued fire
ChainEffect ->
ChainEffect
rateIncAB exeffFirst exeffCont eff item cr w
| repeatFire =
w
& pointItem
%~ ( (itUse . heldDelay . rateMax .~ max fastRate (currentRate - 1))
. itUseAmmo 1
. (itUse . heldDelay . rateTime .~ currentRate)
)
& exeffCont eff item cr
| firstFire =
w
& pointItem
%~ ( (itUse . heldDelay . rateMax .~ startRate - 1)
. itUseAmmo 1
. (itUse . heldDelay . rateTime .~ startRate)
)
& exeffFirst eff item cr
| otherwise = w
where
fastRate = _rateMinMax . _heldDelay $ _itUse item
startRate = _rateMaxMax . _heldDelay $ _itUse item
cid = _crID cr
itRef = cr ^?! crManipulation . manObject . inInventory . ispItem -- unsafe!! TODO change
pointItem = cWorld . lWorld . creatures . ix cid . crInv . ix itRef
currentRate = _rateMax (_heldDelay (_itUse item))
repeatFire = crWeaponReady cr && _rateTime (_heldDelay (_itUse item)) == 1
firstFire = crWeaponReady cr && _rateTime (_heldDelay (_itUse item)) == 0
-- | Apply effect after a warm up.
-- note this is quite unsafe, requires the item to have the correct delay type
withWarmUp ::
-- | warm up sound id
SoundID ->
ChainEffect
withWarmUp soundID f item cr w
| curWarmUp < maxWarmUp && crWeaponReady cr =
w
& pointerToItem . itUse . heldDelay . warmTime +~ 2
& soundContinue (CrWeaponSound cid 0) (_crPos cr) soundID (Just 2)
| otherwise =
w
& pointerToItem . itUse . heldDelay . warmTime .~ maxWarmUp
& f item cr
where
cid = _crID cr
itRef = cr ^?! crManipulation . manObject . inInventory . ispItem -- unsafe!! TODO change
pointerToItem = cWorld . lWorld . creatures . ix cid . crInv . ix itRef
curWarmUp = _warmTime . _heldDelay $ _itUse item
maxWarmUp = _warmMax . _heldDelay $ _itUse item
withSoundItemChoiceStart ::
(Item -> SoundID) ->
ChainEffect
withSoundItemChoiceStart soundf f it cr =
soundMultiFrom
[CrWeaponSound cid 0, CrWeaponSound cid 1, CrWeaponSound cid 2]
(_crPos cr)
(soundf it)
Nothing
. f it cr
where
cid = _crID cr
{- | Adds a sound to a creature based world effect.
The sound is emitted from the creature's position.
-}
withSoundStart ::
-- | Sound id
SoundID ->
ChainEffect
withSoundStart soundid f item cr =
soundMultiFrom [CrWeaponSound cid 0, CrWeaponSound cid 1, CrWeaponSound cid 2] (_crPos cr) soundid Nothing
. f item cr
where
cid = _crID cr
{- | Adds a sound to a creature based world effect.
The sound is emitted from the creature's position.
-}
withSoundContinue ::
-- | Sound id
SoundID ->
ChainEffect
withSoundContinue soundid f item cr =
soundContinue (CrWeaponSound cid 0) (_crPos cr) soundid Nothing
. f item cr
where
cid = _crID cr
{- | Adds a sound to a creature based world effect.
The sound is emitted from the creature's position.
-}
withSoundForI ::
-- | Sound id
SoundID ->
-- | Frames to play
Int ->
ChainEffect
withSoundForI soundid playTime f item cr =
soundContinue (CrWeaponSound (_crID cr) 0) (_crPos cr) soundid (Just playTime)
. f item cr
{- | Adds a sound to a creature based world effect.
The sound is emitted from the creature's position.
-}
withSoundForVol ::
-- | volume
Float ->
-- | Sound id
SoundID ->
-- | Frames to play
Int ->
ChainEffect
withSoundForVol vol soundid playTime f item cr =
soundContinueVol vol (CrWeaponSound (_crID cr) 0) (_crPos cr) soundid (Just playTime)
. f item cr
afterRecoil ::
-- | Recoil amount
Float ->
ChainEffect
afterRecoil recoilAmount eff item cr = eff item (pushback cr) . over (cWorld . lWorld . creatures . ix cid) pushback
where
cid = _crID cr
pushback = over crPos (+.+ rotateV (_crDir cr) (V2 ((- recoilAmount) / _crMass cr) 0))
withRecoil :: ChainEffect
withRecoil eff it cr = eff it cr . over (cWorld . lWorld . creatures . ix cid) pushback
where
cid = _crID cr
recoilAmount = fromMaybe 0 $ it ^? itParams . recoil
pushback = over crPos (+.+ rotateV (_crDir cr) (V2 ((- recoilAmount) / _crMass cr) 0))
{- | Pushes a creature sideways by a random amount.
Applied before the underlying effect.
-}
withSidePushI ::
-- | Maximal possible side push amount
Float ->
ChainEffect
withSidePushI maxSide eff item cr w =
eff item (push cr) $
w
& cWorld . lWorld . creatures . ix cid %~ push
& randGen .~ g
where
cid = _crID cr
push = over crPos (+.+ rotateV (_crDir cr) (V2 0 (pushAmount / _crMass cr)))
(pushAmount, g) = randomR (- maxSide, maxSide) $ _randGen w
-- consider unifying the pushes using a direction vector
{- | Pushes a creature sideways by a random amount.
Applied after the underlying effect.
-}
withSidePushAfterI ::
-- | Maximal possible side push amount
Float ->
ChainEffect
withSidePushAfterI maxSide eff item cr w =
over (cWorld . lWorld . creatures . ix cid) push . eff item cr $
w
& randGen .~ g
where
cid = _crID cr
push = over crPos (+.+ rotateV (_crDir cr) (V2 0 (pushAmount / _crMass cr)))
(pushAmount, g) = randomR (- maxSide, maxSide) $ _randGen w
useAllAmmo :: ChainEffect
useAllAmmo eff item cr =
eff item cr
. (cWorld . lWorld . creatures . ix (_crID cr) . crInv . ix itRef . itUse . heldConsumption . laLoaded .~ 0)
where
itRef = cr ^?! crManipulation . manObject . inInventory . ispItem -- unsafe!! TODO change
useAmmoUpTo :: Int -> ChainEffect
useAmmoUpTo amAmount eff item cr =
eff item cr
. ( cWorld . lWorld . creatures . ix (_crID cr) . crInv . ix itRef . itUse . heldConsumption . laLoaded
%~ (max 0 . subtract amAmount)
)
where
itRef = cr ^?! crManipulation . manObject . inInventory . ispItem -- unsafe!! TODO change
useAmmoAmount :: Int -> ChainEffect
useAmmoAmount amAmount eff item cr =
eff item cr
. (cWorld . lWorld . creatures . ix (_crID cr) . crInv . ix itRef . itUse . heldConsumption . laLoaded -~ amAmount)
where
itRef = cr ^?! crManipulation . manObject . inInventory . ispItem -- unsafe!! TODO change
{- |
Applies a world effect after an item use cooldown check.
-}
useTimeCheck :: ChainEffect
useTimeCheck f item cr w = case item ^? itUse . heldDelay . rateTime of
Just 0 -> f item cr $ setUseTime w
_ -> w
where
cid = _crID cr
setUseTime = cWorld . lWorld . creatures . ix cid . crInv . ix itRef . itUse . heldDelay . rateTime +~ userate
itRef = cr ^?! crManipulation . manObject . inInventory . ispItem -- unsafe!! TODO change
userate = fromMaybe 0 $ item ^? itUse . heldDelay . rateMax
-- | Applies a world effect after a hammer position check.
hammerCheckI :: ChainEffect
hammerCheckI f it cr w = case it ^? itUse . heldHammer of
Just HammerUp
| _laPrimed (_heldConsumption (_itUse it)) ->
f it cr w
_ -> w
-- | Applies a world effect after an ammo check.
-- this should be made "safe" incase there is no _rateTime
ammoUseCheck :: ChainEffect
ammoUseCheck f item cr w
| fireCondition =
f item cr w & pointerToItem
%~ ( itUseAmmo 1
. (itUse . heldDelay . rateTime .~ _rateMax (_heldDelay (_itUse item)))
)
-- | reloadCondition = fromMaybe w $ startReloadingWeapon cr w
| otherwise = w
where
cid = _crID cr
itRef = cr ^?! crManipulation . manObject . inInventory . ispItem -- unsafe!! TODO change
pointerToItem = cWorld . lWorld . creatures . ix cid . crInv . ix itRef
fireCondition =
crWeaponReady cr
&& _rateTime (_heldDelay (_itUse item)) == 0
&& _laLoaded (_heldConsumption (_itUse item)) > 0
-- reloadCondition = _laLoaded (_itConsumption item) == 0
{- | Applies a world effect after a hammer position check.
Arbitrary inventory position.
-}
hammerCheckL ::
-- | Underlying effect
(Item -> Creature -> World -> World) ->
Item ->
Creature ->
World ->
World
hammerCheckL f itm cr w = case itm ^? itUse . leftHammer of
Just HammerUp -> f itm cr w
_ -> w
{- | Applies a world effect after an ammo check.
Arbitrary inventory position -- cannot be replaced with ammoUseCheck.
-}
shootL ::
-- | Underlying effect
(Item -> Creature -> World -> World) ->
Item ->
Creature ->
World ->
World
shootL f item cr w
| fireCondition =
f item cr w & pointerToItem
%~ ( itUseCharge 1
. (itUse . leftDelay . rateTime .~ _rateMax (_leftDelay (_itUse item)))
)
-- | reloadCondition = fromMaybe w $ startReloadingWeapon cr w
| otherwise = w
where
cid = _crID cr
invid = _ipInvID $ _itLocation item
pointerToItem = cWorld . lWorld . creatures . ix cid . crInv . ix invid
fireCondition =
_rateTime (_leftDelay (_itUse item)) == 0
&& _arLoaded (_leftConsumption (_itUse item)) > 0
-- reloadCondition = _laLoaded (_itConsumption item) == 0
withItem :: (Item -> ChainEffect) -> ChainEffect
withItem g f it = g it f it
-- not ideal
withItemUpdate' :: (Item -> Item) -> ChainEffect
withItemUpdate' up f it cr = f (up it) cr . (cWorld . lWorld . creatures . ix (_crID cr) . crInv . ix itRef %~ up)
where
itRef = cr ^?! crManipulation . manObject . inInventory . ispItem -- unsafe!! TODO change
withItemUpdate :: (Item -> Item) -> (Item -> ChainEffect) -> ChainEffect
withItemUpdate up g f it cr = g it f it cr . (cWorld . lWorld . creatures . ix (_crID cr) . crInv . ix itRef %~ up)
where
itRef = cr ^?! crManipulation . manObject . inInventory . ispItem -- unsafe!! TODO change
withTempLight :: Int -> Float -> V3 Float -> ChainEffect
withTempLight time rad col eff item cr =
eff item cr
. over (cWorld . lWorld . tempLightSources) (theTLS :)
where
theTLS = tlsTimeRadColPos time rad col (V3 x y 10)
V2 x y = _crPos cr +.+ 15 *.* unitVectorAtAngle (_crDir cr)
modClock :: Int -> ChainEffect -> ChainEffect
modClock n chainEff eff it cr w
| (w ^. cWorld . lWorld . lClock) `mod` n == 0 = chainEff eff it cr w
| otherwise = eff it cr w
withMuzFlareI :: ChainEffect
withMuzFlareI f it cr w =
makeTlsTimeRadColPos 2 100 (V3 1 1 0.5) flashPos
. muzFlareAt (V4 5 5 0 2) flarePos cdir
$ f it cr w
where
flarePos = addZ 0 (_crPos cr) +.+.+ rotate3z cdir (muzzleOffset cr it +.+.+ V3 0 0 20)
flashPos = addZ 0 (_crPos cr) +.+.+ rotate3z cdir (muzzleOffset cr it +.+.+ V3 5 0 20)
-- muzzleOffset = V3 (_muzPos (_dimPortage (_itDimension it))) 0 0
cdir = _crDir cr
muzzleOffset :: Creature -> Item -> Point3
muzzleOffset cr it = V3 (holdOffset + 5 + _aimMuzPos dimPort - _aimHandlePos dimPort) 0 0
where
dimPort = _heldAim $ _itUse it
holdOffset
| crInAimStance OneHand cr = 10
| otherwise = 0
withMuzPos :: (Point3 -> World -> World) -> ChainEffect
withMuzPos = withMuzPosShift (V2 0 0)
withMuzPosShift :: Point2 -> (Point3 -> World -> World) -> ChainEffect
withMuzPosShift p g f it cr w =
g (pos `v2z` 20) $
f it cr w
where
pos =
_crPos cr
+.+ rotateV dir p
+.+ aimingMuzzlePos cr it *.* unitVectorAtAngle dir
dir = _crDir cr
crAtMuzPos :: ChainEffect
crAtMuzPos f it cr = f it (cr & crPos +.+.~ (aimingMuzzlePos cr it *.* unitVectorAtAngle (_crDir cr)))
{- | Applies the effect to a randomly rotated creature,
- rotation amount given by inaccuracy in itParams
-}
applyInaccuracy :: ChainEffect
applyInaccuracy f it = withRandomDirI acc f it
where
acc = _brlInaccuracy . _gunBarrels $ _itParams it
-- | Applies the effect to a randomly rotated creature.
withRandomDirI ::
-- | Max possible rotation
Float ->
ChainEffect
withRandomDirI acc f it cr w = f it (cr & crDir +~ a) $ set randGen g w
where
(a, g) = randomR (- acc, acc) $ _randGen w
withOldDir ::
-- | The fraction of the old direction
Float ->
ChainEffect
withOldDir aFrac eff item cr =
eff item (cr & crDir %~ tweenAngles aFrac (_crOldDir cr))
withRandomItemUpdate ::
State StdGen (Item -> Item) ->
ChainEffect
withRandomItemUpdate randItUp eff it cr w = eff (f it) cr $ w & randGen .~ g
where
(f, g) = runState randItUp (_randGen w)
withRandomItemParams :: State StdGen (ItemParams -> ItemParams) -> ChainEffect
withRandomItemParams rip eff it cr w = eff (it & itParams %~ f) cr $ w & randGen .~ g
where
(f, g) = runState rip (_randGen w)
withPositionOffset ::
(Item -> Creature -> World -> (Point2, Float)) ->
ChainEffect
withPositionOffset h f it cr w = f it (cr & crPos .+.+~ p & crDir +~ a) w
where
(p, a) = h it cr w
withPositionWallCheck ::
(Item -> Creature -> World -> Point2) ->
ChainEffect
withPositionWallCheck h f it cr w
| hasLOS p (_crPos cr) w = f it (cr & crPos .~ p) w
| otherwise = w
where
p = h it cr w
withPosDirWallCheck ::
(Item -> Creature -> World -> (Point2, Float)) ->
ChainEffect
withPosDirWallCheck h f it cr w
| hasLOS p (_crPos cr) w = f it (cr & crPos .~ p & crDir .~ a) w
| otherwise = w
where
(p, a) = h it cr w
-- | Apply the effect to a translated creature.
withRandomOffset :: ChainEffect
withRandomOffset f item cr w = f item (cr & crPos %~ (+.+ offV)) $ set randGen g w
where
(offsetVal, g) = randomR (- offsetAmount, offsetAmount) $ _randGen w
offV = rotateV (_crDir cr) (V2 0 offsetVal)
offsetAmount = fromMaybe 0 $ item ^? itParams . randomOffset
-- | Rotates a creature
torqueBefore ::
-- | Max possible rotation
Float ->
ChainEffect
torqueBefore torque feff item cr w
| cid == 0 =
feff item (cr & crDir +~ rot) $
w
& randGen .~ g
& cWorld . lWorld . creatures . ix cid . crDir +~ rot
& wCam . camRot +~ rot
| otherwise = feff item cr $ set randGen g $ over (cWorld . lWorld . creatures . ix cid . crDir) (+ rot) w
where
cid = _crID cr
(rot, g) = randomR (- torque, torque) $ _randGen w
{- | Rotates a creature with minimum rotation
Rotates the player creature before applying the effect, other creatures after.
-}
torqueBeforeAtLeast ::
-- | Minimal possible rotation
Float ->
-- | Extra possible rotation
Float ->
ChainEffect
torqueBeforeAtLeast minTorque exTorque feff item cr w
| cid == 0 =
feff item (cr & crDir +~ rot') $
w
& randGen .~ g
& cWorld . lWorld . creatures . ix cid . crDir +~ rot'
& wCam . camRot +~ rot'
| otherwise = feff item cr $ set randGen g $ over (cWorld . lWorld . creatures . ix cid . crDir) (+ rot') w
where
cid = _crID cr
(rot, g) = randomR (- exTorque, exTorque) $ _randGen w
rot'
| rot < 0 = rot - minTorque
| otherwise = rot + minTorque
-- | Rotate a randomly creature after applying an effect.
withTorqueAfter :: ChainEffect
withTorqueAfter feff item cr w
-- | cid == 0 = rotateScope $ set randGen g $ over cameraRot (+rot) $ feff item cr w
| cid == 0 = set randGen g $ over (wCam . camRot) (+ rot) $ feff item cr w
| otherwise = set randGen g $ over (cWorld . lWorld . creatures . ix cid . crDir) (+ rot) $ feff item cr w
where
cid = _crID cr
(rot, g) = randomR (- torque, torque) $ _randGen w
torque = fromMaybe 0 $ item ^? itParams . torqueAfter
spreadNumI :: ChainEffect
spreadNumI eff item cr w = foldr f w dirs
where
dirs =
zipWith
(+)
[- spread, - spread + (2 * spread / fromIntegral numBul) .. spread]
(randomRs (0, spread / fromIntegral numBul) (_randGen w))
f dir = eff item (cr & crDir +~ dir)
spread = _spreadAngle . _brlSpread . _gunBarrels $ _itParams item
numBul = _brlNum . _gunBarrels $ _itParams item
spreadLoaded :: ChainEffect
spreadLoaded eff item cr w = foldr f w dirs
where
cd = 0.5 * spread * fromIntegral (numBulLoaded -1)
dirs = subtract cd . (spread *) . fromIntegral <$> [0 .. numBulLoaded - 1]
f dir = eff item (cr & crDir +~ dir)
spread = _spreadAngle . _brlSpread . _gunBarrels $ _itParams item
numBulLoaded = _laLoaded $ _heldConsumption (_itUse item)
sideEffectOnFrame ::
Int ->
(Item -> Creature -> WdWd) ->
ChainEffect
sideEffectOnFrame i sf f it cr w =
f it cr w
& cWorld . lWorld . delayedEvents .:~ (i, sf it cr)
torqueSideEffect :: Float -> Item -> Creature -> World -> World
torqueSideEffect torque _ cr w
| cid == 0 = set randGen g $ over (wCam . camRot) (+ rot) w
| otherwise = set randGen g $ over (cWorld . lWorld . creatures . ix cid . crDir) (+ rot) w
where
cid = _crID cr
(rot, g) = randomR (- torque, torque) $ _randGen w
-- pump the updated creature into the chain in later frames
repeatOnFrames :: [Int] -> HeldMod -> ChainEffect
--repeatOnFrames is hm f it cr w = f it cr w
repeatOnFrames is hm f it cr w =
f it cr $
w
& cWorld . lWorld . delayedEvents .++~ (is <&> (,WdWdFromItCrixWdWd (it & itUse . heldMods .~ hm) (_crID cr) ItCrWdItemEffect))
-- where
-- f' = fromMaybe w' $ do
-- cr' <- w' ^? creatures . ix (_crID cr)
-- return $ f it cr' w'
duplicateLoaded :: ChainEffect
duplicateLoaded eff it cr w = foldr f w [1 .. numBul]
where
f _ = eff it cr
numBul = _laLoaded $ _heldConsumption (_itUse it)
duplicateLoadedBarrels :: ChainEffect
duplicateLoadedBarrels eff item cr w = foldr f w poss
where
cp :: Float
cp = -0.5 * (fromIntegral numBar - 1)
poss :: [V2 Float]
poss = map (rotateV (_crDir cr) . V2 0 . (* 5) . (+ cp) . fromIntegral) [0 .. numBul - 1]
f pos = eff item (cr & crPos %~ (+.+ pos))
numBar = _brlNum . _gunBarrels $ _itParams item
numBul = _laLoaded $ _heldConsumption (_itUse item)
duplicateOffsetsFocus :: [Float] -> ChainEffect
duplicateOffsetsFocus xs eff item cr w = foldr f w poss
where
poss :: [V2 Float]
poss = map (rotateV (_crDir cr) . V2 0) xs
f pos =
eff item $
cr
& crPos %~ (+.+ pos)
& crDir .~ thedir pos
thedir pos
| dist (mouseWorldPos (w ^. input) (w ^. wCam)) (_crPos cr) < aimingMuzzlePos cr item =
argV
( _crPos cr +.+ aimingMuzzlePos cr item *.* unitVectorAtAngle (_crDir cr)
-.- (_crPos cr +.+ pos)
)
| otherwise = argV (mouseWorldPos (w ^. input) (w ^. wCam) -.- (_crPos cr +.+ pos))
duplicateItem :: (Item -> [Item]) -> ChainEffect
duplicateItem fit eff itm cr w = foldr f w (fit itm)
where
f itm' = eff itm' cr
duplicateOffsetsV2 :: [Point2] -> ChainEffect
duplicateOffsetsV2 xs eff item cr w = foldr f w poss
where
poss = map (rotateV (_crDir cr)) xs
f pos = eff item (cr & crPos +.+.~ pos)
duplicateOffsets :: [Float] -> ChainEffect
duplicateOffsets xs eff item cr w = foldr f w poss
where
poss :: [V2 Float]
poss = map (rotateV (_crDir cr) . V2 0) xs
f pos = eff item (cr & crPos +.+.~ pos)