about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--Fallen/Map.hs67
-rw-r--r--Fallen/Map/Dungeon.hs0
-rw-r--r--Fallen/Map/Overworld.hs59
-rw-r--r--Fallen/Point.hs58
-rw-r--r--Fallen/Tiles.hs30
-rw-r--r--Fallen/Util.hs8
-rw-r--r--Main.hs48
-rw-r--r--README.md4
8 files changed, 272 insertions, 2 deletions
diff --git a/Fallen/Map.hs b/Fallen/Map.hs new file mode 100644 index 0000000..96c6467 --- /dev/null +++ b/Fallen/Map.hs
@@ -0,0 +1,67 @@
1module Fallen.Map
2( Map,
3 emptyMap,
4 dimension,
5 inBounds,
6 getTileAtPos,
7 findTileInMap,
8 updateMap,
9 legalMoves,
10 fillMapRect
11) where
12 import Fallen.Tiles
13 import Fallen.Point
14 import Data.List
15 import Fallen.Util
16 import Data.Maybe
17
18 data Map = Map {
19 dimension :: (Int, Int),
20 mapdata :: [(Point, Tile)],
21 background :: Tile
22 }
23
24 -- emptyMap :: Int -> Int -> Tile -> Map
25 emptyMap w h t = Map { dimension=(w,h), mapdata=[], background=t }
26
27 -- inBounds :: Map -> Point -> Bool
28 inBounds m (x,y) = let (w,h) = dimension m in (x >= 0) && (x < w) && (y >= 0) && (y < h)
29
30 -- getTileAtPos :: Map -> Point -> Tile
31 --getTileAtPos m p = if (inBounds m p)
32 -- then mapdata m p
33 -- else background m
34 getTileAtPos m p = fromMaybe (background m) $ lookup p $ mapdata m
35
36 -- findTileInMap :: Map -> Tile -> [Point]
37-- findTileInMap m t = filter (\p -> t == mapdata m p) rawPoints where
38-- (w,h) = dimension m
39-- rawPoints = [(x,y) | x <- [0..w-1], y <- [0..h-1]]
40 findTileInMap m t = map fst $ filter ((== t) . snd) $ mapdata m
41
42 -- updateMap updates the tiles at the given position in the map
43 -- if the passed point already exists in the internal array, it is overwritten with the new point
44 -- if the passed tile is the background tile, it removes the tile pair from the internal array
45 -- updateMap :: Point -> Tile -> Map -> Map
46 updateMap p t (Map d xs bg) = if t == bg
47 then Map d (filter ((/= p) . fst) xs) bg
48 else case lookup p xs of
49 Just _ -> Map d (map (\(p1,t1) -> if p1 == p then (p,t) else (p1,t1)) xs) bg
50 Nothing -> Map d ((p,t):xs) bg
51-- updateMap p t (Map d xs bg) = Map d (redirect p t xs) bg where
52-- redirect p t xs = (\p2 -> if p == p2 then t else xs p2)
53
54 -- legalMoves :: Map -> Point -> [Tile] -> [Direction]
55 legalMoves m p ts = map fst $ filter legal $ map tileDir directions where
56 tileDir d = (d, getTileAtPos m $ stepInDirection p d)
57 legal (_,t) = t `elem` ts
58
59 -- fillMapRect :: Int -> Int -> Int -> Int -> Tile -> Map -> Map
60 fillMapRect x y w h t (Map d xs bg) = if bg == t
61 then Map d (filter outBounds xs) bg
62 else Map d (filter outBounds xs ++ [((px,py), t) | px <- [x..x+w-1], py <- [y..y+h-1]]) bg where
63 outBounds ((px,py),_) = (px < x) || (px >= (x+w)) || (py < y) || (py >= (y+h))
64-- fillMapRect x y w h t (Map d xs bg) = Map d redirectInBounds bg where
65-- redirectInBounds = (\p -> if (inBounds p) then t else xs p)
66-- inBounds (px,py) = (px >= x) && (px < (x+w)) && (py >= y) && (py < (y+h))
67 \ No newline at end of file
diff --git a/Fallen/Map/Dungeon.hs b/Fallen/Map/Dungeon.hs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Fallen/Map/Dungeon.hs
diff --git a/Fallen/Map/Overworld.hs b/Fallen/Map/Overworld.hs new file mode 100644 index 0000000..308aad0 --- /dev/null +++ b/Fallen/Map/Overworld.hs
@@ -0,0 +1,59 @@
1module Fallen.Map.Overworld
2( initOverworld
3) where
4 import Fallen.Map
5 import Fallen.Tiles
6 import System.Random
7 import Fallen.Util
8 import Fallen.Point
9
10 -- initOverworld : generate the overworld
11 initOverworld rg = do
12 let m = emptyMap 150 150 Forest -- create map
13 let m' = fillMapRect 0 0 150 150 Grass m -- fill with grass
14 let (tr,rg1) = randomR (1,50) rg :: (Int,StdGen)
15 let (lr,rg2) = randomR (1,50) rg1 :: (Int,StdGen)
16 let (rr,rg3) = randomR (1,50) rg2 :: (Int,StdGen)
17 let (br,rg4) = randomR (1,50) rg3 :: (Int,StdGen)
18 let (m'',rg5) = roughen 150 tr lr rr br rg4 m' -- add surrounding forest
19 let (clumps,rg6) = randomR (30,60) rg5 :: (Int,StdGen)
20 let (m2,rg7) = drawClumps clumps rg6 m''
21 (m2,rg7)
22
23 -- roughen : create the rough forest edges of the overworld
24 roughen 0 _ _ _ _ rg m = (m,rg)
25 roughen w tr lr rr br rg m = do
26 let m' = fillMapRect (w-1) 0 1 tr Forest m
27 let m'' = fillMapRect 0 (w-1) lr 1 Forest m'
28 let m2 = fillMapRect (150-rr-1) (w-1) rr 1 Forest m''
29 let m2' = fillMapRect (w-1) (150-br-1) 1 br Forest m2
30 let (str,rg1) = randomR (-2,2) rg :: (Int,StdGen)
31 let (slr,rg2) = randomR (-2,2) rg1 :: (Int,StdGen)
32 let (srr,rg3) = randomR (-2,2) rg2 :: (Int,StdGen)
33 let (sbr,rg4) = randomR (-2,2) rg3 :: (Int,StdGen)
34 roughen (w-1) (bound tr str) (bound lr slr) (bound rr srr) (bound br sbr) rg4 m2' where
35 bound r s
36 | r + s < 1 = 1
37 | r + s > 50 = 50
38 | otherwise = r + s
39
40 -- drawClumps : add in clumps of rocks, water, and trees
41 clumpTypes = [Rock, Water, Forest]
42 clumpOver = [Rock, Water, Forest, Grass]
43 drawClumps 0 rg m = (m,rg)
44 drawClumps num rg m = do
45 let (area,rg1) = randomR (1,300) rg :: (Int,StdGen)
46 let (clumpType,rg2) = randomSetElement rg1 clumpTypes
47 let (startPoint,rg3) = randomPoint 0 0 149 149 rg2
48 let (m',rg4) = drawClump area clumpType startPoint m rg3
49 drawClumps (num-1) rg4 m'
50 drawClump 0 clumpType p m rg = (updateMap p clumpType m,rg)
51 drawClump area clumpType p m rg = do
52 let m' = updateMap p clumpType m
53 let legalDirs = legalMoves m' p clumpOver
54 if null legalDirs
55 then (m',rg)
56 else do
57 let (nextDir,rg1) = randomSetElement rg legalDirs
58 let nextPoint = stepInDirection p nextDir
59 drawClump (area-1) clumpType nextPoint m' rg1 \ No newline at end of file
diff --git a/Fallen/Point.hs b/Fallen/Point.hs new file mode 100644 index 0000000..321f3b0 --- /dev/null +++ b/Fallen/Point.hs
@@ -0,0 +1,58 @@
1module Fallen.Point
2( Point,
3 Direction(North, South, East, West),
4 directions,
5 distance,
6 stepInDirection,
7 opposite,
8 randomPoint,
9 dirToPoint
10) where
11 import System.Random
12
13 type Point = (Int, Int)
14 data Direction = North | South | East | West deriving (Show)
15
16 -- directions :: [Direction]
17 directions = [North, South, East, West]
18
19 -- distance :: Point -> Point -> Int
20 distance (x1, y1) (x2, y2) = ceiling . sqrt . fromIntegral $ (x1-x2)^2 + (y1-y2)^2
21
22 -- stepInDirection :: Point -> Direction -> Point
23 stepInDirection (x, y) dir = case dir of
24 North -> (x, y-1)
25 South -> (x, y+1)
26 East -> (x+1, y)
27 West -> (x-1, y)
28
29 -- opposite :: Direction -> Direction
30 opposite dir = case dir of
31 North -> South
32 South -> North
33 East -> West
34 West -> East
35
36 -- randomPoint :: Int -> Int -> Int -> Int -> IO Point
37 randomPoint minX minY maxX maxY rg = do
38 let (x,rg1) = randomR (minX, maxX) rg :: (Int,StdGen)
39 let (y,rg2) = randomR (minY, maxY) rg1 :: (Int,StdGen)
40 ((x,y),rg2)
41
42 -- dirToPoint :: Point -> Point -> [Direction]
43 dirToPoint p1 p2 = horizDirToPoint p1 p2 ++ vertDirToPoint p1 p2 where
44 horizDirToPoint (x1,y1) (x2,y2) = case compare x1 x2 of
45 LT -> [East]
46 EQ -> []
47 GT -> [West]
48 vertDirToPoint (x1,y1) (x2,y2) = case compare y1 y2 of
49 LT -> [North]
50 EQ -> []
51 GT -> [South]
52
53 instance Eq Direction where
54 North == North = True
55 South == South = True
56 East == East = True
57 West == West = True
58 _ == _ = False
diff --git a/Fallen/Tiles.hs b/Fallen/Tiles.hs new file mode 100644 index 0000000..e64a650 --- /dev/null +++ b/Fallen/Tiles.hs
@@ -0,0 +1,30 @@
1module Fallen.Tiles
2( Tile(Grass, Earth, Passage, Floor, Forest, Rock, Water),
3 drawTile,
4 passableTiles
5) where
6 import UI.HSCurses.CursesHelper
7
8 data Tile = Grass | Earth | Passage | Floor | Forest | Rock | Water deriving (Show)
9
10 instance Eq Tile where
11 Grass == Grass = True
12 Earth == Earth = True
13 Passage == Passage = True
14 Floor == Floor = True
15 Forest == Forest = True
16 Rock == Rock = True
17 Water == Water = True
18 _ == _ = False
19
20 drawCharWithColor ch color = toEnum $ fromEnum ch
21
22 drawTile Grass = drawCharWithColor '.' GreenF
23 drawTile Earth = drawCharWithColor ' ' BlackF
24 drawTile Passage = drawCharWithColor '.' GreyF
25 drawTile Floor = drawCharWithColor '.' GreyF
26 drawTile Forest = drawCharWithColor '~' GreenF
27 drawTile Rock = drawCharWithColor '*' GreyF
28 drawTile Water = drawCharWithColor '~' BlueF
29
30 passableTiles = [Grass, Passage, Floor] \ No newline at end of file
diff --git a/Fallen/Util.hs b/Fallen/Util.hs new file mode 100644 index 0000000..dd01fff --- /dev/null +++ b/Fallen/Util.hs
@@ -0,0 +1,8 @@
1module Fallen.Util
2( randomSetElement
3) where
4 import System.Random
5
6 randomSetElement rg set = do
7 let (index,rg') = randomR (0,length set - 1) rg :: (Int,StdGen)
8 (set !! index, rg') \ No newline at end of file
diff --git a/Main.hs b/Main.hs new file mode 100644 index 0000000..4908c59 --- /dev/null +++ b/Main.hs
@@ -0,0 +1,48 @@
1module Main where
2 import Fallen.Point
3 import Fallen.Tiles
4 import Fallen.Map
5 import Fallen.Map.Overworld
6 import System.Random
7 import UI.HSCurses.Curses
8
9 -- main :: ()
10 main = do
11 rg <- getStdGen
12 let (m,rg') = initOverworld rg
13 initCurses
14 keypad stdScr True
15 echo False
16 cursSet CursorInvisible
17 startColor
18 mainLoop (75,75) m rg'
19 endWin
20
21 mainLoop player m rg = do
22 render player m
23 input <- getCh
24 case input of
25 KeyLeft -> moveIfPassable player m rg West
26 KeyRight -> moveIfPassable player m rg East
27 KeyUp -> moveIfPassable player m rg North
28 KeyDown -> moveIfPassable player m rg South
29 _ -> putStrLn "endgame"
30
31 moveIfPassable player m rg dir = do
32 let p' = stepInDirection player dir
33 let t' = getTileAtPos m p'
34 if t' `elem` passableTiles
35 then mainLoop p' m rg
36 else mainLoop player m rg
37
38 -- render :: Point -> Map -> Window -> ()
39 render (px,py) m = do
40 (h,w) <- scrSize
41 let viewportX = px - quot w 2
42 let viewportY = py - quot h 2
43 let viewport = [(x,y) | y <- [viewportY..viewportY+h-1], x <- [viewportX..viewportX+w-1]]
44 let drawch = drawTile . getTileAtPos m
45 let viewport_ = map (\p@(x,y) -> (p, drawch p)) viewport
46 mapM_ (\((x,y),ch) -> mvAddCh (y-viewportY) (x-viewportX) ch) viewport_
47 mvAddCh (py-viewportY) (px-viewportX) (toEnum $ fromEnum '@')
48 refresh \ No newline at end of file
diff --git a/README.md b/README.md index 0bfd78c..ff1a6a0 100644 --- a/README.md +++ b/README.md
@@ -1,4 +1,4 @@
1fallen-hs 1The Fallen
2========= 2=========
3 3
4An experimental roguelike written in Haskell \ No newline at end of file 4An experimental roguelike written in Haskell