{-
Rooms containing particularly challenging creatures, that may drop useful loot.
-}
module Dodge.Room.Boss
  where
import Dodge.Data
import Dodge.Default.Room
import Dodge.Room.Data
import Dodge.Room.Procedural
import Dodge.Room.Placement
import Dodge.Room.Link
import Dodge.Room.Corridor
import Dodge.Room.Path
import Dodge.LevelGen.Data
import Dodge.Creature
import Dodge.Creature.State.Data
import Dodge.RandomHelp
import Dodge.Layout.Tree.Polymorphic
import Geometry

import Data.Tree
import Control.Monad.State
import Control.Lens
import System.Random
roomGlassOctogon
    :: Float    -- ^ Size
    -> Room
roomGlassOctogon x = createPathGrid $ defaultRoom
--roomGlassOctogon x = defaultRoom
    { _rmPolys = 
        [rectNSWE x (-x) (-x) x
        ,rectNSWE 0 (-(x + 40)) (-20) 20
        ]
    , _rmLinks = lnks
    , _rmPath  = linksAndPath lnks  
        [ ( V2 0 x        , V2 0 (-(x+40)))
        , ( V2 0 (-(x+40)), V2 0 x)
        ]
    , _rmPS = 
        [sPS (V2 fx fx)   0 putLamp
        ,sPS (V2 (-fx) fx)  0 putLamp
        ,sPS (V2 fx (-fx))  0 putLamp
        ,sPS (V2 (-fx) (-fx)) 0 putLamp
        ,crystalLine (V2 (-x) (x/2)) (V2 (negate (x/2))  x)
        ,crystalLine (V2 x (x/2))  (V2 (x/2)  x)
        ,crystalLine (V2 (x/2) (-x)) (V2 x (negate (x/2)))
        ,crystalLine (V2 (negate $ x/2) (-x)) (V2 (-x) (negate (x/2)))
        ,blockLine (V2 (-40) (50-x)) (V2 40 (50-x))
        ]
    , _rmBound = [rectNSWE x (-x) (-x) x]
    }
  where
    fx = 4 * x / 5
    lnks = 
        [ (V2 0 x,0)
        , (V2 0 (-(x+40)),pi)
        ]

bossRoom :: RandomGen g => Creature -> State g Room
bossRoom cr = randomMediumRoom <&> rmPS %~ ( sPS (V2 0 100) (negate $ pi/2) (PutCrit cr) :)

armouredChasers :: RandomGen g => State g (Tree Room)
armouredChasers = do
    ps <- takeN 5 [V2 x y | x <- [-100,-80 .. 100] ,y <- [-100,-80 .. 100] ]
    as <- replicateM 5 . state $ randomR (0,2*pi)
    let theCrits = zipWith3 (\p a c -> sPS p a (PutCrit c)) ps as cs
    treeFromPost [corridor,corridor] <$> (randomMediumRoom <&> rmPS %~ (++ theCrits))
  where
    cs = (armourChaseCrit & crState . crDropsOnDeath .~ DropSpecific [0]) 
            : replicate 4 chaseCrit

randomMediumRoom :: RandomGen g => State g Room
randomMediumRoom = takeOne 
    [ roomGlassOctogon 300
    , roomCross 180 300
    , roomShuriken 200 300
    , roomTwistCross 230 300 0
    ]

roomCross 
    :: Float -- ^ First width/2
    -> Float -- ^ Second width/2
    -> Room
roomCross x y = defaultRoom
    { _rmPolys = [rectNSWE y (-y) (-x) x
                 ,rectNSWE (-x) x y (-y)
                 ]
    , _rmLinks = 
        [(V2  x  (y-20),negate $ pi/2)
        ,(V2  x  (20-y),negate $ pi/2)
        ,(V2 (20-y)  x ,0)
        ,(V2 (y-20)  x ,0)
        ,(V2 (-x) (y-20),pi/2)
        ,(V2 (-x) (20-y),pi/2)
        ,(V2 (20-y) (-x),pi)
        ,(V2 (y-20) (-x),pi)
        ]
    , _rmPath  = []
    , _rmPS = 
        [sPS (V2  x  0) 0 putLamp
        ,sPS (-V2 x  0) 0 putLamp
        ,sPS (V2  0  x) 0 putLamp
        ,sPS (V2  0 (-x)) 0 putLamp
        ]
    , _rmBound = 
        [rectNSWE y (-y) (-x) x
        ,rectNSWE x (-x) (-y) y
        ]
    }
{- | TODO: pathing -}
roomShuriken 
    :: Float -- ^ First width/2
    -> Float -- ^ Second width/2
    -> Room
roomShuriken x y = 
    let ps = [ map toV2
            [ (0,-20)
            , (x,-20)
            , (x,y)
            , (0,x)
            ]   ]
        corner = defaultRoom
            { _rmPolys  = ps
            , _rmLinks  = [(V2 (x-1) (y-20),negate $ pi/2)]
            , _rmPath   = []
            , _rmPS     = [sPS (V2 (x/2) (x/2)) 0 putLamp]
            , _rmBound  = ps
            }
    in foldr1 combineRooms $ map (\r -> shiftRoomBy (V2 0 0, r) corner) [0,pi/2,pi,3*pi/2]
{- | TODO: pathing 
Precondition: first float is less than the second by at least 40. -}
roomTwistCross 
    :: Float -- ^ First width/2, 
    -> Float -- ^ Second width/2, should be biggest
    -> Float -- ^ Third width, should be smallest, possibly negative
    -> Room
roomTwistCross x y z = 
    let ps = [ map toV2 [ (x,negate $ z+20)
                , (x,x)
                , (z,y)
                , (z-20,x)
                , (z,negate $ z+20)
                ]   
            , rectNSWE (x-5) 0 0 (x-5)
            ]
        corner = defaultRoom
            { _rmPolys  = ps
            , _rmLinks  = [(V2 z (y-20), pi/2)]
            , _rmPath   = []
            , _rmPS     = [sPS (V2 (x/2) (x/2)) 0 putLamp]
            , _rmBound  = ps
            }
    in foldr1 combineRooms $ map (\r -> shiftRoomBy (V2 0 0, r) corner) [0,pi/2,pi,3*pi/2]
