735 lines
23 KiB
Plaintext
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)
|