module Dodge.Item.Weapon.BatteryGuns ( lasGun , lasGunDual , lasGunWide , lasGunWidePulse , lasGunSway , lasGunSwing , lasGunFocus , lasGunPulse , sparkGun , teslaGun , teslaParams , tractorGun , lasRayAt , flameBeamCombine , teslaBeamCombine , splitBeamCombine ) where import Dodge.Data import Dodge.Tesla import Dodge.Beam import Dodge.Item.Weapon.LaserPath import Dodge.Item.Location import Dodge.Creature.HandPos import Dodge.Particle.TeslaArc import Dodge.Particle.Flame import Dodge.SoundLogic.LoadSound import Dodge.WorldEvent.Flash import Dodge.WorldEvent.Damage --import Dodge.Default --import Dodge.Item.Weapon.InventoryDisplay import Dodge.Item.Weapon.TriggerType import Dodge.Item.Weapon.AmmoParams import Dodge.Default.Weapon --import Dodge.Item.Attachment import Dodge.WorldEvent.HelperParticle import Dodge.Base import Dodge.Zone import Geometry import Picture import Shape import ShapePicture import LensHelp import Dodge.RandomHelp import MonadHelp import Data.Maybe import Data.List (sortOn) import System.Random --import Data.Tuple import qualified Data.IntMap.Strict as IM import qualified Data.Map.Strict as M import Control.Monad.State defaultBatteryGun :: Item defaultBatteryGun = defaultGun & itType . iyModules .~ batteryModules batteryModules :: M.Map ModuleSlot ItemModuleType batteryModules = M.fromList [(ModBattery, EMPTYMODULE) ,(ModTeleport, EMPTYMODULE) ] defaultAutoBatteryGun :: Item defaultAutoBatteryGun = defaultAutoGun & itType . iyModules .~ batteryModules sparkGun :: Item sparkGun = teslaGun & itType . iyBase .~ SPARKGUN & itParams . arcSize .~ 10 teslaGun :: Item teslaGun = defaultBatteryGun { _itConsumption = defaultAmmo { _laMax = 200 , _laLoaded = 200 , _laReloadTime = 80 } , _itUse = ruseInstant shootTeslaArc NoHammer [ ammoCheckI , withTempLight 1 100 (V3 0 0 1) , withSoundForI elecCrackleS 1 , useAmmoAmount 1 ] & useAim . aimWeight .~ 6 & useAim . aimStance .~ TwoHandFlat , _itDimension = ItemDimension { _dimRad = 9 , _dimCenter = V3 4 0 0 , _dimPortage = HeldItem {_handlePos = 4 ,_muzPos = 4 } , _dimSPic = teslaGunPic } , _itParams = teslaParams } & itType . iyBase .~ TESLAGUN teslaGunPic :: Item -> SPic teslaGunPic _ = noPic $ colorSH blue $ upperPrismPoly 5 (rectNESW xb 8 xa 0) ++ upperPrismPoly 5 (rectNESW (-xa) 8 (-xb) 0) where xa = 1 xb = 9 lasGunPulse :: Item lasGunPulse = lasGun & itType . iyBase .~ LASPULSE & itUse . useMods .~ [ ammoCheckI , withItem $ \it -> withTempLight 1 (100 * frac it) (xyzV4 (_lasColor $ _itParams it)) , withItem $ \it -> withSoundForVol (frac it) tone440sawtoothquietS 2 , withItemUpdate itup $ \it -> withMuzPos $ flareCircleAt (_lasColor $ _itParams it) (frac it * 0.8) , useAmmoAmount 1 ] where itup it = it & itParams . lasCycle %~ (\i -> (i+1) `mod` 20) & itParams . lasDamage .~ ceiling ((22 :: Float) * frac it) & itParams . lasColor .~ frac it * orange frac it = 0.5 * (1 + sin (pi * fromIntegral (_lasCycle $ _itParams it) * 0.1)) lasGunWide :: Int -> Item lasGunWide n = lasGun & itType . iyBase .~ LASGUNWIDE n & itParams . lasColor .~ orange & itParams . lasDamage .~ 2 & itUse .~ ( ruseInstant shootLaser NoHammer [ ammoCheckI , withItem $ \it -> withTempLight 1 100 (xyzV4 (_lasColor $ _itParams it)) , withItem $ \it -> withMuzPos $ flareCircleAt (_lasColor $ _itParams it) 0.8 , withSoundForI tone440sawtoothquietS 2 , useAmmoAmount 1 , duplicateOffsets xs ] & useAim . aimWeight .~ 6 & useAim . aimRange .~ 1 & useAim . aimStance .~ TwoHandTwist ) where n' = 9 * n xs = [ 0.25 * (fromIntegral x - fromIntegral (n'-1) /2) | x <- [0..n'-1] ] lasGunWidePulse :: Item lasGunWidePulse = lasGun & itType . iyBase .~ LASGUNWIDEPULSE & itParams . lasColor .~ orange & itParams . lasDamage .~ 2 & itUse .~ ( ruseInstant shootLaser NoHammer [ ammoCheckI , withItem $ \it -> withTempLight 1 (100 * frac it) (xyzV4 (_lasColor $ _itParams it)) , withItem $ \it -> withSoundForVol (frac it) tone440sawtoothquietS 2 , withItemUpdate itup $ \it -> withMuzPos $ flareCircleAt (_lasColor $ _itParams it) (frac it * 0.8) , useAmmoAmount 1 , withItemUpdate itup $ \it -> duplicateOffsets (xs it) ] & useAim . aimWeight .~ 6 & useAim . aimRange .~ 1 & useAim . aimStance .~ TwoHandTwist ) where itup it = it & itParams . lasCycle %~ (\i -> (i+1) `mod` 40) & itParams . lasDamage .~ ceiling ((22 :: Float) * frac it) & itParams . lasColor .~ frac it * orange frac it = 0.5 * (1 + sin (pi * fromIntegral (_lasCycle $ _itParams it) * 0.05)) xs it = [ 0.25 * (fromIntegral x - fromIntegral (n'-1) /2) | x <- [0..n'-1] ] where n' = (ceiling $ (150 :: Float) * frac it) :: Int lasGunSway :: Item lasGunSway = lasGun & itType . iyBase .~ LASGUNSWAY & itParams . lasColor .~ orange & itParams . lasDamage .~ 11 & itUse .~ ( ruseInstant shootLaser NoHammer [ 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 itup $ \it -> duplicateOffsets (x it) ] & useAim . aimWeight .~ 6 & useAim . aimRange .~ 1 & useAim . aimStance .~ TwoHandTwist ) where itup = itParams . lasCycle %~ (\i -> (i+1) `mod` 40) x it = [ 15 * sin (pi * fromIntegral x' * 0.05) ] where x' = _lasCycle $ _itParams it lasGunFocus :: Int -> Item lasGunFocus n = lasGunWide n & itType . iyBase .~ LASGUNFOCUS n & itParams . lasColor .~ red & itUse . useMods .~ [ ammoCheckI , withItem $ \it -> withTempLight 1 100 (xyzV4 (_lasColor $ _itParams it)) , withItem $ \it -> withMuzPos $ flareCircleAt (_lasColor $ _itParams it) 0.8 , withSoundForI tone440sawtoothquietS 2 , useAmmoAmount 1 , duplicateOffsetsFocus xs ] where n' = 9 * n xs = [ 0.25 * (fromIntegral x - fromIntegral (n'-1) /2) | x <- [0..n'-1] ] lasGunDual :: Item lasGunDual = lasGun & itType . iyBase .~ LASGUNDUAL & itParams .~ DualBeam { _phaseV = 1 , _lasColor = orange , _lasColor2 = blue , _lasCycle = 0 , _lasDamage = 11 , _lasBeam = BeamCombine lasBeamCombine , _subParams = Nothing } & itUse .~ (ruseInstant shootDualLaser NoHammer [ ammoCheckI -- , withItem $ \it -> withTempLight 1 100 (xyzV4 (_lasColor $ _itParams it)) , withItem $ \it -> withMuzPosShift (V2 0 10) $ flareCircleAt (_lasColor $ _itParams it) 0.8 , withItem $ \it -> withMuzPosShift (V2 0 (-10)) $ flareCircleAt (_lasColor2 $ _itParams it) 0.8 , withSoundForI tone440sawtoothquietS 2 , useAmmoAmount 1 ] & useAim . aimWeight .~ 6 & useAim . aimRange .~ 1 & useAim . aimStance .~ TwoHandTwist ) & itType . iyModules . at ModDualBeam ?~ EMPTYMODULE lasGunSwing :: Item lasGunSwing = lasGun & itType . iyBase .~ LASGUNSWING & itParams . lasColor .~ orange & itUse . useMods .~ [ 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 itup $ \it -> duplicateOffsetsFocus (x it) ] where itup = itParams . lasCycle %~ (\i -> (i+1) `mod` 200) x it = [-y,y] where y = 15 * sin (pi * fromIntegral x' * 0.01) x' = _lasCycle $ _itParams it lasGun :: Item lasGun = defaultAutoBatteryGun { _itConsumption = defaultAmmo { _laMax = 200 , _laLoaded = 200 , _laReloadTime = 80 } , _itUse = ruseInstant shootLaser NoHammer [ ammoCheckI , withItem $ \it -> withTempLight 1 100 (xyzV4 (_lasColor $ _itParams it)) , withSoundForI tone440sawtoothquietS 2 , withItem $ \it -> withMuzPos $ flareCircleAt (_lasColor $ _itParams it) 0.8 , useAmmoAmount 1 ] & useAim . aimWeight .~ 6 & useAim . aimRange .~ 1 & useAim . aimStance .~ TwoHandTwist , _itParams = Refracting { _phaseV = 1 , _lasColor = yellow , _lasColor2 = yellow , _lasCycle = 0 , _lasDamage = 11 } , _itTweaks = Tweakable { _tweakParams = IM.fromList [(0,lasGunTweak)] , _tweakSel = 0 } , _itDimension = ItemDimension { _dimRad = 10 , _dimCenter = V3 15 0 0 , _dimPortage = HeldItem 5 30 , _dimSPic = lasGunPic } } & itType . iyBase .~ LASGUN lasGunPic :: Item -> SPic lasGunPic it = ( colorSH blue $ upperPrismPoly 4 (rectNESW 3 30 1 0) <> upperPrismPoly 4 (rectNESW (-1) 30 (-3) 0) <> upperPrismPoly 1 (rectNESW 3 30 (-3) 0) , setLayer BloomNoZWrite . color col . setDepth 1.1 . polygon $ rectNESW 1 30 (-1) 0 ) where amFrac = fractionLoadedAmmo it col = brightX 2 1.5 $ mixColors amFrac (1-amFrac) green red lasGunTweak :: TweakParam lasGunTweak = TweakParam { _doTweak = thetweak , _curTweak = 1 , _maxTweak = 3 , _showTweak = showPhaseV , _nameTweak = "PHASE VELOCITY" } where thetweak 0 = itParams . phaseV .~ 0.2 thetweak 1 = itParams . phaseV .~ 1 thetweak 2 = itParams . phaseV .~ 5 thetweak _ = id showPhaseV 0 = "V" showPhaseV 1 = "/" showPhaseV 2 = "Z" showPhaseV i = "THIS SHOULD NOT BE POSSIBLE" ++ show i tractorGun :: Item tractorGun = lasGun { _itConsumption = defaultAmmo { _laMax = 10000 , _laLoaded = 10000 , _laReloadTime = 40 } , _itUse = ruseInstant aTractorBeam NoHammer [ ammoCheckI ] & useAim . aimWeight .~ 6 & useAim . aimRange .~ 1 & useAim . aimStance .~ TwoHandTwist , _itDimension = ItemDimension { _dimRad = 10 , _dimCenter = V3 15 0 0 , _dimPortage = HeldItem 5 30 , _dimSPic = tractorGunPic } , _itParams = Attracting {_attractionPower = 1} , _itTweaks = Tweakable { _tweakParams = IM.fromList [(0,tractorGunTweak)] , _tweakSel = 0 } } & itType . iyBase .~ TRACTORGUN tractorGunTweak :: TweakParam tractorGunTweak = TweakParam { _doTweak = thetweak , _curTweak = 1 , _maxTweak = 4 , _showTweak = showPower , _nameTweak = "TRACTION POWER" } where thetweak 0 = itParams . attractionPower .~ 1 thetweak 1 = itParams . attractionPower .~ -1 thetweak 2 = itParams . attractionPower .~ -10 thetweak 3 = itParams . attractionPower .~ 0 thetweak _ = id showPower 0 = "+" showPower 1 = "-" showPower 2 = "#" showPower 3 = "0" -- object should stay in the center of the beam showPower i = "THIS SHOULD NOT BE POSSIBLE" ++ show i tractorGunPic :: Item -> SPic tractorGunPic it = ( colorSH red $ upperPrismPoly 4 (rectNESW 3 30 1 0) <> upperPrismPoly 4 (rectNESW (-1) 30 (-3) 0) <> upperPrismPoly 1 (rectNESW 3 30 (-3) 0) , setLayer BloomNoZWrite . color col . setDepth 1.1 . polygon $ rectNESW 1 30 (-1) 0 ) where amFrac = fractionLoadedAmmo it col = brightX 2 1.5 $ mixColors amFrac (1-amFrac) green red -- | assumes that the item is held shootTeslaArc :: Item -> Creature -> World -> World shootTeslaArc it cr w = w' & creatures . ix (_crID cr) . crInv . ix (_crInvSel cr) . itParams .~ ip where (w',ip) = shootTeslaArc' (_itParams it) pos dir w pos = _crPos cr +.+ aimingMuzzlePos cr it *.* unitVectorAtAngle dir dir = _crDir cr shootLaser :: Item -> Creature -> World -> World shootLaser it cr = instantParticles .:~ lasRayAt (_lasColor $ _itParams it) dam phasev pos dir where pos = _crPos cr +.+ aimingMuzzlePos cr it *.* unitVectorAtAngle dir dir = _crDir cr phasev = _phaseV . _itParams $ _crInv cr IM.! _crInvSel cr dam = _lasDamage $ _itParams it shootDualLaser :: Item -> Creature -> World -> World shootDualLaser it cr w = w' & newBeams . positronBeams .:~ dualRayAt (_lasBeam $ _itParams it) itid w (_lasColor $ _itParams it) dam phasev posl dirl & newBeams . electronBeams .:~ basicBeamAt itid w (_lasColor2 $ _itParams it) dam phasev posr dirr where (w',itid) = getHeldItemLoc cr w dir = _crDir cr pos = _crPos cr +.+ aimlength *.* unitVectorAtAngle dir aimlength = aimingMuzzlePos cr it posl = pos +.+ (-10) * vNormal (unitVectorAtAngle dir) posr = pos +.+ 10 * vNormal (unitVectorAtAngle dir) mwp = mouseWorldPos w mwp' | dist mwp (_crPos cr) < aimlength + 5 = _crPos cr +.+ (aimlength + 5) *.* unitVectorAtAngle dir | otherwise = mwp dirl = argV $ mwp' -.- posl dirr = argV $ mwp' -.- posr phasev = _phaseV . _itParams $ _crInv cr IM.! _crInvSel cr dam = _lasDamage $ _itParams it drawBeam :: Beam -> Picture drawBeam bm = setLayer BloomNoZWrite $ pictures [ setDepth 19 . color (brightX 0 0.5 col) $ thickLine 20 ps , setDepth 19.5 . color (brightX 10 1 col) $ thickLine 3 ps ] where col = _bmColor bm ps = _bmFirstPoints bm basicBeamAt :: Int -> World -> Color -> Int -> Float -> Point2 -> Float -> Beam basicBeamAt itid w col dam phasev pos dir = Beam { _bmDraw = drawBeam , _bmPos = pos , _bmDir = dir , _bmDamage = dam , _bmRange = 800 , _bmPhaseV = phasev , _bmColor = col , _bmPoints = pos:ps , _bmFirstPoints = [] , _bmOrigin = Just itid , _bmType = BeamCombine $ const id } where (_,ps) = reflectLaserAlong phasev [] pos (pos +.+ 800 *.* unitVectorAtAngle dir) w dualRayAt :: BeamType -> Int -> World -> Color -> Int -> Float -> Point2 -> Float -> Beam dualRayAt bt itid w col dam phasev pos dir = basicBeamAt itid w col dam phasev pos dir & bmType .~ bt aTractorBeam :: Item -> Creature -> World -> World aTractorBeam _ cr w = w & props . at i ?~ tractorBeamAt i spos outpos dir power where i = newProjectileKey w cpos = _crPos cr spos = cpos +.+ (_crRad cr + 10) *.* unitVectorAtAngle dir xpos = cpos +.+ 400 *.* unitVectorAtAngle dir dir = _crDir cr outpos = collidePointWalls cpos xpos $ wallsAlongLine cpos xpos w power = _attractionPower . _itParams $ _crInv cr IM.! _crInvSel cr tractorBeamAt :: Int -> Point2 -> Point2 -> Float -> Point2 -> Prop tractorBeamAt i pos outpos dir power = ProjectileTimed { _pjPos = pos , _pjStartPos = outpos , _pjVel = d , _prDraw = tractorSPic , _pjID = i , _pjUpdate = updateTractor , _pjTime = 10 } where d = unitVectorAtAngle dir * power {- | The interaction of this with objects, walls etc needs more thought. -} updateTractor :: Prop -> World -> World updateTractor pj w | _pjTime pj <= 0 = w & props %~ IM.delete i | otherwise = w & props . ix i . pjTime -~ 1 & creatures %~ IM.map (tractCr pullVel pos outpos) & floorItems %~ IM.map (tractFlIt pullVel pos outpos) where i = _pjID pj pullVel = _pjVel pj pos = _pjPos pj outpos = _pjStartPos pj tractFlIt :: Point2 -> Point2 -> Point2 -> FloorItem -> FloorItem tractFlIt q p1 outpos it | circOnSeg p1 outpos (_flItPos it) 10 = it & flItPos %~ tractorPullPos q p1 | otherwise = it tractCr :: Point2 -> Point2 -> Point2 -> Creature -> Creature tractCr q p1 outpos cr | circOnSeg p1 outpos (_crPos cr) 10 = cr & crPos %~ tractorPullPos q p1 | otherwise = cr tractorPullPos :: Point2 -> Point2 -> Point2 -> Point2 tractorPullPos q p1 p = p -.- m *.* (0.3/ x' *.* q +.+ g y *.* p4) where x' = abs y + 1 y = errorClosestPointOnLineParam 1 p1 p3 p m | dist p p1 < 350 = 1 | otherwise = (400 - dist p p1) / 50 g x | x > 5 = (10 - x) / 250 | x > 1 = 0.02 | x > -1 = x * 0.02 | x > -5 = -0.02 | otherwise = (x - 10) / 250 --p4 = vNormal p5 p4 = vNormal $ squashNormalizeV q p3 = p1 +.+ p4 tractorSPic :: Prop -> SPic tractorSPic pj = (,) mempty $ setLayer BloomNoZWrite $ setDepth 20 $ color (withAlpha 0.5 col) $ polygon [ spos -- not sure if this is anticlockwise... , spos +.+ size *.* (d +.+ n) , xpos +.+ size *.* n , xpos -.- size *.* n , spos +.+ size *.* (d -.- n) ] where size = fromIntegral (_pjTime pj) spos = _pjPos pj xpos = _pjStartPos pj d = squashNormalizeV $ spos -.- xpos n = vNormal d col = mixColors 0.5 0.5 white blue