module Dodge.Creature.PistolCrit
    ( pistolCrit 
    ) where
import Dodge.Data
import Dodge.Default
import Dodge.Creature.Picture
import Dodge.Creature.Update
import Dodge.Creature.Test
import Dodge.Creature.Action
import Dodge.Creature.Volition
import Dodge.Creature.Strategy
import Dodge.Creature.ReaderUpdate
import Dodge.Creature.Perception
--import Dodge.Creature.State.Data
import Dodge.Item.Weapon.BulletGuns
import Dodge.Item.Consumable
import Geometry
import Picture
import RandomHelp

import Data.Maybe
import qualified Data.IntMap.Strict as IM
import Control.Lens

pistolCrit :: Creature
pistolCrit = defaultCreature
    { _crPict = basicCrPict
    , _crUpdate =  defaultImpulsive
        [ performActions
        , watchUpdateStrat
              [ (crHasTargetLOS, \w cr -> StrategyActions (ShootAt 0) 
                    [DoActionIf (const $ not . crIsAiming) drawWeapon,chooseMovement cr w])
              , (const crAwayFromPost, const goToPostStrat)
              ]
        , perceptionUpdate [0]
        , const doStrategyActions
        , const reloadOverride
        , targetYouWhenCognizant
        , const $ overrideInternal
            (\cr -> crHasTarget cr && crStratConMatches (GetTo (V2 0 0)) cr)
            (crActionPlan . apStrategy .~ WatchAndWait)
        ]
    , _crInv = IM.fromList [(0,pistol),(1,medkit 100)]
    , _crRad = 10
    , _crHP = 500
    }
    & crSkin . skinUpper .~ light4 red
chooseMovement :: Creature -> World -> Action
chooseMovement cr w = chooseMovement' cr w
        `DoActionThen`
    DoImpulses [ChangeStrategy WatchAndWait]

chooseMovement' :: Creature -> World -> Action
chooseMovement' cr w = takeOneWeighted [chargeProb,retreatProb,strafeProb,strafeProb] 
    [chargeActions
    ,retreatActions ycr cr
    ,strafeLeftActions
    ,strafeRightActions
    ] & evalState $ g
  where
    g = _randGen w
    cpos = _crPos cr
    ycr = _creatures w IM.! 0
    ypos = _crPos ycr
    chargeProb | dist cpos ypos > 300 = 5
               | dist cpos ypos > 150 = 1
               | otherwise            = 0
    strafeProb | dist cpos ypos > 150 = 1
               | otherwise            = 0
    retreatProb | dist cpos ypos < 200 = 1 :: Float
                | otherwise            = 0
    chargeActions =
        [TurnToward ypos 0.1]
        `DoImpulsesAlongside`
        3
        `DoReplicate`
        ImpulsesList (replicate 9 [Move (V2 3 0)] ++ [[Move (V2 3 0),UseItem]])
    strafeLeftActions = 
        DoImpulses [TurnToward yposr (2*pi)]
        `DoActionThen`
        3
        `DoReplicate`
        ImpulsesList (replicate 9 [Move (V2 0 3)] ++ [[Move (V2 0 3),UseItem]])
    strafeRightActions = 
        DoImpulses [TurnToward yposl (2*pi)]
        `DoActionThen`
        3
        `DoReplicate`
        ImpulsesList (replicate 9 [Move (V2 0 (-3))] ++ [[Move (V2 0 (-3)),UseItem]])
    yposl = ypos -.- 100 *.* vNormal (normalizeV $ ypos -.- cpos)
    yposr = ypos +.+ 100 *.* vNormal (normalizeV $ ypos -.- cpos)

retreatActions :: Creature -> Creature -> Action
retreatActions tcr cr = 
    [TurnToward retreatOffset 0.2]
    `DoImpulsesAlongside`
    3
    `DoReplicate`
    ImpulsesList (replicate 9 [Move (V2 (-3) 0)] ++ [[UseItem]])
  where 
    cpos = _crPos cr
    tpos = _crPos tcr
    retreatOffset = 
        let a | dist cpos tpos < 50 = 0
              | isLeftOfA (_crDir cr) (argV $ tpos -.- cpos)
                    = -0.7
              | otherwise = 0.7
        in  fromMaybe tpos $ intersectLineLine' cpos 
                                                     (cpos +.+ rotateV a (tpos -.- cpos))
                                                     tpos
                                                     (tpos +.+ vNormal (cpos -.- tpos))
    

