-Worldmap cleanups (use DrawingContext transformstack)
authorMatthias Braun <matze@braunis.de>
Fri, 1 Apr 2005 12:16:53 +0000 (12:16 +0000)
committerMatthias Braun <matze@braunis.de>
Fri, 1 Apr 2005 12:16:53 +0000 (12:16 +0000)
-Refactoring/Cleanup in PlayerStatus handling (no separate handling of
    PlayerStatus in Player object now)
-Reimplemented stalactite badguy
-more smaller cleanups

SVN-Revision: 2311

23 files changed:
TODO
data/images/supertux.strf
data/levels/test/verticalforest.stl
lib/special/sprite.cpp
lib/special/sprite_data.cpp
lib/video/drawing_context.cpp
src/badguy/stalactite.cpp [new file with mode: 0644]
src/badguy/stalactite.h [new file with mode: 0644]
src/gameloop.cpp
src/object/block.cpp
src/object/coin.cpp
src/object/flower.cpp
src/object/growup.cpp
src/object/oneup.cpp
src/object/player.cpp
src/object/player.h
src/player_status.cpp
src/player_status.h
src/sector.cpp
src/title.cpp
src/trigger/door.cpp
src/worldmap.cpp
src/worldmap.h

diff --git a/TODO b/TODO
index 83d4918..a2dcadc 100644 (file)
--- a/TODO
+++ b/TODO
@@ -21,12 +21,6 @@ Low priority [L]:    things that should be fixed sometime
 Programming
 ~~~~~~~~~~~
 --Collision Detection Rewrite (all [H])--
- * enemies:
-    - implement fish
-    - implement wingling
-    - implement stalactite
-    - implement tree (really?)
-    - bring back stay on platform flag
  ** implement ability to cary mriceblock (and other objects) around
  * smoke clouds are too fast
  * rethink slopes collision feedback... tux becomes too slow when walking up
@@ -58,6 +52,13 @@ Programming
     themselfes. This could speed up rendering of tilemaps.
 [M] Make the gamelogic run in a fixed logical framerate
 
+--BadGuys--
+[H] Bring back stay on platform flag
+[H] Reimplement fish
+[H] Reimplement stalactite
+[H] Do something with the wingling
+[?] Do something with the tree?
+
 --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.
@@ -99,10 +100,6 @@ Programming
         - After enemy-kill is used, powerup should be removed from Tux
 [H] Icebullet related things
      - we should decide on specifics
-[H] Graphics
-     - New forest tileset
-     - Badguy sprites
-     - Tux's buttjump animation
 [M] Save score on per-level basis to make high-score
 [M] Save time on per-level basis to make low-time-score
 [M] Add bonus score for extra time left when finishing a level
@@ -126,6 +123,7 @@ Graphics
 [H] Create a graphics to visually present reset points. (Maybe a bell that
     starts swinging once tux touched it?)
 [M] Add graphics for ropes
+[H] Animation for the buttjump
 [L] Create graphics for bubbles and soap (not necessary for milestone2)
 
 -new enemies need to be designed and added
index 96a3a3a..eb0fae5 100644 (file)
          (y-offset 0)
          (images "shared/stalactite.png"))
        (action
-         (name "broken")
+         (name "squished")
          (x-offset 0)
          (y-offset 16)
          (images "shared/stalactite-broken.png")))
   ; Door
   (sprite (name "door")
        (action
-          (name "default")
+          (name "normal")
           (x-offset 0)
           (y-offset 0)
           (images "shared/door-1.png"))
   ; coin
   (sprite (name "coin")
       (action 
-          (name "default")
+          (name "normal")
           (images "tilesets/coin-1.png"
                   "tilesets/coin-2.png"
                   "tilesets/coin-3.png"
   (sprite (name "bonusblock")
       (action
          (fps 15)
-         (name "default")
+         (name "normal")
          (images "tilesets/bonus2-1.png"
                  "tilesets/bonus2-2.png"
                  "tilesets/bonus2-3.png"
         (name "empty")
         (images "tilesets/bonus2-d.png"))
       (action 
-        (name "default")
+        (name "normal")
         (images "tilesets/brick0.png"))
   )
 
         (name "empty")
         (images "tilesets/bonus2-d.png"))
       (action 
-        (name "default")
+        (name "normal")
         (images "tilesets/brick1.png"))
   )
 
   (sprite (name "rock")
       (action
-        (name "default")
+        (name "normal")
         (images "tilesets/block11.png"))
   )
 
 
   (sprite (name "bell")
        (action
-          (name "default")
+          (name "normal")
           (x-offset 0)
           (y-offset 0)
           (images "shared/bell/bell-m.png")
       (images "shared/unstable_tile.png"))
   )
 
-; Hatch
+  (sprite (name "worldmaptux")
+    (action
+      (name "small")
+      (y-offset 10) 
+      (images "worldmap/smalltux.png")
+    )
+    (action
+      (name "large")
+      (y-offset 10) 
+      (images "worldmap/tux.png")
+    )
+    (action
+      (name "fire")
+      (y-offset 10) 
+      (images "worldmap/firetux.png")
+    )
+  )
+
   (sprite (name "hatch")
        (action
           (name "default")
                   "shared/hatch-6.png"))
   )
 )
-;; EOF ;;
index c5b22fe..b7f453b 100644 (file)
@@ -2,7 +2,7 @@
 (supertux-level
   (version 1)
   (author "Marek Moeckel")
-  (name "Inside The Tree")
+  (name (_ "Inside The Tree"))
   (width  30)
   (height 300)
   (start_pos_x    100)
index f07cfc1..48aa325 100644 (file)
@@ -34,7 +34,9 @@ namespace SuperTux
 Sprite::Sprite(SpriteData& newdata)
   : data(newdata), frame(0), animation_loops(-1)
 {
-  action = data.actions.begin()->second;
+  action = data.get_action("normal");
+  if(!action)
+    action = data.actions.begin()->second;
   last_ticks = SDL_GetTicks();
 }
 
index 252fbf8..cb84a6a 100644 (file)
@@ -86,18 +86,6 @@ SpriteData::parse_action(const lisp::Lisp* lisp)
   lisp->get("z-order", action->z_order);
   lisp->get("fps", action->fps);
 
-  // this doesn't seem to be used and implemented
-#if 0
-  std::vector <int> mask_color;
-  lispreader.read_int_vector("apply-mask", mask_color);
-  if(mask_color.size() == 4) {
-    for(std::vector<Surface*>::iterator i = action->surfaces.begin();
-        i < action->surfaces.end(); i++) {
-      (*i)->apply_filter(MASK_FILTER, Color(mask_color));
-    }
-  }
-#endif
-
   std::string mirror_action;
   lisp->get("mirror-action", mirror_action);
   if(!mirror_action.empty()) {
@@ -136,8 +124,6 @@ SpriteData::get_action(std::string act)
 {
   Actions::iterator i = actions.find(act);
   if(i == actions.end()) {
-    std::cerr << "Warning: Action '" << act <<
-      "' not found on Sprite '" << name << "'\n";
     return 0;
   }
   return i->second;
index 6257b9f..8aadf06 100644 (file)
@@ -323,6 +323,11 @@ DrawingContext::draw_filled_rect(DrawingRequest& request)
 void
 DrawingContext::do_drawing()
 {
+#ifdef DEBUG
+  assert(transformstack.empty());
+#endif
+  transformstack.clear();
+    
   std::stable_sort(drawingrequests.begin(), drawingrequests.end());
 
   for(DrawingRequests::iterator i = drawingrequests.begin();
diff --git a/src/badguy/stalactite.cpp b/src/badguy/stalactite.cpp
new file mode 100644 (file)
index 0000000..788683b
--- /dev/null
@@ -0,0 +1,99 @@
+#include <config.h>
+
+#include "stalactite.h"
+
+static const int SHAKE_RANGE = 40;
+static const float SHAKE_TIME = .8;
+static const float SQUISH_TIME = 2;
+
+Stalactite::Stalactite(const lisp::Lisp& lisp)
+{
+  lisp.get("x", start_position.x);
+  lisp.get("y", start_position.y);
+  bbox.set_size(31.8, 31.8);
+  sprite = sprite_manager->create("stalactite");
+  state = STALACTITE_HANGING;
+}
+
+void
+Stalactite::write(lisp::Writer& writer)
+{
+  writer.start_list("stalactite");
+  writer.write_float("x", start_position.x);
+  writer.write_float("y", start_position.y);
+  writer.end_list("stalactite");
+}
+
+void
+Stalactite::active_action(float elapsed_time)
+{
+  if(state == STALACTITE_HANGING) {
+    Player* player = Sector::current()->player;
+    if(player->get_bbox().p2.x > bbox.p1.x - SHAKE_RANGE
+        && player->get_bbox().p1.x < bbox.p2.x + SHAKE_RANGE
+        && player->get_bbox().p2.y > bbox.p1.y) {
+      timer.start(SHAKE_TIME);
+      state = STALACTITE_SHAKING;
+    }
+  } else if(state == STALACTITE_SHAKING) {
+    if(timer.check()) {
+      state = STALACTITE_FALLING;
+      physic.enable_gravity(true);
+    }
+  } else if(state == STALACTITE_FALLING || state == STALACTITE_SQUISHED) {
+    movement = physic.get_movement(elapsed_time);
+    if(state == STALACTITE_SQUISHED && timer.check())
+      remove_me();
+  }
+}
+
+HitResponse
+Stalactite::collision_solid(GameObject& , const CollisionHit& hit)
+{
+  if(state != STALACTITE_FALLING && state != STALACTITE_SQUISHED)
+    return FORCE_MOVE;
+  
+  if(fabsf(hit.normal.y) > .5) { // hit floor or roof?
+    state = STALACTITE_SQUISHED;
+    physic.set_velocity_y(0);
+    sprite->set_action("squished");
+    if(!timer.started())
+      timer.start(SQUISH_TIME);
+  }
+
+  return CONTINUE;
+}
+
+HitResponse
+Stalactite::collision_player(Player& player, const CollisionHit& )
+{
+  if(state != STALACTITE_SQUISHED) {
+    player.kill(Player::SHRINK);
+  }
+
+  return FORCE_MOVE;
+}
+
+void
+Stalactite::kill_fall()
+{
+}
+
+void
+Stalactite::draw(DrawingContext& context)
+{
+  if(state == STALACTITE_SHAKING) {
+    sprite->draw(context, get_pos() + Vector((rand() % 6)-3, 0), LAYER_OBJECTS);
+  } else {
+    sprite->draw(context, get_pos(), LAYER_OBJECTS);
+  }
+}
+
+void
+Stalactite::deactivate()
+{
+  if(state != STALACTITE_HANGING)
+    remove_me();
+}
+
+IMPLEMENT_FACTORY(Stalactite, "stalactite")
diff --git a/src/badguy/stalactite.h b/src/badguy/stalactite.h
new file mode 100644 (file)
index 0000000..62ab230
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __STALACTITE_H__
+#define __STALACTITE_H__
+
+#include "badguy.h"
+
+class Stalactite : public BadGuy
+{
+public:
+  Stalactite(const lisp::Lisp& reader);
+  void active_action(float elapsed_time);
+  void write(lisp::Writer& writer);
+  HitResponse collision_solid(GameObject& other, const CollisionHit& hit);
+  HitResponse collision_player(Player& player, const CollisionHit& hit);
+
+  void kill_fall();
+  void draw(DrawingContext& context);
+  void deactivate();
+
+private:
+  Physic physic;
+  Timer2 timer;
+
+  enum StalactiteState {
+    STALACTITE_HANGING,
+    STALACTITE_SHAKING,
+    STALACTITE_FALLING,
+    STALACTITE_SQUISHED
+  };
+  StalactiteState state;
+};
+
+#endif
+
index 6e6b790..642a436 100644 (file)
@@ -458,17 +458,15 @@ GameSession::handle_cheats()
   // Cheating words (the goal of this is really for debugging,
   // but could be used for some cheating, nothing wrong with that)
   if(compare_last(last_keys, "grow")) {
-    tux.grow(false);
+    tux.set_bonus(GROWUP_BONUS, false);
     last_keys.clear();
   }
   if(compare_last(last_keys, "fire")) {
-    tux.grow(false);
-    tux.got_power = tux.FIRE_POWER;
+    tux.set_bonus(FIRE_BONUS, false);
     last_keys.clear();
   }
   if(compare_last(last_keys, "ice")) {
-    tux.grow(false);
-    tux.got_power = tux.ICE_POWER;
+    tux.set_bonus(ICE_BONUS, false);
     last_keys.clear();
   }
   if(compare_last(last_keys, "lifeup")) {
@@ -547,8 +545,6 @@ GameSession::check_end_conditions()
     exit_status = ES_LEVEL_FINISHED;
     return;
   } else if (!end_sequence && tux->is_dead()) {
-    player_status.bonus = PlayerStatus::NO_BONUS;
-
     if (player_status.lives < 0) { // No more lives!?
       exit_status = ES_GAME_OVER;
     } else { // Still has lives, so reset Tux to the levelstart
@@ -571,10 +567,14 @@ GameSession::action(float elapsed_time)
   // respawning in new sector?
   if(newsector != "" && newspawnpoint != "") {
     Sector* sector = level->get_sector(newsector);
+    if(sector == 0) {
+      std::cerr << "Sector '" << newsector << "' not found.\n";
+    }
+    sector->activate(newspawnpoint);
+    sector->play_music(LEVEL_MUSIC);
     currentsector = sector;
-    currentsector->activate(newspawnpoint);
-    currentsector->play_music(LEVEL_MUSIC);
-    newsector = newspawnpoint = "";
+    newsector = "";
+    newspawnpoint = "";
   }
 }
 
index 4bc3434..0f9fba4 100644 (file)
@@ -100,7 +100,7 @@ BonusBlock::BonusBlock(const Vector& pos, int data)
   : Block(sprite_manager->create("bonusblock"))
 {
   bbox.set_pos(pos);
-  sprite->set_action("default");
+  sprite->set_action("normal");
   switch(data) {
     case 1: contents = CONTENT_COIN; break;
     case 2: contents = CONTENT_FIREGROW; break;
@@ -160,11 +160,11 @@ BonusBlock::try_open()
   switch(contents) {
     case CONTENT_COIN:
       Sector::current()->add_object(new BouncyCoin(get_pos()));
-      player.get_status().incCoins();
+      player.get_status()->incCoins();
       break;
 
     case CONTENT_FIREGROW:
-      if(player.size == SMALL) {
+      if(player.get_status()->bonus == NO_BONUS) {
         SpecialRiser* riser = new SpecialRiser(
             new GrowUp(get_pos() + Vector(0, -32)));
         sector->add_object(riser);
@@ -177,7 +177,7 @@ BonusBlock::try_open()
       break;
 
     case CONTENT_ICEGROW:
-      if(player.size == SMALL) {
+      if(player.get_status()->bonus == NO_BONUS) {
         SpecialRiser* riser = new SpecialRiser(
             new GrowUp(get_pos() + Vector(0, -32)));
         sector->add_object(riser);                                            
@@ -241,12 +241,12 @@ Brick::try_break(bool playerhit)
   if(coin_counter > 0) {
     sector->add_object(new BouncyCoin(get_pos()));
     coin_counter--;
-    player.get_status().incCoins();
+    player.get_status()->incCoins();
     if(coin_counter == 0)
       sprite->set_action("empty");
     start_bounce();
   } else if(breakable) {
-    if(playerhit && player.size == SMALL) {
+    if(playerhit && !player.is_big()) {
       start_bounce();
       return;
     }
index c9b38ba..2ab89da 100644 (file)
@@ -45,7 +45,7 @@ Coin::draw(DrawingContext& context)
 void
 Coin::collect()
 {
-  Sector::current()->player->get_status().incCoins();
+  Sector::current()->player->get_status()->incCoins();
   Sector::current()->add_object(new BouncyCoin(get_pos()));
   global_stats.add_points(COINS_COLLECTED_STAT, 1);
   remove_me();
index d480555..d406592 100644 (file)
@@ -45,9 +45,10 @@ Flower::collision(GameObject& other, const CollisionHit& )
     return ABORT_MOVE;
 
   if(type == FIREFLOWER)
-    player->got_power = Player::FIRE_POWER;
+    player->set_bonus(FIRE_BONUS, true);
   else
-    player->got_power = Player::ICE_POWER;
+    player->set_bonus(ICE_BONUS, true);
+  
   SoundManager::get()->play_sound(IDToSound(SND_COFFEE));
   remove_me();
   return ABORT_MOVE;
index 4ed6e72..3f37e0f 100644 (file)
@@ -45,7 +45,7 @@ GrowUp::collision(GameObject& other, const CollisionHit& hit)
   
   Player* player = dynamic_cast<Player*>(&other);
   if(player != 0) {
-    player->grow();
+    player->set_bonus(GROWUP_BONUS, true);
     SoundManager::get()->play_sound(IDToSound(SND_EXCELLENT));
     remove_me();
     
index 324f838..313efdf 100644 (file)
@@ -41,7 +41,7 @@ OneUp::collision(GameObject& other, const CollisionHit& )
 {
   Player* player = dynamic_cast<Player*> (&other);
   if(player) {
-    player->get_status().incLives();
+    player->get_status()->incLives();
     remove_me();
     return ABORT_MOVE;
   }
index e2b8a88..e4d8c6e 100644 (file)
@@ -28,7 +28,6 @@
 #include "special/sprite_manager.h"
 #include "player.h"
 #include "tile.h"
-#include "player_status.h"
 #include "special/sprite.h"
 #include "sector.h"
 #include "resources.h"
@@ -125,8 +124,8 @@ TuxBodyParts::draw(DrawingContext& context, const Vector& pos, int layer,
     feet->draw(context, pos, layer-2, drawing_effect);
 }
 
-Player::Player()
-  : grabbed_object(0)
+Player::Player(PlayerStatus* _player_status)
+  : player_status(_player_status), grabbed_object(0)
 {
   smalltux_gameover = sprite_manager->create("smalltux-gameover");
   smalltux_star = sprite_manager->create("smalltux-star");
@@ -144,10 +143,10 @@ Player::~Player()
 void
 Player::init()
 {
-  bbox.set_size(31.8, 31.8);
-
-  size = SMALL;
-  got_power = NONE_POWER;
+  if(is_big())
+    bbox.set_size(31.8, 63.8);
+  else
+    bbox.set_size(31.8, 31.8);
 
   dir = RIGHT;
   old_dir = dir;
@@ -168,7 +167,7 @@ Player::init()
   flapping_velocity = 0;
 
   // temporary to help player's choosing a flapping
-  flapping_mode = MAREK_FLAP;
+  flapping_mode = NO_FLAP;
 
   // Ricardo's flapping
   flaps_nb = 0;
@@ -229,27 +228,6 @@ Player::key_event(SDLKey key, bool state)
 }
 
 void
-Player::level_begin()
-{
-  move(Vector(100, 170));
-  duck = false;
-
-  dying = false;
-
-  input.reset();
-
-  on_ground_flag = false;
-
-  physic.reset();
-}
-
-PlayerStatus&
-Player::get_status()
-{
-  return player_status;
-}
-
-void
 Player::action(float elapsed_time)
 {
   if(dying && dying_timer.check()) {
@@ -303,6 +281,15 @@ Player::on_ground()
   return on_ground_flag;
 }
 
+bool
+Player::is_big()
+{
+  if(player_status->bonus == NO_BONUS)
+    return false;
+
+  return true;
+}
+
 void
 Player::handle_horizontal_input()
 {
@@ -455,10 +442,10 @@ Player::handle_vertical_input()
       can_jump = false;
       can_flap = false;
       flaps_nb = 0; // Ricardo's flapping
-      if (size == SMALL)
-        SoundManager::get()->play_sound(IDToSound(SND_JUMP));
-      else
+      if (is_big())
         SoundManager::get()->play_sound(IDToSound(SND_BIGJUMP));
+      else
+        SoundManager::get()->play_sound(IDToSound(SND_JUMP));
     }
   // Let go of jump key
   else if(!input.jump)
@@ -576,7 +563,7 @@ Player::handle_vertical_input()
     butt_jump = false;
 
   // Do butt jump
-  if (butt_jump && on_ground() && size == BIG)
+  if (butt_jump && on_ground() && is_big())
   {
     // Add a smoke cloud
     if (duck) 
@@ -657,7 +644,7 @@ Player::handle_input()
   handle_vertical_input();
 
   /* Shoot! */
-  if (input.fire && !input.old_fire && got_power != NONE_POWER) {
+  if (input.fire && !input.old_fire && player_status->bonus == FIRE_BONUS) {
     if(Sector::current()->add_bullet(
 //           get_pos() + Vector(0, bbox.get_height()/2),
           get_pos() + ((dir == LEFT)? Vector(0, bbox.get_height()/2) 
@@ -669,14 +656,14 @@ Player::handle_input()
   }
 
   /* Duck! */
-  if (input.down && size == BIG && !duck 
+  if (input.down && is_big() && !duck 
       && physic.get_velocity_y() == 0 && on_ground())
     {
       duck = true;
       bbox.move(Vector(0, 32));
       bbox.set_height(31.8);
     }
-  else if(!input.down && size == BIG && duck)
+  else if(!input.down && is_big() && duck)
     {
       // try if we can really unduck
       bbox.move(Vector(0, -32));
@@ -697,17 +684,19 @@ Player::handle_input()
 }
 
 void
-Player::grow(bool animate)
+Player::set_bonus(BonusType type, bool animate)
 {
-  if(size == BIG)
+  if(player_status->bonus == type)
     return;
   
-  size = BIG;
-  bbox.set_height(63.8);
-  bbox.move(Vector(0, -32));
-
-  if(animate)
-    growing_timer.start(GROWING_TIME);
+  if(player_status->bonus == NO_BONUS) {
+      bbox.set_height(63.8);
+      bbox.move(Vector(0, -32));
+      if(animate)
+        growing_timer.start(GROWING_TIME);
+  }
+      
+  player_status->bonus = type;
 }
 
 void
@@ -715,19 +704,19 @@ Player::draw(DrawingContext& context)
 {
   TuxBodyParts* tux_body;
           
-  if (size == SMALL)
-    tux_body = small_tux;
-  else if (got_power == FIRE_POWER)
+  if (player_status->bonus == GROWUP_BONUS)
+    tux_body = big_tux;
+  else if (player_status->bonus == FIRE_BONUS)
     tux_body = fire_tux;
-  else if (got_power == ICE_POWER)
+  else if (player_status->bonus == ICE_BONUS)
     tux_body = ice_tux;
   else
-    tux_body = big_tux;
+    tux_body = small_tux;
 
   int layer = LAYER_OBJECTS + 10;
 
   /* Set Tux sprite action */
-  if (duck && size == BIG)
+  if (duck && is_big())
     {
     if(dir == LEFT)
       tux_body->set_action("duck-left");
@@ -748,7 +737,7 @@ Player::draw(DrawingContext& context)
     else // dir == RIGHT
       tux_body->set_action("kick-right");
     }
-  else if (butt_jump && size == BIG)
+  else if (butt_jump && is_big())
     {
     if(dir == LEFT)
       tux_body->set_action("buttjump-left");
@@ -782,7 +771,7 @@ Player::draw(DrawingContext& context)
 
   if(idle_timer.check())
     {
-    if(size == BIG)
+    if(is_big())
       {
       if(dir == LEFT)
         tux_body->head->set_action("idle-left", 1);
@@ -816,7 +805,7 @@ Player::draw(DrawingContext& context)
   if(dying) {
     smalltux_gameover->draw(context, get_pos(), layer);
   } else if(growing_timer.get_timeleft() > 0) {
-    if(size == SMALL)
+    if(!is_big())
       {
       if (dir == RIGHT)
         context.draw_surface(growingtux_right[GROWING_FRAMES-1 - 
@@ -851,7 +840,7 @@ Player::draw(DrawingContext& context)
       || size_t(global_time*20)%2)
      && !dying)
   {
-    if (size == SMALL || duck)
+    if (!is_big() || duck)
       smalltux_star->draw(context, get_pos(), layer + 5);
     else
       bigtux_star->draw(context, get_pos(), layer + 5);
@@ -920,20 +909,21 @@ Player::kill(HurtMode mode)
 
   physic.set_velocity_x(0);
 
-  if (mode == SHRINK && size == BIG)
+  if (mode == SHRINK && is_big())
     {
-      if (got_power != NONE_POWER)
+      if (player_status->bonus == FIRE_BONUS
+          || player_status->bonus == ICE_BONUS)
         {
           safe_timer.start(TUX_SAFE_TIME);
-          got_power = NONE_POWER;
+          player_status->bonus = GROWUP_BONUS;
         }
-      else
+      else 
         {
           growing_timer.start(GROWING_TIME);
           safe_timer.start(TUX_SAFE_TIME + GROWING_TIME);
-          size = SMALL;
           bbox.set_height(31.8);
           duck = false;
+          player_status->bonus = NO_BONUS;
         }
     }
   else
@@ -941,26 +931,26 @@ Player::kill(HurtMode mode)
       physic.enable_gravity(true);
       physic.set_acceleration(0, 0);
       physic.set_velocity(0, 700);
-      --player_status.lives;
+      player_status->lives -= 1;
       dying = true;
       dying_timer.start(3.0);
       flags |= FLAG_NO_COLLDET;
     }
 }
 
-/* Remove Tux's power ups */
-void
-Player::remove_powerups()
-{
-  got_power = NONE_POWER;
-  size = SMALL;
-  bbox.set_height(31.8);
-}
-
 void
 Player::move(const Vector& vector)
 {
   bbox.set_pos(vector);
+  if(is_big())
+    bbox.set_size(31.8, 63.8);
+  else
+    bbox.set_size(31.8, 31.8);
+  on_ground_flag = false;
+  duck = false;
+
+  input.reset();
+  physic.reset();
 }
 
 void
index 91e14b5..0fe60fa 100644 (file)
@@ -28,6 +28,7 @@
 #include "special/moving_object.h"
 #include "special/sprite.h"
 #include "math/physic.h"
+#include "player_status.h"
 
 using namespace SuperTux;
 
@@ -42,10 +43,6 @@ class Portable;
 #define TUX_FLAPPING_TIME 1 /* How long Tux can flap his wings to gain additional jump height */
 #define TIME_WARNING 20     /* When to alert player they're low on time! */
 
-/* Sizes: */
-#define SMALL 0
-#define BIG 1
-
 struct PlayerKeymap
 {
 public:
@@ -126,12 +123,10 @@ class Player : public MovingObject
 {
 public:
   enum HurtMode { KILL, SHRINK };
-  enum Power { NONE_POWER, FIRE_POWER, ICE_POWER };
   enum FallMode { ON_GROUND, JUMPING, TRAMPOLINE_JUMP, FALLING };
 
   PlayerInputType input;
-  int got_power;
-  int size;
+  PlayerStatus* player_status;
   bool duck;
   bool dead;
 
@@ -160,7 +155,7 @@ public:
   int flaps_nb;
 
   // temporary to help player's choosing a flapping
-  enum { MAREK_FLAP, RICARDO_FLAP, RYAN_FLAP, NONE_FLAP };
+  enum { MAREK_FLAP, RICARDO_FLAP, RYAN_FLAP, NO_FLAP };
   int flapping_mode;
 
   Timer2 invincible_timer;
@@ -175,15 +170,12 @@ public:
   Physic physic;
   
 public:
-  Player();
+  Player(PlayerStatus* player_status);
   virtual ~Player();
   
   bool key_event(SDLKey key, bool state);
-  void level_begin();
   void handle_input();
 
-  PlayerStatus& get_status();
-
   virtual void action(float elapsed_time);
   virtual void draw(DrawingContext& context);
   virtual HitResponse collision(GameObject& other, const CollisionHit& hit);
@@ -201,13 +193,18 @@ public:
   void kill(HurtMode mode);
   void player_remove_powerups();
   void check_bounds(Camera* camera);
-  void grow(bool animate = false);
   void move(const Vector& vector);
+  void set_bonus(BonusType type, bool animate = false);
+  PlayerStatus* get_status()
+  {
+    return player_status;
+  }
 
   void bounce(BadGuy& badguy);
 
   bool is_dead() const
   { return dead; }
+  bool is_big();
   
 private:
   bool on_ground();
@@ -216,7 +213,6 @@ private:
   
   void handle_horizontal_input();
   void handle_vertical_input();
-  void remove_powerups();
 
   Portable* grabbed_object;
 
index ba8b633..de5b7df 100644 (file)
@@ -69,15 +69,18 @@ void
 PlayerStatus::write(lisp::Writer& writer)
 {
   switch(bonus) {
-    case PlayerStatus::NO_BONUS:
+    case NO_BONUS:
       writer.write_string("bonus", "none");
       break;
-    case PlayerStatus::GROWUP_BONUS:
+    case GROWUP_BONUS:
       writer.write_string("bonus", "growup");
       break;
-    case PlayerStatus::FLOWER_BONUS:
+    case FIRE_BONUS:
       writer.write_string("bonus", "fireflower");
       break;
+    case ICE_BONUS:
+      writer.write_string("bonus", "iceflower");
+      break;
     default:
       std::cerr << "Unknown bonus type.\n";
       writer.write_string("bonus", "none");
@@ -100,7 +103,9 @@ PlayerStatus::read(const lisp::Lisp& lisp)
     } else if(bonusname == "growup") {
       bonus = GROWUP_BONUS;
     } else if(bonusname == "fireflower") {
-      bonus = FLOWER_BONUS;
+      bonus = FIRE_BONUS;
+    } else if(bonusname == "iceflower") {
+      bonus = ICE_BONUS;
     } else {
       std::cerr << "Unknown bonus '" << bonusname << "' in savefile.\n";
       bonus = NO_BONUS;
index 760ae92..1e2dd83 100644 (file)
 #include "timer.h"
 #include "serializable.h"
 
+enum BonusType {
+  NO_BONUS, GROWUP_BONUS, FIRE_BONUS, ICE_BONUS
+};
+
 /** 
  * This class memorizes player status between different game sessions (for
  * example when switching maps in the worldmap)
@@ -40,10 +44,9 @@ public:
 
   int  distros;
   int  lives;
-  enum BonusType { NO_BONUS, GROWUP_BONUS, FLOWER_BONUS };
   BonusType bonus;
 
-  int  score_multiplier;
+  int score_multiplier;
   int max_score_multiplier;
 };
 
index 53edbf4..00a8538 100644 (file)
@@ -56,6 +56,7 @@
 #include "badguy/jumpy.h"
 #include "badguy/spike.h"
 #include "trigger/sequence_trigger.h"
+#include "player_status.h"
 
 //#define USE_GRID
 
@@ -66,7 +67,7 @@ Sector::Sector()
     currentmusic(LEVEL_MUSIC)
 {
   song_title = "Mortimers_chipdisko.mod";
-  player = new Player();
+  player = new Player(&player_status);
   add_object(player);
 
   grid = new CollisionGrid(32000, 32000);
@@ -157,14 +158,15 @@ Sector::parse(const lisp::Lisp& sector)
 
   update_game_objects();
   fix_old_tiles();
-  update_game_objects();
   if(!camera) {
     std::cerr << "sector '" << name << "' does not contain a camera.\n";
-    camera = new Camera(this);
-    add_object(camera);
+    update_game_objects();
+    add_object(new Camera(this));
   }
   if(!solids)
     throw std::runtime_error("sector does not contain a solid tile layer.");
+
+  update_game_objects();
 }
 
 void
@@ -417,24 +419,6 @@ Sector::activate(const Vector& player_pos)
 {
   _current = this;
 
-  // Apply bonuses from former levels
-  switch (player_status.bonus) {
-    case PlayerStatus::NO_BONUS:
-      break;
-                                                                                
-    case PlayerStatus::FLOWER_BONUS:
-      player->got_power = Player::FIRE_POWER;  // FIXME: add ice power to here
-      // fall through
-                                                                                
-    case PlayerStatus::GROWUP_BONUS:
-      player->grow(false);
-      break;
-
-    default:
-      std::cerr << "Unknown bonus in PlayerStatus?!?\n";
-      break;
-  }
-
   player->move(player_pos);
   camera->reset(player->get_pos());
 }
@@ -742,22 +726,19 @@ Sector::add_bullet(const Vector& pos, float xm, Direction dir)
   // TODO remove this function and move these checks elsewhere...
   static const size_t MAX_FIRE_BULLETS = 2;
   static const size_t MAX_ICE_BULLETS = 1;
-    
-  if(player->got_power == Player::FIRE_POWER) {
+
+  Bullet* new_bullet = 0;
+  if(player_status.bonus == FIRE_BONUS) {
     if(bullets.size() > MAX_FIRE_BULLETS-1)
       return false;
-  } else if(player->got_power == Player::ICE_POWER) {
+    new_bullet = new Bullet(pos, xm, dir, FIRE_BULLET);
+  } else if(player_status.bonus == ICE_BONUS) {
     if(bullets.size() > MAX_ICE_BULLETS-1)
       return false;
-  }
-                                                                                
-  Bullet* new_bullet = 0;
-  if(player->got_power == Player::FIRE_POWER)
-    new_bullet = new Bullet(pos, xm, dir, FIRE_BULLET);
-  else if(player->got_power == Player::ICE_POWER)
     new_bullet = new Bullet(pos, xm, dir, ICE_BULLET);
-  else
-    throw std::runtime_error("wrong bullet type.");
+  } else {
+    return false;
+  }
   add_object(new_bullet);
 
   SoundManager::get()->play_sound(IDToSound(SND_SHOOT));
index 791cbfb..93ec351 100644 (file)
@@ -84,8 +84,7 @@ static FrameRate frame_rate(100);
  */
 void resume_demo()
 {
-  // FIXME: shouldn't be needed if GameSession
-  // didn't relay on global variables
+  player_status.reset();
   titlesession->get_current_sector()->activate("main");
   titlesession->set_current();
 
@@ -261,7 +260,7 @@ void draw_demo(float elapsed_time)
   // Wrap around at the end of the level back to the beginnig
   if(world->solids->get_width() * 32 - 320 < tux->get_pos().x)
     {
-      tux->level_begin();
+      world->activate("main");
       world->camera->reset(tux->get_pos());
     }
 
index 446f2fa..282c476 100644 (file)
@@ -79,6 +79,7 @@ Door::action(float )
 {
   //Check if door animation is complete
   if(sprite->check_animation()) {
+    sprite->set_action("normal");
     GameSession::current()->respawn(target_sector, target_spawnpoint);
   }
 }
index 59da5f2..58dc152 100644 (file)
@@ -33,6 +33,7 @@
 #include "video/screen.h"
 #include "video/drawing_context.h"
 #include "special/frame_rate.h"
+#include "special/sprite_manager.h"
 #include "audio/sound_manager.h"
 #include "lisp/parser.h"
 #include "lisp/lisp.h"
@@ -110,10 +111,8 @@ string_to_direction(const std::string& directory)
 Tux::Tux(WorldMap* worldmap_)
   : worldmap(worldmap_)
 {
-  largetux_sprite = new Surface(datadir +  "/images/worldmap/tux.png", true);
-  firetux_sprite = new Surface(datadir +  "/images/worldmap/firetux.png", true);
-  smalltux_sprite = new Surface(datadir +  "/images/worldmap/smalltux.png", true);
-
+  tux_sprite = sprite_manager->create("worldmaptux");
+  
   offset = 0;
   moving = false;
   tile_pos.x = worldmap->get_start_x();
@@ -124,30 +123,31 @@ Tux::Tux(WorldMap* worldmap_)
 
 Tux::~Tux()
 {
-  delete smalltux_sprite;
-  delete firetux_sprite;
-  delete largetux_sprite;
+  delete tux_sprite;
 }
 
 void
-Tux::draw(DrawingContext& context, const Vector& offset)
+Tux::draw(DrawingContext& context)
 {
-  Vector pos = get_pos();
-  switch (player_status.bonus)
-    {
-    case PlayerStatus::GROWUP_BONUS:
-      context.draw_surface(largetux_sprite,
-          Vector(pos.x + offset.x, pos.y + offset.y - 10), LAYER_OBJECTS);
+  switch (player_status.bonus) {
+    case GROWUP_BONUS:
+      tux_sprite->set_action("large");
       break;
-    case PlayerStatus::FLOWER_BONUS:
-      context.draw_surface(firetux_sprite,
-          Vector(pos.x + offset.x, pos.y + offset.y - 10), LAYER_OBJECTS);
+    case FIRE_BONUS:
+      tux_sprite->set_action("fire");
       break;
-    case PlayerStatus::NO_BONUS:
-      context.draw_surface(smalltux_sprite,
-          Vector(pos.x + offset.x, pos.y + offset.y - 10), LAYER_OBJECTS);
+    case NO_BONUS:
+      tux_sprite->set_action("small");
       break;
-    }
+    default:
+#ifdef DBEUG
+      std::cerr << "Bonus type not handled in worldmap.\n";
+#endif
+      tux_sprite->set_action("large");
+      break;
+  }
+
+  tux_sprite->draw(context, get_pos(), LAYER_OBJECTS);
 }
 
 
@@ -739,14 +739,6 @@ WorldMap::update(float delta)
                 level->statistics.merge(global_stats);
                 calculate_total_stats();
 
-                if (session.get_current_sector()->player->got_power !=
-                      session.get_current_sector()->player->NONE_POWER)
-                  player_status.bonus = PlayerStatus::FLOWER_BONUS;
-                else if (session.get_current_sector()->player->size == BIG)
-                  player_status.bonus = PlayerStatus::GROWUP_BONUS;
-                else
-                  player_status.bonus = PlayerStatus::NO_BONUS;
-
                 if (old_level_state != level->solved && level->auto_path)
                   { // Try to detect the next direction to which we should walk
                     // FIXME: Mostly a hack
@@ -784,7 +776,7 @@ WorldMap::update(float delta)
                   status. But the minimum lives and no bonus. */
               player_status.distros = old_player_status.distros;
               player_status.lives = std::min(old_player_status.lives, player_status.lives);
-              player_status.bonus = player_status.NO_BONUS;
+              player_status.bonus = NO_BONUS;
 
               break;
             case GameSession::ES_GAME_OVER:
@@ -914,26 +906,24 @@ WorldMap::at_special_tile()
   return 0;
 }
 
-
 void
-WorldMap::draw(DrawingContext& context, const Vector& offset)
+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 + offset.x, y*32 + offset.y),
-            LAYER_TILES);
+        tile->draw(context, Vector(x*32, y*32), LAYER_TILES);
       }
 
   for(Levels::iterator i = levels.begin(); i != levels.end(); ++i)
     {
       if (i->solved)
         context.draw_surface(leveldot_green,
-            Vector(i->pos.x*32 + offset.x, i->pos.y*32 + offset.y), LAYER_TILES+1);
+            Vector(i->pos.x*32, i->pos.y*32), LAYER_TILES+1);
       else
         context.draw_surface(leveldot_red,
-            Vector(i->pos.x*32 + offset.x, i->pos.y*32 + offset.y), LAYER_TILES+1);
+            Vector(i->pos.x*32, i->pos.y*32), LAYER_TILES+1);
     }
 
   for(SpecialTiles::iterator i = special_tiles.begin(); i != special_tiles.end(); ++i)
@@ -943,20 +933,23 @@ WorldMap::draw(DrawingContext& context, const Vector& offset)
 
       if (i->teleport_dest != Vector(-1, -1))
         context.draw_surface(teleporterdot,
-                Vector(i->pos.x*32 + offset.x, i->pos.y*32 + offset.y), LAYER_TILES+1);
+                Vector(i->pos.x*32, i->pos.y*32), LAYER_TILES+1);
 
       else if (!i->map_message.empty() && !i->passive_message)
         context.draw_surface(messagedot,
-                Vector(i->pos.x*32 + offset.x, i->pos.y*32 + offset.y), LAYER_TILES+1);
+                Vector(i->pos.x*32, i->pos.y*32), LAYER_TILES+1);
     }
 
-  tux->draw(context, offset);
+  tux->draw(context);
   draw_status(context);
 }
 
 void
 WorldMap::draw_status(DrawingContext& context)
 {
+  context.push_transform();
+  context.set_translation(Vector(0, 0));
+  
   char str[80];
   sprintf(str, " %d", total_stats.get_points(SCORE_STAT));
 
@@ -1026,6 +1019,8 @@ WorldMap::draw_status(DrawingContext& context)
     context.draw_text(gold_text, passive_message, 
             Vector(screen->w/2, screen->h - white_text->get_height() - 60),
             CENTER_ALLIGN, LAYER_FOREGROUND1);
+
+  context.pop_transform();
 }
 
 void
@@ -1066,8 +1061,11 @@ WorldMap::display()
 
     if (offset.x < screen->w - width*32) offset.x = screen->w - width*32;
     if (offset.y < screen->h - height*32) offset.y = screen->h - height*32;
-    
-    draw(context, offset);
+  
+    context.push_transform();
+    context.set_translation(offset);
+    draw(context);
+    context.pop_transform();
     get_input();
     update(elapsed_time);
       
index 01d0bfa..55eddfc 100644 (file)
@@ -32,6 +32,7 @@
 
 namespace SuperTux {
   class Menu;
+  class Sprite;
 }
 
 extern Menu* worldmap_menu;
@@ -66,9 +67,7 @@ public:
   Direction back_direction;
 private:
   WorldMap* worldmap;
-  Surface* largetux_sprite;
-  Surface* firetux_sprite;
-  Surface* smalltux_sprite;
+  Sprite* tux_sprite;
 
   Direction input_direction;
   Direction direction;
@@ -83,7 +82,7 @@ public:
   Tux(WorldMap* worldmap_);
   ~Tux();
   
-  void draw(DrawingContext& context, const Vector& offset);
+  void draw(DrawingContext& context);
   void action(float elapsed_time);
 
   void set_direction(Direction dir);
@@ -227,7 +226,7 @@ public:
   void update(float delta);
 
   /** Draw one frame */
-  void draw(DrawingContext& context, const Vector& offset);
+  void draw(DrawingContext& context);
 
   Vector get_next_tile(Vector pos, Direction direction);
   const Tile* at(Vector pos);