From 1486ceaaf9dd7a9d2d7e3654550b9a2768df2a56 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Fri, 7 Apr 2006 13:37:56 +0000 Subject: [PATCH] refactored some supertux mainloops SVN-Revision: 3262 --- data/credits.txt | 6 +- data/images/creatures/tux_small/tux-life.sprite | 6 + data/images/engine/editor/README | 2 + data/images/engine/editor/camera.png | Bin 0 -> 2863 bytes data/images/worldmap/common/teleporterdot.sprite | 8 + data/levels/misc/menu.stl | 7 + data/levels/test/default.nut | 4 +- data/levels/world1/extro.txt | 1 - data/levels/world1/worldmap.stwm | 3 - data/levels/world2/dfk-level3.stl | 4 +- data/levels/world2/info | 6 +- src/console.cpp | 10 +- src/console.hpp | 4 +- src/control/controller.cpp | 6 + src/control/controller.hpp | 2 + src/game_session.cpp | 281 +++++-------- src/game_session.hpp | 38 +- src/gui/menu.cpp | 22 +- src/gui/menu.hpp | 16 +- src/level_subset.cpp | 160 -------- src/lisp/lisp.hpp | 29 ++ src/main.cpp | 20 +- src/mainloop.cpp | 177 ++++++++ src/mainloop.hpp | 55 +++ src/misc.cpp | 27 +- src/misc.hpp | 9 + src/object/floating_image.cpp | 4 +- src/object/player.hpp | 3 +- src/player_status.cpp | 17 +- src/player_status.hpp | 12 +- src/resources.cpp | 19 - src/resources.hpp | 6 - src/screen.hpp | 39 ++ src/scripting/functions.cpp | 3 +- src/scripting/level.cpp | 4 +- src/scripting/level.hpp | 2 +- src/scripting/wrapper.cpp | 4 +- src/sector.cpp | 2 +- src/textscroller.cpp | 223 +++++------ src/textscroller.hpp | 28 +- src/tile_manager.cpp | 2 +- src/title.cpp | 489 +++++++++++------------ src/title.hpp | 52 ++- src/video/screen.cpp | 41 +- src/video/screen.hpp | 6 +- src/video/texture_manager.cpp | 2 +- src/world.cpp | 118 ++++++ src/{level_subset.hpp => world.hpp} | 42 +- src/worldmap.cpp | 250 ++++-------- src/worldmap.hpp | 22 +- 50 files changed, 1193 insertions(+), 1100 deletions(-) create mode 100644 data/images/creatures/tux_small/tux-life.sprite create mode 100644 data/images/engine/editor/README create mode 100644 data/images/engine/editor/camera.png create mode 100644 data/images/worldmap/common/teleporterdot.sprite delete mode 100644 src/level_subset.cpp create mode 100644 src/mainloop.cpp create mode 100644 src/mainloop.hpp create mode 100644 src/screen.hpp create mode 100644 src/world.cpp rename src/{level_subset.hpp => world.hpp} (50%) diff --git a/data/credits.txt b/data/credits.txt index 6ad9a2ca7..c3a1f5538 100644 --- a/data/credits.txt +++ b/data/credits.txt @@ -1,7 +1,8 @@ ; Credits text (supertux-text (background "oiltux.jpg") - (speed 1.5) + (music "music/credits.ogg") + (speed 30) (text (_ "!images/credits/milestone.png @@ -27,6 +28,8 @@ Ryan \"sik0fewl\" Flegel + Christoph Sommer + Bastiaan \"basti_\" Zapf Marek \"Wansti\" Moeckel @@ -41,7 +44,6 @@ Richard Smith - Christoph Sommer -Graphics diff --git a/data/images/creatures/tux_small/tux-life.sprite b/data/images/creatures/tux_small/tux-life.sprite new file mode 100644 index 000000000..be6476e28 --- /dev/null +++ b/data/images/creatures/tux_small/tux-life.sprite @@ -0,0 +1,6 @@ +(supertux-sprite + (action + (name "default") + (images "tux-life.png") + ) +) diff --git a/data/images/engine/editor/README b/data/images/engine/editor/README new file mode 100644 index 000000000..60051d103 --- /dev/null +++ b/data/images/engine/editor/README @@ -0,0 +1,2 @@ +camera.png from tango-project.org + diff --git a/data/images/engine/editor/camera.png b/data/images/engine/editor/camera.png new file mode 100644 index 0000000000000000000000000000000000000000..3350f5236a3e8b8aca195484ac677931e5db8497 GIT binary patch literal 2863 zcmV+~3()k5P)_m~QY!W$O z1dMq=@*}X>g|Uo?B0utwePK5bpddvS3J6{z!3znBWg%fAD;T8l7?7A{7CRU`9uJ<6 z?w;)xvWzs@;Tr>kL8Hf2*bWm7ig|FMWa)x=X% zQ(G;|ddnE|=ayxKw|dVQqk!K7fB(uWugvxKJ3l4J+ldh3w<9AXzu2~In`2ql;O*XR zG#Xpy=jZb&L3@o zQ|Q2O)$Gf}qdkZ%g2X7hWg^K~Mm29Opr;^*;>`4*uE1!~}QVc_)=hg;J@65CW|= zmSrJ?z_P4N)3y-e4y|?9_;DQLc^>og^PE3_o?5L&p-`Y$ERxIR$mjETo=34*yd}my z0?$AH{NX~Oa8gS7bIY>w)oL|%UDvWK%iXtcANSmI50+)6tB8~m%d*(9V+T$)hV`X&=XAcW{@mr5n}?AgQp_utR-^faeWpQc)^;y4ar7^0LyO4&Eoh6G-G@x|ZW zamO9Mdg6&EO5@|>*tU(<+BU|py1GiOR^x*YKH&1@%V@31<#O!bzn=pK4p1x>aa|Y7 zvKSibbJg3*%E}70T8(}C_OZ6M#>~tN+qZAW81v%^OifMw&Dhx3FQ0z;>5}jJtgNhH zi~&GvO|#kL?YH0N;>C+hPfycsw;353VSav|D_5>??AS51)+nV|US9su;Nv*X^xCy+ zJoL~*eEjjpG@DJrFeIPP-}d`#7s}`J|2#Q4S#CC)wA<|rd^*XQGiNw=?i|lP`z&94 z@dcBUlT@o!KL7l4=H}*@nVCUKiPriDHC@>-42hx$DJ4-9(Qdbi_vPM$o;`|rQc zH{X22^71mDe)=i*-FIJRg;Y9yzSE*gDU?#gah#QL9OL^w!^6YO&CSK_c3T0$7*khD z9R&pD zCC82(XCV+>MNv_U2d7yd!MnlbmW6HGS@{F?ZMJQ1>wI3VRylL#3>Pk3c$S z&~*-U23ZtET_ncG$2oH32!%p{D2iw_8hD;ZsZ`?e#~;UaT^1G=@O_`5p&^t~_`Z+p zx@fKWm;buPcgrzpO!ux;+BTTJeko&q{dc46-@gx~6j2meLWo-CLMeD-3=0bjeD~dV zefzIciiwE{o_XdO78e)seV&t@O__FtHtv2GKE3`&-2h)69fUS>tc+d9Vmv% z`EGE=V9YvbW74+4pfTEDj9%|kF_n^oQYziS>^P1aeFUVGT)%#u$;rt+0<~I=k3RZ{ ziHQleZ{JQBhWNhEjT<*8m&@dGIXus!(P%I?H%GBpB#I(-?b@|YMrtf40jbwP0+_^g z4La*vr<9T~Xc;nCbUO*S<#M^+M?fh>rBd1O^edOk*>l^r$>;MF3I#07!Wcud*(3-8 zn$0GM4jp3u{{4LT;fKU=j4=k^k0=%`z<|-2#f{O~%7e)W$v8&J7^O5?D+UL083ALA z^YY6tH~Rf)?3u;by}?!N-0j9IFY3V zN~taal}d$B#uyc1VzIu;sRgu7+{IvGjUPtDN%TDNIo_+#p(iVodydVJ9eg63I<6UWR zx-z{Mh@vR5Km$ulOq>AM8W}5OEYWIx)q7VytqTlA$HjGB!Z1vKK-Ibk2q9z~$HMo0 z!Z4)OYB4-KOub%bczBpbqd}!oq0wkCG&GdCOfQMl0&l+gCPIjeK&u^qj)lgkk7)I6bc2t{PIi6<#JZe&dyRUm+?H0 zD2n%j&U4^w(k>19+BTB4n0g9B6O6gWp36*XFbuPOJ;#2YhCUl z@X|{!MYe7K@4~_YVHk4m+&Omc+{xLqXS4FIyYAxb*|Qj9`hcgJ#1hqNm4Sf)(kqiF zj3~K=QqHWGz4czr8A>_UH4nq(ZWmHYecu-YaUB2arAwE7vuDqq(%!v$dFP#XICA7j zR=)f0yFBv9BeYsAj4>O!kk&d2{xro9Lhx4y@8hrkVsF=NMVes>A+k(#qrP;!@$qp! z`|LB~I1Yf-6t|sPA_#)ZTefU@W?*1oKx@tJ-Me|?jW;-Y^eC^t{(4sK-MhCda8nJ# z5YO|nU>8DUCQtiP7ws)OH3)*PcKY4r%a@s%nb9jNE1s0{AEu|LYjE>!G!G0+PEP(} ze0=o4Vukn7qRqOCao6=1uB&a09UVG zjTaUc{yU1IMccL`%d({7IHBV>k>fZ)y=NEg^)!ah$FnF6lSvO~$or*M5Kg{P};s zbm`L9K%4d3ympV)=(yqQJ*{k@G&(vua`526zja-AmocWKl*(zXbB^OwwAPN++7UwJ zT-O~e7K>YK+b#$p@zbd52x(P+$HxpL*p+1c4S*7F>% z2lOh?;O6zD+{gmGVkNFs1O^h#0|g+L)N_EFsFMJ-Z}H4Z=Ce{VWG5C1h=C{pzt*w( zUh+IunUo7({ N002ovPDHLkV1ntLg;@Xq literal 0 HcmV?d00001 diff --git a/data/images/worldmap/common/teleporterdot.sprite b/data/images/worldmap/common/teleporterdot.sprite new file mode 100644 index 000000000..bc8f2302d --- /dev/null +++ b/data/images/worldmap/common/teleporterdot.sprite @@ -0,0 +1,8 @@ +(supertux-sprite + (action + (name "default") + (x-offset 16) + (y-offset 16) + (images "teleporterdot.png") + ) +) diff --git a/data/levels/misc/menu.stl b/data/levels/misc/menu.stl index 93fff4df0..db896452a 100644 --- a/data/levels/misc/menu.stl +++ b/data/levels/misc/menu.stl @@ -9,6 +9,13 @@ (gravity 10.000000) (background (image "images/background/arctis.jpg") (speed 0.5)) + (init-script " +logo <- FloatingImage(\"images/objects/logo/logo.sprite\"); +logo.set_anchor_point(ANCHOR_TOP); +logo.set_pos(0, 30); +logo.set_visible(true); +wait(10000); +") (tilemap (layer "background") (solid #f) diff --git a/data/levels/test/default.nut b/data/levels/test/default.nut index 53a21c35d..d569d68f0 100644 --- a/data/levels/test/default.nut +++ b/data/levels/test/default.nut @@ -78,7 +78,7 @@ function intro() //end intro sequence DisplayEffect.fade_out(2); wait(3); - Level.finish(); + Level.finish(true); } function shake_bush() @@ -124,6 +124,6 @@ function intro_scene2() SUPERTUX.set_visible(true); SUPERTUX.set_velocity(300,0); wait(24); - Level.finish(); + Level.finish(true); } diff --git a/data/levels/world1/extro.txt b/data/levels/world1/extro.txt index 72dca8bdb..b0a6a683d 100644 --- a/data/levels/world1/extro.txt +++ b/data/levels/world1/extro.txt @@ -2,7 +2,6 @@ (supertux-text (background "extro.jpg") (music "music/theme.ogg") - (show-after "CREDITS") (text (_ "-Entering Nolok's Throne Room! diff --git a/data/levels/world1/worldmap.stwm b/data/levels/world1/worldmap.stwm index 3d985a7cb..9176c5f96 100644 --- a/data/levels/world1/worldmap.stwm +++ b/data/levels/world1/worldmap.stwm @@ -163,14 +163,12 @@ (special-tile (teleport-to-x 9) (teleport-to-y 15) - (map-message (_ "")) (x 16) (y 25) ) (special-tile (teleport-to-x 1) (teleport-to-y 26) - (map-message (_ "")) (invisible-tile #t) (x 29) (y 18) @@ -178,7 +176,6 @@ (special-tile (teleport-to-x 22) (teleport-to-y 4) - (map-message (_ "")) (x 1) (y 26) ) diff --git a/data/levels/world2/dfk-level3.stl b/data/levels/world2/dfk-level3.stl index 3def2df26..bc716c038 100644 --- a/data/levels/world2/dfk-level3.stl +++ b/data/levels/world2/dfk-level3.stl @@ -1086,7 +1086,7 @@ ) (spawnpoint (name "main") (x 64) (y 11040)) - (background + (gradient (top_color 0 0 0.2) (bottom_color 0 0 0.6) (speed 1.000000) @@ -1220,7 +1220,7 @@ (mode "normal") ) - (background + (gradient (top_color 0 0 0.2) (bottom_color 0 0 0.6) (speed 1.000000) diff --git a/data/levels/world2/info b/data/levels/world2/info index 807578d08..37ef529c6 100644 --- a/data/levels/world2/info +++ b/data/levels/world2/info @@ -1,6 +1,6 @@ -;SuperTux-Level-Subset -(supertux-level-subset +(supertux-world (title "Forest World") (description "World 2") (hide-from-contribs #f) - ) + (levelset #f) +) diff --git a/src/console.cpp b/src/console.cpp index 78acb1e2b..bf7b28e5a 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -30,7 +30,7 @@ namespace { int ticks; // TODO: use a clock? } -Console::Console(DrawingContext* context) : context(context) +Console::Console() { background = new Surface("images/engine/console.jpg"); } @@ -106,7 +106,7 @@ Console::hide() } void -Console::draw() +Console::draw(DrawingContext& context) { if (height == 0) return; if (!focused) { @@ -118,21 +118,21 @@ Console::draw() if (height == 0) return; } - context->draw_surface(background, Vector(SCREEN_WIDTH/2 - background->get_width()/2, height - background->get_height()), LAYER_FOREGROUND1+1); + context.draw_surface(background, Vector(SCREEN_WIDTH/2 - background->get_width()/2, height - background->get_height()), LAYER_FOREGROUND1+1); int lineNo = 0; if (focused) { lineNo++; float py = height-4-1*9; - context->draw_text(white_small_text, "> "+inputBuffer.str(), Vector(4, py), LEFT_ALLIGN, LAYER_FOREGROUND1+1); + context.draw_text(white_small_text, "> "+inputBuffer.str(), Vector(4, py), LEFT_ALLIGN, LAYER_FOREGROUND1+1); } for (std::list::iterator i = lines.begin(); i != lines.end(); i++) { lineNo++; float py = height-4-lineNo*9; if (py < -9) break; - context->draw_text(white_small_text, *i, Vector(4, py), LEFT_ALLIGN, LAYER_FOREGROUND1+1); + context.draw_text(white_small_text, *i, Vector(4, py), LEFT_ALLIGN, LAYER_FOREGROUND1+1); } } diff --git a/src/console.hpp b/src/console.hpp index b4fb85a1c..323869141 100644 --- a/src/console.hpp +++ b/src/console.hpp @@ -34,7 +34,7 @@ class Surface; class Console { public: - Console(DrawingContext* context); + Console(); ~Console(); static std::ostream input; /**< stream of keyboard input to send to the console. Do not forget to send std::endl or to flush the stream. */ @@ -42,7 +42,7 @@ class Console static void flush(ConsoleStreamBuffer* buffer); /**< act upon changes in a stream, normally called by the stream itself */ - void draw(); /**< draw the console to its */ + void draw(DrawingContext& context); /**< draw the console to its */ static void show(); /**< display the console */ static void hide(); /**< hide the console */ static bool hasFocus(); /**< true if characters should be sent to the console instead of their normal target */ diff --git a/src/control/controller.cpp b/src/control/controller.cpp index 73f93afed..db924af7d 100644 --- a/src/control/controller.cpp +++ b/src/control/controller.cpp @@ -65,6 +65,12 @@ Controller::pressed(Control control) return oldControls[control] == false && controls[control] == true; } +bool +Controller::released(Control control) +{ + return oldControls[control] == true && controls[control] == false; +} + void Controller::update() { diff --git a/src/control/controller.hpp b/src/control/controller.hpp index 50cdb17f1..f320825c8 100644 --- a/src/control/controller.hpp +++ b/src/control/controller.hpp @@ -46,6 +46,8 @@ public: bool hold(Control control); /** returns true if the control has just been pressed down this frame */ bool pressed(Control control); + /** returns true if the control has just been released down this frame */ + bool released(Control control); virtual void reset(); virtual void update(); diff --git a/src/game_session.cpp b/src/game_session.cpp index 5e77dc482..7269678d0 100644 --- a/src/game_session.cpp +++ b/src/game_session.cpp @@ -36,6 +36,8 @@ #include "game_session.hpp" #include "msg.hpp" +#include "worldmap.hpp" +#include "mainloop.hpp" #include "video/screen.hpp" #include "audio/sound_manager.hpp" #include "gui/menu.hpp" @@ -73,6 +75,8 @@ // binary fraction... static const float LOGICAL_FPS = 64.0; +using namespace WorldMapNS; + GameSession* GameSession::current_ = 0; GameSession::GameSession(const std::string& levelfile_, GameSessionMode mode, @@ -88,8 +92,6 @@ GameSession::GameSession(const std::string& levelfile_, GameSessionMode mode, game_pause = false; fps_fps = 0; - context = new DrawingContext(); - console = new Console(context); Console::registerCommandReceiver(this); restart_level(true); @@ -99,7 +101,6 @@ void GameSession::restart_level(bool fromBeginning) { game_pause = false; - exit_status = ES_NONE; end_sequence = NO_ENDSEQUENCE; main_controller->reset(); @@ -165,9 +166,7 @@ GameSession::~GameSession() delete end_sequence_controller; delete level; - delete context; Console::unregisterCommandReceiver(this); - delete console; current_ = NULL; } @@ -243,9 +242,6 @@ GameSession::levelintro() if(best_level_statistics != NULL) best_level_statistics->draw_message_info(context, _("Best Level Statistics")); - console->draw(); - context.do_drawing(); - wait_for_event(1.0, 3.0); } @@ -256,7 +252,7 @@ GameSession::on_escape_press() return; // don't let the player open the menu, when he is dying if(mode == ST_GL_TEST) { - exit_status = ES_LEVEL_ABORT; + main_loop->exit_screen(); } else if (!Menu::current()) { Menu::set_current(game_menu); game_menu->set_active_item(MNID_CONTINUE); @@ -270,7 +266,6 @@ void GameSession::process_events() { Player& tux = *currentsector->player; - main_controller->update(); // end of pause mode? if(!Menu::current() && game_pause) { @@ -290,17 +285,6 @@ GameSession::process_events() last_x_pos = tux.get_pos().x; } - main_controller->update(); - SDL_Event event; - while (SDL_PollEvent(&event)) { - /* Check for menu-events, if the menu is shown */ - if (Menu::current()) - Menu::current()->event(event); - main_controller->process_event(event); - if(event.type == SDL_QUIT) - throw graceful_shutdown(); - } - // playback a demo? if(playback_demo_stream != 0) { demo_controller->update(); @@ -431,9 +415,10 @@ GameSession::consoleCommand(std::string command) return true; } if (command == "finish") { - // finish current sector - exit_status = ES_LEVEL_FINISHED; - // don't add points to stats though... + if(WorldMap::current() != NULL) { + WorldMap::current()->finished_level(levelfile); + } + return true; } if (command == "camera") { @@ -453,7 +438,7 @@ GameSession::check_end_conditions() /* End of level? */ if(end_sequence && endsequence_timer.check()) { - exit_status = ES_LEVEL_FINISHED; + finish(true); // add time spent to statistics int tottime = 0, remtime = 0; @@ -491,57 +476,20 @@ GameSession::check_end_conditions() } } -void -GameSession::update(float elapsed_time) -{ - // handle controller - if(main_controller->pressed(Controller::PAUSE_MENU)) - on_escape_press(); - - // advance timers - if(!currentsector->player->growing_timer.started()) { - // Update Tux and the World - currentsector->update(elapsed_time); - } - - // respawning in new sector? - if(newsector != "" && newspawnpoint != "") { - Sector* sector = level->get_sector(newsector); - if(sector == 0) { - msg_warning("Sector '" << newsector << "' not found"); - } - sector->activate(newspawnpoint); - sector->play_music(LEVEL_MUSIC); - currentsector = sector; - newsector = ""; - newspawnpoint = ""; - } - - // update sounds - sound_manager->set_listener_position(currentsector->player->get_pos()); -} - void -GameSession::draw() +GameSession::draw(DrawingContext& context) { - currentsector->draw(*context); - drawstatus(*context); + currentsector->draw(context); + drawstatus(context); if(game_pause) - draw_pause(); - - if(Menu::current()) { - Menu::current()->draw(*context); - } - - console->draw(); - context->do_drawing(); + draw_pause(context); } void -GameSession::draw_pause() +GameSession::draw_pause(DrawingContext& context) { - context->draw_filled_rect( + context.draw_filled_rect( Vector(0,0), Vector(SCREEN_WIDTH, SCREEN_HEIGHT), Color(.2, .2, .2, .5), LAYER_FOREGROUND1); } @@ -560,18 +508,77 @@ GameSession::process_menu() break; case MNID_ABORTLEVEL: Menu::set_current(0); - exit_status = ES_LEVEL_ABORT; + main_loop->exit_screen(); break; } } else if(menu == options_menu) { process_options_menu(); - } else if(menu == load_game_menu ) { - process_load_game_menu(); } } } +void +GameSession::setup() +{ + Menu::set_current(NULL); + current_ = this; + + // Eat unneeded events + SDL_Event event; + while(SDL_PollEvent(&event)) + {} +} + +void +GameSession::update(float elapsed_time) +{ + process_events(); + process_menu(); + check_end_conditions(); + + // handle controller + if(main_controller->pressed(Controller::PAUSE_MENU)) + on_escape_press(); + + // respawning in new sector? + if(newsector != "" && newspawnpoint != "") { + Sector* sector = level->get_sector(newsector); + if(sector == 0) { + msg_warning("Sector '" << newsector << "' not found"); + } + sector->activate(newspawnpoint); + sector->play_music(LEVEL_MUSIC); + currentsector = sector; + newsector = ""; + newspawnpoint = ""; + } + + // Update the world state and all objects in the world + if(!game_pause) { + // Update the world + if (end_sequence == ENDSEQUENCE_RUNNING) { + currentsector->update(elapsed_time/2); + } else if(end_sequence == NO_ENDSEQUENCE) { + if(!currentsector->player->growing_timer.started()) + currentsector->update(elapsed_time); + } + } + + // update sounds + sound_manager->set_listener_position(currentsector->player->get_pos()); + + /* Handle music: */ + if (currentsector->player->invincible_timer.started() && + currentsector->player->invincible_timer.get_timeleft() + > TUX_INVINCIBLE_TIME_WARNING && !end_sequence) { + currentsector->play_music(HERRING_MUSIC); + } else if(currentsector->get_music_type() != LEVEL_MUSIC && !end_sequence) { + currentsector->play_music(LEVEL_MUSIC); + } +} + +#if 0 GameSession::ExitStatus GameSession::run() { @@ -594,6 +601,8 @@ GameSession::run() while (exit_status == ES_NONE) { // we run in a logical framerate so elapsed time is a constant + // This will make the game run determistic and not different on different + // machines static const float elapsed_time = 1.0 / LOGICAL_FPS; // old code... float elapsed_time = float(ticks - lastticks) / 1000.; if(!game_pause) @@ -624,25 +633,11 @@ GameSession::run() } fps_nextframe_ticks = ticks + (Uint32) (1000.0 / LOGICAL_FPS); -#if 0 - float diff = SDL_GetTicks() - fps_nextframe_ticks; - if (diff > 5.0) { - // sets the ticks that must have elapsed - fps_nextframe_ticks = SDL_GetTicks() + (1000.0 / LOGICAL_FPS); - } else { - // sets the ticks that must have elapsed - // in order for the next frame to start. - fps_nextframe_ticks += 1000.0 / LOGICAL_FPS; - } -#endif - process_events(); process_menu(); // Update the world state and all objects in the world - // Do that with a constante time-delta so that the game will run - // determistic and not different on different machines - if(!game_pause && !Menu::current()) + if(!game_pause) { // Update the world check_end_conditions(); @@ -651,10 +646,6 @@ GameSession::run() else if(end_sequence == NO_ENDSEQUENCE) update(elapsed_time); } - else - { - ++pause_menu_frame; - } if(!skipdraw) draw(); @@ -668,8 +659,6 @@ GameSession::run() continue; } - //frame_rate.update(); - /* Handle music: */ if (currentsector->player->invincible_timer.started() && currentsector->player->invincible_timer.get_timeleft() @@ -702,14 +691,17 @@ GameSession::run() main_controller->reset(); return exit_status; } +#endif void GameSession::finish(bool win) { - if(win) - exit_status = ES_LEVEL_FINISHED; - else - exit_status = ES_LEVEL_ABORT; + if(win) { + if(WorldMap::current()) + WorldMap::current()->finished_level(levelfile); + } + + main_loop->exit_screen(); } void @@ -738,6 +730,8 @@ GameSession::display_info_box(const std::string& text) InfoBox* box = new InfoBox(text); bool running = true; + DrawingContext context; + while(running) { main_controller->update(); @@ -757,8 +751,9 @@ GameSession::display_info_box(const std::string& text) box->scrolldown(); else if(main_controller->pressed(Controller::UP)) box->scrollup(); - box->draw(*context); - draw(); + box->draw(context); + draw(context); + context.do_drawing(); sound_manager->update(); } @@ -819,93 +814,3 @@ GameSession::drawstatus(DrawingContext& context) } } -void -GameSession::drawresultscreen() -{ - char str[80]; - - DrawingContext context; - for(Sector::GameObjects::iterator i = currentsector->gameobjects.begin(); - i != currentsector->gameobjects.end(); ++i) { - Background* background = dynamic_cast (*i); - if(background) { - background->draw(context); - } - } - - context.draw_text(blue_text, _("Result:"), Vector(SCREEN_WIDTH/2, 200), - CENTER_ALLIGN, LAYER_FOREGROUND1); - -// sprintf(str, _("SCORE: %d"), global_stats.get_points(SCORE_STAT)); -// context.draw_text(gold_text, str, Vector(SCREEN_WIDTH/2, 224), CENTER_ALLIGN, LAYER_FOREGROUND1); - - // y == 256 before removal of score - sprintf(str, _("COINS: %d"), player_status->coins); - context.draw_text(gold_text, str, Vector(SCREEN_WIDTH/2, 224), CENTER_ALLIGN, LAYER_FOREGROUND1); - - console->draw(); - context.do_drawing(); - - wait_for_event(2.0, 5.0); -} - -std::string slotinfo(int slot) -{ - std::string tmp; - std::string slotfile; - std::string title; - std::stringstream stream; - stream << slot; - slotfile = "save/slot" + stream.str() + ".stsg"; - - try { - lisp::Parser parser; - std::auto_ptr root (parser.parse(slotfile)); - - const lisp::Lisp* savegame = root->get_lisp("supertux-savegame"); - if(!savegame) - throw std::runtime_error("file is not a supertux-savegame."); - - savegame->get("title", title); - } catch(std::exception& e) { - return std::string(_("Slot")) + " " + stream.str() + " - " + - std::string(_("Free")); - } - - return std::string("Slot ") + stream.str() + " - " + title; -} - -bool process_load_game_menu() -{ - int slot = load_game_menu->check(); - - if(slot == -1) - return false; - - if(load_game_menu->get_item_by_id(slot).kind != MN_ACTION) - return false; - - std::stringstream stream; - stream << slot; - std::string slotfile = "save/slot" + stream.str() + ".stsg"; - - sound_manager->stop_music(); - fadeout(256); - DrawingContext context; - context.draw_text(white_text, "Loading...", - Vector(SCREEN_WIDTH/2, SCREEN_HEIGHT/2), - CENTER_ALLIGN, LAYER_FOREGROUND1); - context.do_drawing(); - - WorldMapNS::WorldMap worldmap; - - worldmap.set_map_filename("/levels/world1/worldmap.stwm"); - // Load the game or at least set the savegame_file variable - worldmap.loadgame(slotfile); - - worldmap.display(); - - Menu::set_current(main_menu); - - return true; -} diff --git a/src/game_session.hpp b/src/game_session.hpp index 830428df9..57edaa4fe 100644 --- a/src/game_session.hpp +++ b/src/game_session.hpp @@ -23,6 +23,7 @@ #include #include +#include "screen.hpp" #include "timer.hpp" #include "statistics.hpp" #include "math/vector.hpp" @@ -50,32 +51,28 @@ class Statistics; class DrawingContext; class CodeController; -/** The GameSession class controlls the controll flow of a World, ie. - present the menu on specifc keypresses, render and update it while - keeping the speed and framerate sane, etc. */ -class GameSession : public ConsoleCommandReceiver +/** + * The GameSession class controlls the controll flow of the Game (the part + * where you actually play a level) + */ +class GameSession : public Screen, public ConsoleCommandReceiver { public: - enum ExitStatus { ES_NONE, ES_LEVEL_FINISHED, /*ES_GAME_OVER,*/ ES_LEVEL_ABORT }; - -public: - DrawingContext* context; - GameSession(const std::string& levelfile, GameSessionMode mode, - Statistics* statistics=0); + Statistics* statistics = NULL); ~GameSession(); - /** Enter the busy loop */ - ExitStatus run(); - void record_demo(const std::string& filename); void play_demo(const std::string& filename); - void draw(); + + void draw(DrawingContext& context); void update(float frame_ratio); + void setup(); void set_current() { current_ = this; } - static GameSession* current() { return current_; } + static GameSession* current() + { return current_; } /// ends the current level void finish(bool win = true); @@ -84,6 +81,7 @@ public: void set_reset_point(const std::string& sectorname, const Vector& pos); void display_info_box(const std::string& text); + Sector* get_current_sector() { return currentsector; } @@ -108,9 +106,7 @@ private: void levelintro(); void drawstatus(DrawingContext& context); - void drawendscreen(); - void drawresultscreen(); - void draw_pause(); + void draw_pause(DrawingContext& context); void on_escape_press(); void process_menu(); @@ -150,7 +146,6 @@ private: static GameSession* current_; Statistics* best_level_statistics; - ExitStatus exit_status; std::ostream* capture_demo_stream; std::string capture_file; @@ -159,10 +154,5 @@ private: Console* console; }; -std::string slotinfo(int slot); - -/** Return true if the gameloop() was entered, false otherwise */ -bool process_load_game_menu(); - #endif /*SUPERTUX_GAMELOOP_H*/ diff --git a/src/gui/menu.cpp b/src/gui/menu.cpp index 7b2868f55..052a54d13 100644 --- a/src/gui/menu.cpp +++ b/src/gui/menu.cpp @@ -45,12 +45,6 @@ static const int FLICK_CURSOR_TIME = 500; extern SDL_Surface* screen; -Surface* checkbox; -Surface* checkbox_checked; -Surface* back; -Surface* arrow_left; -Surface* arrow_right; - std::vector Menu::last_menus; Menu* Menu::current_ = 0; Font* Menu::default_font; @@ -211,6 +205,12 @@ Menu::Menu() pos_y = SCREEN_HEIGHT/2; arrange_left = 0; active_item = -1; + + checkbox.reset(new Surface("images/engine/menu/checkbox-unchecked.png")); + checkbox_checked.reset(new Surface("images/engine/menu/checkbox-checked.png")); + back.reset(new Surface("images/engine/menu/arrow-back.png")); + arrow_left.reset(new Surface("images/engine/menu/arrow-left.png")); + arrow_right.reset(new Surface("images/engine/menu/arrow-right.png")); } void Menu::set_pos(float x, float y, float rw, float rh) @@ -600,10 +600,10 @@ Menu::draw_item(DrawingContext& context, int index) int text_pos = (text_width + 16)/2; /* Draw arrows */ - context.draw_surface(arrow_left, + context.draw_surface(arrow_left.get(), Vector(x_pos - list_pos + text_pos - 17, y_pos - 8), LAYER_GUI); - context.draw_surface(arrow_right, + context.draw_surface(arrow_right.get(), Vector(x_pos - list_pos + text_pos - 1 + list_pos_2, y_pos - 8), LAYER_GUI); @@ -630,7 +630,7 @@ Menu::draw_item(DrawingContext& context, int index) context.draw_text(text_font, pitem.text, Vector(SCREEN_WIDTH/2, y_pos - int(text_font->get_height()/2)), CENTER_ALLIGN, LAYER_GUI); - context.draw_surface(back, + context.draw_surface(back.get(), Vector(x_pos + text_width/2 + 16, y_pos - 8), LAYER_GUI); break; @@ -643,11 +643,11 @@ Menu::draw_item(DrawingContext& context, int index) CENTER_ALLIGN, LAYER_GUI); if(pitem.toggled) - context.draw_surface(checkbox_checked, + context.draw_surface(checkbox_checked.get(), Vector(x_pos + (text_width+16)/2, y_pos - 8), LAYER_GUI + 1); else - context.draw_surface(checkbox, + context.draw_surface(checkbox.get(), Vector(x_pos + (text_width+16)/2, y_pos - 8), LAYER_GUI + 1); break; diff --git a/src/gui/menu.hpp b/src/gui/menu.hpp index 302a402cb..9b6308857 100644 --- a/src/gui/menu.hpp +++ b/src/gui/menu.hpp @@ -20,6 +20,7 @@ #define SUPERTUX_MENU_H #include +#include #include #include #include @@ -89,12 +90,13 @@ private: static std::vector last_menus; static Menu* current_; - static void push_current(Menu* pmenu); static void pop_current(); public: /** Set the current menu, if pmenu is NULL, hide the current menu */ static void set_current(Menu* pmenu); + + static void push_current(Menu* pmenu); /** Return the current active menu or NULL if none is active */ static Menu* current() @@ -193,12 +195,12 @@ private: Uint32 effect_ticks; int arrange_left; int active_item; -}; -extern Surface* checkbox; -extern Surface* checkbox_checked; -extern Surface* back; -extern Surface* arrow_left; -extern Surface* arrow_right; + std::auto_ptr checkbox; + std::auto_ptr checkbox_checked; + std::auto_ptr back; + std::auto_ptr arrow_left; + std::auto_ptr arrow_right; +}; #endif diff --git a/src/level_subset.cpp b/src/level_subset.cpp deleted file mode 100644 index e7c4ac7a9..000000000 --- a/src/level_subset.cpp +++ /dev/null @@ -1,160 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2004 SuperTux Development Team, see AUTHORS for details -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. -#include - -#include -#include -#include -#include -#include -#include "level.hpp" -#include "msg.hpp" -#include "resources.hpp" -#include "file_system.hpp" -#include "video/surface.hpp" -#include "level_subset.hpp" -#include "lisp/parser.hpp" -#include "lisp/lisp.hpp" -#include "lisp/writer.hpp" - -static bool has_suffix(const std::string& data, const std::string& suffix) -{ - if (data.length() >= suffix.length()) - return data.compare(data.length() - suffix.length(), suffix.length(), suffix) == 0; - else - return false; -} - -LevelSubset::LevelSubset() - : levels(0) -{ -} - -LevelSubset::~LevelSubset() -{ -} - -void LevelSubset::create(const std::string& subset_name) -{ - Level new_lev; - LevelSubset new_subset; - new_subset.name = subset_name; - new_subset.title = "Unknown Title"; - new_subset.description = "No description so far."; - new_subset.hide_from_contribs = false; - new_subset.save(); -} - -void LevelSubset::read_info_file(const std::string& info_file) -{ - lisp::Parser parser; - std::auto_ptr root (parser.parse(info_file)); - - const lisp::Lisp* info = root->get_lisp("supertux-level-subset"); - if(!info) - throw std::runtime_error("File is not a levelsubset file"); - - hide_from_contribs = false; - - info->get("title", title); - info->get("description", description); - info->get_vector("levels", levels); - info->get("hide-from-contribs", hide_from_contribs); -} - -void LevelSubset::load(const std::string& subset) -{ - name = subset; - - std::string infofile = subset + "/info"; - try { - read_info_file(infofile); - } catch(std::exception& e) { - std::stringstream msg; - msg << "Couldn't parse info file '" << infofile << "': " << e.what(); - throw std::runtime_error(msg.str()); - } - - // test is a worldmap exists - has_worldmap = false; - std::string worldmap = subset + "/worldmap.stwm"; - if(PHYSFS_exists(worldmap.c_str())) { - has_worldmap = true; - } - - if (levels.empty()) { - // Level info file doesn't define any levels, so read the - // directory to see what we can find - - std::string path = subset + "/"; - char** files = PHYSFS_enumerateFiles(path.c_str()); - if(!files) { - msg_warning("Couldn't read subset dir '" - << path << "'"); - return; - } - - for(const char* const* filename = files; *filename != 0; ++filename) { - if(has_suffix(*filename, ".stl")) { - levels.push_back(path + *filename); - } - } - PHYSFS_freeList(files); - } -} - -void -LevelSubset::save() -{ - /* Save data file: */ - std::string filename = name + "/info"; - lisp::Writer writer(filename); - - writer.start_list("supertux-level-subset"); - writer.write_string("title", title); - writer.write_string("description", description); - writer.write_bool("hide-from-contribs", hide_from_contribs); - writer.end_list("supertux-level-subset"); -} - -void -LevelSubset::add_level(const std::string& name) -{ - levels.push_back(name); -} - -std::string -LevelSubset::get_level_filename(unsigned int num) -{ - assert(num < levels.size()); - return levels[num]; -} - -std::string -LevelSubset::get_worldmap_filename() -{ - return std::string(name + "/worldmap.stwm"); -} - -int -LevelSubset::get_num_levels() const -{ - return levels.size(); -} diff --git a/src/lisp/lisp.hpp b/src/lisp/lisp.hpp index fa4bda554..fb8dd8812 100644 --- a/src/lisp/lisp.hpp +++ b/src/lisp/lisp.hpp @@ -47,6 +47,7 @@ public: { return v.cons.car; } Lisp* get_cdr() const { return v.cons.cdr; } + bool get(std::string& val) const { if(type != TYPE_STRING && type != TYPE_SYMBOL) @@ -54,6 +55,13 @@ public: val = v.string; return true; } + + std::string get_string() const + { + assert(type == TYPE_STRING); + return v.string; + } + bool get(unsigned int& val) const { if(type != TYPE_INTEGER) @@ -61,6 +69,7 @@ public: val = v.integer; return true; } + bool get(int& val) const { if(type != TYPE_INTEGER) @@ -68,6 +77,13 @@ public: val = v.integer; return true; } + + int get_int() const + { + assert(type == TYPE_INTEGER); + return v.integer; + } + bool get(float& val) const { if(type != TYPE_REAL) { @@ -80,6 +96,13 @@ public: val = v.real; return true; } + + float get_float() const + { + assert(type == TYPE_REAL); + return v.real; + } + bool get(bool& val) const { if(type != TYPE_BOOLEAN) @@ -88,6 +111,12 @@ public: return true; } + bool get_bool() const + { + assert(type == TYPE_BOOLEAN); + return v.boolean; + } + /** conveniance functions which traverse the list until a child with a * specified name is found. The value part is then interpreted in a specific * way. The functions return true, if a child was found and could be diff --git a/src/main.cpp b/src/main.cpp index 47af8c47f..bb2fd8682 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -45,6 +45,7 @@ #include "video/texture_manager.hpp" #include "control/joystickkeyboardcontroller.hpp" #include "misc.hpp" +#include "mainloop.hpp" #include "title.hpp" #include "game_session.hpp" #include "file_system.hpp" @@ -467,22 +468,29 @@ int main(int argc, char** argv) timelog("resources"); load_shared(); timelog(0); + + main_loop = new MainLoop(); if(config->start_level != "") { // we have a normal path specified at commandline not physfs paths. // So we simply mount that path here... std::string dir = FileSystem::dirname(config->start_level); PHYSFS_addToSearchPath(dir.c_str(), true); - GameSession session( + GameSession* session + = new GameSession( FileSystem::basename(config->start_level), ST_GL_LOAD_LEVEL_FILE); if(config->start_demo != "") - session.play_demo(config->start_demo); + session->play_demo(config->start_demo); if(config->record_demo != "") - session.record_demo(config->record_demo); - session.run(); + session->record_demo(config->record_demo); + main_loop->push_screen(session); } else { - // normal game - title(); + main_loop->push_screen(new TitleScreen()); } + + main_loop->run(); + + delete main_loop; + main_loop = NULL; } catch(graceful_shutdown& e) { } catch(std::exception& e) { msg_fatal("Unexpected exception: " << e.what()); diff --git a/src/mainloop.cpp b/src/mainloop.cpp new file mode 100644 index 000000000..1c98cd499 --- /dev/null +++ b/src/mainloop.cpp @@ -0,0 +1,177 @@ +// $Id: worldmap.hpp 2800 2005-10-02 22:57:31Z matzebraun $ +// +// SuperTux +// Copyright (C) 2006 Matthias Braun +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#include + +#include "mainloop.hpp" + +#include +#include +#include "video/drawing_context.hpp" +#include "control/joystickkeyboardcontroller.hpp" +#include "gui/menu.hpp" +#include "audio/sound_manager.hpp" +#include "gameconfig.hpp" +#include "main.hpp" +#include "resources.hpp" +#include "screen.hpp" +#include "timer.hpp" + +// the engine will be run with a logical framerate of 64fps. +// We chose 64fps here because it is a power of 2, so 1/64 gives an "even" +// binary fraction... +static const float LOGICAL_FPS = 64.0; + +MainLoop* main_loop = NULL; + +MainLoop::MainLoop() + : speed(1.0) +{ + console.reset(new Console()); +} + +MainLoop::~MainLoop() +{ + for(std::vector::iterator i = screen_stack.begin(); + i != screen_stack.end(); ++i) { + delete *i; + } +} + +void +MainLoop::push_screen(Screen* screen) +{ + this->next_screen.reset(screen); + nextpush = true; + speed = 1.0; +} + +void +MainLoop::exit_screen() +{ + next_screen.reset(screen_stack.back()); + nextpush = false; + screen_stack.pop_back(); + speed = 1.0; +} + +void +MainLoop::quit() +{ + running = false; +} + +void +MainLoop::set_speed(float speed) +{ + this->speed = speed; +} + +void +MainLoop::run() +{ + DrawingContext context; + + unsigned int frame_count; + float fps_fps; + Uint32 fps_ticks = SDL_GetTicks(); + Uint32 fps_nextframe_ticks = SDL_GetTicks(); + Uint32 ticks; + bool skipdraw = false; + + running = true; + while(running) { + if(next_screen.get() != NULL) { + if(nextpush) + screen_stack.push_back(current_screen.release()); + + next_screen->setup(); + current_screen.reset(next_screen.release()); + next_screen.reset(NULL); + nextpush = false; + } + + if(current_screen.get() == NULL) + break; + + float elapsed_time = 1.0 / LOGICAL_FPS; + ticks = SDL_GetTicks(); + if(ticks > fps_nextframe_ticks) { + if(skipdraw == true) { + // already skipped last frame? we have to slow down the game then... + skipdraw = false; + fps_nextframe_ticks -= (Uint32) (1000.0 / LOGICAL_FPS); + } else { + // don't draw all frames when we're getting too slow + skipdraw = true; + } + } else { + skipdraw = false; + while(fps_nextframe_ticks > ticks) { + /* just wait */ + // If we really have to wait long, then do an imprecise SDL_Delay() + Uint32 diff = fps_nextframe_ticks - ticks; + if(diff > 15) { + SDL_Delay(diff - 10); + } + ticks = SDL_GetTicks(); + } + } + fps_nextframe_ticks = ticks + (Uint32) (1000.0 / LOGICAL_FPS); + + if(!skipdraw) { + current_screen->draw(context); + if(Menu::current() != NULL) + Menu::current()->draw(context); + console->draw(context); + + context.do_drawing(); + + /* Calculate frames per second */ + if(config->show_fps) + { + ++frame_count; + + if(SDL_GetTicks() - fps_ticks >= 500) + { + fps_fps = (float) frame_count / .5; + frame_count = 0; + fps_ticks = SDL_GetTicks(); + } + } + } + + elapsed_time *= speed; + + game_time += elapsed_time; + current_screen->update(elapsed_time); + + main_controller->update(); + SDL_Event event; + while(SDL_PollEvent(&event)) { + main_controller->process_event(event); + if(Menu::current() != NULL) + Menu::current()->event(event); + if(event.type == SDL_QUIT) + quit(); + } + + sound_manager->update(); + } +} + diff --git a/src/mainloop.hpp b/src/mainloop.hpp new file mode 100644 index 000000000..20d21075f --- /dev/null +++ b/src/mainloop.hpp @@ -0,0 +1,55 @@ +// $Id: worldmap.hpp 2800 2005-10-02 22:57:31Z matzebraun $ +// +// SuperTux +// Copyright (C) 2006 Matthias Braun +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#ifndef __MAINLOOP_HPP__ +#define __MAINLOOP_HPP__ + +#include +#include + +class Screen; +class Console; + +class MainLoop +{ +public: + MainLoop(); + ~MainLoop(); + + void run(); + void exit_screen(); + void quit(); + void set_speed(float speed); + + // push new screen on screen_stack + void push_screen(Screen* screen); + +private: + bool running; + float speed; + bool nextpush; + std::auto_ptr next_screen; + std::auto_ptr current_screen; + std::auto_ptr console; + std::vector screen_stack; +}; + +extern MainLoop* main_loop; + +#endif + diff --git a/src/misc.cpp b/src/misc.cpp index b8279b585..047ab3e20 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -32,13 +32,6 @@ Menu* main_menu = 0; Menu* game_menu = 0; Menu* options_menu = 0; -Menu* options_keys_menu = 0; -Menu* options_joystick_menu = 0; -Menu* highscore_menu = 0; -Menu* load_game_menu = 0; -Menu* save_game_menu = 0; -Menu* contrib_menu = 0; -Menu* contrib_subset_menu = 0; void process_options_menu() { @@ -73,15 +66,12 @@ void setup_menu() { main_menu = new Menu(); options_menu = new Menu(); - load_game_menu = new Menu(); game_menu = new Menu(); - contrib_menu = new Menu(); - contrib_subset_menu = new Menu(); worldmap_menu = new Menu(); main_menu->set_pos(SCREEN_WIDTH/2, 335); - main_menu->add_submenu(_("Start Game"), load_game_menu, MNID_STARTGAME); - main_menu->add_submenu(_("Contrib Levels"), contrib_menu, MNID_LEVELS_CONTRIB); + main_menu->add_entry(MNID_STARTGAME, _("Start Game")); + main_menu->add_entry(MNID_LEVELS_CONTRIB, _("Contrib Levels")); main_menu->add_submenu(_("Options"), options_menu); //main_menu->add_entry(MNID_LEVELEDITOR, _("Level Editor")); main_menu->add_entry(MNID_CREDITS, _("Credits")); @@ -99,16 +89,6 @@ void setup_menu() options_menu->add_hl(); options_menu->add_back(_("Back")); - load_game_menu->add_label(_("Start Game")); - load_game_menu->add_hl(); - load_game_menu->add_deactive(1, "Slot 1"); - load_game_menu->add_deactive(2, "Slot 2"); - load_game_menu->add_deactive(3, "Slot 3"); - load_game_menu->add_deactive(4, "Slot 4"); - load_game_menu->add_deactive(5, "Slot 5"); - load_game_menu->add_hl(); - load_game_menu->add_back(_("Back")); - game_menu->add_label(_("Pause")); game_menu->add_hl(); game_menu->add_entry(MNID_CONTINUE, _("Continue")); @@ -130,8 +110,5 @@ void free_menu() delete main_menu; delete game_menu; delete options_menu; - delete contrib_menu; - delete contrib_subset_menu; - delete load_game_menu; } diff --git a/src/misc.hpp b/src/misc.hpp index 0978b1417..7b97edd17 100644 --- a/src/misc.hpp +++ b/src/misc.hpp @@ -17,6 +17,15 @@ #ifndef SUPERTUX_MISC_H #define SUPERTUX_MISC_H +enum MainMenuIDs { + MNID_STARTGAME, + MNID_LEVELS_CONTRIB, + MNID_OPTIONMENU, + MNID_LEVELEDITOR, + MNID_CREDITS, + MNID_QUITMAINMENU +}; + enum OptionsMenuIDs { MNID_FULLSCREEN, MNID_SOUND, diff --git a/src/object/floating_image.cpp b/src/object/floating_image.cpp index a1461cff4..1933b9bd7 100644 --- a/src/object/floating_image.cpp +++ b/src/object/floating_image.cpp @@ -37,10 +37,10 @@ FloatingImage::draw(DrawingContext& context) context.push_transform(); context.set_translation(Vector(0, 0)); - Vector pos = get_anchor_pos(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), + Vector spos = pos + get_anchor_pos(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), sprite->get_width(), sprite->get_height(), anchor); - sprite->draw(context, pos, layer); + sprite->draw(context, spos, layer); context.pop_transform(); } diff --git a/src/object/player.hpp b/src/object/player.hpp index add9a09d0..ffa727c99 100644 --- a/src/object/player.hpp +++ b/src/object/player.hpp @@ -161,10 +161,11 @@ public: void set_visible(bool visible); bool get_visible(); + + bool on_ground(); private: void handle_input(); - bool on_ground(); bool deactivated; void init(); diff --git a/src/player_status.cpp b/src/player_status.cpp index f5c721f64..25eb28ecc 100644 --- a/src/player_status.cpp +++ b/src/player_status.cpp @@ -42,25 +42,22 @@ PlayerStatus::PlayerStatus() max_score_multiplier(1) { reset(); - key_brass = sprite_manager->create("images/objects/keys/key_brass.sprite"); - key_iron = sprite_manager->create("images/objects/keys/key_iron.sprite"); - key_bronze = sprite_manager->create("images/objects/keys/key_bronze.sprite"); - key_silver = sprite_manager->create("images/objects/keys/key_silver.sprite"); - key_gold = sprite_manager->create("images/objects/keys/key_gold.sprite"); + key_brass.reset(sprite_manager->create("images/objects/keys/key_brass.sprite")); + key_iron.reset(sprite_manager->create("images/objects/keys/key_iron.sprite")); + key_bronze.reset(sprite_manager->create("images/objects/keys/key_bronze.sprite")); + key_silver.reset(sprite_manager->create("images/objects/keys/key_silver.sprite")); + key_gold.reset(sprite_manager->create("images/objects/keys/key_gold.sprite")); key_brass->set_action("outline"); key_iron->set_action("outline"); key_bronze->set_action("outline"); key_silver->set_action("outline"); key_gold->set_action("outline"); + + tux_life.reset(sprite_manager->create("images/creatures/tux_small/tux-life.sprite")); } PlayerStatus::~PlayerStatus() { - delete key_brass; - delete key_iron; - delete key_bronze; - delete key_silver; - delete key_gold; } void PlayerStatus::reset() diff --git a/src/player_status.hpp b/src/player_status.hpp index 29b8f83be..7b352cf77 100644 --- a/src/player_status.hpp +++ b/src/player_status.hpp @@ -20,6 +20,7 @@ #define SUPERTUX_PLAYERSTATUS_H #include +#include #include "lisp/lisp.hpp" #include "timer.hpp" #include "serializable.hpp" @@ -74,11 +75,12 @@ private: PlayerStatus(const PlayerStatus& other); int keys; - Sprite* key_iron; - Sprite* key_brass; - Sprite* key_bronze; - Sprite* key_silver; - Sprite* key_gold; + std::auto_ptr tux_life; + std::auto_ptr key_iron; + std::auto_ptr key_brass; + std::auto_ptr key_bronze; + std::auto_ptr key_silver; + std::auto_ptr key_gold; }; // global player state diff --git a/src/resources.cpp b/src/resources.cpp index 933185121..3570e002e 100644 --- a/src/resources.cpp +++ b/src/resources.cpp @@ -42,13 +42,6 @@ Font* white_big_text; /* Load graphics/sounds shared between all levels: */ void load_shared() { - /* Load GUI/menu images: */ - checkbox = new Surface("images/engine/menu/checkbox-unchecked.png"); - checkbox_checked = new Surface("images/engine/menu/checkbox-checked.png"); - back = new Surface("images/engine/menu/arrow-back.png"); - arrow_left = new Surface("images/engine/menu/arrow-left.png"); - arrow_right = new Surface("images/engine/menu/arrow-right.png"); - /* Load the mouse-cursor */ mouse_cursor = new MouseCursor("images/engine/menu/mousecursor.png"); MouseCursor::set_current(mouse_cursor); @@ -113,9 +106,6 @@ void load_shared() ice_tux->arms = sprite_manager->create("images/creatures/tux_big/big-tux-arms.sprite"); ice_tux->feet = sprite_manager->create("images/creatures/tux_big/big-tux-feet.sprite"); - /* Tux life: */ - tux_life = new Surface("images/creatures/tux_small/tux-life.png"); - player_status = new PlayerStatus(); } @@ -130,8 +120,6 @@ void unload_shared() delete white_small_text; delete white_big_text; - delete tux_life; - delete small_tux; delete big_tux; delete fire_tux; @@ -147,13 +135,6 @@ void unload_shared() delete tile_manager; tile_manager = 0; - /* Free GUI/menu images: */ - delete checkbox; - delete checkbox_checked; - delete back; - delete arrow_left; - delete arrow_right; - /* Free mouse-cursor */ delete mouse_cursor; } diff --git a/src/resources.hpp b/src/resources.hpp index 1771aa567..811ff53a0 100644 --- a/src/resources.hpp +++ b/src/resources.hpp @@ -27,18 +27,12 @@ class SoundManager; class TileManager; class MouseCursor; -extern Surface* img_super_bkgd; -extern Surface* tux_life; - extern SpriteManager* sprite_manager; extern TileManager* tile_manager; -extern Menu* contrib_menu; -extern Menu* contrib_subset_menu; extern Menu* main_menu; extern Menu* game_menu; extern Menu* options_menu; -extern Menu* load_game_menu; extern MouseCursor* mouse_cursor; diff --git a/src/screen.hpp b/src/screen.hpp new file mode 100644 index 000000000..fd3b8908f --- /dev/null +++ b/src/screen.hpp @@ -0,0 +1,39 @@ +// $Id: worldmap.hpp 2800 2005-10-02 22:57:31Z matzebraun $ +// +// SuperTux +// Copyright (C) 2006 Matthias Braun +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#ifndef __SCREEN_HPP__ +#define __SCREEN_HPP__ + +class DrawingContext; + +class Screen +{ +public: + virtual ~Screen() + {} + + virtual void setup() + {} + + virtual void draw(DrawingContext& context) = 0; + + virtual void update(float elapsed_time) = 0; +}; + +#endif + diff --git a/src/scripting/functions.cpp b/src/scripting/functions.cpp index 6bff401d7..050ec72db 100644 --- a/src/scripting/functions.cpp +++ b/src/scripting/functions.cpp @@ -9,6 +9,7 @@ #include "resources.hpp" #include "gettext.hpp" #include "msg.hpp" +#include "mainloop.hpp" namespace Scripting { @@ -27,7 +28,7 @@ void display_text_file(const std::string& filename) { std::string file = ScriptInterpreter::current()->get_working_directory() + filename; - ::display_text_file(file); + main_loop->push_screen(new TextScroller(file)); } void import(HSQUIRRELVM v, const std::string& filename) diff --git a/src/scripting/level.cpp b/src/scripting/level.cpp index a66df0adf..3c21ed036 100644 --- a/src/scripting/level.cpp +++ b/src/scripting/level.cpp @@ -15,9 +15,9 @@ namespace Scripting {} void - Level::finish() + Level::finish(bool win) { - GameSession::current()->finish(); + GameSession::current()->finish(win); } void diff --git a/src/scripting/level.hpp b/src/scripting/level.hpp index aae3faf5d..26d03f734 100644 --- a/src/scripting/level.hpp +++ b/src/scripting/level.hpp @@ -13,7 +13,7 @@ public: #endif /** Instantly finish the currently played level */ - void finish(); + void finish(bool win); /** spawn tux at specified sector and spawnpoint */ void spawn(const std::string& sector, const std::string& spawnpoint); /** Flip level vertically */ diff --git a/src/scripting/wrapper.cpp b/src/scripting/wrapper.cpp index 746110cad..944c7b617 100644 --- a/src/scripting/wrapper.cpp +++ b/src/scripting/wrapper.cpp @@ -172,8 +172,10 @@ static int Level_finish_wrapper(HSQUIRRELVM v) { Scripting::Level* _this; sq_getinstanceup(v, 1, (SQUserPointer*) &_this, 0); + SQBool arg0; + sq_getbool(v, 2, &arg0); - _this->finish(); + _this->finish(arg0); return 0; } diff --git a/src/sector.cpp b/src/sector.cpp index 3c1322f48..c6ee2419a 100644 --- a/src/sector.cpp +++ b/src/sector.cpp @@ -573,7 +573,7 @@ Sector::draw(DrawingContext& context) context.pop_transform(); } -static const float DELTA = .1; +static const float DELTA = .001; void Sector::collision_tilemap(const Rect& dest, const Vector& movement, diff --git a/src/textscroller.cpp b/src/textscroller.cpp index d1cd0ce09..c46dde376 100644 --- a/src/textscroller.cpp +++ b/src/textscroller.cpp @@ -23,10 +23,13 @@ #include #include "msg.hpp" +#include "mainloop.hpp" #include "resources.hpp" #include "video/font.hpp" #include "video/drawing_context.hpp" #include "video/surface.hpp" +#include "video/screen.hpp" +#include "gui/menu.hpp" #include "lisp/parser.hpp" #include "lisp/lisp.hpp" #include "audio/sound_manager.hpp" @@ -34,7 +37,8 @@ #include "control/joystickkeyboardcontroller.hpp" #include "exceptions.hpp" -static const float DEFAULT_SPEED = .02; +static const float DEFAULT_SPEED = 20; +static const float LEFT_BORDER = 50; static const float SCROLL = 60; static const float ITEMS_SPACE = 4; @@ -57,19 +61,13 @@ static void split_text(const std::string& text, std::vector& lines) } } -void display_text_file(const std::string& filename) +TextScroller::TextScroller(const std::string& filename) { - const Font* heading_font = white_big_text; - const Font* normal_font = white_text; - const Font* small_font = white_small_text; - const Font* reference_font = blue_text; - float defaultspeed = DEFAULT_SPEED; - float speed = defaultspeed; + defaultspeed = DEFAULT_SPEED; + speed = defaultspeed; std::string text; std::string background_file; - std::vector lines; - std::map images; lisp::Parser parser; try { @@ -83,8 +81,8 @@ void display_text_file(const std::string& filename) throw std::runtime_error("file doesn't contain a text field"); if(!text_lisp->get("background", background_file)) throw std::runtime_error("file doesn't contain a background file"); - if(text_lisp->get("speed", defaultspeed)) - defaultspeed /= 50; + text_lisp->get("speed", defaultspeed); + text_lisp->get("music", music); } catch(std::exception& e) { msg_warning("Couldn't load file '" << filename << "': " << e.what()); return; @@ -99,122 +97,115 @@ void display_text_file(const std::string& filename) continue; if(line[0] == '!') { std::string imagename = line.substr(1, line.size()-1); - msg_debug("Imagename: " << imagename); images.insert(std::make_pair(imagename, new Surface(imagename))); } } // load background image - Surface* background = new Surface("images/background/" + background_file); - - bool done = false; - float scroll = 0; - float left_border = 50; - - DrawingContext context; - SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); - - Uint32 lastticks = SDL_GetTicks(); - while(!done) { - main_controller->update(); - /* in case of input, exit */ - SDL_Event event; - while(SDL_PollEvent(&event)) { - main_controller->process_event(event); - if(event.type == SDL_QUIT) - throw graceful_shutdown(); - } + background.reset(new Surface("images/background/" + background_file)); - if(main_controller->hold(Controller::UP)) { - speed = -defaultspeed*5; - } else if(main_controller->hold(Controller::DOWN)) { - speed = defaultspeed*5; - } else { - speed = defaultspeed; - } - if(main_controller->pressed(Controller::JUMP) - || main_controller->pressed(Controller::ACTION) - || main_controller->pressed(Controller::MENU_SELECT)) - scroll += SCROLL; - if(main_controller->pressed(Controller::PAUSE_MENU)) - done = true; + scroll = 0; +} + +TextScroller::~TextScroller() +{ + for(std::map::iterator i = images.begin(); + i != images.end(); ++i) + delete i->second; +} + +void +TextScroller::setup() +{ + sound_manager->play_music(music); + Menu::set_current(NULL); +} + +void +TextScroller::update(float elapsed_time) +{ + if(main_controller->hold(Controller::UP)) { + speed = -defaultspeed*5; + } else if(main_controller->hold(Controller::DOWN)) { + speed = defaultspeed*5; + } else { + speed = defaultspeed; + } + if(main_controller->pressed(Controller::JUMP) + || main_controller->pressed(Controller::ACTION) + || main_controller->pressed(Controller::MENU_SELECT)) + scroll += SCROLL; + if(main_controller->pressed(Controller::PAUSE_MENU)) { + fadeout(500); + main_loop->exit_screen(); + } + + scroll += speed * elapsed_time; - /* draw the credits */ - context.draw_surface(background, Vector(0,0), 0); - - float y = 0; - for(size_t i = 0; i < lines.size(); i++) { - const std::string& line = lines[i]; - if(line.size() == 0) { - y += normal_font->get_height() + ITEMS_SPACE; - continue; - } + if(scroll < 0) + scroll = 0; +} + +void +TextScroller::draw(DrawingContext& context) +{ + context.draw_surface(background.get(), Vector(0,0), 0); + + float y = SCREEN_HEIGHT - scroll; + for(size_t i = 0; i < lines.size(); i++) { + const std::string& line = lines[i]; + if(line.size() == 0) { + y += white_text->get_height() + ITEMS_SPACE; + continue; + } - const Font* font = 0; - const Surface* image = 0; - bool center = true; - switch(line[0]) - { - case ' ': font = small_font; break; - case '\t': font = normal_font; break; - case '-': font = heading_font; break; - case '*': font = reference_font; break; - case '#': font = normal_font; center = false; break; - case '!': { - std::string imagename = line.substr(1, line.size()-1); - image = images[imagename]; - break; - } - default: - msg_warning("text contains an unformated line"); - font = normal_font; - center = false; - break; - } - - if(font != 0) { - if(center) { - context.draw_text(font, - line.substr(1, line.size()-1), - Vector(SCREEN_WIDTH/2, SCREEN_HEIGHT + y - scroll), - CENTER_ALLIGN, LAYER_FOREGROUND1); - } else { - context.draw_text(font, - line.substr(1, line.size()-1), - Vector(left_border, SCREEN_HEIGHT + y - scroll), - LEFT_ALLIGN, LAYER_FOREGROUND1); - } - y += font->get_height() + ITEMS_SPACE; - } - if(image != 0) { - context.draw_surface(image, - Vector( (SCREEN_WIDTH - image->get_width()) / 2, - SCREEN_HEIGHT + y - scroll), 255); - y += image->get_height() + ITEMS_SPACE; - } + const Font* font = 0; + const Surface* image = 0; + bool center = true; + switch(line[0]) + { + case ' ': font = white_small_text; break; + case '\t': font = white_text; break; + case '-': font = white_big_text; break; + case '*': font = blue_text; break; + case '#': font = white_text; center = false; break; + case '!': { + std::string imagename = line.substr(1, line.size()-1); + image = images[imagename]; + break; + } + default: + msg_warning("text contains an unformated line"); + font = white_text; + center = false; + break; } - context.do_drawing(); - sound_manager->update(); - - if(SCREEN_HEIGHT+y-scroll < 0 && 20+SCREEN_HEIGHT+y-scroll < 0) - done = 1; - - Uint32 ticks = SDL_GetTicks(); - scroll += speed * (ticks - lastticks); - lastticks = ticks; - if(scroll < 0) - scroll = 0; - - SDL_Delay(10); + if(font != 0) { + if(center) { + context.draw_text(font, + line.substr(1, line.size()-1), + Vector(SCREEN_WIDTH/2, y), + CENTER_ALLIGN, LAYER_FOREGROUND1); + } else { + context.draw_text(font, + line.substr(1, line.size()-1), + Vector(LEFT_BORDER, y), + LEFT_ALLIGN, LAYER_FOREGROUND1); + } + y += font->get_height() + ITEMS_SPACE; + } + if(image != 0) { + context.draw_surface(image, + Vector( (SCREEN_WIDTH - image->get_width()) / 2, y), 255); + y += image->get_height() + ITEMS_SPACE; + } } - for(std::map::iterator i = images.begin(); - i != images.end(); ++i) - delete i->second; - - SDL_EnableKeyRepeat(0, 0); // disables key repeating - delete background; + if(y < 0) { + fadeout(500); + main_loop->exit_screen(); + } } InfoBox::InfoBox(const std::string& text) diff --git a/src/textscroller.hpp b/src/textscroller.hpp index 5afef3549..1bdefbf93 100644 --- a/src/textscroller.hpp +++ b/src/textscroller.hpp @@ -25,9 +25,10 @@ #include #include -#include "video/surface.hpp" +#include "screen.hpp" class DrawingContext; +class Surface; /** This class is displaying a box with information text inside the game */ @@ -51,12 +52,25 @@ private: Surface* arrow_scrolldown; }; -/** Reads a text file (using LispReader, so it as to be in its formatting) - * and scroll it over the screen - * (this call blocks until all text scrolled through or the user aborted the - * textscrolling) - */ -void display_text_file(const std::string& file); +class TextScroller : public Screen +{ +public: + TextScroller(const std::string& file); + virtual ~TextScroller(); + + void setup(); + void draw(DrawingContext& context); + void update(float elapsed_time); + +private: + float defaultspeed; + float speed; + std::string music; + std::auto_ptr background; + std::vector lines; + std::map images; + float scroll; +}; #endif diff --git a/src/tile_manager.cpp b/src/tile_manager.cpp index 474b8f271..77b6d335a 100644 --- a/src/tile_manager.cpp +++ b/src/tile_manager.cpp @@ -41,7 +41,7 @@ TileManager::TileManager(const std::string& filename) #endif load_tileset(filename); #ifdef DEBUG - msg_debug("Tiles loaded in " << (SDL_GetTicks() - ticks) / 1000.0 << "seconds"); + msg_debug("Tiles loaded in " << (SDL_GetTicks() - ticks) / 1000.0 << " seconds"); #endif } diff --git a/src/title.cpp b/src/title.cpp index e5e5aa58d..f6ebca478 100644 --- a/src/title.cpp +++ b/src/title.cpp @@ -34,7 +34,9 @@ #include #include "title.hpp" +#include "mainloop.hpp" #include "video/screen.hpp" +#include "video/drawing_context.hpp" #include "video/surface.hpp" #include "audio/sound_manager.hpp" #include "gui/menu.hpp" @@ -42,7 +44,7 @@ #include "lisp/lisp.hpp" #include "lisp/parser.hpp" #include "level.hpp" -#include "level_subset.hpp" +#include "world.hpp" #include "game_session.hpp" #include "worldmap.hpp" #include "player_status.hpp" @@ -63,84 +65,62 @@ #include "msg.hpp" #include "console.hpp" -static Surface* bkg_title; -static Surface* logo; -//static Surface* img_choose_subset; - -static int frame; - -static GameSession* titlesession; -static CodeController* controller; - -static std::vector contrib_subsets; -static LevelSubset* current_contrib_subset = 0; -static int current_subset = -1; - -static Console* console; - -/* If the demo was stopped - because game started, level - editor was excuted, etc - call this when you get back - to the title code. - */ -void resume_demo() +void +TitleScreen::update_load_game_menu() { - player_status->reset(); - titlesession->get_current_sector()->activate("main"); - titlesession->set_current(); - - //frame_rate.update(); -} + load_game_menu.reset(new Menu()); -void update_load_save_game_menu(Menu* menu) -{ - msg_debug("update loadsavemenu"); - for(int i = 1; i < 6; ++i) { - MenuItem& item = menu->get_item_by_id(i); - item.kind = MN_ACTION; - item.change_text(slotinfo(i)); + load_game_menu->add_label(_("Start Game")); + load_game_menu->add_hl(); + for(int i = 1; i <= 5; ++i) { + load_game_menu->add_entry(i, get_slotinfo(i)); } + load_game_menu->add_hl(); + load_game_menu->add_back(_("Back")); } -void free_contrib_menu() +void +TitleScreen::free_contrib_menu() { - for(std::vector::iterator i = contrib_subsets.begin(); - i != contrib_subsets.end(); ++i) + for(std::vector::iterator i = contrib_worlds.begin(); + i != contrib_worlds.end(); ++i) delete *i; - contrib_subsets.clear(); - contrib_menu->clear(); - current_contrib_subset = 0; - current_subset = -1; + contrib_worlds.clear(); + current_contrib_world = 0; + current_world = -1; } -void generate_contrib_menu() +void +TitleScreen::generate_contrib_menu() { /** Generating contrib levels list by making use of Level Subset */ - std::vector level_subsets; + std::vector level_worlds; char** files = PHYSFS_enumerateFiles("levels/"); for(const char* const* filename = files; *filename != 0; ++filename) { std::string filepath = std::string("levels/") + *filename; if(PHYSFS_isDirectory(filepath.c_str())) - level_subsets.push_back(filepath); + level_worlds.push_back(filepath); } PHYSFS_freeList(files); free_contrib_menu(); + contrib_menu.reset(new Menu()); contrib_menu->add_label(_("Contrib Levels")); contrib_menu->add_hl(); int i = 0; - for (std::vector::iterator it = level_subsets.begin(); - it != level_subsets.end(); ++it) { + for (std::vector::iterator it = level_worlds.begin(); + it != level_worlds.end(); ++it) { try { - std::auto_ptr subset (new LevelSubset()); - subset->load(*it); - if(subset->hide_from_contribs) { + std::auto_ptr world (new World()); + world->load(*it + "/info"); + if(world->hide_from_contribs) { continue; } - contrib_menu->add_submenu(subset->title, contrib_subset_menu, i++); - contrib_subsets.push_back(subset.release()); + contrib_menu->add_entry(i++, world->title); + contrib_worlds.push_back(world.release()); } catch(std::exception& e) { #ifdef DEBUG msg_warning("Couldn't parse levelset info for '" @@ -153,7 +133,8 @@ void generate_contrib_menu() contrib_menu->add_back(_("Back")); } -std::string get_level_name(const std::string& filename) +std::string +TitleScreen::get_level_name(const std::string& filename) { try { lisp::Parser parser; @@ -172,87 +153,73 @@ std::string get_level_name(const std::string& filename) } } -void check_levels_contrib_menu() +void +TitleScreen::check_levels_contrib_menu() { int index = contrib_menu->check(); if (index == -1) return; - LevelSubset& subset = * (contrib_subsets[index]); - - if(subset.has_worldmap) { - WorldMapNS::WorldMap worldmap; - worldmap.set_map_filename(subset.get_worldmap_filename()); - sound_manager->stop_music(); - - // some fading - fadeout(256); - DrawingContext context; - context.draw_text(white_text, "Loading...", - Vector(SCREEN_WIDTH/2, SCREEN_HEIGHT/2), CENTER_ALLIGN, LAYER_FOREGROUND1); - context.do_drawing(); - - // TODO: slots should be available for contrib maps - worldmap.loadgame("save/" + subset.name + "-slot1.stsg"); - worldmap.display(); // run the map + World& world = * (contrib_worlds[index]); - Menu::set_current(main_menu); - resume_demo(); - } else if (current_subset != index) { - current_subset = index; - LevelSubset& subset = * (contrib_subsets[index]); + if(!world.is_levelset) { + // TODO fade out + world.run(); + } - current_contrib_subset = ⊂ + if (current_world != index) { + current_world = index; + World& world = * (contrib_worlds[index]); - contrib_subset_menu->clear(); + current_contrib_world = &world; - contrib_subset_menu->add_label(subset.title); - contrib_subset_menu->add_hl(); + contrib_world_menu.reset(new Menu()); - for (int i = 0; i < subset.get_num_levels(); ++i) + contrib_world_menu->add_label(world.title); + contrib_world_menu->add_hl(); + + for (unsigned int i = 0; i < world.get_num_levels(); ++i) { /** get level's title */ - std::string filename = subset.get_level_filename(i); + std::string filename = world.get_level_filename(i); std::string title = get_level_name(filename); - contrib_subset_menu->add_entry(i, title); + contrib_world_menu->add_entry(i, title); } - contrib_subset_menu->add_hl(); - contrib_subset_menu->add_back(_("Back")); + contrib_world_menu->add_hl(); + contrib_world_menu->add_back(_("Back")); - titlesession->get_current_sector()->activate("main"); - titlesession->set_current(); + Menu::push_current(contrib_world_menu.get()); } } -void check_contrib_subset_menu() +void +TitleScreen::check_contrib_world_menu() { - int index = contrib_subset_menu->check(); + int index = contrib_world_menu->check(); if (index != -1) { - if (contrib_subset_menu->get_item_by_id(index).kind == MN_ACTION) { + if (contrib_world_menu->get_item_by_id(index).kind == MN_ACTION) { sound_manager->stop_music(); - GameSession session( - current_contrib_subset->get_level_filename(index), ST_GL_PLAY); - session.run(); - player_status->reset(); - Menu::set_current(main_menu); - resume_demo(); + GameSession* session = + new GameSession( + current_contrib_world->get_level_filename(index), ST_GL_PLAY); + main_loop->push_screen(session); } } } -void draw_demo(float elapsed_time) +void +TitleScreen::make_tux_jump() { static Timer randomWaitTimer; static Timer jumpPushTimer; - static Timer jumpRecoverTimer; static float last_tux_x_pos = -1; static float last_tux_y_pos = -1; Sector* sector = titlesession->get_current_sector(); Player* tux = sector->player; - sector->play_music(LEVEL_MUSIC); + //sector->play_music(LEVEL_MUSIC); controller->update(); controller->press(Controller::RIGHT); @@ -262,23 +229,27 @@ void draw_demo(float elapsed_time) float dy = fabsf(last_tux_y_pos - tux->get_pos().y); // Calculate space to check for obstacles - Rect lookahead = Rect(tux->get_bbox()); - lookahead.move(Vector(lookahead.get_width()*2,0)); + Rect lookahead = tux->get_bbox(); + lookahead.move(Vector(96, 0)); // Check if we should press the jump button bool randomJump = !randomWaitTimer.started(); - bool mayJump = !jumpRecoverTimer.started(); - bool notMoving = (dx+dy < 0.1); + bool notMoving = (fabsf(dx) + fabsf(dy)) < 0.1; bool pathBlocked = !sector->is_free_space(lookahead); - if ((notMoving || pathBlocked || randomJump) && mayJump) { - float jumpDuration = float(rand() % 200 + 500) / 1000.0; + if (!controller->released(Controller::JUMP) + && (notMoving || pathBlocked || randomJump)) { + float jumpDuration; + if(pathBlocked) + jumpDuration = 0.5; + else + jumpDuration = float(rand() % 500 + 300) / 1000.0; jumpPushTimer.start(jumpDuration); - jumpRecoverTimer.start(jumpDuration+0.1); randomWaitTimer.start(float(rand() % 3000 + 3000) / 1000.0); } // Keep jump button pressed - if (jumpPushTimer.started()) controller->press(Controller::JUMP); + if (jumpPushTimer.started()) + controller->press(Controller::JUMP); // Remember last position, so we can determine if we moved last_tux_x_pos = tux->get_pos().x; @@ -289,178 +260,192 @@ void draw_demo(float elapsed_time) sector->activate("main"); sector->camera->reset(tux->get_pos()); } - - sector->update(elapsed_time); - sector->draw(*titlesession->context); } -/* --- TITLE SCREEN --- */ -void title() +TitleScreen::TitleScreen() { - //LevelEditor* leveleditor; - controller = new CodeController(); + controller.reset(new CodeController()); + titlesession.reset(new GameSession("levels/misc/menu.stl", ST_GL_DEMO_GAME)); - titlesession = new GameSession("levels/misc/menu.stl", ST_GL_DEMO_GAME); - - /* Load images: */ - bkg_title = new Surface("images/background/arctis.jpg"); - logo = new Surface("images/engine/menu/logo.png"); - //img_choose_subset = new Surface("images/status/choose-level-subset.png"); + // delete contrib_world_menu; + // contrib_world_menu = new Menu(); titlesession->get_current_sector()->activate("main"); titlesession->set_current(); Player* player = titlesession->get_current_sector()->player; - player->set_controller(controller); + player->set_controller(controller.get()); - /* --- Main title loop: --- */ - frame = 0; + Menu::set_current(main_menu); +} - Uint32 lastticks = SDL_GetTicks(); - - Menu::set_current(main_menu); - DrawingContext& context = *titlesession->context; +TitleScreen::~TitleScreen() +{ +} - console = new Console(&context); +void +TitleScreen::setup() +{ + player_status->reset(); - bool running = true; - while (running) - { - // Calculate the movement-factor - Uint32 ticks = SDL_GetTicks(); - float elapsed_time = float(ticks - lastticks) / 1000.; - game_time += elapsed_time; - lastticks = ticks; - // 40fps is minimum - if(elapsed_time > .04) - elapsed_time = .04; - - /* Lower the speed so that Tux doesn't jump too hectically throught - the demo. */ - elapsed_time /= 2; - - SDL_Event event; - main_controller->update(); - while (SDL_PollEvent(&event)) { - if (Menu::current()) { - Menu::current()->event(event); - } - main_controller->process_event(event); - if (event.type == SDL_QUIT) - throw graceful_shutdown(); - } - - /* Draw the background: */ - draw_demo(elapsed_time); + Sector* sector = titlesession->get_current_sector(); + sector->play_music(LEVEL_MUSIC); + sector->activate(sector->player->get_pos()); - if (Menu::current() == main_menu) - context.draw_surface(logo, Vector(SCREEN_WIDTH/2 - logo->get_width()/2, 30), + Menu::set_current(main_menu); +} + +void +TitleScreen::draw(DrawingContext& context) +{ + Sector* sector = titlesession->get_current_sector(); + sector->draw(context); + + /* + if (Menu::current() == main_menu) + context.draw_surface(logo, Vector(SCREEN_WIDTH/2 - logo->get_width()/2, 30), LAYER_FOREGROUND1+1); + */ - context.draw_text(white_small_text, " SuperTux " PACKAGE_VERSION "\n", - Vector(0, SCREEN_HEIGHT - 50), LEFT_ALLIGN, LAYER_FOREGROUND1); - context.draw_text(white_small_text, - _( + context.draw_text(white_small_text, " SuperTux " PACKAGE_VERSION "\n", + Vector(0, SCREEN_HEIGHT - 50), LEFT_ALLIGN, LAYER_FOREGROUND1); + context.draw_text(white_small_text, + _( "Copyright (c) 2006 SuperTux Devel Team\n" "This game comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to\n" "redistribute it under certain conditions; see the file COPYING for details.\n" - ), - Vector(0, SCREEN_HEIGHT - 50 + white_small_text->get_height() + 5), - LEFT_ALLIGN, LAYER_FOREGROUND1); - - /* Don't draw menu, if quit is true */ - Menu* menu = Menu::current(); - if(menu) - { - menu->draw(context); - menu->update(); +), + Vector(0, SCREEN_HEIGHT - 50 + white_small_text->get_height() + 5), + LEFT_ALLIGN, LAYER_FOREGROUND1); +} + +void +TitleScreen::update(float elapsed_time) +{ + main_loop->set_speed(0.6); + Sector* sector = titlesession->get_current_sector(); + sector->update(elapsed_time); + + make_tux_jump(); + + Menu* menu = Menu::current(); + if(menu) { + menu->update(); - if(menu == main_menu) - { - switch (main_menu->check()) - { - case MNID_STARTGAME: - // Start Game, ie. goto the slots menu - update_load_save_game_menu(load_game_menu); - break; - case MNID_LEVELS_CONTRIB: - // Contrib Menu - generate_contrib_menu(); - break; - case MNID_CREDITS: - sound_manager->stop_music(); - fadeout(500); - sound_manager->play_music("music/credits.ogg"); - display_text_file("credits.txt"); - sound_manager->stop_music(); - fadeout(500); - Menu::set_current(main_menu); - break; - case MNID_QUITMAINMENU: - running = false; - break; - } - } - else if(menu == options_menu) - { - process_options_menu(); - } - else if(menu == load_game_menu) - { - if(event.key.keysym.sym == SDLK_DELETE) - { - int slot = menu->get_active_item_id(); - std::stringstream stream; - stream << slot; - std::string str = _("Are you sure you want to delete slot") + stream.str() + "?"; - - if(confirm_dialog(bkg_title, str.c_str())) { - str = "save/slot" + stream.str() + ".stsg"; - msg_debug("Removing: " << str); - PHYSFS_delete(str.c_str()); - } - - update_load_save_game_menu(load_game_menu); - Menu::set_current(main_menu); - resume_demo(); - } - else if (process_load_game_menu()) - { - resume_demo(); - } - } - else if(menu == contrib_menu) - { - check_levels_contrib_menu(); - } - else if (menu == contrib_subset_menu) - { - check_contrib_subset_menu(); - } + if(menu == main_menu) { + switch (main_menu->check()) { + case MNID_STARTGAME: + // Start Game, ie. goto the slots menu + update_load_game_menu(); + Menu::push_current(load_game_menu.get()); + break; + case MNID_LEVELS_CONTRIB: + // Contrib Menu + generate_contrib_menu(); + Menu::push_current(contrib_menu.get()); + break; + case MNID_CREDITS: + fadeout(500); + main_loop->push_screen(new TextScroller("credits.txt")); + break; + case MNID_QUITMAINMENU: + main_loop->quit(); + break; + } + } else if(menu == options_menu) { + process_options_menu(); + } else if(menu == load_game_menu.get()) { + /* + if(event.key.keysym.sym == SDLK_DELETE) { + int slot = menu->get_active_item_id(); + std::stringstream stream; + stream << slot; + std::string str = _("Are you sure you want to delete slot") + stream.str() + "?"; + + if(confirm_dialog(bkg_title, str.c_str())) { + str = "save/slot" + stream.str() + ".stsg"; + msg_debug("Removing: " << str); + PHYSFS_delete(str.c_str()); } - // reopen menu of user closed it (so that the app doesn't close when user - // accidently hit ESC) - if(Menu::current() == 0) { + update_load_save_game_menu(load_game_menu); Menu::set_current(main_menu); - } + }*/ + process_load_game_menu(); + } else if(menu == contrib_menu.get()) { + check_levels_contrib_menu(); + } else if (menu == contrib_world_menu.get()) { + check_contrib_world_menu(); + } + } + + // reopen menu of user closed it (so that the app doesn't close when user + // accidently hit ESC) + if(Menu::current() == 0) { + Menu::set_current(main_menu); + } +} + +std::string +TitleScreen::get_slotinfo(int slot) +{ + std::string tmp; + std::string slotfile; + std::string title; + std::stringstream stream; + stream << slot; + slotfile = "save/slot" + stream.str() + ".stsg"; - console->draw(); + try { + lisp::Parser parser; + std::auto_ptr root (parser.parse(slotfile)); - context.do_drawing(); - sound_manager->update(); + const lisp::Lisp* savegame = root->get_lisp("supertux-savegame"); + if(!savegame) + throw std::runtime_error("file is not a supertux-savegame."); - //frame_rate.update(); + savegame->get("title", title); + } catch(std::exception& e) { + return std::string(_("Slot")) + " " + stream.str() + " - " + + std::string(_("Free")); + } - /* Pause: */ - frame++; - } - /* Free surfaces: */ + return std::string("Slot ") + stream.str() + " - " + title; +} - free_contrib_menu(); - delete titlesession; - delete bkg_title; - delete logo; - delete console; - //delete img_choose_subset; +bool +TitleScreen::process_load_game_menu() +{ + int slot = load_game_menu->check(); + + if(slot == -1) + return false; + + if(load_game_menu->get_item_by_id(slot).kind != MN_ACTION) + return false; + + std::stringstream stream; + stream << slot; + std::string slotfile = "save/slot" + stream.str() + ".stsg"; + + sound_manager->stop_music(); + fadeout(256); + DrawingContext context; + context.draw_text(white_text, "Loading...", + Vector(SCREEN_WIDTH/2, SCREEN_HEIGHT/2), + CENTER_ALLIGN, LAYER_FOREGROUND1); + context.do_drawing(); + + WorldMapNS::WorldMap* worldmap = new WorldMapNS::WorldMap(); + + worldmap->set_map_filename("/levels/world1/worldmap.stwm"); + // Load the game or at least set the savegame_file variable + worldmap->loadgame(slotfile); + + main_loop->push_screen(worldmap); + + //Menu::set_current(main_menu); + + return true; } + diff --git a/src/title.hpp b/src/title.hpp index ce841b144..aa264736b 100644 --- a/src/title.hpp +++ b/src/title.hpp @@ -21,16 +21,48 @@ #ifndef SUPERTUX_TITLE_H #define SUPERTUX_TITLE_H -enum MainMenuIDs { - MNID_STARTGAME, - MNID_LEVELS_CONTRIB, - MNID_OPTIONMENU, - MNID_LEVELEDITOR, - MNID_CREDITS, - MNID_QUITMAINMENU - }; +#include +#include +#include "screen.hpp" +#include "game_session.hpp" + +class Menu; +class World; +class CodeController; + +class TitleScreen : public Screen +{ +public: + TitleScreen(); + virtual ~TitleScreen(); + + virtual void setup(); + + virtual void draw(DrawingContext& context); + + virtual void update(float elapsed_time); + +private: + std::string get_slotinfo(int slot); + std::string get_level_name(const std::string& levelfile); + bool process_load_game_menu(); + void make_tux_jump(); + void update_load_game_menu(); + void generate_contrib_menu(); + void check_levels_contrib_menu(); + void check_contrib_world_menu(); + void free_contrib_menu(); + + std::auto_ptr load_game_menu; + std::auto_ptr contrib_menu; + std::auto_ptr contrib_world_menu; + std::vector contrib_worlds; + int current_world; + World* current_contrib_world; -void title(); + std::auto_ptr controller; + std::auto_ptr titlesession; +}; -#endif //SUPERTUX_TITLE_H +#endif diff --git a/src/video/screen.cpp b/src/video/screen.cpp index 2227ccfe0..da579f0b1 100644 --- a/src/video/screen.cpp +++ b/src/video/screen.cpp @@ -38,7 +38,7 @@ static const float LOOP_DELAY = 20.0; -void fillrect(float x, float y, float w, float h, int r, int g, int b, int a) +void fillrect(float x, float y, float w, float h, const Color& col) { if(w < 0) { x += w; @@ -49,7 +49,7 @@ void fillrect(float x, float y, float w, float h, int r, int g, int b, int a) h = -h; } - glColor4ub(r, g, b,a); + glColor4f(col.red, col.green, col.blue, col.alpha); glDisable(GL_TEXTURE_2D); glBegin(GL_POLYGON); @@ -59,34 +59,40 @@ void fillrect(float x, float y, float w, float h, int r, int g, int b, int a) glVertex2f(x, y+h); glEnd(); glEnable(GL_TEXTURE_2D); + + glColor4f(0, 0, 0, 1); } -void fadeout(int fade_time) +void fadeout(float fade_time) { - float alpha_inc = 256 / (fade_time / LOOP_DELAY); - float alpha = 256; + float alpha_inc = LOOP_DELAY / fade_time; + Color c(0, 0, 0, alpha_inc); + float alpha = 1.0; - while(alpha > 0) { + while(alpha >= 0) { alpha -= alpha_inc; - fillrect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0,0,0, (int)alpha_inc); // left side + fillrect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, c); + // left side SDL_GL_SwapBuffers(); sound_manager->update(); SDL_Delay(int(LOOP_DELAY)); + alpha -= alpha_inc; } - fillrect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, 0, 255); + fillrect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, Color()); } -void shrink_fade(const Vector& point, int fade_time) +void shrink_fade(const Vector& point, float fade_time) { - float left_inc = point.x / ((float)fade_time / LOOP_DELAY); - float right_inc = (SCREEN_WIDTH - point.x) / ((float)fade_time / LOOP_DELAY); - float up_inc = point.y / ((float)fade_time / LOOP_DELAY); - float down_inc = (SCREEN_HEIGHT - point.y) / ((float)fade_time / LOOP_DELAY); + float left_inc = point.x / (fade_time / LOOP_DELAY); + float right_inc = (SCREEN_WIDTH - point.x) / (fade_time / LOOP_DELAY); + float up_inc = point.y / (fade_time / LOOP_DELAY); + float down_inc = (SCREEN_HEIGHT - point.y) / (fade_time / LOOP_DELAY); float left_cor = 0, right_cor = 0, up_cor = 0, down_cor = 0; + Color c; while(left_cor < point.x && right_cor < SCREEN_WIDTH - point.x && up_cor < point.y && down_cor < SCREEN_HEIGHT - point.y) { @@ -95,10 +101,10 @@ void shrink_fade(const Vector& point, int fade_time) up_cor += up_inc; down_cor += down_inc; - fillrect(0, 0, left_cor, SCREEN_HEIGHT, 0,0,0); // left side - fillrect(SCREEN_WIDTH - right_cor, 0, right_cor, SCREEN_HEIGHT, 0,0,0); // right side - fillrect(0, 0, SCREEN_WIDTH, up_cor, 0,0,0); // up side - fillrect(0, SCREEN_HEIGHT - down_cor, SCREEN_WIDTH, down_cor+1, 0,0,0); // down side + fillrect(0, 0, left_cor, SCREEN_HEIGHT, c); // left side + fillrect(SCREEN_WIDTH - right_cor, 0, right_cor, SCREEN_HEIGHT, c); // right side + fillrect(0, 0, SCREEN_WIDTH, up_cor, c); // up side + fillrect(0, SCREEN_HEIGHT - down_cor, SCREEN_WIDTH, down_cor+1, c); // down side SDL_GL_SwapBuffers(); @@ -106,3 +112,4 @@ void shrink_fade(const Vector& point, int fade_time) SDL_Delay(int(LOOP_DELAY)); } } + diff --git a/src/video/screen.hpp b/src/video/screen.hpp index a26d5e9cb..1af26357f 100644 --- a/src/video/screen.hpp +++ b/src/video/screen.hpp @@ -26,9 +26,7 @@ #include #include "math/vector.hpp" -void fillrect(float x, float y, float w, float h, int r, int g, int b, int a = 255); - -void fadeout(int fade_time); -void shrink_fade(const Vector& point, int fade_time); +void fadeout(float fade_time); +void shrink_fade(const Vector& point, float fade_time); #endif diff --git a/src/video/texture_manager.cpp b/src/video/texture_manager.cpp index 56ec74b87..38ad4110e 100644 --- a/src/video/texture_manager.cpp +++ b/src/video/texture_manager.cpp @@ -54,7 +54,7 @@ TextureManager::get(const std::string& _filename) void TextureManager::release(ImageTexture* texture) { - image_textures[texture->filename] = NULL; + image_textures.erase(texture->filename); delete texture; } diff --git a/src/world.cpp b/src/world.cpp new file mode 100644 index 000000000..a806afd99 --- /dev/null +++ b/src/world.cpp @@ -0,0 +1,118 @@ +// $Id: level_subset.cpp 3118 2006-03-25 17:29:08Z sommer $ +// +// SuperTux +// Copyright (C) 2006 Matthias Braun +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +#include + +#include +#include + +#include "world.hpp" +#include "file_system.hpp" +#include "lisp/parser.hpp" +#include "lisp/lisp.hpp" +#include "physfs/physfs_stream.hpp" +#include "scripting/script_interpreter.hpp" +#include "msg.hpp" + +static bool has_suffix(const std::string& data, const std::string& suffix) +{ + if (data.length() >= suffix.length()) + return data.compare(data.length() - suffix.length(), suffix.length(), suffix) == 0; + else + return false; +} + +World::World() +{ + is_levelset = true; + hide_from_contribs = false; +} + +World::~World() +{ +} + +void +World::load(const std::string& filename) +{ + basedir = FileSystem::dirname(filename); + + lisp::Parser parser; + std::auto_ptr root (parser.parse(filename)); + + const lisp::Lisp* info = root->get_lisp("supertux-world"); + if(info == NULL) + info = root->get_lisp("supertux-level-subset"); + if(info == NULL) + throw std::runtime_error("File is not a world or levelsubset file"); + + hide_from_contribs = false; + is_levelset = true; + + info->get("title", title); + info->get("description", description); + info->get("levelset", is_levelset); + info->get_vector("levels", levels); + info->get("hide-from-contribs", hide_from_contribs); + + // Level info file doesn't define any levels, so read the + // directory to see what we can find + + std::string path = basedir + "/"; + char** files = PHYSFS_enumerateFiles(path.c_str()); + if(!files) { + msg_warning("Couldn't read subset dir '" + << path << "'"); + return; + } + + for(const char* const* filename = files; *filename != 0; ++filename) { + if(has_suffix(*filename, ".stl")) { + levels.push_back(path + *filename); + } + } + PHYSFS_freeList(files); +} + +void +World::run() +{ + try { + std::string filename = basedir + "/world.nut"; + std::auto_ptr interpeter (new ScriptInterpreter(basedir)); + IFileStream in(filename); + + interpeter->run_script(in, filename, true); + } catch(std::exception& e) { + msg_warning("Problem running world script: " << e.what()); + } +} + +const std::string& +World::get_level_filename(unsigned int i) const +{ + return levels[i]; +} + +unsigned int +World::get_num_levels() const +{ + return levels.size(); +} + diff --git a/src/level_subset.hpp b/src/world.hpp similarity index 50% rename from src/level_subset.hpp rename to src/world.hpp index 40f4b754d..12e775951 100644 --- a/src/level_subset.hpp +++ b/src/world.hpp @@ -1,7 +1,7 @@ -// $Id$ +// $Id: worldmap.hpp 2800 2005-10-02 22:57:31Z matzebraun $ // // SuperTux -// Copyright (C) 2004 SuperTux Development Team, see AUTHORS for details +// Copyright (C) 2004 Ingo Ruhnke // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -15,49 +15,37 @@ // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. -#ifndef SUPERTUX_LEVEL_SUBSET_H -#define SUPERTUX_LEVEL_SUBSET_H +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#ifndef SUPERTUX_WORLD_H +#define SUPERTUX_WORLD_H #include #include -/** This type holds meta-information about a level-subset. - It could be extended to handle manipulation of subsets. */ -class LevelSubset +class World { private: - /** Level filenames without the leading path ("level1.stl", - "level3.stl", ...) */ std::vector levels; + std::string basedir; public: - LevelSubset(); - ~LevelSubset(); + World(); + ~World(); - static void create(const std::string& subset_name); void load(const std::string& filename); - void save(); + + const std::string& get_level_filename(unsigned int i) const; + unsigned int get_num_levels() const; - void add_level(const std::string& name); + const std::string& get_basedir() const; - std::string get_level_filename(unsigned int i); - std::string get_worldmap_filename(); - int get_num_levels() const; + void run(); - std::string name; std::string title; std::string description; bool hide_from_contribs; - bool has_worldmap; - -private: - void read_info_file(const std::string& info_file); + bool is_levelset; }; #endif -/* Local Variables: */ -/* mode:c++ */ -/* End: */ diff --git a/src/worldmap.cpp b/src/worldmap.cpp index e7dfc8c2d..26fb7be62 100644 --- a/src/worldmap.cpp +++ b/src/worldmap.cpp @@ -30,6 +30,7 @@ #include "gettext.hpp" #include "msg.hpp" +#include "mainloop.hpp" #include "video/surface.hpp" #include "video/screen.hpp" #include "video/drawing_context.hpp" @@ -64,6 +65,8 @@ static const float map_message_TIME = 2.8; namespace WorldMapNS { +WorldMap* WorldMap::current_ = NULL; + Direction reverse_dir(Direction direction) { switch(direction) @@ -678,6 +681,50 @@ WorldMap::path_ok(Direction direction, Vector old_pos, Vector* new_pos) } void +WorldMap::finished_level(const std::string& filename) +{ + // TODO calculate level from filename? + (void) filename; + Level* level = at_level(); + + bool old_level_state = level->solved; + level->solved = true; + level->sprite->set_action("solved"); + + // deal with statistics + level->statistics.merge(global_stats); + calculate_total_stats(); + + if(savegame_file != "") + savegame(savegame_file); + + if (old_level_state != level->solved && level->auto_path) { + // Try to detect the next direction to which we should walk + // FIXME: Mostly a hack + Direction dir = D_NONE; + + const Tile* tile = at(tux->get_tile_pos()); + + if (tile->getData() & Tile::WORLDMAP_NORTH + && tux->back_direction != D_NORTH) + dir = D_NORTH; + else if (tile->getData() & Tile::WORLDMAP_SOUTH + && tux->back_direction != D_SOUTH) + dir = D_SOUTH; + else if (tile->getData() & Tile::WORLDMAP_EAST + && tux->back_direction != D_EAST) + dir = D_EAST; + else if (tile->getData() & Tile::WORLDMAP_WEST + && tux->back_direction != D_WEST) + dir = D_WEST; + + if (dir != D_NONE) { + tux->set_direction(dir); + } + } +} + +void WorldMap::update(float delta) { Menu* menu = Menu::current(); @@ -691,7 +738,7 @@ WorldMap::update(float delta) Menu::set_current(0); break; case MNID_QUITWORLDMAP: // Quit Worldmap - quit = true; + main_loop->exit_screen(); break; } } else if(menu == options_menu) { @@ -707,6 +754,7 @@ WorldMap::update(float delta) GameObject* object = *i; object->update(delta); } + // remove old GameObjects for(GameObjects::iterator i = game_objects.begin(); i != game_objects.end(); ) { @@ -718,7 +766,23 @@ WorldMap::update(float delta) ++i; } } - + + // position "camera" + Vector tux_pos = tux->get_pos(); + camera_offset.x = tux_pos.x - SCREEN_WIDTH/2; + camera_offset.y = tux_pos.y - SCREEN_HEIGHT/2; + + if (camera_offset.x < 0) + camera_offset.x = 0; + if (camera_offset.y < 0) + camera_offset.y = 0; + + if (camera_offset.x > solids->get_width()*32 - SCREEN_WIDTH) + camera_offset.x = solids->get_width()*32 - SCREEN_WIDTH; + if (camera_offset.y > solids->get_height()*32 - SCREEN_HEIGHT) + camera_offset.y = solids->get_height()*32 - SCREEN_HEIGHT; + + // handle input bool enter_level = false; if(main_controller->pressed(Controller::ACTION) || main_controller->pressed(Controller::JUMP) @@ -746,117 +810,22 @@ WorldMap::update(float delta) /* Check level action */ bool level_finished = true; Level* level = at_level(); - if (!level) - { + if (!level) { msg_warning("No level to enter at: " - << tux->get_tile_pos().x << ", " << tux->get_tile_pos().y); + << tux->get_tile_pos().x << ", " << tux->get_tile_pos().y); return; - } - + } if (level->pos == tux->get_tile_pos()) { - sound_manager->stop_music(); - PlayerStatus old_player_status; - old_player_status = *player_status; - // do a shriking fade to the level shrink_fade(Vector((level->pos.x*32 + 16 + offset.x), (level->pos.y*32 + 16 + offset.y)), 500); - GameSession session(levels_path + level->name, - ST_GL_LOAD_LEVEL_FILE, &level->statistics); - - switch (session.run()) - { - case GameSession::ES_LEVEL_FINISHED: - { - level_finished = true; - bool old_level_state = level->solved; - level->solved = true; - level->sprite->set_action("solved"); - - // deal with statistics - level->statistics.merge(global_stats); - calculate_total_stats(); - - if (old_level_state != level->solved && level->auto_path) - { // Try to detect the next direction to which we should walk - // FIXME: Mostly a hack - Direction dir = D_NONE; - - const Tile* tile = at(tux->get_tile_pos()); - - if (tile->getData() & Tile::WORLDMAP_NORTH - && tux->back_direction != D_NORTH) - dir = D_NORTH; - else if (tile->getData() & Tile::WORLDMAP_SOUTH - && tux->back_direction != D_SOUTH) - dir = D_SOUTH; - else if (tile->getData() & Tile::WORLDMAP_EAST - && tux->back_direction != D_EAST) - dir = D_EAST; - else if (tile->getData() & Tile::WORLDMAP_WEST - && tux->back_direction != D_WEST) - dir = D_WEST; - - if (dir != D_NONE) - { - tux->set_direction(dir); - } - } - } - - break; - case GameSession::ES_LEVEL_ABORT: - level_finished = false; - /* In case the player's abort the level, keep it using the old - status. But the minimum lives and no bonus. */ - player_status->coins = std::min(old_player_status.coins, player_status->coins); - player_status->bonus = NO_BONUS; - break; - /* - case GameSession::ES_GAME_OVER: - { - level_finished = false; - // draw an end screen - // TODO: in the future, this should make a dialog a la SuperMario, asking - // if the player wants to restart the world map with no score and from - // level 1 - char str[80]; - - DrawingContext context; - context.draw_gradient(Color (200,240,220), Color(200,200,220), - LAYER_BACKGROUND0); - - context.draw_text(blue_text, _("GAMEOVER"), - Vector(SCREEN_WIDTH/2, 200), CENTER_ALLIGN, LAYER_FOREGROUND1); - - sprintf(str, _("COINS: %d"), player_status->coins); - context.draw_text(gold_text, str, - Vector(SCREEN_WIDTH/2, SCREEN_WIDTH - 32), CENTER_ALLIGN, - LAYER_FOREGROUND1); - - total_stats.draw_message_info(context, _("Total Statistics")); - - context.do_drawing(); - - wait_for_event(2.0, 6.0); - quit = true; - player_status->reset(); - break; - } - */ - case GameSession::ES_NONE: - assert(false); - // Should never be reached - break; - } - - sound_manager->play_music(music); - Menu::set_current(0); - if (!savegame_file.empty()) - savegame(savegame_file); + GameSession *session = + new GameSession(levels_path + level->name, + ST_GL_LOAD_LEVEL_FILE, &level->statistics); + main_loop->push_screen(session); } /* The porpose of the next checking is that if the player lost the level (in case there is one), don't show anything */ @@ -879,7 +848,7 @@ WorldMap::update(float delta) loadmap(level->next_worldmap); } if (level->quit_worldmap) - quit = true; + main_loop->exit_screen(); } } else @@ -921,6 +890,9 @@ WorldMap::at_special_tile() void WorldMap::draw(DrawingContext& context) { + context.push_transform(); + context.set_translation(camera_offset); + for(GameObjects::iterator i = game_objects.begin(); i != game_objects.end(); ++i) { GameObject* object = *i; @@ -950,6 +922,7 @@ WorldMap::draw(DrawingContext& context) } draw_status(context); + context.pop_transform(); } void @@ -1002,73 +975,12 @@ WorldMap::draw_status(DrawingContext& context) } void -WorldMap::display() +WorldMap::setup() { - Menu::set_current(0); - - quit = false; - sound_manager->play_music(music); + Menu::set_current(NULL); - if(!intro_displayed && intro_script != "") { - try { - std::auto_ptr interpreter - (new ScriptInterpreter(levels_path)); - std::istringstream in(intro_script); - interpreter->run_script(in, "worldmap-intro-script"); - add_object(interpreter.release()); - } catch(std::exception& e) { - msg_warning("Couldn't execute worldmap-intro-script: " - << e.what()); - } - - intro_displayed = true; - } - - Uint32 lastticks = SDL_GetTicks(); - DrawingContext context; - Console* console = new Console(&context); - while(!quit) { - Uint32 ticks = SDL_GetTicks(); - float elapsed_time = float(ticks - lastticks) / 1000; - game_time += elapsed_time; - lastticks = ticks; - - // 40 fps minimum // TODO use same code as in GameSession here - if(elapsed_time > .025) - elapsed_time = .025; - - Vector tux_pos = tux->get_pos(); - offset.x = tux_pos.x - SCREEN_WIDTH/2; - offset.y = tux_pos.y - SCREEN_HEIGHT/2; - - if (offset.x < 0) - offset.x = 0; - if (offset.y < 0) - offset.y = 0; - - if (offset.x > solids->get_width()*32 - SCREEN_WIDTH) - offset.x = solids->get_width()*32 - SCREEN_WIDTH; - if (offset.y > solids->get_height()*32 - SCREEN_HEIGHT) - offset.y = solids->get_height()*32 - SCREEN_HEIGHT; - - context.push_transform(); - context.set_translation(offset); - draw(context); - context.pop_transform(); - get_input(); - update(elapsed_time); - sound_manager->update(); - - if(Menu::current()) { - Menu::current()->draw(context); - } - - console->draw(); - context.do_drawing(); - } - - delete console; + current_ = this; } void diff --git a/src/worldmap.hpp b/src/worldmap.hpp index 24db45750..0833c38e8 100644 --- a/src/worldmap.hpp +++ b/src/worldmap.hpp @@ -29,6 +29,7 @@ #include "control/controller.hpp" #include "statistics.hpp" #include "timer.hpp" +#include "screen.hpp" #include "tile_manager.hpp" #include "game_object.hpp" #include "console.hpp" @@ -104,17 +105,18 @@ public: }; /** */ -class WorldMap +class WorldMap : public Screen { private: Tux* tux; - bool quit; - Surface* leveldot_green; Surface* leveldot_red; Surface* messagedot; Sprite* teleporterdot; + static WorldMap* current_; + + Vector camera_offset; std::string name; std::string music; @@ -225,9 +227,6 @@ public: WorldMap(); ~WorldMap(); - /** Busy loop */ - void display(); - void load_map(); void get_input(); @@ -235,6 +234,11 @@ public: void add_object(GameObject* object); void clear_objects(); + static WorldMap* current() + { return current_; } + + void setup(); + /** Update Tux position */ void update(float delta); @@ -244,6 +248,12 @@ public: Vector get_next_tile(Vector pos, Direction direction); const Tile* at(Vector pos); + /** + * gets called from the GameSession when a level has been successfully + * finished + */ + void finished_level(const std::string& filename); + WorldMap::Level* at_level(); WorldMap::SpecialTile* at_special_tile(); -- 2.11.0