206 lines
6.5 KiB
Haskell
206 lines
6.5 KiB
Haskell
{-# LANGUAGE FlexibleInstances #-}
|
|
-- | deals with placement of objects within the world
|
|
-- after they have had their coordinates set by the layout
|
|
module Dodge.LevelGen
|
|
( module Dodge.LevelGen
|
|
, cutWalls
|
|
, pairsToGraph
|
|
, makeButton
|
|
, makeSwitch
|
|
) where
|
|
import Dodge.Data
|
|
--import Dodge.Room.Data
|
|
import Dodge.LevelGen.Block
|
|
import Dodge.LevelGen.LineBlock
|
|
import Dodge.LevelGen.Pathing
|
|
import Dodge.LevelGen.StaticWalls
|
|
import Dodge.LevelGen.AutoDoor
|
|
import Dodge.LevelGen.TriggerDoor
|
|
import Dodge.LevelGen.Switch
|
|
import Dodge.LevelGen.Data
|
|
import Geometry
|
|
import Geometry.Vector3D
|
|
import Shape
|
|
--import Geometry.Data
|
|
import Picture
|
|
import qualified IntMapHelp as IM
|
|
|
|
--import System.Random
|
|
import Control.Monad.State
|
|
--import Control.Applicative
|
|
import Control.Lens
|
|
import Data.List.Extra
|
|
--import Data.Function
|
|
--import Data.Maybe
|
|
--import qualified Data.Set as S
|
|
--import qualified Data.Map as M
|
|
|
|
placeSpots :: [Placement] -> World -> World
|
|
placeSpots pss w = foldr (placeSpot . _placementSpot) w simplePlacements
|
|
where
|
|
(simplePlacements, idPlacements ) = partition isSimple pss
|
|
isSimple SimplePlacement{} = True
|
|
isSimple _ = False
|
|
|
|
placeSpot :: PlacementSpot -> World -> World
|
|
placeSpot ps w = case _psType ps of
|
|
PutProp prop -> placeProp prop p rot w
|
|
PutButton bt -> placeBt bt p rot w
|
|
PutFlIt itm -> placeFlIt itm p rot w
|
|
PutCrit cr -> placeCr cr p rot w
|
|
PutLS ls dec -> placeLS ls dec p' rot w
|
|
PutPressPlate pp -> placePressPlate pp p rot w
|
|
RandPS rgen -> placeSpot (set psType evaluatedType ps) (set randGen g w)
|
|
where
|
|
(evaluatedType, g) = runState rgen (_randGen w)
|
|
PutDoor col f pss -> putDoor col f (map (mapBoth $ shiftPointBy (p,rot)) pss) w
|
|
where
|
|
mapBoth fn (x,y) = (fn x, fn y)
|
|
PutDoubleDoor col f a b speed
|
|
-> putDoubleDoor False col f (shiftPointBy (p,rot) a) (shiftPointBy (p,rot) b) speed w
|
|
PutSingleDoor col f a b speed
|
|
-> putSingleDoor False col f (shiftPointBy (p,rot) a) (shiftPointBy (p,rot) b) speed w
|
|
PutAutoDoor a b -> addAutoDoor (shiftPointBy (p,rot) a) (shiftPointBy (p,rot) b) w
|
|
PutBlock (hp:hps) col ps' -> putBlock (map (shiftPointBy (p,rot)) ps') hp col False hps w
|
|
PutBlock{} -> error "messed up block placement somehow"
|
|
PutBtDoor c bp f a b speed
|
|
-> addButtonDoor c (shiftPointBy (p,rot) bp) (f + rot)
|
|
(shiftPointBy (p,rot) a) (shiftPointBy (p,rot) b) speed w
|
|
PutLineBlock wl width depth a b
|
|
-> putLineBlock wl width depth (shiftPointBy (p,rot) a) (shiftPointBy (p,rot) b) w
|
|
PutWall { _pwPoly = ps', _pwWall = wl } -> rmCrossPaths $ over walls (addWalls (q:qs) wl) w
|
|
where
|
|
(q:qs) = map (shiftPointBy (p,rot)) ps'
|
|
rmCrossPaths w' = foldr (uncurry removePathsCrossing) w' $ zip (q:qs) (qs++[q])
|
|
PutForeground sh -> w & foregroundShape %~ ((uncurryV translateSHf p . rotateSH rot) sh <>)
|
|
PutNothing -> w
|
|
PutID _ -> w
|
|
--_ -> w
|
|
where
|
|
p@(V2 px py) = _psPos ps
|
|
p' = V3 px py 0
|
|
rot = _psRot ps
|
|
|
|
-- TODO: remove this typeclass
|
|
class Shiftable a where
|
|
translateS :: Point2 -> a -> a
|
|
rotateS :: Float -> a -> a
|
|
|
|
instance {-# OVERLAPPING #-} Shiftable Point2 where
|
|
translateS = (+.+)
|
|
rotateS = rotateV
|
|
|
|
instance (Shiftable a,Shiftable b) => Shiftable (a, b) where
|
|
translateS p (x,y) = (translateS p x,translateS p y)
|
|
rotateS r (x,y) = ( rotateS r x, rotateS r y)
|
|
|
|
instance (Shiftable a) => Shiftable [a] where
|
|
translateS p x = map (translateS p) x
|
|
rotateS r x = map (rotateS r) x
|
|
|
|
instance Shiftable PlacementSpot where
|
|
translateS p' (PS p r x) = PS (p +.+ p') r x
|
|
rotateS r' (PS p r x) = PS (rotateV r' p) (r + r') x
|
|
|
|
shiftPointBy :: (Point2,Float) -> Point2 -> Point2
|
|
shiftPointBy (pos,rot) p = pos +.+ rotateV rot p
|
|
|
|
addWalls :: [Point2] -> Wall -> IM.IntMap Wall -> IM.IntMap Wall
|
|
addWalls qs wl wls = foldr (addPane wl) wls pairs
|
|
where
|
|
(p:ps) = orderPolygon qs
|
|
pairs = zip (ps ++ [p]) (p:ps)
|
|
|
|
addPane :: Wall -> (Point2,Point2) -> IM.IntMap Wall -> IM.IntMap Wall
|
|
addPane wl (p0,p1) wls = IM.insert (IM.newKey wls) (wl
|
|
{ _wlLine = (p0,p1)
|
|
, _wlID = IM.newKey wls
|
|
})
|
|
wls
|
|
|
|
-- TODO make rotation of props sensible
|
|
placeProp
|
|
:: Prop
|
|
-> Point2
|
|
-> Float -- ^ Rotation
|
|
-> World
|
|
-> World
|
|
placeProp pr p a = over props addProp
|
|
where
|
|
addProp prs = IM.insert (IM.newKey prs) (over pjRot (+a) pr {_pjPos = p, _pjID = IM.newKey prs}) prs
|
|
|
|
placePropID
|
|
:: Prop
|
|
-> Point2
|
|
-> Float -- ^ Rotation
|
|
-> World
|
|
-> (World,Int)
|
|
placePropID pr p a w = (w & props %~ addProp , k)
|
|
where
|
|
k = IM.newKey (_props w)
|
|
addProp prs = IM.insert (IM.newKey prs) (over pjRot (+a) pr {_pjPos = p, _pjID = IM.newKey prs}) prs
|
|
|
|
placeBt
|
|
:: Button
|
|
-> Point2
|
|
-> Float -- ^ Rotation
|
|
-> World
|
|
-> World
|
|
placeBt bt p rot = over buttons addBT
|
|
where
|
|
addBT bts = IM.insert (IM.newKey bts) (bt {_btPos = p, _btRot = rot, _btID = IM.newKey bts}) bts
|
|
{- Creates a floor item at a given point.
|
|
Assigns an id correctly. -}
|
|
placeFlIt
|
|
:: Item
|
|
-> Point2 -- ^ Position
|
|
-> Float -- ^ Rotation
|
|
-> World
|
|
-> World
|
|
placeFlIt itm p rot = floorItems %~
|
|
\ fis -> IM.insert (IM.newKey fis)
|
|
(FlIt
|
|
{ _flItPos = p
|
|
, _flItRot = rot
|
|
, _flItID = IM.newKey fis
|
|
, _flIt = itm
|
|
}
|
|
) fis
|
|
|
|
placePressPlate
|
|
:: PressPlate
|
|
-> Point2
|
|
-> Float -- ^ Rotation
|
|
-> World
|
|
-> World
|
|
placePressPlate pp p rot = over pressPlates addPP
|
|
where
|
|
addPP pps = IM.insert (IM.newKey pps) (pp {_ppPos = p,_ppRot = rot}) pps
|
|
|
|
placeUpdateCr :: Creature -> Point2 -> Float -> World -> (World, PSType)
|
|
placeUpdateCr scr p rot w = (w & creatures %~ IM.insert cid cr, PutCrit cr)
|
|
where
|
|
cid = IM.newKey (_creatures w)
|
|
cr = scr {_crPos = p,_crOldPos = p,_crDir = rot,_crID = cid}
|
|
|
|
placeCr :: Creature -> Point2 -> Float -> World -> World
|
|
placeCr crF p rot = over creatures addCr
|
|
where
|
|
addCr crs = IM.insert
|
|
(IM.newKey crs)
|
|
(crF {_crPos = p,_crOldPos = p,_crDir = rot,_crID = IM.newKey crs})
|
|
crs
|
|
|
|
placeLS :: LightSource -> Picture -> Point3 -> Float -> World -> World
|
|
placeLS ls dec (V3 x y z) rot w = over lightSources addLS $ over decorations addDec w
|
|
where
|
|
startPos = _lsPos ls
|
|
addLS lss = IM.insert
|
|
(IM.newKey lss)
|
|
(ls {_lsPos = V3 x y z +.+.+ startPos,_lsDir = rot,_lsID = IM.newKey lss})
|
|
lss
|
|
addDec decs = IM.insert
|
|
(IM.newKey decs)
|
|
(translate x y $ rotate (negate rot) dec)
|
|
decs
|