From: Matthias Braun Date: Fri, 1 Apr 2005 12:16:53 +0000 (+0000) Subject: -Worldmap cleanups (use DrawingContext transformstack) X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=495f8b77cb935fe8eff81bec755efca8e34e8a99;p=supertux.git -Worldmap cleanups (use DrawingContext transformstack) -Refactoring/Cleanup in PlayerStatus handling (no separate handling of PlayerStatus in Player object now) -Reimplemented stalactite badguy -more smaller cleanups SVN-Revision: 2311 --- diff --git a/TODO b/TODO index 83d49181d..a2dcadc18 100644 --- 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 diff --git a/data/images/supertux.strf b/data/images/supertux.strf index 96a3a3a2f..eb0fae59e 100644 --- a/data/images/supertux.strf +++ b/data/images/supertux.strf @@ -964,7 +964,7 @@ (y-offset 0) (images "shared/stalactite.png")) (action - (name "broken") + (name "squished") (x-offset 0) (y-offset 16) (images "shared/stalactite-broken.png"))) @@ -1280,7 +1280,7 @@ ; Door (sprite (name "door") (action - (name "default") + (name "normal") (x-offset 0) (y-offset 0) (images "shared/door-1.png")) @@ -1308,7 +1308,7 @@ ; coin (sprite (name "coin") (action - (name "default") + (name "normal") (images "tilesets/coin-1.png" "tilesets/coin-2.png" "tilesets/coin-3.png" @@ -1325,7 +1325,7 @@ (sprite (name "bonusblock") (action (fps 15) - (name "default") + (name "normal") (images "tilesets/bonus2-1.png" "tilesets/bonus2-2.png" "tilesets/bonus2-3.png" @@ -1347,7 +1347,7 @@ (name "empty") (images "tilesets/bonus2-d.png")) (action - (name "default") + (name "normal") (images "tilesets/brick0.png")) ) @@ -1356,13 +1356,13 @@ (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")) ) @@ -1382,7 +1382,7 @@ (sprite (name "bell") (action - (name "default") + (name "normal") (x-offset 0) (y-offset 0) (images "shared/bell/bell-m.png") @@ -1402,7 +1402,24 @@ (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") @@ -1421,4 +1438,3 @@ "shared/hatch-6.png")) ) ) -;; EOF ;; diff --git a/data/levels/test/verticalforest.stl b/data/levels/test/verticalforest.stl index c5b22fe9a..b7f453bef 100644 --- a/data/levels/test/verticalforest.stl +++ b/data/levels/test/verticalforest.stl @@ -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) diff --git a/lib/special/sprite.cpp b/lib/special/sprite.cpp index f07cfc1ef..48aa32565 100644 --- a/lib/special/sprite.cpp +++ b/lib/special/sprite.cpp @@ -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(); } diff --git a/lib/special/sprite_data.cpp b/lib/special/sprite_data.cpp index 252fbf8ff..cb84a6a82 100644 --- a/lib/special/sprite_data.cpp +++ b/lib/special/sprite_data.cpp @@ -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 mask_color; - lispreader.read_int_vector("apply-mask", mask_color); - if(mask_color.size() == 4) { - for(std::vector::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; diff --git a/lib/video/drawing_context.cpp b/lib/video/drawing_context.cpp index 6257b9fbc..8aadf064e 100644 --- a/lib/video/drawing_context.cpp +++ b/lib/video/drawing_context.cpp @@ -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 index 000000000..788683ba8 --- /dev/null +++ b/src/badguy/stalactite.cpp @@ -0,0 +1,99 @@ +#include + +#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 index 000000000..62ab23034 --- /dev/null +++ b/src/badguy/stalactite.h @@ -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 + diff --git a/src/gameloop.cpp b/src/gameloop.cpp index 6e6b79037..642a4364b 100644 --- a/src/gameloop.cpp +++ b/src/gameloop.cpp @@ -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 = ""; } } diff --git a/src/object/block.cpp b/src/object/block.cpp index 4bc343407..0f9fba404 100644 --- a/src/object/block.cpp +++ b/src/object/block.cpp @@ -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; } diff --git a/src/object/coin.cpp b/src/object/coin.cpp index c9b38ba54..2ab89dab7 100644 --- a/src/object/coin.cpp +++ b/src/object/coin.cpp @@ -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(); diff --git a/src/object/flower.cpp b/src/object/flower.cpp index d4805553b..d40659250 100644 --- a/src/object/flower.cpp +++ b/src/object/flower.cpp @@ -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; diff --git a/src/object/growup.cpp b/src/object/growup.cpp index 4ed6e7231..3f37e0f60 100644 --- a/src/object/growup.cpp +++ b/src/object/growup.cpp @@ -45,7 +45,7 @@ GrowUp::collision(GameObject& other, const CollisionHit& hit) Player* player = dynamic_cast(&other); if(player != 0) { - player->grow(); + player->set_bonus(GROWUP_BONUS, true); SoundManager::get()->play_sound(IDToSound(SND_EXCELLENT)); remove_me(); diff --git a/src/object/oneup.cpp b/src/object/oneup.cpp index 324f8381f..313efdf77 100644 --- a/src/object/oneup.cpp +++ b/src/object/oneup.cpp @@ -41,7 +41,7 @@ OneUp::collision(GameObject& other, const CollisionHit& ) { Player* player = dynamic_cast (&other); if(player) { - player->get_status().incLives(); + player->get_status()->incLives(); remove_me(); return ABORT_MOVE; } diff --git a/src/object/player.cpp b/src/object/player.cpp index e2b8a88b4..e4d8c6efb 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -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 diff --git a/src/object/player.h b/src/object/player.h index 91e14b511..0fe60fad3 100644 --- a/src/object/player.h +++ b/src/object/player.h @@ -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; diff --git a/src/player_status.cpp b/src/player_status.cpp index ba8b633c7..de5b7dfe5 100644 --- a/src/player_status.cpp +++ b/src/player_status.cpp @@ -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; diff --git a/src/player_status.h b/src/player_status.h index 760ae9212..1e2dd834a 100644 --- a/src/player_status.h +++ b/src/player_status.h @@ -23,6 +23,10 @@ #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; }; diff --git a/src/sector.cpp b/src/sector.cpp index 53edbf4ab..00a853876 100644 --- a/src/sector.cpp +++ b/src/sector.cpp @@ -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)); diff --git a/src/title.cpp b/src/title.cpp index 791cbfbd7..93ec351fb 100644 --- a/src/title.cpp +++ b/src/title.cpp @@ -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()); } diff --git a/src/trigger/door.cpp b/src/trigger/door.cpp index 446f2faa9..282c47670 100644 --- a/src/trigger/door.cpp +++ b/src/trigger/door.cpp @@ -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); } } diff --git a/src/worldmap.cpp b/src/worldmap.cpp index 59da5f234..58dc15288 100644 --- a/src/worldmap.cpp +++ b/src/worldmap.cpp @@ -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); diff --git a/src/worldmap.h b/src/worldmap.h index 01d0bfa26..55eddfce3 100644 --- a/src/worldmap.h +++ b/src/worldmap.h @@ -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);