module Dodge.HeldUse where import Dodge.Data import Dodge.Base.Coordinate import Sound.Data import Dodge.Bullet import Dodge.Item.Weapon.TriggerType import Dodge.SoundLogic import Dodge.WorldEvent.Flash import Dodge.Item.Location import Dodge.Item.Weapon.Radar import Dodge.Item.Weapon.BatteryGuns import Dodge.Item.Weapon.SonicGuns import Dodge.Item.Weapon.Utility import Dodge.Item.Weapon.Shatter import Dodge.Item.Weapon.Launcher import Dodge.Projectile.Create import Dodge.Gas import Geometry import qualified IntMapHelp as IM import LensHelp import RandomHelp import Color import Data.Maybe import Data.Traversable useMod :: HeldMod -> [(Item -> Creature -> World -> World) -> Item -> Creature -> World -> World] useMod hm = case hm of HeldModNothing -> [] PoisonSprayerMod -> [ ammoCheckI , withSoundForI foamSprayLoopS 5 , useAmmoAmount 1 ] FlameSpitterMod -> [ ammoCheckI , useTimeCheck , lockInvFor 10 , repeatOnFrames [1..9] , withRandomItemParams f , useAmmoAmount 1 , withSidePushI 5 , withSidePushAfterI 20 ] FlameThrowerMod -> [ ammoCheckI , useAmmoAmount 1 , withSidePushI 5 --, withTempLight 1 100 (V3 1 0 0) , withSidePushAfterI 20 ] LauncherMod -> [ hammerCheckI , ammoCheckI , useTimeCheck , withSoundStart tap4S , useAmmoAmount 1 ] TeslaMod -> [ ammoCheckI , withTempLight 1 100 (V3 0 0 1) , withSoundForI elecCrackleS 1 , useAmmoAmount 1 ] CircleLaserMod -> [ ammoCheckI , withItem $ \it -> withTempLight 1 100 (xyzV4 (_lasColor $ _itParams it)) , withItem $ \it -> withMuzPos $ flareCircleAt (_lasColor $ _itParams it) 0.8 , withSoundForI tone440sawtoothquietS 2 , useAmmoAmount 1 , withItemUpdate' increasecycleLasCircle , duplicateItem fLasCircle ] LasWideMod n -> [ ammoCheckI , withItem $ \it -> withTempLight 1 100 (xyzV4 (_lasColor $ _itParams it)) , withItem $ \it -> withMuzPos $ flareCircleAt (_lasColor $ _itParams it) 0.8 , withSoundForI tone440sawtoothquietS 2 , useAmmoAmount 1 , crAtMuzPos , withItemUpdate' (increasecycleLasWide n) , withItem $ \it -> duplicateOffsetsV2 (xsLasWide it) ] DualBeamMod -> [ ammoCheckI , withItem $ \it -> withMuzPosShift (V2 0 (thegapDualBeam it)) $ flareCircleAt (_lasColor $ _itParams it) 0.8 , withItem $ \it -> withMuzPosShift (V2 0 (-thegapDualBeam it)) $ flareCircleAt (_lasColor2 $ _itParams it) 0.8 , withSoundForI tone440sawtoothquietS 2 , useAmmoAmount 1 ] LasMod -> [ ammoCheckI , withItem $ \it -> withTempLight 1 100 (xyzV4 (_lasColor $ _itParams it)) , withSoundForI tone440sawtoothquietS 2 , withItem $ \it -> withMuzPos $ flareCircleAt (_lasColor $ _itParams it) 0.8 , useAmmoAmount 1 , crAtMuzPos ] LauncherXMod i -> [ hammerCheckI , ammoCheckI , useTimeCheck , withSoundStart tap4S , useAmmoAmount i ] ShatterMod -> [ ammoHammerCheck , useTimeCheck -- , withSoundStart tap3S , useAmmoAmount 1 ] AmmoCheckMod -> [ ammoCheckI ] AmmoUseCheckMod -> [ ammoUseCheck ] AmmoHammerTimeUseOneMod -> [ ammoHammerCheck , useTimeCheck , useAmmoAmount 1 ] BangCaneMod -> [ ammoHammerCheck , useTimeCheck , withSoundStart tap3S , useAmmoAmount 1 , withTorqueAfter , applyInaccuracy , withRecoil , withSmoke 1 black 20 200 5 , withMuzFlareI ] VolleyGunMod -> [ ammoHammerCheck , useTimeCheck , withSoundItemChoiceStart caneStickSoundChoice , useAllAmmo , withTorqueAfter , duplicateLoadedBarrels , applyInaccuracy , withMuzFlareI , withRecoil ] AutoRifleMod -> -- note this is the same as BangCanemMod with the first changed [ ammoCheckI , useTimeCheck , withSoundStart tap3S , useAmmoAmount 1 , withTorqueAfter , applyInaccuracy , withRecoil , withSmoke 1 black 20 200 5 , withMuzFlareI ] BangRodMod -> [ ammoHammerCheck , useTimeCheck , withSoundStart bangEchoS , useAmmoAmount 1 , withTorqueAfter , applyInaccuracy , withThickSmokeI , withMuzFlareI , withRecoil ] ElephantGunMod -> [ ammoHammerCheck , useTimeCheck , withSoundStart bangEchoS , useAmmoAmount 1 , withTorqueAfter , applyInaccuracy , withThickSmokeI , withMuzFlareI , withRecoil ] AutoAmrMod -> [ ammoCheckI -- cf ElephantGun , useTimeCheck , withSoundStart bangEchoS , useAmmoAmount 1 , withTorqueAfter , applyInaccuracy , withThickSmokeI , withMuzFlareI , withRecoil ] MachineGunMod -> [ ammoCheckI , rateIncAB (torqueBeforeAtLeast 0.1 0.1) withTorqueAfter , withSoundStart bangEchoS , withThinSmokeI , withMuzFlareI ] ModWithDirectedTeleport hm' -> withPosDirWallCheck directedTelPos : useMod hm' BangStickMod -> [ ammoHammerCheck , useTimeCheck , withSoundItemChoiceStart bangStickSoundChoice , useAllAmmo , withMuzFlareI , withTorqueAfter , spreadLoaded -- , applyInaccuracy , withRecoil ] PistolMod -> [ ammoHammerCheck , useTimeCheck , useAmmoAmount 1 , withSoundStart tap3S , applyInaccuracy , withTorqueAfter , withRecoil , withSidePushI 50 , withMuzFlareI ] AutoPistolMod -> [ ammoCheckI , useTimeCheck , useAmmoAmount 1 , withSoundStart tap3S , applyInaccuracy , withTorqueAfter , withRecoil , withSidePushI 50 , withMuzFlareI ] MachinePistolMod -> [ ammoCheckI , useTimeCheck , useAmmoAmount 1 , withSoundStart tap1S , applyInaccuracy , withTorqueAfter , withSidePushI 50 , withRecoil , withMuzFlareI ] BurstRifleMod -> [ ammoHammerCheck , useTimeCheck , sideEffectOnFrame 7 (\_ cr -> TorqueCr 0.2 (_crID cr)) --(torqueSideEffect 0.2) , lockInvFor 7 , \f' it -> repeatOnFrames (take (_laLoaded (_itConsumption it) - 1) [3,6]) f' it , withSoundStart tap3S , useAmmoAmount 1 , applyInaccuracy , withMuzFlareI , withRecoil ] MiniGunMod i -> [ ammoCheckI , withWarmUp crankSlowS , withSoundForI mini1S 2 --, withThinSmokeI , withSmoke 1 black 20 200 5 , withMuzFlareI , useAmmoAmount i , withSidePushI (fromIntegral i * 50) , torqueBefore (fromIntegral i * 0.05) , afterRecoil (fromIntegral i * 5) ] <> [ trigDoAlso' (moddelay x) (modcrpos x) useAmmoParams | x <- map ((/fromIntegral i) . fromIntegral) [1..i-1] ] SmgMod -> [ ammoCheckI , useTimeCheck , useAmmoAmount 1 , withSoundStart tap3S , applyInaccuracy , withTorqueAfter , withRecoil , withSidePushI 30 , withMuzFlareI ] RevolverXMod -> [ ammoHammerCheck , useTimeCheck -- rather than locking the inventory, a better solution may be to check -- that the weapon is still in your hands in the repeated frames , lockInvFor 10 , \f' it -> repeatOnFrames (take (_laLoaded (_itConsumption it) - 1) [2,4,6,8,10]) f' it , withSoundStart tap3S , useAmmoUpTo 1 , applyInaccuracy , withMuzFlareI -- , spreadLoaded , withTorqueAfter , withRecoil ] BangConeMod -> [ ammoCheckI , hammerCheckI , useTimeCheck , withSoundStart bangEchoS , useAllAmmo , withTorqueAfter , withRecoil , duplicateLoaded , withMuzFlareI , applyInaccuracy , withRandomOffset , withRandomItemUpdate coneRandItemUpdate , withRandomItemParams coneRandItemParams ] 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 _useHammer (_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 it cr w = (p,a) where p = fromMaybe (_crPos cr) $ it ^? itTargeting . tgPos . _Just a = argV (mouseWorldPos w -.- p) moddelay x = itConsumption . laAmmoType . amBullet . buState .~ DelayedBullet x modcrpos x cr = cr & crDir %~ tweenAngles x (_crOldDir cr) & crPos %~ tweenPoints x (_crOldPos cr) useHeld :: HeldUse -> 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 (_itConsumption it))) it usePjCreationX :: Int -> Item -> Creature -> World -> World usePjCreationX i it cr = foldr f (createProjectile (_amPjCreation (_laAmmoType (_itConsumption it))) it cr) [1..i-1] where f n = (. createProjectile (_amPjCreation (_laAmmoType (_itConsumption 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 & creatures . ix cid . crInv . ix i . itParams . sprayNozzles .~ newNozzles where cid = _crID cr i = crSel $ _creatures w IM.! cid (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 (_itConsumption 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 (creatures . ix cid . crInv . ix j . itUse . rUse) (HeldExplodeRemoteShell itid i) $ addRemRocket w' where (w',itid) = getHeldItemLoc cr w i = IM.newKey $ _props w cid = _crID cr addRemRocket = makeShell it cr [ PJSetScope itid , PJThrust 330 0 , PJRemoteDirection 340 0 cid itid ] j = crSel cr caneStickSoundChoice :: Item -> SoundID caneStickSoundChoice it | _laLoaded (_itConsumption it) < 2 = tap3S | otherwise = shotgunS bangStickSoundChoice :: Item -> SoundID bangStickSoundChoice it | _laLoaded (_itConsumption it) < 2 = tap3S | otherwise = shotgunS coneRandItemUpdate :: State StdGen (Item -> Item) coneRandItemUpdate = do wth <- state $ randomR (1,5) return (itConsumption . 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 }