- Refactored worldmap a bit to reuse GameObject from the rest of the game
authorMatthias Braun <matze@braunis.de>
Thu, 12 May 2005 11:25:09 +0000 (11:25 +0000)
committerMatthias Braun <matze@braunis.de>
Thu, 12 May 2005 11:25:09 +0000 (11:25 +0000)
- Moved status drawing to PlayerStatus class
- Made Level timeout an own object, so that you can explicitely enable it in
  some levels. (So all these levels with 999 time will no have no time)
- Fixed wrong encoding for level/worldmap translations
- Added workaround to tinygettext to skip the UTF-8 BOM

SVN-Revision: 2474

37 files changed:
data/images/engine/editor/clock.png [new file with mode: 0644]
data/levels/bonus1/abednego-level4.stl
data/levels/bonus1/worldmap.stwm
data/levels/misc/menu.stl
data/levels/world1/de.po
data/levels/world1/worldmap.stwm
src/badguy/badguy.cpp
src/control/joystickkeyboardcontroller.cpp
src/control/joystickkeyboardcontroller.h
src/flip_level_transformer.cpp
src/flip_level_transformer.h
src/game_session.cpp
src/game_session.h
src/gettext.h
src/gui/menu.cpp
src/gui/mousecursor.cpp
src/level.cpp
src/level.h
src/lisp/parser.cpp
src/main.cpp
src/object/level_time.cpp [new file with mode: 0644]
src/object/level_time.h [new file with mode: 0644]
src/object/player.h
src/object/tilemap.cpp
src/object/tilemap.h
src/player_status.cpp
src/player_status.h
src/sector.cpp
src/sector.h
src/tinygettext/tinygettext.cpp
src/tinygettext/tinygettext.h
src/title.cpp
src/trigger/scripttrigger.cpp
src/video/surface.cpp
src/video/surface.h
src/worldmap.cpp
src/worldmap.h

diff --git a/data/images/engine/editor/clock.png b/data/images/engine/editor/clock.png
new file mode 100644 (file)
index 0000000..ce4d584
Binary files /dev/null and b/data/images/engine/editor/clock.png differ
index 9a03c5a..ae41af7 100644 (file)
@@ -15,7 +15,6 @@
   (bkgd_red_bottom    255)
   (bkgd_green_bottom  255)
   (bkgd_blue_bottom   255)
   (bkgd_red_bottom    255)
   (bkgd_green_bottom  255)
   (bkgd_blue_bottom   255)
-  (time  60)
   (gravity  10.0)
   (particle_system "snow")
   (theme "antarctica")
   (gravity  10.0)
   (particle_system "snow")
   (theme "antarctica")
@@ -76,6 +75,9 @@
   (reset-points
    )
   (objects
   (reset-points
    )
   (objects
+    (leveltime
+      (time 60)
+    )
     (spiky  (x 2171) (y 348))
     (spiky  (x 2035) (y 312))
     (spiky  (x 1947) (y 323))
     (spiky  (x 2171) (y 348))
     (spiky  (x 2035) (y 312))
     (spiky  (x 1947) (y 323))
index 9f60663..250c951 100644 (file)
@@ -3,8 +3,11 @@
   (properties
     (name (_ "Bonus Island I"))
     (music "salcon.mod")
   (properties
     (name (_ "Bonus Island I"))
     (music "salcon.mod")
-    (start_pos_x 35)
-    (start_pos_y 2)
+  )
+  (spawnpoint
+    (name "main")
+    (x 35)
+    (y 2)
   )
   (tilemap
     (width 70)
   )
   (tilemap
     (width 70)
index a7e6313..eb57c88 100644 (file)
@@ -3,7 +3,6 @@
   (version 2)
   (name   (_ "Menu Level"))
   (author "SuperTux Team")
   (version 2)
   (name   (_ "Menu Level"))
   (author "SuperTux Team")
-  (time   500)
   (sector
     (name  "main")
     (music  "theme.ogg")
   (sector
     (name  "main")
     (music  "theme.ogg")
index 11fa716..91a252b 100644 (file)
@@ -1,4 +1,4 @@
-# German translations for world package
+# German translations for world package
 # German messages for world.
 # Copyright (C) 2004 THE world'S COPYRIGHT HOLDER
 # This file is distributed under the same license as the world package.
 # German messages for world.
 # Copyright (C) 2004 THE world'S COPYRIGHT HOLDER
 # This file is distributed under the same license as the world package.
@@ -13,7 +13,7 @@ msgstr ""
 "Last-Translator:  <matze@braunis.de>\n"
 "Language-Team: German <de@li.org>\n"
 "MIME-Version: 1.0\n"
 "Last-Translator:  <matze@braunis.de>\n"
 "Language-Team: German <de@li.org>\n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
@@ -45,9 +45,9 @@ msgstr ""
 "\n"
 "#Tux und Penny sassen gemtlich beim Picknick\n"
 "#in den eisigen Ebenen der Antarktis.\n"
 "\n"
 "#Tux und Penny sassen gemtlich beim Picknick\n"
 "#in den eisigen Ebenen der Antarktis.\n"
-"#Plzlich sprang eine dunkle Kreatur hinter\n"
+"#Plötzlich sprang eine dunkle Kreatur hinter\n"
 "#einem Felsen hervor. Tux sah einen grellen\n"
 "#einem Felsen hervor. Tux sah einen grellen\n"
-"#Blitz, dann wurde er ohnmhtig.\n"
+"#Blitz, dann wurde er ohnmächtig.\n"
 "\n"
 "#Als er aufwachte bemerkte er, dass Penny\n"
 "#verschwunden war. Wo sie eben noch gesessen\n"
 "\n"
 "#Als er aufwachte bemerkte er, dass Penny\n"
 "#verschwunden war. Wo sie eben noch gesessen\n"
@@ -82,11 +82,11 @@ msgstr "Zu den Sternen"
 
 #: basest/levels/world1/level13.stl:5
 msgid "Above the Arctic Skies"
 
 #: basest/levels/world1/level13.stl:5
 msgid "Above the Arctic Skies"
-msgstr "er den Wolken"
+msgstr "Über den Wolken"
 
 #: basest/levels/world1/level14.stl:5
 msgid "Entrance to the Cave"
 
 #: basest/levels/world1/level14.stl:5
 msgid "Entrance to the Cave"
-msgstr "Hleneingang"
+msgstr "Höhleneingang"
 
 #: basest/levels/world1/level15.stl:5
 msgid "Under the Ice"
 
 #: basest/levels/world1/level15.stl:5
 msgid "Under the Ice"
@@ -94,7 +94,7 @@ msgstr "Unter dem Eis"
 
 #: basest/levels/world1/level16.stl:5
 msgid "Living in a Fridge"
 
 #: basest/levels/world1/level16.stl:5
 msgid "Living in a Fridge"
-msgstr "Leben im Khlschrank"
+msgstr "Leben im Kühlschrank"
 
 #: basest/levels/world1/level17.stl:5
 msgid "'...or is it just me?'"
 
 #: basest/levels/world1/level17.stl:5
 msgid "'...or is it just me?'"
@@ -126,7 +126,7 @@ msgstr "Die Flucht"
 
 #: basest/levels/world1/level24.stl:5
 msgid "The Shattered Bridge"
 
 #: basest/levels/world1/level24.stl:5
 msgid "The Shattered Bridge"
-msgstr "Brckentrmmer"
+msgstr "Die zertrümmerte Brücke"
 
 #: basest/levels/world1/level25.stl:5
 msgid "Arctic Ruins"
 
 #: basest/levels/world1/level25.stl:5
 msgid "Arctic Ruins"
@@ -146,7 +146,7 @@ msgstr "Die Reise Beginnt"
 
 #: basest/levels/world1/level3.stl:5
 msgid "Via Nostalgica"
 
 #: basest/levels/world1/level3.stl:5
 msgid "Via Nostalgica"
-msgstr "Nostalgiestra"
+msgstr "Nostalgiestraße"
 
 #: basest/levels/world1/level4.stl:5
 msgid "Tobgle Road"
 
 #: basest/levels/world1/level4.stl:5
 msgid "Tobgle Road"
@@ -162,7 +162,7 @@ msgstr "Eisige Felder"
 
 #: basest/levels/world1/level7.stl:5
 msgid "Oh no! More Snowballs!"
 
 #: basest/levels/world1/level7.stl:5
 msgid "Oh no! More Snowballs!"
-msgstr "Oh Nein! Noch mehr Schneeble!"
+msgstr "Oh Nein! Noch mehr Schneebälle!"
 
 #: basest/levels/world1/level8.stl:5
 msgid "Stone Cold"
 
 #: basest/levels/world1/level8.stl:5
 msgid "Stone Cold"
@@ -170,7 +170,7 @@ msgstr "Steinkalt"
 
 #: basest/levels/world1/level9.stl:5
 msgid "Grumbel's Sense of Snow"
 
 #: basest/levels/world1/level9.stl:5
 msgid "Grumbel's Sense of Snow"
-msgstr "Grumbels Schneegespr"
+msgstr "Grumbels Gespür für Schnee"
 
 #: basest/levels/world1/extro.txt:7
 msgid ""
 
 #: basest/levels/world1/extro.txt:7
 msgid ""
@@ -228,17 +228,17 @@ msgstr ""
 "#dennoch vergeblich. Mit jeder meiner\n"
 "#Festungen die du eroberst, werde ich zu\n"
 "#einer weiteren fliehen. Sei nicht dumm,\n"
 "#dennoch vergeblich. Mit jeder meiner\n"
 "#Festungen die du eroberst, werde ich zu\n"
 "#einer weiteren fliehen. Sei nicht dumm,\n"
-"#es we das beste jetzt aufzugeben.\n"
+"#es wäre das beste jetzt aufzugeben.\n"
 "\n"
 "#Tux verliess traurig den Saal, als etwas\n"
 "#unter seinem Fuss raschelte...\n"
 "#Ein Briefumschlag mit seinem Namen!\n"
 "#In dem Umschlag war eine grobe Karte,\n"
 "\n"
 "#Tux verliess traurig den Saal, als etwas\n"
 "#unter seinem Fuss raschelte...\n"
 "#Ein Briefumschlag mit seinem Namen!\n"
 "#In dem Umschlag war eine grobe Karte,\n"
-"#die Festungen in verschiedenen Ldern\n"
+"#die Festungen in verschiedenen Ländern\n"
 "#zeigte. Auf der Rckseite der Karte war\n"
 "#Pennys Zeichen, das Bild einer Eisblume.\n"
 "\n"
 "#Tux nahm die Karte in die Hand und rannte\n"
 "#zeigte. Auf der Rckseite der Karte war\n"
 "#Pennys Zeichen, das Bild einer Eisblume.\n"
 "\n"
 "#Tux nahm die Karte in die Hand und rannte\n"
-"#aus der Festung. Nein, er wrde nicht\n"
+"#aus der Festung. Nein, er würde nicht\n"
 "#einfach aufgeben. Penny verliess sich auf\n"
 "#ihn.\n"
 "#einfach aufgeben. Penny verliess sich auf\n"
 "#ihn.\n"
index 67c2a95..8934bc9 100644 (file)
@@ -4,11 +4,16 @@
     (name (_ "Icyisland"))
     (intro-filename "intro.txt")
     (music "salcon.mod")
     (name (_ "Icyisland"))
     (intro-filename "intro.txt")
     (music "salcon.mod")
-    (start_pos_x 4)
-    (start_pos_y 5))
+  )
+  (spawnpoint
+    (name "main")
+    (x 4)
+    (y 5)
+  )
   (tilemap 
     (width  40)
     (height 30)
   (tilemap 
     (width  40)
     (height 30)
+    (solid #t)
     (tiles
        9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  
        9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  11 12 9  9  9  9  9  9  9  9  9  9  9  9  
     (tiles
        9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  
        9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  11 12 9  9  9  9  9  9  9  9  9  9  9  9  
index a312986..7dcb5c8 100644 (file)
@@ -153,7 +153,7 @@ BadGuy::collision_player(Player& player, const CollisionHit& )
     return ABORT_MOVE;
   }
   // hit from above?
     return ABORT_MOVE;
   }
   // hit from above?
-  if(player.get_movement().y > 0 && player.get_bbox().p2.y <
+  if(player.get_movement().y - get_movement().y > 0 && player.get_bbox().p2.y <
       (get_bbox().p1.y + get_bbox().p2.y) / 2) {
     // if it's not is it possible to squish us, then this will hurt
     if(!collision_squished(player))
       (get_bbox().p1.y + get_bbox().p2.y) / 2) {
     // if it's not is it possible to squish us, then this will hurt
     if(!collision_squished(player))
index 09220c9..6bebf6b 100644 (file)
@@ -116,6 +116,13 @@ JoystickKeyboardController::JoystickKeyboardController()
     if(i != min_joybuttons-1)
       joy_button_map.insert(std::make_pair(i, MENU_SELECT));
   }
     if(i != min_joybuttons-1)
       joy_button_map.insert(std::make_pair(i, MENU_SELECT));
   }
+
+  // some joysticks or SDL seem to produce some bogus events after being opened
+  Uint32 ticks = SDL_GetTicks();
+  while(SDL_GetTicks() - ticks < 200) {
+    SDL_Event event;
+    SDL_PollEvent(&event);
+  }
 }
 
 JoystickKeyboardController::~JoystickKeyboardController()
 }
 
 JoystickKeyboardController::~JoystickKeyboardController()
@@ -228,6 +235,14 @@ JoystickKeyboardController::write(lisp::Writer& writer)
 }
 
 void
 }
 
 void
+JoystickKeyboardController::reset()
+{
+  Controller::reset();
+  for(size_t i = 0; i < sizeof(last_keys); ++i)
+      last_keys[i] = 0;
+}
+
+void
 JoystickKeyboardController::process_event(const SDL_Event& event)
 {
   switch(event.type) {
 JoystickKeyboardController::process_event(const SDL_Event& event)
 {
   switch(event.type) {
index 150ddb3..6520a2b 100644 (file)
@@ -43,6 +43,7 @@ public:
   void write(lisp::Writer& writer);
   void read(const lisp::Lisp& lisp);
        bool check_cheatcode(const std::string& cheatcode);
   void write(lisp::Writer& writer);
   void read(const lisp::Lisp& lisp);
        bool check_cheatcode(const std::string& cheatcode);
+  void reset();
 
   Menu* get_key_options_menu();
   Menu* get_joystick_options_menu();
 
   Menu* get_key_options_menu();
   Menu* get_joystick_options_menu();
index 6e2b2db..22f10d4 100644 (file)
@@ -17,7 +17,6 @@
 //  along with this program; if not, write to the Free Software
 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 //  02111-1307, USA.
 //  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 "flip_level_transformer.h"
 #include <config.h>
 
 #include "flip_level_transformer.h"
@@ -25,6 +24,7 @@
 #include "badguy/badguy.h"
 #include "sector.h"
 #include "tile_manager.h"
 #include "badguy/badguy.h"
 #include "sector.h"
 #include "tile_manager.h"
+#include "spawn_point.h"
 
 void
 FlipLevelTransformer::transform_sector(Sector* sector)
 
 void
 FlipLevelTransformer::transform_sector(Sector* sector)
index 317629f..79b7b02 100644 (file)
@@ -17,7 +17,6 @@
 //  along with this program; if not, write to the Free Software
 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 //  02111-1307, USA.
 //  along with this program; if not, write to the Free Software
 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 //  02111-1307, USA.
-
 #ifndef __FLIP_LEVEL_TRANSFORMER_H__
 #define __FLIP_LEVEL_TRANSFORMER_H__
 
 #ifndef __FLIP_LEVEL_TRANSFORMER_H__
 #define __FLIP_LEVEL_TRANSFORMER_H__
 
index 86b38e3..1402e64 100644 (file)
@@ -109,7 +109,7 @@ GameSession::restart_level()
   global_stats.reset();
   global_stats.set_total_points(COINS_COLLECTED_STAT, level->get_total_coins());
   global_stats.set_total_points(BADGUYS_KILLED_STAT, level->get_total_badguys());
   global_stats.reset();
   global_stats.set_total_points(COINS_COLLECTED_STAT, level->get_total_coins());
   global_stats.set_total_points(BADGUYS_KILLED_STAT, level->get_total_badguys());
-  global_stats.set_total_points(TIME_NEEDED_STAT, level->timelimit);
+  //global_stats.set_total_points(TIME_NEEDED_STAT, level->timelimit);
 
   if(reset_sector != "") {
     currentsector = level->get_sector(reset_sector);
 
   if(reset_sector != "") {
     currentsector = level->get_sector(reset_sector);
@@ -129,7 +129,6 @@ GameSession::restart_level()
   if(mode == ST_GL_PLAY || mode == ST_GL_LOAD_LEVEL_FILE)
     levelintro();
 
   if(mode == ST_GL_PLAY || mode == ST_GL_LOAD_LEVEL_FILE)
     levelintro();
 
-  start_timers();
   currentsector->play_music(LEVEL_MUSIC);
 
   if(capture_file != "")
   currentsector->play_music(LEVEL_MUSIC);
 
   if(capture_file != "")
@@ -219,13 +218,6 @@ GameSession::levelintro()
   wait_for_event(1.0, 3.0);
 }
 
   wait_for_event(1.0, 3.0);
 }
 
-/* Reset Timers */
-void
-GameSession::start_timers()
-{
-  time_left.start(level->timelimit);
-}
-
 void
 GameSession::on_escape_press()
 {
 void
 GameSession::on_escape_press()
 {
@@ -315,6 +307,8 @@ GameSession::process_events()
 void
 GameSession::try_cheats()
 {
 void
 GameSession::try_cheats()
 {
+  if(currentsector == 0)
+    return;
   Player& tux = *currentsector->player;
   
   // Cheating words (the goal of this is really for debugging,
   Player& tux = *currentsector->player;
   
   // Cheating words (the goal of this is really for debugging,
@@ -442,7 +436,6 @@ GameSession::draw()
 
   if(Menu::current()) {
     Menu::current()->draw(*context);
 
   if(Menu::current()) {
     Menu::current()->draw(*context);
-    mouse_cursor->draw(*context);
   }
 
   context->do_drawing();
   }
 
   context->do_drawing();
@@ -601,10 +594,6 @@ GameSession::run()
 
     //frame_rate.update();
     
 
     //frame_rate.update();
     
-    /* Handle time: */
-    if (time_left.check() && !end_sequence)
-      currentsector->player->kill(Player::KILL);
-    
     /* Handle music: */
     if (currentsector->player->invincible_timer.started() && !end_sequence)
     {
     /* Handle music: */
     if (currentsector->player->invincible_timer.started() && !end_sequence)
     {
@@ -631,14 +620,18 @@ GameSession::run()
   }
  
   // just in case
   }
  
   // just in case
+  currentsector = 0;
   main_controller->reset();
   return exit_status;
 }
 
 void
   main_controller->reset();
   return exit_status;
 }
 
 void
-GameSession::finish()
+GameSession::finish(bool win)
 {
 {
-  exit_status = ES_LEVEL_FINISHED;
+  if(win)
+    exit_status = ES_LEVEL_FINISHED;
+  else
+    exit_status = ES_LEVEL_ABORT;
 }
 
 void
 }
 
 void
@@ -696,10 +689,6 @@ GameSession::start_sequence(const std::string& sequencename)
     sound_manager->play_music(level_end_song, 0);
     currentsector->player->invincible_timer.start(7.0);
 
     sound_manager->play_music(level_end_song, 0);
     currentsector->player->invincible_timer.start(7.0);
 
-    // add left time to stats
-    global_stats.set_points(TIME_NEEDED_STAT,
-        int(time_left.get_period() - time_left.get_timeleft()));
-
     if(sequencename == "fireworks") {
       currentsector->add_object(new Fireworks());
     }
     if(sequencename == "fireworks") {
       currentsector->add_object(new Fireworks());
     }
@@ -714,58 +703,11 @@ GameSession::start_sequence(const std::string& sequencename)
 void
 GameSession::drawstatus(DrawingContext& context)
 {
 void
 GameSession::drawstatus(DrawingContext& context)
 {
-  char str[60];
-  
-  snprintf(str, 60, " %d", global_stats.get_points(SCORE_STAT));
-  context.draw_text(white_text, _("SCORE"), Vector(0, 0), LEFT_ALLIGN, LAYER_FOREGROUND1);
-  context.draw_text(gold_text, str, Vector(96, 0), LEFT_ALLIGN, LAYER_FOREGROUND1);
-
-  if(mode == ST_GL_TEST) {
-    context.draw_text(white_text, _("Press ESC To Return"), Vector(0,20),
-                      LEFT_ALLIGN, LAYER_FOREGROUND1);
-  }
-
-  if(time_left.get_timeleft() < 0) {
-    context.draw_text(white_text, _("TIME's UP"), Vector(SCREEN_WIDTH/2, 0),
-        CENTER_ALLIGN, LAYER_FOREGROUND1);
-  } else if (time_left.get_timeleft() > TIME_WARNING
-      || int(global_time * 2.5) % 2) {
-    sprintf(str, " %d", int(time_left.get_timeleft()));
-    context.draw_text(white_text, _("TIME"),
-        Vector(SCREEN_WIDTH/2, 0), CENTER_ALLIGN, LAYER_FOREGROUND1);
-    context.draw_text(gold_text, str,
-        Vector(SCREEN_WIDTH/2 + 4*16, 0), CENTER_ALLIGN, LAYER_FOREGROUND1);
-  }
-
-  sprintf(str, " %d", player_status.coins);
-  context.draw_text(white_text, _("COINS"),
-      Vector(SCREEN_WIDTH - white_text->get_text_width(_("COINS"))-white_text->get_text_width("   99"), 0),
-        LEFT_ALLIGN, LAYER_FOREGROUND1);
-  context.draw_text(gold_text, str,
-      Vector(SCREEN_WIDTH - gold_text->get_text_width(" 99"), 0),LEFT_ALLIGN, LAYER_FOREGROUND1);
-
-  if (player_status.lives >= 5)
-    {
-      sprintf(str, "%dx", player_status.lives);
-      float x = SCREEN_WIDTH - gold_text->get_text_width(str) - tux_life->w;
-      context.draw_text(gold_text, str, Vector(x, 20), LEFT_ALLIGN, LAYER_FOREGROUND1);
-      context.draw_surface(tux_life, Vector(SCREEN_WIDTH - 16, 20),
-          LAYER_FOREGROUND1);
-    }
-  else
-    {
-      for(int i= 0; i < player_status.lives; ++i)
-        context.draw_surface(tux_life, 
-            Vector(SCREEN_WIDTH - tux_life->w*4 +(tux_life->w*i), 20),
-            LAYER_FOREGROUND1);
-    }
-
-  context.draw_text(white_text, _("LIVES"),
-      Vector(SCREEN_WIDTH - white_text->get_text_width(_("LIVES")) - white_text->get_text_width("   99"), 20),
-      LEFT_ALLIGN, LAYER_FOREGROUND1);
+  player_status.draw(context);
 
   if(config->show_fps) {
 
   if(config->show_fps) {
-    sprintf(str, "%2.1f", fps_fps);
+    char str[60];
+    snprintf(str, sizeof(str), "%2.1f", fps_fps);
     context.draw_text(white_text, "FPS", 
                       Vector(SCREEN_WIDTH -
                              white_text->get_text_width("FPS     "), 40),
     context.draw_text(white_text, "FPS", 
                       Vector(SCREEN_WIDTH -
                              white_text->get_text_width("FPS     "), 40),
index 5fc2f68..eb31ed4 100644 (file)
@@ -59,7 +59,6 @@ public:
 
 public:
   DrawingContext* context;
 
 public:
   DrawingContext* context;
-  Timer time_left;
 
   GameSession(const std::string& levelfile, GameSessionMode mode,
               Statistics* statistics=0);
 
   GameSession(const std::string& levelfile, GameSessionMode mode,
               Statistics* statistics=0);
@@ -77,8 +76,8 @@ public:
   { current_ = this; }
   static GameSession* current() { return current_; }
 
   { current_ = this; }
   static GameSession* current() { return current_; }
 
-  /// ends the level as finished
-  void finish();
+  /// ends the current level
+  void finish(bool win = true);
   void respawn(const std::string& sectorname,
       const std::string& spawnpointname);
   void set_reset_point(const std::string& sectorname,
   void respawn(const std::string& sectorname,
       const std::string& spawnpointname);
   void set_reset_point(const std::string& sectorname,
@@ -95,7 +94,6 @@ private:
   void restart_level();
 
   void check_end_conditions();
   void restart_level();
 
   void check_end_conditions();
-  void start_timers();
   void process_events();
   void capture_demo_step();
 
   void process_events();
   void capture_demo_step();
 
index 8ecae1a..b12cdd2 100644 (file)
@@ -22,7 +22,12 @@ extern TinyGetText::DictionaryManager dictionary_manager;
 
 static inline const char* _(const char* message)
 {
 
 static inline const char* _(const char* message)
 {
-  return dictionary_manager.get_dictionary().translate(message).c_str();
+  return dictionary_manager.get_dictionary().translate(message);
+}
+
+static inline std::string _(const std::string& message)
+{
+  return dictionary_manager.get_dictionary().translate(message);
 }
 
 static inline const char* N_(const char* id, const char* id2, int num)
 }
 
 static inline const char* N_(const char* id, const char* id2, int num)
index 87d083d..d70472d 100644 (file)
@@ -76,11 +76,10 @@ bool confirm_dialog(Surface *background, std::string text)
   while(true)
     {
       SDL_Event event;
   while(true)
     {
       SDL_Event event;
-
-      if(event.type == SDL_QUIT)
-        throw std::runtime_error("received window close event");
-      
       while (SDL_PollEvent(&event)) {
       while (SDL_PollEvent(&event)) {
+        if(event.type == SDL_QUIT)
+          throw std::runtime_error("received window close event");
+        main_controller->process_event(event);
         dialog->event(event);
       }
 
         dialog->event(event);
       }
 
@@ -691,6 +690,10 @@ int Menu::get_height() const
 void
 Menu::draw(DrawingContext& context)
 {
 void
 Menu::draw(DrawingContext& context)
 {
+  if(MouseCursor::current()) {
+    MouseCursor::current()->draw(context);
+  }
+  
   int menu_height = get_height();
   int menu_width = get_width();  
 
   int menu_height = get_height();
   int menu_width = get_width();  
 
index 5a93563..8b774f7 100644 (file)
@@ -80,6 +80,6 @@ void MouseCursor::draw(DrawingContext& context)
       cur_state = state_before_click;
   }
 
       cur_state = state_before_click;
   }
 
-  context.draw_surface_part(cursor, Vector(w, h*cur_state),
+  context.draw_surface_part(cursor, Vector(0, h*cur_state),
           Vector(w, h), Vector(x-mid_x, y-mid_y), LAYER_GUI+100);
 }
           Vector(w, h), Vector(x-mid_x, y-mid_y), LAYER_GUI+100);
 }
index b097cc4..e9f8ccd 100644 (file)
@@ -51,7 +51,7 @@
 using namespace std;
 
 Level::Level()
 using namespace std;
 
 Level::Level()
-  : name("noname"), author("Mr. X"), timelimit(500)
+  : name("noname"), author("Mr. X")
 {
 }
 
 {
 }
 
@@ -92,8 +92,6 @@ Level::load(const std::string& filepath)
         iter.value()->get(name);
       } else if(token == "author") {
         iter.value()->get(author);
         iter.value()->get(name);
       } else if(token == "author") {
         iter.value()->get(author);
-      } else if(token == "time") {
-        iter.value()->get(timelimit);
       } else if(token == "sector") {
         Sector* sector = new Sector;
         sector->parse(*(iter.lisp()));
       } else if(token == "sector") {
         Sector* sector = new Sector;
         sector->parse(*(iter.lisp()));
@@ -116,7 +114,6 @@ Level::load_old_format(const lisp::Lisp& reader)
 {
   reader.get("name", name);
   reader.get("author", author);
 {
   reader.get("name", name);
   reader.get("author", author);
-  reader.get("time", timelimit);
 
   Sector* sector = new Sector;
   sector->parse_old_format(reader);
 
   Sector* sector = new Sector;
   sector->parse_old_format(reader);
@@ -142,7 +139,6 @@ Level::save(const std::string& filename)
 
   writer->write_string("name", name, true);
   writer->write_string("author", author);
 
   writer->write_string("name", name, true);
   writer->write_string("author", author);
-  writer->write_int("time", timelimit);
 
   for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i) {
     Sector* sector = *i;
 
   for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i) {
     Sector* sector = *i;
index 555138a..18d1803 100644 (file)
@@ -35,7 +35,6 @@ class Level
 public:
   std::string name;
   std::string author;
 public:
   std::string name;
   std::string author;
-  int timelimit;
   typedef std::vector<Sector*> Sectors;
   Sectors sectors;
 
   typedef std::vector<Sector*> Sectors;
   Sectors sectors;
 
index 65f163a..cd74886 100644 (file)
@@ -38,6 +38,7 @@ Parser::Parser(bool translate)
 {
   if(translate) {
     dictionary_manager = new TinyGetText::DictionaryManager();
 {
   if(translate) {
     dictionary_manager = new TinyGetText::DictionaryManager();
+    dictionary_manager->set_charset("ISO8859-1");
   }
 }
 
   }
 }
 
index 494209f..a48b3f4 100644 (file)
@@ -133,7 +133,7 @@ static void find_directories()
 static void init_tinygettext()
 {
   dictionary_manager.add_directory(datadir + "/locale");
 static void init_tinygettext()
 {
   dictionary_manager.add_directory(datadir + "/locale");
-  dictionary_manager.set_charset("iso8859-1");
+  dictionary_manager.set_charset("ISO8859-1");
 }
 
 static void print_usage(const char* argv0)
 }
 
 static void print_usage(const char* argv0)
diff --git a/src/object/level_time.cpp b/src/object/level_time.cpp
new file mode 100644 (file)
index 0000000..fc0ae13
--- /dev/null
@@ -0,0 +1,70 @@
+#include <config.h>
+
+#include "level_time.h"
+
+#include <stdexcept>
+#include "main.h"
+#include "resources.h"
+#include "sector.h"
+#include "gettext.h"
+#include "object_factory.h"
+#include "object/player.h"
+#include "video/drawing_context.h"
+#include "lisp/list_iterator.h"
+
+/** When to alert player they're low on time! */
+static const float TIME_WARNING = 20;
+
+LevelTime::LevelTime(const lisp::Lisp& reader)
+{
+    float time = -1;
+    lisp::ListIterator iter(&reader);
+    while(iter.next()) {
+        if(iter.item() == "time") {
+            iter.value()->get(time);
+            break;
+        } else {
+            std::cerr << "Unknown token '" << iter.item() 
+                      << "' in LevelTime object.\n";
+        }
+    }
+    if(time < 0)
+      throw std::runtime_error("Invalid leveltime specified");
+    time_left.start(time);
+}
+
+LevelTime::~LevelTime()
+{}
+
+void
+LevelTime::update(float )
+{
+  if(time_left.check()) {
+    Sector::current()->player->kill(Player::KILL);
+  }
+}
+
+void
+LevelTime::draw(DrawingContext& context)
+{
+  context.push_transform();
+  context.set_translation(Vector(0, 0));
+
+  char str[60];
+    
+  if(time_left.get_timeleft() < 0) {
+    context.draw_text(white_text, _("TIME's UP"), Vector(SCREEN_WIDTH/2, 0),
+        CENTER_ALLIGN, LAYER_FOREGROUND1);
+  } else if (time_left.get_timeleft() > TIME_WARNING
+      || int(global_time * 2.5) % 2) {
+    snprintf(str, sizeof(str), " %d", int(time_left.get_timeleft()));
+    context.draw_text(white_text, _("TIME"),
+        Vector(SCREEN_WIDTH/2, 0), CENTER_ALLIGN, LAYER_FOREGROUND1);
+    context.draw_text(gold_text, str, Vector(SCREEN_WIDTH/2 + 4*16, 0),
+                      CENTER_ALLIGN, LAYER_FOREGROUND1);
+  }
+
+  context.pop_transform();
+}
+
+IMPLEMENT_FACTORY(LevelTime, "leveltime");
diff --git a/src/object/level_time.h b/src/object/level_time.h
new file mode 100644 (file)
index 0000000..3c7e67e
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef __LEVELTIME_H__
+#define __LEVELTIME_H__
+
+#include "game_object.h"
+#include "timer.h"
+#include "lisp/lisp.h"
+
+class LevelTime : public GameObject
+{
+public:
+    LevelTime(const lisp::Lisp& reader);
+    virtual ~LevelTime();
+
+    void update(float elapsed_time);
+    void draw(DrawingContext& context);
+
+private:
+    Timer time_left;
+};
+
+#endif
+
index 731b443..22fb0f2 100644 (file)
@@ -39,7 +39,6 @@ static const float TUX_SAFE_TIME = 1.250;
 static const float TUX_INVINCIBLE_TIME = 10.0;
 static const float TUX_INVINCIBLE_TIME_WARNING = 2.0;
 static const float TUX_FLAPPING_TIME = 1; /* How long Tux can flap his wings to gain additional jump height */
 static const float TUX_INVINCIBLE_TIME = 10.0;
 static const float TUX_INVINCIBLE_TIME_WARNING = 2.0;
 static const float TUX_FLAPPING_TIME = 1; /* How long Tux can flap his wings to gain additional jump height */
-static const float TIME_WARNING = 20;     /* When to alert player they're low on time! */
 static const float GROWING_TIME = 1.0;
 static const int GROWING_FRAMES = 7;
 
 static const float GROWING_TIME = 1.0;
 static const int GROWING_FRAMES = 7;
 
index a8ca571..15c6125 100644 (file)
@@ -45,11 +45,13 @@ TileMap::TileMap()
     flags |= FLAG_SOLID;
 }
 
     flags |= FLAG_SOLID;
 }
 
-TileMap::TileMap(const lisp::Lisp& reader)
-  : solid(false), speed(1), width(0), height(0), layer(LAYER_TILES),
+TileMap::TileMap(const lisp::Lisp& reader, TileManager* new_tile_manager)
+  : solid(false), speed(1), width(-1), height(-1), layer(LAYER_TILES),
     drawing_effect(0)
 {
     drawing_effect(0)
 {
-  tilemanager = tile_manager;
+  tilemanager = new_tile_manager;
+  if(tilemanager == 0)
+    tilemanager = tile_manager;
 
   std::string layer_str;
   if(reader.get("layer", layer_str)) {
 
   std::string layer_str;
   if(reader.get("layer", layer_str)) {
@@ -72,10 +74,11 @@ TileMap::TileMap(const lisp::Lisp& reader)
   }
   if(solid)
     flags |= FLAG_SOLID;
   }
   if(solid)
     flags |= FLAG_SOLID;
-  
-  if(!reader.get("width", width) ||
-     !reader.get("height", height))
-    throw std::runtime_error("No width or height specified in tilemap.");
+  reader.get("width", width);
+  reader.get("height", height);
+  if(width < 0 || height < 0)
+    throw std::runtime_error("Invalid/No width/height specified in tilemap.");
 
   if(!reader.get_vector("tiles", tiles))
     throw std::runtime_error("No tiles in tilemap.");
 
   if(!reader.get_vector("tiles", tiles))
     throw std::runtime_error("No tiles in tilemap.");
@@ -149,9 +152,11 @@ TileMap::draw(DrawingContext& context)
   /** if we don't round here, we'll have a 1 pixel gap on screen sometimes.
    * I have no idea why */
   float start_x = roundf(context.get_translation().x);
   /** if we don't round here, we'll have a 1 pixel gap on screen sometimes.
    * I have no idea why */
   float start_x = roundf(context.get_translation().x);
-  if(start_x < 0) start_x = 0;
+  if(start_x < 0)
+    start_x = 0;
   float start_y = roundf(context.get_translation().y);
   float start_y = roundf(context.get_translation().y);
-  if(start_y < 0) start_y = 0;
+  if(start_y < 0)
+    start_y = 0;
   float end_x = std::min(start_x + SCREEN_WIDTH, float(width * 32));
   float end_y = std::min(start_y + SCREEN_HEIGHT, float(height * 32));
   start_x -= int(start_x) % 32;
   float end_x = std::min(start_x + SCREEN_WIDTH, float(width * 32));
   float end_y = std::min(start_y + SCREEN_HEIGHT, float(height * 32));
   start_x -= int(start_x) % 32;
index 2aaf3ce..d647a5e 100644 (file)
@@ -41,7 +41,7 @@ class TileMap : public GameObject, public Serializable
 {
 public:
   TileMap();
 {
 public:
   TileMap();
-  TileMap(const lisp::Lisp& reader);
+  TileMap(const lisp::Lisp& reader, TileManager* tile_manager = 0);
   TileMap(int layer_, bool solid_, size_t width_, size_t height_);
   virtual ~TileMap();
 
   TileMap(int layer_, bool solid_, size_t width_, size_t height_);
   virtual ~TileMap();
 
index 6fcf66c..304a076 100644 (file)
@@ -22,6 +22,9 @@
 #include "lisp/lisp.h"
 #include "player_status.h"
 #include "resources.h"
 #include "lisp/lisp.h"
 #include "player_status.h"
 #include "resources.h"
+#include "gettext.h"
+#include "video/drawing_context.h"
+#include "main.h"
 
 static const int START_LIVES = 4;
 static const int MAX_LIVES = 99;
 
 static const int START_LIVES = 4;
 static const int MAX_LIVES = 99;
@@ -117,3 +120,43 @@ PlayerStatus::read(const lisp::Lisp& lisp)
   lisp.get("max-score-multiplier", max_score_multiplier);
 }
 
   lisp.get("max-score-multiplier", max_score_multiplier);
 }
 
+void
+PlayerStatus::draw(DrawingContext& context)
+{
+  context.push_transform();
+  context.set_translation(Vector(0, 0));
+
+  char str[60];
+  
+  sprintf(str, " %d", player_status.coins);
+  const char* coinstext = _("COINS");
+  context.draw_text(white_text, coinstext,
+      Vector(SCREEN_WIDTH - white_text->get_text_width(coinstext) 
+              - white_text->get_text_width("   99"), 0),
+      LEFT_ALLIGN, LAYER_FOREGROUND1);
+  context.draw_text(gold_text, str,
+      Vector(SCREEN_WIDTH - gold_text->get_text_width(" 99"), 0),
+      LEFT_ALLIGN, LAYER_FOREGROUND1);
+
+  if (player_status.lives >= 5) {
+    sprintf(str, "%dx", player_status.lives);
+    float x = SCREEN_WIDTH - gold_text->get_text_width(str) - tux_life->w;
+    context.draw_text(gold_text, str, Vector(x, 20), LEFT_ALLIGN,
+                      LAYER_FOREGROUND1);
+    context.draw_surface(tux_life, Vector(SCREEN_WIDTH - 16, 20),
+                         LAYER_FOREGROUND1);
+  } else {
+    for(int i= 0; i < player_status.lives; ++i)
+      context.draw_surface(tux_life, 
+          Vector(SCREEN_WIDTH - tux_life->w*4 +(tux_life->w*i), 20),
+          LAYER_FOREGROUND1);
+  }
+
+  const char* livestext = _("LIVES");
+  context.draw_text(white_text, livestext,
+      Vector(SCREEN_WIDTH - white_text->get_text_width(livestext) 
+                - white_text->get_text_width("   99"), 20),
+      LEFT_ALLIGN, LAYER_FOREGROUND1);
+
+  context.pop_transform();
+}
index e4fb335..c1bdc25 100644 (file)
@@ -26,6 +26,7 @@
 enum BonusType {
   NO_BONUS, GROWUP_BONUS, FIRE_BONUS, ICE_BONUS
 };
 enum BonusType {
   NO_BONUS, GROWUP_BONUS, FIRE_BONUS, ICE_BONUS
 };
+class DrawingContext;
 
 /** 
  * This class memorizes player status between different game sessions (for
 
 /** 
  * This class memorizes player status between different game sessions (for
@@ -42,6 +43,8 @@ public:
   void write(lisp::Writer& writer);
   void read(const lisp::Lisp& lisp);
 
   void write(lisp::Writer& writer);
   void read(const lisp::Lisp& lisp);
 
+  void draw(DrawingContext& context);
+
   int  coins;
   int  lives;
   BonusType bonus;
   int  coins;
   int  lives;
   BonusType bonus;
index cc1689b..11957a4 100644 (file)
@@ -46,6 +46,7 @@
 #include "collision_grid_iterator.h"
 #include "object_factory.h"
 #include "collision.h"
 #include "collision_grid_iterator.h"
 #include "object_factory.h"
 #include "collision.h"
+#include "spawn_point.h"
 #include "math/rect.h"
 #include "math/aatriangle.h"
 #include "object/coin.h"
 #include "math/rect.h"
 #include "math/aatriangle.h"
 #include "object/coin.h"
@@ -145,12 +146,7 @@ Sector::parse(const lisp::Lisp& sector)
       iter.value()->get(song_title);
       load_music();
     } else if(token == "spawnpoint") {
       iter.value()->get(song_title);
       load_music();
     } else if(token == "spawnpoint") {
-      const lisp::Lisp* spawnpoint_lisp = iter.lisp();
-      
-      SpawnPoint* sp = new SpawnPoint;
-      spawnpoint_lisp->get("name", sp->name);
-      spawnpoint_lisp->get("x", sp->pos.x);
-      spawnpoint_lisp->get("y", sp->pos.y);
+      SpawnPoint* sp = new SpawnPoint(iter.lisp());
       spawnpoints.push_back(sp);
     } else if(token == "init-script") {
       iter.value()->get(init_script);
       spawnpoints.push_back(sp);
     } else if(token == "init-script") {
       iter.value()->get(init_script);
index 5477221..51a135b 100644 (file)
@@ -41,13 +41,7 @@ class TileMap;
 class Bullet;
 class CollisionGrid;
 class ScriptInterpreter;
 class Bullet;
 class CollisionGrid;
 class ScriptInterpreter;
-
-class SpawnPoint
-{
-public:
-  std::string name;
-  Vector pos;
-};
+class SpawnPoint;
 
 enum MusicType {
   LEVEL_MUSIC,
 
 enum MusicType {
   LEVEL_MUSIC,
index dd73e80..9ffd17c 100644 (file)
@@ -433,6 +433,20 @@ Dictionary::translate(const std::string& msgid)
       return msgid;
     }
 }
       return msgid;
     }
 }
+
+const char*
+Dictionary::translate(const char* msgid)
+{
+  Entries::iterator i = entries.find(msgid);
+  if(i == entries.end() || i->second.empty()) {
+#ifdef TRANSLATION_DBEUG
+    std::cout << "Error: Couldn't translate: " << msgid << std::endl;
+#endif                                                                     
+    return msgid;
+  }
+
+  return i->second.c_str();
+}
   
 void
 Dictionary::add_translation(const std::string& msgid, const std::string& ,
   
 void
 Dictionary::add_translation(const std::string& msgid, const std::string& ,
@@ -477,6 +491,13 @@ public:
   {
     state = WANT_MSGID;
     line_num = 0;
   {
     state = WANT_MSGID;
     line_num = 0;
+    char c = in.get();
+    if(c == (char) 0xef) { // skip UTF-8 intro that some texteditors produce
+      in.get();
+      in.get();
+    } else {
+      in.unget();
+    }
     tokenize_po(in);
   }
 
     tokenize_po(in);
   }
 
index 207ce28..a8a5846 100644 (file)
@@ -78,6 +78,8 @@ public:
 
   /** Translate the string \a msgid. */
   std::string translate(const std::string& msgid);
 
   /** Translate the string \a msgid. */
   std::string translate(const std::string& msgid);
+
+  const char* translate(const char* msgid);
     
   /** Add a translation from \a msgid to \a msgstr to the dictionary,
       where \a msgid is the singular form of the message, msgid2 the
     
   /** Add a translation from \a msgid to \a msgstr to the dictionary,
       where \a msgid is the singular form of the message, msgid2 the
index 255b38d..9afb667 100644 (file)
@@ -185,14 +185,12 @@ void check_levels_contrib_menu()
 
     // TODO: slots should be available for contrib maps
     worldmap.loadgame(user_dir + "/save/" + subset.name + "-slot1.stsg");
 
     // TODO: slots should be available for contrib maps
     worldmap.loadgame(user_dir + "/save/" + subset.name + "-slot1.stsg");
-
     worldmap.display();  // run the map
 
     Menu::set_current(main_menu);
     resume_demo();
   } else if (current_subset != index) {
     current_subset = index;
     worldmap.display();  // run the map
 
     Menu::set_current(main_menu);
     resume_demo();
   } else if (current_subset != index) {
     current_subset = index;
-    // FIXME: This shouln't be busy looping
     LevelSubset& subset = * (contrib_subsets[index]);
 
     current_contrib_subset = &subset;
     LevelSubset& subset = * (contrib_subsets[index]);
 
     current_contrib_subset = &subset;
@@ -433,8 +431,6 @@ void title()
         Menu::set_current(main_menu);
       }
 
         Menu::set_current(main_menu);
       }
 
-      mouse_cursor->draw(context);
-     
       context.do_drawing();
 
       //frame_rate.update();
       context.do_drawing();
 
       //frame_rate.update();
index e5bc848..7a7c27a 100644 (file)
@@ -18,8 +18,8 @@
 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
 //  02111-1307, USA.\r
 //\r
 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
 //  02111-1307, USA.\r
 //\r
-\r
 #include <config.h>\r
 #include <config.h>\r
+\r
 #include <sstream>\r
 \r
 #include "scripttrigger.h"\r
 #include <sstream>\r
 \r
 #include "scripttrigger.h"\r
@@ -103,4 +103,5 @@ ScriptTrigger::event(Player& , EventType type)
   }\r
 }\r
 \r
   }\r
 }\r
 \r
-IMPLEMENT_FACTORY(ScriptTrigger, "scripttrigger")\r
+IMPLEMENT_FACTORY(ScriptTrigger, "scripttrigger");\r
+\r
index 9987482..ec846e7 100644 (file)
@@ -137,7 +137,7 @@ static int power_of_two(int input)
 }
 
 Surface::Surface(SDL_Surface* surf, bool use_alpha)
 }
 
 Surface::Surface(SDL_Surface* surf, bool use_alpha)
-    : data(surf, use_alpha), w(0), h(0)
+    : impl(0), data(surf, use_alpha), w(0), h(0)
 {
   impl = data.create();
   if (impl)
 {
   impl = data.create();
   if (impl)
@@ -149,7 +149,7 @@ Surface::Surface(SDL_Surface* surf, bool use_alpha)
 }
 
 Surface::Surface(const std::string& file, bool use_alpha)
 }
 
 Surface::Surface(const std::string& file, bool use_alpha)
-    : data(file, use_alpha), w(0), h(0)
+    : impl(0), data(file, use_alpha), w(0), h(0)
 {
   impl = data.create();
   if (impl)
 {
   impl = data.create();
   if (impl)
@@ -161,7 +161,7 @@ Surface::Surface(const std::string& file, bool use_alpha)
 }
 
 Surface::Surface(const std::string& file, int x, int y, int w_, int h_, bool use_alpha)
 }
 
 Surface::Surface(const std::string& file, int x, int y, int w_, int h_, bool use_alpha)
-    : data(file, x, y, w_, h_, use_alpha), w(0), h(0)
+    : impl(0), data(file, x, y, w_, h_, use_alpha), w(0), h(0)
 {
   impl = data.create();
   if (impl)
 {
   impl = data.create();
   if (impl)
@@ -173,7 +173,7 @@ Surface::Surface(const std::string& file, int x, int y, int w_, int h_, bool use
 }
 
 Surface::Surface(Color top_background, Color bottom_background, int w_, int h_)
 }
 
 Surface::Surface(Color top_background, Color bottom_background, int w_, int h_)
-    : data(top_background, bottom_background, w_, h_), w(0), h(0)
+    : impl(0), data(top_background, bottom_background, w_, h_), w(0), h(0)
 {
   impl = data.create();
   if (impl)
 {
   impl = data.create();
   if (impl)
@@ -296,8 +296,7 @@ sdl_surface_part_from_file(const std::string& file, int x, int y, int w, int h,
   SDL_Surface * conv;
 
   temp = IMG_Load(file.c_str());
   SDL_Surface * conv;
 
   temp = IMG_Load(file.c_str());
-
-  if (temp == NULL) {
+  if (temp == 0) {
     std::stringstream msg;
     msg << "Couldn't load '" << file << "': " << SDL_GetError();
     throw std::runtime_error(msg.str());
     std::stringstream msg;
     msg << "Couldn't load '" << file << "': " << SDL_GetError();
     throw std::runtime_error(msg.str());
@@ -346,8 +345,7 @@ sdl_surface_from_file(const std::string& file, bool use_alpha)
   SDL_Surface* temp;
 
   temp = IMG_Load(file.c_str());
   SDL_Surface* temp;
 
   temp = IMG_Load(file.c_str());
-
-  if (temp == NULL) {
+  if (temp == 0) {
     std::stringstream msg;
     msg << "Couldn't load file '" << file << "': " << SDL_GetError();
     throw std::runtime_error(msg.str());
     std::stringstream msg;
     msg << "Couldn't load file '" << file << "': " << SDL_GetError();
     throw std::runtime_error(msg.str());
@@ -454,11 +452,13 @@ sdl_surface_from_gradient(Color top, Color bottom, int w, int h)
 //---------------------------------------------------------------------------
 
 SurfaceImpl::SurfaceImpl()
 //---------------------------------------------------------------------------
 
 SurfaceImpl::SurfaceImpl()
+  : sdl_surface(0)
 {}
 
 SurfaceImpl::~SurfaceImpl()
 {
 {}
 
 SurfaceImpl::~SurfaceImpl()
 {
-  SDL_FreeSurface(sdl_surface);
+  if(sdl_surface != 0)
+    SDL_FreeSurface(sdl_surface);
 }
 
 SDL_Surface* SurfaceImpl::get_sdl_surface() const
 }
 
 SDL_Surface* SurfaceImpl::get_sdl_surface() const
index 55f6ed0..b7adb5f 100644 (file)
@@ -95,8 +95,8 @@ public:
 class Surface
 {
 public:
 class Surface
 {
 public:
-  SurfaceData data;
   SurfaceImpl* impl;
   SurfaceImpl* impl;
+  SurfaceData data;
   int w;
   int h;
   
   int w;
   int h;
   
index d90afe7..e193b0f 100644 (file)
 #include "player_status.h"
 #include "textscroller.h"
 #include "main.h"
 #include "player_status.h"
 #include "textscroller.h"
 #include "main.h"
+#include "spawn_point.h"
 #include "file_system.h"
 #include "gui/menu.h"
 #include "gui/mousecursor.h"
 #include "control/joystickkeyboardcontroller.h"
 #include "file_system.h"
 #include "gui/menu.h"
 #include "gui/mousecursor.h"
 #include "control/joystickkeyboardcontroller.h"
+#include "object/background.h"
+#include "object/tilemap.h"
 
 Menu* worldmap_menu  = 0;
 
 
 Menu* worldmap_menu  = 0;
 
@@ -116,8 +119,6 @@ Tux::Tux(WorldMap* worldmap_)
   
   offset = 0;
   moving = false;
   
   offset = 0;
   moving = false;
-  tile_pos.x = worldmap->get_start_x();
-  tile_pos.y = worldmap->get_start_y();
   direction = D_NONE;
   input_direction = D_NONE;
 }
   direction = D_NONE;
   input_direction = D_NONE;
 }
@@ -176,7 +177,7 @@ Tux::get_pos()
       break;
     }
   
       break;
     }
   
-  return Vector((int)x, (int)y); 
+  return Vector(x, y);
 }
 
 void
 }
 
 void
@@ -343,21 +344,21 @@ Tux::update(float delta)
 //---------------------------------------------------------------------------
 
 WorldMap::WorldMap()
 //---------------------------------------------------------------------------
 
 WorldMap::WorldMap()
+  : tux(0), solids(0)
 {
   tile_manager = new TileManager("images/worldmap.strf");
   
 {
   tile_manager = new TileManager("images/worldmap.strf");
   
-  width  = 20;
-  height = 15;
-  
-  start_x = 4;
-  start_y = 5;
-
   tux = new Tux(this);
   tux = new Tux(this);
-  
-  leveldot_green = new Surface(datadir +  "/images/tiles/worldmap/leveldot_green.png", true);
-  leveldot_red = new Surface(datadir +  "/images/tiles/worldmap/leveldot_red.png", true);
-  messagedot   = new Surface(datadir +  "/images/tiles/worldmap/messagedot.png", true);
-  teleporterdot   = new Surface(datadir +  "/images/tiles/worldmap/teleporterdot.png", true);
+  add_object(tux);
+    
+  leveldot_green
+    = new Surface(datadir + "/images/tiles/worldmap/leveldot_green.png", true);
+  leveldot_red
+    = new Surface(datadir + "/images/tiles/worldmap/leveldot_red.png", true);
+  messagedot
+    = new Surface(datadir + "/images/tiles/worldmap/messagedot.png", true);
+  teleporterdot
+    = new Surface(datadir + "/images/tiles/worldmap/teleporterdot.png", true);
 
   name = "<no title>";
   music = "salcon.mod";
 
   name = "<no title>";
   music = "salcon.mod";
@@ -368,7 +369,12 @@ WorldMap::WorldMap()
 
 WorldMap::~WorldMap()
 {
 
 WorldMap::~WorldMap()
 {
-  delete tux;
+  clear_objects();
+  for(SpawnPoints::iterator i = spawn_points.begin();
+      i != spawn_points.end(); ++i) {
+    delete *i;
+  }
+    
   delete tile_manager;
 
   delete leveldot_green;
   delete tile_manager;
 
   delete leveldot_green;
@@ -377,6 +383,29 @@ WorldMap::~WorldMap()
   delete teleporterdot;
 }
 
   delete teleporterdot;
 }
 
+void
+WorldMap::add_object(GameObject* object)
+{
+  TileMap* tilemap = dynamic_cast<TileMap*> (object);
+  if(tilemap != 0 && tilemap->is_solid()) {
+    solids = tilemap;
+  }
+
+  game_objects.push_back(object);
+}
+
+void
+WorldMap::clear_objects()
+{
+  for(GameObjects::iterator i = game_objects.begin();
+      i != game_objects.end(); ++i)
+    delete *i;
+  game_objects.clear();
+  solids = 0;
+  tux = new Tux(this);
+  add_object(tux);
+}
+
 // Don't forget to set map_filename before calling this
 void
 WorldMap::load_map()
 // Don't forget to set map_filename before calling this
 void
 WorldMap::load_map()
@@ -392,23 +421,21 @@ WorldMap::load_map()
     if(!lisp)
       throw new std::runtime_error("file isn't a supertux-worldmap file.");
 
     if(!lisp)
       throw new std::runtime_error("file isn't a supertux-worldmap file.");
 
+    clear_objects();
     lisp::ListIterator iter(lisp);
     while(iter.next()) {
       if(iter.item() == "tilemap") {
     lisp::ListIterator iter(lisp);
     while(iter.next()) {
       if(iter.item() == "tilemap") {
-        if(tilemap.size() > 0)
-          throw new std::runtime_error("multiple tilemaps specified");
-        
-        const lisp::Lisp* tilemap_lisp = iter.lisp();
-        tilemap_lisp->get("width",  width);
-        tilemap_lisp->get("height", height);
-        tilemap_lisp->get_vector("tiles", tilemap);
+        add_object(new TileMap(*(iter.lisp()), tile_manager));
+      } else if(iter.item() == "background") {
+        add_object(new Background(*(iter.lisp())));
       } else if(iter.item() == "properties") {
         const lisp::Lisp* props = iter.lisp();
         props->get("name", name);
         props->get("music", music);
         props->get("intro-filename", intro_filename);
       } else if(iter.item() == "properties") {
         const lisp::Lisp* props = iter.lisp();
         props->get("name", name);
         props->get("music", music);
         props->get("intro-filename", intro_filename);
-        props->get("start_pos_x", start_x);
-        props->get("start_pos_y", start_y);
+      } else if(iter.item() == "spawnpoint") {
+        SpawnPoint* sp = new SpawnPoint(iter.lisp());
+        spawn_points.push_back(sp);
       } else if(iter.item() == "level") {
         parse_level_tile(iter.lisp());
       } else if(iter.item() == "special-tile") {
       } else if(iter.item() == "level") {
         parse_level_tile(iter.lisp());
       } else if(iter.item() == "special-tile") {
@@ -417,9 +444,20 @@ WorldMap::load_map()
         std::cerr << "Unknown token '" << iter.item() << "' in worldmap.\n";
       }
     }
         std::cerr << "Unknown token '" << iter.item() << "' in worldmap.\n";
       }
     }
+    if(solids == 0)
+      throw std::runtime_error("No solid tilemap specified");
+
+    // search for main spawnpoint
+    for(SpawnPoints::iterator i = spawn_points.begin();
+        i != spawn_points.end(); ++i) {
+      SpawnPoint* sp = *i;
+      if(sp->name == "main") {
+        Vector p = sp->pos;
+        tux->set_tile_pos(p);
+        break;
+      }
+    }
 
 
-    delete tux;
-    tux = new Tux(this);
   } catch(std::exception& e) {
     std::stringstream msg;
     msg << "Problem when parsing worldmap '" << map_filename << "': " <<
   } catch(std::exception& e) {
     std::stringstream msg;
     msg << "Problem when parsing worldmap '" << map_filename << "': " <<
@@ -588,8 +626,8 @@ WorldMap::path_ok(Direction direction, Vector old_pos, Vector* new_pos)
 {
   *new_pos = get_next_tile(old_pos, direction);
 
 {
   *new_pos = get_next_tile(old_pos, direction);
 
-  if (!(new_pos->x >= 0 && new_pos->x < width
-        && new_pos->y >= 0 && new_pos->y < height))
+  if (!(new_pos->x >= 0 && new_pos->x < solids->get_width()
+        && new_pos->y >= 0 && new_pos->y < solids->get_height()))
     { // New position is outsite the tilemap
       return false;
     }
     { // New position is outsite the tilemap
       return false;
     }
@@ -644,6 +682,24 @@ WorldMap::update(float delta)
     return;
   }
 
     return;
   }
 
+  // update GameObjects
+  for(GameObjects::iterator i = game_objects.begin();
+      i != game_objects.end(); ++i) {
+    GameObject* object = *i;
+    object->update(delta);
+  }
+  // remove old GameObjects
+  for(GameObjects::iterator i = game_objects.begin();
+      i != game_objects.end(); ) {
+    GameObject* object = *i;
+    if(!object->is_valid()) {
+      delete object;
+      i = game_objects.erase(i);
+    } else {
+      ++i;
+    }
+  }
+  
   bool enter_level = false;
   if(main_controller->pressed(Controller::ACTION)
       || main_controller->pressed(Controller::JUMP)
   bool enter_level = false;
   if(main_controller->pressed(Controller::ACTION)
       || main_controller->pressed(Controller::JUMP)
@@ -725,7 +781,6 @@ WorldMap::update(float delta)
                     if (dir != D_NONE)
                       {
                         tux->set_direction(dir);
                     if (dir != D_NONE)
                       {
                         tux->set_direction(dir);
-                        //tux->update(delta);
                       }
                   }
               }
                       }
                   }
               }
@@ -802,7 +857,6 @@ WorldMap::update(float delta)
     }
   else
     {
     }
   else
     {
-      tux->update(delta);
 //      tux->set_direction(input_direction);
     }
 }
 //      tux->set_direction(input_direction);
     }
 }
@@ -810,14 +864,7 @@ WorldMap::update(float delta)
 const Tile*
 WorldMap::at(Vector p)
 {
 const Tile*
 WorldMap::at(Vector p)
 {
-  assert(p.x >= 0 
-         && p.x < width
-         && p.y >= 0
-         && p.y < height);
-
-  int x = int(p.x);
-  int y = int(p.y);
-  return tile_manager->get(tilemap[width * y + x]);
+  return solids->get_tile((int) p.x, (int) p.y);
 }
 
 WorldMap::Level*
 }
 
 WorldMap::Level*
@@ -847,13 +894,12 @@ WorldMap::at_special_tile()
 void
 WorldMap::draw(DrawingContext& context)
 {
 void
 WorldMap::draw(DrawingContext& context)
 {
-  for(int y = 0; y < height; ++y)
-    for(int x = 0; x < width; ++x)
-      {
-        const Tile* tile = at(Vector(x, y));
-        tile->draw(context, Vector(x*32, y*32), LAYER_TILES);
-      }
-
+  for(GameObjects::iterator i = game_objects.begin();
+      i != game_objects.end(); ++i) {
+    GameObject* object = *i;
+    object->draw(context);
+  }
+  
   for(Levels::iterator i = levels.begin(); i != levels.end(); ++i)
     {
       if (i->solved)
   for(Levels::iterator i = levels.begin(); i != levels.end(); ++i)
     {
       if (i->solved)
@@ -878,7 +924,6 @@ WorldMap::draw(DrawingContext& context)
                 Vector(i->pos.x*32, i->pos.y*32), LAYER_TILES+1);
     }
 
                 Vector(i->pos.x*32, i->pos.y*32), LAYER_TILES+1);
     }
 
-  tux->draw(context);
   draw_status(context);
 }
 
   draw_status(context);
 }
 
@@ -887,38 +932,8 @@ WorldMap::draw_status(DrawingContext& context)
 {
   context.push_transform();
   context.set_translation(Vector(0, 0));
 {
   context.push_transform();
   context.set_translation(Vector(0, 0));
-  
-  char str[80];
-  sprintf(str, " %d", total_stats.get_points(SCORE_STAT));
-
-  context.draw_text(white_text, _("SCORE"), Vector(0, 0), LEFT_ALLIGN, LAYER_FOREGROUND1);
-  context.draw_text(gold_text, str, Vector(96, 0), LEFT_ALLIGN, LAYER_FOREGROUND1);
-
-  sprintf(str, "%d", player_status.coins);
-  context.draw_text(white_text, _("COINS"), Vector(SCREEN_WIDTH/2 - 16*5, 0),
-      LEFT_ALLIGN, LAYER_FOREGROUND1);
-  context.draw_text(gold_text, str, Vector(SCREEN_WIDTH/2 + (16*5)/2, 0),
-        LEFT_ALLIGN, LAYER_FOREGROUND1);
-
-  if (player_status.lives >= 5)
-    {
-      sprintf(str, "%dx", player_status.lives);
-      context.draw_text(gold_text, str, 
-          Vector(SCREEN_WIDTH - gold_text->get_text_width(str) - tux_life->w, 0),
-          LEFT_ALLIGN, LAYER_FOREGROUND1);
-      context.draw_surface(tux_life, Vector(SCREEN_WIDTH -
-            gold_text->get_text_width("9"), 0), LAYER_FOREGROUND1);
-    }
-  else
-    {
-      for(int i= 0; i < player_status.lives; ++i)
-        context.draw_surface(tux_life,
-            Vector(SCREEN_WIDTH - tux_life->w*4 + (tux_life->w*i), 0),
-            LAYER_FOREGROUND1);
-    }
-  context.draw_text(white_text, _("LIVES"),
-      Vector(SCREEN_WIDTH - white_text->get_text_width(_("LIVES")) - white_text->get_text_width("   99"), 0),
-      LEFT_ALLIGN, LAYER_FOREGROUND1);
+  player_status.draw(context);
 
   if (!tux->is_moving())
     {
 
   if (!tux->is_moving())
     {
@@ -985,23 +1000,26 @@ WorldMap::display()
     global_time += elapsed_time;
     lastticks = ticks;
     
     global_time += elapsed_time;
     lastticks = ticks;
     
-    // 40 fps minimum
+    // 40 fps minimum // TODO use same code as in GameSession here
     if(elapsed_time > .025)
       elapsed_time = .025;
     
     Vector tux_pos = tux->get_pos();
     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;
+    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 < 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;
 
 
-    if (offset.x < SCREEN_WIDTH - width*32) offset.x = SCREEN_WIDTH - width*32;
-    if (offset.y < SCREEN_HEIGHT - height*32) offset.y = SCREEN_HEIGHT - height*32;
-  
     context.push_transform();
     context.push_transform();
-    context.set_translation(-offset);
+    context.set_translation(offset);
     draw(context);
     context.pop_transform();
     get_input();
     draw(context);
     context.pop_transform();
     get_input();
@@ -1009,7 +1027,6 @@ WorldMap::display()
       
     if(Menu::current()) {
       Menu::current()->draw(context);
       
     if(Menu::current()) {
       Menu::current()->draw(context);
-      mouse_cursor->draw(context);
     }
 
     context.do_drawing();
     }
 
     context.do_drawing();
@@ -1140,13 +1157,13 @@ WorldMap::loadgame(const std::string& filename)
           }
         } else {
           std::cerr << "Unknown token '" << iter.item() 
           }
         } else {
           std::cerr << "Unknown token '" << iter.item() 
-            << "' in levels block in worldmap.\n";
+                    << "' in levels block in worldmap.\n";
         }
       }
     }
   } catch(std::exception& e) {
     std::cerr << "Problem loading game '" << filename << "': " << e.what() 
         }
       }
     }
   } catch(std::exception& e) {
     std::cerr << "Problem loading game '" << filename << "': " << e.what() 
-      << "\n";
+              << "\n";
     load_map();
     player_status.reset();
   }
     load_map();
     player_status.reset();
   }
index dd5d03a..0894d28 100644 (file)
 #include "statistics.h"
 #include "timer.h"
 #include "tile_manager.h"
 #include "statistics.h"
 #include "timer.h"
 #include "tile_manager.h"
+#include "game_object.h"
 
 class Sprite;
 class Menu;
 
 class Sprite;
 class Menu;
+class SpawnPoint;
+class GameObject;
+class TileMap;
 extern Menu* worldmap_menu;
 
 namespace WorldMapNS {
 extern Menu* worldmap_menu;
 
 namespace WorldMapNS {
@@ -59,7 +63,7 @@ Direction reverse_dir(Direction d);
 
 class WorldMap;
 
 
 class WorldMap;
 
-class Tux
+class Tux : public GameObject
 {
 public:
   Direction back_direction;
 {
 public:
   Direction back_direction;
@@ -108,13 +112,10 @@ private:
   std::string name;
   std::string music;
 
   std::string name;
   std::string music;
 
-  std::vector<int> tilemap;
-  int width;
-  int height;
+  typedef std::vector<GameObject*> GameObjects;
+  GameObjects game_objects;
+  TileMap* solids;
   
   
-  int start_x;
-  int start_y;
-
   TileManager* tile_manager;
 
 public:
   TileManager* tile_manager;
 
 public:
@@ -187,9 +188,10 @@ private:
 
   typedef std::vector<SpecialTile> SpecialTiles;
   SpecialTiles special_tiles;
 
   typedef std::vector<SpecialTile> SpecialTiles;
   SpecialTiles special_tiles;
-
   typedef std::vector<Level> Levels;
   Levels levels;
   typedef std::vector<Level> Levels;
   Levels levels;
+  typedef std::vector<SpawnPoint*> SpawnPoints;
+  SpawnPoints spawn_points;
 
   MusicRef song;
 
 
   MusicRef song;
 
@@ -219,6 +221,9 @@ public:
   
   void get_input();
 
   
   void get_input();
 
+  void add_object(GameObject* object);
+  void clear_objects();
+
   /** Update Tux position */
   void update(float delta);
 
   /** Update Tux position */
   void update(float delta);
 
@@ -244,16 +249,10 @@ public:
   void loadmap(const std::string& filename);
 
   const std::string& get_world_title() const
   void loadmap(const std::string& filename);
 
   const std::string& get_world_title() const
-    { return name; }
+  { return name; }
     
     
-  const int& get_start_x() const
-    { return start_x; }
-  
-  const int& get_start_y() const
-    { return start_y; }
-
   void set_map_filename(std::string filename)
   void set_map_filename(std::string filename)
-    { map_filename = filename; }
+  { map_filename = filename; }
 
 private:
   void on_escape_press();
 
 private:
   void on_escape_press();