From: Matthias Braun Date: Wed, 30 Mar 2005 01:52:14 +0000 (+0000) Subject: added a bell object which is a new better way to do reset points X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=626ab69641b179048b9d0fc528cd1626886fe9db;p=supertux.git added a bell object which is a new better way to do reset points SVN-Revision: 2295 --- diff --git a/TODO b/TODO index 1b291a018..83d49181d 100644 --- 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 diff --git a/data/images/supertux.strf b/data/images/supertux.strf index b23f0b8c5..608420d1d 100644 --- a/data/images/supertux.strf +++ b/data/images/supertux.strf @@ -1379,6 +1379,23 @@ (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 ;; diff --git a/data/levels/test/verticalforest.stl b/data/levels/test/verticalforest.stl index c53c858dc..c5b22fe9a 100644 --- a/data/levels/test/verticalforest.stl +++ b/data/levels/test/verticalforest.stl @@ -931,6 +931,8 @@ (reset-points ) (objects + (bell (x 609) (y 6500)) + (bell (x 543) (y 3655)) ) ) diff --git a/lib/special/moving_object.h b/lib/special/moving_object.h index 0ac684421..010387829 100644 --- a/lib/special/moving_object.h +++ b/lib/special/moving_object.h @@ -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) diff --git a/src/flip_level_transformer.cpp b/src/flip_level_transformer.cpp index db5a693a4..89f73b1d9 100644 --- a/src/flip_level_transformer.cpp +++ b/src/flip_level_transformer.cpp @@ -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); } diff --git a/src/gameloop.cpp b/src/gameloop.cpp index f6d92d95d..3b593f955 100644 --- a/src/gameloop.cpp +++ b/src/gameloop.cpp @@ -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") { diff --git a/src/gameloop.h b/src/gameloop.h index ea1df562a..73e26b0c5 100644 --- a/src/gameloop.h +++ b/src/gameloop.h @@ -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 index 000000000..eed60616a --- /dev/null +++ b/src/object/bell.cpp @@ -0,0 +1,64 @@ +#include + +#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 (&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 index 000000000..c52abeb25 --- /dev/null +++ b/src/object/bell.h @@ -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 + diff --git a/src/object/block.h b/src/object/block.h index ae11d2281..d70bc6d3c 100644 --- a/src/object/block.h +++ b/src/object/block.h @@ -1,5 +1,5 @@ -#ifndef __BOX_H__ -#define __BOX_H__ +#ifndef __BLOCK_H__ +#define __BLOCK_H__ #include "special/moving_object.h" diff --git a/src/object/particlesystem.cpp b/src/object/particlesystem.cpp index 232d2cc93..394fe1dbd 100644 --- a/src/object/particlesystem.cpp +++ b/src/object/particlesystem.cpp @@ -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 (grabbed_object); + if(object) { + object->set_pos(pos); + } else { +#ifdef DEBUG + std::cout << "Non MovingObjetc grabbed?!?\n"; +#endif + } + } if(!dying) handle_input(); diff --git a/src/object/portable.h b/src/object/portable.h index ce678d10d..878b649db 100644 --- a/src/object/portable.h +++ b/src/object/portable.h @@ -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 diff --git a/src/sector.cpp b/src/sector.cpp index 795dc78ff..53edbf4ab 100644 --- a/src/sector.cpp +++ b/src/sector.cpp @@ -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() { diff --git a/src/sector.h b/src/sector.h index 39b13bce4..464a64f9c 100644 --- a/src/sector.h +++ b/src/sector.h @@ -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(); diff --git a/src/title.cpp b/src/title.cpp index 514479d77..df500cfab 100644 --- a/src/title.cpp +++ b/src/title.cpp @@ -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: --- */