From: Matthias Braun Date: Fri, 14 Apr 2006 14:09:12 +0000 (+0000) Subject: split worldmap into several files, updates, use SDL_Delay earlier to reduce CPU usage... X-Git-Url: https://git.octo.it/?a=commitdiff_plain;h=112f01454123c94f5627200c6819b219026f0af0;hp=c4b99247a3ffaea12211b90994a8cf042e665b8e;p=supertux.git split worldmap into several files, updates, use SDL_Delay earlier to reduce CPU usage (hopefully this doesn't introduce jerkiness on slower systems) SVN-Revision: 3338 --- diff --git a/data/images/worldmap/common/messagedot.sprite b/data/images/worldmap/common/messagedot.sprite new file mode 100644 index 000000000..5d3f13edc --- /dev/null +++ b/data/images/worldmap/common/messagedot.sprite @@ -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 index 3bf9e0581..000000000 --- a/data/images/worldmap/common/teleporter.sprite +++ /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" - ) - ) -) diff --git a/data/images/worldmap/common/teleporterdot.sprite b/data/images/worldmap/common/teleporterdot.sprite index bc8f2302d..3bf9e0581 100644 --- a/data/images/worldmap/common/teleporterdot.sprite +++ b/data/images/worldmap/common/teleporterdot.sprite @@ -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" + ) ) ) diff --git a/data/levels/bonus1/worldmap.stwm b/data/levels/bonus1/worldmap.stwm index 3be2771cc..cc5a61402 100644 --- a/data/levels/bonus1/worldmap.stwm +++ b/data/levels/bonus1/worldmap.stwm @@ -130,6 +130,7 @@ ) (special-tile (map-message (_ "Hint: Use igloos to get back here.")) + (invisible-tile #t) (passive-message #t) (apply-to-direction "north") (x 35) @@ -141,6 +142,7 @@ (map-message (_ "Warp to Matr1x' Sector")) (x 33) (y 8) + (sprite "images/worldmap/common/teleporterdot.sprite") ) (special-tile (teleport-to-x 34) @@ -148,6 +150,7 @@ (map-message (_ "Warp to Thompson's Domain")) (x 31) (y 8) + (sprite "images/worldmap/common/teleporterdot.sprite") ) (special-tile (teleport-to-x 51) @@ -155,6 +158,7 @@ (map-message (_ "Warp to the SuperTux Team Island")) (x 35) (y 8) + (sprite "images/worldmap/common/teleporterdot.sprite") ) (special-tile (teleport-to-x 15) @@ -162,6 +166,7 @@ (map-message (_ "Warp to Abednego's Area")) (x 37) (y 8) + (sprite "images/worldmap/common/teleporterdot.sprite") ) (special-tile (teleport-to-x 61) @@ -169,6 +174,7 @@ (map-message (_ "Warp to Torfi's Territory")) (x 39) (y 8) + (sprite "images/worldmap/common/teleporterdot.sprite") ) (special-tile (teleport-to-x 32) @@ -176,6 +182,7 @@ (map-message (_ "Leave Matrix' Sector")) (x 19) (y 24) + (sprite "images/worldmap/common/teleporterdot.sprite") ) (special-tile (teleport-to-x 35) @@ -183,6 +190,7 @@ (map-message (_ "Leave Thompson's Domain")) (x 35) (y 26) + (sprite "images/worldmap/common/teleporterdot.sprite") ) (special-tile (teleport-to-x 35) @@ -190,6 +198,7 @@ (map-message (_ "Leave SuperTux Team Island")) (x 54) (y 25) + (sprite "images/worldmap/common/teleporterdot.sprite") ) (special-tile (teleport-to-x 35) @@ -197,6 +206,7 @@ (map-message (_ "Leave Abednego's Area")) (x 18) (y 43) + (sprite "images/worldmap/common/teleporterdot.sprite") ) (special-tile (teleport-to-x 35) @@ -204,6 +214,7 @@ (map-message (_ "Leave Torfi's Territory")) (x 65) (y 43) + (sprite "images/worldmap/common/teleporterdot.sprite") ) (special-tile (teleport-to-x 35) @@ -211,6 +222,7 @@ (map-message (_ "Warp home")) (x 27) (y 39) + (sprite "images/worldmap/common/teleporterdot.sprite") ) (special-tile (teleport-to-x 35) diff --git a/data/levels/bonus2/worldmap.stwm b/data/levels/bonus2/worldmap.stwm index df1c2cb90..ab356a113 100644 --- a/data/levels/bonus2/worldmap.stwm +++ b/data/levels/bonus2/worldmap.stwm @@ -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") @@ -10,225 +10,186 @@ (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") ) - diff --git a/data/levels/world1/worldmap.stwm b/data/levels/world1/worldmap.stwm index 2a68ac5b5..c152d61df 100644 --- a/data/levels/world1/worldmap.stwm +++ b/data/levels/world1/worldmap.stwm @@ -157,6 +157,7 @@ (teleport-to-y 15) (x 16) (y 25) + (sprite "images/worldmap/common/teleporterdot.sprite") ) (special-tile (teleport-to-x 1) @@ -170,6 +171,7 @@ (teleport-to-y 4) (x 1) (y 26) + (sprite "images/worldmap/common/teleporterdot.sprite") ) (special-tile (teleport-to-x 0) diff --git a/src/Jamfile b/src/Jamfile index 38492e855..b1ca0c4af 100644 --- a/src/Jamfile +++ b/src/Jamfile @@ -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) ] ; diff --git a/src/game_session.cpp b/src/game_session.cpp index 26301fabb..1532e3942 100644 --- a/src/game_session.cpp +++ b/src/game_session.cpp @@ -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); diff --git a/src/mainloop.cpp b/src/mainloop.cpp index 523db813f..1be011437 100644 --- a/src/mainloop.cpp +++ b/src/mainloop.cpp @@ -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(); } diff --git a/src/misc.cpp b/src/misc.cpp index 5971a239f..2dba5aa03 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -28,19 +28,18 @@ #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(); diff --git a/src/resources.cpp b/src/resources.cpp index 2bf601e13..940b0a06b 100644 --- a/src/resources.cpp +++ b/src/resources.cpp @@ -28,18 +28,15 @@ #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; diff --git a/src/resources.hpp b/src/resources.hpp index b8152e58b..feaca220b 100644 --- a/src/resources.hpp +++ b/src/resources.hpp @@ -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; diff --git a/src/scripting/functions.cpp b/src/scripting/functions.cpp index 96694698e..b7a377903 100644 --- a/src/scripting/functions.cpp +++ b/src/scripting/functions.cpp @@ -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" diff --git a/src/sprite/sprite_manager.cpp b/src/sprite/sprite_manager.cpp index 999c254e7..411255b54 100644 --- a/src/sprite/sprite_manager.cpp +++ b/src/sprite/sprite_manager.cpp @@ -32,6 +32,8 @@ #include "file_system.hpp" #include "log.hpp" +SpriteManager* sprite_manager = NULL; + SpriteManager::SpriteManager() { } diff --git a/src/sprite/sprite_manager.hpp b/src/sprite/sprite_manager.hpp index 48dca2783..4ebe6c0fd 100644 --- a/src/sprite/sprite_manager.hpp +++ b/src/sprite/sprite_manager.hpp @@ -42,4 +42,6 @@ private: SpriteData* load(const std::string& filename); }; +extern SpriteManager* sprite_manager; + #endif diff --git a/src/tile_manager.cpp b/src/tile_manager.cpp index d301867e3..309311e3e 100644 --- a/src/tile_manager.cpp +++ b/src/tile_manager.cpp @@ -35,6 +35,8 @@ #include "tile_manager.hpp" #include "resources.hpp" +TileManager* tile_manager = NULL; + TileManager::TileManager(const std::string& filename) { #ifdef DEBUG diff --git a/src/tile_manager.hpp b/src/tile_manager.hpp index 585b3f846..319b81910 100644 --- a/src/tile_manager.hpp +++ b/src/tile_manager.hpp @@ -97,4 +97,6 @@ public: } }; +extern TileManager* tile_manager; + #endif diff --git a/src/title.cpp b/src/title.cpp index 579598c77..a68866730 100644 --- a/src/title.cpp +++ b/src/title.cpp @@ -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" diff --git a/src/world.cpp b/src/world.cpp index 4d9d8118e..6c3a5fbd6 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -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 index 0ce2a3e0a..000000000 --- a/src/worldmap.cpp +++ /dev/null @@ -1,1235 +0,0 @@ -// $Id$ -// -// SuperTux - A Jump'n Run -// Copyright (C) 2004 Ingo Ruhnke -// Copyright (C) 2006 Christoph Sommer -// -// 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 - -#include -#include -#include -#include -#include -#include -#include -#include - -#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 = ""; - 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 (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 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 = ""; - - try { - lisp::Parser parser; - std::auto_ptr 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 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 index 741863c3f..000000000 --- a/src/worldmap.hpp +++ /dev/null @@ -1,296 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2004 Ingo Ruhnke -// Copyright (C) 2006 Christoph Sommer -// -// 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 -#include - -#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 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 SpecialTiles; - SpecialTiles special_tiles; - typedef std::vector Levels; - Levels levels; - typedef std::vector 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 index 000000000..c4fc95113 --- /dev/null +++ b/src/worldmap/level.cpp @@ -0,0 +1,67 @@ +// $Id: worldmap.hpp 3327 2006-04-13 15:02:40Z ravu_al_hemio $ +// +// SuperTux +// Copyright (C) 2004 Ingo Ruhnke +// Copyright (C) 2006 Christoph Sommer +// +// 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 + +#include +#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 index 000000000..8e79f3edd --- /dev/null +++ b/src/worldmap/level.hpp @@ -0,0 +1,63 @@ +// $Id: worldmap.hpp 3327 2006-04-13 15:02:40Z ravu_al_hemio $ +// +// SuperTux +// Copyright (C) 2004 Ingo Ruhnke +// Copyright (C) 2006 Christoph Sommer +// +// 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 +#include +#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; + + /** 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 index 000000000..201458a78 --- /dev/null +++ b/src/worldmap/special_tile.cpp @@ -0,0 +1,87 @@ +// $Id: worldmap.hpp 3327 2006-04-13 15:02:40Z ravu_al_hemio $ +// +// SuperTux +// Copyright (C) 2004 Ingo Ruhnke +// Copyright (C) 2006 Christoph Sommer +// +// 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 + +#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 index 000000000..f958d9bcf --- /dev/null +++ b/src/worldmap/special_tile.hpp @@ -0,0 +1,68 @@ +// $Id: worldmap.hpp 3327 2006-04-13 15:02:40Z ravu_al_hemio $ +// +// SuperTux +// Copyright (C) 2004 Ingo Ruhnke +// Copyright (C) 2006 Christoph Sommer +// +// 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 +#include +#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; + + /** 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 index 000000000..7eb044f09 --- /dev/null +++ b/src/worldmap/sprite_change.cpp @@ -0,0 +1,58 @@ +// $Id: worldmap.hpp 3327 2006-04-13 15:02:40Z ravu_al_hemio $ +// +// SuperTux +// Copyright (C) 2004 Ingo Ruhnke +// Copyright (C) 2006 Christoph Sommer +// +// 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 + +#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 index 000000000..c572309d4 --- /dev/null +++ b/src/worldmap/sprite_change.hpp @@ -0,0 +1,66 @@ +// $Id: worldmap.hpp 3327 2006-04-13 15:02:40Z ravu_al_hemio $ +// +// SuperTux +// Copyright (C) 2004 Ingo Ruhnke +// Copyright (C) 2006 Christoph Sommer +// +// 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 +#include +#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; + /** + * 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 index 000000000..ade0588b9 --- /dev/null +++ b/src/worldmap/tux.cpp @@ -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 +// Copyright (C) 2006 Christoph Sommer +// +// 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 + +#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 index 000000000..173bbecf7 --- /dev/null +++ b/src/worldmap/tux.hpp @@ -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 +// Copyright (C) 2006 Christoph Sommer +// +// 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 +#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; + 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 index 000000000..84423f391 --- /dev/null +++ b/src/worldmap/worldmap.cpp @@ -0,0 +1,908 @@ +// $Id$ +// +// SuperTux - A Jump'n Run +// Copyright (C) 2004 Ingo Ruhnke +// Copyright (C) 2006 Christoph Sommer +// +// 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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 = ""; + 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 (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 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 = ""; + + try { + lisp::Parser parser; + std::auto_ptr 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 index 000000000..b6e3a4377 --- /dev/null +++ b/src/worldmap/worldmap.hpp @@ -0,0 +1,186 @@ +// $Id$ +// +// SuperTux +// Copyright (C) 2004 Ingo Ruhnke +// Copyright (C) 2006 Christoph Sommer +// +// 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 +#include + +#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 worldmap_menu; + + Vector camera_offset; + + std::string name; + std::string music; + + typedef std::vector GameObjects; + GameObjects game_objects; + TileMap* solids; + + std::auto_ptr 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 SpecialTiles; + SpecialTiles special_tiles; + typedef std::vector Levels; + Levels levels; + typedef std::vector SpriteChanges; + SpriteChanges sprite_changes; + typedef std::vector 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