module Dodge.Item.Weapon.SprayGuns
    ( poisonSprayer
    , flameSpitter
    , blowTorch
    , flameThrower
    , flameTorrent
    , flameWall
    ) where
import Dodge.Data
import Dodge.Reloading.Action
import Dodge.Particle.Flame
--import Dodge.Data.SoundOrigin
--import Dodge.Base
--import Dodge.Zone
--import Dodge.Picture.Layer
--import Dodge.SoundLogic
import Dodge.SoundLogic.LoadSound
--import Dodge.Creature.Action
import Dodge.WorldEvent
import Dodge.Default
--import Dodge.Item.Weapon.BulletGuns
--import Dodge.Item.Weapon.InventoryDisplay
import Dodge.Item.Weapon.TriggerType
--import Dodge.Item.Weapon.ExtraEffect
--import Dodge.Item.Weapon.UseEffect
import Dodge.Item.Weapon.AmmoParams
import Dodge.Default.Weapon
--import Dodge.Item.Attachment
import Geometry
--import Geometry.Vector3D
import Picture
import Shape
import ShapePicture
import LensHelp

import Data.Traversable
import qualified Data.IntMap.Strict as IM
import Control.Monad.State
--import Data.Function
import System.Random
poisonSprayer :: Item
poisonSprayer = flameThrower 
    & itType . iyBase .~ POISONSPRAYER
    & itConsumption . laAmmoType .~ GasAmmo
        { _amString = "POISONGAS"
        , _amCreateGas = aGasCloud
        }
    & itUse . useMods .~
        [ ammoCheckI
        , withSoundForI foamSprayLoopS 5
        , useAmmoAmount 1
--        , spreadNumI
        ] 
    
flamerPic :: Item -> SPic
flamerPic it = 
    ( colorSH yellow $ 
        translateSHf tx ty (upperPrismPoly tz $ polyCirc 3 r)
        <> upperPrismPoly 5 (rectNESW 2 18 (-2) 0)
    , color black $ translate3 (V3 tx ty (tz+0.01)) $ circleSolid (r * am)
    )
  where
    tx = 4
    ty = - 6
    tz = 3
    r = 5
    am = fractionLoadedAmmo2 it
flameSpitter :: Item
flameSpitter = flameThrower
    & itType . iyBase .~ FLAMESPITTER
    & itConsumption . laMax .~ 10
    & itConsumption . laCycle .~ [loadEject 5, loadInsert 10 , loadPrime 20]
    & itParams . sprayNozzles . ix 0 . nzPressure .~ 4
    & itUse . useAim . aimStance .~ OneHand
    & itUse . useDelay .~ FixedRate {_rateMax =12,_rateTime = 0}
    & itUse . useMods .~
        [ ammoCheckI
        , useTimeCheck
        , lockInvFor 10
        , repeatOnFrames [1..9]
        , withRandomItemParams f
        , useAmmoAmount 1
        , withSidePushI 5
        , withSidePushAfterI 20
        ]
  where
    f = do
        nzpres <- state $ randomR (3,4)
        return $ sprayNozzles . ix 0 . nzPressure .~ nzpres

flameTorrent :: Item
flameTorrent = flameThrower 
    & itType . iyBase .~ FLAMETORRENT
    & itUse . useAim . aimZoom .~ defaultItZoom
    & itParams . sprayNozzles . ix 0 %~ 
        ( (nzPressure .~ 10)
        . (nzMaxWalkAngle .~ 1.5)
        . (nzWalkSpeed .~ 0.05)
        )

blowTorch :: Item
blowTorch = flameThrower
    & itType . iyBase .~ BLOWTORCH
flameWall :: Item
flameWall = flameThrower 
    & itType . iyBase .~ FLAMEWALL
    & itParams . sprayNozzles .~ zipWith makeNozzle [0,0.6,-0.6] [2,2.5,2.5]
  where
    makeNozzle dir pres = Nozzle
        { _nzPressure = pres
        , _nzDir = dir
        , _nzMaxWalkAngle = 0
        , _nzWalkSpeed = 0
        , _nzCurrentWalkAngle = 0
        , _nzLength = 20
        }

flameThrower :: Item
flameThrower = defaultAutoGun
    { _itConsumption = defaultLoadable
        & laMax .~ 250
        & laAmmoType .~ GasAmmo
            {_amString = "FLAME"
            ,_amCreateGas = aFlame
            }
        & laCycle .~ [loadEject 5, loadInsert 10 , loadPrime 20]
    , _itUse = ruseInstant (overNozzles useGasParams) NoHammer
        [ ammoCheckI
        , useAmmoAmount 1
        , withSidePushI 5
        --, withTempLight 1 100 (V3 1 0 0)
        , withSidePushAfterI 20
        ]
        & useAim . aimWeight .~ 5
        & useAim . aimZoom  .~ defaultItZoom {_itZoomMax = 5, _itZoomMin = 1.5}
        & useAim . aimStance .~ TwoHandTwist
--    , _itFloorPict = flamerPic
--    , _itZoom       = defaultItZoom
    , _itParams = Sprayer
        { _sprayNozzles = 
            [ Nozzle 
                { _nzPressure = 4
                , _nzDir = 0
                , _nzMaxWalkAngle = 0.2
                , _nzWalkSpeed = 0.01
                , _nzCurrentWalkAngle = 0
                , _nzLength = 10
                }
            ]
        }
    , _itDimension = ItemDimension
        { _dimRad = 7
        , _dimCenter = V3 9 0 0
        , _dimPortage = HeldItem
            { _handlePos = 0
            , _muzPos = 18
            }
        , _dimSPic = flamerPic
        }
--    , _itFloorPict = flamerPic
    }
    & itType . iyBase .~ FLAMETHROWER

aGasCloud :: Float -> Point2 -> Float -> Creature -> World -> World
aGasCloud pressure pos dir cr = makeGasCloud pos 
    $ (_crPos cr -.- _crOldPos cr) +.+ pressure *.* unitVectorAtAngle dir

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 = _amCreateGas (_laAmmoType (_itConsumption it)) (_nzPressure nz) pos dir cr
  where 
    dir = _crDir cr
    pos = _crPos cr +.+ (_nzLength nz *.* unitVectorAtAngle (_crDir cr))

aFlame :: Float -> Point2 -> Float -> Creature -> World -> World
aFlame pressure pos dir cr = makeFlame pos vel
    --w & instantParticles .:~ aFlameParticle t pos vel Nothing -- (Just $ _crID cr)
  where 
--    (t,_) = randomR (99,101) (_randGen w)
    vel = (_crPos cr -.- _crOldPos cr) +.+ pressure *.* unitVectorAtAngle dir
