module Dodge.Creature 
    ( module Dodge.Creature
    , module Dodge.Creature.Inanimate
    )
  where
-- imports {{{
import Dodge.Data
import Dodge.AIs
import Dodge.CreatureState
import Dodge.Default
import Dodge.Base
import Dodge.Item.Weapon
import Dodge.Item.Consumable
import Dodge.WorldEvent.Cloud
import Dodge.Creature.YourControl
import Dodge.Creature.Inanimate

import Picture
import Geometry

import Data.List
import Data.Char
import Data.Maybe
import Data.Function
import Data.Graph.Inductive.Graph
import Data.Graph.Inductive.PatriciaTree
import Codec.BMP
import qualified Data.ByteString as B
import Control.Lens
import Control.Applicative
import Control.Monad.State
import Control.Monad
import System.Random
import qualified Data.Set as S
import qualified Data.IntMap.Strict as IM
import qualified Data.Map as M
import Foreign.ForeignPtr
import Control.Concurrent

colouredEnemy col = pictures [color col $ circleSolid 10, circLine 10]

spawnerCrit :: Creature
spawnerCrit = defaultCreature
    { _crUpdate = stateUpdate $ spawnerAI chaseCrit
    , _crHP = 300
    , _crPict = enemyPict blue
    , _crState = defaultState {_goals = [[WaitFor 0]]
                            }
    , _crInv = IM.empty -- IM.fromList [(0,frontArmour)]
    }
smallChaseCrit :: Creature
smallChaseCrit = defaultCreature
    { _crUpdate = stateUpdate chaseAI
    , _crHP = 1
    , _crRad = 4
    , _crPict = enemyPict green
    , _crState = defaultState {_goals = [[Wait]]
                            ,_faction = ChaseCritters}
    , _crInv = IM.empty -- IM.fromList [(0,frontArmour)]
    , _crCorpse = onLayer CorpseLayer $ color (greyN 0.5) $ circleSolid 4
    }
chaseCrit :: Creature
chaseCrit = defaultCreature
    { _crUpdate = stateUpdate chaseAI
    , _crHP = 300
    , _crPict = enemyPict green
    , _crState = defaultState {_goals = [[Wait]]
                            ,_faction = ChaseCritters}
    , _crInv = IM.empty 
    }
armourChaseCrit :: Creature
armourChaseCrit = defaultCreature
    { _crUpdate = stateUpdate chaseAI
    , _crHP = 300
    , _crPict = enemyPict green
    , _crState = defaultState {_goals = [[Wait]]}
    , _crInv = IM.fromList [(0,frontArmour)]
    }
miniGunCrit :: Creature
miniGunCrit = defaultCreature
    { _crPict = enemyPict red
    , _crUpdate = stateUpdate  miniAI
    , _crInv = IM.fromList [(0,miniGun)]
    , _crInvSel = 0
    , _crRad = 10
    , _crState = defaultState {_goals = [[InitGuard]]}
    , _crHP = 500
    }
longCrit :: Creature
longCrit = defaultCreature
    { _crPict = enemyPict red
    , _crUpdate = stateUpdate sniperAI
    , _crInv = IM.fromList [(0,longGun),(1,medkit 100)]
    , _crInvSel = 0
    , _crRad = 10
    , _crState = defaultState {_goals = [[InitGuard]]}
    , _crHP = 300
    }
multGunCrit :: Creature
multGunCrit = defaultCreature
    { _crPict = enemyPict red
    , _crUpdate = stateUpdate (twitchMissAI 300 350)
    , _crInv = IM.fromList [(0,multGun),(1,medkit 100)]
    , _crInvSel = 0
    , _crRad = 10
    , _crState = defaultState {_goals = [[InitGuard]]}
    , _crHP = 300
    }
launcherCrit :: Creature
launcherCrit = defaultCreature
    { _crPict = enemyPict red
    , _crUpdate = stateUpdate (launcherAI 150 200)
    , _crInv = IM.fromList [(0,launcher),(1,medkit 100)]
    , _crInvSel = 0
    , _crRad = 10
    , _crState = defaultState {_goals = [[Init]]}
    , _crHP = 300
    }
spreadGunCrit :: Creature
spreadGunCrit = defaultCreature
    { _crPict = enemyPict red
    , _crUpdate = stateUpdate chargeAI
    , _crInv = IM.fromList [(0,spreadGun),(1,medkit 100)]
    , _crInvSel = 0
    , _crRad = 10
    , _crState = defaultState {_goals = [[Init]]}
    , _crHP = 300
    }
pistolCrit :: Creature
pistolCrit = defaultCreature
    { _crPict = enemyPict red
    , _crUpdate = stateUpdate (dodgeAI 150 200)
    , _crInv = IM.fromList [(0,pistol),(1,medkit 100)]
    , _crInvSel = 0
    , _crRad = 10
    , _crState = defaultState {_goals = [[InitGuard]]}
    , _crHP = 500
    }
autoCrit :: Creature
autoCrit = defaultCreature
    { _crPict = enemyPict red
    --, _crUpdate =  checkDeadStopSound n . shooterFootsteps n . makeStateAI autoShooterAI n
    , _crUpdate = stateUpdate  basicShooterAI
    --, _crUpdate = shooterFootsteps n . makeStateAI autoShooterAI n
    , _crInv = IM.fromList [(0,autoGun),(1,medkit 100)]
    , _crInvSel = 0
    , _crRad = 10
    --, _crState = ShooterWait
    , _crState = defaultState {_goals = [[InitGuard]]}
    , _crHP = 300
    }
addArmour :: Creature -> Creature
addArmour = over crInv insarmour
    where insarmour xs = IM.insert i frontArmour xs
            where i = newKey xs

equipOnTop :: (Creature -> Picture) -> Creature -> Picture
--equipOnTop f cr = onLayer CrLayer $ pictures $ fst (drawEquipment cr) ++ [f cr] ++ snd (drawEquipment cr)
equipOnTop f cr = pictures [onLayer CrLayer (f cr) , drawEquipment cr]

drawEquipment :: Creature -> Picture
drawEquipment cr = pictures $ map f $ IM.toList (_crInv cr)
    where f (i,it) = case it ^? itEquipPict of
                        Just g -> g cr i
                        _      -> blank

--drawEquipment :: Creature -> ([Picture],[Picture])
--drawEquipment cr = (map fst p1, map fst p2)
--     where f (k,it) = join $ (it ^? itEquipPict) <*> (pure cr) <*> (pure k)
--           picts = sortBy (compare `on` snd) $ mapMaybe f $ IM.toList (_crInv cr)
--           (p1,p2) = partition (\ x -> snd x < 0) picts

frontArmouredPict = const $ pictures [ color (greyN 0.8) $ circleSolid 20
                             , color red $ circLine 20
                             ]

--packCrits :: (Int -> World -> World) -> [Int] -> [Creature]
--packCrits ai is = [(defaultCreature i)
--    { _crPos = (150,10+20*fromIntegral i)
--    , _crPict = swarmPict
--    , _crUpdate = ai i
--    --, _crUpdate = swarmAI is i
--    , _crRad = 3
--    , _crHP = 1
--    , _crMass = 2
--    }
--    | i <- is]

--queenBeeCrit :: Int -> Creature
--queenBeeCrit cID = (defaultCreature cID)
--    { _crRad = 20
--    , _crCorpse = color (greyN 0.5) $ circleSolid 20
--    , _crPict = const $ pictures [color black $ circSolid 20
--                         ,color yellow $ circLine 20
--                         ]
--    , _crUpdate = checkDead cID . makeStateAI queenBeeAI cID
--    , _crState = QueenBee 0 20
--    , _crMass = 20
--    }

--antCrit :: Int -> Creature
--antCrit cID = (defaultCreature cID)
--    { _crPos = (0,100 + 3 * fromIntegral cID)
--    , _crUpdate = checkDead cID . makeStateAI (antAI 2) cID
--    , _crState = AntMove 50
--    , _crPict = antPic
--    , _crRad = 3
--    , _crHP = 1
--    , _crMass = 2
--    , _crCorpse = color (greyN 0.5) $ circSolid 3
--    }
--    where i = evalState (state (randomR (1::Int,100))) (mkStdGen cID)
--antPic = const $ pictures [ translate (-1) 0 $ circleSolid 2
--                  , translate (2) 0 $ circleSolid 1
--                  , translate (1) 0 $ circleSolid 1
--                  , line [(3,3),(-3,-3)]
--                  , line [(-3,3),(3,-3)]
--                  , line [(0,-3),(0,3)]
--                  ]

flamerPict = const $ pictures [color (light $ light $ light $ dim blue) $ circleSolid 10, circLine 10]



goalPict cr = let r = _crRad cr in case _crState cr of
    CrSt {_goals = gls ,_crDamage = crDam } 
--            | crDam > _crHP cr -> color white $ circleSolid r
            | otherwise        -> case head gls of
                        [] -> sizeColEnemy r white
                        (MoveToFor p i:_) -> dImpulses $ sizeColEnemy r green
                        (WaitFor x:_) -> dImpulses $ sizeColEnemy r yellow
                        (FireAt p:_) -> dImpulses $ sizeColEnemy r red
                        (Reload:_) -> dImpulses $ sizeColEnemy r orange
                        (PathTo p:_) -> dImpulses $ sizeColEnemy r cyan
                        (SubPathTo p i _:_) -> dImpulses $ sizeColEnemy r blue
                        (Search i:_) -> dImpulses $ sizeColEnemy r black
                        _ -> dImpulses $ sizeColEnemy r magenta
                    where dImpulses p = pictures [p, rotate (0 - _crDir cr) $ scale 0.1 0.1 $ color white $ text $ show gls]
    _                  -> sizeColEnemy r (light $ dim green)

startCr :: Creature
startCr = defaultCreature
    { _crPos = (0,0)
    , _crOldPos = (0,0)
    , _crDir = 0
    , _crID = 0
    , _crPict = basicCrPict $ greyN 0.8
                
    , _crUpdate = stateUpdate yourControl
    , _crRad = 10
    , _crMass = 10
    , _crHP = 10000
    , _crMaxHP = 1500
    , _crInv = IM.fromList (zip [0..20] 
<<<<<<< HEAD:src/Dodge/Creature.hs
         (
          [pistol,autoGun,launcher,lasGun,grenade
          ,ltAutoGun,flamer,multGun,spreadGun,remoteLauncher
          ,longGun
          ,hvAutoGun
          ,teslaGun
          ,latchkey 0
          ,miniGun
          ,medkit 50
          ,bezierGun
          ,poisonSprayer
          ,blinkGun
          ,frontArmour
          ] 
          ++ repeat NoItem)) 
         -- startInv
=======
                           ([pistol,flameGrenade, teslaGrenade, autoGun,launcher,flameLauncher, poisonLauncher, teslaLauncher, lasGun,grenade
                            ,ltAutoGun,flamer,multGun,spreadGun,remoteLauncher
                            ,longGun
                            ,hvAutoGun
                            ,teslaGun
                            ,latchkey 0
                            ,miniGun
                            ,medkit 50
                            ,bezierGun
                            ,poisonSprayer
                            ,blinkGun
                            ] 
                            ++ repeat NoItem)) 
                          -- startInv
>>>>>>> testing:src/Dodge/Critters.hs
    , _crCorpse = onLayer CorpseLayer $ color (greyN 0.5) $ pictures [color (greyN 0.8) $ circleSolid 10, circLine 10]
    }

smokeGenGun = effectGun "smoke" $ \_ -> spawnSmokeAtCursor

enemyPict :: Color -> Creature -> Picture
enemyPict col = equipOnTop $ sizeEnemy (light $ light $ light $ light col)

sizeEnemy col cr 
    | pdam > 200      = color red $ circleSolid $ _crRad cr
    | pdam > 100      = color white $ circleSolid $ _crRad cr
    | mod pdam 2 == 1 = color white $ circleSolid $ _crRad cr
    | otherwise       = pictures [color col $ circleSolid $ _crRad cr
                                 , circLine $ _crRad cr ]
    where pdam = _crPastDamage $ _crState cr

sizeColEnemy r col = pictures [color col $ circleSolid r, circLine r]

basicCrPict :: Color -> Creature -> Picture
basicCrPict col cr = pictures [ onLayer CrLayer naked , drawEquipment cr]
    where naked | pdam > 200      = color red $ circleSolid $ _crRad cr
                | pdam > 100      = color white $ circleSolid $ _crRad cr
                | mod pdam 2 == 1 = color white $ circleSolid $ _crRad cr
                -- | crDam > _crHP cr && odd (crDam - _crHP cr)
                --     = [color white $ circleSolid $ _crRad cr]
                | otherwise        =  pictures [color col $ circleSolid $ _crRad cr, circLine $ _crRad cr]
          pdam = _crPastDamage $ _crState cr
