module Dodge.Creature.Damage where
import Dodge.Data
import Dodge.Creature.Test
import Dodge.Particle.Spark
import Dodge.Particle.Bullet.Spawn
import Color
import Geometry
import LensHelp

import Control.Monad.State
--import System.Random
import Data.List

applyNoDamage :: [Damage] -> Creature -> World -> World
applyNoDamage _ _ = id

defaultApplyDamage :: [Damage] -> Creature -> World -> World
defaultApplyDamage ds cr w = foldl' (applyIndividualDamage cr) w ds'
    & creatures . ix (_crID cr) %~ doPoisonDam
  where 
    (ps,ds') = partition isPoison ds
    isPoison Damage{_dmType=POISONDAM} = True
    isPoison _ = False
    poisonDam = quot (max 0 (sum (map _dmAmount ps))) 10
    doPoisonDam = crHP -~ poisonDam

applyDamageEffect :: Damage -> DamageEffect -> Creature -> World -> World
applyDamageEffect dm de cr w = case de of
    PushDamage push pushexp pushRad -> w
        & creatures . ix (_crID cr) . crPos .+.+~ pushAmount *.* squashNormalizeV (_crPos cr -.- fromDir) 
      where
        pushAmount
            | dist (_crPos cr) fromDir == 0 = 0
            | otherwise = min 5 $ (push*5*pushRad / (dist (_crPos cr) fromDir * _crMass cr))**pushexp
    PushBackDamage pback -> w
        & creatures . ix (_crID cr) . crPos .+.+~ (1/_crMass cr) *.* pback
    TorqueDamage rot -> w
        & creatures . ix (_crID cr) . crDir +~ rot
    BounceBullet bt | crIsArmouredFrom p cr -> w & instantParticles .:~ bouncer
      where
        bouncer = (aBulAt Nothing id (Just (_ptColor bt)) Nothing pOut reflectVel (_btDrag bt)
                                          (_ptHitEff bt) (_ptWidth bt)
                  ) {_ptTimer = _ptTimer bt - 1}
        pOut = p +.+ 2 *.* newDir
        reflectVel = magV bulVel *.* newDir
        newDir = squashNormalizeV (p -.- _crPos cr)
        bulVel = _ptVel bt
    BounceBullet _ -> w
    DamageSpawn f -> w & instantParticles .:~ thepart
        & randGen .~ g
      where
        (thepart,g) = runState (f (Left cr) dm) $ _randGen w
    NoDamageEffect -> w
  where
    fromDir = _dmFrom dm
    p = _dmAt dm

applyIndividualDamage :: Creature -> World -> Damage -> World
applyIndividualDamage cr w dm = applyDamageEffect dm (_dmEffect dm) cr $ applyIndividualDamage' cr w dm

applyIndividualDamage' :: Creature -> World -> Damage -> World
applyIndividualDamage' cr w dm = case _dmType dm of
    PIERCING -> applyPiercingDamage cr dm w
    _ -> w & damageHP cr (_dmAmount dm)

applyPiercingDamage :: Creature -> Damage -> World -> World
applyPiercingDamage cr dm
    | crIsArmouredFrom p cr = colSpark 8 (brightX 10 1.5 orange) p1 (argV (p1 -.- p))
    | otherwise = damageHP cr $ _dmAmount dm
  where
    p = _dmAt dm
    p1 = p +.+ 2 *.* squashNormalizeV (p -.- _crPos cr)

damageHP :: Creature -> Int -> World -> World
damageHP cr x = creatures . ix (_crID cr) %~
    ( (crHP -~ x)
    . (crPastDamage +~ x)
    )
