module Dodge.HeldUse where import Dodge.Wall.Move import Dodge.Wall.ForceField import Color import Data.Maybe import Data.Traversable import Dodge.Base.Coordinate import Dodge.Bullet import Dodge.Creature.HandPos import Dodge.Data.World import Dodge.Gas import Dodge.Item.Weapon.BatteryGuns import Dodge.Item.Weapon.Launcher import Dodge.Item.Weapon.Radar import Dodge.Item.Weapon.Shatter import Dodge.Item.Weapon.TriggerType import Dodge.Projectile.Create import Dodge.SoundLogic import Dodge.Tesla.Arc import Dodge.WorldEvent.Flash import Geometry import qualified IntMapHelp as IM import LensHelp import RandomHelp import Sound.Data useMod :: HeldMod -> [(Item -> Creature -> World -> World) -> Item -> Creature -> World -> World] useMod hm = case hm of HeldModNothing -> [] PoisonSprayerMod -> [ useAmmoAmount 1 , withSoundForI foamSprayLoopS 5 , ammoCheckI ] FlameSpitterMod -> [ withSidePushAfterI 20 , withSidePushI 5 , useAmmoAmount 1 , withRandomItemParams f , repeatOnFrames [1 .. 9] FlameSpitterRepeatMod , lockInvFor 10 , useTimeCheck , ammoCheckI ] FlameSpitterRepeatMod -> [ withSidePushAfterI 20 , withSidePushI 5 , useAmmoAmount 1 , withRandomItemParams f , ammoCheckI ] FlameThrowerMod -> [ withSidePushAfterI 20 --, withTempLight 1 100 (V3 1 0 0) , withSidePushI 5 , useAmmoAmount 1 , ammoCheckI ] LauncherMod -> [ useAmmoAmount 1 , withSoundStart tap4S , useTimeCheck , ammoCheckI , hammerCheckI ] TeslaMod -> [ useAmmoAmount 1 , withSoundForI elecCrackleS 1 , withTempLight 1 100 (V3 0 0 1) , ammoCheckI ] CircleLaserMod -> [ duplicateItem fLasCircle , withItemUpdate' increasecycleLasCircle , useAmmoAmount 1 , withSoundForI tone440sawtoothquietS 2 , withItem $ \it -> withMuzPos $ flareCircleAt (_lasColor $ _itParams it) 0.8 , withItem $ \it -> withTempLight 1 100 (xyzV4 (_lasColor $ _itParams it)) , ammoCheckI ] LasWideMod n -> [ withItem $ \it -> duplicateOffsetsV2 (xsLasWide it) , withItemUpdate' (increasecycleLasWide n) , crAtMuzPos , useAmmoAmount 1 , withSoundForI tone440sawtoothquietS 2 , withItem $ \it -> withMuzPos $ flareCircleAt (_lasColor $ _itParams it) 0.8 , withItem $ \it -> withTempLight 1 100 (xyzV4 (_lasColor $ _itParams it)) , ammoCheckI ] DualBeamMod -> [ useAmmoAmount 1 , withSoundForI tone440sawtoothquietS 2 , withItem $ \it -> withMuzPosShift (V2 0 (- thegapDualBeam it)) $ flareCircleAt (_lasColor2 $ _itParams it) 0.8 , withItem $ \it -> withMuzPosShift (V2 0 (thegapDualBeam it)) $ flareCircleAt (_lasColor $ _itParams it) 0.8 , ammoCheckI ] LasMod -> [ crAtMuzPos , useAmmoAmount 1 , withItem $ \it -> withMuzPos $ flareCircleAt (_lasColor $ _itParams it) 0.8 , withSoundForI tone440sawtoothquietS 2 , withItem $ \it -> withTempLight 1 100 (xyzV4 (_lasColor $ _itParams it)) , ammoCheckI ] LauncherXMod i -> [ useAmmoAmount i , withSoundStart tap4S , useTimeCheck , ammoCheckI , hammerCheckI ] ShatterMod -> [ useAmmoAmount 1 -- , withSoundStart tap3S , useTimeCheck , ammoHammerCheck ] AmmoCheckMod -> [ammoCheckI] AmmoUseCheckMod -> [ammoUseCheck] AmmoHammerTimeUseOneMod -> [ useAmmoAmount 1 , useTimeCheck , ammoHammerCheck ] BangCaneMod -> [ withMuzFlareI , withSmoke 1 black 20 200 5 , withRecoil , applyInaccuracy , withTorqueAfter , useAmmoAmount 1 , withSoundStart tap3S , useTimeCheck , ammoHammerCheck ] VolleyGunMod -> [ withRecoil , withMuzFlareI , applyInaccuracy , duplicateLoadedBarrels , withTorqueAfter , useAllAmmo , withSoundItemChoiceStart caneStickSoundChoice , useTimeCheck , ammoHammerCheck ] AutoRifleMod -> -- note this is the same as BangCanemMod with the first changed [ withMuzFlareI , withSmoke 1 black 20 200 5 , withRecoil , applyInaccuracy , withTorqueAfter , useAmmoAmount 1 , withSoundStart tap3S , useTimeCheck , ammoCheckI ] BangRodMod -> [ withRecoil , withMuzFlareI , withThickSmokeI , applyInaccuracy , withTorqueAfter , useAmmoAmount 1 , withSoundStart bangEchoS , useTimeCheck , ammoHammerCheck ] ElephantGunMod -> [ withRecoil , withMuzFlareI , withThickSmokeI , applyInaccuracy , withTorqueAfter , useAmmoAmount 1 , withSoundStart bangEchoS , useTimeCheck , ammoHammerCheck ] AutoAmrMod -> [ withRecoil , withMuzFlareI , withThickSmokeI , applyInaccuracy , withTorqueAfter , useAmmoAmount 1 , withSoundStart bangEchoS , useTimeCheck , ammoCheckI -- cf ElephantGun ] MachineGunMod -> [ withMuzFlareI , withThinSmokeI , withSoundStart bangEchoS , rateIncAB (torqueBeforeAtLeast 0.1 0.1) withTorqueAfter , ammoCheckI ] ModWithDirectedTeleport hm' -> reverse $ withPosDirWallCheck directedTelPos : useMod hm' BangStickMod -> [ withRecoil -- , applyInaccuracy , spreadLoaded , withTorqueAfter , withMuzFlareI , useAllAmmo , withSoundItemChoiceStart bangStickSoundChoice , useTimeCheck , ammoHammerCheck ] PistolMod -> [ withMuzFlareI , withSidePushI 50 , withRecoil , withTorqueAfter , applyInaccuracy , withSoundStart tap3S , useAmmoAmount 1 , useTimeCheck , ammoHammerCheck ] AutoPistolMod -> [ withMuzFlareI , withSidePushI 50 , withRecoil , withTorqueAfter , applyInaccuracy , withSoundStart tap3S , useAmmoAmount 1 , useTimeCheck , ammoCheckI ] MachinePistolMod -> [ withMuzFlareI , withRecoil , withSidePushI 50 , withTorqueAfter , applyInaccuracy , withSoundStart tap1S , useAmmoAmount 1 , useTimeCheck , ammoCheckI ] BurstRifleMod -> [ withRecoil , withMuzFlareI , applyInaccuracy , useAmmoAmount 1 , withSoundStart tap3S , repeatOnFrames [3, 6] BurstRifleRepeatMod , lockInvFor 7 , sideEffectOnFrame 7 (\_ cr -> TorqueCr 0.2 (_crID cr)) --(torqueSideEffect 0.2) , useTimeCheck , ammoHammerCheck ] BurstRifleRepeatMod -> [ withRecoil , withMuzFlareI , applyInaccuracy , useAmmoAmount 1 , withSoundStart tap3S , sideEffectOnFrame 7 (\_ cr -> TorqueCr 0.2 (_crID cr)) --(torqueSideEffect 0.2) , ammoCheckI ] MiniGunMod i -> reverse [ trigDoAlso' (moddelay x) (modcrpos x) useAmmoParams | x <- map ((/ fromIntegral i) . fromIntegral) [1 .. i -1] ] <> [ afterRecoil (fromIntegral i * 5) , torqueBefore (fromIntegral i * 0.05) , withSidePushI (fromIntegral i * 50) , useAmmoAmount i , withMuzFlareI , withSmoke 1 black 20 200 5 --, withThinSmokeI , withSoundForI mini1S 2 , withWarmUp crankSlowS , ammoCheckI ] SmgMod -> [ withMuzFlareI , withSidePushI 30 , withRecoil , withTorqueAfter , applyInaccuracy , withSoundStart tap3S , useAmmoAmount 1 , useTimeCheck , ammoCheckI ] RevolverXMod -> [ withRecoil , withTorqueAfter -- , spreadLoaded , withMuzFlareI , applyInaccuracy , useAmmoUpTo 1 , withSoundStart tap3S , repeatOnFrames [2, 4, 6, 8, 10] RevolverXRepeatMod , lockInvFor 10 -- rather than locking the inventory, a better solution may be to check -- that the weapon is still in your hands in the repeated frames , useTimeCheck , ammoHammerCheck ] RevolverXRepeatMod -> [ withRecoil , withTorqueAfter , withMuzFlareI , applyInaccuracy , useAmmoUpTo 1 , withSoundStart tap3S , ammoCheckI ] BangConeMod -> [ withRandomItemParams coneRandItemParams , withRandomItemUpdate coneRandItemUpdate , withRandomOffset , applyInaccuracy , withMuzFlareI , duplicateLoaded , withRecoil , withTorqueAfter , useAllAmmo , withSoundStart bangEchoS , useTimeCheck , hammerCheckI , ammoCheckI ] where f = do nzpres <- state $ randomR (3, 4) return $ sprayNozzles . ix 0 . nzPressure .~ nzpres increasecycleLasCircle it = it & itParams . lasCycle %~ (flip mod 2000 . (+ 1)) --f it = [it & itParams . lasCycle +~ x | x <- [0,100 .. 1900] ] fLasCircle it = [it & itParams . lasCycle +~ x | x <- [0, 50 .. 1999]] increasecycleLasWide n it = case _heldHammer (_itUse it) of HammerUp -> it & itParams . lasCycle .~ 1 _ -> it & itParams . lasCycle %~ (min (n * 5) . (+ 1)) xsLasWide it = [V2 ((0.2 * yoff x) ^ (2 :: Int)) (yoff x) | x <- [(0 :: Int) .. n' -1]] where yoff x = fromIntegral x - fromIntegral (n' -1) / 2 n' = _lasCycle (_itParams it) thegapDualBeam = _dbGap . _itParams directedTelPos _ cr w = (p, a) where p = fromMaybe (_crPos cr) $ cr ^? crTargeting . ctPos . _Just a = argV (mouseWorldPos (w ^. input) (w ^. wCam) -.- p) moddelay x = itUse . heldConsumption . laAmmoType . amBullet . buDelayFraction .~ x modcrpos x cr = cr & crDir %~ tweenAngles x (_crOldDir cr) & crPos %~ alongSegBy x (_crOldPos cr) mcUseHeld :: HeldItemType -> Item -> Machine -> World -> World mcUseHeld hit = case hit of LASGUN -> mcShootLaser _ -> \_ _ -> id useHeld :: Huse -> Item -> Creature -> World -> World useHeld hu = case hu of HeldDoNothing -> const $ const id HeldUseAmmoParams -> useAmmoParams HeldOverNozzlesUseGasParams -> overNozzles useGasParams HeldPJCreation -> usePjCreation HeldPJCreationX i -> usePjCreationX i HeldFireRemoteShell -> fireRemoteShell HeldDetectorEffect dt -> detectorEffect dt HeldTeslaArc -> shootTeslaArc HeldLaser -> shootLaser HeldCircleLaser -> circleLaser HeldDualLaser -> shootDualLaser HeldTractor -> aTractorBeam -- HeldSonicWave -> aSonicWave HeldForceField -> useForceFieldGun HeldShatter -> shootShatter HeldExplodeRemoteShell itid pjid -> const $ const $ explodeRemoteRocket itid pjid usePjCreation :: Item -> Creature -> World -> World usePjCreation it = createProjectile (_amPjCreation (_laAmmoType (_heldConsumption (_itUse it)))) it usePjCreationX :: Int -> Item -> Creature -> World -> World usePjCreationX i it cr = foldr f (createProjectile (_amPjCreation (_laAmmoType (_heldConsumption (_itUse it)))) it cr) [1 .. i -1] where f n = (. createProjectile (_amPjCreation (_laAmmoType (_heldConsumption (_itUse it)))) it (cr & crDir +~ (2 * pi * fromIntegral n / fromIntegral i))) overNozzles :: (Nozzle -> Item -> Creature -> World -> World) -> Item -> Creature -> World -> World overNozzles = overNozzles' . overNozzle overNozzles' :: (Item -> Creature -> World -> Nozzle -> (World, Nozzle)) -> Item -> Creature -> World -> World overNozzles' eff it cr w = neww & cWorld . lWorld . creatures . ix cid . crInv . ix i . itParams . sprayNozzles .~ newNozzles where cid = _crID cr i = w ^?! cWorld . lWorld . creatures . ix cid . crManipulation . manObject . inInventory . ispItem (neww, newNozzles) = mapAccumR (eff it cr) w $ _sprayNozzles (_itParams it) overNozzle :: (Nozzle -> Item -> Creature -> World -> World) -> Item -> Creature -> World -> Nozzle -> (World, Nozzle) overNozzle eff it cr w nz = ( eff nz it (cr & crDir +~ wa + na) w & randGen .~ g , nz & nzCurrentWalkAngle .~ wa ) where na = _nzDir nz (walkamount, g) = randomR (- aspeed, aspeed) (_randGen w) aspeed = _nzWalkSpeed nz maxa = _nzMaxWalkAngle nz wa = min maxa $ max (negate maxa) (_nzCurrentWalkAngle nz + walkamount) useGasParams :: Nozzle -> Item -> Creature -> World -> World useGasParams nz it cr = createGas (_amCreateGas (_laAmmoType (_heldConsumption (_itUse it)))) (_nzPressure nz) pos dir cr where dir = _crDir cr pos = _crPos cr +.+ (_nzLength nz *.* unitVectorAtAngle (_crDir cr)) fireRemoteShell :: Item -> Creature -> World -> World fireRemoteShell it cr w = set (cWorld . lWorld . creatures . ix cid . crInv . ix j . itUse . heldUse) (HeldExplodeRemoteShell itid i) $ addRemRocket w where itid = _itID it i = IM.newKey $ w ^. cWorld . lWorld . props cid = _crID cr addRemRocket = makeShell it cr [ PJRemoteShellCollisionCheck , PJSetScope itid , PJDecTimMvVel , PJThrust 330 0 , PJRemoteDirection 340 0 cid itid ] j = cr ^?! crManipulation . manObject . inInventory . ispItem -- unsafe!! TODO change caneStickSoundChoice :: Item -> SoundID caneStickSoundChoice it | _laLoaded (_heldConsumption (_itUse it)) < 2 = tap3S | otherwise = shotgunS bangStickSoundChoice :: Item -> SoundID bangStickSoundChoice it | _laLoaded (_heldConsumption (_itUse it)) < 2 = tap3S | otherwise = shotgunS coneRandItemUpdate :: State StdGen (Item -> Item) coneRandItemUpdate = do wth <- state $ randomR (1, 5) return (itUse . heldConsumption . laAmmoType . amBullet . buWidth .~ wth) coneRandItemParams :: State StdGen (ItemParams -> ItemParams) coneRandItemParams = do muzv <- state $ randomR (0.5, 1) rifl <- state $ randomR (0.3, 0.9) return $ \itparams -> itparams { _muzVel = muzv , _rifling = rifl } mcShootLaser :: Item -> Machine -> World -> World mcShootLaser it mc = cWorld . lWorld . lasers .:~ lasRayAt (_lasColor $ _itParams it) dam phasev pos dir where pos = _mcPos mc +.+ 20 *.* unitVectorAtAngle dir dir = mc ^?! mcType . _McTurret . tuDir phasev = _phaseV . _itParams $ it dam = _lasDamage $ _itParams it -- | assumes that the item is held shootTeslaArc :: Item -> Creature -> World -> World shootTeslaArc it cr w = w' & cWorld . lWorld . creatures . ix (_crID cr) . crInv . ix itRef . itParams .~ ip where itRef = cr ^?! crManipulation . manObject . inInventory . ispItem -- unsafe!! TODO change (w', ip) = makeTeslaArc (_itParams it) pos dir w pos = _crPos cr +.+ aimingMuzzlePos cr it *.* unitVectorAtAngle dir dir = _crDir cr -- I believe because the targeting returns to nothing straight after you release -- the rmb, it is possible for this to do nothing -- TODO investigate more and fix useForceFieldGun :: Item -> Creature -> World -> World useForceFieldGun itm cr w = fromMaybe w $ do a <- cr ^? crTargeting . ctPos . _Just let mwp = mouseWorldPos (w ^. input) (w ^. wCam) b = if dist a mwp < 100 then mwp else a +.+ 100 *.* normalizeV (mwp -.- a) wlline = (a, b) return $ w & cWorld . lWorld . walls %~ IM.insertWith (\_ x -> x) i forceField{_wlID = i} & cWorld . lWorld . creatures . ix (_crID cr) . crInv . ix (_ipInvID (_itLocation itm)) . itParams . paramMID ?~ i & moveWallIDUnsafe i wlline where i = fromMaybe (IM.newKey (_walls (_lWorld (_cWorld w)))) $ itm ^? itParams . paramMID . _Just