split worldmap into several files, updates, use SDL_Delay earlier to reduce CPU usage...
authorMatthias Braun <matze@braunis.de>
Fri, 14 Apr 2006 14:09:12 +0000 (14:09 +0000)
committerMatthias Braun <matze@braunis.de>
Fri, 14 Apr 2006 14:09:12 +0000 (14:09 +0000)
SVN-Revision: 3338

31 files changed:
data/images/worldmap/common/messagedot.sprite [new file with mode: 0644]
data/images/worldmap/common/teleporter.sprite [deleted file]
data/images/worldmap/common/teleporterdot.sprite
data/levels/bonus1/worldmap.stwm
data/levels/bonus2/worldmap.stwm
data/levels/world1/worldmap.stwm
src/Jamfile
src/game_session.cpp
src/mainloop.cpp
src/misc.cpp
src/resources.cpp
src/resources.hpp
src/scripting/functions.cpp
src/sprite/sprite_manager.cpp
src/sprite/sprite_manager.hpp
src/tile_manager.cpp
src/tile_manager.hpp
src/title.cpp
src/world.cpp
src/worldmap.cpp [deleted file]
src/worldmap.hpp [deleted file]
src/worldmap/level.cpp [new file with mode: 0644]
src/worldmap/level.hpp [new file with mode: 0644]
src/worldmap/special_tile.cpp [new file with mode: 0644]
src/worldmap/special_tile.hpp [new file with mode: 0644]
src/worldmap/sprite_change.cpp [new file with mode: 0644]
src/worldmap/sprite_change.hpp [new file with mode: 0644]
src/worldmap/tux.cpp [new file with mode: 0644]
src/worldmap/tux.hpp [new file with mode: 0644]
src/worldmap/worldmap.cpp [new file with mode: 0644]
src/worldmap/worldmap.hpp [new file with mode: 0644]

diff --git a/data/images/worldmap/common/messagedot.sprite b/data/images/worldmap/common/messagedot.sprite
new file mode 100644 (file)
index 0000000..5d3f13e
--- /dev/null
@@ -0,0 +1,6 @@
+(supertux-sprite
+  (action
+    (name "default")
+    (images "messagedot.png")
+  )
+)
diff --git a/data/images/worldmap/common/teleporter.sprite b/data/images/worldmap/common/teleporter.sprite
deleted file mode 100644 (file)
index 3bf9e05..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-(supertux-sprite
-  (action
-    (name "default")
-    (x-offset 16)
-    (y-offset 16)
-    (fps 3)
-    (images "teleporterdot_1.png"
-           "teleporterdot_2.png"
-           "teleporterdot_3.png"
-           "teleporterdot_4.png"
-       )
-  )
-)
index bc8f230..3bf9e05 100644 (file)
@@ -3,6 +3,11 @@
     (name "default")
     (x-offset 16)
     (y-offset 16)
-    (images "teleporterdot.png")
+    (fps 3)
+    (images "teleporterdot_1.png"
+           "teleporterdot_2.png"
+           "teleporterdot_3.png"
+           "teleporterdot_4.png"
+       )
   )
 )
index 3be2771..cc5a614 100644 (file)
     )
     (special-tile
       (map-message (_ "Hint: Use igloos to get back here."))
+      (invisible-tile #t)
       (passive-message #t)
       (apply-to-direction "north")
       (x 35)
       (map-message (_ "Warp to Matr1x' Sector"))
       (x 33)
       (y 8)
+      (sprite "images/worldmap/common/teleporterdot.sprite")
     )
     (special-tile
       (teleport-to-x 34)
       (map-message (_ "Warp to Thompson's Domain"))
       (x 31)
       (y 8)
+      (sprite "images/worldmap/common/teleporterdot.sprite")
     )
     (special-tile
       (teleport-to-x 51)
       (map-message (_ "Warp to the SuperTux Team Island"))
       (x 35)
       (y 8)
+      (sprite "images/worldmap/common/teleporterdot.sprite")
     )
     (special-tile
       (teleport-to-x 15)
       (map-message (_ "Warp to Abednego's Area"))
       (x 37)
       (y 8)
+      (sprite "images/worldmap/common/teleporterdot.sprite")
     )
     (special-tile
       (teleport-to-x 61)
       (map-message (_ "Warp to Torfi's Territory"))
       (x 39)
       (y 8)
+      (sprite "images/worldmap/common/teleporterdot.sprite")
     )
     (special-tile
       (teleport-to-x 32)
       (map-message (_ "Leave Matrix' Sector"))
       (x 19)
       (y 24)
+      (sprite "images/worldmap/common/teleporterdot.sprite")
     )
     (special-tile
       (teleport-to-x 35)
       (map-message (_ "Leave Thompson's Domain"))
       (x 35)
       (y 26)
+      (sprite "images/worldmap/common/teleporterdot.sprite")
     )
     (special-tile
       (teleport-to-x 35)
       (map-message (_ "Leave SuperTux Team Island"))
       (x 54)
       (y 25)
+      (sprite "images/worldmap/common/teleporterdot.sprite")
     )
     (special-tile
       (teleport-to-x 35)
       (map-message (_ "Leave Abednego's Area"))
       (x 18)
       (y 43)
+      (sprite "images/worldmap/common/teleporterdot.sprite")
     )
     (special-tile
       (teleport-to-x 35)
       (map-message (_ "Leave Torfi's Territory"))
       (x 65)
       (y 43)
+      (sprite "images/worldmap/common/teleporterdot.sprite")
     )
     (special-tile
       (teleport-to-x 35)
       (map-message (_ "Warp home"))
       (x 27)
       (y 39)
+      (sprite "images/worldmap/common/teleporterdot.sprite")
     )
     (special-tile
       (teleport-to-x 35)
index df1c2cb..ab356a1 100644 (file)
@@ -1,7 +1,7 @@
 (supertux-level
-  (name  (_ "Bonus Island II"))
-  (tileset "images/worldmap.strf")
-
+  (version 2)
+  (name (_ "Bonus Island II"))
+  (author "")
   (sector
     (name "main")
     (music "music/salcon.ogg")
       (x 22)
       (y 17)
     )
-    (tilemap 
-      (width  70)
-      (height 40)
-      (layer "interactive")
-      (solid #t)
-      (speed 1.000000)
-      (tiles
-         9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  11 16 16 16 16 16 16 16 16 16 12 9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  15 19 24 25 26 19 24 26 19 19 17 9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  15 19 30 29 28 19 30 28 19 19 17 9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  15 19 19 19 49 50 51 19 24 26 17 9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  15 19 24 26 52 53 54 19 30 28 17 9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  15 19 30 28 55 56 57 43 40 71 17 9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  15 19 19 19 24 25 26 47 24 26 17 9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  15 24 26 19 30 29 28 47 30 28 23 16 16 16 12 9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  11 16 12 9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  11 16 16 16 22 30 28 19 19 19 60 47 60 24 26 19 19 19 17 9  9  9  9  9  9  9  9  9  9  9  11 16 12 9  9  9  9  9  15 19 17 9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  15 48 40 40 40 40 40 40 40 40 40 42 19 30 28 19 19 19 17 9  9  9  9  9  9  9  9  9  9  9  15 19 17 9  9  9  9  9  15 19 23 12 9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  15 47 20 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 13 9  9  11 16 16 16 16 16 12 9  9  15 19 23 12 9  9  11 16 22 24 26 23 12 9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  15 47 17 9  11 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 22 48 40 40 40 39 17 9  9  14 18 18 13 9  9  15 19 19 30 28 19 23 16 16 16 16 16 16 12 9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  15 47 17 9  15 19 48 40 40 40 40 40 40 40 39 19 20 18 18 18 21 19 47 20 18 21 47 17 9  9  9  9  9  9  9  9  14 21 24 25 25 25 25 26 24 25 25 25 26 17 9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  15 47 17 9  14 21 47 19 19 19 58 19 19 19 47 19 17 9  9  9  15 19 47 17 9  15 47 17 9  9  9  9  9  9  9  9  9  15 31 32 32 32 32 27 31 32 32 32 27 17 9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  15 47 17 9  9  15 47 19 19 19 59 19 19 19 47 19 23 12 9  9  15 19 47 17 9  15 47 17 9  9  9  9  9  9  9  9  9  15 31 32 32 32 32 27 31 32 32 32 27 23 12 9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  11 16 16 22 47 23 16 16 22 47 19 19 60 47 60 19 19 47 19 19 17 9  9  15 19 47 17 9  15 47 17 9  9  9  9  9  9  9  9  9  15 30 29 29 29 29 28 30 29 29 29 28 19 23 16 16 12 9  9  9  9  
-         9  9  9  9  9  9  9  9  9  15 48 40 40 45 40 40 40 40 45 40 40 40 45 40 40 40 42 19 19 23 16 16 22 19 47 23 16 22 47 17 9  9  9  9  9  9  9  9  9  15 19 19 60 19 19 60 19 19 60 19 19 24 25 25 26 17 9  9  9  9  
-         9  9  9  9  9  9  9  9  9  15 47 20 21 47 20 18 21 19 47 24 26 19 47 19 19 19 19 19 48 40 40 40 40 40 45 40 40 40 61 64 63 63 63 63 63 63 63 63 63 62 72 40 40 40 40 40 40 40 40 40 71 31 32 32 27 23 12 9  9  9  
-         9  9  9  9  9  9  9  9  9  15 47 17 15 68 17 9  15 19 47 30 28 19 47 20 18 18 21 19 47 19 20 18 18 21 47 19 19 19 47 17 9  9  9  9  9  9  9  9  9  15 24 25 25 25 25 26 24 25 26 24 26 30 29 29 28 19 23 16 16 16 
-         9  9  9  9  9  9  9  9  9  15 47 17 14 18 13 9  15 19 37 39 19 19 47 17 9  9  15 19 47 19 17 9  9  15 47 19 48 40 42 17 9  9  11 16 16 12 9  9  9  15 31 32 32 32 32 27 31 32 27 30 28 69 40 40 40 40 40 40 40 40 
-         9  9  9  9  9  9  9  9  9  15 47 23 16 16 16 12 14 18 21 47 20 21 47 23 16 16 22 19 47 19 23 16 16 22 47 19 47 19 19 17 9  9  15 19 19 17 9  9  9  15 31 32 32 32 32 27 31 32 27 24 25 25 26 20 18 18 18 18 18 18 
-         9  9  9  9  9  9  9  9  9  15 37 40 40 40 39 17 9  9  15 68 17 15 37 40 40 40 40 40 45 40 40 40 40 40 42 19 47 24 26 17 9  9  15 19 20 13 9  9  11 22 31 32 32 32 32 27 31 32 27 31 32 32 27 17 9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  14 18 18 18 21 47 17 9  9  14 18 13 14 18 18 18 18 18 21 47 20 18 18 18 18 21 19 47 30 28 23 12 9  14 18 13 9  9  9  15 19 30 29 29 29 29 28 30 29 28 30 29 29 28 17 9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  11 16 12 9  15 47 23 16 16 16 16 16 16 16 16 16 16 16 22 47 23 16 16 16 16 22 19 47 19 19 19 17 9  9  9  9  9  9  9  14 21 24 26 24 26 20 21 19 20 18 18 18 18 18 13 9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  14 21 17 9  15 37 40 40 40 40 40 40 40 40 40 43 40 40 40 45 40 40 40 40 40 43 40 44 40 39 19 17 9  9  9  9  9  9  9  9  15 30 28 30 28 17 14 18 13 11 16 16 12 9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  14 13 9  14 18 18 18 18 18 18 21 24 26 19 47 19 24 26 47 20 18 18 18 21 47 24 25 26 47 20 13 9  9  9  9  9  9  9  9  14 18 18 18 18 13 9  9  9  15 19 19 17 9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  11 16 12 9  15 30 28 19 47 19 30 28 47 17 11 16 12 15 47 31 32 27 68 17 9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  15 19 20 13 9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  14 18 13 9  14 21 24 26 68 24 26 19 47 17 15 19 17 15 47 31 32 27 60 17 9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  14 18 13 9  9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  15 30 28 19 30 28 19 47 17 14 18 13 15 47 31 32 27 70 17 9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  14 18 21 19 19 19 19 47 17 9  9  9  15 47 30 29 28 47 17 9  9  9  9  9  9  9  9  9  11 16 16 12 9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  14 18 18 18 21 47 23 16 12 9  15 37 40 40 40 61 64 63 63 63 63 63 63 63 63 63 62 67 19 17 9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  15 37 40 39 17 9  14 18 18 18 21 47 17 9  9  9  9  9  9  9  9  9  15 24 26 17 9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  15 20 21 47 23 16 16 16 16 16 22 47 17 9  9  9  9  9  9  9  9  9  15 30 28 17 9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  15 23 22 37 40 40 40 40 40 40 40 42 17 9  9  9  9  9  9  9  9  9  15 19 20 13 9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  15 19 19 19 20 18 18 21 20 18 21 19 17 9  9  9  9  9  9  9  9  9  14 18 13 9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  14 18 18 18 13 9  9  14 13 9  14 18 13 9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  
-         9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9)
-    )
     (level
+      (name "level1.stl")
       (x 18)
       (y 15)
-      (name "level1.stl")
     )
     (level
+      (name "level2.stl")
       (x 26)
       (y 15)
-      (name "level2.stl")
     )
     (level
+      (name "level3.stl")
       (x 13)
       (y 21)
-      (name "level3.stl")
     )
     (level
+      (name "level4.stl")
       (x 19)
       (y 24)
-      (name "level4.stl")
     )
     (level
+      (name "level5.stl")
       (x 28)
       (y 31)
-      (name "level5.stl")
     )
     (level
+      (name "level6.stl")
       (x 34)
       (y 24)
-      (name "level6.stl")
     )
     (level
+      (name "level7.stl")
       (x 38)
       (y 22)
-      (name "level7.stl")
     )
     (level
+      (name "level8.stl")
       (x 17)
       (y 12)
-      (name "level8.stl")
     )
     (level
+      (name "level9.stl")
       (x 34)
       (y 14)
-      (name "level9.stl")
     )
     (level
+      (name "level10.stl")
       (x 36)
       (y 27)
-      (name "level10.stl")
     )
     (level
+      (name "level11.stl")
       (x 21)
       (y 27)
-      (name "level11.stl")
     )
     (level
+      (name "level12.stl")
       (x 34)
       (y 20)
-      (name "level12.stl")
     )
     (level
+      (name "level13.stl")
       (x 13)
       (y 16)
-      (name "level13.stl")
     )
     (level
+      (name "level14.stl")
       (x 28)
       (y 27)
-      (name "level14.stl")
     )
     (level
+      (name "level15.stl")
       (x 14)
       (y 27)
-      (name "level15.stl")
     )
     (level
+      (name "level16.stl")
       (x 23)
       (y 12)
-      (name "level16.stl")
     )
     (level
+      (name "level17.stl")
       (x 22)
       (y 19)
-      (name "level17.stl")
     )
     (level
+      (name "level18.stl")
       (x 24)
       (y 30)
-      (name "level18.stl")
     )
     (level
+      (name "level19.stl")
       (x 50)
       (y 20)
-      (name "level19.stl")
     )
     (level
+      (name "level20.stl")
       (x 21)
       (y 8)
-      (extro-script "
-  display_text_file(\"extro.txt\")
-  ")
-      (name "level20.stl")
     )
     (level
+      (name "level21.stl")
       (x 13)
       (y 12)
-      (name "level21.stl")
     )
     (level
+      (name "level22.stl")
       (x 34)
       (y 29)
-      (name "level22.stl")
     )
     (level
+      (name "level23.stl")
       (x 10)
       (y 22)
-      (name "level23.stl")
     )
     (level
+      (name "level24.stl")
       (x 28)
       (y 20)
-      (name "level24.stl")
     )
     (level
+      (name "level25.stl")
       (x 33)
       (y 36)
-      (name "level25.stl")
     )
     (level
+      (name "level26.stl")
       (x 34)
       (y 33)
-      (name "level26.stl")
     )
     (level
+      (name "level27.stl")
       (x 38)
       (y 14)
-      (name "level27.stl")
     )
     (level
+      (name "level28.stl")
       (x 50)
       (y 33)
-      (name "level28.stl")
     )
     (special-tile
-      (x 60)
-      (y 20)
-      (map-message (_ "I wonder where that path leads to..."))
       (teleport-to-x 25)
       (teleport-to-y 8)
+      (map-message (_ "I wonder where that path leads to..."))
+      (x 60)
+      (y 20)
+      (sprite "images/worldmap/common/teleporterdot.sprite")
     )
     (special-tile
-      (x 25)
-      (y 8)
-      (map-message (_ "Warp home"))
       (teleport-to-x 22)
       (teleport-to-y 17)
+      (map-message (_ "Warp home"))
+      (x 25)
+      (y 8)
+      (sprite "images/worldmap/common/teleporterdot.sprite")
     )
     (special-tile
-      (x 39)
-      (y 20)
       (map-message (_ "You found a secret place!"))
+      (invisible-tile #t)
       (passive-message #t)
       (apply-to-direction "west")
+      (x 39)
+      (y 20)
     )
     (special-tile
-      (x 39)
-      (y 33)
       (map-message (_ "You found a secret place!"))
+      (invisible-tile #t)
       (passive-message #t)
       (apply-to-direction "west")
+      (x 39)
+      (y 33)
+    )
+    (tilemap
+      (layer "interactive")
+      (solid #t)
+      (speed 1)
+      (width 70)
+      (height 40)
+      (tiles 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 11 16 16 16 16 16 16 16 16 16 12 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 15 19 24 25 26 19 24 26 19 19 17 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 15 19 30 29 28 19 30 28 19 19 17 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 15 19 19 19 49 50 51 19 24 26 17 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 15 19 24 26 52 53 54 19 30 28 17 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 15 19 30 28 55 56 57 43 40 71 17 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 15 19 19 19 24 25 26 47 24 26 17 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 15 24 26 19 30 29 28 47 30 28 23 16 16 16 12 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 11 16 12 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 11 16 16 16 22 30 28 19 19 19 60 47 60 24 26 19 19 19 17 9 9 9 9 9 9 9 9 9 9 9 11 16 12 9 9 9 9 9 15 19 17 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 15 48 40 40 40 40 40 40 40 40 40 42 19 30 28 19 19 19 17 9 9 9 9 9 9 9 9 9 9 9 15 19 17 9 9 9 9 9 15 19 23 12 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 15 47 20 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 13 9 9 11 16 16 16 16 16 12 9 9 15 19 23 12 9 9 11 16 22 24 26 23 12 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 15 47 17 9 11 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 22 48 40 40 40 39 17 9 9 14 18 18 13 9 9 15 19 19 30 28 19 23 16 16 16 16 16 16 12 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 15 47 17 9 15 19 48 40 40 40 40 40 40 40 39 19 20 18 18 18 21 19 47 20 18 21 47 17 9 9 9 9 9 9 9 9 14 21 24 25 25 25 25 26 24 25 25 25 26 17 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 15 47 17 9 14 21 47 19 19 19 58 19 19 19 47 19 17 9 9 9 15 19 47 17 9 15 47 17 9 9 9 9 9 9 9 9 9 15 31 32 32 32 32 27 31 32 32 32 27 17 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 15 47 17 9 9 15 47 19 19 19 59 19 19 19 47 19 23 12 9 9 15 19 47 17 9 15 47 17 9 9 9 9 9 9 9 9 9 15 31 32 32 32 32 27 31 32 32 32 27 23 12 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 11 16 16 22 47 23 16 16 22 47 19 19 60 47 60 19 19 47 19 19 17 9 9 15 19 47 17 9 15 47 17 9 9 9 9 9 9 9 9 9 15 30 29 29 29 29 28 30 29 29 29 28 19 23 16 16 12 9 9 9 9 9 9 9 9 9 9 9 9 9 15 48 40 40 45 40 40 40 40 45 40 40 40 45 40 40 40 42 19 19 23 16 16 22 19 47 23 16 22 47 17 9 9 9 9 9 9 9 9 9 15 19 19 60 19 19 60 19 19 60 19 19 24 25 25 26 17 9 9 9 9 9 9 9 9 9 9 9 9 9 15 47 20 21 47 20 18 21 19 47 24 26 19 47 19 19 19 19 19 48 40 40 40 40 40 45 40 40 40 61 64 63 63 63 63 63 63 63 63 63 62 72 40 40 40 40 40 40 40 40 40 71 31 32 32 27 23 12 9 9 9 9 9 9 9 9 9 9 9 9 15 47 17 15 68 17 9 15 19 47 30 28 19 47 20 18 18 21 19 47 19 20 18 18 21 47 19 19 19 47 17 9 9 9 9 9 9 9 9 9 15 24 25 25 25 25 26 24 25 26 24 26 30 29 29 28 19 23 16 16 16 9 9 9 9 9 9 9 9 9 15 47 17 14 18 13 9 15 19 37 39 19 19 47 17 9 9 15 19 47 19 17 9 9 15 47 19 48 40 42 17 9 9 11 16 16 12 9 9 9 15 31 32 32 32 32 27 31 32 27 30 28 69 40 40 40 40 40 40 40 40 9 9 9 9 9 9 9 9 9 15 47 23 16 16 16 12 14 18 21 47 20 21 47 23 16 16 22 19 47 19 23 16 16 22 47 19 47 19 19 17 9 9 15 19 19 17 9 9 9 15 31 32 32 32 32 27 31 32 27 24 25 25 26 20 18 18 18 18 18 18 9 9 9 9 9 9 9 9 9 15 37 40 40 40 39 17 9 9 15 68 17 15 37 40 40 40 40 40 45 40 40 40 40 40 42 19 47 24 26 17 9 9 15 19 20 13 9 9 11 22 31 32 32 32 32 27 31 32 27 31 32 32 27 17 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 14 18 18 18 21 47 17 9 9 14 18 13 14 18 18 18 18 18 21 47 20 18 18 18 18 21 19 47 30 28 23 12 9 14 18 13 9 9 9 15 19 30 29 29 29 29 28 30 29 28 30 29 29 28 17 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 11 16 12 9 15 47 23 16 16 16 16 16 16 16 16 16 16 16 22 47 23 16 16 16 16 22 19 47 19 19 19 17 9 9 9 9 9 9 9 14 21 24 26 24 26 20 21 19 20 18 18 18 18 18 13 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 14 21 17 9 15 37 40 40 40 40 40 40 40 40 40 43 40 40 40 45 40 40 40 40 40 43 40 44 40 39 19 17 9 9 9 9 9 9 9 9 15 30 28 30 28 17 14 18 13 11 16 16 12 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 14 13 9 14 18 18 18 18 18 18 21 24 26 19 47 19 24 26 47 20 18 18 18 21 47 24 25 26 47 20 13 9 9 9 9 9 9 9 9 14 18 18 18 18 13 9 9 9 15 19 19 17 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 11 16 12 9 15 30 28 19 47 19 30 28 47 17 11 16 12 15 47 31 32 27 68 17 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 15 19 20 13 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 14 18 13 9 14 21 24 26 68 24 26 19 47 17 15 19 17 15 47 31 32 27 60 17 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 14 18 13 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 15 30 28 19 30 28 19 47 17 14 18 13 15 47 31 32 27 70 17 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 14 18 21 19 19 19 19 47 17 9 9 9 15 47 30 29 28 47 17 9 9 9 9 9 9 9 9 9 11 16 16 12 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 14 18 18 18 21 47 23 16 12 9 15 37 40 40 40 61 64 63 63 63 63 63 63 63 63 63 62 67 19 17 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 15 37 40 39 17 9 14 18 18 18 21 47 17 9 9 9 9 9 9 9 9 9 15 24 26 17 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 15 20 21 47 23 16 16 16 16 16 22 47 17 9 9 9 9 9 9 9 9 9 15 30 28 17 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 15 23 22 37 40 40 40 40 40 40 40 42 17 9 9 9 9 9 9 9 9 9 15 19 20 13 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 15 19 19 19 20 18 18 21 20 18 21 19 17 9 9 9 9 9 9 9 9 9 14 18 13 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 14 18 18 18 13 9 9 14 13 9 14 18 13 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9)
     )
   )
+  (tileset "images/worldmap.strf")
 )
-
index 2a68ac5..c152d61 100644 (file)
       (teleport-to-y 15)
       (x 16)
       (y 25)
+      (sprite "images/worldmap/common/teleporterdot.sprite")
     )
     (special-tile
       (teleport-to-x 1)
       (teleport-to-y 4)
       (x 1)
       (y 26)
+      (sprite "images/worldmap/common/teleporterdot.sprite")
     )
     (special-tile
       (teleport-to-x 0)
index 38492e8..b1ca0c4 100644 (file)
@@ -18,6 +18,7 @@ sources =
     [ Wildcard tinygettext : *.cpp *.hpp ]
     [ Wildcard trigger : *.cpp *.hpp ]
     [ Wildcard video : *.cpp *.hpp ]
+    [ Wildcard worldmap : *.cpp *.hpp ]
 ;
 TRANSLATABLE_SOURCES += [ SearchSource $(sources) ] ;
 
index 26301fa..1532e39 100644 (file)
@@ -34,7 +34,7 @@
 
 #include "game_session.hpp"
 #include "log.hpp"
-#include "worldmap.hpp"
+#include "worldmap/worldmap.hpp"
 #include "mainloop.hpp"
 #include "video/screen.hpp"
 #include "audio/sound_manager.hpp"
@@ -72,9 +72,7 @@
 // binary fraction...
 static const float LOGICAL_FPS = 64.0;
 
-using namespace WorldMapNS;
-
-GameSession* GameSession::current_ = 0;
+GameSession* GameSession::current_ = NULL;
 
 GameSession::GameSession(const std::string& levelfile_, GameSessionMode mode,
     Statistics* statistics)
@@ -84,7 +82,7 @@ GameSession::GameSession(const std::string& levelfile_, GameSessionMode mode,
     capture_demo_stream(0), playback_demo_stream(0), demo_controller(0)
 {
   current_ = this;
-  currentsector = 0;
+  currentsector = NULL;
   
   game_pause = false;
   fps_fps = 0;
@@ -252,6 +250,7 @@ GameSession::on_escape_press()
     game_menu->set_active_item(MNID_CONTINUE);
     game_pause = true;
   } else {
+    Menu::set_current(NULL);
     game_pause = false;
   }
 }
@@ -560,6 +559,8 @@ GameSession::run()
 void
 GameSession::finish(bool win)
 {
+  using namespace WorldMapNS;
+
   if(win) {
     if(WorldMap::current())
       WorldMap::current()->finished_level(levelfile);
index 523db81..1be0114 100644 (file)
@@ -133,8 +133,8 @@ MainLoop::run()
         /* just wait */
         // If we really have to wait long, then do an imprecise SDL_Delay()
         Uint32 diff = fps_nextframe_ticks - ticks;
-        if(diff > 15) {
-          SDL_Delay(diff - 10);
+        if(diff > 10) {
+          SDL_Delay(diff - 2);
         }
         ticks = SDL_GetTicks();
       }
index 5971a23..2dba5aa 100644 (file)
 #include "audio/sound_manager.hpp"
 #include "title.hpp"
 #include "resources.hpp"
-#include "worldmap.hpp"
+#include "worldmap/worldmap.hpp"
 #include "gettext.hpp"
 #include "options_menu.hpp"
 #include "control/joystickkeyboardcontroller.hpp"
 
-Menu* main_menu      = 0;
-Menu* game_menu      = 0;
+Menu* main_menu      = NULL;
+Menu* game_menu      = NULL;
 
 void setup_menu()
 {
   main_menu      = new Menu();
   game_menu      = new Menu();
-  worldmap_menu  = new Menu();
 
   main_menu->set_pos(SCREEN_WIDTH/2, 335);
   main_menu->add_entry(MNID_STARTGAME, _("Start Game"));
@@ -55,18 +54,10 @@ void setup_menu()
   game_menu->add_submenu(_("Options"), get_options_menu());
   game_menu->add_hl();
   game_menu->add_entry(MNID_ABORTLEVEL, _("Abort Level"));
-
-  worldmap_menu->add_label(_("Pause"));
-  worldmap_menu->add_hl();
-  worldmap_menu->add_entry(WorldMapNS::MNID_RETURNWORLDMAP, _("Continue"));
-  worldmap_menu->add_submenu(_("Options"), get_options_menu());
-  worldmap_menu->add_hl();
-  worldmap_menu->add_entry(WorldMapNS::MNID_QUITWORLDMAP, _("Quit Game"));
 }
 
 void free_menu()
 {
-  delete worldmap_menu;
   delete main_menu;
   delete game_menu;
   free_options_menu();
index 2bf601e..940b0a0 100644 (file)
 #include "object/gameobjs.hpp"
 #include "object/player.hpp"
 
-SpriteManager* sprite_manager = 0;
-TileManager* tile_manager = 0;
-
-MouseCursor* mouse_cursor = 0;
-
-Font* gold_text;
-Font* blue_text;
-Font* gray_text;
-Font* white_text;
-Font* white_small_text;
-Font* white_big_text;                              
-                                   
+MouseCursor* mouse_cursor = NULL;
+
+Font* gold_text = NULL;
+Font* blue_text = NULL;
+Font* gray_text = NULL;
+Font* white_text = NULL;
+Font* white_small_text = NULL;
+Font* white_big_text = NULL;
+
 /* Load graphics/sounds shared between all levels: */
 void load_shared()
 {
@@ -132,9 +129,9 @@ void unload_shared()
   }
 
   delete sprite_manager;
-  sprite_manager = 0;
+  sprite_manager = NULL;
   delete tile_manager;
-  tile_manager = 0;
+  tile_manager = NULL;
 
   /* Free mouse-cursor */
   delete mouse_cursor;
index b8152e5..feaca22 100644 (file)
@@ -28,9 +28,6 @@ class SoundManager;
 class TileManager;
 class MouseCursor;
 
-extern SpriteManager* sprite_manager;
-extern TileManager* tile_manager;
-
 extern Menu* main_menu;
 extern Menu* game_menu;
 
index 9669469..b7a3779 100644 (file)
@@ -34,7 +34,7 @@
 #include "gettext.hpp"
 #include "log.hpp"
 #include "mainloop.hpp"
-#include "worldmap.hpp"
+#include "worldmap/worldmap.hpp"
 #include "world.hpp"
 #include "sector.hpp"
 #include "object/player.hpp"
index 999c254..411255b 100644 (file)
@@ -32,6 +32,8 @@
 #include "file_system.hpp"
 #include "log.hpp"
 
+SpriteManager* sprite_manager = NULL;
+
 SpriteManager::SpriteManager()
 {
 }
index 48dca27..4ebe6c0 100644 (file)
@@ -42,4 +42,6 @@ private:
   SpriteData* load(const std::string& filename);
 };
 
+extern SpriteManager* sprite_manager;
+
 #endif
index d301867..309311e 100644 (file)
@@ -35,6 +35,8 @@
 #include "tile_manager.hpp"
 #include "resources.hpp"
 
+TileManager* tile_manager = NULL;
+
 TileManager::TileManager(const std::string& filename)
 {
 #ifdef DEBUG
index 585b3f8..319b819 100644 (file)
@@ -97,4 +97,6 @@ public:
   }
 };
 
+extern TileManager* tile_manager;
+
 #endif
index 579598c..a688667 100644 (file)
@@ -46,7 +46,7 @@
 #include "level.hpp"
 #include "world.hpp"
 #include "game_session.hpp"
-#include "worldmap.hpp"
+#include "worldmap/worldmap.hpp"
 #include "player_status.hpp"
 #include "tile.hpp"
 #include "sector.hpp"
index 4d9d811..6c3a5fb 100644 (file)
@@ -32,7 +32,7 @@
 #include "scripting/wrapper_util.hpp"
 #include "scripting/serialize.hpp"
 #include "log.hpp"
-#include "worldmap.hpp"
+#include "worldmap/worldmap.hpp"
 #include "mainloop.hpp"
 
 static bool has_suffix(const std::string& data, const std::string& suffix)
diff --git a/src/worldmap.cpp b/src/worldmap.cpp
deleted file mode 100644 (file)
index 0ce2a3e..0000000
+++ /dev/null
@@ -1,1235 +0,0 @@
-//  $Id$
-//
-//  SuperTux -  A Jump'n Run
-//  Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.de>
-//  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#include <config.h>
-
-#include <iostream>
-#include <fstream>
-#include <vector>
-#include <cassert>
-#include <stdexcept>
-#include <sstream>
-#include <unistd.h>
-#include <physfs.h>
-
-#include "worldmap.hpp"
-
-#include "gettext.hpp"
-#include "log.hpp"
-#include "mainloop.hpp"
-#include "video/surface.hpp"
-#include "video/screen.hpp"
-#include "video/drawing_context.hpp"
-#include "sprite/sprite_manager.hpp"
-#include "audio/sound_manager.hpp"
-#include "lisp/parser.hpp"
-#include "lisp/lisp.hpp"
-#include "lisp/list_iterator.hpp"
-#include "lisp/writer.hpp"
-#include "game_session.hpp"
-#include "sector.hpp"
-#include "worldmap.hpp"
-#include "resources.hpp"
-#include "misc.hpp"
-#include "log.hpp"
-#include "world.hpp"
-#include "player_status.hpp"
-#include "textscroller.hpp"
-#include "main.hpp"
-#include "spawn_point.hpp"
-#include "file_system.hpp"
-#include "gui/menu.hpp"
-#include "gui/mousecursor.hpp"
-#include "control/joystickkeyboardcontroller.hpp"
-#include "object/background.hpp"
-#include "object/tilemap.hpp"
-#include "scripting/squirrel_error.hpp"
-#include "scripting/wrapper_util.hpp"
-
-Menu* worldmap_menu  = 0;
-
-static const float TUXSPEED = 200;
-static const float map_message_TIME = 2.8;
-
-namespace WorldMapNS {
-
-WorldMap* WorldMap::current_ = NULL;
-
-Direction reverse_dir(Direction direction)
-{
-  switch(direction)
-    {
-    case D_WEST:
-      return D_EAST;
-    case D_EAST:
-      return D_WEST;
-    case D_NORTH:
-      return D_SOUTH;
-    case D_SOUTH:
-      return D_NORTH;
-    case D_NONE:
-      return D_NONE;
-    }
-  return D_NONE;
-}
-
-std::string
-direction_to_string(Direction direction)
-{
-  switch(direction)
-    {
-    case D_WEST:
-      return "west";
-    case D_EAST:
-      return "east";
-    case D_NORTH:
-      return "north";
-    case D_SOUTH:
-      return "south";
-    default:
-      return "none";
-    }
-}
-
-Direction
-string_to_direction(const std::string& directory)
-{
-  if (directory == "west")
-    return D_WEST;
-  else if (directory == "east")
-    return D_EAST;
-  else if (directory == "north")
-    return D_NORTH;
-  else if (directory == "south")
-    return D_SOUTH;
-  else
-    return D_NONE;
-}
-
-//---------------------------------------------------------------------------
-
-Tux::Tux(WorldMap* worldmap_)
-  : worldmap(worldmap_)
-{
-  tux_sprite = sprite_manager->create("images/worldmap/common/tux.sprite");
-  
-  offset = 0;
-  moving = false;
-  direction = D_NONE;
-  input_direction = D_NONE;
-}
-
-Tux::~Tux()
-{
-  delete tux_sprite;
-}
-
-void
-Tux::draw(DrawingContext& context)
-{
-  switch (player_status->bonus) {
-    case GROWUP_BONUS:
-      tux_sprite->set_action(moving ? "large-walking" : "large-stop");
-      break;
-    case FIRE_BONUS:
-      tux_sprite->set_action(moving ? "fire-walking" : "fire-stop");
-      break;
-    case NO_BONUS:
-      tux_sprite->set_action(moving ? "small-walking" : "small-stop");
-      break;
-    default:
-      log_debug << "Bonus type not handled in worldmap." << std::endl;
-      tux_sprite->set_action("large-stop");
-      break;
-  }
-
-  tux_sprite->draw(context, get_pos(), LAYER_OBJECTS);
-}
-
-
-Vector
-Tux::get_pos()
-{
-  float x = tile_pos.x * 32;
-  float y = tile_pos.y * 32;
-
-  switch(direction)
-    {
-    case D_WEST:
-      x -= offset - 32;
-      break;
-    case D_EAST:
-      x += offset - 32;
-      break;
-    case D_NORTH:
-      y -= offset - 32;
-      break;
-    case D_SOUTH:
-      y += offset - 32;
-      break;
-    case D_NONE:
-      break;
-    }
-  
-  return Vector(x, y);
-}
-
-void
-Tux::stop()
-{
-  offset = 0;
-  direction = D_NONE;
-  input_direction = D_NONE;
-  moving = false;
-}
-
-void
-Tux::set_direction(Direction dir)
-{
-  input_direction = dir;
-}
-
-void 
-Tux::tryStartWalking() 
-{
-  if (moving) return;
-  if (input_direction == D_NONE) return;
-
-  WorldMap::Level* level = worldmap->at_level();
-
-  // We got a new direction, so lets start walking when possible
-  Vector next_tile;
-  if ((!level || level->solved) && worldmap->path_ok(input_direction, tile_pos, &next_tile))
-  {
-    tile_pos = next_tile;
-    moving = true;
-    direction = input_direction;
-    back_direction = reverse_dir(direction);
-  }
-  else if (input_direction == back_direction)
-  {
-    moving = true;
-    direction = input_direction;
-    tile_pos = worldmap->get_next_tile(tile_pos, direction);
-    back_direction = reverse_dir(direction);
-  }
-
-}
-
-bool 
-Tux::canWalk(const Tile* tile, Direction dir)
-{
-  return ((tile->getData() & Tile::WORLDMAP_NORTH && dir == D_NORTH) ||
-         (tile->getData() & Tile::WORLDMAP_SOUTH && dir == D_SOUTH) ||
-         (tile->getData() & Tile::WORLDMAP_EAST && dir == D_EAST) ||
-         (tile->getData() & Tile::WORLDMAP_WEST && dir == D_WEST));
-}
-
-void 
-Tux::tryContinueWalking(float elapsed_time)
-{
-  if (!moving) return;
-
-  // Let tux walk
-  offset += TUXSPEED * elapsed_time;
-
-  // Do nothing if we have not yet reached the next tile
-  if (offset <= 32) return;
-
-  offset -= 32;
-
-  // if this is a special_tile with passive_message, display it
-  WorldMap::SpecialTile* special_tile = worldmap->at_special_tile();
-  if(special_tile && special_tile->passive_message)
-  {  
-    // direction and the apply_action_ are opposites, since they "see"
-    // directions in a different way
-    if((direction == D_NORTH && special_tile->apply_action_south) ||
-                   (direction == D_SOUTH && special_tile->apply_action_north) ||
-                   (direction == D_WEST && special_tile->apply_action_east) ||
-                   (direction == D_EAST && special_tile->apply_action_west))
-    {
-      worldmap->passive_message = special_tile->map_message;
-      worldmap->passive_message_timer.start(map_message_TIME);
-    }
-  }
-
-  // stop if we reached a level, a WORLDMAP_STOP tile or a special tile without a passive_message
-  if ((worldmap->at_level()) || (worldmap->at(tile_pos)->getData() & Tile::WORLDMAP_STOP) || (special_tile && !special_tile->passive_message))
-  {
-    if(special_tile && !special_tile->map_message.empty() && !special_tile->passive_message) worldmap->passive_message_timer.start(0);
-    stop();
-    return;
-  }
-
-  // if user wants to change direction, try changing, else guess the direction in which to walk next
-  const Tile* tile = worldmap->at(tile_pos);
-  if (direction != input_direction)
-  { 
-    if(canWalk(tile, input_direction))
-    {  
-      direction = input_direction;
-      back_direction = reverse_dir(direction);
-    }
-  }
-  else
-  {
-    Direction dir = D_NONE;
-    if (tile->getData() & Tile::WORLDMAP_NORTH && back_direction != D_NORTH) dir = D_NORTH;
-    else if (tile->getData() & Tile::WORLDMAP_SOUTH && back_direction != D_SOUTH) dir = D_SOUTH;
-    else if (tile->getData() & Tile::WORLDMAP_EAST && back_direction != D_EAST) dir = D_EAST;
-    else if (tile->getData() & Tile::WORLDMAP_WEST && back_direction != D_WEST) dir = D_WEST;
-
-    if (dir == D_NONE) 
-    {
-      // Should never be reached if tiledata is good
-      log_warning << "Could not determine where to walk next" << std::endl;
-      stop();
-      return;
-    }
-
-    direction = dir;
-    input_direction = direction;
-    back_direction = reverse_dir(direction);
-  }
-
-  // Walk automatically to the next tile
-  if(direction != D_NONE)
-  {
-    Vector next_tile;
-    if (worldmap->path_ok(direction, tile_pos, &next_tile))
-    {
-      tile_pos = next_tile;
-    }
-    else
-    {
-      log_warning << "Tilemap data is buggy" << std::endl;
-      stop();
-    }
-  }
-}
-
-void
-Tux::updateInputDirection()
-{
-  if(main_controller->hold(Controller::UP)) input_direction = D_NORTH;
-  else if(main_controller->hold(Controller::DOWN)) input_direction = D_SOUTH;
-  else if(main_controller->hold(Controller::LEFT)) input_direction = D_WEST;
-  else if(main_controller->hold(Controller::RIGHT)) input_direction = D_EAST;
-}
-
-
-void
-Tux::update(float elapsed_time)
-{
-  updateInputDirection(); 
-  if (moving) tryContinueWalking(elapsed_time); else tryStartWalking();
-}
-
-//---------------------------------------------------------------------------
-
-WorldMap::WorldMap()
-  : tux(0), solids(0)
-{
-  tile_manager = new TileManager("images/worldmap.strf");
-  
-  tux = new Tux(this);
-  add_object(tux);
-    
-  messagedot = new Surface("images/worldmap/common/messagedot.png");
-  teleporterdot = sprite_manager->create("images/worldmap/common/teleporter.sprite");
-
-  name = "<no title>";
-  music = "music/salcon.ogg";
-  intro_displayed = false;
-
-  total_stats.reset();
-}
-
-WorldMap::~WorldMap()
-{
-  if(current_ == this)
-    current_ = NULL;
-
-  clear_objects();
-  for(SpawnPoints::iterator i = spawn_points.begin();
-      i != spawn_points.end(); ++i) {
-    delete *i;
-  }
-  for(Levels::iterator i = levels.begin(); i != levels.end(); ++i) {
-    Level& level = *i;
-    delete level.sprite;
-  }
-  for(SpecialTiles::iterator i = special_tiles.begin(); i != special_tiles.end(); ++i) {
-    delete i->sprite;
-  }
-  
-  delete tile_manager;
-
-  delete messagedot;
-  delete teleporterdot;
-}
-
-void
-WorldMap::add_object(GameObject* object)
-{
-  TileMap* tilemap = dynamic_cast<TileMap*> (object);
-  if(tilemap != 0 && tilemap->is_solid()) {
-    solids = tilemap;
-  }
-
-  game_objects.push_back(object);
-}
-
-void
-WorldMap::clear_objects()
-{
-  for(GameObjects::iterator i = game_objects.begin();
-      i != game_objects.end(); ++i)
-    delete *i;
-  game_objects.clear();
-  solids = 0;
-  tux = new Tux(this);
-  add_object(tux);
-}
-
-// Don't forget to set map_filename before calling this
-void
-WorldMap::load_map()
-{
-  levels_path = FileSystem::dirname(map_filename);
-
-  try {
-    lisp::Parser parser;
-    std::auto_ptr<lisp::Lisp> root (parser.parse(map_filename));
-
-    const lisp::Lisp* lisp = root->get_lisp("supertux-level");
-    if(!lisp)
-      throw std::runtime_error("file isn't a supertux-level file.");
-
-    lisp->get("name", name);
-    
-    const lisp::Lisp* sector = lisp->get_lisp("sector");
-    if(!sector)
-      throw std::runtime_error("No sector sepcified in worldmap file.");
-    
-    clear_objects();
-    lisp::ListIterator iter(sector);
-    while(iter.next()) {
-      if(iter.item() == "tilemap") {
-        add_object(new TileMap(*(iter.lisp()), tile_manager));
-      } else if(iter.item() == "background") {
-        add_object(new Background(*(iter.lisp())));
-      } else if(iter.item() == "music") {
-        iter.value()->get(music);
-      } else if(iter.item() == "intro-script") {
-        iter.value()->get(intro_script);
-      } else if(iter.item() == "worldmap-spawnpoint") {
-        SpawnPoint* sp = new SpawnPoint(iter.lisp());
-        spawn_points.push_back(sp);
-      } else if(iter.item() == "level") {
-        parse_level_tile(iter.lisp());
-      } else if(iter.item() == "special-tile") {
-        parse_special_tile(iter.lisp());
-      } else if(iter.item() == "name") {
-        // skip
-      } else {
-        log_warning << "Unknown token '" << iter.item() << "' in worldmap" << std::endl;
-      }
-    }
-    if(solids == 0)
-      throw std::runtime_error("No solid tilemap specified");
-
-    // search for main spawnpoint
-    for(SpawnPoints::iterator i = spawn_points.begin();
-        i != spawn_points.end(); ++i) {
-      SpawnPoint* sp = *i;
-      if(sp->name == "main") {
-        Vector p = sp->pos;
-        tux->set_tile_pos(p);
-        break;
-      }
-    }
-
-  } catch(std::exception& e) {
-    std::stringstream msg;
-    msg << "Problem when parsing worldmap '" << map_filename << "': " <<
-      e.what();
-    throw std::runtime_error(msg.str());
-  }
-}
-
-void
-WorldMap::parse_special_tile(const lisp::Lisp* lisp)
-{
-  SpecialTile special_tile;
-  
-  lisp->get("x", special_tile.pos.x);
-  lisp->get("y", special_tile.pos.y);
-
-  std::string sprite;
-  if (lisp->get("sprite", sprite)) {
-    special_tile.sprite = sprite_manager->create(sprite);
-  } else {
-    special_tile.sprite = 0;
-  }
-
-  lisp->get("map-message", special_tile.map_message);
-  special_tile.passive_message = false;
-  lisp->get("passive-message", special_tile.passive_message);
-  special_tile.teleport_dest = Vector(-1,-1);
-  lisp->get("teleport-to-x", special_tile.teleport_dest.x);
-  lisp->get("teleport-to-y", special_tile.teleport_dest.y);
-  special_tile.invisible = false;
-  lisp->get("invisible-tile", special_tile.invisible);
-
-  special_tile.apply_action_north = true;
-  special_tile.apply_action_south = true;
-  special_tile.apply_action_east = true;
-  special_tile.apply_action_west = true;
-
-  std::string apply_direction;
-  lisp->get("apply-to-direction", apply_direction);
-  if(!apply_direction.empty()) {
-    special_tile.apply_action_north = false;
-    special_tile.apply_action_south = false;
-    special_tile.apply_action_east = false;
-    special_tile.apply_action_west = false;
-    if(apply_direction.find("north") != std::string::npos)
-      special_tile.apply_action_north = true;
-    if(apply_direction.find("south") != std::string::npos)
-      special_tile.apply_action_south = true;
-    if(apply_direction.find("east") != std::string::npos)
-      special_tile.apply_action_east = true;
-    if(apply_direction.find("west") != std::string::npos)
-      special_tile.apply_action_west = true;
-  }
-  
-  special_tiles.push_back(special_tile);
-}
-
-void
-WorldMap::parse_level_tile(const lisp::Lisp* level_lisp)
-{
-  Level level;
-
-  level.solved = false;
-                  
-  level.north = true;
-  level.east  = true;
-  level.south = true;
-  level.west  = true;
-
-  std::string sprite = "images/worldmap/common/leveldot.sprite";
-  level_lisp->get("sprite", sprite);
-  level.sprite = sprite_manager->create(sprite);
-
-  level_lisp->get("extro-script", level.extro_script);
-  level_lisp->get("next-worldmap", level.next_worldmap);
-
-  level.quit_worldmap = false;
-  level_lisp->get("quit-worldmap", level.quit_worldmap);
-
-  level_lisp->get("name", level.name);
-  
-  if (!PHYSFS_exists((levels_path + level.name).c_str()))
-  {
-       // Do we want to bail out instead...? We might get messages from modders
-       // who can't make their levels run because they're too dumb to watch
-       // their terminals...
-    log_warning << "level file '" << level.name << "' does not exist and will not be added to the worldmap" << std::endl;
-    return;
-  }
-
-  level_lisp->get("x", level.pos.x);
-  level_lisp->get("y", level.pos.y);
-
-  level.auto_path = true;
-  level_lisp->get("auto-path", level.auto_path);
-
-  level.vertical_flip = false;
-  level_lisp->get("vertical-flip", level.vertical_flip);
-
-  levels.push_back(level);
-}
-
-void
-WorldMap::get_level_title(Level& level)
-{
-  /** get special_tile's title */
-  level.title = "<no title>";
-
-  try {
-    lisp::Parser parser;
-    std::auto_ptr<lisp::Lisp> root (parser.parse(levels_path + level.name));
-
-    const lisp::Lisp* level_lisp = root->get_lisp("supertux-level");
-    if(!level_lisp)
-      return;
-    
-    level_lisp->get("name", level.title);
-  } catch(std::exception& e) {
-    log_warning << "Problem when reading leveltitle: " << e.what() << std::endl;
-    return;
-  }
-}
-
-void WorldMap::calculate_total_stats()
-{
-  total_stats.reset();
-  for(Levels::iterator i = levels.begin(); i != levels.end(); ++i)
-    {
-    if (i->solved)
-      {
-      total_stats += i->statistics;
-      }
-    }
-}
-
-void
-WorldMap::on_escape_press()
-{
-  // Show or hide the menu
-  if(!Menu::current()) {
-    Menu::set_current(worldmap_menu);
-    tux->set_direction(D_NONE);  // stop tux movement when menu is called
-  } else {
-    Menu::set_current(0);
-  }
-}
-
-Vector
-WorldMap::get_next_tile(Vector pos, Direction direction)
-{
-  switch(direction) {
-    case D_WEST:
-      pos.x -= 1;
-      break;
-    case D_EAST:
-      pos.x += 1;
-      break;
-    case D_NORTH:
-      pos.y -= 1;
-      break;
-    case D_SOUTH:
-      pos.y += 1;
-      break;
-    case D_NONE:
-      break;
-  }
-  return pos;
-}
-
-bool
-WorldMap::path_ok(Direction direction, Vector old_pos, Vector* new_pos)
-{
-  *new_pos = get_next_tile(old_pos, direction);
-
-  if (!(new_pos->x >= 0 && new_pos->x < solids->get_width()
-        && new_pos->y >= 0 && new_pos->y < solids->get_height()))
-    { // New position is outsite the tilemap
-      return false;
-    }
-  else
-    { // Check if the tile allows us to go to new_pos
-      switch(direction)
-        {
-        case D_WEST:
-          return (at(old_pos)->getData() & Tile::WORLDMAP_WEST
-              && at(*new_pos)->getData() & Tile::WORLDMAP_EAST);
-
-        case D_EAST:
-          return (at(old_pos)->getData() & Tile::WORLDMAP_EAST
-              && at(*new_pos)->getData() & Tile::WORLDMAP_WEST);
-
-        case D_NORTH:
-          return (at(old_pos)->getData() & Tile::WORLDMAP_NORTH
-              && at(*new_pos)->getData() & Tile::WORLDMAP_SOUTH);
-
-        case D_SOUTH:
-          return (at(old_pos)->getData() & Tile::WORLDMAP_SOUTH
-              && at(*new_pos)->getData() & Tile::WORLDMAP_NORTH);
-
-        case D_NONE:
-          assert(!"path_ok() can't work if direction is NONE");
-        }
-      return false;
-    }
-}
-
-void
-WorldMap::finished_level(const std::string& filename)
-{
-  // TODO calculate level from filename?
-  (void) filename;
-  Level* level = at_level();
-
-  bool old_level_state = level->solved;
-  level->solved = true;
-  level->sprite->set_action("solved");
-
-  // deal with statistics
-  level->statistics.merge(global_stats);
-  calculate_total_stats();
-
-  save_state();
-  if(World::current() != NULL)
-    World::current()->save_state();
-
-  if (old_level_state != level->solved && level->auto_path) {
-    // Try to detect the next direction to which we should walk
-    // FIXME: Mostly a hack
-    Direction dir = D_NONE;
-  
-    const Tile* tile = at(tux->get_tile_pos());
-
-    // first, test for crossroads
-    if (tile->getData() & Tile::WORLDMAP_CNSE || tile->getData() && Tile::WORLDMAP_CNSW
-     || tile->getData() & Tile::WORLDMAP_CNEW || tile->getData() && Tile::WORLDMAP_CSEW
-     || tile->getData() & Tile::WORLDMAP_CNSEW)
-      dir = D_NONE;
-    else if (tile->getData() & Tile::WORLDMAP_NORTH
-        && tux->back_direction != D_NORTH)
-      dir = D_NORTH;
-    else if (tile->getData() & Tile::WORLDMAP_SOUTH
-        && tux->back_direction != D_SOUTH)
-      dir = D_SOUTH;
-    else if (tile->getData() & Tile::WORLDMAP_EAST
-        && tux->back_direction != D_EAST)
-      dir = D_EAST;
-    else if (tile->getData() & Tile::WORLDMAP_WEST
-        && tux->back_direction != D_WEST)
-      dir = D_WEST;
-
-    if (dir != D_NONE) {
-      tux->set_direction(dir);
-    }
-  }
-
-  if (level->extro_script != "") {
-    /* TODO
-    try {
-      std::auto_ptr<ScriptInterpreter> interpreter
-        (new ScriptInterpreter(levels_path));
-      std::istringstream in(level->extro_script);
-      interpreter->run_script(in, "level-extro-script");
-      add_object(interpreter.release());
-    } catch(std::exception& e) {
-      log_fatal << "Couldn't run level-extro-script:" << e.what() << std::endl;
-    }
-    */
-  }
-  
-  if (!level->next_worldmap.empty()) {
-    // Load given worldmap
-    loadmap(level->next_worldmap);
-  }
-  
-  if (level->quit_worldmap)
-    main_loop->exit_screen();
-}
-
-void
-WorldMap::update(float delta)
-{
-  Menu* menu = Menu::current();
-  if(menu) {
-    menu->update();
-
-    if(menu == worldmap_menu) {
-      switch (worldmap_menu->check())
-      {
-        case MNID_RETURNWORLDMAP: // Return to game  
-          Menu::set_current(0);
-          break;
-        case MNID_QUITWORLDMAP: // Quit Worldmap
-          main_loop->exit_screen();
-          break;
-      }
-    }
-
-    return;
-  }
-
-  // update GameObjects
-  for(GameObjects::iterator i = game_objects.begin();
-      i != game_objects.end(); ++i) {
-    GameObject* object = *i;
-    object->update(delta);
-  }
-
-  // remove old GameObjects
-  for(GameObjects::iterator i = game_objects.begin();
-      i != game_objects.end(); ) {
-    GameObject* object = *i;
-    if(!object->is_valid()) {
-      delete object;
-      i = game_objects.erase(i);
-    } else {
-      ++i;
-    }
-  }
-
-  // position "camera"
-  Vector tux_pos = tux->get_pos();
-  camera_offset.x = tux_pos.x - SCREEN_WIDTH/2;
-  camera_offset.y = tux_pos.y - SCREEN_HEIGHT/2;
-
-  if (camera_offset.x < 0)
-    camera_offset.x = 0;
-  if (camera_offset.y < 0)
-    camera_offset.y = 0;
-
-  if (camera_offset.x > solids->get_width()*32 - SCREEN_WIDTH)
-    camera_offset.x = solids->get_width()*32 - SCREEN_WIDTH;
-  if (camera_offset.y > solids->get_height()*32 - SCREEN_HEIGHT)
-    camera_offset.y = solids->get_height()*32 - SCREEN_HEIGHT;
-
-  // handle input
-  bool enter_level = false;
-  if(main_controller->pressed(Controller::ACTION)
-      || main_controller->pressed(Controller::JUMP)
-      || main_controller->pressed(Controller::MENU_SELECT))
-    enter_level = true;
-  if(main_controller->pressed(Controller::PAUSE_MENU))
-    on_escape_press();
-  
-  if (enter_level && !tux->is_moving())
-    {
-      /* Check special tile action */
-      SpecialTile* special_tile = at_special_tile();
-      if(special_tile)
-        {
-        if (special_tile->teleport_dest != Vector(-1,-1))
-          {
-          // TODO: an animation, camera scrolling or a fading would be a nice touch
-          sound_manager->play("sounds/warp.wav");
-          tux->back_direction = D_NONE;
-          tux->set_tile_pos(special_tile->teleport_dest);
-          SDL_Delay(1000);
-          }
-        }
-
-      /* Check level action */
-      Level* level = at_level();
-      if (!level) {
-        log_warning << "No level to enter at: " << tux->get_tile_pos().x << ", " << tux->get_tile_pos().y << std::endl;
-        return;
-      }
-
-      if (level->pos == tux->get_tile_pos()) {
-        // do a shriking fade to the level
-        shrink_fade(Vector((level->pos.x*32 + 16 + offset.x),
-                           (level->pos.y*32 + 16 + offset.y)), 500);
-
-        try {
-          GameSession *session =
-            new GameSession(levels_path + level->name,
-                ST_GL_LOAD_LEVEL_FILE, &level->statistics);
-          main_loop->push_screen(session);
-        } catch(std::exception& e) {
-          log_fatal << "Couldn't load level: " << e.what() << std::endl;
-        }
-      }
-    }
-  else
-    {
-//      tux->set_direction(input_direction);
-    }
-}
-
-const Tile*
-WorldMap::at(Vector p)
-{
-  return solids->get_tile((int) p.x, (int) p.y);
-}
-
-WorldMap::Level*
-WorldMap::at_level()
-{
-  for(Levels::iterator i = levels.begin(); i != levels.end(); ++i)
-    {
-      if (i->pos == tux->get_tile_pos())
-        return &*i; 
-    }
-
-  return 0;
-}
-
-WorldMap::SpecialTile*
-WorldMap::at_special_tile()
-{
-  for(SpecialTiles::iterator i = special_tiles.begin(); i != special_tiles.end(); ++i)
-    {
-      if (i->pos == tux->get_tile_pos())
-        return &*i; 
-    }
-
-  return 0;
-}
-
-void
-WorldMap::draw(DrawingContext& context)
-{
-  context.push_transform();
-  context.set_translation(camera_offset);
-  
-  for(GameObjects::iterator i = game_objects.begin();
-      i != game_objects.end(); ++i) {
-    GameObject* object = *i;
-    object->draw(context);
-  }
-  
-  for(Levels::iterator i = levels.begin(); i != levels.end(); ++i)
-    {
-      const Level& level = *i;
-      level.sprite->draw(context, level.pos*32 + Vector(16, 16), LAYER_TILES+1);
-    }
-
-  for(SpecialTiles::iterator i = special_tiles.begin(); i != special_tiles.end(); ++i)
-    {
-      if(i->invisible)
-        continue;
-
-      if (i->sprite)
-       i->sprite->draw(context, i->pos*32 + Vector(16, 16), LAYER_TILES+1);
-
-      else if (i->teleport_dest != Vector(-1, -1))
-       teleporterdot->draw(context, i->pos*32 + Vector(16, 16), LAYER_TILES+1);
-
-      else if (!i->map_message.empty() && !i->passive_message)
-        context.draw_surface(messagedot,
-                Vector(i->pos.x*32, i->pos.y*32), LAYER_TILES+1);
-    }
-
-  draw_status(context);
-  context.pop_transform();
-}
-
-void
-WorldMap::draw_status(DrawingContext& context)
-{
-  context.push_transform();
-  context.set_translation(Vector(0, 0));
-  player_status->draw(context);
-
-  if (!tux->is_moving())
-    {
-      for(Levels::iterator i = levels.begin(); i != levels.end(); ++i)
-        {
-          if (i->pos == tux->get_tile_pos())
-            {
-              if(i->title == "")
-                get_level_title(*i);
-
-              context.draw_text(white_text, i->title, 
-                  Vector(SCREEN_WIDTH/2,
-                         SCREEN_HEIGHT - white_text->get_height() - 30),
-                  CENTER_ALLIGN, LAYER_FOREGROUND1);
-
-              i->statistics.draw_worldmap_info(context);
-              break;
-            }
-        }
-      for(SpecialTiles::iterator i = special_tiles.begin(); i != special_tiles.end(); ++i)
-        {
-          if (i->pos == tux->get_tile_pos())
-            {
-               /* Display an in-map message in the map, if any as been selected */
-              if(!i->map_message.empty() && !i->passive_message)
-                context.draw_text(gold_text, i->map_message, 
-                    Vector(SCREEN_WIDTH/2,
-                           SCREEN_HEIGHT - white_text->get_height() - 60),
-                    CENTER_ALLIGN, LAYER_FOREGROUND1);
-              break;
-            }
-        }
-    }
-  /* Display a passive message in the map, if needed */
-  if(passive_message_timer.started())
-    context.draw_text(gold_text, passive_message, 
-            Vector(SCREEN_WIDTH/2, SCREEN_HEIGHT - white_text->get_height() - 60),
-            CENTER_ALLIGN, LAYER_FOREGROUND1);
-
-  context.pop_transform();
-}
-
-void
-WorldMap::setup()
-{
-  sound_manager->play_music(music);
-  Menu::set_current(NULL);
-
-  current_ = this;
-  load_state();
-}
-
-static void store_float(HSQUIRRELVM vm, const char* name, float val)
-{
-  sq_pushstring(vm, name, -1);
-  sq_pushfloat(vm, val);
-  if(SQ_FAILED(sq_createslot(vm, -3)))
-    throw Scripting::SquirrelError(vm, "Couldn't add float value to table");
-}
-
-/*
-static void store_int(HSQUIRRELVM vm, const char* name, int val)
-{
-  sq_pushstring(vm, name, -1);
-  sq_pushinteger(vm, val);
-  if(SQ_FAILED(sq_createslot(vm, -3)))
-    throw Scripting::SquirrelError(vm, "Couldn't add float value to table");
-}
-*/
-
-static void store_string(HSQUIRRELVM vm, const char* name, const std::string& val)
-{
-  sq_pushstring(vm, name, -1);
-  sq_pushstring(vm, val.c_str(), val.length());
-  if(SQ_FAILED(sq_createslot(vm, -3)))
-    throw Scripting::SquirrelError(vm, "Couldn't add float value to table");
-}
-
-static void store_bool(HSQUIRRELVM vm, const char* name, bool val)
-{
-  sq_pushstring(vm, name, -1);
-  sq_pushbool(vm, val ? SQTrue : SQFalse);
-  if(SQ_FAILED(sq_createslot(vm, -3)))
-    throw Scripting::SquirrelError(vm, "Couldn't add float value to table");
-}
-
-static float read_float(HSQUIRRELVM vm, const char* name)
-{
-  sq_pushstring(vm, name, -1);
-  if(SQ_FAILED(sq_get(vm, -2))) {
-    std::ostringstream msg;
-    msg << "Couldn't get float value for '" << name << "' from table";
-    throw Scripting::SquirrelError(vm, msg.str());
-  }
-  
-  float result;
-  if(SQ_FAILED(sq_getfloat(vm, -1, &result))) {
-    std::ostringstream msg;
-    msg << "Couldn't get float value for '" << name << "' from table";
-    throw Scripting::SquirrelError(vm, msg.str());
-  }
-  sq_pop(vm, 1);
-
-  return result;
-}
-
-static std::string read_string(HSQUIRRELVM vm, const char* name)
-{
-  sq_pushstring(vm, name, -1);
-  if(SQ_FAILED(sq_get(vm, -2))) {
-    std::ostringstream msg;
-    msg << "Couldn't get string value for '" << name << "' from table";
-    throw Scripting::SquirrelError(vm, msg.str());
-  }
-  
-  const char* result;
-  if(SQ_FAILED(sq_getstring(vm, -1, &result))) {
-    std::ostringstream msg;
-    msg << "Couldn't get string value for '" << name << "' from table";
-    throw Scripting::SquirrelError(vm, msg.str());
-  }
-  sq_pop(vm, 1);
-
-  return std::string(result);
-}
-
-static bool read_bool(HSQUIRRELVM vm, const char* name)
-{
-  sq_pushstring(vm, name, -1);
-  if(SQ_FAILED(sq_get(vm, -2))) {
-    std::ostringstream msg;
-    msg << "Couldn't get bool value for '" << name << "' from table";
-    throw Scripting::SquirrelError(vm, msg.str());
-  } 
-  
-  SQBool result;
-  if(SQ_FAILED(sq_getbool(vm, -1, &result))) {
-    std::ostringstream msg;
-    msg << "Couldn't get bool value for '" << name << "' from table";
-    throw Scripting::SquirrelError(vm, msg.str());
-  }
-  sq_pop(vm, 1);
-
-  return result == SQTrue;
-}
-
-void
-WorldMap::save_state()
-{
-  HSQUIRRELVM vm = ScriptManager::instance->get_vm();
-  int oldtop = sq_gettop(vm);
-
-  try {
-    // get state table
-    sq_pushroottable(vm);
-    sq_pushstring(vm, "state", -1);
-    if(SQ_FAILED(sq_get(vm, -2)))
-      throw Scripting::SquirrelError(vm, "Couldn't get state table");
-
-    // get or create worlds table
-    sq_pushstring(vm, "worlds", -1);
-    if(SQ_FAILED(sq_get(vm, -2))) {
-      sq_pushstring(vm, "worlds", -1);
-      sq_newtable(vm);
-      if(SQ_FAILED(sq_createslot(vm, -3)))
-        throw Scripting::SquirrelError(vm, "Couldn't create state.worlds");
-
-      sq_pushstring(vm, "worlds", -1);
-      if(SQ_FAILED(sq_get(vm, -2)))
-        throw Scripting::SquirrelError(vm, "Couldn't create.get state.worlds");
-    }
-    
-    sq_pushstring(vm, map_filename.c_str(), map_filename.length());
-    if(SQ_FAILED(sq_deleteslot(vm, -2, SQFalse)))
-      sq_pop(vm, 1);
-
-    // construct new table for this worldmap
-    sq_pushstring(vm, map_filename.c_str(), map_filename.length());
-    sq_newtable(vm);
-
-    // store tux
-    sq_pushstring(vm, "tux", -1);
-    sq_newtable(vm);
-    
-    store_float(vm, "x", tux->get_tile_pos().x);
-    store_float(vm, "y", tux->get_tile_pos().y);
-    store_string(vm, "back", direction_to_string(tux->back_direction));
-
-    sq_createslot(vm, -3);
-    
-    // levels...
-    sq_pushstring(vm, "levels", -1);
-    sq_newtable(vm);
-
-    for(Levels::iterator i = levels.begin(); i != levels.end(); ++i) {
-      if (i->solved) {
-        sq_pushstring(vm, i->name.c_str(), -1);
-        sq_newtable(vm);
-
-        store_bool(vm, "solved", true);            
-        // TODO write statistics
-        // i->statistics.write(writer);
-
-        sq_createslot(vm, -3);
-      }
-    }
-    
-    sq_createslot(vm, -3);
-
-    // push world into worlds table
-    sq_createslot(vm, -3);
-  } catch(std::exception& e) {
-    sq_settop(vm, oldtop);
-  }
-
-  sq_settop(vm, oldtop);
-}
-
-void
-WorldMap::load_state()
-{
-  HSQUIRRELVM vm = ScriptManager::instance->get_vm();
-  int oldtop = sq_gettop(vm);
-  try {
-    // get state table
-    sq_pushroottable(vm);
-    sq_pushstring(vm, "state", -1);
-    if(SQ_FAILED(sq_get(vm, -2)))
-      throw Scripting::SquirrelError(vm, "Couldn't get state table");
-
-    // get worlds table
-    sq_pushstring(vm, "worlds", -1);
-    if(SQ_FAILED(sq_get(vm, -2)))
-      throw Scripting::SquirrelError(vm, "Couldn't get state.worlds");
-
-    // get table for our world
-    sq_pushstring(vm, map_filename.c_str(), map_filename.length());
-    if(SQ_FAILED(sq_get(vm, -2)))
-      throw Scripting::SquirrelError(vm, "Couldn't get state.world.mapfilename");
-
-    // load tux
-    sq_pushstring(vm, "tux", -1);
-    if(SQ_FAILED(sq_get(vm, -2)))
-      throw Scripting::SquirrelError(vm, "Couldn't get tux");
-
-    Vector p;
-    p.x = read_float(vm, "x");
-    p.y = read_float(vm, "y");
-    std::string back_str = read_string(vm, "back");
-    tux->back_direction = string_to_direction(back_str);
-    tux->set_tile_pos(p);
-
-    sq_pop(vm, 1);
-
-    // load levels
-    sq_pushstring(vm, "levels", -1);
-    if(SQ_FAILED(sq_get(vm, -2)))
-      throw Scripting::SquirrelError(vm, "Couldn't get levels");
-
-    for(Levels::iterator i = levels.begin(); i != levels.end(); ++i) {
-      sq_pushstring(vm, i->name.c_str(), -1);
-      if(SQ_SUCCEEDED(sq_get(vm, -2))) {
-        i->solved = read_bool(vm, "solved");
-        i->sprite->set_action(i->solved ? "solved" : "default");
-        // i->statistics.parse(*level);
-        sq_pop(vm, 1);
-      }
-    }
-    sq_pop(vm, 1);
-
-  } catch(std::exception& e) {
-    log_debug << "Not loading worldmap state: " << e.what() << std::endl;
-  }
-  sq_settop(vm, oldtop);
-}
-
-size_t
-WorldMap::level_count()
-{
-  return levels.size();
-}
-
-size_t
-WorldMap::solved_level_count()
-{
-  size_t count = 0;
-  for(Levels::iterator i = levels.begin(); i != levels.end(); ++i) {
-    if(i->solved)
-      count++;
-  }
-
-  return count;
-}
-    
-void
-WorldMap::loadmap(const std::string& filename)
-{
-  savegame_file = "";
-  map_filename = filename;
-  load_map();
-}
-
-} // namespace WorldMapNS
diff --git a/src/worldmap.hpp b/src/worldmap.hpp
deleted file mode 100644 (file)
index 741863c..0000000
+++ /dev/null
@@ -1,296 +0,0 @@
-//  $Id$
-//
-//  SuperTux
-//  Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.de>
-//  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#ifndef SUPERTUX_WORLDMAP_H
-#define SUPERTUX_WORLDMAP_H
-
-#include <vector>
-#include <string>
-
-#include "math/vector.hpp"
-#include "video/screen.hpp"
-#include "lisp/lisp.hpp"
-#include "control/controller.hpp"
-#include "statistics.hpp"
-#include "timer.hpp"
-#include "screen.hpp"
-#include "tile_manager.hpp"
-#include "game_object.hpp"
-#include "console.hpp"
-
-class Sprite;
-class Menu;
-class SpawnPoint;
-class GameObject;
-class TileMap;
-extern Menu* worldmap_menu;
-
-namespace WorldMapNS {
-
-enum WorldMapMenuIDs {
-  MNID_RETURNWORLDMAP,
-  MNID_QUITWORLDMAP
-};
-
-// For one way tiles
-enum {
-  BOTH_WAYS,
-  NORTH_SOUTH_WAY,
-  SOUTH_NORTH_WAY,
-  EAST_WEST_WAY,
-  WEST_EAST_WAY
-};
-
-enum Direction { D_NONE, D_WEST, D_EAST, D_NORTH, D_SOUTH };
-
-std::string direction_to_string(Direction d);
-Direction   string_to_direction(const std::string& d);
-Direction reverse_dir(Direction d);
-
-class WorldMap;
-
-class Tux : public GameObject
-{
-public:
-  Direction back_direction;
-private:
-  WorldMap* worldmap;
-  Sprite* tux_sprite;
-  Controller* controller;
-
-  Direction input_direction;
-  Direction direction;
-  Vector tile_pos;
-  /** Length by which tux is away from its current tile, length is in
-      input_direction direction */
-  float offset;
-  bool  moving;
-
-  void stop();
-
-  bool canWalk(const Tile* tile, Direction dir); /**< check if we can leave "tile" in direction "dir" */
-  void updateInputDirection(); /**< if controller was pressed, update input_direction */
-  void tryStartWalking(); /**< try starting to walk in input_direction */
-  void tryContinueWalking(float elapsed_time); /**< try to continue walking in current direction */
-
-public: 
-  Tux(WorldMap* worldmap_);
-  ~Tux();
-  
-  void draw(DrawingContext& context);
-  void update(float elapsed_time);
-
-  void set_direction(Direction dir);
-
-  bool is_moving() const { return moving; }
-  Vector get_pos();
-  Vector get_tile_pos() const { return tile_pos; } 
-  void  set_tile_pos(Vector p) { tile_pos = p; } 
-};
-
-/** */
-class WorldMap : public Screen
-{
-private:
-  Tux* tux;
-
-  Surface* leveldot_green;
-  Surface* leveldot_red;
-  Surface* messagedot;
-  Sprite* teleporterdot;
-  static WorldMap* current_;
-
-  Vector camera_offset;
-
-  std::string name;
-  std::string music;
-
-  typedef std::vector<GameObject*> GameObjects;
-  GameObjects game_objects;
-  TileMap* solids;
-  
-  TileManager* tile_manager;
-  
-  Console* console;
-
-public:
-  struct SpecialTile
-  {
-    Vector pos;
-
-    /** Optional flags: */
-
-    /** Sprite to render instead of guessing what image to draw */
-    Sprite* sprite;
-
-    /** Position to swap to player */
-    Vector teleport_dest;
-
-    /** Message to show in the Map */
-    std::string map_message;
-    bool passive_message;
-
-    /** Hide special tile */
-    bool invisible;
-
-    /** Only applies actions (ie. passive messages) when going to that direction */
-    bool apply_action_north;
-    bool apply_action_east;
-    bool apply_action_south;
-    bool apply_action_west;
-  };
-
-  struct Level
-  {
-    Vector pos;
-
-    std::string name;
-    std::string title;
-    bool solved;
-
-    Sprite* sprite;
-
-    /** Statistics for level tiles */
-    Statistics statistics;
-
-    /** Optional flags: */
-
-    /** Check if this level should be vertically flipped */
-    bool vertical_flip;
-
-    /** Script that is run when the level is successfully finished */
-    std::string extro_script;
-
-    /** Go to this world */
-    std::string next_worldmap;
-
-    /** Quit the worldmap */
-    bool quit_worldmap;
-
-    /** If false, disables the auto walking after finishing a level */
-    bool auto_path;
-
-    // Directions which are walkable from this level
-    bool north;
-    bool east;
-    bool south;
-    bool west;
-  };
-
-  /** Variables to deal with the passive map messages */
-  Timer passive_message_timer;
-  std::string passive_message;
-
-private:
-  std::string map_filename;
-  std::string levels_path;
-
-  typedef std::vector<SpecialTile> SpecialTiles;
-  SpecialTiles special_tiles;
-  typedef std::vector<Level> Levels;
-  Levels levels;
-  typedef std::vector<SpawnPoint*> SpawnPoints;
-  SpawnPoints spawn_points;
-
-  Vector offset;
-  std::string savegame_file;
-  
-  std::string intro_script;
-  bool intro_displayed;
-
-  void get_level_title(Level& level);
-
-  void draw_status(DrawingContext& context);
-
-  // to avoid calculating total stats all the time. This way only
-  // when need, it is calculated.
-  Statistics total_stats;
-  void calculate_total_stats();
-
-public:
-  WorldMap();
-  ~WorldMap();
-
-  void load_map();
-  
-  void add_object(GameObject* object);
-  void clear_objects();
-
-  static WorldMap* current()
-  { return current_; }
-
-  void setup();
-
-  /** Update Tux position */
-  void update(float delta);
-
-  /** Draw one frame */
-  void draw(DrawingContext& context);
-
-  Vector get_next_tile(Vector pos, Direction direction);
-  const Tile* at(Vector pos);
-
-  size_t level_count();
-  size_t solved_level_count();
-
-  /**
-   * gets called from the GameSession when a level has been successfully
-   * finished
-   */
-  void finished_level(const std::string& filename);
-
-  WorldMap::Level* at_level();
-  WorldMap::SpecialTile* at_special_tile();
-
-  /** Check if it is possible to walk from \a pos into \a direction,
-      if possible, write the new position to \a new_pos */
-  bool path_ok(Direction direction, Vector pos, Vector* new_pos);
-
-  /**
-   * Save worldmap state to squirrel state table
-   */
-  void save_state();
-  /**
-   * Load worldmap state from squirrel state table
-   */
-  void load_state();
-  /**
-   * Load a worldmap
-   */
-  void loadmap(const std::string& filename);
-
-  const std::string& get_title() const
-  { return name; }
-    
-  void set_map_filename(std::string filename)
-  { map_filename = filename; }
-
-private:
-  void on_escape_press();
-  void parse_special_tile(const lisp::Lisp* lisp);
-  void parse_level_tile(const lisp::Lisp* lisp);
-};
-
-} // namespace WorldMapNS
-
-#endif
-
-/* Local Variables: */
-/* mode:c++ */
-/* End: */
diff --git a/src/worldmap/level.cpp b/src/worldmap/level.cpp
new file mode 100644 (file)
index 0000000..c4fc951
--- /dev/null
@@ -0,0 +1,67 @@
+//  $Id: worldmap.hpp 3327 2006-04-13 15:02:40Z ravu_al_hemio $
+//
+//  SuperTux
+//  Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.de>
+//  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#include <config.h>
+
+#include <physfs.h>
+#include "level.hpp"
+#include "sprite/sprite_manager.hpp"
+#include "sprite/sprite.hpp"
+#include "video/drawing_context.hpp"
+
+namespace WorldMapNS
+{
+
+Level::Level(const std::string& basedir, const lisp::Lisp* lisp)
+  : solved(false), auto_path(true)
+{
+  lisp->get("x", pos.x);
+  lisp->get("y", pos.y);
+  
+  std::string spritefile = "images/worldmap/common/leveldot.sprite";
+  lisp->get("sprite", spritefile);
+  sprite.reset(sprite_manager->create(spritefile));
+
+  lisp->get("extro-script", extro_script);
+  lisp->get("name", name);
+  
+  if (!PHYSFS_exists((basedir + name).c_str()))
+  {
+    log_warning << "level file '" << name 
+      << "' does not exist and will not be added to the worldmap" << std::endl;
+    return;
+  }
+}
+
+Level::~Level()
+{
+}
+
+void
+Level::draw(DrawingContext& context)
+{
+  sprite->draw(context, pos*32 + Vector(16, 16), LAYER_OBJECTS - 1);
+}
+
+void
+Level::update(float )
+{
+}
+
+}
diff --git a/src/worldmap/level.hpp b/src/worldmap/level.hpp
new file mode 100644 (file)
index 0000000..8e79f3e
--- /dev/null
@@ -0,0 +1,63 @@
+//  $Id: worldmap.hpp 3327 2006-04-13 15:02:40Z ravu_al_hemio $
+//
+//  SuperTux
+//  Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.de>
+//  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#ifndef __WORLDMAP_LEVEL_HPP__
+#define __WORLDMAP_LEVEL_HPP__
+
+#include <memory>
+#include <string>
+#include "math/vector.hpp"
+#include "game_object.hpp"
+#include "statistics.hpp"
+
+class Sprite;
+
+namespace WorldMapNS
+{
+
+class Level : public GameObject
+{
+public:
+  Level(const std::string& basedir, const lisp::Lisp* lisp);
+  virtual ~Level();
+
+  virtual void draw(DrawingContext& context);
+  virtual void update(float elapsed_time);
+  
+  Vector pos;
+  std::string name;
+  std::string title;
+  bool solved;
+
+  std::auto_ptr<Sprite> sprite;
+
+  /** Statistics for level tiles */
+  Statistics statistics;
+
+  /** Script that is run when the level is successfully finished */
+  std::string extro_script;
+
+  /** If false, disables the auto walking after finishing a level */
+  bool auto_path;
+};
+
+}
+
+#endif
+
diff --git a/src/worldmap/special_tile.cpp b/src/worldmap/special_tile.cpp
new file mode 100644 (file)
index 0000000..201458a
--- /dev/null
@@ -0,0 +1,87 @@
+//  $Id: worldmap.hpp 3327 2006-04-13 15:02:40Z ravu_al_hemio $
+//
+//  SuperTux
+//  Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.de>
+//  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#include <config.h>
+
+#include "worldmap/special_tile.hpp"
+#include "sprite/sprite_manager.hpp"
+#include "sprite/sprite.hpp"
+#include "video/drawing_context.hpp"
+
+namespace WorldMapNS
+{
+
+SpecialTile::SpecialTile(const lisp::Lisp* lisp)
+  : passive_message(false), invisible(false),
+    apply_action_north(true), apply_action_east(true),
+    apply_action_south(true), apply_action_west(true)
+{
+  lisp->get("x", pos.x);
+  lisp->get("y", pos.y);
+  lisp->get("invisible-tile", invisible);
+  
+  if(!invisible) {
+    std::string spritefile = "";
+    lisp->get("sprite", spritefile);
+    sprite.reset(sprite_manager->create(spritefile));
+  }
+
+  lisp->get("map-message", map_message);
+  lisp->get("passive-message", passive_message);
+  lisp->get("teleport-to-x", teleport_dest.x);
+  lisp->get("teleport-to-y", teleport_dest.y);
+
+  std::string apply_direction;
+  lisp->get("apply-to-direction", apply_direction);
+  if(!apply_direction.empty()) {
+    apply_action_north = false;
+    apply_action_south = false;
+    apply_action_east = false;
+    apply_action_west = false;
+    if(apply_direction.find("north") != std::string::npos)
+      apply_action_north = true;
+    if(apply_direction.find("south") != std::string::npos)
+      apply_action_south = true;
+    if(apply_direction.find("east") != std::string::npos)
+      apply_action_east = true;
+    if(apply_direction.find("west") != std::string::npos)
+      apply_action_west = true;
+  }
+}
+
+SpecialTile::~SpecialTile()
+{
+}
+
+void
+SpecialTile::draw(DrawingContext& context)
+{
+  if(invisible)
+    return;
+
+  sprite->draw(context, pos*32 + Vector(16, 16), LAYER_OBJECTS - 1);
+}
+
+void
+SpecialTile::update(float )
+{
+}
+
+}
+
diff --git a/src/worldmap/special_tile.hpp b/src/worldmap/special_tile.hpp
new file mode 100644 (file)
index 0000000..f958d9b
--- /dev/null
@@ -0,0 +1,68 @@
+//  $Id: worldmap.hpp 3327 2006-04-13 15:02:40Z ravu_al_hemio $
+//
+//  SuperTux
+//  Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.de>
+//  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#ifndef __WORLDMAP_SPECIAL_TILE_HPP__
+#define __WORLDMAP_SPECIAL_TILE_HPP__
+
+#include <memory>
+#include <string>
+#include "game_object.hpp"
+#include "math/vector.hpp"
+#include "lisp/lisp.hpp"
+
+class Sprite;
+
+namespace WorldMapNS
+{
+
+class SpecialTile : public GameObject
+{
+public:
+  SpecialTile(const lisp::Lisp* lisp);
+  virtual ~SpecialTile();
+
+  virtual void draw(DrawingContext& context);
+  virtual void update(float elapsed_time);
+
+  Vector pos;
+  
+  /** Sprite to render instead of guessing what image to draw */
+  std::auto_ptr<Sprite> sprite;
+
+  /** Position to swap to player */
+  Vector teleport_dest;
+
+  /** Message to show in the Map */
+  std::string map_message;
+  bool passive_message;
+
+  /** Hide special tile */
+  bool invisible;
+
+  /** Only applies actions (ie. passive messages) when going to that direction */
+  bool apply_action_north;
+  bool apply_action_east;
+  bool apply_action_south;
+  bool apply_action_west;
+};
+
+}
+
+#endif
+
diff --git a/src/worldmap/sprite_change.cpp b/src/worldmap/sprite_change.cpp
new file mode 100644 (file)
index 0000000..7eb044f
--- /dev/null
@@ -0,0 +1,58 @@
+//  $Id: worldmap.hpp 3327 2006-04-13 15:02:40Z ravu_al_hemio $
+//
+//  SuperTux
+//  Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.de>
+//  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#include <config.h>
+
+#include "sprite_change.hpp"
+#include "sprite/sprite_manager.hpp"
+#include "sprite/sprite.hpp"
+
+namespace WorldMapNS
+{
+
+SpriteChange::SpriteChange(const lisp::Lisp* lisp)
+  : enter(false), in_stay_action(false)
+{
+  lisp->get("x", pos.x);
+  lisp->get("y", pos.y);
+  lisp->get("enter", enter);
+  
+  std::string spritefile = "";
+  lisp->get("sprite", spritefile);
+  sprite.reset(sprite_manager->create(spritefile));
+
+  lisp->get("stay-action", stay_action);
+  lisp->get("initial-stay-action", in_stay_action);
+}
+
+SpriteChange::~SpriteChange()
+{
+}
+
+void
+SpriteChange::draw(DrawingContext& )
+{
+}
+
+void
+SpriteChange::update(float )
+{
+}
+
+}
diff --git a/src/worldmap/sprite_change.hpp b/src/worldmap/sprite_change.hpp
new file mode 100644 (file)
index 0000000..c572309
--- /dev/null
@@ -0,0 +1,66 @@
+//  $Id: worldmap.hpp 3327 2006-04-13 15:02:40Z ravu_al_hemio $
+//
+//  SuperTux
+//  Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.de>
+//  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#ifndef __WORLDMAP_SPRITE_CHANGE_HPP__
+#define __WORLDMAP_SPRITE_CHANGE_HPP__
+
+#include <string>
+#include <memory>
+#include "game_object.hpp"
+#include "lisp/lisp.hpp"
+#include "math/vector.hpp"
+
+class Sprite;
+
+namespace WorldMapNS
+{
+
+class SpriteChange : public GameObject
+{
+public:
+  SpriteChange(const lisp::Lisp* lisp);
+  virtual ~SpriteChange();
+
+  Vector pos;
+  /**
+   * should tuxs sprite change when the tile has been completely entered,
+   * or already when the tile was just touched
+   */
+  bool enter;
+  /// sprite to change tux image to
+  std::auto_ptr<Sprite> sprite;
+  /**
+   * stay action can be used for objects like boats or cars, if it is
+   * != "" then this sprite will be displayed when tux left the tile towards
+   * another SpriteChange object.
+   */
+  std::string stay_action;
+  /**
+   * should the stayaction be displayed
+   */
+  bool in_stay_action;
+
+  virtual void draw(DrawingContext& context);
+  virtual void update(float elapsed_time);
+};
+
+}
+
+#endif
+
diff --git a/src/worldmap/tux.cpp b/src/worldmap/tux.cpp
new file mode 100644 (file)
index 0000000..ade0588
--- /dev/null
@@ -0,0 +1,260 @@
+//  $Id: worldmap.cpp 3327 2006-04-13 15:02:40Z ravu_al_hemio $
+//
+//  SuperTux -  A Jump'n Run
+//  Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.de>
+//  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#include <config.h>
+
+#include "tux.hpp"
+#include "sprite/sprite_manager.hpp"
+#include "video/drawing_context.hpp"
+#include "player_status.hpp"
+#include "worldmap.hpp"
+#include "level.hpp"
+#include "special_tile.hpp"
+#include "control/joystickkeyboardcontroller.hpp"
+#include "main.hpp"
+
+namespace WorldMapNS
+{
+
+static const float TUXSPEED = 200; 
+static const float map_message_TIME = 2.8;
+
+Tux::Tux(WorldMap* worldmap_)
+  : worldmap(worldmap_)
+{
+  sprite.reset(sprite_manager->create("images/worldmap/common/tux.sprite"));
+  
+  offset = 0;
+  moving = false;
+  direction = D_NONE;
+  input_direction = D_NONE;
+}
+
+Tux::~Tux()
+{
+}
+
+void
+Tux::draw(DrawingContext& context)
+{
+  switch (player_status->bonus) {
+    case GROWUP_BONUS:
+      sprite->set_action(moving ? "large-walking" : "large-stop");
+      break;
+    case FIRE_BONUS:
+      sprite->set_action(moving ? "fire-walking" : "fire-stop");
+      break;
+    case NO_BONUS:
+      sprite->set_action(moving ? "small-walking" : "small-stop");
+      break;
+    default:
+      log_debug << "Bonus type not handled in worldmap." << std::endl;
+      sprite->set_action("large-stop");
+      break;
+  }
+
+  sprite->draw(context, get_pos(), LAYER_OBJECTS);
+}
+
+
+Vector
+Tux::get_pos()
+{
+  float x = tile_pos.x * 32;
+  float y = tile_pos.y * 32;
+
+  switch(direction)
+    {
+    case D_WEST:
+      x -= offset - 32;
+      break;
+    case D_EAST:
+      x += offset - 32;
+      break;
+    case D_NORTH:
+      y -= offset - 32;
+      break;
+    case D_SOUTH:
+      y += offset - 32;
+      break;
+    case D_NONE:
+      break;
+    }
+  
+  return Vector(x, y);
+}
+
+void
+Tux::stop()
+{
+  offset = 0;
+  direction = D_NONE;
+  input_direction = D_NONE;
+  moving = false;
+}
+
+void
+Tux::set_direction(Direction dir)
+{
+  input_direction = dir;
+}
+
+void 
+Tux::tryStartWalking() 
+{
+  if (moving)
+    return;  
+  if (input_direction == D_NONE)
+    return;
+
+  Level* level = worldmap->at_level();
+
+  // We got a new direction, so lets start walking when possible
+  Vector next_tile;
+  if ((!level || level->solved) && worldmap->path_ok(input_direction, tile_pos, &next_tile))
+  {
+    tile_pos = next_tile;
+    moving = true;
+    direction = input_direction;
+    back_direction = reverse_dir(direction);
+  }
+  else if (input_direction == back_direction)
+  {
+    moving = true;
+    direction = input_direction;
+    tile_pos = worldmap->get_next_tile(tile_pos, direction);
+    back_direction = reverse_dir(direction);
+  }
+
+}
+
+bool 
+Tux::canWalk(const Tile* tile, Direction dir)
+{
+  return ((tile->getData() & Tile::WORLDMAP_NORTH && dir == D_NORTH) ||
+         (tile->getData() & Tile::WORLDMAP_SOUTH && dir == D_SOUTH) ||
+         (tile->getData() & Tile::WORLDMAP_EAST && dir == D_EAST) ||
+         (tile->getData() & Tile::WORLDMAP_WEST && dir == D_WEST));
+}
+
+void 
+Tux::tryContinueWalking(float elapsed_time)
+{
+  if (!moving) return;
+
+  // Let tux walk
+  offset += TUXSPEED * elapsed_time;
+
+  // Do nothing if we have not yet reached the next tile
+  if (offset <= 32) return;
+
+  offset -= 32;
+
+  // if this is a special_tile with passive_message, display it
+  SpecialTile* special_tile = worldmap->at_special_tile();
+  if(special_tile && special_tile->passive_message)
+  {  
+    // direction and the apply_action_ are opposites, since they "see"
+    // directions in a different way
+    if((direction == D_NORTH && special_tile->apply_action_south) ||
+                   (direction == D_SOUTH && special_tile->apply_action_north) ||
+                   (direction == D_WEST && special_tile->apply_action_east) ||
+                   (direction == D_EAST && special_tile->apply_action_west))
+    {
+      worldmap->passive_message = special_tile->map_message;
+      worldmap->passive_message_timer.start(map_message_TIME);
+    }
+  }
+
+  // stop if we reached a level, a WORLDMAP_STOP tile or a special tile without a passive_message
+  if ((worldmap->at_level()) || (worldmap->at(tile_pos)->getData() & Tile::WORLDMAP_STOP) || (special_tile && !special_tile->passive_message))
+  {
+    if(special_tile && !special_tile->map_message.empty() && !special_tile->passive_message) worldmap->passive_message_timer.start(0);
+    stop();
+    return;
+  }
+
+  // if user wants to change direction, try changing, else guess the direction in which to walk next
+  const Tile* tile = worldmap->at(tile_pos);
+  if (direction != input_direction)
+  { 
+    if(canWalk(tile, input_direction))
+    {  
+      direction = input_direction;
+      back_direction = reverse_dir(direction);
+    }
+  }
+  else
+  {
+    Direction dir = D_NONE;
+    if (tile->getData() & Tile::WORLDMAP_NORTH && back_direction != D_NORTH) dir = D_NORTH;
+    else if (tile->getData() & Tile::WORLDMAP_SOUTH && back_direction != D_SOUTH) dir = D_SOUTH;
+    else if (tile->getData() & Tile::WORLDMAP_EAST && back_direction != D_EAST) dir = D_EAST;
+    else if (tile->getData() & Tile::WORLDMAP_WEST && back_direction != D_WEST) dir = D_WEST;
+
+    if (dir == D_NONE) 
+    {
+      // Should never be reached if tiledata is good
+      log_warning << "Could not determine where to walk next" << std::endl;
+      stop();
+      return;
+    }
+
+    direction = dir;
+    input_direction = direction;
+    back_direction = reverse_dir(direction);
+  }
+
+  // Walk automatically to the next tile
+  if(direction != D_NONE)
+  {
+    Vector next_tile;
+    if (worldmap->path_ok(direction, tile_pos, &next_tile))
+    {
+      tile_pos = next_tile;
+    }
+    else
+    {
+      log_warning << "Tilemap data is buggy" << std::endl;
+      stop();
+    }
+  }
+}
+
+void
+Tux::updateInputDirection()
+{
+  if(main_controller->hold(Controller::UP))
+    input_direction = D_NORTH;
+  else if(main_controller->hold(Controller::DOWN))
+    input_direction = D_SOUTH;
+  else if(main_controller->hold(Controller::LEFT))
+    input_direction = D_WEST;
+  else if(main_controller->hold(Controller::RIGHT))
+    input_direction = D_EAST;
+}
+
+void
+Tux::update(float elapsed_time)
+{
+  updateInputDirection(); 
+  if (moving) tryContinueWalking(elapsed_time); else tryStartWalking();
+}
+
+}
diff --git a/src/worldmap/tux.hpp b/src/worldmap/tux.hpp
new file mode 100644 (file)
index 0000000..173bbec
--- /dev/null
@@ -0,0 +1,76 @@
+//  $Id: worldmap.cpp 3327 2006-04-13 15:02:40Z ravu_al_hemio $
+//
+//  SuperTux -  A Jump'n Run
+//  Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.de>
+//  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#ifndef __WORLDMAP_TUX_HPP__
+#define __WORLDMAP_TUX_HPP__
+
+#include <memory>
+#include "game_object.hpp"
+#include "worldmap.hpp"
+
+class Sprite;
+
+namespace WorldMapNS
+{
+
+class WorldMap;
+
+class Tux : public GameObject
+{
+public:
+  Direction back_direction;
+private:
+  WorldMap* worldmap;
+  std::auto_ptr<Sprite> sprite;
+  Controller* controller;
+
+  Direction input_direction;
+  Direction direction;
+  Vector tile_pos;
+  /** Length by which tux is away from its current tile, length is in
+      input_direction direction */
+  float offset;
+  bool  moving;
+
+  void stop();
+
+  bool canWalk(const Tile* tile, Direction dir); /**< check if we can leave "tile" in direction "dir" */
+  void updateInputDirection(); /**< if controller was pressed, update input_direction */
+  void tryStartWalking(); /**< try starting to walk in input_direction */
+  void tryContinueWalking(float elapsed_time); /**< try to continue walking in current direction */
+
+public: 
+  Tux(WorldMap* worldmap_);
+  ~Tux();
+  
+  void draw(DrawingContext& context);
+  void update(float elapsed_time);
+
+  void set_direction(Direction dir);
+
+  bool is_moving() const { return moving; }
+  Vector get_pos();
+  Vector get_tile_pos() const { return tile_pos; } 
+  void  set_tile_pos(Vector p) { tile_pos = p; } 
+};
+
+}
+
+#endif
+
diff --git a/src/worldmap/worldmap.cpp b/src/worldmap/worldmap.cpp
new file mode 100644 (file)
index 0000000..84423f3
--- /dev/null
@@ -0,0 +1,908 @@
+//  $Id$
+//
+//  SuperTux -  A Jump'n Run
+//  Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.de>
+//  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#include <config.h>
+
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <cassert>
+#include <stdexcept>
+#include <sstream>
+#include <unistd.h>
+#include <physfs.h>
+
+#include "worldmap.hpp"
+
+#include "gettext.hpp"
+#include "log.hpp"
+#include "mainloop.hpp"
+#include "video/surface.hpp"
+#include "video/screen.hpp"
+#include "video/drawing_context.hpp"
+#include "sprite/sprite_manager.hpp"
+#include "audio/sound_manager.hpp"
+#include "lisp/parser.hpp"
+#include "lisp/lisp.hpp"
+#include "lisp/list_iterator.hpp"
+#include "lisp/writer.hpp"
+#include "game_session.hpp"
+#include "sector.hpp"
+#include "worldmap.hpp"
+#include "resources.hpp"
+#include "misc.hpp"
+#include "log.hpp"
+#include "world.hpp"
+#include "player_status.hpp"
+#include "textscroller.hpp"
+#include "main.hpp"
+#include "spawn_point.hpp"
+#include "file_system.hpp"
+#include "gui/menu.hpp"
+#include "gui/mousecursor.hpp"
+#include "control/joystickkeyboardcontroller.hpp"
+#include "object/background.hpp"
+#include "object/tilemap.hpp"
+#include "script_manager.hpp"
+#include "options_menu.hpp"
+#include "scripting/squirrel_error.hpp"
+#include "scripting/wrapper_util.hpp"
+#include "worldmap/level.hpp"
+#include "worldmap/special_tile.hpp"
+#include "worldmap/tux.hpp"
+#include "worldmap/sprite_change.hpp"
+
+namespace WorldMapNS {
+
+enum WorldMapMenuIDs {
+  MNID_RETURNWORLDMAP,
+  MNID_QUITWORLDMAP
+};
+
+WorldMap* WorldMap::current_ = NULL;
+
+Direction reverse_dir(Direction direction)
+{
+  switch(direction)
+    {
+    case D_WEST:
+      return D_EAST;
+    case D_EAST:
+      return D_WEST;
+    case D_NORTH:
+      return D_SOUTH;
+    case D_SOUTH:
+      return D_NORTH;
+    case D_NONE:
+      return D_NONE;
+    }
+  return D_NONE;
+}
+
+std::string
+direction_to_string(Direction direction)
+{
+  switch(direction)
+    {
+    case D_WEST:
+      return "west";
+    case D_EAST:
+      return "east";
+    case D_NORTH:
+      return "north";
+    case D_SOUTH:
+      return "south";
+    default:
+      return "none";
+    }
+}
+
+Direction
+string_to_direction(const std::string& directory)
+{
+  if (directory == "west")
+    return D_WEST;
+  else if (directory == "east")
+    return D_EAST;
+  else if (directory == "north")
+    return D_NORTH;
+  else if (directory == "south")
+    return D_SOUTH;
+  else
+    return D_NONE;
+}
+
+//---------------------------------------------------------------------------
+
+WorldMap::WorldMap()
+  : tux(0), solids(0)
+{
+  tile_manager.reset(new TileManager("images/worldmap.strf"));
+  
+  tux = new Tux(this);
+  add_object(tux);
+    
+  name = "<no title>";
+  music = "music/salcon.ogg";
+  intro_displayed = false;
+
+  total_stats.reset();
+
+  worldmap_menu.reset(new Menu());
+  worldmap_menu->add_label(_("Pause"));
+  worldmap_menu->add_hl();
+  worldmap_menu->add_entry(MNID_RETURNWORLDMAP, _("Continue"));
+  worldmap_menu->add_submenu(_("Options"), get_options_menu());
+  worldmap_menu->add_hl();
+  worldmap_menu->add_entry(MNID_QUITWORLDMAP, _("Quit World"));
+}
+
+WorldMap::~WorldMap()
+{
+  if(current_ == this)
+    current_ = NULL;
+
+  clear_objects();
+  for(SpawnPoints::iterator i = spawn_points.begin();
+      i != spawn_points.end(); ++i) {
+    delete *i;
+  }
+}
+
+void
+WorldMap::add_object(GameObject* object)
+{
+  TileMap* tilemap = dynamic_cast<TileMap*> (object);
+  if(tilemap != 0 && tilemap->is_solid()) {
+    solids = tilemap;
+  }
+
+  game_objects.push_back(object);
+}
+
+void
+WorldMap::clear_objects()
+{
+  for(GameObjects::iterator i = game_objects.begin();
+      i != game_objects.end(); ++i)
+    delete *i;
+  game_objects.clear();
+  solids = 0;
+  tux = new Tux(this);
+  add_object(tux);
+}
+
+// Don't forget to set map_filename before calling this
+void
+WorldMap::load_map()
+{
+  levels_path = FileSystem::dirname(map_filename);
+
+  try {
+    lisp::Parser parser;
+    std::auto_ptr<lisp::Lisp> root (parser.parse(map_filename));
+
+    const lisp::Lisp* lisp = root->get_lisp("supertux-level");
+    if(!lisp)
+      throw std::runtime_error("file isn't a supertux-level file.");
+
+    lisp->get("name", name);
+    
+    const lisp::Lisp* sector = lisp->get_lisp("sector");
+    if(!sector)
+      throw std::runtime_error("No sector sepcified in worldmap file.");
+    
+    clear_objects();
+    lisp::ListIterator iter(sector);
+    while(iter.next()) {
+      if(iter.item() == "tilemap") {
+        add_object(new TileMap(*(iter.lisp()), tile_manager.get()));
+      } else if(iter.item() == "background") {
+        add_object(new Background(*(iter.lisp())));
+      } else if(iter.item() == "music") {
+        iter.value()->get(music);
+      } else if(iter.item() == "intro-script") {
+        iter.value()->get(intro_script);
+      } else if(iter.item() == "worldmap-spawnpoint") {
+        SpawnPoint* sp = new SpawnPoint(iter.lisp());
+        spawn_points.push_back(sp);
+      } else if(iter.item() == "level") {
+        Level* level = new Level(levels_path, iter.lisp());
+        levels.push_back(level);
+        game_objects.push_back(level);
+      } else if(iter.item() == "special-tile") {
+        SpecialTile* special_tile = new SpecialTile(iter.lisp());
+        special_tiles.push_back(special_tile);
+        game_objects.push_back(special_tile);
+      } else if(iter.item() == "spritechange") {
+        SpriteChange* sprite_change = new SpriteChange(iter.lisp());
+        sprite_changes.push_back(sprite_change);
+        game_objects.push_back(sprite_change);
+      } else if(iter.item() == "name") {
+        // skip
+      } else {
+        log_warning << "Unknown token '" << iter.item() << "' in worldmap" << std::endl;
+      }
+    }
+    if(solids == 0)
+      throw std::runtime_error("No solid tilemap specified");
+
+    // search for main spawnpoint
+    for(SpawnPoints::iterator i = spawn_points.begin();
+        i != spawn_points.end(); ++i) {
+      SpawnPoint* sp = *i;
+      if(sp->name == "main") {
+        Vector p = sp->pos;
+        tux->set_tile_pos(p);
+        break;
+      }
+    }
+
+  } catch(std::exception& e) {
+    std::stringstream msg;
+    msg << "Problem when parsing worldmap '" << map_filename << "': " <<
+      e.what();
+    throw std::runtime_error(msg.str());
+  }
+}
+
+void
+WorldMap::get_level_title(Level& level)
+{
+  /** get special_tile's title */
+  level.title = "<no title>";
+
+  try {
+    lisp::Parser parser;
+    std::auto_ptr<lisp::Lisp> root (parser.parse(levels_path + level.name));
+
+    const lisp::Lisp* level_lisp = root->get_lisp("supertux-level");
+    if(!level_lisp)
+      return;
+    
+    level_lisp->get("name", level.title);
+  } catch(std::exception& e) {
+    log_warning << "Problem when reading leveltitle: " << e.what() << std::endl;
+    return;
+  }
+}
+
+void WorldMap::calculate_total_stats()
+{
+  total_stats.reset();
+  for(Levels::iterator i = levels.begin(); i != levels.end(); ++i) {
+    Level* level = *i;
+    if (level->solved) {
+      total_stats += level->statistics;
+    }
+  }
+}
+
+void
+WorldMap::on_escape_press()
+{
+  // Show or hide the menu
+  if(!Menu::current()) {
+    Menu::set_current(worldmap_menu.get());
+    tux->set_direction(D_NONE);  // stop tux movement when menu is called
+  } else {
+    Menu::set_current(NULL);
+  }
+}
+
+Vector
+WorldMap::get_next_tile(Vector pos, Direction direction)
+{
+  switch(direction) {
+    case D_WEST:
+      pos.x -= 1;
+      break;
+    case D_EAST:
+      pos.x += 1;
+      break;
+    case D_NORTH:
+      pos.y -= 1;
+      break;
+    case D_SOUTH:
+      pos.y += 1;
+      break;
+    case D_NONE:
+      break;
+  }
+  return pos;
+}
+
+bool
+WorldMap::path_ok(Direction direction, Vector old_pos, Vector* new_pos)
+{
+  *new_pos = get_next_tile(old_pos, direction);
+
+  if (!(new_pos->x >= 0 && new_pos->x < solids->get_width()
+        && new_pos->y >= 0 && new_pos->y < solids->get_height()))
+    { // New position is outsite the tilemap
+      return false;
+    }
+  else
+    { // Check if the tile allows us to go to new_pos
+      switch(direction)
+        {
+        case D_WEST:
+          return (at(old_pos)->getData() & Tile::WORLDMAP_WEST
+              && at(*new_pos)->getData() & Tile::WORLDMAP_EAST);
+
+        case D_EAST:
+          return (at(old_pos)->getData() & Tile::WORLDMAP_EAST
+              && at(*new_pos)->getData() & Tile::WORLDMAP_WEST);
+
+        case D_NORTH:
+          return (at(old_pos)->getData() & Tile::WORLDMAP_NORTH
+              && at(*new_pos)->getData() & Tile::WORLDMAP_SOUTH);
+
+        case D_SOUTH:
+          return (at(old_pos)->getData() & Tile::WORLDMAP_SOUTH
+              && at(*new_pos)->getData() & Tile::WORLDMAP_NORTH);
+
+        case D_NONE:
+          assert(!"path_ok() can't work if direction is NONE");
+        }
+      return false;
+    }
+}
+
+void
+WorldMap::finished_level(const std::string& filename)
+{
+  // TODO calculate level from filename?
+  (void) filename;
+  Level* level = at_level();
+
+  bool old_level_state = level->solved;
+  level->solved = true;
+  level->sprite->set_action("solved");
+
+  // deal with statistics
+  level->statistics.merge(global_stats);
+  calculate_total_stats();
+
+  save_state();
+  if(World::current() != NULL)
+    World::current()->save_state();
+
+  if (old_level_state != level->solved && level->auto_path) {
+    // Try to detect the next direction to which we should walk
+    // FIXME: Mostly a hack
+    Direction dir = D_NONE;
+  
+    const Tile* tile = at(tux->get_tile_pos());
+
+    // first, test for crossroads
+    if (tile->getData() & Tile::WORLDMAP_CNSE || tile->getData() && Tile::WORLDMAP_CNSW
+     || tile->getData() & Tile::WORLDMAP_CNEW || tile->getData() && Tile::WORLDMAP_CSEW
+     || tile->getData() & Tile::WORLDMAP_CNSEW)
+      dir = D_NONE;
+    else if (tile->getData() & Tile::WORLDMAP_NORTH
+        && tux->back_direction != D_NORTH)
+      dir = D_NORTH;
+    else if (tile->getData() & Tile::WORLDMAP_SOUTH
+        && tux->back_direction != D_SOUTH)
+      dir = D_SOUTH;
+    else if (tile->getData() & Tile::WORLDMAP_EAST
+        && tux->back_direction != D_EAST)
+      dir = D_EAST;
+    else if (tile->getData() & Tile::WORLDMAP_WEST
+        && tux->back_direction != D_WEST)
+      dir = D_WEST;
+
+    if (dir != D_NONE) {
+      tux->set_direction(dir);
+    }
+  }
+
+  if (level->extro_script != "") {
+    try {
+      HSQUIRRELVM vm = ScriptManager::instance->create_thread();
+
+      std::istringstream in(level->extro_script);
+      Scripting::compile_and_run(vm, in, "worldmap,extro_script");
+    } catch(std::exception& e) {
+      log_fatal << "Couldn't run level-extro-script: " << e.what() << std::endl;
+    }
+  }
+}
+
+void
+WorldMap::update(float delta)
+{
+  Menu* menu = Menu::current();
+  if(menu != NULL) {
+    menu->update();
+
+    if(menu == worldmap_menu.get()) {
+      switch (worldmap_menu->check())
+      {
+        case MNID_RETURNWORLDMAP: // Return to game  
+          Menu::set_current(0);
+          break;
+        case MNID_QUITWORLDMAP: // Quit Worldmap
+          main_loop->exit_screen();
+          break;
+      }
+    }
+
+    return;
+  }
+
+  // update GameObjects
+  for(GameObjects::iterator i = game_objects.begin();
+      i != game_objects.end(); ++i) {
+    GameObject* object = *i;
+    object->update(delta);
+  }
+
+  // remove old GameObjects
+  for(GameObjects::iterator i = game_objects.begin();
+      i != game_objects.end(); ) {
+    GameObject* object = *i;
+    if(!object->is_valid()) {
+      delete object;
+      i = game_objects.erase(i);
+    } else {
+      ++i;
+    }
+  }
+
+  // position "camera"
+  Vector tux_pos = tux->get_pos();
+  camera_offset.x = tux_pos.x - SCREEN_WIDTH/2;
+  camera_offset.y = tux_pos.y - SCREEN_HEIGHT/2;
+
+  if (camera_offset.x < 0)
+    camera_offset.x = 0;
+  if (camera_offset.y < 0)
+    camera_offset.y = 0;
+
+  if (camera_offset.x > solids->get_width()*32 - SCREEN_WIDTH)
+    camera_offset.x = solids->get_width()*32 - SCREEN_WIDTH;
+  if (camera_offset.y > solids->get_height()*32 - SCREEN_HEIGHT)
+    camera_offset.y = solids->get_height()*32 - SCREEN_HEIGHT;
+
+  // handle input
+  bool enter_level = false;
+  if(main_controller->pressed(Controller::ACTION)
+      || main_controller->pressed(Controller::JUMP)
+      || main_controller->pressed(Controller::MENU_SELECT))
+    enter_level = true;
+  if(main_controller->pressed(Controller::PAUSE_MENU))
+    on_escape_press();
+  
+  if (enter_level && !tux->is_moving())
+    {
+      /* Check special tile action */
+      SpecialTile* special_tile = at_special_tile();
+      if(special_tile)
+        {
+        if (special_tile->teleport_dest != Vector(-1,-1))
+          {
+          // TODO: an animation, camera scrolling or a fading would be a nice touch
+          sound_manager->play("sounds/warp.wav");
+          tux->back_direction = D_NONE;
+          tux->set_tile_pos(special_tile->teleport_dest);
+          SDL_Delay(1000);
+          }
+        }
+
+      /* Check level action */
+      Level* level = at_level();
+      if (!level) {
+        log_warning << "No level to enter at: " << tux->get_tile_pos().x << ", " << tux->get_tile_pos().y << std::endl;
+        return;
+      }
+
+      if (level->pos == tux->get_tile_pos()) {
+        // do a shriking fade to the level
+        shrink_fade(Vector((level->pos.x*32 + 16 + offset.x),
+                           (level->pos.y*32 + 16 + offset.y)), 500);
+
+        try {
+          GameSession *session =
+            new GameSession(levels_path + level->name,
+                ST_GL_LOAD_LEVEL_FILE, &level->statistics);
+          main_loop->push_screen(session);
+        } catch(std::exception& e) {
+          log_fatal << "Couldn't load level: " << e.what() << std::endl;
+        }
+      }
+    }
+  else
+    {
+//      tux->set_direction(input_direction);
+    }
+}
+
+const Tile*
+WorldMap::at(Vector p)
+{
+  return solids->get_tile((int) p.x, (int) p.y);
+}
+
+Level*
+WorldMap::at_level()
+{
+  for(Levels::iterator i = levels.begin(); i != levels.end(); ++i) {
+    Level* level = *i;
+    if (level->pos == tux->get_tile_pos())
+      return level;
+  }
+
+  return NULL;
+}
+
+SpecialTile*
+WorldMap::at_special_tile()
+{
+  for(SpecialTiles::iterator i = special_tiles.begin();
+      i != special_tiles.end(); ++i) {
+    SpecialTile* special_tile = *i;
+    if (special_tile->pos == tux->get_tile_pos())
+      return special_tile; 
+  }
+
+  return NULL;
+}
+
+SpriteChange*
+WorldMap::at_sprite_change()
+{
+  return NULL;
+}
+
+void
+WorldMap::draw(DrawingContext& context)
+{
+  context.push_transform();
+  context.set_translation(camera_offset);
+  
+  for(GameObjects::iterator i = game_objects.begin();
+      i != game_objects.end(); ++i) {
+    GameObject* object = *i;
+    object->draw(context);
+  }
+  
+  draw_status(context);
+  context.pop_transform();
+}
+
+void
+WorldMap::draw_status(DrawingContext& context)
+{
+  context.push_transform();
+  context.set_translation(Vector(0, 0));
+  player_status->draw(context);
+
+  if (!tux->is_moving()) {
+    for(Levels::iterator i = levels.begin(); i != levels.end(); ++i) {
+      Level* level = *i;
+      
+      if (level->pos == tux->get_tile_pos()) {
+        if(level->title == "")
+          get_level_title(*level);
+
+        context.draw_text(white_text, level->title,
+            Vector(SCREEN_WIDTH/2,
+              SCREEN_HEIGHT - white_text->get_height() - 30),
+            CENTER_ALLIGN, LAYER_FOREGROUND1);
+        
+        level->statistics.draw_worldmap_info(context);
+        break;
+      }
+    }
+
+    for(SpecialTiles::iterator i = special_tiles.begin();
+        i != special_tiles.end(); ++i) {
+      SpecialTile* special_tile = *i;
+      
+      if (special_tile->pos == tux->get_tile_pos()) {
+        /* Display an in-map message in the map, if any as been selected */
+        if(!special_tile->map_message.empty() && !special_tile->passive_message)
+          context.draw_text(gold_text, special_tile->map_message, 
+              Vector(SCREEN_WIDTH/2,
+                SCREEN_HEIGHT - white_text->get_height() - 60),
+              CENTER_ALLIGN, LAYER_FOREGROUND1);
+        break;
+      }
+    }
+  }
+  
+  /* Display a passive message in the map, if needed */
+  if(passive_message_timer.started())
+    context.draw_text(gold_text, passive_message, 
+            Vector(SCREEN_WIDTH/2, SCREEN_HEIGHT - white_text->get_height() - 60),
+            CENTER_ALLIGN, LAYER_FOREGROUND1);
+
+  context.pop_transform();
+}
+
+void
+WorldMap::setup()
+{
+  sound_manager->play_music(music);
+  Menu::set_current(NULL);
+
+  current_ = this;
+  load_state();
+}
+
+static void store_float(HSQUIRRELVM vm, const char* name, float val)
+{
+  sq_pushstring(vm, name, -1);
+  sq_pushfloat(vm, val);
+  if(SQ_FAILED(sq_createslot(vm, -3)))
+    throw Scripting::SquirrelError(vm, "Couldn't add float value to table");
+}
+
+/*
+static void store_int(HSQUIRRELVM vm, const char* name, int val)
+{
+  sq_pushstring(vm, name, -1);
+  sq_pushinteger(vm, val);
+  if(SQ_FAILED(sq_createslot(vm, -3)))
+    throw Scripting::SquirrelError(vm, "Couldn't add float value to table");
+}
+*/
+
+static void store_string(HSQUIRRELVM vm, const char* name, const std::string& val)
+{
+  sq_pushstring(vm, name, -1);
+  sq_pushstring(vm, val.c_str(), val.length());
+  if(SQ_FAILED(sq_createslot(vm, -3)))
+    throw Scripting::SquirrelError(vm, "Couldn't add float value to table");
+}
+
+static void store_bool(HSQUIRRELVM vm, const char* name, bool val)
+{
+  sq_pushstring(vm, name, -1);
+  sq_pushbool(vm, val ? SQTrue : SQFalse);
+  if(SQ_FAILED(sq_createslot(vm, -3)))
+    throw Scripting::SquirrelError(vm, "Couldn't add float value to table");
+}
+
+static float read_float(HSQUIRRELVM vm, const char* name)
+{
+  sq_pushstring(vm, name, -1);
+  if(SQ_FAILED(sq_get(vm, -2))) {
+    std::ostringstream msg;
+    msg << "Couldn't get float value for '" << name << "' from table";
+    throw Scripting::SquirrelError(vm, msg.str());
+  }
+  
+  float result;
+  if(SQ_FAILED(sq_getfloat(vm, -1, &result))) {
+    std::ostringstream msg;
+    msg << "Couldn't get float value for '" << name << "' from table";
+    throw Scripting::SquirrelError(vm, msg.str());
+  }
+  sq_pop(vm, 1);
+
+  return result;
+}
+
+static std::string read_string(HSQUIRRELVM vm, const char* name)
+{
+  sq_pushstring(vm, name, -1);
+  if(SQ_FAILED(sq_get(vm, -2))) {
+    std::ostringstream msg;
+    msg << "Couldn't get string value for '" << name << "' from table";
+    throw Scripting::SquirrelError(vm, msg.str());
+  }
+  
+  const char* result;
+  if(SQ_FAILED(sq_getstring(vm, -1, &result))) {
+    std::ostringstream msg;
+    msg << "Couldn't get string value for '" << name << "' from table";
+    throw Scripting::SquirrelError(vm, msg.str());
+  }
+  sq_pop(vm, 1);
+
+  return std::string(result);
+}
+
+static bool read_bool(HSQUIRRELVM vm, const char* name)
+{
+  sq_pushstring(vm, name, -1);
+  if(SQ_FAILED(sq_get(vm, -2))) {
+    std::ostringstream msg;
+    msg << "Couldn't get bool value for '" << name << "' from table";
+    throw Scripting::SquirrelError(vm, msg.str());
+  } 
+  
+  SQBool result;
+  if(SQ_FAILED(sq_getbool(vm, -1, &result))) {
+    std::ostringstream msg;
+    msg << "Couldn't get bool value for '" << name << "' from table";
+    throw Scripting::SquirrelError(vm, msg.str());
+  }
+  sq_pop(vm, 1);
+
+  return result == SQTrue;
+}
+
+void
+WorldMap::save_state()
+{
+  HSQUIRRELVM vm = ScriptManager::instance->get_vm();
+  int oldtop = sq_gettop(vm);
+
+  try {
+    // get state table
+    sq_pushroottable(vm);
+    sq_pushstring(vm, "state", -1);
+    if(SQ_FAILED(sq_get(vm, -2)))
+      throw Scripting::SquirrelError(vm, "Couldn't get state table");
+
+    // get or create worlds table
+    sq_pushstring(vm, "worlds", -1);
+    if(SQ_FAILED(sq_get(vm, -2))) {
+      sq_pushstring(vm, "worlds", -1);
+      sq_newtable(vm);
+      if(SQ_FAILED(sq_createslot(vm, -3)))
+        throw Scripting::SquirrelError(vm, "Couldn't create state.worlds");
+
+      sq_pushstring(vm, "worlds", -1);
+      if(SQ_FAILED(sq_get(vm, -2)))
+        throw Scripting::SquirrelError(vm, "Couldn't create.get state.worlds");
+    }
+    
+    sq_pushstring(vm, map_filename.c_str(), map_filename.length());
+    if(SQ_FAILED(sq_deleteslot(vm, -2, SQFalse)))
+      sq_pop(vm, 1);
+
+    // construct new table for this worldmap
+    sq_pushstring(vm, map_filename.c_str(), map_filename.length());
+    sq_newtable(vm);
+
+    // store tux
+    sq_pushstring(vm, "tux", -1);
+    sq_newtable(vm);
+    
+    store_float(vm, "x", tux->get_tile_pos().x);
+    store_float(vm, "y", tux->get_tile_pos().y);
+    store_string(vm, "back", direction_to_string(tux->back_direction));
+
+    sq_createslot(vm, -3);
+    
+    // levels...
+    sq_pushstring(vm, "levels", -1);
+    sq_newtable(vm);
+
+    for(Levels::iterator i = levels.begin(); i != levels.end(); ++i) {
+      Level* level = *i;
+      
+      if (level->solved) {
+        sq_pushstring(vm, level->name.c_str(), -1);
+        sq_newtable(vm);
+
+        store_bool(vm, "solved", true);            
+        // TODO write statistics
+        // i->statistics.write(writer);
+
+        sq_createslot(vm, -3);
+      }
+    }
+    
+    sq_createslot(vm, -3);
+
+    // push world into worlds table
+    sq_createslot(vm, -3);
+  } catch(std::exception& e) {
+    sq_settop(vm, oldtop);
+  }
+
+  sq_settop(vm, oldtop);
+}
+
+void
+WorldMap::load_state()
+{
+  HSQUIRRELVM vm = ScriptManager::instance->get_vm();
+  int oldtop = sq_gettop(vm);
+  try {
+    // get state table
+    sq_pushroottable(vm);
+    sq_pushstring(vm, "state", -1);
+    if(SQ_FAILED(sq_get(vm, -2)))
+      throw Scripting::SquirrelError(vm, "Couldn't get state table");
+
+    // get worlds table
+    sq_pushstring(vm, "worlds", -1);
+    if(SQ_FAILED(sq_get(vm, -2)))
+      throw Scripting::SquirrelError(vm, "Couldn't get state.worlds");
+
+    // get table for our world
+    sq_pushstring(vm, map_filename.c_str(), map_filename.length());
+    if(SQ_FAILED(sq_get(vm, -2)))
+      throw Scripting::SquirrelError(vm, "Couldn't get state.world.mapfilename");
+
+    // load tux
+    sq_pushstring(vm, "tux", -1);
+    if(SQ_FAILED(sq_get(vm, -2)))
+      throw Scripting::SquirrelError(vm, "Couldn't get tux");
+
+    Vector p;
+    p.x = read_float(vm, "x");
+    p.y = read_float(vm, "y");
+    std::string back_str = read_string(vm, "back");
+    tux->back_direction = string_to_direction(back_str);
+    tux->set_tile_pos(p);
+
+    sq_pop(vm, 1);
+
+    // load levels
+    sq_pushstring(vm, "levels", -1);
+    if(SQ_FAILED(sq_get(vm, -2)))
+      throw Scripting::SquirrelError(vm, "Couldn't get levels");
+
+    for(Levels::iterator i = levels.begin(); i != levels.end(); ++i) {
+      Level* level = *i;
+      sq_pushstring(vm, level->name.c_str(), -1);
+      if(SQ_SUCCEEDED(sq_get(vm, -2))) {
+        level->solved = read_bool(vm, "solved");
+        level->sprite->set_action(level->solved ? "solved" : "default");
+        // i->statistics.parse(*level);
+        sq_pop(vm, 1);
+      }
+    }
+    sq_pop(vm, 1);
+
+  } catch(std::exception& e) {
+    log_debug << "Not loading worldmap state: " << e.what() << std::endl;
+  }
+  sq_settop(vm, oldtop);
+}
+
+size_t
+WorldMap::level_count()
+{
+  return levels.size();
+}
+
+size_t
+WorldMap::solved_level_count()
+{
+  size_t count = 0;
+  for(Levels::iterator i = levels.begin(); i != levels.end(); ++i) {
+    Level* level = *i;
+    
+    if(level->solved)
+      count++;
+  }
+
+  return count;
+}
+    
+void
+WorldMap::loadmap(const std::string& filename)
+{
+  savegame_file = "";
+  map_filename = filename;
+  load_map();
+}
+
+} // namespace WorldMapNS
diff --git a/src/worldmap/worldmap.hpp b/src/worldmap/worldmap.hpp
new file mode 100644 (file)
index 0000000..b6e3a43
--- /dev/null
@@ -0,0 +1,186 @@
+//  $Id$
+//
+//  SuperTux
+//  Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.de>
+//  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#ifndef SUPERTUX_WORLDMAP_H
+#define SUPERTUX_WORLDMAP_H
+
+#include <vector>
+#include <string>
+
+#include "math/vector.hpp"
+#include "video/screen.hpp"
+#include "lisp/lisp.hpp"
+#include "control/controller.hpp"
+#include "statistics.hpp"
+#include "timer.hpp"
+#include "screen.hpp"
+#include "tile_manager.hpp"
+#include "game_object.hpp"
+#include "console.hpp"
+
+class Sprite;
+class Menu;
+class SpawnPoint;
+class GameObject;
+class TileMap;
+
+namespace WorldMapNS {
+
+class Tux;
+class Level;
+class SpecialTile;
+class SpriteChange;
+
+// For one way tiles
+enum {
+  BOTH_WAYS,
+  NORTH_SOUTH_WAY,
+  SOUTH_NORTH_WAY,
+  EAST_WEST_WAY,
+  WEST_EAST_WAY
+};
+
+enum Direction { D_NONE, D_WEST, D_EAST, D_NORTH, D_SOUTH };
+
+std::string direction_to_string(Direction d);
+Direction   string_to_direction(const std::string& d);
+Direction reverse_dir(Direction d);
+
+/** */
+class WorldMap : public Screen
+{
+private:
+  Tux* tux;
+
+  static WorldMap* current_;
+
+  std::auto_ptr<Menu> worldmap_menu;
+
+  Vector camera_offset;
+
+  std::string name;
+  std::string music;
+
+  typedef std::vector<GameObject*> GameObjects;
+  GameObjects game_objects;
+  TileMap* solids;
+  
+  std::auto_ptr<TileManager> tile_manager;
+  
+public:
+  /** Variables to deal with the passive map messages */
+  Timer passive_message_timer;
+  std::string passive_message;
+
+private:
+  std::string map_filename;
+  std::string levels_path;
+
+  typedef std::vector<SpecialTile*> SpecialTiles;
+  SpecialTiles special_tiles;
+  typedef std::vector<Level*> Levels;
+  Levels levels;
+  typedef std::vector<SpriteChange*> SpriteChanges;
+  SpriteChanges sprite_changes;
+  typedef std::vector<SpawnPoint*> SpawnPoints;
+  SpawnPoints spawn_points;
+
+  Vector offset;
+  std::string savegame_file;
+  
+  std::string intro_script;
+  bool intro_displayed;
+
+  void get_level_title(Level& level);
+
+  void draw_status(DrawingContext& context);
+
+  // to avoid calculating total stats all the time. This way only
+  // when need, it is calculated.
+  Statistics total_stats;
+  void calculate_total_stats();
+
+public:
+  WorldMap();
+  ~WorldMap();
+
+  void load_map();
+  
+  void add_object(GameObject* object);
+  void clear_objects();
+
+  static WorldMap* current()
+  { return current_; }
+
+  void setup();
+
+  /** Update Tux position */
+  void update(float delta);
+
+  /** Draw one frame */
+  void draw(DrawingContext& context);
+
+  Vector get_next_tile(Vector pos, Direction direction);
+  const Tile* at(Vector pos);
+
+  size_t level_count();
+  size_t solved_level_count();
+
+  /**
+   * gets called from the GameSession when a level has been successfully
+   * finished
+   */
+  void finished_level(const std::string& filename);
+
+  Level* at_level();
+  SpecialTile* at_special_tile();
+  SpriteChange* at_sprite_change();
+
+  /** Check if it is possible to walk from \a pos into \a direction,
+      if possible, write the new position to \a new_pos */
+  bool path_ok(Direction direction, Vector pos, Vector* new_pos);
+
+  /**
+   * Save worldmap state to squirrel state table
+   */
+  void save_state();
+  /**
+   * Load worldmap state from squirrel state table
+   */
+  void load_state();
+  /**
+   * Load a worldmap
+   */
+  void loadmap(const std::string& filename);
+
+  const std::string& get_title() const
+  { return name; }
+    
+  void set_map_filename(std::string filename)
+  { map_filename = filename; }
+
+private:
+  void on_escape_press();
+  void parse_special_tile(const lisp::Lisp* lisp);
+  void parse_sprite_change(const lisp::Lisp* lisp);
+};
+
+} // namespace WorldMapNS
+
+#endif