// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
+#include <config.h>
#include <iostream>
+#include <sstream>
+#include <stdexcept>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
+#include <cmath>
#include <SDL.h>
#include <SDL_image.h>
#include <ctype.h>
#endif
-#include "defines.h"
-#include "globals.h"
#include "title.h"
-#include "screen.h"
-#include "high_scores.h"
-#include "menu.h"
-#include "texture.h"
+#include "video/screen.h"
+#include "video/surface.h"
+#include "gui/menu.h"
#include "timer.h"
-#include "setup.h"
+#include "lisp/lisp.h"
+#include "lisp/parser.h"
#include "level.h"
-#include "gameloop.h"
+#include "level_subset.h"
+#include "game_session.h"
+#include "worldmap.h"
#include "leveleditor.h"
-#include "scene.h"
-#include "player.h"
-#include "math.h"
+#include "player_status.h"
#include "tile.h"
+#include "sector.h"
+#include "object/tilemap.h"
+#include "object/camera.h"
+#include "object/player.h"
#include "resources.h"
+#include "gettext.h"
+#include "misc.h"
+#include "textscroller.h"
+#include "file_system.h"
+#include "control/joystickkeyboardcontroller.h"
+#include "control/codecontroller.h"
+#include "main.h"
static Surface* bkg_title;
static Surface* logo;
-static Surface* img_choose_subset;
+//static Surface* img_choose_subset;
static bool walking;
static Timer random_timer;
static int frame;
-static unsigned int last_update_time;
-static unsigned int update_time;
-std::vector<LevelSubset*> contrib_subsets;
-std::string current_contrib_subset;
+static GameSession* titlesession;
+static CodeController* controller;
+
+static std::vector<LevelSubset*> contrib_subsets;
+static LevelSubset* current_contrib_subset = 0;
+
+/* 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()
+{
+ player_status.reset();
+ titlesession->get_current_sector()->activate("main");
+ titlesession->set_current();
+
+ //frame_rate.update();
+}
+
+void update_load_save_game_menu(Menu* menu)
+{
+ printf("update loadsavemenu.\n");
+ for(int i = 1; i < 6; ++i) {
+ MenuItem& item = menu->get_item_by_id(i);
+ item.kind = MN_ACTION;
+ item.change_text(slotinfo(i));
+ }
+}
void free_contrib_menu()
{
void generate_contrib_menu()
{
- string_list_type level_subsets = dsubdirs("/levels", "info");
+ /** Generating contrib levels list by making use of Level Subset */
+ std::set<std::string> level_subsets = FileSystem::dsubdirs("/levels", "info");
free_contrib_menu();
- contrib_menu->additem(MN_LABEL,"Contrib Levels",0,0);
- contrib_menu->additem(MN_HL,"",0,0);
-
- for (int i = 0; i < level_subsets.num_items; ++i)
+ contrib_menu->add_label(_("Contrib Levels"));
+ contrib_menu->add_hl();
+
+ int i = 0;
+ for (std::set<std::string>::iterator it = level_subsets.begin();
+ it != level_subsets.end(); ++it)
{
LevelSubset* subset = new LevelSubset();
- subset->load(level_subsets.item[i]);
- contrib_menu->additem(MN_GOTO, subset->title.c_str(), i,
- contrib_subset_menu, i+1);
+ subset->load(*it);
+ if(subset->hide_from_contribs) {
+ delete subset;
+ continue;
+ }
+ contrib_menu->add_submenu(subset->title, contrib_subset_menu, i);
contrib_subsets.push_back(subset);
+ ++i;
}
- contrib_menu->additem(MN_HL,"",0,0);
- contrib_menu->additem(MN_BACK,"Back",0,0);
+ contrib_menu->add_hl();
+ contrib_menu->add_back(_("Back"));
+
+ level_subsets.clear();
+}
- string_list_free(&level_subsets);
+std::string get_level_name(const std::string& filename)
+{
+ try {
+ lisp::Parser parser;
+ std::auto_ptr<lisp::Lisp> root (parser.parse(filename));
+
+ const lisp::Lisp* level = root->get_lisp("supertux-level");
+ if(!level)
+ return "";
+
+ std::string name;
+ level->get("name", name);
+ return name;
+ } catch(std::exception& e) {
+ std::cerr << "Problem getting name of '" << filename << "'.\n";
+ return "";
+ }
}
-void check_contrib_menu()
+void check_levels_contrib_menu()
{
static int current_subset = -1;
int index = contrib_menu->check();
- if (index != -1)
- {
- index -= 1;
- if (index >= 0 && index <= int(contrib_subsets.size()))
- {
- if (current_subset != index)
- {
- current_subset = index;
- // FIXME: This shouln't be busy looping
- LevelSubset& subset = * (contrib_subsets[index]);
-
- current_contrib_subset = subset.name;
+ if (index == -1)
+ return;
- std::cout << "Updating the contrib subset menu..." << subset.levels << std::endl;
-
- contrib_subset_menu->clear();
+ LevelSubset& subset = * (contrib_subsets[index]);
+
+ if(subset.has_worldmap) {
+ WorldMapNS::WorldMap worldmap;
+ worldmap.set_map_filename(subset.get_worldmap_filename());
- contrib_subset_menu->additem(MN_LABEL, subset.title, 0,0);
- contrib_subset_menu->additem(MN_HL,"",0,0);
- for (int i = 1; i <= subset.levels; ++i)
- {
- Level level;
- level.load(subset.name, i);
- contrib_subset_menu->additem(MN_ACTION, level.name, 0, 0, i);
- }
- contrib_subset_menu->additem(MN_HL,"",0,0);
- contrib_subset_menu->additem(MN_BACK, "Back", 0, 0);
- }
- }
- else
- {
- // Back button
- }
- }
-}
+ // 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();
-void check_contrib_subset_menu()
-{
- int index = contrib_subset_menu->check();
- if (index != -1)
- {
- if (contrib_subset_menu->get_item_by_id(index).kind == MN_ACTION)
- {
- std::cout << "Sarting level: " << index << std::endl;
- GameSession session(current_contrib_subset, index, ST_GL_PLAY);
- session.run();
- Menu::set_current(main_menu);
- }
- }
-}
+ // TODO: slots should be available for contrib maps
+ worldmap.loadgame(user_dir + "/save/" + subset.name + "-slot1.stsg");
+ worldmap.display(); // run the map
-void draw_background()
-{
- /* Draw the title background: */
+ Menu::set_current(main_menu);
+ resume_demo();
+ } else if (current_subset != index) {
+ current_subset = index;
+ LevelSubset& subset = * (contrib_subsets[index]);
- bkg_title->draw_bg();
-}
+ current_contrib_subset = ⊂
-void draw_demo(GameSession* session, double frame_ratio)
-{
- World::set_current(session->get_world());
- //World* world = session->get_world();
- Level* plevel = session->get_level();
- Player* tux = session->get_world()->get_tux();
+ contrib_subset_menu->clear();
- session->get_world()->play_music(LEVEL_MUSIC);
-
- /* FIXME:
- // update particle systems
- std::vector<ParticleSystem*>::iterator p;
- for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
- {
- (*p)->simulate(frame_ratio);
- }
+ contrib_subset_menu->add_label(subset.title);
+ contrib_subset_menu->add_hl();
- // Draw particle systems (background)
- for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
+ for (int i = 0; i < subset.get_num_levels(); ++i)
{
- (*p)->draw(scroll_x, 0, 0);
+ /** get level's title */
+ std::string filename = subset.get_level_filename(i);
+ std::string title = get_level_name(filename);
+ contrib_subset_menu->add_entry(i, title);
}
- */
- // Draw interactive tiles:
- for (int y = 0; y < 15; ++y)
- {
- for (int x = 0; x < 21; ++x)
- {
- Tile::draw(32*x - fmodf(scroll_x, 32), y * 32,
- plevel->ia_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
- }
- }
+ contrib_subset_menu->add_hl();
+ contrib_subset_menu->add_back(_("Back"));
- global_frame_counter++;
- tux->key_event((SDLKey) keymap.right,DOWN);
-
- if(random_timer.check())
- {
- if(walking)
- tux->key_event((SDLKey) keymap.jump,UP);
- else
- tux->key_event((SDLKey) keymap.jump,DOWN);
- }
- else
- {
- random_timer.start(rand() % 3000 + 3000);
- walking = !walking;
- }
-
- // Wrap around at the end of the level back to the beginnig
- if(plevel->width * 32 - 320 < tux->base.x)
- {
- tux->base.x = tux->base.x - (plevel->width * 32 - 640);
- scroll_x = tux->base.x - 320;
+ titlesession->get_current_sector()->activate("main");
+ titlesession->set_current();
+ }
+}
+
+void check_contrib_subset_menu()
+{
+ int index = contrib_subset_menu->check();
+ if (index != -1) {
+ if (contrib_subset_menu->get_item_by_id(index).kind == MN_ACTION) {
+ GameSession session(
+ current_contrib_subset->get_level_filename(index), ST_GL_PLAY);
+ session.run();
+ player_status.reset();
+ Menu::set_current(main_menu);
+ resume_demo();
}
+ }
+}
+
+void draw_demo(float elapsed_time)
+{
+ static float last_tux_x_pos = -1;
+ static float last_tux_y_pos = -1;
+ Sector* sector = titlesession->get_current_sector();
+ Player* tux = sector->player;
- float last_tux_x_pos = tux->base.x;
- tux->action(frame_ratio);
+ sector->play_music(LEVEL_MUSIC);
- // Jump if tux stays in the same position for one loop, ie. if he is
- // stuck behind a wall
- if (last_tux_x_pos == tux->base.x)
+ controller->update();
+ controller->press(Controller::RIGHT);
+
+ if(random_timer.check() ||
+ (walking && fabsf(last_tux_x_pos - tux->get_pos().x)) < .1) {
walking = false;
+ } else {
+ if(!walking && fabsf(tux->get_pos().y - last_tux_y_pos) < .1) {
+ random_timer.start(float(rand() % 3000 + 3000) / 1000.);
+ walking = true;
+ }
+ }
+ if(!walking)
+ controller->press(Controller::JUMP);
+ last_tux_x_pos = tux->get_pos().x;
+ last_tux_y_pos = tux->get_pos().y;
- tux->draw();
+ // Wrap around at the end of the level back to the beginnig
+ if(sector->solids->get_width() * 32 - 320 < tux->get_pos().x) {
+ sector->activate("main");
+ sector->camera->reset(tux->get_pos());
+ }
+
+ sector->update(elapsed_time);
+ sector->draw(*titlesession->context);
}
/* --- TITLE SCREEN --- */
-void title(void)
+void title()
{
- random_timer.init(true);
-
walking = true;
+ //LevelEditor* leveleditor;
+ MusicRef credits_music;
+ controller = new CodeController();
- st_pause_ticks_init();
+ titlesession = new GameSession(get_resource_filename("levels/misc/menu.stl"),
+ ST_GL_DEMO_GAME);
- GameSession session(datadir + "/levels/misc/menu.stl", 0, ST_GL_DEMO_GAME);
+ /* Load images: */
+ bkg_title = new Surface(datadir + "/images/background/arctis.jpg", false);
+ logo = new Surface(datadir + "/images/engine/menu/logo.png", true);
+ //img_choose_subset = new Surface(datadir + "/images/status/choose-level-subset.png", true);
- clearscreen(0, 0, 0);
- updatescreen();
+ titlesession->get_current_sector()->activate("main");
+ titlesession->set_current();
- /* Load images: */
- bkg_title = new Surface(datadir + "/images/title/background.jpg", IGNORE_ALPHA);
- logo = new Surface(datadir + "/images/title/logo.png", USE_ALPHA);
- img_choose_subset = new Surface(datadir + "/images/status/choose-level-subset.png", USE_ALPHA);
+ Player* player = titlesession->get_current_sector()->player;
+ player->set_controller(controller);
/* --- Main title loop: --- */
frame = 0;
- /* Draw the title background: */
- bkg_title->draw_bg();
-
- update_time = st_get_ticks();
- random_timer.start(rand() % 2000 + 2000);
+ random_timer.start(float(rand() % 2000 + 2000) / 1000.0);
+ Uint32 lastticks = SDL_GetTicks();
+
Menu::set_current(main_menu);
- while (Menu::current())
+ DrawingContext& context = *titlesession->context;
+ bool running = true;
+ while (running)
{
- // if we spent to much time on a menu entry
- if( (update_time - last_update_time) > 1000)
- update_time = last_update_time = st_get_ticks();
-
// Calculate the movement-factor
- double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
- if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
- frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
- /* Lower the frame_ratio that Tux doesn't jump to hectically throught the demo. */
- frame_ratio /= 2;
+ Uint32 ticks = SDL_GetTicks();
+ float elapsed_time = float(ticks - lastticks) / 1000.;
+ global_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;
- while (SDL_PollEvent(&event))
- {
- if (Menu::current())
- {
- Menu::current()->event(event);
- }
- // FIXME: QUIT signal should be handled more generic, not locally
- if (event.type == SDL_QUIT)
- Menu::set_current(0);
+ 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 std::runtime_error("Received window close");
+ }
+
/* Draw the background: */
- draw_background();
- draw_demo(&session, frame_ratio);
-
- if (Menu::current() == main_menu)
- logo->draw( 160, 30);
+ draw_demo(elapsed_time);
- white_small_text->draw(" SuperTux " VERSION "\n"
- "Copyright (c) 2003 SuperTux Devel Team\n"
- "This game comes with ABSOLUTELY NO WARRANTY. This is free software, and you\n"
- "are welcome to redistribute it under certain conditions; see the file COPYING\n"
- "for details.\n",
- 0, 420, 0);
+ if (Menu::current() == main_menu)
+ context.draw_surface(logo, Vector(SCREEN_WIDTH/2 - logo->w/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,
+ _(
+"Copyright (c) 2005 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();
- menu->action();
-
+ menu->draw(context);
+ menu->update();
+
if(menu == main_menu)
{
switch (main_menu->check())
// Start Game, ie. goto the slots menu
update_load_save_game_menu(load_game_menu);
break;
- case MNID_CONTRIB:
+ case MNID_LEVELS_CONTRIB:
// Contrib Menu
- puts("Entering contrib menu");
generate_contrib_menu();
break;
- case MNID_LEVELEDITOR:
- leveleditor(1);
+#if 0
+ case MNID_LEVELEDITOR: {
+ LevelEdtiro* leveleditor = new LevelEditor();
+ leveleditor->run();
+ delete leveleditor;
Menu::set_current(main_menu);
+ resume_demo();
break;
+ }
+#endif
case MNID_CREDITS:
- display_text_file("CREDITS", bkg_title, SCROLL_SPEED_CREDITS);
+ fadeout(500);
+ credits_music = sound_manager->load_music(
+ get_resource_filename("/music/credits.ogg"));
+ sound_manager->play_music(credits_music);
+ display_text_file("credits.txt");
+ fadeout(500);
Menu::set_current(main_menu);
break;
case MNID_QUITMAINMENU:
- Menu::set_current(0);
+ running = false;
break;
}
}
if(event.key.keysym.sym == SDLK_DELETE)
{
int slot = menu->get_active_item_id();
- char str[1024];
- sprintf(str,"Are you sure you want to delete slot %d?", slot);
+ std::stringstream stream;
+ stream << slot;
+ std::string str = _("Are you sure you want to delete slot") + stream.str() + "?";
- Menu::set_current(0);
- draw_background();
-
- if(confirm_dialog(str))
+ if(confirm_dialog(bkg_title, str.c_str()))
{
- sprintf(str,"%s/slot%d.stsg", st_save_dir, slot);
- printf("Removing: %s\n",str);
- remove(str);
+ str = user_dir + "/save/slot" + stream.str() + ".stsg";
+ printf("Removing: %s\n",str.c_str());
+ remove(str.c_str());
}
- update_time = st_get_ticks();
+ update_load_save_game_menu(load_game_menu);
Menu::set_current(main_menu);
+ resume_demo();
}
else if (process_load_game_menu())
{
- // FIXME: shouldn't be needed if GameSession doesn't relay on global variables
- // reset tux
- scroll_x = 0;
- //titletux.level_begin();
- update_time = st_get_ticks();
+ resume_demo();
}
}
else if(menu == contrib_menu)
{
- check_contrib_menu();
+ check_levels_contrib_menu();
}
else if (menu == contrib_subset_menu)
{
}
}
- mouse_cursor->draw();
-
- flipscreen();
+ // 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);
+ }
+
+ context.do_drawing();
- /* Set the time of the last update and the time of the current update */
- last_update_time = update_time;
- update_time = st_get_ticks();
+ //frame_rate.update();
/* Pause: */
frame++;
- SDL_Delay(25);
}
/* Free surfaces: */
free_contrib_menu();
+ delete titlesession;
delete bkg_title;
delete logo;
- delete img_choose_subset;
+ //delete img_choose_subset;
}
-
-// EOF //
-