<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -17,5 +17,5 @@ Executable gp3
     GHC-Options: -Wall
     C-Sources: src/gtk_docker.c
     Includes: src/gtk_docker.h
-    Build-Depends: base, glib, glade, gtk, filepath, unix
+    Build-Depends: base, glib, glade, gtk, filepath, unix, missingh
 </diff>
      <filename>gp3.cabal</filename>
    </modified>
    <modified>
      <diff>@@ -11,6 +11,11 @@ import Control.Concurrent
 import Data.Maybe
 import Data.Array.MArray
 import Data.Word
+import Data.IORef
+import Data.Char
+import Data.String.Utils
+import System.Directory
+import Debug.Trace
 import qualified Data.ByteString.Lazy as B
 
 import qualified BPackReader as BPCK
@@ -18,11 +23,26 @@ import qualified BPackReader as BPCK
 foreign import ccall unsafe &quot;gtk_docker.h do_gnome_init&quot;
       c_gnome_init :: IO ()
 
+#define LEVELS_FOLDER     &quot;levels&quot;
+#define TILESETS_FOLDER   &quot;gfx&quot;
+#define LEVEL_SUFFIX      &quot;.gfb&quot;
+#define TILESET_SUFFIX     &quot;.bmap&quot;
+
 data GUI = GUI {
     mainApp :: Window,
     canvas :: DrawingArea
   }
 
+data MapInfo = MI {
+    tileSetFile :: String,
+    mapFile :: String
+  } deriving (Show)
+
+data MapState = MS {
+    mapList :: [MapInfo],
+    renderedMap :: Pixmap
+  }
+
 {-# INLINE doFromTo #-}
 -- do the action for [from..to], ie it's inclusive.
 doFromTo :: Int -&gt; Int -&gt; (Int -&gt; IO ()) -&gt; IO ()
@@ -84,28 +104,79 @@ createTiledPixmap tileSet tileMap = do
                     totalWidthPixels = tileSizePixels * tilesAcross
                     totalHeightPixels = tileSizePixels * tilesHigh
 
+hasSuffix :: String -&gt; String -&gt; Bool
+hasSuffix suffix = \s -&gt; endswith suffix (map toLower s)
+
+hasPrefix :: String -&gt; String -&gt; Bool
+hasPrefix prefix = \s -&gt; startswith prefix (map toLower s)
+
+-- Gets a list of the tile sets from disk
+getTileSets :: IO [String]
+getTileSets = do 
+           files &lt;- getDirectoryContents TILESETS_FOLDER
+           return $ filter (hasSuffix TILESET_SUFFIX) files
+
+-- Creates MapInfos by matching maps with TileSets
+matchUpFiles :: [String] -&gt; [String] -&gt; [MapInfo]
+matchUpFiles mapFiles tileSets = catMaybes $ map mapToMapInfo mapFiles
+           where mapToMapInfo file = case matchTileSet file of
+                                       Just mapName -&gt; Just $ MI (TILESETS_FOLDER ++ &quot;/&quot; ++ mapName) (LEVELS_FOLDER ++ &quot;/&quot; ++ file)
+                                       Nothing -&gt; Nothing
+                 matchTileSet file = case filter (hasPrefix (map toLower (take 2 file))) tileSets of
+                                       (res:_) -&gt; Just res
+                                       _       -&gt; Nothing
+
+-- Gets a list of Maps / Levels from disk
+getMaps :: IO [MapInfo]
+getMaps = do
+     mapFiles &lt;- getDirectoryContents LEVELS_FOLDER
+     tileSets &lt;- getTileSets
+     return $ matchUpFiles (filter (hasSuffix LEVEL_SUFFIX) mapFiles) tileSets
+
+-- Loads a Pixmap from a MapInfo
+loadPixmap :: MapInfo -&gt; IO (Pixmap)
+loadPixmap info = do
+    tileSet &lt;- BPCK.parseImageFile (tileSetFile info)
+    let justTileSet = fromJust tileSet
+    tileMap &lt;- BPCK.parseMapFile (mapFile info)
+    let justTileMap = fromJust tileMap
+    tiledPixmap &lt;- createTiledPixmap justTileSet justTileMap
+    return tiledPixmap
+
+-- Creates a fresh blank MapState
+newMapState :: IO (MapState)
+newMapState = do
+    allMaps &lt;- getMaps
+    thisMap &lt;- loadPixmap $ head allMaps    
+    return $ MS allMaps thisMap
+
+-- Advances MapState to the next map
+nextMapState :: MapState -&gt; IO (MapState)
+nextMapState state = do
+    let newMapList = (tail oldMapList) ++ [head oldMapList]
+    thisMap &lt;- loadPixmap $ head newMapList
+    return $ MS newMapList thisMap
+    where oldMapList = mapList state
+
 main :: FilePath -&gt; IO ()
 main gladepath = 
   do
     unsafeInitGUIForThreadedRTS
     c_gnome_init
     timeoutAddFull (yield &gt;&gt; return True) priorityDefaultIdle 100
-    tileSet &lt;- BPCK.parseImageFile &quot;gfx/Metallic.bmap&quot;
-    let justTileSet = fromJust tileSet
-    tileMap &lt;- BPCK.parseMapFile &quot;levels/MEMechanoid.GFB&quot;
-    let justTileMap = fromJust tileMap
-    gui &lt;- loadGlade gladepath justTileSet justTileMap
+    mapState &lt;- newMapState
+    mapStateRef &lt;- newIORef mapState
+    gui &lt;- loadGlade gladepath mapStateRef
     connectGui gui
     windowPresent (mainApp gui)
     mainGUI
 
-loadGlade :: String -&gt; BPCK.ParsedImage -&gt; BPCK.ParsedTileMap -&gt; IO GUI
-loadGlade gladepath tileSet tileMap = 
+loadGlade :: String -&gt; IORef (MapState) -&gt; IO GUI
+loadGlade gladepath mapStateRef = 
   do
     Just xml &lt;- xmlNew gladepath
     app &lt;- xmlGetWidget xml castToWindow &quot;MainApp&quot;
     canvas &lt;- xmlGetWidget xml castToDrawingArea &quot;GameCanvas&quot;
-    tiledPixmap &lt;- createTiledPixmap tileSet tileMap
     onExpose canvas (\(Expose {eventRegion = region}) -&gt; do 
                               drawWin &lt;- widgetGetDrawWindow canvas
                               gc &lt;- gcNew drawWin
@@ -113,8 +184,24 @@ loadGlade gladepath tileSet tileMap =
                               dwRegion &lt;- regionRectangle (Rectangle 0 0 width height)
                               regionIntersect region dwRegion
                               rects &lt;- regionGetRectangles region
-                              (flip mapM_) rects (\(Rectangle x y w h) -&gt; postGUIAsync $ drawDrawable drawWin gc tiledPixmap x y x y w h)
+                              mapState &lt;- readIORef mapStateRef
+                              (flip mapM_) rects (\(Rectangle x y w h) -&gt; postGUIAsync $ drawDrawable drawWin gc (renderedMap mapState) x y x y w h)
                               return True)
+    onKeyPress app (\x@(Key { eventKeyName = name,
+                              eventKeyChar = char }) -&gt; do 
+                              case char of
+                                 Just ' ' -&gt; do 
+                                      putStrLn $ &quot;Switching map&quot;
+                                      currentState &lt;- readIORef mapStateRef
+                                      nextState &lt;- nextMapState currentState
+                                      writeIORef mapStateRef nextState
+                                      drawWin &lt;- widgetGetDrawWindow canvas
+                                      gc &lt;- gcNew drawWin
+                                      (width, height) &lt;- drawableGetSize drawWin
+                                      postGUIAsync $ drawDrawable drawWin gc (renderedMap nextState) 0 0 0 0 width height
+                                 Just c  -&gt; putStrLn $ &quot;Press &quot; ++ name ++ &quot;('&quot; ++ [c] ++ &quot;')&quot;
+                                 Nothing -&gt; putStrLn $ &quot;weird key: &quot; ++ name
+                              return (eventSent x))
     return $ GUI app undefined
 
 connectGui gui = </diff>
      <filename>src/GP3GUI.hs</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>8bb6ac73ef986b1bc08a3ca5d12ea46f4901defc</id>
    </parent>
  </parents>
  <author>
    <name>reciva-at</name>
    <email>codders@octomonkey.org.uk</email>
  </author>
  <url>http://github.com/codders/gp3/commit/121ed7f2386d76c8cb525a8c789480bd4bfbd7f0</url>
  <id>121ed7f2386d76c8cb525a8c789480bd4bfbd7f0</id>
  <committed-date>2009-01-04T14:10:54-08:00</committed-date>
  <authored-date>2009-01-04T14:10:54-08:00</authored-date>
  <message>Allow cycling through all maps</message>
  <tree>36d62a09bcb58e997432fbd8f25b09cb40b97143</tree>
  <committer>
    <name>reciva-at</name>
    <email>codders@octomonkey.org.uk</email>
  </committer>
</commit>
