hiding the time while end_sequence wasn't nice
[supertux.git] / src / title.cpp
1 //  $Id$
2 // 
3 //  SuperTux
4 //  Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
5 //  Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
6 //
7 //  This program is free software; you can redistribute it and/or
8 //  modify it under the terms of the GNU General Public License
9 //  as published by the Free Software Foundation; either version 2
10 //  of the License, or (at your option) any later version.
11 //
12 //  This program is distributed in the hope that it will be useful,
13 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 //  GNU General Public License for more details.
16 // 
17 //  You should have received a copy of the GNU General Public License
18 //  along with this program; if not, write to the Free Software
19 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 //  02111-1307, USA.
21
22 #include <iostream>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <SDL.h>
29 #include <SDL_image.h>
30
31 #ifndef WIN32
32 #include <sys/types.h>
33 #include <ctype.h>
34 #endif
35
36 #include "defines.h"
37 #include "globals.h"
38 #include "title.h"
39 #include "screen.h"
40 #include "high_scores.h"
41 #include "menu.h"
42 #include "texture.h"
43 #include "timer.h"
44 #include "setup.h"
45 #include "level.h"
46 #include "gameloop.h"
47 #include "leveleditor.h"
48 #include "scene.h"
49 #include "player.h"
50 #include "math.h"
51 #include "tile.h"
52 #include "resources.h"
53
54 static Surface* bkg_title;
55 static Surface* logo;
56 static Surface* img_choose_subset;
57
58 static bool walking;
59 static Timer random_timer;
60
61 static int frame;
62 static unsigned int last_update_time;
63 static unsigned int update_time;
64
65 std::vector<LevelSubset*> contrib_subsets;
66 std::string current_contrib_subset;
67
68 void free_contrib_menu()
69 {
70   for(std::vector<LevelSubset*>::iterator i = contrib_subsets.begin();
71       i != contrib_subsets.end(); ++i)
72     delete *i;
73
74   contrib_subsets.clear();
75   contrib_menu->clear();
76 }
77
78 void generate_contrib_menu()
79 {
80   string_list_type level_subsets = dsubdirs("/levels", "info");
81
82   free_contrib_menu();
83
84   contrib_menu->additem(MN_LABEL,"Contrib Levels",0,0);
85   contrib_menu->additem(MN_HL,"",0,0);
86
87   for (int i = 0; i < level_subsets.num_items; ++i)
88     {
89       LevelSubset* subset = new LevelSubset();
90       subset->load(level_subsets.item[i]);
91       contrib_menu->additem(MN_GOTO, subset->title.c_str(), i,
92           contrib_subset_menu, i+1);
93       contrib_subsets.push_back(subset);
94     }
95
96   contrib_menu->additem(MN_HL,"",0,0);
97   contrib_menu->additem(MN_BACK,"Back",0,0);
98
99   string_list_free(&level_subsets);
100 }
101
102 void check_contrib_menu()
103 {
104   static int current_subset = -1;
105
106   int index = contrib_menu->check();
107   if (index != -1)
108     {
109       index -= 1;
110       if (index >= 0 && index <= int(contrib_subsets.size()))
111         {
112           if (current_subset != index)
113             {
114               current_subset = index;
115               // FIXME: This shouln't be busy looping
116               LevelSubset& subset = * (contrib_subsets[index]);
117           
118               current_contrib_subset = subset.name;
119
120               std::cout << "Updating the contrib subset menu..." << subset.levels << std::endl;
121       
122               contrib_subset_menu->clear();
123
124               contrib_subset_menu->additem(MN_LABEL, subset.title, 0,0);
125               contrib_subset_menu->additem(MN_HL,"",0,0);
126               for (int i = 1; i <= subset.levels; ++i)
127                 {
128                   Level level;
129                   level.load(subset.name, i);
130                   contrib_subset_menu->additem(MN_ACTION, level.name, 0, 0, i);
131                 }
132               contrib_subset_menu->additem(MN_HL,"",0,0);      
133               contrib_subset_menu->additem(MN_BACK, "Back", 0, 0);
134             }
135         }
136       else
137         {
138           // Back button
139         }
140     }
141 }
142
143 void check_contrib_subset_menu()
144 {
145   int index = contrib_subset_menu->check();
146   if (index != -1)
147     {
148       if (contrib_subset_menu->get_item_by_id(index).kind == MN_ACTION)
149         {
150           std::cout << "Sarting level: " << index << std::endl;
151           GameSession session(current_contrib_subset, index, ST_GL_PLAY);
152           session.run();
153           player_status.reset();
154           Menu::set_current(main_menu);
155         }
156     }  
157 }
158
159 void draw_background()
160 {
161   /* Draw the title background: */
162
163   bkg_title->draw_bg();
164 }
165
166 void draw_demo(GameSession* session, double frame_ratio)
167 {
168   World::set_current(session->get_world());
169   //World* world  = session->get_world();
170   Level* plevel = session->get_level();
171   Player* tux = session->get_world()->get_tux();
172
173   session->get_world()->play_music(LEVEL_MUSIC);
174   
175   /* FIXME:
176   // update particle systems
177   std::vector<ParticleSystem*>::iterator p;
178   for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
179     {
180       (*p)->simulate(frame_ratio);
181     }
182
183   // Draw particle systems (background)
184   for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
185     {
186       (*p)->draw(scroll_x, 0, 0);
187     }
188   */
189
190   // Draw interactive tiles:
191   for (int y = 0; y < 15; ++y)
192     {
193       for (int x = 0; x < 21; ++x)
194         {
195           Tile::draw(32*x - fmodf(scroll_x, 32), y * 32,
196                      plevel->ia_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
197         }
198     }
199
200   global_frame_counter++;
201   tux->key_event((SDLKey) keymap.right,DOWN);
202   
203   if(random_timer.check())
204     {
205       if(walking)
206         tux->key_event((SDLKey) keymap.jump,UP);
207       else
208         tux->key_event((SDLKey) keymap.jump,DOWN);
209     }
210   else
211     {
212       random_timer.start(rand() % 3000 + 3000);
213       walking = !walking;
214     }
215
216   // Wrap around at the end of the level back to the beginnig
217   if(plevel->width * 32 - 320 < tux->base.x)
218     {
219       tux->base.x = tux->base.x - (plevel->width * 32 - 640);
220       scroll_x = tux->base.x - 320;
221     }
222
223   tux->can_jump = true;
224   float last_tux_x_pos = tux->base.x;
225   tux->action(frame_ratio);
226
227   // disabled for now, since with the new jump code we easily get deadlocks
228   // Jump if tux stays in the same position for one loop, ie. if he is
229   // stuck behind a wall
230   if (last_tux_x_pos == tux->base.x)
231     {
232       walking = false;
233     }
234
235   tux->draw();
236 }
237
238 /* --- TITLE SCREEN --- */
239 void title(void)
240 {
241   random_timer.init(true);
242
243   walking = true;
244
245   st_pause_ticks_init();
246
247   GameSession session(datadir + "/levels/misc/menu.stl", 0, ST_GL_DEMO_GAME);
248
249   clearscreen(0, 0, 0);
250   updatescreen();
251
252   /* Load images: */
253   bkg_title = new Surface(datadir + "/images/title/background.jpg", IGNORE_ALPHA);
254   logo = new Surface(datadir + "/images/title/logo.png", USE_ALPHA);
255   img_choose_subset = new Surface(datadir + "/images/status/choose-level-subset.png", USE_ALPHA);
256
257   /* --- Main title loop: --- */
258   frame = 0;
259
260   /* Draw the title background: */
261   bkg_title->draw_bg();
262
263   update_time = st_get_ticks();
264   random_timer.start(rand() % 2000 + 2000);
265
266   Menu::set_current(main_menu);
267   while (Menu::current())
268     {
269       // if we spent to much time on a menu entry
270       if( (update_time - last_update_time) > 1000)
271         update_time = last_update_time = st_get_ticks();
272
273       // Calculate the movement-factor
274       double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
275       if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
276         frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
277       /* Lower the frame_ratio that Tux doesn't jump to hectically throught the demo. */
278       frame_ratio /= 2;
279
280       SDL_Event event;
281       while (SDL_PollEvent(&event))
282         {
283           if (Menu::current())
284             {
285               Menu::current()->event(event);
286             }
287          // FIXME: QUIT signal should be handled more generic, not locally
288           if (event.type == SDL_QUIT)
289             Menu::set_current(0);
290         }
291
292       /* Draw the background: */
293       draw_background();
294       draw_demo(&session, frame_ratio);
295       
296       if (Menu::current() == main_menu)
297         logo->draw( 160, 30);
298
299       white_small_text->draw(" SuperTux " VERSION "\n"
300                              "Copyright (c) 2003 SuperTux Devel Team\n"
301                              "This game comes with ABSOLUTELY NO WARRANTY. This is free software, and you\n"
302                              "are welcome to redistribute it under certain conditions; see the file COPYING\n"
303                              "for details.\n",
304                              0, 420, 0);
305
306       /* Don't draw menu, if quit is true */
307       Menu* menu = Menu::current();
308       if(menu)
309         {
310           menu->draw();
311           menu->action();
312         
313           if(menu == main_menu)
314             {
315               switch (main_menu->check())
316                 {
317                 case MNID_STARTGAME:
318                   // Start Game, ie. goto the slots menu
319                   update_load_save_game_menu(load_game_menu);
320                   break;
321                 case MNID_CONTRIB:
322                   // Contrib Menu
323                   puts("Entering contrib menu");
324                   generate_contrib_menu();
325                   break;
326                 case MNID_LEVELEDITOR:
327                   leveleditor(1);
328                   Menu::set_current(main_menu);
329                   break;
330                 case MNID_CREDITS:
331                   display_text_file("CREDITS", bkg_title, SCROLL_SPEED_CREDITS);
332                   Menu::set_current(main_menu);
333                   break;
334                 case MNID_QUITMAINMENU:
335                   Menu::set_current(0);
336                   break;
337                 }
338             }
339           else if(menu == options_menu)
340             {
341               process_options_menu();
342             }
343           else if(menu == load_game_menu)
344             {
345               if(event.key.keysym.sym == SDLK_DELETE)
346                 {
347                 int slot = menu->get_active_item_id();
348                 char str[1024];
349                 sprintf(str,"Are you sure you want to delete slot %d?", slot);
350                 
351                 draw_background();
352
353                 if(confirm_dialog(str))
354                   {
355                   sprintf(str,"%s/slot%d.stsg", st_save_dir, slot);
356                   printf("Removing: %s\n",str);
357                   remove(str);
358                   }
359
360                 update_load_save_game_menu(load_game_menu);
361                 update_time = st_get_ticks();
362                 }
363               else if (process_load_game_menu())
364                 {
365                   // FIXME: shouldn't be needed if GameSession doesn't relay on global variables
366                   // reset tux
367                   scroll_x = 0;
368                   //titletux.level_begin();
369                   update_time = st_get_ticks();
370                 }
371             }
372           else if(menu == contrib_menu)
373             {
374               check_contrib_menu();
375             }
376           else if (menu == contrib_subset_menu)
377             {
378               check_contrib_subset_menu();
379             }
380         }
381
382       mouse_cursor->draw();
383       
384       flipscreen();
385
386       /* Set the time of the last update and the time of the current update */
387       last_update_time = update_time;
388       update_time = st_get_ticks();
389
390       /* Pause: */
391       frame++;
392       SDL_Delay(25);
393     }
394   /* Free surfaces: */
395
396   free_contrib_menu();
397   delete bkg_title;
398   delete logo;
399   delete img_choose_subset;
400 }
401
402 // EOF //
403