Move some code from TitleScreen to ContribMenu
[supertux.git] / src / supertux / title_screen.cpp
1 //  SuperTux
2 //  Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
3 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
4 //
5 //  This program is free software: you can redistribute it and/or modify
6 //  it under the terms of the GNU General Public License as published by
7 //  the Free Software Foundation, either version 3 of the License, or
8 //  (at your option) any later version.
9 //
10 //  This program is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18 #include <version.h>
19
20 #include "supertux/title_screen.hpp"
21
22 #include <algorithm>
23 #include <physfs.h>
24
25 #include "addon/addon_manager.hpp"
26 #include "audio/sound_manager.hpp"
27 #include "gui/menu.hpp"
28 #include "gui/menu_manager.hpp"
29 #include "gui/menu_item.hpp"
30 #include "lisp/parser.hpp"
31 #include "object/camera.hpp"
32 #include "object/player.hpp"
33 #include "supertux/fadeout.hpp"
34 #include "supertux/gameconfig.hpp"
35 #include "supertux/globals.hpp"
36 #include "supertux/mainloop.hpp"
37 #include "supertux/menu/menu_storage.hpp"
38 #include "supertux/menu/addon_menu.hpp"
39 #include "supertux/menu/contrib_world_menu.hpp"
40 #include "supertux/menu/contrib_menu.hpp"
41 #include "supertux/menu/main_menu.hpp"
42 #include "supertux/menu/options_menu.hpp"
43 #include "supertux/resources.hpp"
44 #include "supertux/sector.hpp"
45 #include "supertux/textscroller.hpp"
46 #include "supertux/world.hpp"
47 #include "util/file_system.hpp"
48 #include "util/gettext.hpp"
49 #include "util/reader.hpp"
50 #include "video/drawing_context.hpp"
51
52 TitleScreen::TitleScreen() :
53   main_menu(),
54   contrib_menu(),
55   contrib_world_menu(),
56   main_world(),
57   contrib_worlds(),
58   addons_menu(),
59   addons(),
60   current_world(),
61   frame(),
62   controller(),
63   titlesession()
64 {
65   controller.reset(new CodeController());
66   titlesession.reset(new GameSession("levels/misc/menu.stl"));
67
68   Player* player = titlesession->get_current_sector()->player;
69   player->set_controller(controller.get());
70   player->set_speedlimit(230); //MAX_WALK_XM
71
72   generate_main_menu();
73
74   frame = std::auto_ptr<Surface>(new Surface("images/engine/menu/frame.png"));
75 }
76
77 std::string
78 TitleScreen::get_level_name(const std::string& filename)
79 {
80   try {
81     lisp::Parser parser;
82     const lisp::Lisp* root = parser.parse(filename);
83
84     const lisp::Lisp* level = root->get_lisp("supertux-level");
85     if(!level)
86       return "";
87
88     std::string name;
89     level->get("name", name);
90     return name;
91   } catch(std::exception& e) {
92     log_warning << "Problem getting name of '" << filename << "': "
93                 << e.what() << std::endl;
94     return "";
95   }
96 }
97
98 void
99 TitleScreen::check_levels_contrib_menu()
100 {
101   current_world = contrib_menu->get_current_world();
102   
103   if (current_world)
104   {
105     if (!current_world->is_levelset) 
106     {
107       start_game();
108     }
109     else 
110     {
111       contrib_world_menu.reset(new ContribWorldMenu(*current_world));
112       MenuManager::push_current(contrib_world_menu.get());
113     }
114   }
115 }
116
117 namespace {
118 bool generate_addons_menu_sorter(const Addon* a1, const Addon* a2)
119 {
120   return a1->title < a2->title;
121 }
122 }
123
124 void
125 TitleScreen::generate_addons_menu()
126 {
127   AddonManager& adm = AddonManager::get_instance();
128
129   // refresh list of addons
130   addons = adm.get_addons();
131   
132   // sort list
133   std::sort(addons.begin(), addons.end(), generate_addons_menu_sorter);
134
135   // (re)generate menu
136   addons_menu.reset(new AddonMenu(addons));
137 }
138
139 void
140 TitleScreen::check_addons_menu()
141 {
142   int index = addons_menu->check();
143   if (index == -1) return;
144
145   // check if "Check Online" was chosen
146   if (index == 0) {
147     try {
148       AddonManager::get_instance().check_online();
149       generate_addons_menu();
150       MenuManager::set_current(addons_menu.get());
151       addons_menu->set_active_item(index);
152     } 
153     catch (std::runtime_error e) {
154       log_warning << "Check for available Add-ons failed: " << e.what() << std::endl;
155     }
156     return;
157   }
158
159   // if one of the Addons listed was chosen, take appropriate action
160   if ((index >= ADDON_LIST_START_ID) && (index < ADDON_LIST_START_ID) + addons.size()) {
161     Addon& addon = *addons[index - ADDON_LIST_START_ID];
162     if (!addon.installed) {
163       try {
164         AddonManager::get_instance().install(&addon);
165       } 
166       catch (std::runtime_error e) {
167         log_warning << "Installing Add-on failed: " << e.what() << std::endl;
168       }
169       addons_menu->set_toggled(index, addon.loaded);
170     } else if (!addon.loaded) {
171       try {
172         AddonManager::get_instance().enable(&addon);
173       } 
174       catch (std::runtime_error e) {
175         log_warning << "Enabling Add-on failed: " << e.what() << std::endl;
176       }
177       addons_menu->set_toggled(index, addon.loaded);
178     } else {
179       try {
180         AddonManager::get_instance().disable(&addon);
181       } 
182       catch (std::runtime_error e) {
183         log_warning << "Disabling Add-on failed: " << e.what() << std::endl;
184       }
185       addons_menu->set_toggled(index, addon.loaded);
186     }
187   }
188 }
189
190 void
191 TitleScreen::make_tux_jump()
192 {
193   static bool jumpWasReleased = true;
194   Sector* sector  = titlesession->get_current_sector();
195   Player* tux = sector->player;
196
197   controller->update();
198   controller->press(Controller::RIGHT);
199
200   // Check if we should press the jump button
201   Rect lookahead = tux->get_bbox();
202   lookahead.p2.x += 96;
203   bool pathBlocked = !sector->is_free_of_statics(lookahead);
204   if ((pathBlocked && jumpWasReleased) || !tux->on_ground()) {
205     controller->press(Controller::JUMP);
206     jumpWasReleased = false;
207   } else {
208     jumpWasReleased = true;
209   }
210
211   // Wrap around at the end of the level back to the beginning
212   if(sector->get_width() - 320 < tux->get_pos().x) {
213     sector->activate("main");
214     sector->camera->reset(tux->get_pos());
215   }
216 }
217
218 void
219 TitleScreen::generate_main_menu()
220 {
221   main_menu.reset(new MainMenu());
222 }
223
224 TitleScreen::~TitleScreen()
225 {
226 }
227
228 void
229 TitleScreen::setup()
230 {
231   player_status->reset();
232
233   Sector* sector = titlesession->get_current_sector();
234   if(Sector::current() != sector) {
235     sector->play_music(LEVEL_MUSIC);
236     sector->activate(sector->player->get_pos());
237   }
238
239   MenuManager::set_current(main_menu.get());
240 }
241
242 void
243 TitleScreen::leave()
244 {
245   Sector* sector = titlesession->get_current_sector();
246   sector->deactivate();
247   MenuManager::set_current(NULL);
248 }
249
250 void
251 TitleScreen::draw(DrawingContext& context)
252 {
253   Sector* sector  = titlesession->get_current_sector();
254   sector->draw(context);
255
256   // FIXME: Add something to scale the frame to the resolution of the screen
257   context.draw_surface(frame.get(), Vector(0,0),LAYER_FOREGROUND1);
258
259   context.draw_text(Resources::small_font, "SuperTux " PACKAGE_VERSION "\n",
260                     Vector(5, SCREEN_HEIGHT - 50), ALIGN_LEFT, LAYER_FOREGROUND1);
261   context.draw_text(Resources::small_font,
262                     _(
263                       "Copyright (c) 2007 SuperTux Devel Team\n"
264                       "This game comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to\n"
265                       "redistribute it under certain conditions; see the file COPYING for details.\n"
266                       ),
267                     Vector(5, SCREEN_HEIGHT - 50 + Resources::small_font->get_height() + 5),
268                     ALIGN_LEFT, LAYER_FOREGROUND1);
269 }
270
271 void
272 TitleScreen::update(float elapsed_time)
273 {
274   g_main_loop->set_speed(0.6f);
275   Sector* sector  = titlesession->get_current_sector();
276   sector->update(elapsed_time);
277
278   make_tux_jump();
279
280   Menu* menu = MenuManager::current();
281   if(menu) {
282     if(menu == main_menu.get()) {
283       switch (main_menu->check()) {
284         case MNID_STARTGAME:
285           // Start Game, ie. goto the slots menu
286           if(main_world.get() == NULL) {
287             main_world.reset(new World());
288             main_world->load("levels/world1/info");
289           }
290           current_world = main_world.get();
291           start_game();
292           break;
293
294         case MNID_LEVELS_CONTRIB:
295           // Contrib Menu
296           contrib_menu.reset(new ContribMenu());
297           MenuManager::push_current(contrib_menu.get());
298           break;
299
300         case MNID_ADDONS:
301           // Add-ons Menu
302           generate_addons_menu();
303           MenuManager::push_current(addons_menu.get());
304           break;
305
306         case MNID_CREDITS:
307           MenuManager::set_current(NULL);
308           g_main_loop->push_screen(new TextScroller("credits.txt"),
309                                    new FadeOut(0.5));
310           break;
311
312         case MNID_QUITMAINMENU:
313           g_main_loop->quit(new FadeOut(0.25));
314           sound_manager->stop_music(0.25);
315           break;
316       }
317     } else if(menu == contrib_menu.get()) {
318       check_levels_contrib_menu();
319     } else if(menu == addons_menu.get()) {
320       check_addons_menu();
321     } else if (menu == contrib_world_menu.get()) {
322       contrib_world_menu->check_menu();
323     }
324   }
325
326   // reopen menu if user closed it (so that the app doesn't close when user
327   // accidently hit ESC)
328   if(MenuManager::current() == 0 && g_main_loop->has_no_pending_fadeout()) {
329     generate_main_menu();
330     MenuManager::set_current(main_menu.get());
331   }
332 }
333
334 void
335 TitleScreen::start_game()
336 {
337   MenuManager::set_current(NULL);
338   std::string basename = current_world->get_basedir();
339   basename = basename.substr(0, basename.length()-1);
340   std::string worlddirname = FileSystem::basename(basename);
341   std::ostringstream stream;
342   stream << "profile" << g_config->profile << "/" << worlddirname << ".stsg";
343   std::string slotfile = stream.str();
344
345   try {
346     current_world->set_savegame_filename(slotfile);
347     current_world->run();
348   } catch(std::exception& e) {
349     log_fatal << "Couldn't start world: " << e.what() << std::endl;
350   }
351 }
352
353 /* EOF */