refactored some supertux mainloops
authorMatthias Braun <matze@braunis.de>
Fri, 7 Apr 2006 13:37:56 +0000 (13:37 +0000)
committerMatthias Braun <matze@braunis.de>
Fri, 7 Apr 2006 13:37:56 +0000 (13:37 +0000)
SVN-Revision: 3262

51 files changed:
data/credits.txt
data/images/creatures/tux_small/tux-life.sprite [new file with mode: 0644]
data/images/engine/editor/README [new file with mode: 0644]
data/images/engine/editor/camera.png [new file with mode: 0644]
data/images/worldmap/common/teleporterdot.sprite [new file with mode: 0644]
data/levels/misc/menu.stl
data/levels/test/default.nut
data/levels/world1/extro.txt
data/levels/world1/worldmap.stwm
data/levels/world2/dfk-level3.stl
data/levels/world2/info
src/console.cpp
src/console.hpp
src/control/controller.cpp
src/control/controller.hpp
src/game_session.cpp
src/game_session.hpp
src/gui/menu.cpp
src/gui/menu.hpp
src/level_subset.cpp [deleted file]
src/level_subset.hpp [deleted file]
src/lisp/lisp.hpp
src/main.cpp
src/mainloop.cpp [new file with mode: 0644]
src/mainloop.hpp [new file with mode: 0644]
src/misc.cpp
src/misc.hpp
src/object/floating_image.cpp
src/object/player.hpp
src/player_status.cpp
src/player_status.hpp
src/resources.cpp
src/resources.hpp
src/screen.hpp [new file with mode: 0644]
src/scripting/functions.cpp
src/scripting/level.cpp
src/scripting/level.hpp
src/scripting/wrapper.cpp
src/sector.cpp
src/textscroller.cpp
src/textscroller.hpp
src/tile_manager.cpp
src/title.cpp
src/title.hpp
src/video/screen.cpp
src/video/screen.hpp
src/video/texture_manager.cpp
src/world.cpp [new file with mode: 0644]
src/world.hpp [new file with mode: 0644]
src/worldmap.cpp
src/worldmap.hpp

index 6ad9a2c..c3a1f55 100644 (file)
@@ -1,7 +1,8 @@
 ; Credits text
 (supertux-text
   (background "oiltux.jpg")
-  (speed 1.5)
+  (music "music/credits.ogg")
+  (speed 30)
 
   (text (_ "!images/credits/milestone.png
 
@@ -27,6 +28,8 @@
 
        Ryan \"sik0fewl\" Flegel
 
+       Christoph Sommer
+
        Bastiaan \"basti_\" Zapf
 
        Marek \"Wansti\" Moeckel
@@ -41,7 +44,6 @@
 
        Richard Smith
 
-       Christoph Sommer
 
 -Graphics
 
diff --git a/data/images/creatures/tux_small/tux-life.sprite b/data/images/creatures/tux_small/tux-life.sprite
new file mode 100644 (file)
index 0000000..be6476e
--- /dev/null
@@ -0,0 +1,6 @@
+(supertux-sprite
+  (action
+    (name "default")
+    (images "tux-life.png")
+  )
+)
diff --git a/data/images/engine/editor/README b/data/images/engine/editor/README
new file mode 100644 (file)
index 0000000..60051d1
--- /dev/null
@@ -0,0 +1,2 @@
+camera.png from tango-project.org
+
diff --git a/data/images/engine/editor/camera.png b/data/images/engine/editor/camera.png
new file mode 100644 (file)
index 0000000..3350f52
Binary files /dev/null and b/data/images/engine/editor/camera.png differ
diff --git a/data/images/worldmap/common/teleporterdot.sprite b/data/images/worldmap/common/teleporterdot.sprite
new file mode 100644 (file)
index 0000000..bc8f230
--- /dev/null
@@ -0,0 +1,8 @@
+(supertux-sprite
+  (action
+    (name "default")
+    (x-offset 16)
+    (y-offset 16)
+    (images "teleporterdot.png")
+  )
+)
index 93fff4d..db89645 100644 (file)
@@ -9,6 +9,13 @@
     (gravity 10.000000)
     (background (image "images/background/arctis.jpg")
                 (speed 0.5))
+    (init-script "
+logo <- FloatingImage(\"images/objects/logo/logo.sprite\");
+logo.set_anchor_point(ANCHOR_TOP);
+logo.set_pos(0, 30);
+logo.set_visible(true);
+wait(10000);
+")
     (tilemap
       (layer  "background")
       (solid #f)
index 53a21c3..d569d68 100644 (file)
@@ -78,7 +78,7 @@ function intro()
   //end intro sequence
   DisplayEffect.fade_out(2);
   wait(3);
-  Level.finish();
+  Level.finish(true);
 }
 
 function shake_bush()
@@ -124,6 +124,6 @@ function intro_scene2()
   SUPERTUX.set_visible(true);
   SUPERTUX.set_velocity(300,0);
   wait(24);
-  Level.finish();
+  Level.finish(true);
 }
 
index 72dca8b..b0a6a68 100644 (file)
@@ -2,7 +2,6 @@
 (supertux-text
   (background "extro.jpg")
   (music "music/theme.ogg")
-  (show-after "CREDITS")
 
   (text (_ "-Entering Nolok's Throne Room!
 
index 3d985a7..9176c5f 100644 (file)
     (special-tile
       (teleport-to-x 9)
       (teleport-to-y 15)
-      (map-message (_ ""))
       (x 16)
       (y 25)
     )
     (special-tile
       (teleport-to-x 1)
       (teleport-to-y 26)
-      (map-message (_ ""))
       (invisible-tile #t)
       (x 29)
       (y 18)
     (special-tile
       (teleport-to-x 22)
       (teleport-to-y 4)
-      (map-message (_ ""))
       (x 1)
       (y 26)
     )
index 3def2df..bc716c0 100644 (file)
     )
 
        (spawnpoint (name "main") (x 64) (y 11040))
-       (background
+       (gradient
          (top_color 0 0 0.2)
          (bottom_color 0 0 0.6)
          (speed 1.000000)
       (mode "normal")
     )
 
-       (background
+       (gradient
          (top_color 0 0 0.2)
          (bottom_color 0 0 0.6)
          (speed 1.000000)
index 807578d..37ef529 100644 (file)
@@ -1,6 +1,6 @@
-;SuperTux-Level-Subset
-(supertux-level-subset
+(supertux-world
   (title "Forest World")
   (description "World 2")
   (hide-from-contribs #f)
-  )
+  (levelset #f)
+)
index 78acb1e..bf7b28e 100644 (file)
@@ -30,7 +30,7 @@ namespace {
   int ticks; // TODO: use a clock?
 }
 
-Console::Console(DrawingContext* context) : context(context)
+Console::Console()
 {
   background = new Surface("images/engine/console.jpg");
 }
@@ -106,7 +106,7 @@ Console::hide()
 }
 
 void 
-Console::draw(
+Console::draw(DrawingContext& context)
 {
   if (height == 0) return;
   if (!focused) {
@@ -118,21 +118,21 @@ Console::draw()
     if (height == 0) return;
   }
 
-  context->draw_surface(background, Vector(SCREEN_WIDTH/2 - background->get_width()/2, height - background->get_height()), LAYER_FOREGROUND1+1);
+  context.draw_surface(background, Vector(SCREEN_WIDTH/2 - background->get_width()/2, height - background->get_height()), LAYER_FOREGROUND1+1);
 
   int lineNo = 0;
 
   if (focused) {
     lineNo++;
     float py = height-4-1*9;
-    context->draw_text(white_small_text, "> "+inputBuffer.str(), Vector(4, py), LEFT_ALLIGN, LAYER_FOREGROUND1+1);
+    context.draw_text(white_small_text, "> "+inputBuffer.str(), Vector(4, py), LEFT_ALLIGN, LAYER_FOREGROUND1+1);
   }
 
   for (std::list<std::string>::iterator i = lines.begin(); i != lines.end(); i++) {
     lineNo++;
     float py = height-4-lineNo*9;
     if (py < -9) break;
-    context->draw_text(white_small_text, *i, Vector(4, py), LEFT_ALLIGN, LAYER_FOREGROUND1+1);
+    context.draw_text(white_small_text, *i, Vector(4, py), LEFT_ALLIGN, LAYER_FOREGROUND1+1);
   }
 }
 
index b4fb85a..3238691 100644 (file)
@@ -34,7 +34,7 @@ class Surface;
 class Console 
 {
   public:
-    Console(DrawingContext* context);
+    Console();
     ~Console();
 
     static std::ostream input; /**< stream of keyboard input to send to the console. Do not forget to send std::endl or to flush the stream. */
@@ -42,7 +42,7 @@ class Console
 
     static void flush(ConsoleStreamBuffer* buffer); /**< act upon changes in a stream, normally called by the stream itself */
 
-    void draw(); /**< draw the console to its */
+    void draw(DrawingContext& context); /**< draw the console to its */
     static void show(); /**< display the console */
     static void hide(); /**< hide the console */
     static bool hasFocus(); /**< true if characters should be sent to the console instead of their normal target */
index 73f93af..db924af 100644 (file)
@@ -65,6 +65,12 @@ Controller::pressed(Control control)
   return oldControls[control] == false && controls[control] == true;
 }
 
+bool
+Controller::released(Control control)
+{
+  return oldControls[control] == true && controls[control] == false;
+}
+
 void
 Controller::update()
 {
index 50cdb17..f320825 100644 (file)
@@ -46,6 +46,8 @@ public:
   bool hold(Control control);
   /** returns true if the control has just been pressed down this frame */
   bool pressed(Control control);
+  /** returns true if the control has just been released down this frame */ 
+  bool released(Control control);
 
   virtual void reset();
   virtual void update();
index 5e77dc4..7269678 100644 (file)
@@ -36,6 +36,8 @@
 
 #include "game_session.hpp"
 #include "msg.hpp"
+#include "worldmap.hpp"
+#include "mainloop.hpp"
 #include "video/screen.hpp"
 #include "audio/sound_manager.hpp"
 #include "gui/menu.hpp"
@@ -73,6 +75,8 @@
 // binary fraction...
 static const float LOGICAL_FPS = 64.0;
 
+using namespace WorldMapNS;
+
 GameSession* GameSession::current_ = 0;
 
 GameSession::GameSession(const std::string& levelfile_, GameSessionMode mode,
@@ -88,8 +92,6 @@ GameSession::GameSession(const std::string& levelfile_, GameSessionMode mode,
   game_pause = false;
   fps_fps = 0;
 
-  context = new DrawingContext();
-  console = new Console(context);
   Console::registerCommandReceiver(this);
 
   restart_level(true);
@@ -99,7 +101,6 @@ void
 GameSession::restart_level(bool fromBeginning)
 {
   game_pause   = false;
-  exit_status  = ES_NONE;
   end_sequence = NO_ENDSEQUENCE;
 
   main_controller->reset();
@@ -165,9 +166,7 @@ GameSession::~GameSession()
 
   delete end_sequence_controller;
   delete level;
-  delete context;
   Console::unregisterCommandReceiver(this);
-  delete console;
 
   current_ = NULL;
 }
@@ -243,9 +242,6 @@ GameSession::levelintro()
   if(best_level_statistics != NULL)
     best_level_statistics->draw_message_info(context, _("Best Level Statistics"));
 
-  console->draw();
-  context.do_drawing();
-
   wait_for_event(1.0, 3.0);
 }
 
@@ -256,7 +252,7 @@ GameSession::on_escape_press()
     return;   // don't let the player open the menu, when he is dying
   
   if(mode == ST_GL_TEST) {
-    exit_status = ES_LEVEL_ABORT;
+    main_loop->exit_screen();
   } else if (!Menu::current()) {
     Menu::set_current(game_menu);
     game_menu->set_active_item(MNID_CONTINUE);
@@ -270,7 +266,6 @@ void
 GameSession::process_events()
 {
   Player& tux = *currentsector->player;
-  main_controller->update();
 
   // end of pause mode?
   if(!Menu::current() && game_pause) {
@@ -290,17 +285,6 @@ GameSession::process_events()
     last_x_pos = tux.get_pos().x;
   }
 
-  main_controller->update();
-  SDL_Event event;
-  while (SDL_PollEvent(&event)) {
-    /* Check for menu-events, if the menu is shown */
-    if (Menu::current())
-      Menu::current()->event(event);
-    main_controller->process_event(event);
-    if(event.type == SDL_QUIT)
-      throw graceful_shutdown();
-  }
-
   // playback a demo?
   if(playback_demo_stream != 0) {
     demo_controller->update();
@@ -431,9 +415,10 @@ GameSession::consoleCommand(std::string command)
     return true;
   }
   if (command == "finish") {
-    // finish current sector
-    exit_status = ES_LEVEL_FINISHED;
-    // don't add points to stats though...
+    if(WorldMap::current() != NULL) {
+      WorldMap::current()->finished_level(levelfile);
+    }
+
     return true;
   }
   if (command == "camera") {
@@ -453,7 +438,7 @@ GameSession::check_end_conditions()
 
   /* End of level? */
   if(end_sequence && endsequence_timer.check()) {
-    exit_status = ES_LEVEL_FINISHED;
+    finish(true);
     
     // add time spent to statistics
     int tottime = 0, remtime = 0;
@@ -491,57 +476,20 @@ GameSession::check_end_conditions()
   }
 }
 
-void
-GameSession::update(float elapsed_time)
-{
-  // handle controller
-  if(main_controller->pressed(Controller::PAUSE_MENU))
-    on_escape_press();
-  
-  // advance timers
-  if(!currentsector->player->growing_timer.started()) {
-    // Update Tux and the World
-    currentsector->update(elapsed_time);
-  }
-
-  // respawning in new sector?
-  if(newsector != "" && newspawnpoint != "") {
-    Sector* sector = level->get_sector(newsector);
-    if(sector == 0) {
-      msg_warning("Sector '" << newsector << "' not found");
-    }
-    sector->activate(newspawnpoint);
-    sector->play_music(LEVEL_MUSIC);
-    currentsector = sector;
-    newsector = "";
-    newspawnpoint = "";
-  }
-
-  // update sounds
-  sound_manager->set_listener_position(currentsector->player->get_pos());
-}
-
 void 
-GameSession::draw()
+GameSession::draw(DrawingContext& context)
 {
-  currentsector->draw(*context);
-  drawstatus(*context);
+  currentsector->draw(context);
+  drawstatus(context);
 
   if(game_pause)
-    draw_pause();
-
-  if(Menu::current()) {
-    Menu::current()->draw(*context);
-  }
-
-  console->draw();
-  context->do_drawing();
+    draw_pause(context);
 }
 
 void
-GameSession::draw_pause()
+GameSession::draw_pause(DrawingContext& context)
 {
-  context->draw_filled_rect(
+  context.draw_filled_rect(
       Vector(0,0), Vector(SCREEN_WIDTH, SCREEN_HEIGHT),
       Color(.2, .2, .2, .5), LAYER_FOREGROUND1);
 }
@@ -560,18 +508,77 @@ GameSession::process_menu()
           break;
         case MNID_ABORTLEVEL:
           Menu::set_current(0);
-          exit_status = ES_LEVEL_ABORT;
+          main_loop->exit_screen();
           break;
       }
     } else if(menu == options_menu) {
       process_options_menu();
-    } else if(menu == load_game_menu ) {
-      process_load_game_menu();
     }
   }
 }
 
+void
+GameSession::setup()
+{
+  Menu::set_current(NULL);
+  current_ = this;
+
+  // Eat unneeded events
+  SDL_Event event;
+  while(SDL_PollEvent(&event))
+  {}
+}
+
+void
+GameSession::update(float elapsed_time)
+{
+  process_events();
+  process_menu();
 
+  check_end_conditions();
+
+  // handle controller
+  if(main_controller->pressed(Controller::PAUSE_MENU))
+    on_escape_press();
+  
+  // respawning in new sector?
+  if(newsector != "" && newspawnpoint != "") {
+    Sector* sector = level->get_sector(newsector);
+    if(sector == 0) {
+      msg_warning("Sector '" << newsector << "' not found");
+    }
+    sector->activate(newspawnpoint);
+    sector->play_music(LEVEL_MUSIC);
+    currentsector = sector;
+    newsector = "";
+    newspawnpoint = "";
+  }
+
+  // Update the world state and all objects in the world
+  if(!game_pause) {
+    // Update the world
+    if (end_sequence == ENDSEQUENCE_RUNNING) {
+      currentsector->update(elapsed_time/2);
+    } else if(end_sequence == NO_ENDSEQUENCE) {
+      if(!currentsector->player->growing_timer.started())
+        currentsector->update(elapsed_time);
+    } 
+  }
+
+  // update sounds
+  sound_manager->set_listener_position(currentsector->player->get_pos());
+
+  /* Handle music: */
+  if (currentsector->player->invincible_timer.started() && 
+      currentsector->player->invincible_timer.get_timeleft() 
+      > TUX_INVINCIBLE_TIME_WARNING && !end_sequence) {
+    currentsector->play_music(HERRING_MUSIC);
+  } else if(currentsector->get_music_type() != LEVEL_MUSIC && !end_sequence) {
+    currentsector->play_music(LEVEL_MUSIC);
+  }
+}
+
+#if 0
 GameSession::ExitStatus
 GameSession::run()
 {
@@ -594,6 +601,8 @@ GameSession::run()
 
   while (exit_status == ES_NONE) {
     // we run in a logical framerate so elapsed time is a constant
+    // This will make the game run determistic and not different on different
+    // machines
     static const float elapsed_time = 1.0 / LOGICAL_FPS;
     // old code... float elapsed_time = float(ticks - lastticks) / 1000.;
     if(!game_pause)
@@ -624,25 +633,11 @@ GameSession::run()
     }
     fps_nextframe_ticks = ticks + (Uint32) (1000.0 / LOGICAL_FPS);
 
-#if 0
-    float diff = SDL_GetTicks() - fps_nextframe_ticks;
-    if (diff > 5.0) {
-         // sets the ticks that must have elapsed
-       fps_nextframe_ticks = SDL_GetTicks() + (1000.0 / LOGICAL_FPS);
-    } else {
-        // sets the ticks that must have elapsed
-        // in order for the next frame to start.
-       fps_nextframe_ticks += 1000.0 / LOGICAL_FPS;
-    }
-#endif
-
     process_events();
     process_menu();
 
     // Update the world state and all objects in the world
-    // Do that with a constante time-delta so that the game will run
-    // determistic and not different on different machines
-    if(!game_pause && !Menu::current())
+    if(!game_pause)
     {
       // Update the world
       check_end_conditions();
@@ -651,10 +646,6 @@ GameSession::run()
       else if(end_sequence == NO_ENDSEQUENCE)
         update(elapsed_time);
     }
-    else
-    {
-      ++pause_menu_frame;
-    }
 
     if(!skipdraw)
       draw();
@@ -668,8 +659,6 @@ GameSession::run()
       continue;
     }
 
-    //frame_rate.update();
-    
     /* Handle music: */
     if (currentsector->player->invincible_timer.started() && 
             currentsector->player->invincible_timer.get_timeleft() 
@@ -702,14 +691,17 @@ GameSession::run()
   main_controller->reset();
   return exit_status;
 }
+#endif
 
 void
 GameSession::finish(bool win)
 {
-  if(win)
-    exit_status = ES_LEVEL_FINISHED;
-  else
-    exit_status = ES_LEVEL_ABORT;
+  if(win) {
+    if(WorldMap::current())
+      WorldMap::current()->finished_level(levelfile);
+  }
+  
+  main_loop->exit_screen();
 }
 
 void
@@ -738,6 +730,8 @@ GameSession::display_info_box(const std::string& text)
   InfoBox* box = new InfoBox(text);
 
   bool running = true;
+  DrawingContext context;
+  
   while(running)  {
 
     main_controller->update();
@@ -757,8 +751,9 @@ GameSession::display_info_box(const std::string& text)
       box->scrolldown();
     else if(main_controller->pressed(Controller::UP))
       box->scrollup();
-    box->draw(*context);
-    draw();
+    box->draw(context);
+    draw(context);
+    context.do_drawing();
     sound_manager->update();
   }
 
@@ -819,93 +814,3 @@ GameSession::drawstatus(DrawingContext& context)
   }
 }
 
-void
-GameSession::drawresultscreen()
-{
-  char str[80];
-
-  DrawingContext context;
-  for(Sector::GameObjects::iterator i = currentsector->gameobjects.begin();
-      i != currentsector->gameobjects.end(); ++i) {
-    Background* background = dynamic_cast<Background*> (*i);
-    if(background) {
-      background->draw(context);
-    }
-  }
-
-  context.draw_text(blue_text, _("Result:"), Vector(SCREEN_WIDTH/2, 200),
-      CENTER_ALLIGN, LAYER_FOREGROUND1);
-
-//  sprintf(str, _("SCORE: %d"), global_stats.get_points(SCORE_STAT));
-//  context.draw_text(gold_text, str, Vector(SCREEN_WIDTH/2, 224), CENTER_ALLIGN, LAYER_FOREGROUND1);
-
-  // y == 256 before removal of score
-  sprintf(str, _("COINS: %d"), player_status->coins);
-  context.draw_text(gold_text, str, Vector(SCREEN_WIDTH/2, 224), CENTER_ALLIGN, LAYER_FOREGROUND1);
-
-  console->draw();
-  context.do_drawing();
-  
-  wait_for_event(2.0, 5.0);
-}
-
-std::string slotinfo(int slot)
-{
-  std::string tmp;
-  std::string slotfile;
-  std::string title;
-  std::stringstream stream;
-  stream << slot;
-  slotfile = "save/slot" + stream.str() + ".stsg";
-
-  try {
-    lisp::Parser parser;
-    std::auto_ptr<lisp::Lisp> root (parser.parse(slotfile));
-
-    const lisp::Lisp* savegame = root->get_lisp("supertux-savegame");
-    if(!savegame)
-      throw std::runtime_error("file is not a supertux-savegame.");
-
-    savegame->get("title", title);
-  } catch(std::exception& e) {
-    return std::string(_("Slot")) + " " + stream.str() + " - " +
-      std::string(_("Free"));
-  }
-
-  return std::string("Slot ") + stream.str() + " - " + title;
-}
-
-bool process_load_game_menu()
-{
-  int slot = load_game_menu->check();
-
-  if(slot == -1)
-    return false;
-  
-  if(load_game_menu->get_item_by_id(slot).kind != MN_ACTION)
-    return false;
-  
-  std::stringstream stream;
-  stream << slot;
-  std::string slotfile = "save/slot" + stream.str() + ".stsg";
-
-  sound_manager->stop_music();
-  fadeout(256);
-  DrawingContext context;
-  context.draw_text(white_text, "Loading...",
-                    Vector(SCREEN_WIDTH/2, SCREEN_HEIGHT/2),
-                    CENTER_ALLIGN, LAYER_FOREGROUND1);
-  context.do_drawing();
-
-  WorldMapNS::WorldMap worldmap;
-
-  worldmap.set_map_filename("/levels/world1/worldmap.stwm");
-  // Load the game or at least set the savegame_file variable
-  worldmap.loadgame(slotfile);
-
-  worldmap.display();
-
-  Menu::set_current(main_menu);
-
-  return true;
-}
index 830428d..57edaa4 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <string>
 #include <SDL.h>
+#include "screen.hpp"
 #include "timer.hpp"
 #include "statistics.hpp"
 #include "math/vector.hpp"
@@ -50,32 +51,28 @@ class Statistics;
 class DrawingContext;
 class CodeController;
 
-/** The GameSession class controlls the controll flow of a World, ie.
-    present the menu on specifc keypresses, render and update it while
-    keeping the speed and framerate sane, etc. */
-class GameSession : public ConsoleCommandReceiver
+/**
+ * The GameSession class controlls the controll flow of the Game (the part
+ * where you actually play a level)
+ */
+class GameSession : public Screen, public ConsoleCommandReceiver
 {
 public:
-  enum ExitStatus { ES_NONE, ES_LEVEL_FINISHED, /*ES_GAME_OVER,*/ ES_LEVEL_ABORT };
-
-public:
-  DrawingContext* context;
-
   GameSession(const std::string& levelfile, GameSessionMode mode,
-              Statistics* statistics=0);
+              Statistics* statistics = NULL);
   ~GameSession();
 
-  /** Enter the busy loop */
-  ExitStatus run();
-
   void record_demo(const std::string& filename);
   void play_demo(const std::string& filename);
-  void draw();
+
+  void draw(DrawingContext& context);
   void update(float frame_ratio);
+  void setup();
 
   void set_current()
   { current_ = this; }
-  static GameSession* current() { return current_; }
+  static GameSession* current()
+  { return current_; }
 
   /// ends the current level
   void finish(bool win = true);
@@ -84,6 +81,7 @@ public:
   void set_reset_point(const std::string& sectorname,
       const Vector& pos);
   void display_info_box(const std::string& text);
+  
   Sector* get_current_sector()
   { return currentsector; }
 
@@ -108,9 +106,7 @@ private:
 
   void levelintro();
   void drawstatus(DrawingContext& context);
-  void drawendscreen();
-  void drawresultscreen();
-  void draw_pause();
+  void draw_pause(DrawingContext& context);
 
   void on_escape_press();
   void process_menu();
@@ -150,7 +146,6 @@ private:
   static GameSession* current_;
 
   Statistics* best_level_statistics;
-  ExitStatus exit_status;
 
   std::ostream* capture_demo_stream;
   std::string capture_file;
@@ -159,10 +154,5 @@ private:
   Console* console;
 };
 
-std::string slotinfo(int slot);
-
-/** Return true if the gameloop() was entered, false otherwise */
-bool process_load_game_menu();
-
 #endif /*SUPERTUX_GAMELOOP_H*/
 
index 7b2868f..052a54d 100644 (file)
@@ -45,12 +45,6 @@ static const int FLICK_CURSOR_TIME = 500;
 
 extern SDL_Surface* screen;
 
-Surface* checkbox;
-Surface* checkbox_checked;
-Surface* back;
-Surface* arrow_left;
-Surface* arrow_right;
-
 std::vector<Menu*> Menu::last_menus;
 Menu* Menu::current_ = 0;
 Font* Menu::default_font;
@@ -211,6 +205,12 @@ Menu::Menu()
   pos_y        = SCREEN_HEIGHT/2;
   arrange_left = 0;
   active_item  = -1;
+
+  checkbox.reset(new Surface("images/engine/menu/checkbox-unchecked.png"));
+  checkbox_checked.reset(new Surface("images/engine/menu/checkbox-checked.png"));
+  back.reset(new Surface("images/engine/menu/arrow-back.png"));
+  arrow_left.reset(new Surface("images/engine/menu/arrow-left.png"));
+  arrow_right.reset(new Surface("images/engine/menu/arrow-right.png"));
 }
 
 void Menu::set_pos(float x, float y, float rw, float rh)
@@ -600,10 +600,10 @@ Menu::draw_item(DrawingContext& context, int index)
         int text_pos   = (text_width + 16)/2;
 
         /* Draw arrows */
-        context.draw_surface(arrow_left,
+        context.draw_surface(arrow_left.get(),
                              Vector(x_pos - list_pos + text_pos - 17, y_pos - 8),
                              LAYER_GUI);
-        context.draw_surface(arrow_right,
+        context.draw_surface(arrow_right.get(),
                              Vector(x_pos - list_pos + text_pos - 1 + list_pos_2, y_pos - 8),
                              LAYER_GUI);
 
@@ -630,7 +630,7 @@ Menu::draw_item(DrawingContext& context, int index)
         context.draw_text(text_font, pitem.text,
                           Vector(SCREEN_WIDTH/2, y_pos - int(text_font->get_height()/2)),
                           CENTER_ALLIGN, LAYER_GUI);
-        context.draw_surface(back,
+        context.draw_surface(back.get(),
                              Vector(x_pos + text_width/2  + 16, y_pos - 8),
                              LAYER_GUI);
         break;
@@ -643,11 +643,11 @@ Menu::draw_item(DrawingContext& context, int index)
                           CENTER_ALLIGN, LAYER_GUI);
 
         if(pitem.toggled)
-          context.draw_surface(checkbox_checked,
+          context.draw_surface(checkbox_checked.get(),
                                Vector(x_pos + (text_width+16)/2, y_pos - 8),
                                LAYER_GUI + 1);
         else
-          context.draw_surface(checkbox,
+          context.draw_surface(checkbox.get(),
                                Vector(x_pos + (text_width+16)/2, y_pos - 8),
                                LAYER_GUI + 1);
         break;
index 302a402..9b63088 100644 (file)
@@ -20,6 +20,7 @@
 #define SUPERTUX_MENU_H
 
 #include <vector>
+#include <memory>
 #include <set>
 #include <string>
 #include <utility>
@@ -89,12 +90,13 @@ private:
   static std::vector<Menu*> last_menus;
   static Menu* current_;
   
-  static void push_current(Menu* pmenu);
   static void pop_current();
   
 public:
   /** Set the current menu, if pmenu is NULL, hide the current menu */
   static void set_current(Menu* pmenu);
+
+  static void push_current(Menu* pmenu); 
   
   /** Return the current active menu or NULL if none is active */
   static Menu* current()
@@ -193,12 +195,12 @@ private:
   Uint32 effect_ticks;
   int arrange_left;
   int active_item;
-};
 
-extern Surface* checkbox;
-extern Surface* checkbox_checked;
-extern Surface* back;
-extern Surface* arrow_left;
-extern Surface* arrow_right;
+  std::auto_ptr<Surface> checkbox;
+  std::auto_ptr<Surface> checkbox_checked;
+  std::auto_ptr<Surface> back;
+  std::auto_ptr<Surface> arrow_left;
+  std::auto_ptr<Surface> arrow_right;
+};
 
 #endif
diff --git a/src/level_subset.cpp b/src/level_subset.cpp
deleted file mode 100644 (file)
index e7c4ac7..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-//  $Id$
-// 
-//  SuperTux
-//  Copyright (C) 2004 SuperTux Development Team, see AUTHORS for details
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-// 
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-//  02111-1307, USA.
-#include <config.h>
-
-#include <sstream>
-#include <stdexcept>
-#include <assert.h>
-#include <unistd.h>
-#include <physfs.h>
-#include "level.hpp"
-#include "msg.hpp"
-#include "resources.hpp"
-#include "file_system.hpp"
-#include "video/surface.hpp"
-#include "level_subset.hpp"
-#include "lisp/parser.hpp"
-#include "lisp/lisp.hpp"
-#include "lisp/writer.hpp"
-
-static bool has_suffix(const std::string& data, const std::string& suffix)
-{
-  if (data.length() >= suffix.length())
-    return data.compare(data.length() - suffix.length(), suffix.length(), suffix) == 0;
-  else
-    return false;
-}
-
-LevelSubset::LevelSubset()
-  : levels(0)
-{
-}
-
-LevelSubset::~LevelSubset()
-{
-}
-
-void LevelSubset::create(const std::string& subset_name)
-{
-  Level new_lev;
-  LevelSubset new_subset;
-  new_subset.name = subset_name;
-  new_subset.title = "Unknown Title";
-  new_subset.description = "No description so far.";
-  new_subset.hide_from_contribs = false;
-  new_subset.save();
-}
-
-void LevelSubset::read_info_file(const std::string& info_file)
-{
-  lisp::Parser parser;
-  std::auto_ptr<lisp::Lisp> root (parser.parse(info_file));
-
-  const lisp::Lisp* info = root->get_lisp("supertux-level-subset");
-  if(!info)
-    throw std::runtime_error("File is not a levelsubset file");
-
-  hide_from_contribs = false;
-
-  info->get("title", title);
-  info->get("description", description);
-  info->get_vector("levels", levels);
-  info->get("hide-from-contribs", hide_from_contribs);
-}
-
-void LevelSubset::load(const std::string& subset)
-{
-  name = subset;
-  
-  std::string infofile = subset + "/info";
-  try {
-    read_info_file(infofile);
-  } catch(std::exception& e) {
-    std::stringstream msg;
-    msg << "Couldn't parse info file '" << infofile << "': " << e.what();
-    throw std::runtime_error(msg.str());
-  }
-
-  // test is a worldmap exists
-  has_worldmap = false;
-  std::string worldmap = subset + "/worldmap.stwm";
-  if(PHYSFS_exists(worldmap.c_str())) {
-    has_worldmap = true;
-  }
-
-  if (levels.empty()) { 
-    // Level info file doesn't define any levels, so read the
-    // directory to see what we can find
-      
-    std::string path = subset + "/";
-    char** files = PHYSFS_enumerateFiles(path.c_str());
-    if(!files) {
-      msg_warning("Couldn't read subset dir '" 
-                << path << "'");
-      return;
-    }
-
-    for(const char* const* filename = files; *filename != 0; ++filename) {
-      if(has_suffix(*filename, ".stl")) {
-        levels.push_back(path + *filename);
-      }
-    }
-    PHYSFS_freeList(files);
-  }
-}
-
-void
-LevelSubset::save()
-{
-  /* Save data file: */
-  std::string filename = name + "/info";
-  lisp::Writer writer(filename);
-
-  writer.start_list("supertux-level-subset");
-  writer.write_string("title", title);
-  writer.write_string("description", description);
-  writer.write_bool("hide-from-contribs", hide_from_contribs);
-  writer.end_list("supertux-level-subset");
-}
-
-void
-LevelSubset::add_level(const std::string& name)
-{
-  levels.push_back(name);
-}
-
-std::string
-LevelSubset::get_level_filename(unsigned int num)
-{
-  assert(num < levels.size());
-  return levels[num];
-}
-
-std::string
-LevelSubset::get_worldmap_filename()
-{
-  return std::string(name + "/worldmap.stwm");
-}
-
-int
-LevelSubset::get_num_levels() const
-{
-  return levels.size();
-}
diff --git a/src/level_subset.hpp b/src/level_subset.hpp
deleted file mode 100644 (file)
index 40f4b75..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-//  $Id$
-// 
-//  SuperTux
-//  Copyright (C) 2004 SuperTux Development Team, see AUTHORS for details
-//
-//  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_LEVEL_SUBSET_H
-#define SUPERTUX_LEVEL_SUBSET_H
-
-#include <vector>
-#include <string>
-
-/** This type holds meta-information about a level-subset. 
-    It could be extended to handle manipulation of subsets. */
-class LevelSubset
-{
-private:
-  /** Level filenames without the leading path ("level1.stl",
-      "level3.stl", ...) */
-  std::vector<std::string> levels;
-
-public:
-  LevelSubset();
-  ~LevelSubset();
-
-  static void create(const std::string& subset_name);
-  void load(const std::string& filename);
-  void save();
-
-  void add_level(const std::string& name);
-
-  std::string get_level_filename(unsigned int i);
-  std::string get_worldmap_filename();
-  int get_num_levels() const;
-
-  std::string name;
-  std::string title;
-  std::string description;
-  bool hide_from_contribs;
-  bool has_worldmap;
-
-private:
-  void read_info_file(const std::string& info_file);
-};
-
-#endif
-
-/* Local Variables: */
-/* mode:c++ */
-/* End: */
index fa4bda5..fb8dd88 100644 (file)
@@ -47,6 +47,7 @@ public:
   { return v.cons.car; }
   Lisp* get_cdr() const
   { return v.cons.cdr; }
+  
   bool get(std::string& val) const
   { 
     if(type != TYPE_STRING && type != TYPE_SYMBOL)
@@ -54,6 +55,13 @@ public:
     val = v.string;
     return true;
   }
+  
+  std::string get_string() const
+  {
+    assert(type == TYPE_STRING);
+    return v.string;
+  }
+  
   bool get(unsigned int& val) const
   {
     if(type != TYPE_INTEGER)
@@ -61,6 +69,7 @@ public:
     val = v.integer;
     return true;
   }
+  
   bool get(int& val) const
   {
     if(type != TYPE_INTEGER)
@@ -68,6 +77,13 @@ public:
     val = v.integer;
     return true;
   }
+
+  int get_int() const
+  {
+    assert(type == TYPE_INTEGER);
+    return v.integer;
+  }
+  
   bool get(float& val) const
   {
     if(type != TYPE_REAL) {
@@ -80,6 +96,13 @@ public:
     val = v.real;
     return true;
   }
+
+  float get_float() const
+  {
+    assert(type == TYPE_REAL);
+    return v.real;
+  }
+
   bool get(bool& val) const
   {
     if(type != TYPE_BOOLEAN)
@@ -88,6 +111,12 @@ public:
     return true;
   }
 
+  bool get_bool() const
+  {
+    assert(type == TYPE_BOOLEAN);
+    return v.boolean;
+  }
+
   /** conveniance functions which traverse the list until a child with a
    * specified name is found. The value part is then interpreted in a specific
    * way. The functions return true, if a child was found and could be
index 47af8c4..bb2fd86 100644 (file)
@@ -45,6 +45,7 @@
 #include "video/texture_manager.hpp"
 #include "control/joystickkeyboardcontroller.hpp"
 #include "misc.hpp"
+#include "mainloop.hpp"
 #include "title.hpp"
 #include "game_session.hpp"
 #include "file_system.hpp"
@@ -467,22 +468,29 @@ int main(int argc, char** argv)
     timelog("resources");
     load_shared();
     timelog(0);
+
+    main_loop = new MainLoop(); 
     if(config->start_level != "") {
       // we have a normal path specified at commandline not physfs paths.
       // So we simply mount that path here...
       std::string dir = FileSystem::dirname(config->start_level);
       PHYSFS_addToSearchPath(dir.c_str(), true);
-      GameSession session(
+      GameSession* session
+        = new GameSession(
           FileSystem::basename(config->start_level), ST_GL_LOAD_LEVEL_FILE);
       if(config->start_demo != "")
-        session.play_demo(config->start_demo);
+        session->play_demo(config->start_demo);
       if(config->record_demo != "")
-        session.record_demo(config->record_demo);
-      session.run();
+        session->record_demo(config->record_demo);
+      main_loop->push_screen(session);
     } else {
-      // normal game
-      title();
+      main_loop->push_screen(new TitleScreen());
     }
+
+    main_loop->run();
+
+    delete main_loop;
+    main_loop = NULL;
   } catch(graceful_shutdown& e) {
   } catch(std::exception& e) {
     msg_fatal("Unexpected exception: " << e.what());
diff --git a/src/mainloop.cpp b/src/mainloop.cpp
new file mode 100644 (file)
index 0000000..1c98cd4
--- /dev/null
@@ -0,0 +1,177 @@
+//  $Id: worldmap.hpp 2800 2005-10-02 22:57:31Z matzebraun $
+// 
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+// 
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#include <config.h>
+
+#include "mainloop.hpp"
+
+#include <stdlib.h>
+#include <SDL.h>
+#include "video/drawing_context.hpp"
+#include "control/joystickkeyboardcontroller.hpp"
+#include "gui/menu.hpp"
+#include "audio/sound_manager.hpp"
+#include "gameconfig.hpp"
+#include "main.hpp"
+#include "resources.hpp"
+#include "screen.hpp"
+#include "timer.hpp"
+
+// the engine will be run with a logical framerate of 64fps.
+// We chose 64fps here because it is a power of 2, so 1/64 gives an "even"
+// binary fraction...
+static const float LOGICAL_FPS = 64.0;
+
+MainLoop* main_loop = NULL;
+
+MainLoop::MainLoop()
+  : speed(1.0)
+{
+  console.reset(new Console());
+}
+
+MainLoop::~MainLoop()
+{
+  for(std::vector<Screen*>::iterator i = screen_stack.begin();
+      i != screen_stack.end(); ++i) {
+    delete *i;
+  }
+}
+
+void
+MainLoop::push_screen(Screen* screen)
+{
+  this->next_screen.reset(screen);
+  nextpush = true;
+  speed = 1.0;
+}
+
+void
+MainLoop::exit_screen()
+{
+  next_screen.reset(screen_stack.back());
+  nextpush = false;
+  screen_stack.pop_back();
+  speed = 1.0;
+}
+
+void
+MainLoop::quit()
+{
+  running = false;
+}
+
+void
+MainLoop::set_speed(float speed)
+{
+  this->speed = speed;
+}
+
+void
+MainLoop::run()
+{
+  DrawingContext context; 
+  
+  unsigned int frame_count;
+  float fps_fps;
+  Uint32 fps_ticks = SDL_GetTicks();
+  Uint32 fps_nextframe_ticks = SDL_GetTicks();
+  Uint32 ticks;
+  bool skipdraw = false;
+  
+  running = true;
+  while(running) {
+    if(next_screen.get() != NULL) {
+      if(nextpush)
+        screen_stack.push_back(current_screen.release());
+      
+      next_screen->setup();
+      current_screen.reset(next_screen.release());
+      next_screen.reset(NULL);
+      nextpush = false;
+    }
+
+    if(current_screen.get() == NULL)
+        break;
+      
+    float elapsed_time = 1.0 / LOGICAL_FPS;
+    ticks = SDL_GetTicks();
+    if(ticks > fps_nextframe_ticks) {
+      if(skipdraw == true) {
+        // already skipped last frame? we have to slow down the game then...
+        skipdraw = false;
+        fps_nextframe_ticks -= (Uint32) (1000.0 / LOGICAL_FPS);
+      } else {
+        // don't draw all frames when we're getting too slow
+        skipdraw = true;
+      }
+    } else {
+      skipdraw = false;
+      while(fps_nextframe_ticks > ticks) {
+        /* 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);
+        }
+        ticks = SDL_GetTicks();
+      }
+    }
+    fps_nextframe_ticks = ticks + (Uint32) (1000.0 / LOGICAL_FPS);
+
+    if(!skipdraw) {
+      current_screen->draw(context);
+      if(Menu::current() != NULL)
+          Menu::current()->draw(context);
+      console->draw(context);
+
+      context.do_drawing();
+
+      /* Calculate frames per second */
+      if(config->show_fps)
+      {
+        ++frame_count;
+        
+        if(SDL_GetTicks() - fps_ticks >= 500)
+        {
+          fps_fps = (float) frame_count / .5;
+          frame_count = 0;
+          fps_ticks = SDL_GetTicks();
+        }
+      }
+    }
+
+    elapsed_time *= speed;
+
+    game_time += elapsed_time;
+    current_screen->update(elapsed_time);
+
+    main_controller->update();
+    SDL_Event event;
+    while(SDL_PollEvent(&event)) {
+      main_controller->process_event(event);
+      if(Menu::current() != NULL)
+        Menu::current()->event(event);
+      if(event.type == SDL_QUIT)
+        quit();
+    }
+
+    sound_manager->update();
+  }
+}
+
diff --git a/src/mainloop.hpp b/src/mainloop.hpp
new file mode 100644 (file)
index 0000000..20d2107
--- /dev/null
@@ -0,0 +1,55 @@
+//  $Id: worldmap.hpp 2800 2005-10-02 22:57:31Z matzebraun $
+// 
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+// 
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#ifndef __MAINLOOP_HPP__
+#define __MAINLOOP_HPP__
+
+#include <memory>
+#include <vector>
+
+class Screen;
+class Console;
+
+class MainLoop
+{
+public:
+  MainLoop();
+  ~MainLoop();
+  
+  void run();
+  void exit_screen();
+  void quit();
+  void set_speed(float speed);
+
+  // push new screen on screen_stack
+  void push_screen(Screen* screen);
+
+private:
+  bool running;
+  float speed;
+  bool nextpush;
+  std::auto_ptr<Screen> next_screen;
+  std::auto_ptr<Screen> current_screen;
+  std::auto_ptr<Console> console;
+  std::vector<Screen*> screen_stack;
+};
+
+extern MainLoop* main_loop;
+
+#endif
+
index b8279b5..047ab3e 100644 (file)
 Menu* main_menu      = 0;
 Menu* game_menu      = 0;
 Menu* options_menu   = 0;
-Menu* options_keys_menu     = 0;
-Menu* options_joystick_menu = 0;
-Menu* highscore_menu = 0;
-Menu* load_game_menu = 0;
-Menu* save_game_menu = 0;
-Menu* contrib_menu   = 0;
-Menu* contrib_subset_menu   = 0;
 
 void process_options_menu()
 {
@@ -73,15 +66,12 @@ void setup_menu()
 {
   main_menu      = new Menu();
   options_menu   = new Menu();
-  load_game_menu = new Menu();
   game_menu      = new Menu();
-  contrib_menu   = new Menu();
-  contrib_subset_menu   = new Menu();
   worldmap_menu  = new Menu();
 
   main_menu->set_pos(SCREEN_WIDTH/2, 335);
-  main_menu->add_submenu(_("Start Game"), load_game_menu, MNID_STARTGAME);
-  main_menu->add_submenu(_("Contrib Levels"), contrib_menu, MNID_LEVELS_CONTRIB);
+  main_menu->add_entry(MNID_STARTGAME, _("Start Game"));
+  main_menu->add_entry(MNID_LEVELS_CONTRIB, _("Contrib Levels"));
   main_menu->add_submenu(_("Options"), options_menu);
   //main_menu->add_entry(MNID_LEVELEDITOR, _("Level Editor"));
   main_menu->add_entry(MNID_CREDITS, _("Credits"));
@@ -99,16 +89,6 @@ void setup_menu()
   options_menu->add_hl();
   options_menu->add_back(_("Back"));
   
-  load_game_menu->add_label(_("Start Game"));
-  load_game_menu->add_hl();
-  load_game_menu->add_deactive(1, "Slot 1");
-  load_game_menu->add_deactive(2, "Slot 2");
-  load_game_menu->add_deactive(3, "Slot 3");
-  load_game_menu->add_deactive(4, "Slot 4");
-  load_game_menu->add_deactive(5, "Slot 5");
-  load_game_menu->add_hl();
-  load_game_menu->add_back(_("Back"));
-  
   game_menu->add_label(_("Pause"));
   game_menu->add_hl();
   game_menu->add_entry(MNID_CONTINUE, _("Continue"));
@@ -130,8 +110,5 @@ void free_menu()
   delete main_menu;
   delete game_menu;
   delete options_menu;
-  delete contrib_menu;
-  delete contrib_subset_menu;
-  delete load_game_menu;
 }
 
index 0978b14..7b97edd 100644 (file)
 #ifndef SUPERTUX_MISC_H
 #define SUPERTUX_MISC_H
 
+enum MainMenuIDs {
+  MNID_STARTGAME,
+  MNID_LEVELS_CONTRIB,
+  MNID_OPTIONMENU,
+  MNID_LEVELEDITOR,
+  MNID_CREDITS,
+  MNID_QUITMAINMENU
+};
+
 enum OptionsMenuIDs {
   MNID_FULLSCREEN,
   MNID_SOUND,
index a1461cf..1933b9b 100644 (file)
@@ -37,10 +37,10 @@ FloatingImage::draw(DrawingContext& context)
   context.push_transform();
   context.set_translation(Vector(0, 0));
 
-  Vector pos = get_anchor_pos(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT),
+  Vector spos = pos + get_anchor_pos(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT),
       sprite->get_width(), sprite->get_height(), anchor);
 
-  sprite->draw(context, pos, layer);
+  sprite->draw(context, spos, layer);
 
   context.pop_transform();
 }
index add9a09..ffa727c 100644 (file)
@@ -161,10 +161,11 @@ public:
 
   void set_visible(bool visible);
   bool get_visible();
+
+  bool on_ground();
   
 private:
   void handle_input();
-  bool on_ground();
   bool deactivated;
   
   void init();
index f5c721f..25eb28e 100644 (file)
@@ -42,25 +42,22 @@ PlayerStatus::PlayerStatus()
     max_score_multiplier(1)
 {
   reset();
-  key_brass = sprite_manager->create("images/objects/keys/key_brass.sprite");
-  key_iron = sprite_manager->create("images/objects/keys/key_iron.sprite");
-  key_bronze = sprite_manager->create("images/objects/keys/key_bronze.sprite");
-  key_silver = sprite_manager->create("images/objects/keys/key_silver.sprite");
-  key_gold = sprite_manager->create("images/objects/keys/key_gold.sprite");
+  key_brass.reset(sprite_manager->create("images/objects/keys/key_brass.sprite"));
+  key_iron.reset(sprite_manager->create("images/objects/keys/key_iron.sprite"));
+  key_bronze.reset(sprite_manager->create("images/objects/keys/key_bronze.sprite"));
+  key_silver.reset(sprite_manager->create("images/objects/keys/key_silver.sprite"));
+  key_gold.reset(sprite_manager->create("images/objects/keys/key_gold.sprite"));
   key_brass->set_action("outline");
   key_iron->set_action("outline");
   key_bronze->set_action("outline");
   key_silver->set_action("outline");
   key_gold->set_action("outline");
+  
+  tux_life.reset(sprite_manager->create("images/creatures/tux_small/tux-life.sprite"));
 }
 
 PlayerStatus::~PlayerStatus()
 {
-  delete key_brass;
-  delete key_iron;
-  delete key_bronze;
-  delete key_silver;
-  delete key_gold;
 }
 
 void PlayerStatus::reset()
index 29b8f83..7b352cf 100644 (file)
@@ -20,6 +20,7 @@
 #define SUPERTUX_PLAYERSTATUS_H
 
 #include <assert.h>
+#include <memory>
 #include "lisp/lisp.hpp"
 #include "timer.hpp"
 #include "serializable.hpp"
@@ -74,11 +75,12 @@ private:
   PlayerStatus(const PlayerStatus& other);
   
   int  keys;
-  Sprite* key_iron;
-  Sprite* key_brass;
-  Sprite* key_bronze;
-  Sprite* key_silver;
-  Sprite* key_gold;
+  std::auto_ptr<Sprite> tux_life;
+  std::auto_ptr<Sprite> key_iron;
+  std::auto_ptr<Sprite> key_brass;
+  std::auto_ptr<Sprite> key_bronze;
+  std::auto_ptr<Sprite> key_silver;
+  std::auto_ptr<Sprite> key_gold;
 };
 
 // global player state
index 9331851..3570e00 100644 (file)
@@ -42,13 +42,6 @@ Font* white_big_text;
 /* Load graphics/sounds shared between all levels: */
 void load_shared()
 {
-  /* Load GUI/menu images: */
-  checkbox = new Surface("images/engine/menu/checkbox-unchecked.png");
-  checkbox_checked = new Surface("images/engine/menu/checkbox-checked.png");
-  back = new Surface("images/engine/menu/arrow-back.png");
-  arrow_left = new Surface("images/engine/menu/arrow-left.png");
-  arrow_right = new Surface("images/engine/menu/arrow-right.png");
-
   /* Load the mouse-cursor */
   mouse_cursor = new MouseCursor("images/engine/menu/mousecursor.png");
   MouseCursor::set_current(mouse_cursor);
@@ -113,9 +106,6 @@ void load_shared()
   ice_tux->arms = sprite_manager->create("images/creatures/tux_big/big-tux-arms.sprite");
   ice_tux->feet = sprite_manager->create("images/creatures/tux_big/big-tux-feet.sprite");
 
-  /* Tux life: */
-  tux_life = new Surface("images/creatures/tux_small/tux-life.png");
-  
   player_status = new PlayerStatus();
 }
 
@@ -130,8 +120,6 @@ void unload_shared()
   delete white_small_text;
   delete white_big_text;
   
-  delete tux_life;
-
   delete small_tux;
   delete big_tux;
   delete fire_tux;
@@ -147,13 +135,6 @@ void unload_shared()
   delete tile_manager;
   tile_manager = 0;
 
-  /* Free GUI/menu images: */
-  delete checkbox;
-  delete checkbox_checked;
-  delete back;
-  delete arrow_left;
-  delete arrow_right;
-
   /* Free mouse-cursor */
   delete mouse_cursor;
 }
index 1771aa5..811ff53 100644 (file)
@@ -27,18 +27,12 @@ class SoundManager;
 class TileManager;
 class MouseCursor;
 
-extern Surface* img_super_bkgd;
-extern Surface* tux_life;
-
 extern SpriteManager* sprite_manager;
 extern TileManager* tile_manager;
 
-extern Menu* contrib_menu;
-extern Menu* contrib_subset_menu;
 extern Menu* main_menu;
 extern Menu* game_menu;
 extern Menu* options_menu;
-extern Menu* load_game_menu;
 
 extern MouseCursor* mouse_cursor;
 
diff --git a/src/screen.hpp b/src/screen.hpp
new file mode 100644 (file)
index 0000000..fd3b890
--- /dev/null
@@ -0,0 +1,39 @@
+//  $Id: worldmap.hpp 2800 2005-10-02 22:57:31Z matzebraun $
+// 
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+// 
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#ifndef __SCREEN_HPP__
+#define __SCREEN_HPP__
+
+class DrawingContext;
+
+class Screen
+{
+public:
+  virtual ~Screen()
+  {}
+
+  virtual void setup()
+  {}
+
+  virtual void draw(DrawingContext& context) = 0;
+
+  virtual void update(float elapsed_time) = 0;
+};
+
+#endif
+
index 6bff401..050ec72 100644 (file)
@@ -9,6 +9,7 @@
 #include "resources.hpp"
 #include "gettext.hpp"
 #include "msg.hpp"
+#include "mainloop.hpp"
 
 namespace Scripting
 {
@@ -27,7 +28,7 @@ void display_text_file(const std::string& filename)
 {
   std::string file 
     = ScriptInterpreter::current()->get_working_directory() + filename;
-  ::display_text_file(file);
+  main_loop->push_screen(new TextScroller(file));
 }
 
 void import(HSQUIRRELVM v, const std::string& filename)
index a66df0a..3c21ed0 100644 (file)
@@ -15,9 +15,9 @@ namespace Scripting
   {}
 
   void
-  Level::finish()
+  Level::finish(bool win)
   {
-    GameSession::current()->finish();
+    GameSession::current()->finish(win);
   }
 
   void
index aae3faf..26d03f7 100644 (file)
@@ -13,7 +13,7 @@ public:
 #endif
 
     /** Instantly finish the currently played level */
-    void finish();
+    void finish(bool win);
     /** spawn tux at specified sector and spawnpoint */
     void spawn(const std::string& sector, const std::string& spawnpoint);
     /** Flip level vertically */
index 746110c..944c7b6 100644 (file)
@@ -172,8 +172,10 @@ static int Level_finish_wrapper(HSQUIRRELVM v)
 {
   Scripting::Level* _this;
   sq_getinstanceup(v, 1, (SQUserPointer*) &_this, 0);
+  SQBool arg0;
+  sq_getbool(v, 2, &arg0);
   
-  _this->finish();
+  _this->finish(arg0);
   
   return 0;
 }
index 3c1322f..c6ee241 100644 (file)
@@ -573,7 +573,7 @@ Sector::draw(DrawingContext& context)
   context.pop_transform();
 }
 
-static const float DELTA = .1;
+static const float DELTA = .001;
 
 void
 Sector::collision_tilemap(const Rect& dest, const Vector& movement,
index d1cd0ce..c46dde3 100644 (file)
 
 #include <stdexcept>
 #include "msg.hpp"
+#include "mainloop.hpp"
 #include "resources.hpp"
 #include "video/font.hpp"
 #include "video/drawing_context.hpp"
 #include "video/surface.hpp"
+#include "video/screen.hpp"
+#include "gui/menu.hpp"
 #include "lisp/parser.hpp"
 #include "lisp/lisp.hpp"
 #include "audio/sound_manager.hpp"
@@ -34,7 +37,8 @@
 #include "control/joystickkeyboardcontroller.hpp"
 #include "exceptions.hpp"
 
-static const float DEFAULT_SPEED = .02;
+static const float DEFAULT_SPEED = 20;
+static const float LEFT_BORDER = 50;
 static const float SCROLL = 60;
 static const float ITEMS_SPACE = 4;
 
@@ -57,19 +61,13 @@ static void split_text(const std::string& text, std::vector<std::string>& lines)
   }
 }
 
-void display_text_file(const std::string& filename)
+TextScroller::TextScroller(const std::string& filename)
 {
-  const Font* heading_font = white_big_text;
-  const Font* normal_font = white_text;
-  const Font* small_font = white_small_text;
-  const Font* reference_font = blue_text;
-  float defaultspeed = DEFAULT_SPEED;
-  float speed = defaultspeed;
+  defaultspeed = DEFAULT_SPEED;
+  speed = defaultspeed;
   
   std::string text;
   std::string background_file;
-  std::vector<std::string> lines;
-  std::map<std::string, Surface*> images;
 
   lisp::Parser parser;
   try {
@@ -83,8 +81,8 @@ void display_text_file(const std::string& filename)
       throw std::runtime_error("file doesn't contain a text field");
     if(!text_lisp->get("background", background_file))
       throw std::runtime_error("file doesn't contain a background file");
-    if(text_lisp->get("speed", defaultspeed))
-      defaultspeed /= 50;
+    text_lisp->get("speed", defaultspeed);
+    text_lisp->get("music", music);
   } catch(std::exception& e) {
     msg_warning("Couldn't load file '" << filename << "': " << e.what());
     return;
@@ -99,122 +97,115 @@ void display_text_file(const std::string& filename)
       continue;
     if(line[0] == '!') {
       std::string imagename = line.substr(1, line.size()-1);
-      msg_debug("Imagename: " << imagename);
       images.insert(std::make_pair(imagename, new Surface(imagename)));
     }
   }
 
   // load background image
-  Surface* background = new Surface("images/background/" + background_file);
-
-  bool done = false;
-  float scroll = 0;
-  float left_border = 50;
-
-  DrawingContext context;
-  SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
-
-  Uint32 lastticks = SDL_GetTicks();
-  while(!done) {
-    main_controller->update();
-    /* in case of input, exit */
-    SDL_Event event;
-    while(SDL_PollEvent(&event)) {
-      main_controller->process_event(event);
-      if(event.type == SDL_QUIT)
-        throw graceful_shutdown();
-    }
+  background.reset(new Surface("images/background/" + background_file));
 
-    if(main_controller->hold(Controller::UP)) {
-      speed = -defaultspeed*5;
-    } else if(main_controller->hold(Controller::DOWN)) {
-      speed = defaultspeed*5;
-    } else {
-      speed = defaultspeed;
-    }
-    if(main_controller->pressed(Controller::JUMP)
-       || main_controller->pressed(Controller::ACTION)
-       || main_controller->pressed(Controller::MENU_SELECT))
-      scroll += SCROLL;    
-    if(main_controller->pressed(Controller::PAUSE_MENU))
-      done = true;
+  scroll = 0;
+}
+
+TextScroller::~TextScroller()
+{
+  for(std::map<std::string, Surface*>::iterator i = images.begin();
+      i != images.end(); ++i)
+    delete i->second; 
+}
+
+void
+TextScroller::setup()
+{
+  sound_manager->play_music(music);
+  Menu::set_current(NULL);
+}
+
+void
+TextScroller::update(float elapsed_time)
+{
+  if(main_controller->hold(Controller::UP)) {
+    speed = -defaultspeed*5;
+  } else if(main_controller->hold(Controller::DOWN)) {
+    speed = defaultspeed*5;
+  } else {
+    speed = defaultspeed;
+  }
+  if(main_controller->pressed(Controller::JUMP)
+      || main_controller->pressed(Controller::ACTION)
+      || main_controller->pressed(Controller::MENU_SELECT))
+    scroll += SCROLL;    
+  if(main_controller->pressed(Controller::PAUSE_MENU)) {
+    fadeout(500);
+    main_loop->exit_screen();
+  }
+
+  scroll += speed * elapsed_time;
     
-    /* draw the credits */
-    context.draw_surface(background, Vector(0,0), 0);
-
-    float y = 0;
-    for(size_t i = 0; i < lines.size(); i++) {
-      const std::string& line = lines[i];
-      if(line.size() == 0) {
-        y += normal_font->get_height() + ITEMS_SPACE;
-        continue;
-      }
+  if(scroll < 0)
+    scroll = 0;
+}
+
+void
+TextScroller::draw(DrawingContext& context)
+{
+  context.draw_surface(background.get(), Vector(0,0), 0);
+
+  float y = SCREEN_HEIGHT - scroll;
+  for(size_t i = 0; i < lines.size(); i++) {
+    const std::string& line = lines[i];
+    if(line.size() == 0) {
+      y += white_text->get_height() + ITEMS_SPACE;
+      continue;
+    }
       
-      const Font* font = 0;
-      const Surface* image = 0;
-      bool center = true;
-      switch(line[0])
-      {
-        case ' ': font = small_font; break;
-        case '\t': font = normal_font; break;
-        case '-': font = heading_font; break;
-        case '*': font = reference_font; break;
-        case '#': font = normal_font; center = false; break;
-        case '!': {
-            std::string imagename = line.substr(1, line.size()-1);
-            image = images[imagename];
-            break;
-        }
-        default:
-          msg_warning("text contains an unformated line");
-          font = normal_font;
-          center = false;
-          break;
-      }
-     
-      if(font != 0) {
-        if(center) {
-          context.draw_text(font,
-              line.substr(1, line.size()-1),
-              Vector(SCREEN_WIDTH/2, SCREEN_HEIGHT + y - scroll),
-              CENTER_ALLIGN, LAYER_FOREGROUND1);
-        } else {
-          context.draw_text(font,
-              line.substr(1, line.size()-1),
-              Vector(left_border, SCREEN_HEIGHT + y - scroll),
-              LEFT_ALLIGN, LAYER_FOREGROUND1);
-        }
-        y += font->get_height() + ITEMS_SPACE;
-      }
-      if(image != 0) {
-        context.draw_surface(image,
-            Vector( (SCREEN_WIDTH - image->get_width()) / 2,
-                    SCREEN_HEIGHT + y - scroll), 255);
-        y += image->get_height() + ITEMS_SPACE;
-      }
+    const Font* font = 0;
+    const Surface* image = 0;
+    bool center = true;
+    switch(line[0])
+    {
+      case ' ': font = white_small_text; break;
+      case '\t': font = white_text; break;
+      case '-': font = white_big_text; break;
+      case '*': font = blue_text; break;
+      case '#': font = white_text; center = false; break;
+      case '!': {
+                  std::string imagename = line.substr(1, line.size()-1);
+                  image = images[imagename];
+                  break;
+                }
+      default:
+                msg_warning("text contains an unformated line");
+                font = white_text;
+                center = false;
+                break;
     }
     
-    context.do_drawing();
-    sound_manager->update();
-    
-    if(SCREEN_HEIGHT+y-scroll < 0 && 20+SCREEN_HEIGHT+y-scroll < 0)
-      done = 1;
-    
-    Uint32 ticks = SDL_GetTicks();
-    scroll += speed * (ticks - lastticks);
-    lastticks = ticks;
-    if(scroll < 0)
-      scroll = 0;
-    
-    SDL_Delay(10);
+    if(font != 0) {
+      if(center) {
+        context.draw_text(font,
+            line.substr(1, line.size()-1),
+            Vector(SCREEN_WIDTH/2, y),
+            CENTER_ALLIGN, LAYER_FOREGROUND1);
+      } else {
+        context.draw_text(font,
+            line.substr(1, line.size()-1),
+            Vector(LEFT_BORDER, y),
+            LEFT_ALLIGN, LAYER_FOREGROUND1);
+      }
+      y += font->get_height() + ITEMS_SPACE;
+    }
+    if(image != 0) {
+      context.draw_surface(image,
+          Vector( (SCREEN_WIDTH - image->get_width()) / 2, y), 255);
+      y += image->get_height() + ITEMS_SPACE;
+    }
   }
 
-  for(std::map<std::string, Surface*>::iterator i = images.begin();
-      i != images.end(); ++i)
-    delete i->second;
-
-  SDL_EnableKeyRepeat(0, 0);    // disables key repeating
-  delete background;
+  if(y < 0) {
+    fadeout(500); 
+    main_loop->exit_screen();
+  }
 }
 
 InfoBox::InfoBox(const std::string& text)
index 5afef35..1bdefbf 100644 (file)
 #include <string>
 #include <map>
 
-#include "video/surface.hpp"
+#include "screen.hpp"
 
 class DrawingContext;
+class Surface;
 
 /** This class is displaying a box with information text inside the game
  */
@@ -51,12 +52,25 @@ private:
   Surface* arrow_scrolldown;
 };
 
-/** Reads a text file (using LispReader, so it as to be in its formatting)
- * and scroll it over the screen
- * (this call blocks until all text scrolled through or the user aborted the
- *  textscrolling)
- */
-void display_text_file(const std::string& file);
+class TextScroller : public Screen
+{
+public:
+  TextScroller(const std::string& file);
+  virtual ~TextScroller();
+
+  void setup();
+  void draw(DrawingContext& context);
+  void update(float elapsed_time);
+
+private:
+  float defaultspeed;
+  float speed;
+  std::string music;
+  std::auto_ptr<Surface> background;
+  std::vector<std::string> lines;
+  std::map<std::string, Surface*> images;
+  float scroll;
+};
 
 #endif
 
index 474b8f2..77b6d33 100644 (file)
@@ -41,7 +41,7 @@ TileManager::TileManager(const std::string& filename)
 #endif
   load_tileset(filename);
 #ifdef DEBUG
-  msg_debug("Tiles loaded in " << (SDL_GetTicks() - ticks) / 1000.0 << "seconds");
+  msg_debug("Tiles loaded in " << (SDL_GetTicks() - ticks) / 1000.0 << " seconds");
 #endif
 }
 
index e5e5aa5..f6ebca4 100644 (file)
@@ -34,7 +34,9 @@
 #include <physfs.h>
 
 #include "title.hpp"
+#include "mainloop.hpp"
 #include "video/screen.hpp"
+#include "video/drawing_context.hpp"
 #include "video/surface.hpp"
 #include "audio/sound_manager.hpp"
 #include "gui/menu.hpp"
@@ -42,7 +44,7 @@
 #include "lisp/lisp.hpp"
 #include "lisp/parser.hpp"
 #include "level.hpp"
-#include "level_subset.hpp"
+#include "world.hpp"
 #include "game_session.hpp"
 #include "worldmap.hpp"
 #include "player_status.hpp"
 #include "msg.hpp"
 #include "console.hpp"
 
-static Surface* bkg_title;
-static Surface* logo;
-//static Surface* img_choose_subset;
-
-static int frame;
-
-static GameSession* titlesession;
-static CodeController* controller;
-
-static std::vector<LevelSubset*> contrib_subsets;
-static LevelSubset* current_contrib_subset = 0;
-static int current_subset = -1;
-
-static Console* console;
-
-/* If the demo was stopped - because game started, level
-   editor was excuted, etc - call this when you get back
-   to the title code.
- */
-void resume_demo()
+void
+TitleScreen::update_load_game_menu()
 {
-  player_status->reset();
-  titlesession->get_current_sector()->activate("main");
-  titlesession->set_current();
-
-  //frame_rate.update();
-}
+  load_game_menu.reset(new Menu());
 
-void update_load_save_game_menu(Menu* menu)
-{
-  msg_debug("update loadsavemenu");
-  for(int i = 1; i < 6; ++i) {
-    MenuItem& item = menu->get_item_by_id(i);
-    item.kind = MN_ACTION;
-    item.change_text(slotinfo(i));
+  load_game_menu->add_label(_("Start Game"));
+  load_game_menu->add_hl();
+  for(int i = 1; i <= 5; ++i) {
+    load_game_menu->add_entry(i, get_slotinfo(i));
   }
+  load_game_menu->add_hl();
+  load_game_menu->add_back(_("Back"));
 }
 
-void free_contrib_menu()
+void
+TitleScreen::free_contrib_menu()
 {
-  for(std::vector<LevelSubset*>::iterator i = contrib_subsets.begin();
-      i != contrib_subsets.end(); ++i)
+  for(std::vector<World*>::iterator i = contrib_worlds.begin();
+      i != contrib_worlds.end(); ++i)
     delete *i;
 
-  contrib_subsets.clear();
-  contrib_menu->clear();
-  current_contrib_subset = 0;
-  current_subset = -1;
+  contrib_worlds.clear();
+  current_contrib_world = 0;
+  current_world = -1;
 }
 
-void generate_contrib_menu()
+void
+TitleScreen::generate_contrib_menu()
 {
   /** Generating contrib levels list by making use of Level Subset  */
-  std::vector<std::string> level_subsets; 
+  std::vector<std::string> level_worlds; 
   char** files = PHYSFS_enumerateFiles("levels/");
   for(const char* const* filename = files; *filename != 0; ++filename) {
     std::string filepath = std::string("levels/") + *filename;
     if(PHYSFS_isDirectory(filepath.c_str()))
-      level_subsets.push_back(filepath);
+      level_worlds.push_back(filepath);
   }
   PHYSFS_freeList(files);
 
   free_contrib_menu();
+  contrib_menu.reset(new Menu());
 
   contrib_menu->add_label(_("Contrib Levels"));
   contrib_menu->add_hl();
   
   int i = 0;
-  for (std::vector<std::string>::iterator it = level_subsets.begin();
-      it != level_subsets.end(); ++it) {
+  for (std::vector<std::string>::iterator it = level_worlds.begin();
+      it != level_worlds.end(); ++it) {
     try {
-      std::auto_ptr<LevelSubset> subset (new LevelSubset());
-      subset->load(*it);
-      if(subset->hide_from_contribs) {
+      std::auto_ptr<World> world (new World());
+      world->load(*it + "/info");
+      if(world->hide_from_contribs) {
         continue;
       }
-      contrib_menu->add_submenu(subset->title, contrib_subset_menu, i++);
-      contrib_subsets.push_back(subset.release());
+      contrib_menu->add_entry(i++, world->title);
+      contrib_worlds.push_back(world.release());
     } catch(std::exception& e) {
 #ifdef DEBUG
       msg_warning("Couldn't parse levelset info for '"
@@ -153,7 +133,8 @@ void generate_contrib_menu()
   contrib_menu->add_back(_("Back"));
 }
 
-std::string get_level_name(const std::string& filename)
+std::string
+TitleScreen::get_level_name(const std::string& filename)
 {
   try {
     lisp::Parser parser;
@@ -172,87 +153,73 @@ std::string get_level_name(const std::string& filename)
   }
 }
 
-void check_levels_contrib_menu()
+void
+TitleScreen::check_levels_contrib_menu()
 {
   int index = contrib_menu->check();
   if (index == -1)
     return;
 
-  LevelSubset& subset = * (contrib_subsets[index]);
-  
-  if(subset.has_worldmap) {
-    WorldMapNS::WorldMap worldmap;
-    worldmap.set_map_filename(subset.get_worldmap_filename());
-    sound_manager->stop_music();
-
-    // some fading
-    fadeout(256);
-    DrawingContext context;
-    context.draw_text(white_text, "Loading...",
-        Vector(SCREEN_WIDTH/2, SCREEN_HEIGHT/2), CENTER_ALLIGN, LAYER_FOREGROUND1);
-    context.do_drawing();
-
-    // TODO: slots should be available for contrib maps
-    worldmap.loadgame("save/" + subset.name + "-slot1.stsg");
-    worldmap.display();  // run the map
+  World& world = * (contrib_worlds[index]);
 
-    Menu::set_current(main_menu);
-    resume_demo();
-  } else if (current_subset != index) {
-    current_subset = index;
-    LevelSubset& subset = * (contrib_subsets[index]);
+  if(!world.is_levelset) {
+    // TODO fade out
+    world.run();
+  }
 
-    current_contrib_subset = &subset;
+  if (current_world != index) {
+    current_world = index;
+    World& world = * (contrib_worlds[index]);
 
-    contrib_subset_menu->clear();
+    current_contrib_world = &world;
 
-    contrib_subset_menu->add_label(subset.title);
-    contrib_subset_menu->add_hl();
+    contrib_world_menu.reset(new Menu());
 
-    for (int i = 0; i < subset.get_num_levels(); ++i)
+    contrib_world_menu->add_label(world.title);
+    contrib_world_menu->add_hl();
+
+    for (unsigned int i = 0; i < world.get_num_levels(); ++i)
     {
       /** get level's title */
-      std::string filename = subset.get_level_filename(i);
+      std::string filename = world.get_level_filename(i);
       std::string title = get_level_name(filename);
-      contrib_subset_menu->add_entry(i, title);
+      contrib_world_menu->add_entry(i, title);
     }
 
-    contrib_subset_menu->add_hl();
-    contrib_subset_menu->add_back(_("Back"));
+    contrib_world_menu->add_hl();
+    contrib_world_menu->add_back(_("Back"));
 
-    titlesession->get_current_sector()->activate("main");
-    titlesession->set_current();
+    Menu::push_current(contrib_world_menu.get());
   }
 }
 
-void check_contrib_subset_menu()
+void
+TitleScreen::check_contrib_world_menu()
 {
-  int index = contrib_subset_menu->check();
+  int index = contrib_world_menu->check();
   if (index != -1) {
-    if (contrib_subset_menu->get_item_by_id(index).kind == MN_ACTION) {
+    if (contrib_world_menu->get_item_by_id(index).kind == MN_ACTION) {
       sound_manager->stop_music();
-      GameSession session(
-          current_contrib_subset->get_level_filename(index), ST_GL_PLAY);
-      session.run();
-      player_status->reset();
-      Menu::set_current(main_menu);
-      resume_demo();
+      GameSession* session =
+        new GameSession(
+          current_contrib_world->get_level_filename(index), ST_GL_PLAY);
+      main_loop->push_screen(session);
     }
   }  
 }
 
-void draw_demo(float elapsed_time)
+void
+TitleScreen::make_tux_jump()
 {
   static Timer randomWaitTimer;
   static Timer jumpPushTimer;
-  static Timer jumpRecoverTimer;
   static float last_tux_x_pos = -1;
   static float last_tux_y_pos = -1;
 
   Sector* sector  = titlesession->get_current_sector();
   Player* tux = sector->player;
 
-  sector->play_music(LEVEL_MUSIC);
+  //sector->play_music(LEVEL_MUSIC);
 
   controller->update();
   controller->press(Controller::RIGHT);
@@ -262,23 +229,27 @@ void draw_demo(float elapsed_time)
   float dy = fabsf(last_tux_y_pos - tux->get_pos().y); 
  
   // Calculate space to check for obstacles 
-  Rect lookahead = Rect(tux->get_bbox());
-  lookahead.move(Vector(lookahead.get_width()*2,0));
+  Rect lookahead = tux->get_bbox();
+  lookahead.move(Vector(96, 0));
   
   // Check if we should press the jump button
   bool randomJump = !randomWaitTimer.started();
-  bool mayJump = !jumpRecoverTimer.started();
-  bool notMoving = (dx+dy < 0.1);
+  bool notMoving = (fabsf(dx) + fabsf(dy)) < 0.1;
   bool pathBlocked = !sector->is_free_space(lookahead); 
-  if ((notMoving || pathBlocked || randomJump) && mayJump) {
-    float jumpDuration = float(rand() % 200 + 500) / 1000.0;
+  if (!controller->released(Controller::JUMP)
+      && (notMoving || pathBlocked || randomJump)) {
+    float jumpDuration;
+    if(pathBlocked)
+      jumpDuration = 0.5;
+    else
+      jumpDuration = float(rand() % 500 + 300) / 1000.0;
     jumpPushTimer.start(jumpDuration);
-    jumpRecoverTimer.start(jumpDuration+0.1);
     randomWaitTimer.start(float(rand() % 3000 + 3000) / 1000.0);
   }
 
   // Keep jump button pressed
-  if (jumpPushTimer.started()) controller->press(Controller::JUMP);
+  if (jumpPushTimer.started())
+    controller->press(Controller::JUMP);
 
   // Remember last position, so we can determine if we moved
   last_tux_x_pos = tux->get_pos().x;
@@ -289,178 +260,192 @@ void draw_demo(float elapsed_time)
     sector->activate("main");
     sector->camera->reset(tux->get_pos());
   }
-
-  sector->update(elapsed_time);
-  sector->draw(*titlesession->context);
 }
 
-/* --- TITLE SCREEN --- */
-void title()
+TitleScreen::TitleScreen()
 {
-  //LevelEditor* leveleditor;
-  controller = new CodeController();
+  controller.reset(new CodeController());
+  titlesession.reset(new GameSession("levels/misc/menu.stl", ST_GL_DEMO_GAME));
 
-  titlesession = new GameSession("levels/misc/menu.stl", ST_GL_DEMO_GAME);
-
-  /* Load images: */
-  bkg_title = new Surface("images/background/arctis.jpg");
-  logo = new Surface("images/engine/menu/logo.png");
-  //img_choose_subset = new Surface("images/status/choose-level-subset.png");
+  // delete contrib_world_menu;
+  // contrib_world_menu = new Menu();
 
   titlesession->get_current_sector()->activate("main");
   titlesession->set_current();
 
   Player* player = titlesession->get_current_sector()->player;
-  player->set_controller(controller);
+  player->set_controller(controller.get());
 
-  /* --- Main title loop: --- */
-  frame = 0;
+  Menu::set_current(main_menu); 
+}
 
-  Uint32 lastticks = SDL_GetTicks();
-  
-  Menu::set_current(main_menu);
-  DrawingContext& context = *titlesession->context;
+TitleScreen::~TitleScreen()
+{
+}
 
-  console = new Console(&context);
+void
+TitleScreen::setup()
+{
+  player_status->reset();
 
-  bool running = true;
-  while (running)
-    {
-      // Calculate the movement-factor
-      Uint32 ticks = SDL_GetTicks();
-      float elapsed_time = float(ticks - lastticks) / 1000.;
-      game_time += elapsed_time;
-      lastticks = ticks;
-      // 40fps is minimum
-      if(elapsed_time > .04)
-        elapsed_time = .04;
-      
-      /* Lower the speed so that Tux doesn't jump too hectically throught
-         the demo. */
-      elapsed_time /= 2;
-
-      SDL_Event event;
-      main_controller->update();
-      while (SDL_PollEvent(&event)) {
-        if (Menu::current()) {
-          Menu::current()->event(event);
-        }
-        main_controller->process_event(event);
-        if (event.type == SDL_QUIT)
-          throw graceful_shutdown();
-      }
-  
-      /* Draw the background: */
-      draw_demo(elapsed_time);
+  Sector* sector = titlesession->get_current_sector();
+  sector->play_music(LEVEL_MUSIC);
+  sector->activate(sector->player->get_pos());
 
-      if (Menu::current() == main_menu)
-        context.draw_surface(logo, Vector(SCREEN_WIDTH/2 - logo->get_width()/2, 30),
+  Menu::set_current(main_menu);
+}
+
+void
+TitleScreen::draw(DrawingContext& context)
+{
+  Sector* sector  = titlesession->get_current_sector();
+  sector->draw(context);
+  /*
+  if (Menu::current() == main_menu)
+    context.draw_surface(logo, Vector(SCREEN_WIDTH/2 - logo->get_width()/2, 30),
             LAYER_FOREGROUND1+1);
+  */
 
-      context.draw_text(white_small_text, " SuperTux " PACKAGE_VERSION "\n",
-              Vector(0, SCREEN_HEIGHT - 50), LEFT_ALLIGN, LAYER_FOREGROUND1);
-      context.draw_text(white_small_text,
-        _(
+  context.draw_text(white_small_text, " SuperTux " PACKAGE_VERSION "\n",
+      Vector(0, SCREEN_HEIGHT - 50), LEFT_ALLIGN, LAYER_FOREGROUND1);
+  context.draw_text(white_small_text,
+      _(
 "Copyright (c) 2006 SuperTux Devel Team\n"
 "This game comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to\n"
 "redistribute it under certain conditions; see the file COPYING for details.\n"
-        ),
-        Vector(0, SCREEN_HEIGHT - 50 + white_small_text->get_height() + 5),
-        LEFT_ALLIGN, LAYER_FOREGROUND1);
-
-      /* Don't draw menu, if quit is true */
-      Menu* menu = Menu::current();
-      if(menu)
-        {
-          menu->draw(context);
-          menu->update();
+),
+      Vector(0, SCREEN_HEIGHT - 50 + white_small_text->get_height() + 5),
+      LEFT_ALLIGN, LAYER_FOREGROUND1);
+}
+
+void
+TitleScreen::update(float elapsed_time)
+{
+  main_loop->set_speed(0.6);
+  Sector* sector  = titlesession->get_current_sector();
+  sector->update(elapsed_time);
+
+  make_tux_jump();
+  
+  Menu* menu = Menu::current();
+  if(menu) {
+    menu->update();
          
-          if(menu == main_menu)
-            {
-              switch (main_menu->check())
-                {
-                case MNID_STARTGAME:
-                  // Start Game, ie. goto the slots menu
-                  update_load_save_game_menu(load_game_menu);
-                  break;
-                case MNID_LEVELS_CONTRIB:
-                  // Contrib Menu
-                  generate_contrib_menu();
-                  break;
-                case MNID_CREDITS:
-                  sound_manager->stop_music();
-                  fadeout(500);
-                  sound_manager->play_music("music/credits.ogg");
-                  display_text_file("credits.txt");
-                  sound_manager->stop_music();
-                  fadeout(500);
-                  Menu::set_current(main_menu);
-                  break;
-                case MNID_QUITMAINMENU:
-                  running = false;
-                  break;
-                }
-            }
-          else if(menu == options_menu)
-            {
-              process_options_menu();
-            }
-          else if(menu == load_game_menu)
-            {
-              if(event.key.keysym.sym == SDLK_DELETE)
-                {
-                int slot = menu->get_active_item_id();
-                std::stringstream stream;
-                stream << slot;
-                std::string str = _("Are you sure you want to delete slot") + stream.str() + "?";
-                
-                if(confirm_dialog(bkg_title, str.c_str())) {
-                  str = "save/slot" + stream.str() + ".stsg";
-                  msg_debug("Removing: " << str);
-                  PHYSFS_delete(str.c_str());
-                }
-
-                update_load_save_game_menu(load_game_menu);
-                Menu::set_current(main_menu);
-                resume_demo();
-                }
-              else if (process_load_game_menu())
-                {
-                  resume_demo();
-                }
-            }
-          else if(menu == contrib_menu)
-            {
-              check_levels_contrib_menu();
-            }
-          else if (menu == contrib_subset_menu)
-            {
-              check_contrib_subset_menu();
-            }
+    if(menu == main_menu) {
+      switch (main_menu->check()) {
+        case MNID_STARTGAME:
+          // Start Game, ie. goto the slots menu
+          update_load_game_menu();
+          Menu::push_current(load_game_menu.get());
+          break;
+        case MNID_LEVELS_CONTRIB:
+          // Contrib Menu
+          generate_contrib_menu();
+          Menu::push_current(contrib_menu.get());
+          break;
+        case MNID_CREDITS:
+          fadeout(500);
+          main_loop->push_screen(new TextScroller("credits.txt"));
+          break;
+        case MNID_QUITMAINMENU:
+          main_loop->quit();
+          break;
+      }
+    } else if(menu == options_menu) {
+      process_options_menu();
+    } else if(menu == load_game_menu.get()) {
+      /*
+      if(event.key.keysym.sym == SDLK_DELETE) {
+        int slot = menu->get_active_item_id();
+        std::stringstream stream;
+        stream << slot;
+        std::string str = _("Are you sure you want to delete slot") + stream.str() + "?";
+        
+        if(confirm_dialog(bkg_title, str.c_str())) {
+          str = "save/slot" + stream.str() + ".stsg";
+          msg_debug("Removing: " << str);
+          PHYSFS_delete(str.c_str());
         }
 
-      // reopen menu of user closed it (so that the app doesn't close when user
-      // accidently hit ESC)
-      if(Menu::current() == 0) {
+        update_load_save_game_menu(load_game_menu);
         Menu::set_current(main_menu);
-      }
+      }*/
+      process_load_game_menu();
+    } else if(menu == contrib_menu.get()) {
+      check_levels_contrib_menu();
+    } else if (menu == contrib_world_menu.get()) {
+      check_contrib_world_menu();
+    }
+  }
+
+  // reopen menu of user closed it (so that the app doesn't close when user
+  // accidently hit ESC)
+  if(Menu::current() == 0) {
+    Menu::set_current(main_menu);
+  }
+}
+
+std::string
+TitleScreen::get_slotinfo(int slot)
+{
+  std::string tmp;
+  std::string slotfile;
+  std::string title;
+  std::stringstream stream;
+  stream << slot;
+  slotfile = "save/slot" + stream.str() + ".stsg";
 
-      console->draw();
+  try {
+    lisp::Parser parser;
+    std::auto_ptr<lisp::Lisp> root (parser.parse(slotfile));
 
-      context.do_drawing();
-      sound_manager->update();
+    const lisp::Lisp* savegame = root->get_lisp("supertux-savegame");
+    if(!savegame)
+      throw std::runtime_error("file is not a supertux-savegame.");
 
-      //frame_rate.update();
+    savegame->get("title", title);
+  } catch(std::exception& e) {
+    return std::string(_("Slot")) + " " + stream.str() + " - " +
+      std::string(_("Free"));
+  }
 
-      /* Pause: */
-      frame++;
-    }
-  /* Free surfaces: */
+  return std::string("Slot ") + stream.str() + " - " + title;
+}
 
-  free_contrib_menu();
-  delete titlesession;
-  delete bkg_title;
-  delete logo;
-  delete console;
-  //delete img_choose_subset;
+bool
+TitleScreen::process_load_game_menu()
+{
+  int slot = load_game_menu->check();
+
+  if(slot == -1)
+    return false;
+
+  if(load_game_menu->get_item_by_id(slot).kind != MN_ACTION)
+    return false;
+
+  std::stringstream stream;
+  stream << slot;
+  std::string slotfile = "save/slot" + stream.str() + ".stsg";
+
+  sound_manager->stop_music();
+  fadeout(256);
+  DrawingContext context;
+  context.draw_text(white_text, "Loading...",
+                    Vector(SCREEN_WIDTH/2, SCREEN_HEIGHT/2),
+                    CENTER_ALLIGN, LAYER_FOREGROUND1);
+  context.do_drawing();
+
+  WorldMapNS::WorldMap* worldmap = new WorldMapNS::WorldMap();
+
+  worldmap->set_map_filename("/levels/world1/worldmap.stwm");
+  // Load the game or at least set the savegame_file variable
+  worldmap->loadgame(slotfile);
+
+  main_loop->push_screen(worldmap);
+
+  //Menu::set_current(main_menu);
+
+  return true;
 }
+
index ce841b1..aa26473 100644 (file)
 #ifndef SUPERTUX_TITLE_H
 #define SUPERTUX_TITLE_H
 
-enum MainMenuIDs {
-  MNID_STARTGAME,
-  MNID_LEVELS_CONTRIB,
-  MNID_OPTIONMENU,
-  MNID_LEVELEDITOR,
-  MNID_CREDITS,
-  MNID_QUITMAINMENU
-  };
+#include <memory>
+#include <vector>
+#include "screen.hpp"
+#include "game_session.hpp"
+
+class Menu;
+class World;
+class CodeController;
+
+class TitleScreen : public Screen
+{
+public:
+  TitleScreen();
+  virtual ~TitleScreen();
+
+  virtual void setup();
+
+  virtual void draw(DrawingContext& context);
+
+  virtual void update(float elapsed_time);
+
+private:
+  std::string get_slotinfo(int slot);
+  std::string get_level_name(const std::string& levelfile);
+  bool process_load_game_menu();
+  void make_tux_jump();
+  void update_load_game_menu();
+  void generate_contrib_menu();
+  void check_levels_contrib_menu();
+  void check_contrib_world_menu();
+  void free_contrib_menu();
+
+  std::auto_ptr<Menu> load_game_menu;
+  std::auto_ptr<Menu> contrib_menu;
+  std::auto_ptr<Menu> contrib_world_menu;
+  std::vector<World*> contrib_worlds;
+  int current_world;
+  World* current_contrib_world;
   
-void title();
+  std::auto_ptr<CodeController> controller;
+  std::auto_ptr<GameSession> titlesession;
+};
 
-#endif //SUPERTUX_TITLE_H
+#endif
 
index 2227ccf..da579f0 100644 (file)
@@ -38,7 +38,7 @@
 
 static const float LOOP_DELAY = 20.0;
 
-void fillrect(float x, float y, float w, float h, int r, int g, int b, int a)
+void fillrect(float x, float y, float w, float h, const Color& col)
 {
   if(w < 0) {
     x += w;
@@ -49,7 +49,7 @@ void fillrect(float x, float y, float w, float h, int r, int g, int b, int a)
     h = -h;
   }
 
-  glColor4ub(r, g, b,a);
+  glColor4f(col.red, col.green, col.blue, col.alpha);
 
   glDisable(GL_TEXTURE_2D);
   glBegin(GL_POLYGON);
@@ -59,34 +59,40 @@ void fillrect(float x, float y, float w, float h, int r, int g, int b, int a)
   glVertex2f(x, y+h);
   glEnd();
   glEnable(GL_TEXTURE_2D);
+
+  glColor4f(0, 0, 0, 1);
 }
 
-void fadeout(int fade_time)
+void fadeout(float fade_time)
 {
-  float alpha_inc  = 256 / (fade_time / LOOP_DELAY);
-  float alpha = 256;
+  float alpha_inc  = LOOP_DELAY / fade_time;
+  Color c(0, 0, 0, alpha_inc);
+  float alpha = 1.0;
 
-  while(alpha > 0) {
+  while(alpha >= 0) {
     alpha -= alpha_inc;
-    fillrect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0,0,0, (int)alpha_inc);  // left side
+    fillrect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, c);
+    // left side
     
     SDL_GL_SwapBuffers();
     sound_manager->update();
     
     SDL_Delay(int(LOOP_DELAY));
+    alpha -= alpha_inc; 
   }
 
-  fillrect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, 0, 255);
+  fillrect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, Color());
 }
 
-void shrink_fade(const Vector& point, int fade_time)
+void shrink_fade(const Vector& point, float fade_time)
 {
-  float left_inc  = point.x / ((float)fade_time / LOOP_DELAY);
-  float right_inc = (SCREEN_WIDTH - point.x) / ((float)fade_time / LOOP_DELAY);
-  float up_inc    = point.y / ((float)fade_time / LOOP_DELAY);
-  float down_inc  = (SCREEN_HEIGHT - point.y) / ((float)fade_time / LOOP_DELAY);
+  float left_inc  = point.x / (fade_time / LOOP_DELAY);
+  float right_inc = (SCREEN_WIDTH - point.x) / (fade_time / LOOP_DELAY);
+  float up_inc    = point.y / (fade_time / LOOP_DELAY);
+  float down_inc  = (SCREEN_HEIGHT - point.y) / (fade_time / LOOP_DELAY);
                                                                                 
   float left_cor = 0, right_cor = 0, up_cor = 0, down_cor = 0;
+  Color c;
                                                                                 
   while(left_cor < point.x && right_cor < SCREEN_WIDTH - point.x &&
       up_cor < point.y && down_cor < SCREEN_HEIGHT - point.y) {
@@ -95,10 +101,10 @@ void shrink_fade(const Vector& point, int fade_time)
     up_cor    += up_inc;
     down_cor  += down_inc;
                                                                                 
-    fillrect(0, 0, left_cor, SCREEN_HEIGHT, 0,0,0);  // left side
-    fillrect(SCREEN_WIDTH - right_cor, 0, right_cor, SCREEN_HEIGHT, 0,0,0);  // right side
-    fillrect(0, 0, SCREEN_WIDTH, up_cor, 0,0,0);  // up side
-    fillrect(0, SCREEN_HEIGHT - down_cor, SCREEN_WIDTH, down_cor+1, 0,0,0);  // down side                                                                                
+    fillrect(0, 0, left_cor, SCREEN_HEIGHT, c);  // left side
+    fillrect(SCREEN_WIDTH - right_cor, 0, right_cor, SCREEN_HEIGHT, c);  // right side
+    fillrect(0, 0, SCREEN_WIDTH, up_cor, c);  // up side
+    fillrect(0, SCREEN_HEIGHT - down_cor, SCREEN_WIDTH, down_cor+1, c);  // down side
 
     SDL_GL_SwapBuffers();
   
@@ -106,3 +112,4 @@ void shrink_fade(const Vector& point, int fade_time)
     SDL_Delay(int(LOOP_DELAY));
   }
 }
+
index a26d5e9..1af2635 100644 (file)
@@ -26,9 +26,7 @@
 #include <vector>
 #include "math/vector.hpp"
 
-void fillrect(float x, float y, float w, float h, int r, int g, int b, int a = 255);
-
-void fadeout(int fade_time);
-void shrink_fade(const Vector& point, int fade_time);
+void fadeout(float fade_time);
+void shrink_fade(const Vector& point, float fade_time);
 
 #endif
index 56ec74b..38ad411 100644 (file)
@@ -54,7 +54,7 @@ TextureManager::get(const std::string& _filename)
 void
 TextureManager::release(ImageTexture* texture)
 {
-  image_textures[texture->filename] = NULL;
+  image_textures.erase(texture->filename);
   delete texture;
 }
 
diff --git a/src/world.cpp b/src/world.cpp
new file mode 100644 (file)
index 0000000..a806afd
--- /dev/null
@@ -0,0 +1,118 @@
+//  $Id: level_subset.cpp 3118 2006-03-25 17:29:08Z sommer $
+// 
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+// 
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+//  02111-1307, USA.
+#include <config.h>
+
+#include <physfs.h>
+#include <stdexcept>
+
+#include "world.hpp"
+#include "file_system.hpp"
+#include "lisp/parser.hpp"
+#include "lisp/lisp.hpp"
+#include "physfs/physfs_stream.hpp"
+#include "scripting/script_interpreter.hpp"
+#include "msg.hpp"
+
+static bool has_suffix(const std::string& data, const std::string& suffix)
+{
+  if (data.length() >= suffix.length())
+    return data.compare(data.length() - suffix.length(), suffix.length(), suffix) == 0;
+  else
+    return false;
+}
+
+World::World()
+{
+  is_levelset = true;
+  hide_from_contribs = false;
+}
+
+World::~World()
+{
+}
+
+void
+World::load(const std::string& filename)
+{
+  basedir = FileSystem::dirname(filename);
+  
+  lisp::Parser parser;
+  std::auto_ptr<lisp::Lisp> root (parser.parse(filename));
+
+  const lisp::Lisp* info = root->get_lisp("supertux-world");
+  if(info == NULL)
+    info = root->get_lisp("supertux-level-subset");
+  if(info == NULL)
+    throw std::runtime_error("File is not a world or levelsubset file");
+
+  hide_from_contribs = false;
+  is_levelset = true;
+
+  info->get("title", title);
+  info->get("description", description);
+  info->get("levelset", is_levelset);
+  info->get_vector("levels", levels);
+  info->get("hide-from-contribs", hide_from_contribs);
+
+  // Level info file doesn't define any levels, so read the
+  // directory to see what we can find
+      
+  std::string path = basedir + "/";
+  char** files = PHYSFS_enumerateFiles(path.c_str());
+  if(!files) {
+    msg_warning("Couldn't read subset dir '" 
+              << path << "'");
+    return;
+  }
+
+  for(const char* const* filename = files; *filename != 0; ++filename) {
+    if(has_suffix(*filename, ".stl")) {
+      levels.push_back(path + *filename);
+    }
+  }
+  PHYSFS_freeList(files);
+}
+
+void
+World::run()
+{
+  try {
+    std::string filename = basedir + "/world.nut";
+    std::auto_ptr<ScriptInterpreter> interpeter (new ScriptInterpreter(basedir));
+    IFileStream in(filename);
+  
+    interpeter->run_script(in, filename, true);
+  } catch(std::exception& e) {
+    msg_warning("Problem running world script: " << e.what());
+  }
+}
+
+const std::string&
+World::get_level_filename(unsigned int i) const
+{
+  return levels[i];
+}
+
+unsigned int
+World::get_num_levels() const
+{
+  return levels.size();
+}
+
diff --git a/src/world.hpp b/src/world.hpp
new file mode 100644 (file)
index 0000000..12e7759
--- /dev/null
@@ -0,0 +1,51 @@
+//  $Id: worldmap.hpp 2800 2005-10-02 22:57:31Z matzebraun $
+// 
+//  SuperTux
+//  Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+// 
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#ifndef SUPERTUX_WORLD_H
+#define SUPERTUX_WORLD_H
+
+#include <vector>
+#include <string>
+
+class World
+{
+private:
+  std::vector<std::string> levels;
+  std::string basedir;
+
+public:
+  World();
+  ~World();
+
+  void load(const std::string& filename);
+  
+  const std::string& get_level_filename(unsigned int i) const;
+  unsigned int get_num_levels() const;
+
+  const std::string& get_basedir() const;
+
+  void run();
+
+  std::string title;
+  std::string description;
+  bool hide_from_contribs;
+  bool is_levelset;
+};
+
+#endif
+
index e7dfc8c..26fb7be 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "gettext.hpp"
 #include "msg.hpp"
+#include "mainloop.hpp"
 #include "video/surface.hpp"
 #include "video/screen.hpp"
 #include "video/drawing_context.hpp"
@@ -64,6 +65,8 @@ static const float map_message_TIME = 2.8;
 
 namespace WorldMapNS {
 
+WorldMap* WorldMap::current_ = NULL;
+
 Direction reverse_dir(Direction direction)
 {
   switch(direction)
@@ -678,6 +681,50 @@ WorldMap::path_ok(Direction direction, Vector old_pos, Vector* new_pos)
 }
 
 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();
+
+  if(savegame_file != "")
+    savegame(savegame_file);
+
+  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());
+
+    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);
+    }
+  }
+}
+
+void
 WorldMap::update(float delta)
 {
   Menu* menu = Menu::current();
@@ -691,7 +738,7 @@ WorldMap::update(float delta)
           Menu::set_current(0);
           break;
         case MNID_QUITWORLDMAP: // Quit Worldmap
-          quit = true;                               
+          main_loop->exit_screen();
           break;
       }
     } else if(menu == options_menu) {
@@ -707,6 +754,7 @@ WorldMap::update(float delta)
     GameObject* object = *i;
     object->update(delta);
   }
+
   // remove old GameObjects
   for(GameObjects::iterator i = game_objects.begin();
       i != game_objects.end(); ) {
@@ -718,7 +766,23 @@ WorldMap::update(float delta)
       ++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)
@@ -746,117 +810,22 @@ WorldMap::update(float delta)
       /* Check level action */
       bool level_finished = true;
       Level* level = at_level();
-      if (!level)
-        {
+      if (!level) {
         msg_warning("No level to enter at: "
-          << tux->get_tile_pos().x << ", " << tux->get_tile_pos().y);
+            << tux->get_tile_pos().x << ", " << tux->get_tile_pos().y);
         return;
-        }
-
+      }
 
       if (level->pos == tux->get_tile_pos())
         {
-          sound_manager->stop_music();
-          PlayerStatus old_player_status;
-          old_player_status = *player_status;
-
           // 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);
-          GameSession session(levels_path + level->name,
-                              ST_GL_LOAD_LEVEL_FILE, &level->statistics);
-
-          switch (session.run())
-            {
-            case GameSession::ES_LEVEL_FINISHED:
-              {
-                level_finished = true;
-                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();
-
-                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());
-
-                    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);
-                      }
-                  }
-              }
-
-              break;
-            case GameSession::ES_LEVEL_ABORT:
-              level_finished = false;
-              /* In case the player's abort the level, keep it using the old
-                  status. But the minimum lives and no bonus. */
-              player_status->coins = std::min(old_player_status.coins, player_status->coins);
-              player_status->bonus = NO_BONUS;
-              break;
-           /*
-            case GameSession::ES_GAME_OVER:
-              {
-              level_finished = false;
-              // draw an end screen
-              // TODO: in the future, this should make a dialog a la SuperMario, asking
-              // if the player wants to restart the world map with no score and from
-              // level 1
-              char str[80];
-
-              DrawingContext context;
-              context.draw_gradient(Color (200,240,220), Color(200,200,220),
-                  LAYER_BACKGROUND0);
-
-              context.draw_text(blue_text, _("GAMEOVER"), 
-                  Vector(SCREEN_WIDTH/2, 200), CENTER_ALLIGN, LAYER_FOREGROUND1);
-
-              sprintf(str, _("COINS: %d"), player_status->coins);
-              context.draw_text(gold_text, str,
-                  Vector(SCREEN_WIDTH/2, SCREEN_WIDTH - 32), CENTER_ALLIGN,
-                  LAYER_FOREGROUND1);
-
-              total_stats.draw_message_info(context, _("Total Statistics"));
-
-              context.do_drawing();
-
-              wait_for_event(2.0, 6.0);
 
-              quit = true;
-              player_status->reset();
-              break;
-              }
-           */
-            case GameSession::ES_NONE:
-              assert(false);
-              // Should never be reached 
-              break;
-            }
-
-          sound_manager->play_music(music);
-          Menu::set_current(0);
-          if (!savegame_file.empty())
-            savegame(savegame_file);
+          GameSession *session =
+              new GameSession(levels_path + level->name,
+                              ST_GL_LOAD_LEVEL_FILE, &level->statistics);
+          main_loop->push_screen(session);
         }
       /* The porpose of the next checking is that if the player lost
          the level (in case there is one), don't show anything */
@@ -879,7 +848,7 @@ WorldMap::update(float delta)
           loadmap(level->next_worldmap);
           }
         if (level->quit_worldmap)
-          quit = true;
+          main_loop->exit_screen();
         }
     }
   else
@@ -921,6 +890,9 @@ WorldMap::at_special_tile()
 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;
@@ -950,6 +922,7 @@ WorldMap::draw(DrawingContext& context)
     }
 
   draw_status(context);
+  context.pop_transform();
 }
 
 void
@@ -1002,73 +975,12 @@ WorldMap::draw_status(DrawingContext& context)
 }
 
 void
-WorldMap::display()
+WorldMap::setup()
 {
-  Menu::set_current(0);
-
-  quit = false;
-
   sound_manager->play_music(music);
+  Menu::set_current(NULL);
 
-  if(!intro_displayed && intro_script != "") {
-    try {
-      std::auto_ptr<ScriptInterpreter> interpreter 
-        (new ScriptInterpreter(levels_path));
-      std::istringstream in(intro_script);
-      interpreter->run_script(in, "worldmap-intro-script");
-      add_object(interpreter.release());
-    } catch(std::exception& e) {
-      msg_warning("Couldn't execute worldmap-intro-script: "
-        << e.what());
-    }
-                                           
-    intro_displayed = true;
-  }
-
-  Uint32 lastticks = SDL_GetTicks();
-  DrawingContext context;
-  Console* console = new Console(&context);
-  while(!quit) {
-    Uint32 ticks = SDL_GetTicks();
-    float elapsed_time = float(ticks - lastticks) / 1000;
-    game_time += elapsed_time;
-    lastticks = ticks;
-    
-    // 40 fps minimum // TODO use same code as in GameSession here
-    if(elapsed_time > .025)
-      elapsed_time = .025;
-    
-    Vector tux_pos = tux->get_pos();
-    offset.x = tux_pos.x - SCREEN_WIDTH/2;
-    offset.y = tux_pos.y - SCREEN_HEIGHT/2;
-
-    if (offset.x < 0)
-      offset.x = 0;
-    if (offset.y < 0)
-      offset.y = 0;
-
-    if (offset.x > solids->get_width()*32 - SCREEN_WIDTH)
-      offset.x = solids->get_width()*32 - SCREEN_WIDTH;
-    if (offset.y > solids->get_height()*32 - SCREEN_HEIGHT)
-      offset.y = solids->get_height()*32 - SCREEN_HEIGHT;
-
-    context.push_transform();
-    context.set_translation(offset);
-    draw(context);
-    context.pop_transform();
-    get_input();
-    update(elapsed_time);
-    sound_manager->update();
-      
-    if(Menu::current()) {
-      Menu::current()->draw(context);
-    }
-
-    console->draw();
-    context.do_drawing();
-  }
-  
-  delete console;
+  current_ = this;
 }
 
 void
index 24db457..0833c38 100644 (file)
@@ -29,6 +29,7 @@
 #include "control/controller.hpp"
 #include "statistics.hpp"
 #include "timer.hpp"
+#include "screen.hpp"
 #include "tile_manager.hpp"
 #include "game_object.hpp"
 #include "console.hpp"
@@ -104,17 +105,18 @@ public:
 };
 
 /** */
-class WorldMap
+class WorldMap : public Screen
 {
 private:
   Tux* tux;
 
-  bool quit;
-
   Surface* leveldot_green;
   Surface* leveldot_red;
   Surface* messagedot;
   Sprite* teleporterdot;
+  static WorldMap* current_;
+
+  Vector camera_offset;
 
   std::string name;
   std::string music;
@@ -225,9 +227,6 @@ public:
   WorldMap();
   ~WorldMap();
 
-  /** Busy loop */
-  void display();
-
   void load_map();
   
   void get_input();
@@ -235,6 +234,11 @@ public:
   void add_object(GameObject* object);
   void clear_objects();
 
+  static WorldMap* current()
+  { return current_; }
+
+  void setup();
+
   /** Update Tux position */
   void update(float delta);
 
@@ -244,6 +248,12 @@ public:
   Vector get_next_tile(Vector pos, Direction direction);
   const Tile* at(Vector pos);
 
+  /**
+   * 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();