ec5618aeb2b9d4a92f0e3625286e5d7dd83906c3
[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           Menu::set_current(main_menu);
154         }
155     }  
156 }
157
158 void draw_background()
159 {
160   /* Draw the title background: */
161
162   bkg_title->draw_bg();
163 }
164
165 void draw_demo(GameSession* session, double frame_ratio)
166 {
167   World::set_current(session->get_world());
168   //World* world  = session->get_world();
169   Level* plevel = session->get_level();
170   Player* tux = session->get_world()->get_tux();
171
172   session->get_world()->play_music(LEVEL_MUSIC);
173   
174   /* FIXME:
175   // update particle systems
176   std::vector<ParticleSystem*>::iterator p;
177   for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
178     {
179       (*p)->simulate(frame_ratio);
180     }
181
182   // Draw particle systems (background)
183   for(p = particle_systems.begin(); p != particle_systems.end(); ++p)
184     {
185       (*p)->draw(scroll_x, 0, 0);
186     }
187   */
188
189   // Draw interactive tiles:
190   for (int y = 0; y < 15; ++y)
191     {
192       for (int x = 0; x < 21; ++x)
193         {
194           Tile::draw(32*x - fmodf(scroll_x, 32), y * 32,
195                      plevel->ia_tiles[(int)y][(int)x + (int)(scroll_x / 32)]);
196         }
197     }
198
199   global_frame_counter++;
200   tux->key_event((SDLKey) keymap.right,DOWN);
201   
202   if(random_timer.check())
203     {
204       if(walking)
205         tux->key_event((SDLKey) keymap.jump,UP);
206       else
207         tux->key_event((SDLKey) keymap.jump,DOWN);
208     }
209   else
210     {
211       random_timer.start(rand() % 3000 + 3000);
212       walking = !walking;
213     }
214   
215   // Wrap around at the end of the level back to the beginnig
216   if(plevel->width * 32 - 320 < tux->base.x)
217     {
218       tux->base.x = tux->base.x - (plevel->width * 32 - 640);
219       scroll_x = tux->base.x - 320;
220     }
221
222   float last_tux_x_pos = tux->base.x;
223   tux->action(frame_ratio);
224
225 #if 0 // disabled for now, since with the new jump code we easily get deadlocks
226   // Jump if tux stays in the same position for one loop, ie. if he is
227   // stuck behind a wall
228   if (last_tux_x_pos == tux->base.x)
229     walking = false;
230 #endif
231
232   tux->draw();
233 }
234
235 /* --- TITLE SCREEN --- */
236 void title(void)
237 {
238   random_timer.init(true);
239
240   walking = true;
241
242   st_pause_ticks_init();
243
244   GameSession session(datadir + "/levels/misc/menu.stl", 0, ST_GL_DEMO_GAME);
245
246   clearscreen(0, 0, 0);
247   updatescreen();
248
249   /* Load images: */
250   bkg_title = new Surface(datadir + "/images/title/background.jpg", IGNORE_ALPHA);
251   logo = new Surface(datadir + "/images/title/logo.png", USE_ALPHA);
252   img_choose_subset = new Surface(datadir + "/images/status/choose-level-subset.png", USE_ALPHA);
253
254   /* --- Main title loop: --- */
255   frame = 0;
256
257   /* Draw the title background: */
258   bkg_title->draw_bg();
259
260   update_time = st_get_ticks();
261   random_timer.start(rand() % 2000 + 2000);
262
263   Menu::set_current(main_menu);
264   while (Menu::current())
265     {
266       // if we spent to much time on a menu entry
267       if( (update_time - last_update_time) > 1000)
268         update_time = last_update_time = st_get_ticks();
269
270       // Calculate the movement-factor
271       double frame_ratio = ((double)(update_time-last_update_time))/((double)FRAME_RATE);
272       if(frame_ratio > 1.5) /* Quick hack to correct the unprecise CPU clocks a little bit. */
273         frame_ratio = 1.5 + (frame_ratio - 1.5) * 0.85;
274       /* Lower the frame_ratio that Tux doesn't jump to hectically throught the demo. */
275       frame_ratio /= 2;
276
277       SDL_Event event;
278       while (SDL_PollEvent(&event))
279         {
280           if (Menu::current())
281             {
282               Menu::current()->event(event);
283             }
284          // FIXME: QUIT signal should be handled more generic, not locally
285           if (event.type == SDL_QUIT)
286             Menu::set_current(0);
287         }
288
289       /* Draw the background: */
290       draw_background();
291       draw_demo(&session, frame_ratio);
292       
293       if (Menu::current() == main_menu)
294         logo->draw( 160, 30);
295
296       white_small_text->draw(" SuperTux " VERSION "\n"
297                              "Copyright (c) 2003 SuperTux Devel Team\n"
298                              "This game comes with ABSOLUTELY NO WARRANTY. This is free software, and you\n"
299                              "are welcome to redistribute it under certain conditions; see the file COPYING\n"
300                              "for details.\n",
301                              0, 420, 0);
302
303       /* Don't draw menu, if quit is true */
304       Menu* menu = Menu::current();
305       if(menu)
306         {
307           menu->draw();
308           menu->action();
309         
310           if(menu == main_menu)
311             {
312               switch (main_menu->check())
313                 {
314                 case MNID_STARTGAME:
315                   // Start Game, ie. goto the slots menu
316                   update_load_save_game_menu(load_game_menu);
317                   break;
318                 case MNID_CONTRIB:
319                   // Contrib Menu
320                   puts("Entering contrib menu");
321                   generate_contrib_menu();
322                   break;
323                 case MNID_LEVELEDITOR:
324                   leveleditor(1);
325                   Menu::set_current(main_menu);
326                   break;
327                 case MNID_CREDITS:
328                   display_text_file("CREDITS", bkg_title, SCROLL_SPEED_CREDITS);
329                   Menu::set_current(main_menu);
330                   break;
331                 case MNID_QUITMAINMENU:
332                   Menu::set_current(0);
333                   break;
334                 }
335             }
336           else if(menu == options_menu)
337             {
338               process_options_menu();
339             }
340           else if(menu == load_game_menu)
341             {
342               if(event.key.keysym.sym == SDLK_DELETE)
343                 {
344                 int slot = menu->get_active_item_id();
345                 char str[1024];
346                 sprintf(str,"Are you sure you want to delete slot %d?", slot);
347                 
348                 draw_background();
349
350                 if(confirm_dialog(str))
351                   {
352                   sprintf(str,"%s/slot%d.stsg", st_save_dir, slot);
353                   printf("Removing: %s\n",str);
354                   remove(str);
355                   }
356
357                 update_load_save_game_menu(load_game_menu);
358                 update_time = st_get_ticks();
359                 }
360               else if (process_load_game_menu())
361                 {
362                   // FIXME: shouldn't be needed if GameSession doesn't relay on global variables
363                   // reset tux
364                   scroll_x = 0;
365                   //titletux.level_begin();
366                   update_time = st_get_ticks();
367                 }
368             }
369           else if(menu == contrib_menu)
370             {
371               check_contrib_menu();
372             }
373           else if (menu == contrib_subset_menu)
374             {
375               check_contrib_subset_menu();
376             }
377         }
378
379       mouse_cursor->draw();
380       
381       flipscreen();
382
383       /* Set the time of the last update and the time of the current update */
384       last_update_time = update_time;
385       update_time = st_get_ticks();
386
387       /* Pause: */
388       frame++;
389       SDL_Delay(25);
390     }
391   /* Free surfaces: */
392
393   free_contrib_menu();
394   delete bkg_title;
395   delete logo;
396   delete img_choose_subset;
397 }
398
399 // EOF //
400