added a bell object which is a new better way to do reset points
authorMatthias Braun <matze@braunis.de>
Wed, 30 Mar 2005 01:52:14 +0000 (01:52 +0000)
committerMatthias Braun <matze@braunis.de>
Wed, 30 Mar 2005 01:52:14 +0000 (01:52 +0000)
SVN-Revision: 2295

16 files changed:
TODO
data/images/supertux.strf
data/levels/test/verticalforest.stl
lib/special/moving_object.h
src/flip_level_transformer.cpp
src/gameloop.cpp
src/gameloop.h
src/object/bell.cpp [new file with mode: 0644]
src/object/bell.h [new file with mode: 0644]
src/object/block.h
src/object/particlesystem.cpp
src/object/player.cpp
src/object/portable.h
src/sector.cpp
src/sector.h
src/title.cpp

diff --git a/TODO b/TODO
index 1b291a0..83d4918 100644 (file)
--- a/TODO
+++ b/TODO
@@ -58,13 +58,7 @@ Programming
     themselfes. This could speed up rendering of tilemaps.
 [M] Make the gamelogic run in a fixed logical framerate
 
---Miscellaneous--
-[?] think about how to implement scripting, and how to make a simple and easy to
-  use api for the scripting interface
-  (language will probably be lua - just have to figure out how well we can do
-   without OO support in the scripting language.
-   Other candidates are python, ruby and less likely java, mono/.net,
-   surely no own invention, perl or 1 of these c-like scripting languages)
+--Objects--
 [H] Create a "sound object" that is an object or area, that can be placed on the
     map and constantly plays a .wav file to improve game athmosphere.
     Good examples would be a water sound which can be placed at waterfalls,
@@ -86,6 +80,14 @@ Programming
 [H] Add a rope object on which tux is able to climb, also add a ? block that
     emits a rope when hit
 [H] redo trampolines
+
+--Miscellaneous--
+[?] think about how to implement scripting, and how to make a simple and easy to
+  use api for the scripting interface
+  (language will probably be lua - just have to figure out how well we can do
+   without OO support in the scripting language.
+   Other candidates are python, ruby and less likely java, mono/.net,
+   surely no own invention, perl or 1 of these c-like scripting languages)
 [H] Buttjump related things
      - enable buttjump again
      - Should kill enemies with a certain range
index b23f0b8..608420d 100644 (file)
           (y-offset 0)
           (images "shared/stomp.png")
   ))
+
+  (sprite (name "bell")
+       (action
+          (name "default")
+          (x-offset 0)
+          (y-offset 0)
+          (images "shared/bell/bell-m.png")
+       )
+       (action
+         (name "ringing")
+         (images "shared/bell/bell-l.png"
+           "shared/bell/bell-m.png"
+           "shared/bell/bell-r.png"
+           "shared/bell/bell-m.png"
+         )
+       )
+  )
 )
 
 ;; EOF ;;
index c53c858..c5b22fe 100644 (file)
   (reset-points
    )
   (objects
+   (bell (x 609) (y 6500))
+   (bell (x 543) (y 3655))   
   )
    )
 
index 0ac6844..0103878 100644 (file)
@@ -63,10 +63,18 @@ namespace SuperTux
         return movement;
       }
 
+      /** places the moving object at a specific position. Be carefull when
+       * using this function. There are no collision detection checks performed
+       * here so bad things could happen.
+       */
+      virtual void set_pos(const Vector& pos)
+      {
+        bbox.set_pos(pos);
+      }
+
     protected:
       friend class Sector;
       friend class CollisionGrid;
-      friend class FlipLevelTransformer;
       
       /** The bounding box of the object (as used for collision detection, this
        * isn't necessarily the bounding box for graphics)
index db5a693..89f73b1 100644 (file)
@@ -71,8 +71,8 @@ FlipLevelTransformer::transform_spawnpoint(float height, SpawnPoint* spawn)
 void
 FlipLevelTransformer::transform_moving_object(float height, MovingObject*object)
 {
-  Vector pos = object->bbox.p1;
+  Vector pos = object->get_pos();
   pos.y = height - pos.y;
-  object->bbox.set_pos(pos);
+  object->set_pos(pos);
 }
 
index f6d92d9..3b593f9 100644 (file)
@@ -91,9 +91,6 @@ GameSession::GameSession(const std::string& levelfile_, int mode,
 
   context = new DrawingContext();
 
-  last_swap_point = Vector(-1, -1);
-  last_swap_stats.reset();
-
   restart_level();
 }
 
@@ -126,40 +123,23 @@ GameSession::restart_level()
   global_stats.set_total_points(BADGUYS_KILLED_STAT, level->get_total_badguys());
   global_stats.set_total_points(TIME_NEEDED_STAT, level->timelimit);
 
-  currentsector = level->get_sector("main");
-  if(!currentsector)
-    Termination::abort("Level has no main sector.", "");
-  currentsector->activate("main");
-
-#if 0
-  // Set Tux to the nearest reset point
-  if(tux_pos.x != -1)
-    {
-    tux_pos = currentsector->get_best_spawn_point(tux_pos);
-
-    if(last_swap_point.x > tux_pos.x)
-      tux_pos = last_swap_point;
-    else  // new swap point
-      {
-      last_swap_point = tux_pos;
-
-      last_swap_stats += global_stats;
-      }
-
-    currentsector->player->base.x = tux_pos.x;
-    currentsector->player->base.y = tux_pos.y;
-
-    // has to reset camera on swapping
-    currentsector->camera->reset(Vector(currentsector->player->base.x,
-                                        currentsector->player->base.y));
-    }
-#endif
-
-  if (st_gl_mode != ST_GL_DEMO_GAME)
-    {
-      if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
-        levelintro();
+  if(reset_sector != "") {
+    currentsector = level->get_sector(reset_sector);
+    if(!currentsector) {
+      std::stringstream msg;
+      msg << "Couldn't find sector '" << reset_sector << "' for resetting tux.";
+      throw std::runtime_error(msg.str());
     }
+    currentsector->activate(reset_pos);
+  } else {
+    currentsector = level->get_sector("main");
+    if(!currentsector)
+      throw std::runtime_error("Couldn't find main sector");
+    currentsector->activate("main");
+  }
+  
+  if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
+    levelintro();
 
   start_timers();
   currentsector->play_music(LEVEL_MUSIC);
@@ -172,7 +152,7 @@ GameSession::~GameSession()
 }
 
 void
-GameSession::levelintro(void)
+GameSession::levelintro()
 {
   SoundManager::get()->halt_music();
   
@@ -383,13 +363,13 @@ GameSession::process_events()
                       }
                   }
 
-                        /* Check if chacrater is ASCII */
-                        char ch[2];
-                        if((event.key.keysym.unicode & 0xFF80) == 0)
-                          {
-                          ch[0] = event.key.keysym.unicode & 0x7F;
-                          ch[1] = '\0';
-                          }
+                  /* Check if chacrater is ASCII */
+                  char ch[2];
+                  if((event.key.keysym.unicode & 0xFF80) == 0)
+                  {
+                      ch[0] = event.key.keysym.unicode & 0x7F;
+                      ch[1] = '\0';
+                  }
                         last_keys.append(ch);  // add to cheat keys
                         handle_cheats();
                   break;
@@ -572,9 +552,8 @@ GameSession::check_end_conditions()
 
   /* End of level? */
   if(end_sequence && endsequence_timer.check()) {
-      exit_status = ES_LEVEL_FINISHED;
-      global_stats += last_swap_stats;  // add swap points stats
-      return;
+    exit_status = ES_LEVEL_FINISHED;
+    return;
   } else if (!end_sequence && tux->is_dead()) {
     player_status.bonus = PlayerStatus::NO_BONUS;
 
@@ -795,6 +774,13 @@ GameSession::respawn(const std::string& sector, const std::string& spawnpoint)
 }
 
 void
+GameSession::set_reset_point(const std::string& sector, const Vector& pos)
+{
+  reset_sector = sector;
+  reset_pos = pos;
+}
+
+void
 GameSession::start_sequence(const std::string& sequencename)
 {
   if(sequencename == "endsequence" || sequencename == "fireworks") {
index ea1df56..73e26b0 100644 (file)
@@ -55,39 +55,9 @@ class DrawingContext;
     keeping the speed and framerate sane, etc. */
 class GameSession
 {
-private:
-  Uint32 fps_ticks;
-  Timer2 endsequence_timer;
-  Level* level;
-  Sector* currentsector;
-
-  int st_gl_mode;
-  int levelnb;
-  float fps_fps;
-  int pause_menu_frame;
-
-  /** If true the end_sequence will be played, user input will be
-      ignored while doing that */
-  enum EndSequenceState {
-    NO_ENDSEQUENCE,
-    ENDSEQUENCE_RUNNING, // tux is running right
-    ENDSEQUENCE_WAITING  // waiting for the end of the music
-  };
-  EndSequenceState end_sequence;
-  float last_x_pos;
-
-  bool game_pause;
-
-  std::string levelfile;
-
-  // the sector and spawnpoint we shoudl spawn after this frame
-  std::string newsector;
-  std::string newspawnpoint;
-
 public:
   enum ExitStatus { ES_NONE, ES_LEVEL_FINISHED, ES_GAME_OVER, ES_LEVEL_ABORT };
-private:
-  ExitStatus exit_status;
+
 public:
   DrawingContext* context;
   Timer2 time_left;
@@ -107,23 +77,14 @@ public:
 
   void respawn(const std::string& sectorname,
       const std::string& spawnpointname);
+  void set_reset_point(const std::string& sectorname,
+      const Vector& pos);
   Sector* get_current_sector()
   { return currentsector; }
 
   void start_sequence(const std::string& sequencename);
   
 private:
-  static GameSession* current_;
-
-  // for cheating
-  std::string last_keys;
-
-  // swap points
-  Vector last_swap_point;
-  Statistics last_swap_stats;
-
-  Statistics* best_level_statistics;
-
   void restart_level();
 
   void check_end_conditions();
@@ -138,12 +99,52 @@ private:
 
   void on_escape_press();
   void process_menu();
+
+
+  Uint32 fps_ticks;
+  Timer2 endsequence_timer;
+  Level* level;
+  Sector* currentsector;
+
+  int st_gl_mode;
+  int levelnb;
+  float fps_fps;
+  int pause_menu_frame;
+
+  /** If true the end_sequence will be played, user input will be
+      ignored while doing that */
+  enum EndSequenceState {
+    NO_ENDSEQUENCE,
+    ENDSEQUENCE_RUNNING, // tux is running right
+    ENDSEQUENCE_WAITING  // waiting for the end of the music
+  };
+  EndSequenceState end_sequence;
+  float last_x_pos;
+
+  bool game_pause;
+
+  std::string levelfile;
+
+  // reset point (the point where tux respawns if he dies)
+  std::string reset_sector;
+  Vector reset_pos;
+
+  // the sector and spawnpoint we should spawn after this frame
+  std::string newsector;
+  std::string newspawnpoint;
+
+  static GameSession* current_;
+
+  // for cheating
+  std::string last_keys;
+
+  Statistics* best_level_statistics;
+
+  ExitStatus exit_status;
 };
 
 std::string slotinfo(int slot);
 
-void bumpbrick(float x, float y);
-
 /** Return true if the gameloop() was entered, false otherwise */
 bool process_load_game_menu();
 
diff --git a/src/object/bell.cpp b/src/object/bell.cpp
new file mode 100644 (file)
index 0000000..eed6061
--- /dev/null
@@ -0,0 +1,64 @@
+#include <config.h>
+
+#include "bell.h"
+#include "resources.h"
+#include "special/sprite_manager.h"
+#include "video/drawing_context.h"
+#include "player.h"
+#include "object_factory.h"
+#include "gameloop.h"
+#include "sector.h"
+
+Bell::Bell(const lisp::Lisp& lisp)
+  : ringing(false)
+{
+  lisp.get("x", bbox.p1.x);
+  lisp.get("y", bbox.p1.y);
+  bbox.set_size(32, 32);
+  sprite = sprite_manager->create("bell");
+}
+
+Bell::~Bell()
+{
+  delete sprite;
+}
+
+void
+Bell::write(lisp::Writer& writer)
+{
+  writer.start_list("bell");
+  writer.write_float("x", bbox.p1.x);
+  writer.write_float("y", bbox.p1.y);
+  writer.end_list("bell");
+}
+
+void
+Bell::action(float )
+{
+}
+
+void
+Bell::draw(DrawingContext& context)
+{
+  sprite->draw(context, get_pos(), LAYER_TILES);
+}
+
+HitResponse
+Bell::collision(GameObject& other, const CollisionHit& )
+{
+  if(ringing)
+    return ABORT_MOVE;
+  
+  Player* player = dynamic_cast<Player*> (&other);
+  if(player) {
+    ringing = true;
+    // TODO play sound
+    sprite->set_action("ringing");
+    GameSession::current()->set_reset_point(Sector::current()->get_name(),
+        get_pos());
+  }
+  
+  return ABORT_MOVE;
+}
+
+IMPLEMENT_FACTORY(Bell, "bell");
diff --git a/src/object/bell.h b/src/object/bell.h
new file mode 100644 (file)
index 0000000..c52abeb
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef __BELL_H__
+#define __BELL_H__
+
+#include "lisp/lisp.h"
+#include "special/moving_object.h"
+#include "special/sprite.h"
+#include "serializable.h"
+
+using namespace SuperTux;
+
+/**
+ * A bell: When tux touches it, it begins ringing and you will respawn at this
+ * position.
+ */
+class Bell : public MovingObject, public Serializable
+{
+public:
+  Bell(const lisp::Lisp& lisp);
+  ~Bell();
+
+  void write(lisp::Writer& writer);
+  void action(float elapsed_time);
+  void draw(DrawingContext& context);
+  HitResponse collision(GameObject& other, const CollisionHit& hit);
+
+private:
+  Sprite* sprite;
+  bool ringing;
+};
+
+#endif
+
index ae11d22..d70bc6d 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef __BOX_H__
-#define __BOX_H__
+#ifndef __BLOCK_H__
+#define __BLOCK_H__
 
 #include "special/moving_object.h"
 
index 232d2cc..394fe1d 100644 (file)
@@ -137,7 +137,7 @@ RainParticleSystem::RainParticleSystem()
 
     virtual_width = screen->w * 2;
 
-    // create some random snowflakes
+    // create some random raindrops
     size_t raindropcount = size_t(virtual_width/8.0);
     for(size_t i=0; i<raindropcount; ++i) {
         RainParticle* particle = new RainParticle;
index 93fd5c4..e2b8a88 100644 (file)
@@ -257,9 +257,21 @@ Player::action(float elapsed_time)
     return;
   }
 
-  if(input.fire == false)
+  if(input.fire == false && grabbed_object) {
     grabbed_object = 0;
-
+    // move the grabbed object a bit away from tux
+    Vector pos = get_pos() + 
+        Vector(dir == LEFT ? -bbox.get_width() : bbox.get_width(),
+                bbox.get_height()*0.66666 - 32);
+    MovingObject* object = dynamic_cast<MovingObject*> (grabbed_object);
+    if(object) {
+      object->set_pos(pos);
+    } else {
+#ifdef DEBUG
+      std::cout << "Non MovingObjetc grabbed?!?\n";
+#endif
+    }
+  }
 
   if(!dying)
     handle_input();
index ce678d1..878b649 100644 (file)
@@ -14,10 +14,19 @@ using namespace SuperTux;
 class Portable
 {
 public:
-    /**
-     * called each frame when the object has been grabbed.
-     */
+  virtual ~Portable()
+  { }
+  
+  /**
+   * called each frame when the object has been grabbed.
+   */
   virtual void grab(MovingObject& object, const Vector& pos) = 0;
+
+  /** called when object isn't grabbed anymore */
+  virtual void ungrab(MovingObject& object)
+  {
+    (void) object;
+  }
 };
 
 #endif
index 795dc78..53edbf4 100644 (file)
@@ -392,11 +392,33 @@ Sector::add_object(GameObject* object)
 void
 Sector::activate(const std::string& spawnpoint)
 {
+  SpawnPoint* sp = 0;
+  for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
+      ++i) {
+    if((*i)->name == spawnpoint) {
+      sp = *i;
+      break;
+    }
+  }                                                                           
+  if(!sp) {
+    std::cerr << "Spawnpoint '" << spawnpoint << "' not found.\n";
+    if(spawnpoint != "main") {
+      activate("main");
+    } else {
+      activate(Vector(0, 0));
+    }
+  } else {
+    activate(sp->pos);
+  }
+}
+
+void
+Sector::activate(const Vector& player_pos)
+{
   _current = this;
 
   // Apply bonuses from former levels
-  switch (player_status.bonus)
-    {
+  switch (player_status.bonus) {
     case PlayerStatus::NO_BONUS:
       break;
                                                                                 
@@ -407,41 +429,16 @@ Sector::activate(const std::string& spawnpoint)
     case PlayerStatus::GROWUP_BONUS:
       player->grow(false);
       break;
-    }
 
-  SpawnPoint* sp = 0;
-  for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
-      ++i) {
-    if((*i)->name == spawnpoint) {
-      sp = *i;
+    default:
+      std::cerr << "Unknown bonus in PlayerStatus?!?\n";
       break;
-    }
-  }
-  if(!sp) {
-    std::cerr << "Spawnpoint '" << spawnpoint << "' not found.\n";
-  } else {
-    player->move(sp->pos);
   }
 
+  player->move(player_pos);
   camera->reset(player->get_pos());
 }
 
-Vector
-Sector::get_best_spawn_point(Vector pos)
-{
-  Vector best_reset_point = Vector(-1,-1);
-
-  for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
-      ++i) {
-    if((*i)->name != "main")
-      continue;
-    if((*i)->pos.x > best_reset_point.x && (*i)->pos.x < pos.x)
-      best_reset_point = (*i)->pos;
-  }
-
-  return best_reset_point;
-}
-
 Rectangle
 Sector::get_active_region()
 {
index 39b13bc..464a64f 100644 (file)
@@ -69,9 +69,8 @@ public:
   void write(lisp::Writer& writer);
 
   /// activates this sector (change music, intialize player class, ...)
-  void activate(const std::string& spawnpoint = "main");
-  /// get best spawn point
-  Vector get_best_spawn_point(Vector pos);
+  void activate(const std::string& spawnpoint);
+  void activate(const Vector& player_pos);
 
   void action(float elapsed_time);
   void update_game_objects();
index 514479d..df500cf 100644 (file)
@@ -85,7 +85,7 @@ void resume_demo()
 {
   // FIXME: shouldn't be needed if GameSession
   // didn't relay on global variables
-  titlesession->get_current_sector()->activate();
+  titlesession->get_current_sector()->activate("main");
   titlesession->set_current();
 
   frame_rate.update();
@@ -214,7 +214,7 @@ void check_levels_contrib_menu()
     contrib_subset_menu->additem(MN_HL,"",0,0);      
     contrib_subset_menu->additem(MN_BACK, _("Back"), 0, 0);
 
-    titlesession->get_current_sector()->activate();
+    titlesession->get_current_sector()->activate("main");
     titlesession->set_current();
   }
 }
@@ -297,7 +297,7 @@ void title(void)
   logo = new Surface(datadir + "/images/title/logo.png", true);
   img_choose_subset = new Surface(datadir + "/images/status/choose-level-subset.png", true);
 
-  titlesession->get_current_sector()->activate();
+  titlesession->get_current_sector()->activate("main");
   titlesession->set_current();
 
   /* --- Main title loop: --- */